]> git.saurik.com Git - wxWidgets.git/blob - samples/dll/my_dll.cpp
Use more readable wxListCtrl::AppendColumn() in the samples.
[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 __WINDOWS__
26 #error "This sample is Windows-only"
27 #endif
28
29 #include "wx/app.h"
30 #include "wx/dynlib.h"
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
48 class MyDllFrame : public wxFrame
49 {
50 public:
51 MyDllFrame(wxWindow *parent, const wxString& label);
52
53 void OnAbout(wxCommandEvent& event);
54
55 DECLARE_EVENT_TABLE()
56 };
57
58
59 static const int CMD_SHOW_WINDOW = wxNewId();
60 static const int CMD_TERMINATE = wxNewId();
61
62 class MyDllApp : public wxApp
63 {
64 public:
65 MyDllApp();
66
67 private:
68 void OnShowWindow(wxThreadEvent& event);
69 void OnTerminate(wxThreadEvent& event);
70 };
71
72
73 // ============================================================================
74 // implementation
75 // ============================================================================
76
77 // ----------------------------------------------------------------------------
78 // MyDllFrame
79 // ----------------------------------------------------------------------------
80
81 BEGIN_EVENT_TABLE(MyDllFrame, wxFrame)
82 EVT_BUTTON(wxID_ABOUT, MyDllFrame::OnAbout)
83 END_EVENT_TABLE()
84
85 MyDllFrame::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
121 void 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
134 MyDllApp::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(CMD_SHOW_WINDOW,
152 wxEVT_THREAD,
153 wxThreadEventHandler(MyDllApp::OnShowWindow));
154 Connect(CMD_TERMINATE,
155 wxEVT_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 unsigned wxSTDCALL 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, use this MSW-specific wx
196 // function to get it. Notice that under Windows XP and later the name is
197 // not needed/used as we retrieve the DLL handle from an address inside it
198 // but you do need to use the correct name for this code to work with older
199 // systems as well.
200 const HINSTANCE
201 hInstance = wxDynamicLibrary::MSWGetModuleHandle("my_dll",
202 &gs_wxMainThread);
203 if ( !hInstance )
204 return 0; // failed to get DLL's handle
205
206 // IMPLEMENT_WXWIN_MAIN does this as the first thing
207 wxDISABLE_DEBUG_SUPPORT();
208
209 // We do this before wxEntry() explicitly, even though wxEntry() would
210 // do it too, so that we know when wx is initialized and can signal
211 // run_wx_gui_from_dll() about it *before* starting the event loop.
212 wxInitializer wxinit;
213 if ( !wxinit.IsOk() )
214 return 0; // failed to init wx
215
216 // Signal run_wx_gui_from_dll() that it can continue
217 HANDLE hEvent = *(static_cast<HANDLE*>(event));
218 if ( !SetEvent(hEvent) )
219 return 0; // failed setting up the mutex
220
221 // Run the app:
222 wxEntry(hInstance);
223
224 return 1;
225 }
226
227 } // anonymous namespace
228
229 // ----------------------------------------------------------------------------
230 // public DLL interface
231 // ----------------------------------------------------------------------------
232
233 extern "C"
234 {
235
236 void run_wx_gui_from_dll(const char *title)
237 {
238 // In order to prevent conflicts with hosting app's event loop, we
239 // launch wx app from the DLL in its own thread.
240 //
241 // We can't even use wxInitializer: it initializes wxModules and one of
242 // the modules it handles is wxThread's private module that remembers
243 // ID of the main thread. But we need to fool wxWidgets into thinking that
244 // the thread we are about to create now is the main thread, not the one
245 // from which this function is called.
246 //
247 // Note that we cannot use wxThread here, because the wx library wasn't
248 // initialized yet. wxCriticalSection is safe to use, though.
249
250 wxCriticalSectionLocker lock(gs_wxStartupCS);
251
252 if ( !gs_wxMainThread )
253 {
254 HANDLE hEvent = CreateEvent
255 (
256 NULL, // default security attributes
257 FALSE, // auto-reset
258 FALSE, // initially non-signaled
259 NULL // anonymous
260 );
261 if ( !hEvent )
262 return; // error
263
264 // NB: If your compiler doesn't have _beginthreadex(), use CreateThread()
265 gs_wxMainThread = (HANDLE)_beginthreadex
266 (
267 NULL, // default security
268 0, // default stack size
269 &MyAppLauncher,
270 &hEvent, // arguments
271 0, // create running
272 NULL
273 );
274
275 if ( !gs_wxMainThread )
276 {
277 CloseHandle(hEvent);
278 return; // error
279 }
280
281 // Wait until MyAppLauncher signals us that wx was initialized. This
282 // is because we use wxMessageQueue<> and wxString later and so must
283 // be sure that they are in working state.
284 WaitForSingleObject(hEvent, INFINITE);
285 CloseHandle(hEvent);
286 }
287
288 // Send a message to wx thread to show a new frame:
289 wxThreadEvent *event =
290 new wxThreadEvent(wxEVT_THREAD, CMD_SHOW_WINDOW);
291 event->SetString(title);
292 wxQueueEvent(wxApp::GetInstance(), event);
293 }
294
295 void wx_dll_cleanup()
296 {
297 wxCriticalSectionLocker lock(gs_wxStartupCS);
298
299 if ( !gs_wxMainThread )
300 return;
301
302 // If wx main thread is running, we need to stop it. To accomplish this,
303 // send a message telling it to terminate the app.
304 wxThreadEvent *event =
305 new wxThreadEvent(wxEVT_THREAD, CMD_TERMINATE);
306 wxQueueEvent(wxApp::GetInstance(), event);
307
308 // We must then wait for the thread to actually terminate.
309 WaitForSingleObject(gs_wxMainThread, INFINITE);
310 CloseHandle(gs_wxMainThread);
311 gs_wxMainThread = NULL;
312 }
313
314 } // extern "C"