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