1///////////////////////////////////////////////////////////////////////////// 2// Name: src/msw/main.cpp 3// Purpose: WinMain/DllMain 4// Author: Julian Smart 5// Modified by: 6// Created: 04/01/98 7// RCS-ID: $Id: main.cpp 44727 2007-03-10 17:24:09Z VZ $ 8// Copyright: (c) Julian Smart 9// Licence: wxWindows licence 10///////////////////////////////////////////////////////////////////////////// 11 12// ============================================================================ 13// declarations 14// ============================================================================ 15 16// ---------------------------------------------------------------------------- 17// headers 18// ---------------------------------------------------------------------------- 19 20// For compilers that support precompilation, includes "wx.h". 21#include "wx/wxprec.h" 22 23#ifdef __BORLANDC__ 24 #pragma hdrstop 25#endif 26 27#ifndef WX_PRECOMP 28 #include "wx/event.h" 29 #include "wx/app.h" 30 #include "wx/utils.h" 31#endif //WX_PRECOMP 32 33#include "wx/cmdline.h" 34#include "wx/scopeguard.h" 35 36#include "wx/msw/private.h" 37#include "wx/msw/seh.h" 38 39#if wxUSE_ON_FATAL_EXCEPTION 40 #include "wx/datetime.h" 41 #include "wx/msw/crashrpt.h" 42#endif // wxUSE_ON_FATAL_EXCEPTION 43 44#ifdef __WXWINCE__ 45 // there is no ExitProcess() under CE but exiting the main thread has the 46 // same effect 47 #ifndef ExitProcess 48 #define ExitProcess ExitThread 49 #endif 50#endif // __WXWINCE__ 51 52#ifdef __BORLANDC__ 53 // BC++ has to be special: its run-time expects the DLL entry point to be 54 // named DllEntryPoint instead of the (more) standard DllMain 55 #define DllMain DllEntryPoint 56#endif // __BORLANDC__ 57 58#if defined(__WXMICROWIN__) 59 #define HINSTANCE HANDLE 60#endif 61 62// defined in common/init.cpp 63extern int wxEntryReal(int& argc, wxChar **argv); 64 65// ============================================================================ 66// implementation: various entry points 67// ============================================================================ 68 69#if wxUSE_BASE 70 71#if wxUSE_ON_FATAL_EXCEPTION && defined(__VISUALC__) && !defined(__WXWINCE__) 72 // VC++ (at least from 4.0 up to version 7.1) is incredibly broken in that 73 // a "catch ( ... )" will *always* catch SEH exceptions in it even though 74 // it should have never been the case... to prevent such catches from 75 // stealing the exceptions from our wxGlobalSEHandler which is only called 76 // if the exception is not handled elsewhere, we have to also call it from 77 // a special SEH translator function which is called by VC CRT when a Win32 78 // exception occurs 79 80 // this warns that /EHa (async exceptions) should be used when using 81 // _set_se_translator but, in fact, this doesn't seem to change anything 82 // with VC++ up to 8.0 83 #if _MSC_VER <= 1400 84 #pragma warning(disable:4535) 85 #endif 86 87 // note that the SE translator must be called wxSETranslator! 88 #define DisableAutomaticSETranslator() _set_se_translator(wxSETranslator) 89#else // !__VISUALC__ 90 #define DisableAutomaticSETranslator() 91#endif // __VISUALC__/!__VISUALC__ 92 93// ---------------------------------------------------------------------------- 94// wrapper wxEntry catching all Win32 exceptions occurring in a wx program 95// ---------------------------------------------------------------------------- 96 97// wrap real wxEntry in a try-except block to be able to call 98// OnFatalException() if necessary 99#if wxUSE_ON_FATAL_EXCEPTION 100 101// global pointer to exception information, only valid inside OnFatalException, 102// used by wxStackWalker and wxCrashReport 103extern EXCEPTION_POINTERS *wxGlobalSEInformation = NULL; 104 105// flag telling us whether the application wants to handle exceptions at all 106static bool gs_handleExceptions = false; 107 108static void wxFatalExit() 109{ 110 // use the same exit code as abort() 111 ::ExitProcess(3); 112} 113 114unsigned long wxGlobalSEHandler(EXCEPTION_POINTERS *pExcPtrs) 115{ 116 if ( gs_handleExceptions && wxTheApp ) 117 { 118 // store the pointer to exception info 119 wxGlobalSEInformation = pExcPtrs; 120 121 // give the user a chance to do something special about this 122 wxSEH_TRY 123 { 124 wxTheApp->OnFatalException(); 125 } 126 wxSEH_IGNORE // ignore any exceptions inside the exception handler 127 128 wxGlobalSEInformation = NULL; 129 130 // this will execute our handler and terminate the process 131 return EXCEPTION_EXECUTE_HANDLER; 132 } 133 134 return EXCEPTION_CONTINUE_SEARCH; 135} 136 137#ifdef __VISUALC__ 138 139void wxSETranslator(unsigned int WXUNUSED(code), EXCEPTION_POINTERS *ep) 140{ 141 switch ( wxGlobalSEHandler(ep) ) 142 { 143 default: 144 wxFAIL_MSG( _T("unexpected wxGlobalSEHandler() return value") ); 145 // fall through 146 147 case EXCEPTION_EXECUTE_HANDLER: 148 // if wxApp::OnFatalException() had been called we should exit the 149 // application -- but we shouldn't kill our host when we're a DLL 150#ifndef WXMAKINGDLL 151 wxFatalExit(); 152#endif // not a DLL 153 break; 154 155 case EXCEPTION_CONTINUE_SEARCH: 156 // we're called for each "catch ( ... )" and if we (re)throw from 157 // here, the catch handler body is not executed, so the effect is 158 // as if had inhibited translation of SE to C++ ones because the 159 // handler will never see any structured exceptions 160 throw; 161 } 162} 163 164#endif // __VISUALC__ 165 166bool wxHandleFatalExceptions(bool doit) 167{ 168 // assume this can only be called from the main thread 169 gs_handleExceptions = doit; 170 171#if wxUSE_CRASHREPORT 172 if ( doit ) 173 { 174 // try to find a place where we can put out report file later 175 wxChar fullname[MAX_PATH]; 176 if ( !::GetTempPath(WXSIZEOF(fullname), fullname) ) 177 { 178 wxLogLastError(_T("GetTempPath")); 179 180 // when all else fails... 181 wxStrcpy(fullname, _T("c:\\")); 182 } 183 184 // use PID and date to make the report file name more unique 185 wxString name = wxString::Format 186 ( 187 _T("%s_%s_%lu.dmp"), 188 wxTheApp ? wxTheApp->GetAppName().c_str() 189 : _T("wxwindows"), 190 wxDateTime::Now().Format(_T("%Y%m%dT%H%M%S")).c_str(), 191 ::GetCurrentProcessId() 192 ); 193 194 wxStrncat(fullname, name, WXSIZEOF(fullname) - wxStrlen(fullname) - 1); 195 196 wxCrashReport::SetFileName(fullname); 197 } 198#endif // wxUSE_CRASHREPORT 199 200 return true; 201} 202 203int wxEntry(int& argc, wxChar **argv) 204{ 205 DisableAutomaticSETranslator(); 206 207 wxSEH_TRY 208 { 209 return wxEntryReal(argc, argv); 210 } 211 wxSEH_HANDLE(-1) 212} 213 214#else // !wxUSE_ON_FATAL_EXCEPTION 215 216#if defined(__VISUALC__) && !defined(__WXWINCE__) 217 218static void 219wxSETranslator(unsigned int WXUNUSED(code), EXCEPTION_POINTERS * WXUNUSED(ep)) 220{ 221 // see wxSETranslator() version for wxUSE_ON_FATAL_EXCEPTION above 222 throw; 223} 224 225#endif // __VISUALC__ 226 227int wxEntry(int& argc, wxChar **argv) 228{ 229 DisableAutomaticSETranslator(); 230 231 return wxEntryReal(argc, argv); 232} 233 234#endif // wxUSE_ON_FATAL_EXCEPTION/!wxUSE_ON_FATAL_EXCEPTION 235 236#endif // wxUSE_BASE 237 238#if wxUSE_GUI && defined(__WXMSW__) 239 240#if wxUSE_UNICODE && !defined(__WXWINCE__) 241 #define NEED_UNICODE_CHECK 242#endif 243 244#ifdef NEED_UNICODE_CHECK 245 246// check whether Unicode is available 247static bool wxIsUnicodeAvailable() 248{ 249 static const wchar_t *ERROR_STRING = L"wxWidgets Fatal Error"; 250 251 if ( wxGetOsVersion() != wxOS_WINDOWS_NT ) 252 { 253 // we need to be built with MSLU support 254#if !wxUSE_UNICODE_MSLU 255 // note that we can use MessageBoxW() as it's implemented even under 256 // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs 257 // used by wxLocale are not 258 ::MessageBox 259 ( 260 NULL, 261 L"This program uses Unicode and requires Windows NT/2000/XP.\n" 262 L"\n" 263 L"Program aborted.", 264 ERROR_STRING, 265 MB_ICONERROR | MB_OK 266 ); 267 268 return false; 269#else // wxUSE_UNICODE_MSLU 270 // and the MSLU DLL must also be available 271 HMODULE hmod = ::LoadLibraryA("unicows.dll"); 272 if ( !hmod ) 273 { 274 ::MessageBox 275 ( 276 NULL, 277 L"This program uses Unicode and requires unicows.dll to work " 278 L"under current operating system.\n" 279 L"\n" 280 L"Please install unicows.dll and relaunch the program.", 281 ERROR_STRING, 282 MB_ICONERROR | MB_OK 283 ); 284 return false; 285 } 286 287 // this is not really necessary but be tidy 288 ::FreeLibrary(hmod); 289 290 // finally do the last check: has unicows.lib initialized correctly? 291 hmod = ::LoadLibraryW(L"unicows.dll"); 292 if ( !hmod ) 293 { 294 ::MessageBox 295 ( 296 NULL, 297 L"This program uses Unicode but is not using unicows.dll\n" 298 L"correctly and so cannot work under current operating system.\n" 299 L"Please contact the program author for an updated version.\n" 300 L"\n" 301 L"Program aborted.", 302 ERROR_STRING, 303 MB_ICONERROR | MB_OK 304 ); 305 306 return false; 307 } 308 309 ::FreeLibrary(hmod); 310#endif // !wxUSE_UNICODE_MSLU 311 } 312 313 return true; 314} 315 316#endif // NEED_UNICODE_CHECK 317 318// ---------------------------------------------------------------------------- 319// Windows-specific wxEntry 320// ---------------------------------------------------------------------------- 321 322// helper function used to clean up in wxEntry() just below 323// 324// notice that argv elements are supposed to be allocated using malloc() while 325// argv array itself is allocated with new 326static void wxFreeArgs(int argc, wxChar **argv) 327{ 328 for ( int i = 0; i < argc; i++ ) 329 { 330 free(argv[i]); 331 } 332 333 delete [] argv; 334} 335 336WXDLLEXPORT int wxEntry(HINSTANCE hInstance, 337 HINSTANCE WXUNUSED(hPrevInstance), 338 wxCmdLineArgType WXUNUSED(pCmdLine), 339 int nCmdShow) 340{ 341 // the first thing to do is to check if we're trying to run an Unicode 342 // program under Win9x w/o MSLU emulation layer - if so, abort right now 343 // as it has no chance to work and has all chances to crash 344#ifdef NEED_UNICODE_CHECK 345 if ( !wxIsUnicodeAvailable() ) 346 return -1; 347#endif // NEED_UNICODE_CHECK 348 349 350 // remember the parameters Windows gave us 351 wxSetInstance(hInstance); 352 wxApp::m_nCmdShow = nCmdShow; 353 354 // parse the command line: we can't use pCmdLine in Unicode build so it is 355 // simpler to never use it at all (this also results in a more correct 356 // argv[0]) 357 358 // break the command line in words 359 wxArrayString args; 360 361 const wxChar *cmdLine = ::GetCommandLine(); 362 if ( cmdLine ) 363 { 364 args = wxCmdLineParser::ConvertStringToArgs(cmdLine); 365 } 366 367#ifdef __WXWINCE__ 368 // WinCE doesn't insert the program itself, so do it ourselves. 369 args.Insert(wxGetFullModuleName(), 0); 370#endif 371 372 int argc = args.GetCount(); 373 374 // +1 here for the terminating NULL 375 wxChar **argv = new wxChar *[argc + 1]; 376 for ( int i = 0; i < argc; i++ ) 377 { 378 argv[i] = wxStrdup(args[i]); 379 } 380 381 // argv[] must be NULL-terminated 382 argv[argc] = NULL; 383 384 wxON_BLOCK_EXIT2(wxFreeArgs, argc, argv); 385 386 return wxEntry(argc, argv); 387} 388 389#endif // wxUSE_GUI && __WXMSW__ 390 391// ---------------------------------------------------------------------------- 392// global HINSTANCE 393// ---------------------------------------------------------------------------- 394 395#if wxUSE_BASE 396 397HINSTANCE wxhInstance = 0; 398 399extern "C" HINSTANCE wxGetInstance() 400{ 401 return wxhInstance; 402} 403 404void wxSetInstance(HINSTANCE hInst) 405{ 406 wxhInstance = hInst; 407} 408 409#endif // wxUSE_BASE 410