Extract reusable part of the MFC sample in a header
Allow reusing this functionality from outside the library, it can he useful if an MFC window needs to be embedded into a wx application (or vice versa). Also use a better wxEntryStart() overload as a side effect, this should, in particular, fix the problem with command line arguments processing in mixed MFC/wx applications pointed out in a comment in the sample previously.
This commit is contained in:
137
include/wx/msw/mfc.h
Normal file
137
include/wx/msw/mfc.h
Normal file
@@ -0,0 +1,137 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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:
|
||||
explicit wxMFCWnd(wxWindow* w)
|
||||
{
|
||||
Attach(w->GetHWND());
|
||||
}
|
||||
|
||||
~wxMFCWnd()
|
||||
{
|
||||
// Prevent MFC from destroying the wxWindow.
|
||||
Detach();
|
||||
}
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// MFC application class forwarding everything to wxApp
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class wxMFCWinApp : public CWinApp
|
||||
{
|
||||
public:
|
||||
BOOL InitInstance() wxOVERRIDE
|
||||
{
|
||||
if ( !CWinApp::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;
|
||||
|
||||
if ( wxTheApp )
|
||||
wxTheApp->OnExit();
|
||||
|
||||
wxEntryCleanup();
|
||||
|
||||
return CWinApp::ExitInstance();
|
||||
}
|
||||
|
||||
// Override this to provide wxWidgets message loop compatibility
|
||||
BOOL PreTranslateMessage(MSG *msg) wxOVERRIDE
|
||||
{
|
||||
wxEventLoop * const
|
||||
evtLoop = static_cast<wxEventLoop *>(wxEventLoop::GetActive());
|
||||
if ( evtLoop && evtLoop->PreProcessMessage(msg) )
|
||||
return TRUE;
|
||||
|
||||
return CWinApp::PreTranslateMessage(msg);
|
||||
}
|
||||
|
||||
BOOL OnIdle(LONG lCount) wxOVERRIDE
|
||||
{
|
||||
BOOL moreIdle = CWinApp::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);
|
||||
|
||||
// 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;
|
||||
}
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// 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_
|
@@ -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();
|
||||
}
|
||||
|
||||
|
@@ -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__
|
||||
|
Reference in New Issue
Block a user