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