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