Opened 5 years ago

Last modified 5 years ago

#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: stable-latest
Keywords: Destroy(), EVT_WINDOW_DESTROY, Plugin, DLL Cc:
Blocked By: Blocking:
Patch: no

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

}

code

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

Change History (8)

comment:1 Changed 5 years ago by slytron

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 http://www.tronacom.com/downloads/TestWxWidgetHostAndPlugin.rar

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

}

/code

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

comment:2 Changed 5 years ago by slytron

sorry about the double post.. I tried to fix the download link

http://www.tronacom.com/downloads/TestWxWidgetHostAndPlugin.rar

Also I have tried it with the current 2.9 release and the problem exists in it also

comment:3 Changed 5 years ago by vadz

  • Priority changed from high to normal
  • Status changed from new to infoneeded_new
  • Version changed from 2.8.10 to 2.9-svn

Sorry, I'm unable to read/debug all this code and I don't think anybody else can do it either. We need a small patch to a sample allowing to reproduce the problem, we can't really do anything about the problem without it.

comment:4 Changed 5 years ago by slytron

  • Status changed from infoneeded_new to new

there are no samples that use wxWidgit's wxFrame or wxDialog in a dll so a patch is not possible unless I missed something. I did make a new project with the minimum needed to reproduce the problem. the parent frame in the dll calls the OnClose when the the user presses the close button in the title bar but calling destroy in the OnClose does not destroy the window. child windows created when the "Open Child" button on the parent frame is pressed do work correctly.

CODE FOR EXE

#include "wx/wx.h"
typedef _declspec(dllexport) void (_cdecl*FUNC_TEST_PLUGIN) ( void );
class CWidgetsHostDlg : public wxFrame
{
public:
	CWidgetsHostDlg( void );// constructor
	FUNC_TEST_PLUGIN fnTestPluginDll;
	DECLARE_EVENT_TABLE()
};
CWidgetsHostDlg::CWidgetsHostDlg( void )
	: wxFrame(  NULL,	// parent
				wxID_ANY,	// id
				wxString(_("App Host")),
				wxDefaultPosition,
				wxSize(200,200),
				wxCAPTION |wxSYSTEM_MENU | wxCLOSE_BOX)
{
	std::string strDllFileName = "WidgetsDll.dll";
	HMODULE hModule = LoadLibrary( strDllFileName.c_str() );
	fnTestPluginDll = (FUNC_TEST_PLUGIN)GetProcAddress(	hModule,
														"TestDllStartup" );
	fnTestPluginDll();
}
BEGIN_EVENT_TABLE(CWidgetsHostDlg, wxFrame)
END_EVENT_TABLE()
class CWidgetsHostApp : public wxApp
{
	bool OnInit();
	DECLARE_EVENT_TABLE()
};
IMPLEMENT_APP(CWidgetsHostApp)
BEGIN_EVENT_TABLE(CWidgetsHostApp, wxApp)
END_EVENT_TABLE()
bool CWidgetsHostApp::OnInit()
{
	CWidgetsHostDlg * poDlg = new CWidgetsHostDlg();
	poDlg->Show();
	return true;
}

CODE FOR DLL

#include "wx/wx.h"
WXDLLIMPEXP_BASE void wxSetInstance(HINSTANCE hInst);
class CMyAppInDll : public wxApp 
{ 
public: 
	bool OnInit(){return true;} 
}; 
IMPLEMENT_APP_NO_MAIN(CMyAppInDll) 
DECLARE_APP(CMyAppInDll) 
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) || 
                !wxTheApp || 
                !wxTheApp->CallOnInit()) 
        { 
                return FALSE; 
        } 
    } 
    return TRUE; 
} 
class CWxWidgetsChildInDll : public wxFrame
{
public: 
	CWxWidgetsChildInDll(wxWindow * pParent);
    DECLARE_EVENT_TABLE()
	void OnClose( wxCloseEvent& oEvent );
};
BEGIN_EVENT_TABLE(CWxWidgetsChildInDll, wxFrame)
	EVT_CLOSE( CWxWidgetsChildInDll::OnClose)
END_EVENT_TABLE()
CWxWidgetsChildInDll::CWxWidgetsChildInDll(wxWindow * pParent)
	: wxFrame( NULL,	// parent
				wxID_ANY,	// id
				wxString(wxT("wxWidgets in DLL Child Dialog")),
				wxPoint( 10, 10 ), 
				wxSize(300,300),
				wxCAPTION |wxSYSTEM_MENU | wxCLOSE_BOX )
{
}
void CWxWidgetsChildInDll::OnClose( wxCloseEvent& oEvent )
{
	Destroy(); //<--- this destroy DOES work
}

