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