]> git.saurik.com Git - wxWidgets.git/blame_incremental - samples/dll/my_dll.cpp
wxMessageBox off the main thread lost result code.
[wxWidgets.git] / samples / dll / my_dll.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: my_dll.cpp
3// Purpose: Sample showing how to use wx from a DLL
4// Author: Vaclav Slavik
5// Created: 2009-12-03
6// Copyright: (c) 2009 Vaclav Slavik
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
10// ============================================================================
11// declarations
12// ============================================================================
13
14// ----------------------------------------------------------------------------
15// headers
16// ----------------------------------------------------------------------------
17
18#include "wx/wxprec.h"
19
20#ifdef __BORLANDC__
21 #pragma hdrstop
22#endif
23
24#ifndef __WINDOWS__
25 #error "This sample is Windows-only"
26#endif
27
28#include "wx/app.h"
29#include "wx/dynlib.h"
30#include "wx/frame.h"
31#include "wx/panel.h"
32#include "wx/sizer.h"
33#include "wx/stattext.h"
34#include "wx/button.h"
35#include "wx/thread.h"
36#include "wx/msgdlg.h"
37#include "wx/msw/wrapwin.h"
38
39#include <process.h> // for _beginthreadex()
40
41#include "my_dll.h"
42
43// ----------------------------------------------------------------------------
44// GUI classes
45// ----------------------------------------------------------------------------
46
47class MyDllFrame : public wxFrame
48{
49public:
50 MyDllFrame(wxWindow *parent, const wxString& label);
51
52 void OnAbout(wxCommandEvent& event);
53
54 DECLARE_EVENT_TABLE()
55};
56
57
58static const int CMD_SHOW_WINDOW = wxNewId();
59static const int CMD_TERMINATE = wxNewId();
60
61class MyDllApp : public wxApp
62{
63public:
64 MyDllApp();
65
66private:
67 void OnShowWindow(wxThreadEvent& event);
68 void OnTerminate(wxThreadEvent& event);
69};
70
71
72// ============================================================================
73// implementation
74// ============================================================================
75
76// ----------------------------------------------------------------------------
77// MyDllFrame
78// ----------------------------------------------------------------------------
79
80BEGIN_EVENT_TABLE(MyDllFrame, wxFrame)
81 EVT_BUTTON(wxID_ABOUT, MyDllFrame::OnAbout)
82END_EVENT_TABLE()
83
84MyDllFrame::MyDllFrame(wxWindow *parent, const wxString& label)
85 : wxFrame(parent, wxID_ANY, label)
86{
87 wxPanel *p = new wxPanel(this, wxID_ANY);
88 wxSizer *sizer = new wxBoxSizer(wxVERTICAL);
89
90 sizer->Add
91 (
92 new wxStaticText
93 (
94 p, wxID_ANY,
95 wxString::Format
96 (
97 "Running using %s\n"
98 "wxApp instance is %p, thread ID %ld",
99 wxVERSION_STRING,
100 wxApp::GetInstance(),
101 wxThread::GetCurrentId()
102 )
103 ),
104 wxSizerFlags(1).Expand().Border(wxALL, 10)
105 );
106
107 sizer->Add
108 (
109 new wxButton(p, wxID_ABOUT, "Show info"),
110 wxSizerFlags(0).Right().Border(wxALL, 10)
111 );
112
113 p->SetSizerAndFit(sizer);
114
115 wxSizer *fsizer = new wxBoxSizer(wxVERTICAL);
116 fsizer->Add(p, wxSizerFlags(1).Expand());
117 SetSizerAndFit(fsizer);
118}
119
120void MyDllFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
121{
122 wxMessageBox("This window is running in its own thread,\n"
123 "using private wxWidgets instance compiled into the DLL.",
124 "About",
125 wxOK | wxICON_INFORMATION);
126}
127
128
129// ----------------------------------------------------------------------------
130// MyDllApp
131// ----------------------------------------------------------------------------
132
133MyDllApp::MyDllApp()
134{
135 // Keep the wx "main" thread running even without windows. This greatly
136 // simplifies threads handling, because we don't have to correctly
137 // implement wx-thread restarting.
138 //
139 // Note that this only works if you don't explicitly call ExitMainLoop(),
140 // except in reaction to wx_dll_cleanup()'s message. wx_dll_cleanup()
141 // relies on the availability of wxApp instance and if the event loop
142 // terminated, wxEntry() would return and wxApp instance would be
143 // destroyed.
144 //
145 // Also note that this is efficient, because if there are no windows, the
146 // thread will sleep waiting for a new event. We could safe some memory
147 // by shutting the thread down when it's no longer needed, though.
148 SetExitOnFrameDelete(false);
149
150 Connect(CMD_SHOW_WINDOW,
151 wxEVT_THREAD,
152 wxThreadEventHandler(MyDllApp::OnShowWindow));
153 Connect(CMD_TERMINATE,
154 wxEVT_THREAD,
155 wxThreadEventHandler(MyDllApp::OnTerminate));
156}
157
158void MyDllApp::OnShowWindow(wxThreadEvent& event)
159{
160 wxFrame *f = new MyDllFrame(NULL, event.GetString());
161 f->Show(true);
162}
163
164void MyDllApp::OnTerminate(wxThreadEvent& WXUNUSED(event))
165{
166 ExitMainLoop();
167}
168
169
170// ----------------------------------------------------------------------------
171// application startup
172// ----------------------------------------------------------------------------
173
174// we can't have WinMain() in a DLL and want to start the app ourselves
175IMPLEMENT_APP_NO_MAIN(MyDllApp)
176
177namespace
178{
179
180// Critical section that guards everything related to wxWidgets "main" thread
181// startup or shutdown.
182wxCriticalSection gs_wxStartupCS;
183// Handle of wx "main" thread if running, NULL otherwise
184HANDLE gs_wxMainThread = NULL;
185
186
187// wx application startup code -- runs from its own thread
188unsigned wxSTDCALL MyAppLauncher(void* event)
189{
190 // Note: The thread that called run_wx_gui_from_dll() holds gs_wxStartupCS
191 // at this point and won't release it until we signal it.
192
193 // We need to pass correct HINSTANCE to wxEntry() and the right value is
194 // HINSTANCE of this DLL, not of the main .exe, use this MSW-specific wx
195 // function to get it. Notice that under Windows XP and later the name is
196 // not needed/used as we retrieve the DLL handle from an address inside it
197 // but you do need to use the correct name for this code to work with older
198 // systems as well.
199 const HINSTANCE
200 hInstance = wxDynamicLibrary::MSWGetModuleHandle("my_dll",
201 &gs_wxMainThread);
202 if ( !hInstance )
203 return 0; // failed to get DLL's handle
204
205 // IMPLEMENT_WXWIN_MAIN does this as the first thing
206 wxDISABLE_DEBUG_SUPPORT();
207
208 // We do this before wxEntry() explicitly, even though wxEntry() would
209 // do it too, so that we know when wx is initialized and can signal
210 // run_wx_gui_from_dll() about it *before* starting the event loop.
211 wxInitializer wxinit;
212 if ( !wxinit.IsOk() )
213 return 0; // failed to init wx
214
215 // Signal run_wx_gui_from_dll() that it can continue
216 HANDLE hEvent = *(static_cast<HANDLE*>(event));
217 if ( !SetEvent(hEvent) )
218 return 0; // failed setting up the mutex
219
220 // Run the app:
221 wxEntry(hInstance);
222
223 return 1;
224}
225
226} // anonymous namespace
227
228// ----------------------------------------------------------------------------
229// public DLL interface
230// ----------------------------------------------------------------------------
231
232extern "C"
233{
234
235void run_wx_gui_from_dll(const char *title)
236{
237 // In order to prevent conflicts with hosting app's event loop, we
238 // launch wx app from the DLL in its own thread.
239 //
240 // We can't even use wxInitializer: it initializes wxModules and one of
241 // the modules it handles is wxThread's private module that remembers
242 // ID of the main thread. But we need to fool wxWidgets into thinking that
243 // the thread we are about to create now is the main thread, not the one
244 // from which this function is called.
245 //
246 // Note that we cannot use wxThread here, because the wx library wasn't
247 // initialized yet. wxCriticalSection is safe to use, though.
248
249 wxCriticalSectionLocker lock(gs_wxStartupCS);
250
251 if ( !gs_wxMainThread )
252 {
253 HANDLE hEvent = CreateEvent
254 (
255 NULL, // default security attributes
256 FALSE, // auto-reset
257 FALSE, // initially non-signaled
258 NULL // anonymous
259 );
260 if ( !hEvent )
261 return; // error
262
263 // NB: If your compiler doesn't have _beginthreadex(), use CreateThread()
264 gs_wxMainThread = (HANDLE)_beginthreadex
265 (
266 NULL, // default security
267 0, // default stack size
268 &MyAppLauncher,
269 &hEvent, // arguments
270 0, // create running
271 NULL
272 );
273
274 if ( !gs_wxMainThread )
275 {
276 CloseHandle(hEvent);
277 return; // error
278 }
279
280 // Wait until MyAppLauncher signals us that wx was initialized. This
281 // is because we use wxMessageQueue<> and wxString later and so must
282 // be sure that they are in working state.
283 WaitForSingleObject(hEvent, INFINITE);
284 CloseHandle(hEvent);
285 }
286
287 // Send a message to wx thread to show a new frame:
288 wxThreadEvent *event =
289 new wxThreadEvent(wxEVT_THREAD, CMD_SHOW_WINDOW);
290 event->SetString(title);
291 wxQueueEvent(wxApp::GetInstance(), event);
292}
293
294void wx_dll_cleanup()
295{
296 wxCriticalSectionLocker lock(gs_wxStartupCS);
297
298 if ( !gs_wxMainThread )
299 return;
300
301 // If wx main thread is running, we need to stop it. To accomplish this,
302 // send a message telling it to terminate the app.
303 wxThreadEvent *event =
304 new wxThreadEvent(wxEVT_THREAD, CMD_TERMINATE);
305 wxQueueEvent(wxApp::GetInstance(), event);
306
307 // We must then wait for the thread to actually terminate.
308 WaitForSingleObject(gs_wxMainThread, INFINITE);
309 CloseHandle(gs_wxMainThread);
310 gs_wxMainThread = NULL;
311}
312
313} // extern "C"