class CWxWidgetsParentInDll : public wxFrame
{
public: 
	CWxWidgetsParentInDll();
	wxButton	m_oOpenNewChildBut;
    DECLARE_EVENT_TABLE()
	void OnButton( wxCommandEvent& oEvent );
	void OnClose( wxCloseEvent& oEvent );
};
BEGIN_EVENT_TABLE(CWxWidgetsParentInDll, wxFrame)
	EVT_BUTTON( 2000, CWxWidgetsParentInDll::OnButton)
	EVT_CLOSE( CWxWidgetsParentInDll::OnClose)
END_EVENT_TABLE()
CWxWidgetsParentInDll::CWxWidgetsParentInDll()
	: wxFrame( NULL,	// parent
				wxID_ANY,	// id
				wxString(wxT("wxWidgets in DLL Parent")),
				wxPoint( 10, 10 ), 
				wxSize(300,300),
				wxCAPTION |wxSYSTEM_MENU | wxCLOSE_BOX )
	, m_oOpenNewChildBut(this, 2000, "Open Child", wxPoint( 10, 10 ), wxSize( 80, 50 ))
{
}
void CWxWidgetsParentInDll::OnButton( wxCommandEvent& oEvent )
{
	CWxWidgetsChildInDll * poNewChild = new CWxWidgetsChildInDll(this);
	poNewChild->Show();
}
void CWxWidgetsParentInDll::OnClose( wxCloseEvent& oEvent )
{
	Destroy(); //<--- this destroy DOES NOT work
}
//=== plugin supplied functions ===//
extern "C"
{
__declspec(dllimport)	void TestDllStartup( void );
};
void TestDllStartup( void )
{
	CWxWidgetsParentInDll * poDlg = new CWxWidgetsParentInDll();
	poDlg->Show();
}

comment:5 Changed 5 years ago by slytron

Additional information. I did some more testing. different combinations of child and parent frames etc. I turns out that it is the last visible frame that cannot be destroyed so I thought well I will just make a empty frame and hide it and so everthing visible will work right but it is the last visible frame that cannot be destroyed instead of the last window created in the dll. so creating a hidden window as a work around did not work :(

comment:6 Changed 5 years ago by slytron

Found a workaround. In the OnInit of wxApp in the dll create a wxDialog and set its size to wxPoint(0,0).

comment:7 Changed 5 years ago by slytron

For people who want to use wxWidgets dialogs or frames in a DLL here is my workaround for the bug

//------------------------------------------------------------------------------
// wxWidgets initialize
//------------------------------------------------------------------------------
//Start Workaround for wxWidgets Bug #11496
class WxWidgetsBugWorkaround : public wxFrame
{ public: 
WxWidgetsBugWorkaround():wxFrame(NULL,wxID_ANY,"WidgetBugDlgBilliards",wxDefaultPosition,wxSize(0,0), WS_EX_TOOLWINDOW){}
	DECLARE_EVENT_TABLE()
};
BEGIN_EVENT_TABLE(WxWidgetsBugWorkaround, wxFrame)
END_EVENT_TABLE()
//End Workaround for wxWidgets Bug #11496

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) 
        { 
			wxSetInstance((HINSTANCE)hModule); 
            int argc = 0; 
            char** argv = NULL; 
            if(!wxEntryStart(argc, argv) || 
                        !wxTheApp || 
                        !wxTheApp->CallOnInit()) 
            { 
                return FALSE; 
            } 
        } 
        
        return TRUE; 
} 

bool CMyApp::OnInit() 
{
	//Start Workaround for wxWidgets Bug #11496
	WxWidgetsBugWorkaround * pBugDlg = new WxWidgetsBugWorkaround();
	// dont show window on taskbar
	SetWindowLong((HWND)pBugDlg->GetHWND(), GWL_EXSTYLE, (GetWindowLong((HWND)pBugDlg->GetHWND(),GWL_EXSTYLE) | WS_EX_TOOLWINDOW) & ~WS_EX_APPWINDOW);
	pBugDlg->Show();
	//End Workaround for wxWidgets Bug #11496
    wxImage::AddHandler(new wxPNGHandler);
    wxImage::AddHandler(new wxJPEGHandler );   // use only when needed, otherwise big .exe's
    wxImage::AddHandler( new wxICOHandler );   // use only when needed, otherwise big .exe's

    return true; 
}; 


comment:8 Changed 5 years ago by vadz

  • Status changed from new to infoneeded_new

We do have a sample of a wx DLL now (samples/dll), please try to reproduce the problem in it.

TIA!

Note: See TracTickets for help on using tickets.