extracted common initialization/cleanup functions in common/init.cpp; standardized...
[wxWidgets.git] / src / common / init.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: common/init.cpp
3 // Purpose: initialisation for the library
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 04.10.99
7 // RCS-ID: $Id$
8 // Copyright: (c) Vadim Zeitlin
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif //__BORLANDC__
25
26 #ifndef WX_PRECOMP
27 #include "wx/app.h"
28 #include "wx/debug.h"
29 #include "wx/filefn.h"
30 #include "wx/log.h"
31 #include "wx/thread.h"
32 #endif
33
34 #include "wx/ptr_scpd.h"
35 #include "wx/module.h"
36
37 #if defined(__WXMSW__) && defined(__WXDEBUG__)
38 #include "wx/msw/msvcrt.h"
39
40 static struct EnableMemLeakChecking
41 {
42 EnableMemLeakChecking()
43 {
44 // do check for memory leaks on program exit (another useful flag
45 // is _CRTDBG_DELAY_FREE_MEM_DF which doesn't free deallocated
46 // memory which may be used to simulate low-memory condition)
47 wxCrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF);
48 }
49 } gs_enableLeakChecks;
50 #endif // __WXMSW__ && __WXDEBUG__
51
52 // ----------------------------------------------------------------------------
53 // private classes
54 // ----------------------------------------------------------------------------
55
56 // we need a dummy app object if the user doesn't want to create a real one
57 class wxDummyConsoleApp : public wxAppConsole
58 {
59 public:
60 virtual int OnRun() { wxFAIL_MSG( _T("unreachable code") ); return 0; }
61 };
62
63 // we need a special kind of auto pointer to wxApp which not only deletes the
64 // pointer it holds in its dtor but also resets wxTheApp
65 wxDECLARE_SCOPED_PTR(wxApp, wxAppPtrBase);
66 wxDEFINE_SCOPED_PTR(wxApp, wxAppPtrBase);
67
68 class wxAppPtr : public wxAppPtrBase
69 {
70 public:
71 wxEXPLICIT wxAppPtr(wxApp *ptr = NULL) : wxAppPtrBase(ptr) { }
72 ~wxAppPtr()
73 {
74 if ( get() )
75 {
76 // the pointer is going to be deleted in the base class dtor, don't
77 // leave the dangling pointer!
78 wxTheApp = NULL;
79 }
80 }
81
82 void Set(wxApp *ptr)
83 {
84 reset(ptr);
85
86 wxTheApp = ptr;
87 }
88 };
89
90 // another tiny class which simply exists to ensure that wxEntryCleanup is
91 // always called
92 class wxCleanupOnExit
93 {
94 public:
95 ~wxCleanupOnExit() { wxEntryCleanup(); }
96 };
97
98 // ----------------------------------------------------------------------------
99 // initialization data
100 // ----------------------------------------------------------------------------
101
102 static struct InitData
103 {
104 InitData()
105 {
106 nInitCount = 0;
107
108 #if wxUSE_UNICODE
109 argc = 0;
110 // argv = NULL; -- not even really needed
111 #endif // wxUSE_UNICODE
112 }
113
114 // critical section protecting this struct
115 wxCRIT_SECT_DECLARE_MEMBER(csInit);
116
117 // number of times wxInitialize() was called minus the number of times
118 // wxUninitialize() was
119 size_t nInitCount;
120
121 #if wxUSE_UNICODE
122 int argc;
123
124 // if we receive the command line arguments as ASCII and have to convert
125 // them to Unicode ourselves (this is the case under Unix but not Windows,
126 // for example), we remember the converted argv here because we'll have to
127 // free it when doing cleanup to avoid memory leaks
128 wchar_t *argv;
129 #endif // wxUSE_UNICODE
130 } gs_initData;
131
132 // ============================================================================
133 // implementation
134 // ============================================================================
135
136 // ----------------------------------------------------------------------------
137 // command line arguments ANSI -> Unicode conversion
138 // ----------------------------------------------------------------------------
139
140 #if wxUSE_UNICODE
141
142 static void ConvertArgsToUnicode(int argc, char **argv)
143 {
144 gs_initData.argv = new wchar_t *[argc + 1];
145 for ( int i = 0; i < argc; i++ )
146 {
147 gs_initData.argv[i] = wxStrdup(wxConvLocal.cMB2WX(argv[i]));
148 }
149
150 gs_initData.argv[argc] = NULL;
151 }
152
153 static void FreeConvertedArgs()
154 {
155 for ( int mb_argc = 0; mb_argc < wxTheApp->argc; mb_argc++ )
156 {
157 free(wxTheApp->argv[mb_argc]);
158 }
159 }
160
161 #endif // wxUSE_UNICODE
162
163 // ----------------------------------------------------------------------------
164 // start up
165 // ----------------------------------------------------------------------------
166
167 // initialization which is always done (not customizable) before wxApp creation
168 static bool DoCommonPreInit()
169 {
170 wxClassInfo::InitializeClasses();
171
172 return true;
173 }
174
175 // non customizable initialization done after wxApp creation and initialization
176 static bool DoCommonPostInit()
177 {
178 wxModule::RegisterModules();
179
180 return wxModule::InitializeModules();
181 }
182
183 bool wxEntryStart(int argc, wxChar **argv)
184 {
185 // do minimal, always necessary, initialization
186 // --------------------------------------------
187
188 // initialize wxRTTI
189 if ( !DoCommonPreInit() )
190 {
191 return false;
192 }
193
194
195 // first of all, we need an application object
196 // -------------------------------------------
197
198 // the user might have already created it himself somehow
199 wxAppPtr app(wxTheApp);
200 if ( !app.get() )
201 {
202 // if not, he might have used IMPLEMENT_APP() to give us a function to
203 // create it
204 wxAppInitializerFunction fnCreate = wxApp::GetInitializerFunction();
205
206 if ( fnCreate )
207 {
208 // he did, try to create the custom wxApp object
209 app.Set((*fnCreate)());
210 }
211 }
212
213 if ( !app.get() )
214 {
215 // either IMPLEMENT_APP() was not used at all or it failed -- in any
216 // case we still need something
217 //
218 // NB: cast is needed because for the backwards-compatibility reasons
219 // wxTheApp is really a wxApp and not just wxAppConsole...
220 app.Set((wxApp *)new wxDummyConsoleApp);
221 }
222
223
224 // wxApp initialization: this can be customized
225 // --------------------------------------------
226
227 if ( !wxTheApp->Initialize(argc, argv) )
228 {
229 return false;
230 }
231
232
233 // common initialization after wxTheApp creation
234 // ---------------------------------------------
235
236 if ( !DoCommonPostInit() )
237 {
238 return false;
239 }
240
241
242 // prevent the smart pointer from destroying its contents
243 app.release();
244
245 return true;
246 }
247
248 #if wxUSE_UNICODE
249
250 // we provide a wxEntryStart() wrapper taking "char *" pointer too
251 bool wxEntryStart(int argc, char **argv)
252 {
253 ConvertArgsToUnicode(argc, argv);
254
255 if ( !wxEntryStart(argc, gs_initData.argv) )
256 {
257 FreeConvertedArgs();
258
259 return false;
260 }
261
262 return true;
263 }
264
265 #endif // wxUSE_UNICODE
266
267 // ----------------------------------------------------------------------------
268 // clean up
269 // ----------------------------------------------------------------------------
270
271 // cleanup done before destroying wxTheApp
272 static void DoCommonPreCleanup()
273 {
274 #if wxUSE_LOG
275 // flush the logged messages if any and install a 'safer' log target: the
276 // default one (wxLogGui) can't be used after the resources are freed just
277 // below and the user supplied one might be even more unsafe (using any
278 // wxWindows GUI function is unsafe starting from now)
279 wxLog::DontCreateOnDemand();
280
281 // this will flush the old messages if any
282 delete wxLog::SetActiveTarget(new wxLogStderr);
283 #endif // wxUSE_LOG
284
285 wxModule::CleanUpModules();
286 }
287
288 // cleanup done after destroying wxTheApp
289 static void DoCommonPostCleanup()
290 {
291 wxClassInfo::CleanUpClasses();
292
293 // we can't do this in wxApp itself because it doesn't know if argv had
294 // been allocated
295 #if wxUSE_UNICODE
296 FreeConvertedArgs();
297 #endif // wxUSE_UNICODE
298
299 #if wxUSE_LOG
300 // and now delete the last logger as well
301 delete wxLog::SetActiveTarget(NULL);
302 #endif // wxUSE_LOG
303 }
304
305 void wxEntryCleanup()
306 {
307 DoCommonPreCleanup();
308
309
310 // delete the application object
311 if ( wxTheApp )
312 {
313 wxTheApp->CleanUp();
314
315 delete wxTheApp;
316 wxTheApp = NULL;
317 }
318
319
320 DoCommonPostCleanup();
321
322 // check for memory leaks
323 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
324 if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
325 {
326 wxLogDebug(wxT("There were memory leaks.\n"));
327 wxDebugContext::Dump();
328 wxDebugContext::PrintStatistics();
329 }
330 #endif // Debug
331
332 }
333
334 // ----------------------------------------------------------------------------
335 // wxEntry
336 // ----------------------------------------------------------------------------
337
338 #if !defined(__WXMSW__) || !wxUSE_ON_FATAL_EXCEPTION
339 #define wxEntryReal wxEntry
340 #endif // !(__WXMSW__ && wxUSE_ON_FATAL_EXCEPTION)
341
342 int wxEntryReal(int argc, wxChar **argv)
343 {
344 // library initialization
345 if ( !wxEntryStart(argc, argv) )
346 {
347 return -1;
348 }
349
350 // if wxEntryStart succeeded, we must call wxEntryCleanup even if the code
351 // below returns or throws
352 wxCleanupOnExit cleanupOnExit;
353
354 // app initialization
355 if ( !wxTheApp->OnInit() )
356 {
357 // don't call OnExit() if OnInit() failed
358 return -1;
359 }
360
361 // app execution
362 int retValue = wxTheApp->OnRun();
363
364 // why should we do this? it doesn't close all window, just one of them and
365 // this shouldn't be necessary anyhow...
366 #if 0
367 // close any remaining windows
368 wxWindow *topWindow = wxTheApp->GetTopWindow();
369 if ( topWindow )
370 {
371 // forcibly delete the window.
372 topWindow->Destroy();
373
374 // collect the dead objects
375 wxTheApp->DeletePendingObjects();
376 }
377 #endif // 0
378
379 // app clean up
380 wxTheApp->OnExit();
381
382 return retValue;
383 }
384
385 // wrap real wxEntry in a try-except block to be able to call
386 // OnFatalException() if necessary
387 #if defined(__WXMSW__) && wxUSE_ON_FATAL_EXCEPTION
388
389 extern unsigned long wxGlobalSEHandler();
390
391 int wxEntry(int argc, wxChar **argv)
392 {
393 __try
394 {
395 return wxEntryReal(argc, argv);
396 }
397 __except ( wxGlobalSEHandler() )
398 {
399 ::ExitProcess(3); // the same exit code as abort()
400
401 // this code is unreachable but put it here to suppress warnings
402 return -1;
403 }
404 }
405
406 #endif // __WXMSW__ && wxUSE_ON_FATAL_EXCEPTION
407
408 #if wxUSE_UNICODE
409
410 // as with wxEntryStart, we provide an ANSI wrapper
411 int wxEntry(int argc, char **argv)
412 {
413 ConvertArgsToUnicode(argc, argv);
414
415 return wxEntry(argc, gs_initData.argv);
416 }
417
418 #endif // wxUSE_UNICODE
419
420 // ----------------------------------------------------------------------------
421 // wxInitialize/wxUninitialize
422 // ----------------------------------------------------------------------------
423
424 bool wxInitialize(int argc, wxChar **argv)
425 {
426 wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit);
427
428 if ( gs_initData.nInitCount++ )
429 {
430 // already initialized
431 return true;
432 }
433
434 return wxEntryStart(argc, argv);
435 }
436
437 void wxUninitialize()
438 {
439 wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit);
440
441 if ( !--gs_initData.nInitCount )
442 {
443 wxEntryCleanup();
444 }
445 }
446