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