Merge branch 'mfc'

A bunch of improvements for applications using both wxWidgets and MFC.
This commit is contained in:
Vadim Zeitlin
2018-01-23 15:39:00 +01:00
4 changed files with 233 additions and 165 deletions

177
include/wx/msw/mfc.h Normal file
View File

@@ -0,0 +1,177 @@
///////////////////////////////////////////////////////////////////////////////
// Name: wx/msw/mfc.h
// Purpose: Helpers for applications using both wxWidgets and MFC
// Author: Julian Smart, Vadim Zeitlin
// Created: 2017-12-01 (mostly extracted from samples/mfc)
// Copyright: (c) 2017 Vadim Zeitlin <vadim@wxwidgets.org>
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#ifndef _WX_MSW_MFC_H_
#define _WX_MSW_MFC_H_
#ifndef __AFXWIN_H__
#error "MFC headers must be included before including this file."
#endif
#include "wx/app.h"
#include "wx/evtloop.h"
#include "wx/window.h"
#include "wx/msw/winundef.h"
// ----------------------------------------------------------------------------
// MFC window class wrapping a window created by wxWidgets
// ----------------------------------------------------------------------------
class wxMFCWnd : public CWnd
{
public:
// If default ctor is used, Attach() must be called later.
wxMFCWnd()
{
}
// Combines default ctor and Attach().
explicit wxMFCWnd(wxWindow* w)
{
Attach(w);
}
void Attach(wxWindow* w)
{
CWnd::Attach(w->GetHWND());
}
~wxMFCWnd()
{
// Prevent MFC from destroying the wxWindow.
Detach();
}
};
// ----------------------------------------------------------------------------
// MFC application class forwarding everything to wxApp
// ----------------------------------------------------------------------------
// The template parameter here is an existing class deriving from CWinApp or,
// if there is no such class, just CWinApp itself.
template <typename T>
class wxMFCApp : public T
{
public:
typedef T BaseApp;
BOOL InitInstance() wxOVERRIDE
{
if ( !BaseApp::InitInstance() )
return FALSE;
if ( !wxEntryStart(m_hInstance) )
return FALSE;
if ( !wxTheApp || !wxTheApp->CallOnInit() )
return FALSE;
if ( !InitMainWnd() )
return FALSE;
return TRUE;
}
int ExitInstance() wxOVERRIDE
{
delete m_pMainWnd;
m_pMainWnd = NULL;
if ( wxTheApp )
wxTheApp->OnExit();
wxEntryCleanup();
return BaseApp::ExitInstance();
}
// Override this to provide messages pre-processing for wxWidgets windows.
BOOL PreTranslateMessage(MSG *msg) wxOVERRIDE
{
// Use the current event loop if there is one, or just fall back to the
// standard one otherwise, but make sure we pre-process messages in any
// case as otherwise many things would break (e.g. keyboard
// accelerators).
wxGUIEventLoop*
evtLoop = static_cast<wxGUIEventLoop *>(wxEventLoop::GetActive());
wxGUIEventLoop evtLoopStd;
if ( !evtLoop )
evtLoop = &evtLoopStd;
if ( evtLoop->PreProcessMessage(msg) )
return TRUE;
return BaseApp::PreTranslateMessage(msg);
}
BOOL OnIdle(LONG lCount) wxOVERRIDE
{
BOOL moreIdle = BaseApp::OnIdle(lCount);
if ( wxTheApp && wxTheApp->ProcessIdle() )
moreIdle = TRUE;
return moreIdle;
}
protected:
// This virtual method can be overridden to create the main window using
// MFC code. The default implementation relies on wxApp::OnInit() creating
// a top level window which is then wrapped in an MFC window and used as
// the main window.
virtual BOOL InitMainWnd()
{
wxWindow* const w = wxTheApp->GetTopWindow();
if ( !w )
return FALSE;
// We need to initialize the main window to let the program continue
// running.
m_pMainWnd = new wxMFCWnd(w);
// We also need to reset m_pMainWnd when this window will be destroyed
// to prevent MFC from using an invalid HWND, which is probably not
// fatal but can result in at least asserts failures.
w->Bind(wxEVT_DESTROY, &wxMFCApp::OnMainWindowDestroyed, this);
// And we need to let wxWidgets know that it should exit the
// application when this window is closed, as OnRun(), which does this
// by default, won't be called when using MFC main message loop.
wxTheApp->SetExitOnFrameDelete(true);
return TRUE;
}
private:
void OnMainWindowDestroyed(wxWindowDestroyEvent& event)
{
event.Skip();
delete m_pMainWnd;
m_pMainWnd = NULL;
}
};
typedef wxMFCApp<CWinApp> wxMFCWinApp;
// ----------------------------------------------------------------------------
// wxWidgets application class to be used in MFC applications
// ----------------------------------------------------------------------------
class wxAppWithMFC : public wxApp
{
public:
void ExitMainLoop() wxOVERRIDE
{
// There is no wxEventLoop to exit, tell MFC to stop pumping messages
// instead.
::PostQuitMessage(0);
}
};
#endif // _WX_MSW_MFC_H_

