Ticket #11496 (infoneeded_new defect)
calling destroy in OnClose does not destroy window if in dll
| Reported by: | slytron | Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | |
| Component: | wxMSW | Version: | 2.9-svn |
| Keywords: | Destroy(), EVT_WINDOW_DESTROY, Plugin, DLL | Cc: | |
| Blocked By: | Patch: | no | |
| Blocking: |
Description
Here is my situation. I am using wxWidgets 2.8.10 in windows XP enviroment and compiling with visual studio 2005. I have a host app with several dlls as plugins (One is a billiards game ). When the X (close window ) button is pressed on the plugin main window I recieve the OnClose and call Destroy() but the window will not destroy or generate event EVT_WINDOW_DESTROY.
Please Help.. I am so close to releasing my open source project :).
Shameless Plug: full source available at http://tronacom.sourceforge.net/
the workaround to force destroy was to delete the window but this causes many other problems. mainly event handlers are called after the window is deleted (for instance: EVT_ACTIVATE and EVT_CHILD_FOCUS )
The test program (visual studio 2005) I created to demonstrate this problem can be downloaded from [url] http://www.tronacom.com/downloads/TestWxWidgetHostAndPlugin.rar[/url]
EDIT: added <-- to code to explain which destroy does not work
here is the code for the host application
[code]// TestWxWidgetsDlg.cpp : implementation file
//
#include "wx/wx.h"
typedef declspec(dllexport) void (_cdecl*FUNC_TEST_PLUGIN_STARTUP) ( wxWindow * poParentWnd );
typedef declspec(dllexport) void (_cdecl*FUNC_TEST_PLUGIN_FUNCTION) ( void );
declspec(dllexport) void _cdecl TestPluginStartup( wxWindow * poParentWnd );
declspec(dllexport) void _cdecl TestPluginFunction( void );
#define IDD_TESTWXWIDGETS_DIALOG 200
#define IDC_TESTWXWIDGETS_STATIC_TEXT 2000
#define IDC_TESTWXWIDGETS_RADIO_BUTTON 2001
#define IDC_TESTWXWIDGETS_CHECK_BOX 2002
#define IDC_TESTWXWIDGETS_URL_CTRL 2003
#define IDC_TESTWXWIDGETS_LIST_CTRL 2004
#define IDC_TESTWXWIDGETS_RICH_TEXT_CTRL 2004
// CTestWxWidgetsDlg dialog
class CTestWxWidgetsDlg : public wxFrame
{
public:
//=== constructor ===//
CTestWxWidgetsDlg(wxWindow * pParent = NULL); // standard constructor
//! load plugin dll and initialize it
void InitializePlugin( void );
//=== vars ===//
FUNC_TEST_PLUGIN_STARTUP m_pfnStartup;
FUNC_TEST_PLUGIN_FUNCTION m_pfnFunction;
wxStopWatch m_oWxFrameTimer;
//=== events ===//
DECLARE_EVENT_TABLE()
void OnKickIdle( wxIdleEvent& oEvent );
};
class TestWxWidgetsApp : public wxApp
{
public:
virtual bool OnInit()
{
CTestWxWidgetsDlg * poFrame = new CTestWxWidgetsDlg();
poFrame->Show();
return 1;
}
};
IMPLEMENT_APP(TestWxWidgetsApp)
BEGIN_EVENT_TABLE(CTestWxWidgetsDlg, wxFrame)
EVT_IDLE( CTestWxWidgetsDlg::OnKickIdle)
END_EVENT_TABLE()
// ----------------------------------------------------------------------------
//=== constructor ===//
CTestWxWidgetsDlg::CTestWxWidgetsDlg( wxWindow * pParent )
: wxFrame( pParent, // parent
IDD_TESTWXWIDGETS_DIALOG, // id
wxString(wxT("Test WxWidgets Host Frame")),
wxPoint( 10, 10 ),
wxSize(300,300),
wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxCAPTION | wxSYSTEM_MENU | wxCLOSE_BOX )
, m_pfnStartup(0)
, m_pfnFunction(0)
{
InitializePlugin();
}
//------------------------------------------------------------------------------
//! load plugin dll and initialize it
void CTestWxWidgetsDlg::InitializePlugin( void )
{
std::string strDllFileName = "TestWxWidgetsPlugin.dll";
HMODULE hModule = LoadLibrary( strDllFileName.c_str() );
if( NULL == hModule )
{
//couldnt load dll
wxMessageBox( "TestWxWidgetsPlugin could not be loaded" );
return;
}
//get test plugin startup function
m_pfnStartup = (FUNC_TEST_PLUGIN_STARTUP)GetProcAddress( hModule,
"TestPluginStartup" );
if( NULL == m_pfnStartup )
{
wxMessageBox( "TestPluginStartup could not be found" );
return;
}
//get test plugin function
m_pfnFunction = (FUNC_TEST_PLUGIN_FUNCTION)GetProcAddress( hModule,
"TestPluginFunction" );
if( NULL == m_pfnFunction )
{
wxMessageBox( "TestPluginFunction could not be found" );
return;
}
m_pfnStartup( this );
m_oWxFrameTimer.Start(0);
}
//---------------------------------------------------------------------------
void CTestWxWidgetsDlg::OnKickIdle( wxIdleEvent& oEvent )
{
//oEvent.Skip();
long s32MilliSec = m_oWxFrameTimer.Time();
//log_msg( 0, "ProcessEventsTimer %d ms\n", s32MilliSec );
if( s32MilliSec >= 15 )
{
m_oWxFrameTimer.Start(0);
if( m_pfnFunction )
{
m_pfnFunction();
}
if( s32MilliSec > 50 )
{
//log_msg( 0, "ProcessEventsTimer Hic up %d ms\n", s32MilliSec );
}
}
else
{
// sleep a bit so we dont hog cpu
wxMilliSleep(1);
}
oEvent.RequestMore( true ); // want more kick idle
}
here is the code for the plugin
[code]
// TestWxWidgetsDll.cpp : Defines the entry point for the DLL application.
//
#include "wx/wx.h"
#include "wx/msw/private.h"
#define IDD_TESTWXWIDGETS_MAIN_FRAME 200
#define IDD_TESTWXWIDGETS_GAME_FRAME 201
#define IDC_TESTWXWIDGETS_START_GAME 2000
#define IDC_TESTWXWIDGETS_END_GAME 2001
class CMyApp : public wxApp
{
public:
bool OnInit();
};
IMPLEMENT_APP_NO_MAIN(CMyApp)
DECLARE_APP(CMyApp)
BOOL APIENTRY DllMain(HMODULE hModule,DWORD Reason,LPVOID)
{
if(Reason==DLL_PROCESS_DETACH)
{
wxEntryCleanup();
}
else if(Reason==DLL_PROCESS_ATTACH)
{
// Here is where wxWidgets Initialize
wxSetInstance((HINSTANCE)hModule);
int argc = 0;
char** argv = NULL;
if( !wxEntryStart(argc, argv) )
{
return FALSE;
}
if( (0 == wxTheApp)
( 0 == wxTheApp->CallOnInit()) )
{
return FALSE;
}
}
return TRUE;
}
bool CMyApp::OnInit()
{
wxImage::AddHandler(new wxPNGHandler);
wxImage::AddHandler(new wxICOHandler ); // use only when needed, otherwise big .exe's
return true;
};
// game window frame
class CTestGameFrameInDll : public wxFrame
{
public:
//=== constructor ===//
CTestGameFrameInDll(wxWindow * pParent = NULL); // standard constructor
//=== methods ===//
void OncePerFrame( void );
//=== vars ===//
BOOL m_bGameStarted;
wxBitmap m_oBmp1;
wxBitmap m_oBmp2;
//=== events ===//
DECLARE_EVENT_TABLE()
void OnClose( wxCloseEvent& oEvent );
};
// ----------------------------------------------------------------------------
//=== constructor ===//
CTestGameFrameInDll::CTestGameFrameInDll( wxWindow * pParent )
: wxFrame( pParent, // parent
IDD_TESTWXWIDGETS_GAME_FRAME, // id
wxString(wxT("Test Game View Frame")),
wxDefaultPosition,
wxSize(300,300),
wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxCAPTION | wxSYSTEM_MENU | wxCLOSE_BOX )
, m_oBmp1( wxT( "image1.png" ), wxBITMAP_TYPE_PNG )
, m_oBmp2( wxT( "image2.png" ), wxBITMAP_TYPE_PNG )
, m_bGameStarted(1)
{
}
BEGIN_EVENT_TABLE(CTestGameFrameInDll, wxFrame)
EVT_CLOSE( CTestGameFrameInDll::OnClose)
END_EVENT_TABLE()
void CTestGameFrameInDll::OncePerFrame( void )
{
static int iTickTock = 0;
iTickTock++;
if( m_bGameStarted )
{
// show alternate images to simulate game running
if( iTickTock & 0x01 )
{
if( m_oBmp1.Ok())
{
wxClientDC dc( this );
dc.DrawBitmap( m_oBmp1, 40, 40 );
}
}
else
{
if( m_oBmp2.Ok())
{
wxClientDC dc( this );
dc.DrawBitmap( m_oBmp2, 40, 40 );
}
}
}
}
// main window frame
class CTestWxWidgetsFrameInDll : public wxFrame
{
public:
//=== constructor ===//
CTestWxWidgetsFrameInDll(wxWindow * pParent = NULL); // standard constructor
//=== methods ===//
void OncePerFrame( void );
//=== vars ===//
CTestGameFrameInDll * m_poGameWindow;
wxButton m_oStartGameBut;
wxButton m_oEndGameBut;
//=== events ===//
DECLARE_EVENT_TABLE()
void OnBnStartGame( wxCommandEvent& oEvent );
void OnBnEndGame( wxCommandEvent& oEvent );
void OnClose( wxCloseEvent& oEvent );
};
BEGIN_EVENT_TABLE(CTestWxWidgetsFrameInDll, wxFrame)
EVT_BUTTON(IDC_TESTWXWIDGETS_START_GAME, CTestWxWidgetsFrameInDll::OnBnStartGame)
EVT_BUTTON(IDC_TESTWXWIDGETS_END_GAME, CTestWxWidgetsFrameInDll::OnBnEndGame)
EVT_CLOSE( CTestWxWidgetsFrameInDll::OnClose)
END_EVENT_TABLE()
// ----------------------------------------------------------------------------
//=== constructor ===//
CTestWxWidgetsFrameInDll::CTestWxWidgetsFrameInDll( wxWindow * pParent )
: wxFrame( pParent, // parent
IDD_TESTWXWIDGETS_MAIN_FRAME, // id
wxString(wxT("Test Game Options Frame")),
wxPoint( 320, 10 ),
wxSize(300,300),
wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxCAPTION | wxSYSTEM_MENU | wxCLOSE_BOX )
, m_oStartGameBut( this,
IDC_TESTWXWIDGETS_START_GAME,
wxString(wxT("Start Game")),
wxPoint( 20, 20 ),
wxSize( 80, 20 ) )
, m_oEndGameBut( this,
IDC_TESTWXWIDGETS_END_GAME,
wxString(wxT("End Game")),
wxPoint( 20, 80 ),
wxSize( 80, 20 ) )
, m_poGameWindow(0)
{
SetBackgroundColour( wxColor( 0x7f, 0xff, 0x7f ) );
}
//------------------------------------------------------------------------------
//! handle start button event
void CTestWxWidgetsFrameInDll::OnBnStartGame( wxCommandEvent& oEvent )
{
if( NULL == m_poGameWindow )
{
m_poGameWindow = new CTestGameFrameInDll( this );
m_poGameWindow->Show();
}
}
//------------------------------------------------------------------------------
//! handle start button event
void CTestWxWidgetsFrameInDll::OnBnEndGame( wxCommandEvent& oEvent )
{
if( m_poGameWindow )
{
m_poGameWindow->Close( true );
m_poGameWindow = NULL;
}
}
//------------------------------------------------------------------------------
void CTestWxWidgetsFrameInDll::OncePerFrame( void )
{
if( m_poGameWindow )
{
m_poGameWindow->OncePerFrame();
}
}
//------------------------------------------------------------------------------
void CTestWxWidgetsFrameInDll::OnClose( wxCloseEvent& oEvent )
{
if( m_poGameWindow )
{
m_poGameWindow->Close( true );
m_poGameWindow = NULL;
}
Destroy(); //<--- this destroy does NOT work
}
CTestWxWidgetsFrameInDll * g_poDlg = 0;
//=== plugin supplied functions ===//
//------------------------------------------------------------------------------
extern "C"
{
declspec(dllimport) void TestPluginStartup( wxWindow * poParentWnd );
declspec(dllimport) void TestPluginFunction( void );
};
void TestPluginStartup( wxWindow * poParentWnd )
{
g_poDlg = new CTestWxWidgetsFrameInDll( poParentWnd );
g_poDlg->Show();
}
void TestPluginFunction( void )
{
if( g_poDlg )
{
g_poDlg->OncePerFrame();
}
}
//---------------------------------------------------------------------------
void CTestGameFrameInDll::OnClose( wxCloseEvent& oEvent )
{
//if( oEvent.CanVeto() )
//{
// oEvent.Veto();
// Shutdown();
// Hide();
//}
//else
//{
m_bGameStarted = false;
if( g_poDlg )
{
g_poDlg->m_poGameWindow = NULL;
}
//destroy
Destroy(); //<--- this destroy DOES work
//}
}
/code
