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(__WXMSW__) 
  41     #include "wx/msw/msvcrt.h" 
  43     #ifdef wxCrtSetDbgFlag 
  44         static struct EnableMemLeakChecking
 
  46             EnableMemLeakChecking() 
  48                 // check for memory leaks on program exit (another useful flag 
  49                 // is _CRTDBG_DELAY_FREE_MEM_DF which doesn't free deallocated 
  50                 // memory which may be used to simulate low-memory condition) 
  51                 wxCrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF
); 
  53         } gs_enableLeakChecks
; 
  54     #endif // wxCrtSetDbgFlag 
  57 // ---------------------------------------------------------------------------- 
  59 // ---------------------------------------------------------------------------- 
  61 // we need a dummy app object if the user doesn't want to create a real one 
  62 class wxDummyConsoleApp 
: public wxAppConsole
 
  65     wxDummyConsoleApp() { } 
  67     virtual int OnRun() { wxFAIL_MSG( _T("unreachable code") ); return 0; } 
  68     virtual bool DoYield(bool, long) { return true; } 
  70     wxDECLARE_NO_COPY_CLASS(wxDummyConsoleApp
); 
  73 // we need a special kind of auto pointer to wxApp which not only deletes the 
  74 // pointer it holds in its dtor but also resets the global application pointer 
  75 wxDECLARE_SCOPED_PTR(wxAppConsole
, wxAppPtrBase
) 
  76 wxDEFINE_SCOPED_PTR(wxAppConsole
, wxAppPtrBase
) 
  78 class wxAppPtr 
: public wxAppPtrBase
 
  81     wxEXPLICIT 
wxAppPtr(wxAppConsole 
*ptr 
= NULL
) : wxAppPtrBase(ptr
) { } 
  86             // the pointer is going to be deleted in the base class dtor, don't 
  87             // leave the dangling pointer! 
  88             wxApp::SetInstance(NULL
); 
  92     void Set(wxAppConsole 
*ptr
) 
  96         wxApp::SetInstance(ptr
); 
  99     wxDECLARE_NO_COPY_CLASS(wxAppPtr
); 
 102 // class to ensure that wxAppBase::CleanUp() is called if our Initialize() 
 104 class wxCallAppCleanup
 
 107     wxCallAppCleanup(wxAppConsole 
*app
) : m_app(app
) { } 
 108     ~wxCallAppCleanup() { if ( m_app 
) m_app
->CleanUp(); } 
 110     void Dismiss() { m_app 
= NULL
; } 
 116 // another tiny class which simply exists to ensure that wxEntryCleanup is 
 118 class wxCleanupOnExit
 
 121     ~wxCleanupOnExit() { wxEntryCleanup(); } 
 124 // ---------------------------------------------------------------------------- 
 126 // ---------------------------------------------------------------------------- 
 128 // suppress warnings about unused variables 
 129 static inline void Use(void *) { } 
 131 #define WX_SUPPRESS_UNUSED_WARN(x) Use(&x) 
 133 // ---------------------------------------------------------------------------- 
 134 // initialization data 
 135 // ---------------------------------------------------------------------------- 
 137 static struct InitData
 
 145         // argv = NULL; -- not even really needed 
 146 #endif // wxUSE_UNICODE 
 149     // critical section protecting this struct 
 150     wxCRIT_SECT_DECLARE_MEMBER(csInit
); 
 152     // number of times wxInitialize() was called minus the number of times 
 153     // wxUninitialize() was 
 159     // if we receive the command line arguments as ASCII and have to convert 
 160     // them to Unicode ourselves (this is the case under Unix but not Windows, 
 161     // for example), we remember the converted argv here because we'll have to 
 162     // free it when doing cleanup to avoid memory leaks 
 164 #endif // wxUSE_UNICODE 
 166     wxDECLARE_NO_COPY_CLASS(InitData
); 
 169 // ============================================================================ 
 171 // ============================================================================ 
 173 // ---------------------------------------------------------------------------- 
 174 // command line arguments ANSI -> Unicode conversion 
 175 // ---------------------------------------------------------------------------- 
 179 static void ConvertArgsToUnicode(int argc
, char **argv
) 
 181     gs_initData
.argv 
= new wchar_t *[argc 
+ 1]; 
 183     for ( int i 
= 0; i 
< argc
; i
++ ) 
 186         wxWCharBuffer 
buf(wxConvFileName
->cMB2WX(argv
[i
])); 
 188         wxWCharBuffer 
