1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/common/init.cpp 
   3 // Purpose:     initialisation for the library 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) Vadim Zeitlin 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 #include "wx/wxprec.h" 
  28     #include "wx/filefn.h" 
  31     #include "wx/module.h" 
  35 #include "wx/thread.h" 
  37 #include "wx/scopedptr.h" 
  38 #include "wx/except.h" 
  40 #if defined(__WINDOWS__) 
  41     #include "wx/msw/private.h" 
  42     #include "wx/msw/msvcrt.h" 
  44     #ifdef wxCrtSetDbgFlag 
  45         static struct EnableMemLeakChecking
 
  47             EnableMemLeakChecking() 
  49                 // check for memory leaks on program exit (another useful flag 
  50                 // is _CRTDBG_DELAY_FREE_MEM_DF which doesn't free deallocated 
  51                 // memory which may be used to simulate low-memory condition) 
  52                 wxCrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF
); 
  54         } gs_enableLeakChecks
; 
  55     #endif // wxCrtSetDbgFlag 
  58 // ---------------------------------------------------------------------------- 
  60 // ---------------------------------------------------------------------------- 
  62 // we need a dummy app object if the user doesn't want to create a real one 
  63 class wxDummyConsoleApp 
: public wxAppConsole
 
  66     wxDummyConsoleApp() { } 
  68     virtual int OnRun() { wxFAIL_MSG( wxT("unreachable code") ); return 0; } 
  69     virtual bool DoYield(bool, long) { return true; } 
  71     wxDECLARE_NO_COPY_CLASS(wxDummyConsoleApp
); 
  74 // we need a special kind of auto pointer to wxApp which not only deletes the 
  75 // pointer it holds in its dtor but also resets the global application pointer 
  76 wxDECLARE_SCOPED_PTR(wxAppConsole
, wxAppPtrBase
) 
  77 wxDEFINE_SCOPED_PTR(wxAppConsole
, wxAppPtrBase
) 
  79 class wxAppPtr 
: public wxAppPtrBase
 
  82     wxEXPLICIT 
wxAppPtr(wxAppConsole 
*ptr 
= NULL
) : wxAppPtrBase(ptr
) { } 
  87             // the pointer is going to be deleted in the base class dtor, don't 
  88             // leave the dangling pointer! 
  89             wxApp::SetInstance(NULL
); 
  93     void Set(wxAppConsole 
*ptr
) 
  97         wxApp::SetInstance(ptr
); 
 100     wxDECLARE_NO_COPY_CLASS(wxAppPtr
); 
 103 // class to ensure that wxAppBase::CleanUp() is called if our Initialize() 
 105 class wxCallAppCleanup
 
 108     wxCallAppCleanup(wxAppConsole 
*app
) : m_app(app
) { } 
 109     ~wxCallAppCleanup() { if ( m_app 
) m_app
->CleanUp(); } 
 111     void Dismiss() { m_app 
= NULL
; } 
 117 // ---------------------------------------------------------------------------- 
 119 // ---------------------------------------------------------------------------- 
 121 // suppress warnings about unused variables 
 122 static inline void Use(void *) { } 
 124 #define WX_SUPPRESS_UNUSED_WARN(x) Use(&x) 
 126 // ---------------------------------------------------------------------------- 
 127 // initialization data 
 128 // ---------------------------------------------------------------------------- 
 130 static struct InitData
 
 138         // argv = NULL; -- not even really needed 
 139 #endif // wxUSE_UNICODE 
 142     // critical section protecting this struct 
 143     wxCRIT_SECT_DECLARE_MEMBER(csInit
); 
 145     // number of times wxInitialize() was called minus the number of times 
 146     // wxUninitialize() was 
 152     // if we receive the command line arguments as ASCII and have to convert 
 153     // them to Unicode ourselves (this is the case under Unix but not Windows, 
 154     // for example), we remember the converted argv here because we'll have to 
 155     // free it when doing cleanup to avoid memory leaks 
 157 #endif // wxUSE_UNICODE 
 159     wxDECLARE_NO_COPY_CLASS(InitData
); 
 162 // ============================================================================ 
 164 // ============================================================================ 
 166 // ---------------------------------------------------------------------------- 
 167 // command line arguments ANSI -> Unicode conversion 
 168 // ---------------------------------------------------------------------------- 
 172 static void ConvertArgsToUnicode(int argc
, char **argv
) 
 174     gs_initData
.argv 
= new wchar_t *[argc 
+ 1]; 
 176     for ( int i 
= 0; i 
< argc
; i
++ ) 
 179         wxWCharBuffer 
buf(wxConvFileName
->cMB2WX(argv
[i
])); 
 181         wxWCharBuffer 
