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