From 9be928d6fb1dabb387be6bb7828951d7c7361698 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Thu, 9 Jul 2015 20:06:48 +0200 Subject: [PATCH] Fix destruction of wxNativeContainerWindow in wxMSW. WM_CLOSE was not processed at all for native windows wrapped by wxNativeContainerWindow because we don't handle it ourselves at wxWindow level but still mark it as processed in order to prevent DefWindowProc() from destroying the window. Unfortunately this also prevented the original handler for this message in the native window from being called. Calling just the original handler and not the wxWidgets one is not ideal neither but is much better as it allows to e.g. close MFC frames wrapped in wxNativeContainerWindow whereas before this didn't work at all as WM_CLOSE was completely ignored. Also call the original handler for WM_DESTROY to avoid similar potential problems with this message, even if it doesn't seem to create any with MFC. Extend the mfc sample to show how a wxPanel can be embedded into the existing CFrameWnd. --- samples/mfc/mfctest.cpp | 46 +++++++++++++++++++++++++++++++++++++++++ samples/mfc/mfctest.h | 3 +++ src/msw/nativewin.cpp | 19 ++++++++++++++--- 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/samples/mfc/mfctest.cpp b/samples/mfc/mfctest.cpp index d60b17fa4f..b0b14c38de 100644 --- a/samples/mfc/mfctest.cpp +++ b/samples/mfc/mfctest.cpp @@ -70,6 +70,8 @@ #endif #include "wx/evtloop.h" +#include "wx/nativewin.h" +#include "wx/spinctrl.h" #include "resource.h" @@ -121,6 +123,38 @@ public: wxDECLARE_EVENT_TABLE(); }; +class MyPanel : public wxPanel +{ +public: + MyPanel(wxWindow *parent, const wxPoint& pos) + : wxPanel(parent, wxID_ANY, pos) + { + wxSizer* const sizer = new wxFlexGridSizer(2, wxSize(5, 5)); + sizer->Add(new wxStaticText(this, wxID_ANY, "Enter your &name:"), + wxSizerFlags().Center().Right()); + m_textName = new wxTextCtrl(this, wxID_ANY); + m_textName->SetHint("First Last"); + sizer->Add(m_textName, wxSizerFlags().Expand().CenterVertical()); + + sizer->Add(new wxStaticText(this, wxID_ANY, "And your &age:"), + wxSizerFlags().Center().Right()); + m_spinAge = new wxSpinCtrl(this, wxID_ANY); + sizer->Add(m_spinAge, wxSizerFlags().Expand().CenterVertical()); + + wxStaticBoxSizer* const + box = new wxStaticBoxSizer(wxVERTICAL, this, "wxWidgets box"); + box->Add(sizer, wxSizerFlags(1).Expand()); + SetSizer(box); + + // We won't be resized automatically, so set our size ourselves. + SetSize(GetBestSize()); + } + +private: + wxTextCtrl* m_textName; + wxSpinCtrl* m_spinAge; +}; + // ID for the menu quit command #define HELLO_QUIT 1 #define HELLO_NEW 2 @@ -147,6 +181,18 @@ CMainWindow::CMainWindow() LoadAccelTable( wxT("MainAccelTable") ); Create( NULL, wxT("Hello Foundation Application"), WS_OVERLAPPEDWINDOW, rectDefault, NULL, wxT("MainMenu") ); + + // Create a container representing the MFC window in wxWidgets window + // hierarchy. + m_containerWX = new wxNativeContainerWindow(m_hWnd); + + // Now we can create children of this container as usual. + new MyPanel(m_containerWX, wxPoint(5, 5)); + + // An ugly but necessary workaround to prevent the container TLW from + // resizing the panel to fit its entire client area as it would do if it + // were its only child. + new wxWindow(m_containerWX, wxID_ANY, wxPoint(4, 4), wxSize(1, 1)); } void CMainWindow::OnPaint() diff --git a/samples/mfc/mfctest.h b/samples/mfc/mfctest.h index c42f07a41b..2c49911339 100644 --- a/samples/mfc/mfctest.h +++ b/samples/mfc/mfctest.h @@ -26,6 +26,9 @@ public: //}}AFX_MSG DECLARE_MESSAGE_MAP() + +private: + class wxNativeContainerWindow* m_containerWX; }; // A dummy CWnd pointing to a wxWindow's HWND diff --git a/src/msw/nativewin.cpp b/src/msw/nativewin.cpp index 13b8a77efa..b84bb44372 100644 --- a/src/msw/nativewin.cpp +++ b/src/msw/nativewin.cpp @@ -69,11 +69,24 @@ WXLRESULT wxNativeContainerWindow::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) { - if ( nMsg == WM_DESTROY ) + switch ( nMsg ) { - OnNativeDestroyed(); + case WM_CLOSE: + // wxWindow itself, unlike wxFrame, doesn't react to WM_CLOSE and + // just ignores it without even passing it to DefWindowProc(), + // which means that the original WM_CLOSE handler wouldn't be + // called if we didn't explicitly do it here. + return MSWDefWindowProc(nMsg, wParam, lParam); - return 0; + case WM_DESTROY: + // Send it to the original handler which may have some cleanup to + // do as well. Notice that we must do it before calling + // OnNativeDestroyed() as we can't use this object after doing it. + MSWDefWindowProc(nMsg, wParam, lParam); + + OnNativeDestroyed(); + + return 0; } return wxTopLevelWindow::MSWWindowProc(nMsg, wParam, lParam);