buf(wxConvLocal
.cMB2WX(argv
[i
])); 
 185             wxLogWarning(_("Command line argument %d couldn't be converted to Unicode and will be ignored."), 
 190             gs_initData
.argv
[wargc
++] = wxStrdup(buf
); 
 194     gs_initData
.argc 
= wargc
; 
 195     gs_initData
.argv
[wargc
] = NULL
; 
 198 static void FreeConvertedArgs() 
 200     if ( gs_initData
.argv 
) 
 202         for ( int i 
= 0; i 
< gs_initData
.argc
; i
++ ) 
 204             free(gs_initData
.argv
[i
]); 
 207         wxDELETEA(gs_initData
.argv
); 
 208         gs_initData
.argc 
= 0; 
 212 #endif // wxUSE_UNICODE 
 214 // ---------------------------------------------------------------------------- 
 216 // ---------------------------------------------------------------------------- 
 218 // initialization which is always done (not customizable) before wxApp creation 
 219 static bool DoCommonPreInit() 
 222     // Reset logging in case we were cleaned up and are being reinitialized. 
 223     wxLog::DoCreateOnDemand(); 
 225     // force wxLog to create a log target now: we do it because wxTheApp 
 226     // doesn't exist yet so wxLog will create a special log target which is 
 227     // safe to use even when the GUI is not available while without this call 
 228     // we could create wxApp in wxEntryStart() below, then log an error about 
 229     // e.g. failure to establish connection to the X server and wxLog would 
 230     // send it to wxLogGui (because wxTheApp does exist already) which, of 
 231     // course, can't be used in this case 
 233     // notice also that this does nothing if the user had set up a custom log 
 234     // target before -- which is fine as we want to give him this possibility 
 235     // (as it's impossible to override logging by overriding wxAppTraits:: 
 236     // CreateLogTarget() before wxApp is created) and we just assume he knows 
 238     wxLog::GetActiveTarget(); 
 242     // GUI applications obtain HINSTANCE in their WinMain() but we also need to 
 243     // initialize the global wxhInstance variable for the console programs as 
 244     // they may need it too, so set it here if it wasn't done yet 
 245     if ( !wxGetInstance() ) 
 247         wxSetInstance(::GetModuleHandle(NULL
)); 
 249 #endif // __WINDOWS__ 
 254 // non customizable initialization done after wxApp creation and initialization 
 255 static bool DoCommonPostInit() 
 257     wxModule::RegisterModules(); 
 259     if ( !wxModule::InitializeModules() ) 
 261         wxLogError(_("Initialization failed in post init, aborting.")); 
 268 bool wxEntryStart(int& argc
, wxChar 
**argv
) 
 270     // do minimal, always necessary, initialization 
 271     // -------------------------------------------- 
 274     if ( !DoCommonPreInit() ) 
 278     // first of all, we need an application object 
 279     // ------------------------------------------- 
 281     // the user might have already created it himself somehow 
 282     wxAppPtr 
app(wxTheApp
); 
 285         // if not, he might have used IMPLEMENT_APP() to give us a function to 
 287         wxAppInitializerFunction fnCreate 
= wxApp::GetInitializerFunction(); 
 291             // he did, try to create the custom wxApp object 
 292             app
.Set((*fnCreate
)()); 
 298         // either IMPLEMENT_APP() was not used at all or it failed -- in any 
 299         // case we still need something 
 300         app
.Set(new wxDummyConsoleApp
); 
 304     // wxApp initialization: this can be customized 
 305     // -------------------------------------------- 
 307     if ( !app
->Initialize(argc
, argv
) ) 
 310     // remember, possibly modified (e.g. due to removal of toolkit-specific 
 311     // parameters), command line arguments in member variables 
 315     wxCallAppCleanup 
callAppCleanup(app
.get()); 
 318     // common initialization after wxTheApp creation 
 319     // --------------------------------------------- 
 321     if ( !DoCommonPostInit() ) 
 325     // prevent the smart pointer from destroying its contents 
 328     // and the cleanup object from doing cleanup 
 329     callAppCleanup
.Dismiss(); 
 332     // now that we have a valid wxApp (wxLogGui would have crashed if we used 
 333     // it before now), we can delete the temporary sink we had created for the 
 334     // initialization messages -- the next time logging function is called, the 
 335     // sink will be recreated but this time wxAppTraits will be used 
 336     delete wxLog::SetActiveTarget(NULL
); 
 344 // we provide a wxEntryStart() wrapper taking "char *" pointer too 
 345 bool wxEntryStart(int& argc
, char **argv
) 
 347     ConvertArgsToUnicode(argc
, argv
); 
 349     if ( !wxEntryStart(gs_initData
.argc
, gs_initData
.argv
) ) 
 359 #endif // wxUSE_UNICODE 
 361 // ---------------------------------------------------------------------------- 
 363 // ---------------------------------------------------------------------------- 
 365 // cleanup done before destroying wxTheApp 
 366 static void DoCommonPreCleanup() 
 369     // flush the logged messages if any and don't use the current probably 
 370     // unsafe log target any more: the default one (wxLogGui) can't be used 
 371     // after the resources are freed which happens when we return and the user 
 372     // supplied one might be even more unsafe (using any wxWidgets GUI function 
 373     // is unsafe starting from now) 
 375     // notice that wxLog will still recreate a default log target if any 
 376     // messages are logged but that one will be safe to use until the very end 
 377     delete wxLog::SetActiveTarget(NULL
); 
 381 // cleanup done after destroying wxTheApp 
 382 static void DoCommonPostCleanup() 
 384     wxModule::CleanUpModules(); 
 386     // we can't do this in wxApp itself because it doesn't know if argv had 
 390 #endif // wxUSE_UNICODE 
 392     // use Set(NULL) and not Get() to avoid creating a message output object on 
 393     // demand when we just want to delete it 
 394     delete wxMessageOutput::Set(NULL
); 
 397     // and now delete the last logger as well 
 399     // we still don't disable log target auto-vivification even if any log 
 400     // objects created now will result in memory leaks because it seems better 
 401     // to leak memory which doesn't matter much considering the application is 
 402     // exiting anyhow than to not show messages which could still be logged 
 403     // from the user code (e.g. static dtors and such) 
 404     delete wxLog::SetActiveTarget(NULL
); 
 408 void wxEntryCleanup() 
 410     DoCommonPreCleanup(); 
 413     // delete the application object 
 418         // reset the global pointer to it to NULL before destroying it as in 
 419         // some circumstances this can result in executing the code using 
 420         // wxTheApp and using half-destroyed object is no good 
 421         wxAppConsole 
* const app 
= wxApp::GetInstance(); 
 422         wxApp::SetInstance(NULL
); 
 427     DoCommonPostCleanup(); 
 430 // ---------------------------------------------------------------------------- 
 432 // ---------------------------------------------------------------------------- 
 434 // for MSW the real wxEntry is defined in msw/main.cpp 
 436     #define wxEntryReal wxEntry 
 437 #endif // !__WINDOWS__ 
 439 int wxEntryReal(int& argc
, wxChar 
**argv
) 
 441     // library initialization 
 442     wxInitializer 
initializer(argc
, argv
); 
 444     if ( !initializer
.IsOk() ) 
 447         // flush any log messages explaining why we failed 
 448         delete wxLog::SetActiveTarget(NULL
); 
 455         // app initialization 
 456         if ( !wxTheApp
->CallOnInit() ) 
 458             // don't call OnExit() if OnInit() failed 
 462         // ensure that OnExit() is called if OnInit() had succeeded 
 466             ~CallOnExit() { wxTheApp
->OnExit(); } 
 469         WX_SUPPRESS_UNUSED_WARN(callOnExit
); 
 472         return wxTheApp
->OnRun(); 
 474     wxCATCH_ALL( wxTheApp
->OnUnhandledException(); return -1; ) 
 479 // as with wxEntryStart, we provide an ANSI wrapper 
 480 int wxEntry(int& argc
, char **argv
) 
 482     ConvertArgsToUnicode(argc
, argv
); 
 484     return wxEntry(gs_initData
.argc
, gs_initData
.argv
); 
 487 #endif // wxUSE_UNICODE 
 489 // ---------------------------------------------------------------------------- 
 490 // wxInitialize/wxUninitialize 
 491 // ---------------------------------------------------------------------------- 
 495     return wxInitialize(0, (wxChar
**)NULL
); 
 498 bool wxInitialize(int argc
, wxChar 
**argv
) 
 500     wxCRIT_SECT_LOCKER(lockInit
, gs_initData
.csInit
); 
 502     if ( gs_initData
.nInitCount
++ ) 
 504         // already initialized 
 508     return wxEntryStart(argc
, argv
); 
 512 bool wxInitialize(int argc
, char **argv
) 
 514     wxCRIT_SECT_LOCKER(lockInit
, gs_initData
.csInit
); 
 516     if ( gs_initData
.nInitCount
++ ) 
 518         // already initialized 
 522     return wxEntryStart(argc
, argv
); 
 524 #endif // wxUSE_UNICODE 
 526 void wxUninitialize() 
 528     wxCRIT_SECT_LOCKER(lockInit
, gs_initData
.csInit
); 
 530     if ( --gs_initData
.nInitCount 
== 0 )