View File

@@ -15,6 +15,14 @@
#define _WX_WINUNDEF_H_
*/
#ifndef wxUSE_UNICODE_WINDOWS_H
#ifdef _UNICODE
#define wxUSE_UNICODE_WINDOWS_H 1
#else
#define wxUSE_UNICODE_WINDOWS_H 0
#endif
#endif
// ----------------------------------------------------------------------------
// windows.h #defines the following identifiers which are also used in wxWin so
// we replace these symbols with the corresponding inline functions and
@@ -34,7 +42,7 @@
HWND hwndParent,
DLGPROC pDlgProc)
{
#ifdef _UNICODE
#if wxUSE_UNICODE_WINDOWS_H
return CreateDialogW(hInstance, pTemplate, hwndParent, pDlgProc);
#else
return CreateDialogA(hInstance, pTemplate, hwndParent, pDlgProc);
@@ -62,7 +70,7 @@
DWORD family,
LPCTSTR facename)
{
#ifdef _UNICODE
#if wxUSE_UNICODE_WINDOWS_H
return CreateFontW(height, width, escapement, orientation,
weight, italic, underline, strikeout, charset,
outprecision, clipprecision, quality,
@@ -90,7 +98,7 @@
HINSTANCE hInstance,
LPVOID lpParam)
{
#ifdef _UNICODE
#if wxUSE_UNICODE_WINDOWS_H
return CreateWindowW(lpClassName, lpWndClass, dwStyle, x, y, w, h,
hWndParent, hMenu, hInstance, lpParam);
#else
@@ -107,7 +115,7 @@
inline HMENU LoadMenu(HINSTANCE instance, LPCTSTR name)
{
#ifdef _UNICODE
#if wxUSE_UNICODE_WINDOWS_H
return LoadMenuW(instance, name);
#else
return LoadMenuA(instance, name);
@@ -122,7 +130,7 @@
inline HWND APIENTRY FindText(LPFINDREPLACE lpfindreplace)
{
#ifdef _UNICODE
#if wxUSE_UNICODE_WINDOWS_H
return FindTextW(lpfindreplace);
#else
return FindTextA(lpfindreplace);
@@ -136,7 +144,7 @@
#undef GetCharWidth
inline BOOL GetCharWidth(HDC dc, UINT first, UINT last, LPINT buffer)
{
#ifdef _UNICODE
#if wxUSE_UNICODE_WINDOWS_H
return GetCharWidthW(dc, first, last, buffer);
#else
return GetCharWidthA(dc, first, last, buffer);
@@ -148,7 +156,7 @@
#ifdef FindWindow
#undef FindWindow
#ifdef _UNICODE
#if wxUSE_UNICODE_WINDOWS_H
inline HWND FindWindow(LPCWSTR classname, LPCWSTR windowname)
{
return FindWindowW(classname, windowname);
@@ -165,7 +173,7 @@
#ifdef PlaySound
#undef PlaySound
#ifdef _UNICODE
#if wxUSE_UNICODE_WINDOWS_H
inline BOOL PlaySound(LPCWSTR pszSound, HMODULE hMod, DWORD fdwSound)
{
return PlaySoundW(pszSound, hMod, fdwSound);
@@ -182,7 +190,7 @@
#ifdef GetClassName
#undef GetClassName
#ifdef _UNICODE
#if wxUSE_UNICODE_WINDOWS_H
inline int GetClassName(HWND h, LPWSTR classname, int maxcount)
{
return GetClassNameW(h, classname, maxcount);
@@ -199,7 +207,7 @@
#ifdef GetClassInfo
#undef GetClassInfo
#ifdef _UNICODE
#if wxUSE_UNICODE_WINDOWS_H
inline BOOL GetClassInfo(HINSTANCE h, LPCWSTR name, LPWNDCLASSW winclass)
{
return GetClassInfoW(h, name, winclass);
@@ -216,7 +224,7 @@
#ifdef LoadAccelerators
#undef LoadAccelerators
#ifdef _UNICODE
#if wxUSE_UNICODE_WINDOWS_H
inline HACCEL LoadAccelerators(HINSTANCE h, LPCWSTR name)
{
return LoadAcceleratorsW(h, name);
@@ -233,7 +241,7 @@
#ifdef DrawText
#undef DrawText
#ifdef _UNICODE
#if wxUSE_UNICODE_WINDOWS_H
inline int DrawText(HDC h, LPCWSTR str, int count, LPRECT rect, UINT format)
{
return DrawTextW(h, str, count, rect, format);
@@ -252,7 +260,7 @@
#ifdef StartDoc
#undef StartDoc
#ifdef _UNICODE
#if wxUSE_UNICODE_WINDOWS_H
inline int StartDoc(HDC h, CONST DOCINFOW* info)
{
return StartDocW(h, (DOCINFOW*) info);
@@ -271,7 +279,7 @@
#undef GetObject
inline int GetObject(HGDIOBJ h, int i, LPVOID buffer)
{
#ifdef _UNICODE
#if wxUSE_UNICODE_WINDOWS_H
return GetObjectW(h, i, buffer);
#else
return GetObjectA(h, i, buffer);
@@ -285,7 +293,7 @@
#undef GetMessage
inline int GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax)
{
#ifdef _UNICODE
#if wxUSE_UNICODE_WINDOWS_H
return GetMessageW(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
#else
return GetMessageA(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
@@ -298,7 +306,7 @@
#undef LoadIcon
inline HICON LoadIcon(HINSTANCE hInstance, LPCTSTR lpIconName)
{
#ifdef _UNICODE
#if wxUSE_UNICODE_WINDOWS_H
return LoadIconW(hInstance, lpIconName);
#else // ANSI
return LoadIconA(hInstance, lpIconName);
@@ -311,7 +319,7 @@
#undef LoadBitmap
inline HBITMAP LoadBitmap(HINSTANCE hInstance, LPCTSTR lpBitmapName)
{
#ifdef _UNICODE
#if wxUSE_UNICODE_WINDOWS_H
return LoadBitmapW(hInstance, lpBitmapName);
#else // ANSI
return LoadBitmapA(hInstance, lpBitmapName);
@@ -323,7 +331,7 @@
#ifdef LoadLibrary
#undef LoadLibrary
#ifdef _UNICODE
#if wxUSE_UNICODE_WINDOWS_H
inline HINSTANCE LoadLibrary(LPCWSTR lpLibFileName)
{
return LoadLibraryW(lpLibFileName);
@@ -339,7 +347,7 @@
// FindResource
#ifdef FindResource
#undef FindResource
#ifdef _UNICODE
#if wxUSE_UNICODE_WINDOWS_H
inline HRSRC FindResource(HMODULE hModule, LPCWSTR lpName, LPCWSTR lpType)
{
return FindResourceW(hModule, lpName, lpType);
@@ -420,26 +428,6 @@
// For ming and cygwin
// GetFirstChild
#ifdef GetFirstChild
#undef GetFirstChild
inline HWND GetFirstChild(HWND h)
{
return GetTopWindow(h);
}
#endif
// GetNextSibling
#ifdef GetNextSibling
#undef GetNextSibling
inline HWND GetNextSibling(HWND h)
{
return GetWindow(h, GW_HWNDNEXT);
}
#endif
#ifdef Yield
#undef Yield
#endif

View File

@@ -17,8 +17,8 @@
// created subsequently.
//
// (1) Make MyApp::OnInit not create a main window.
// (2) Make MFC's InitInstance create a main window, and remove
// creation of CDummyWindow.
// (2) Define a class deriving from wxMFCWinApp and override its InitMainWnd()
// to create the main window in MFC code.
//
// This can be accomplished by setting START_WITH_MFC_WINDOW to 1 below.
@@ -73,6 +73,8 @@
#include "wx/nativewin.h"
#include "wx/spinctrl.h"
#include "wx/msw/mfc.h"
#include "resource.h"
#include "mfctest.h"
@@ -82,19 +84,15 @@
// theApp:
// Just creating this application object runs the whole application.
//
CTheApp theApp;
SampleMFCWinApp theApp;
// wxWidgets elements
// Define a new application type
class MyApp: public wxApp
// Define a new application type inheriting from wxAppWithMFC
class MyApp: public wxAppWithMFC
{
public:
virtual bool OnInit();
// we need to override this as the default behaviour only works when we're
// running wxWidgets main loop, not MFC one
virtual void ExitMainLoop();
virtual bool OnInit() wxOVERRIDE;
wxFrame *CreateFrame();
};
@@ -238,73 +236,6 @@ ON_COMMAND( IDM_TEST, OnTest )
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
BOOL CTheApp::InitInstance()
{
if ( !CWinApp::InitInstance() )
return FALSE;
// TODO: cmd line parsing
WXDLLIMPEXP_BASE void wxSetInstance(HINSTANCE hInst);
wxSetInstance(m_hInstance);
wxApp::m_nCmdShow = m_nCmdShow;
int argc = 0;
wxChar **argv = NULL;
wxEntryStart(argc, argv);
if ( !wxTheApp || !wxTheApp->CallOnInit() )
return FALSE;
#if START_WITH_MFC_WINDOW
// Demonstrate creation of an initial MFC main window.
m_pMainWnd = new CMainWindow();
m_pMainWnd->ShowWindow( m_nCmdShow );
m_pMainWnd->UpdateWindow();
#else
// Demonstrate creation of an initial wxWidgets main window.
// Wrap wxWidgets window in a dummy MFC window and
// make the main window.
if (wxTheApp && wxTheApp->GetTopWindow())
{
m_pMainWnd = new CDummyWindow((HWND) wxTheApp->GetTopWindow()->GetHWND());
}
#endif
return TRUE;
}
int CTheApp::ExitInstance()
{
#if !START_WITH_MFC_WINDOW
delete m_pMainWnd;
#endif
if ( wxTheApp )
wxTheApp->OnExit();
wxEntryCleanup();
return CWinApp::ExitInstance();
}
// Override this to provide wxWidgets message loop compatibility
BOOL CTheApp::PreTranslateMessage(MSG *msg)
{
wxEventLoop * const
evtLoop = static_cast<wxEventLoop *>(wxEventLoop::GetActive());
if ( evtLoop && evtLoop->PreProcessMessage(msg) )
return TRUE;
return CWinApp::PreTranslateMessage(msg);
}
BOOL CTheApp::OnIdle(LONG lCount)
{
BOOL moreIdle = CWinApp::OnIdle(lCount);
if ( wxTheApp && wxTheApp->ProcessIdle() )
moreIdle = TRUE;
return moreIdle;
}
/*********************************************************************
* wxWidgets elements
********************************************************************/
@@ -315,22 +246,12 @@ bool MyApp::OnInit()
return false;
#if !START_WITH_MFC_WINDOW
// as we're not inside wxWidgets main loop, the default logic doesn't work
// in our case and we need to do this explicitly
SetExitOnFrameDelete(true);
(void) CreateFrame();
#endif
return true;
}
void MyApp::ExitMainLoop()
{
// instead of existing wxWidgets main loop, terminate the MFC one
::PostQuitMessage(0);
}
wxFrame *MyApp::CreateFrame()
{
MyChild *subframe = new MyChild(NULL, wxT("Canvas Frame"), wxPoint(10, 10), wxSize(300, 300),
@@ -451,17 +372,3 @@ void MyChild::OnActivate(wxActivateEvent& event)
if (event.GetActive() && canvas)
canvas->SetFocus();
}
// Dummy MFC window for specifying a valid main window to MFC, using
// a wxWidgets HWND.
CDummyWindow::CDummyWindow(HWND hWnd)
{
Attach(hWnd);
}
// Don't let the CWnd destructor delete the HWND
CDummyWindow::~CDummyWindow()
{
Detach();
}

View File

@@ -9,11 +9,7 @@
#ifndef __MFCTEST_H__
#define __MFCTEST_H__
/////////////////////////////////////////////////////////////////////////////
// CMainWindow:
// See hello.cpp for the code to the member functions and the message map.
//
// CMainWindow: just a normal MFC window class.
class CMainWindow : public CFrameWnd
{
public:
@@ -31,30 +27,30 @@ private:
class wxNativeContainerWindow* m_containerWX;
};
// A dummy CWnd pointing to a wxWindow's HWND
class CDummyWindow: public CWnd
#if START_WITH_MFC_WINDOW
// There is no need to define an application class if the default behaviour of
// using the wxWindow created in wxApp::OnInit() as main window is acceptable,
// but if we want to create the initial window in MFC, we need this class in
// order to override InitMainWnd() in it.
class SampleMFCWinApp : public wxMFCWinApp
{
public:
CDummyWindow(HWND hWnd);
~CDummyWindow(void);
protected:
BOOL InitMainWnd() wxOVERRIDE
{
// Demonstrate creation of an initial MFC main window.
m_pMainWnd = new CMainWindow();
m_pMainWnd->ShowWindow( m_nCmdShow );
m_pMainWnd->UpdateWindow();
return TRUE;
}
};
/////////////////////////////////////////////////////////////////////////////
#else // !START_WITH_MFC_WINDOW
// CTheApp:
//
class CTheApp : public CWinApp
{
public:
BOOL InitInstance();
int ExitInstance();
typedef wxMFCWinApp SampleMFCWinApp;
// Override this to provide wxWidgets message loop
// compatibility
BOOL PreTranslateMessage(MSG *msg);
BOOL OnIdle(LONG lCount);
};
/////////////////////////////////////////////////////////////////////////////
#endif // START_WITH_MFC_WINDOW/!START_WITH_MFC_WINDOW
#endif // __MFCTEST_H__