buf(wxConvLocal
.cMB2WX(argv
[i
])); 
 192             wxLogWarning(_("Command line argument %d couldn't be converted to Unicode and will be ignored."), 
 197             gs_initData
.argv
[wargc
++] = wxStrdup(buf
); 
 201     gs_initData
.argc 
= wargc
; 
 202     gs_initData
.argv
[wargc
] = NULL
; 
 205 static void FreeConvertedArgs() 
 207     if ( gs_initData
.argv 
) 
 209         for ( int i 
= 0; i 
< gs_initData
.argc
; i
++ ) 
 211             free(gs_initData
.argv
[i
]); 
 214         delete [] gs_initData
.argv
; 
 215         gs_initData
.argv 
= NULL
; 
 216         gs_initData
.argc 
= 0; 
 220 #endif // wxUSE_UNICODE 
 222 // ---------------------------------------------------------------------------- 
 224 // ---------------------------------------------------------------------------- 
 226 // initialization which is always done (not customizable) before wxApp creation 
 227 static bool DoCommonPreInit() 
 230     // Reset logging in case we were cleaned up and are being reinitialized. 
 231     wxLog::DoCreateOnDemand(); 
 233     // install temporary log sink: we can't use wxLogGui before wxApp is 
 234     // constructed and if we use wxLogStderr, all messages during 
 235     // initialization simply disappear under Windows 
 237     // note that we will delete this log target below 
 238     delete wxLog::SetActiveTarget(new wxLogBuffer
); 
 244 // non customizable initialization done after wxApp creation and initialization 
 245 static bool DoCommonPostInit() 
 247     wxModule::RegisterModules(); 
 249     if ( !wxModule::InitializeModules() ) 
 251         wxLogError(_("Initialization failed in post init, aborting.")); 
 255 #if defined(__WXDEBUG__) 
 256     // check if event classes implement Clone() correctly 
 257     // NOTE: the check is done against _all_ event classes which are linked to 
 258     //       the executable currently running, which are not necessarily all 
 259     //       wxWidgets event classes. 
 260     const wxClassInfo 
*ci 
= wxClassInfo::GetFirst(); 
 261     for (; ci
; ci 
= ci
->GetNext()) 
 263         // is this class derived from wxEvent? 
 264         if (!ci
->IsKindOf(CLASSINFO(wxEvent
)) || wxString(ci
->GetClassName()) == "wxEvent") 
 267         if (!ci
->IsDynamic()) 
 269             wxLogWarning("The event class '%s' should have a DECLARE_DYNAMIC_CLASS macro!", 
 274         // yes; test if it implements Clone() correctly 
 275         wxEvent
* test 
= wxDynamicCast(ci
->CreateObject(),wxEvent
); 
 278             wxLogWarning("The event class '%s' should have a DECLARE_DYNAMIC_CLASS macro!", 
 283         wxEvent
* cloned 
= test
->Clone(); 
 284         if (!cloned 
|| cloned
->GetClassInfo() != ci
) 
 285             wxLogWarning("The event class '%s' does not correctly implement Clone()!", 
 296 bool wxEntryStart(int& argc
, wxChar 
**argv
) 
 298     // do minimal, always necessary, initialization 
 299     // -------------------------------------------- 
 302     if ( !DoCommonPreInit() ) 
 306     // first of all, we need an application object 
 307     // ------------------------------------------- 
 309     // the user might have already created it himself somehow 
 310     wxAppPtr 
app(wxTheApp
); 
 313         // if not, he might have used IMPLEMENT_APP() to give us a function to 
 315         wxAppInitializerFunction fnCreate 
= wxApp::GetInitializerFunction(); 
 319             // he did, try to create the custom wxApp object 
 320             app
.Set((*fnCreate
)()); 
 326         // either IMPLEMENT_APP() was not used at all or it failed -- in any 
 327         // case we still need something 
 328         app
.Set(new wxDummyConsoleApp
); 
 332     // wxApp initialization: this can be customized 
 333     // -------------------------------------------- 
 335     if ( !app
->Initialize(argc
, argv
) ) 
 338     // remember, possibly modified (e.g. due to removal of toolkit-specific 
 339     // parameters), command line arguments in member variables 
 343     wxCallAppCleanup 
callAppCleanup(app
.get()); 
 346     // common initialization after wxTheApp creation 
 347     // --------------------------------------------- 
 349     if ( !DoCommonPostInit() ) 
 353     // prevent the smart pointer from destroying its contents 
 356     // and the cleanup object from doing cleanup 
 357     callAppCleanup
.Dismiss(); 
 360     // now that we have a valid wxApp (wxLogGui would have crashed if we used 
 361     // it before now), we can delete the temporary sink we had created for the 
 362     // initialization messages -- the next time logging function is called, the 
 363     // sink will be recreated but this time wxAppTraits will be used 
 364     delete wxLog::SetActiveTarget(NULL
); 
 372 // we provide a wxEntryStart() wrapper taking "char *" pointer too 
 373 bool wxEntryStart(int& argc
, char **argv
) 
 375     ConvertArgsToUnicode(argc
, argv
); 
 377     if ( !wxEntryStart(gs_initData
.argc
, gs_initData
.argv
) ) 
 387 #endif // wxUSE_UNICODE 
 389 // ---------------------------------------------------------------------------- 
 391 // ---------------------------------------------------------------------------- 
 393 // cleanup done before destroying wxTheApp 
 394 static void DoCommonPreCleanup() 
 397     // flush the logged messages if any and install a 'safer' log target: the 
 398     // default one (wxLogGui) can't be used after the resources are freed just 
 399     // below and the user supplied one might be even more unsafe (using any 
 400     // wxWidgets GUI function is unsafe starting from now) 
 401     wxLog::DontCreateOnDemand(); 
 403     // this will flush the old messages if any 
 404     delete wxLog::SetActiveTarget(new wxLogStderr
); 
 408 // cleanup done after destroying wxTheApp 
 409 static void DoCommonPostCleanup() 
 411     wxModule::CleanUpModules(); 
 413     // we can't do this in wxApp itself because it doesn't know if argv had 
 417 #endif // wxUSE_UNICODE 
 419     // use Set(NULL) and not Get() to avoid creating a message output object on 
 420     // demand when we just want to delete it 
 421     delete wxMessageOutput::Set(NULL
); 
 424     // and now delete the last logger as well 
 425     delete wxLog::SetActiveTarget(NULL
); 
 429 void wxEntryCleanup() 
 431     DoCommonPreCleanup(); 
 434     // delete the application object 
 439         // reset the global pointer to it to NULL before destroying it as in 
 440         // some circumstances this can result in executing the code using 
 441         // wxTheApp and using half-destroyed object is no good 
 442         wxAppConsole 
* const app 
= wxApp::GetInstance(); 
 443         wxApp::SetInstance(NULL
); 
 448     DoCommonPostCleanup(); 
 451 // ---------------------------------------------------------------------------- 
 453 // ---------------------------------------------------------------------------- 
 455 // for MSW the real wxEntry is defined in msw/main.cpp 
 457     #define wxEntryReal wxEntry 
 460 int wxEntryReal(int& argc
, wxChar 
**argv
) 
 462     // library initialization 
 463     if ( !wxEntryStart(argc
, argv
) ) 
 466         // flush any log messages explaining why we failed 
 467         delete wxLog::SetActiveTarget(NULL
); 
 472     // if wxEntryStart succeeded, we must call wxEntryCleanup even if the code 
 473     // below returns or throws 
 474     wxCleanupOnExit cleanupOnExit
; 
 476     WX_SUPPRESS_UNUSED_WARN(cleanupOnExit
); 
 480         // app initialization 
 481         if ( !wxTheApp
->CallOnInit() ) 
 483             // don't call OnExit() if OnInit() failed 
 487         // ensure that OnExit() is called if OnInit() had succeeded 
 491             ~CallOnExit() { wxTheApp
->OnExit(); } 
 494         WX_SUPPRESS_UNUSED_WARN(callOnExit
); 
 497         return wxTheApp
->OnRun(); 
 499     wxCATCH_ALL( wxTheApp
->OnUnhandledException(); return -1; ) 
 504 // as with wxEntryStart, we provide an ANSI wrapper 
 505 int wxEntry(int& argc
, char **argv
) 
 507     ConvertArgsToUnicode(argc
, argv
); 
 509     return wxEntry(gs_initData
.argc
, gs_initData
.argv
); 
 512 #endif // wxUSE_UNICODE 
 514 // ---------------------------------------------------------------------------- 
 515 // wxInitialize/wxUninitialize 
 516 // ---------------------------------------------------------------------------- 
 518 bool wxInitialize(int argc
, wxChar 
**argv
) 
 520     wxCRIT_SECT_LOCKER(lockInit
, gs_initData
.csInit
); 
 522     if ( gs_initData
.nInitCount
++ ) 
 524         // already initialized 
 528     return wxEntryStart(argc
, argv
); 
 531 void wxUninitialize() 
 533     wxCRIT_SECT_LOCKER(lockInit
, gs_initData
.csInit
); 
 535     if ( --gs_initData
.nInitCount 
== 0 )