/////////////////////////////////////////////////////////////////////////////// // 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 // 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 class wxMFCApp : public T { public: typedef T BaseApp; BOOL InitInstance() wxOVERRIDE { if ( !BaseApp::InitInstance() ) return FALSE; if ( !wxEntryStart(BaseApp::m_hInstance) ) return FALSE; if ( !wxTheApp || !wxTheApp->CallOnInit() ) return FALSE; if ( !InitMainWnd() ) return FALSE; return TRUE; } int ExitInstance() wxOVERRIDE { delete BaseApp::m_pMainWnd; BaseApp::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(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->ProcessPendingEvents(); if ( 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. BaseApp::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 BaseApp::m_pMainWnd; BaseApp::m_pMainWnd = NULL; } }; typedef wxMFCApp 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); } void WakeUpIdle() wxOVERRIDE { // As above, we can't wake up any wx event loop, so try to wake up the // MFC one instead. CWinApp* const mfcApp = AfxGetApp(); if ( mfcApp && mfcApp->m_pMainWnd ) { ::PostMessage(mfcApp->m_pMainWnd->m_hWnd, WM_NULL, 0, 0); } } }; #endif // _WX_MSW_MFC_H_