Added samples/dll for showing how to use wxWidgets to implement
[wxWidgets.git] / samples / dll / my_dll.cpp
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"
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
47 class MyDllFrame : public wxFrame
48 {
49 public:
50 MyDllFrame(wxWindow *parent, const wxString& label);
51
52 void OnAbout(wxCommandEvent& event);
53
54 DECLARE_EVENT_TABLE()
55 };
56
57
58 static const int CMD_SHOW_WINDOW = wxNewId();
59 static const int CMD_TERMINATE = wxNewId();
60
61 class MyDllApp : public wxApp
62 {
63 public:
64 MyDllApp();
65
66 private:
67 void OnShowWindow(wxThreadEvent& event);
68 void OnTerminate(wxThreadEvent& event);
69 };
70
71
72 // ============================================================================
73 // implementation
74 // ============================================================================
75
76 // ----------------------------------------------------------------------------
77 // MyDllFrame
78 // ----------------------------------------------------------------------------
79
80 BEGIN_EVENT_TABLE(MyDllFrame, wxFrame)
81 EVT_BUTTON(wxID_ABOUT, MyDllFrame::OnAbout)
82 END_EVENT_TABLE()
83
84 MyDllFrame::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
120 void 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
133 MyDllApp::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(wxEVT_IDLE, wxIdleEventHandler(MyDllApp::OnIdle));
151 Connect(CMD_SHOW_WINDOW,
152 wxEVT_COMMAND_THREAD,
153 wxThreadEventHandler(MyDllApp::OnShowWindow));
154 Connect(CMD_TERMINATE,
155 wxEVT_COMMAND_THREAD,
156 wxThreadEventHandler(MyDllApp::OnTerminate));
157 }
158
159 void MyDllApp::OnShowWindow(wxThreadEvent& event)
160 {
161 wxFrame *f = new MyDllFrame(NULL, event.GetString());
162 f->Show(true);
163 }
164
165 void MyDllApp::OnTerminate(wxThreadEvent& WXUNUSED(event))
166 {
167 ExitMainLoop();
168 }
169
170
171 // ----------------------------------------------------------------------------
172 // application startup
173 // ----------------------------------------------------------------------------
174
175 // we can't have WinMain() in a DLL and want to start the app ourselves
176 IMPLEMENT_APP_NO_MAIN(MyDllApp)
177
178 namespace
179 {
180
181 // Critical section that guards everything related to wxWidgets "main" thread
182 // startup or shutdown.
183 wxCriticalSection gs_wxStartupCS;
184 // Handle of wx "main" thread if running, NULL otherwise
185 HANDLE gs_wxMainThread = NULL;
186
187
188 // wx application startup code -- runs from its own thread
189 __stdcall unsigned MyAppLauncher(void* event)
190 {
191 // Note: The thread that called run_wx_gui_from_dll() holds gs_wxStartupCS
192 // at this point and won't release it until we signal it.
193
194 // We need to pass correct HINSTANCE to wxEntry() and the right value is
195 // HINSTANCE of this DLL, not of the main .exe.
196 //
197 // This method of obtaining DLL's instance handle requires at least
198 // Windows XP/2003. We could also implement DllMain() and remember it from
199 // there, that would work on older systems too.
200 HINSTANCE hInstance;
201 int ret = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
202 (LPCTSTR)&MyAppLauncher,
203 &hInstance);
204 if ( ret == 0 )
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
234 extern "C" WXEXPORT
235 void 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_COMMAND_THREAD, CMD_SHOW_WINDOW);
290 event->SetString(title);
291 wxQueueEvent(wxApp::GetInstance(), event);
292 }
293
294
295 extern "C" WXEXPORT
296 void wx_dll_cleanup(void)
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 =
306 new wxThreadEvent(wxEVT_COMMAND_THREAD, CMD_TERMINATE);
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 }