don't translate Win32 structured exceptions into C++ ones (requires always using...
[wxWidgets.git] / src / msw / main.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/main.cpp
3 // Purpose: WinMain/DllMain
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #include "wx/event.h"
32 #include "wx/app.h"
33 #include "wx/cmdline.h"
34
35 #include "wx/msw/private.h"
36
37 #if wxUSE_ON_FATAL_EXCEPTION
38 #include "wx/datetime.h"
39 #include "wx/msw/crashrpt.h"
40
41 #ifdef __VISUALC__
42 #include <eh.h>
43 #endif // __VISUALC__
44 #endif // wxUSE_ON_FATAL_EXCEPTION
45
46 #ifdef __WXWINCE__
47 // there is no ExitProcess() under CE but exiting the main thread has the
48 // same effect
49 #ifndef ExitProcess
50 #define ExitProcess ExitThread
51 #endif
52 #endif // __WXWINCE__
53
54 #ifdef __BORLANDC__
55 // BC++ has to be special: its run-time expects the DLL entry point to be
56 // named DllEntryPoint instead of the (more) standard DllMain
57 #define DllMain DllEntryPoint
58 #endif // __BORLANDC__
59
60 #if defined(__WXMICROWIN__)
61 #define HINSTANCE HANDLE
62 #endif
63
64 // ============================================================================
65 // implementation: various entry points
66 // ============================================================================
67
68 #if wxUSE_BASE
69
70 #ifdef __VISUALC__
71 // VC++ (at least from 4.0 up to version 7.1) is incredibly broken in that
72 // a "catch ( ... )" will *always* catch SEH exceptions in it even though
73 // it should have never been the case... to prevent such catches from
74 // stealing the exceptions from our wxGlobalSEHandler which is only called
75 // if the exception is not handled elsewhere, we have to also call it from
76 // a special SEH translator function which is called by VC CRT when a Win32
77 // exception occurs
78
79 // this warns that /EHa (async exceptions) should be used when using
80 // _set_se_translator but, in fact, this doesn't seem to change anything
81 // with VC++ up to 7.1 -- to be confirmed with VC++ 8
82 #if _MSC_VER <= 1310
83 #pragma warning(disable:4535)
84 #endif
85
86 // note that the SE translator must be called wxSETranslator!
87 #define DisableAutomaticSETranslator() _set_se_translator(wxSETranslator)
88 #else // !__VISUALC__
89 #define DisableAutomaticSETranslator()
90 #endif // __VISUALC__/!__VISUALC__
91
92 // ----------------------------------------------------------------------------
93 // wrapper wxEntry catching all Win32 exceptions occuring in a wx program
94 // ----------------------------------------------------------------------------
95
96 // wrap real wxEntry in a try-except block to be able to call
97 // OnFatalException() if necessary
98 #if wxUSE_ON_FATAL_EXCEPTION
99
100 // defined in common/init.cpp
101 extern int wxEntryReal(int& argc, wxChar **argv);
102
103 // global pointer to exception information, only valid inside OnFatalException,
104 // used by wxStackWalker and wxCrashReport
105 extern EXCEPTION_POINTERS *wxGlobalSEInformation = NULL;
106
107 // flag telling us whether the application wants to handle exceptions at all
108 static bool gs_handleExceptions = false;
109
110 static void wxFatalExit()
111 {
112 // use the same exit code as abort()
113 ::ExitProcess(3);
114 }
115
116 unsigned long wxGlobalSEHandler(EXCEPTION_POINTERS *pExcPtrs)
117 {
118 if ( gs_handleExceptions && wxTheApp )
119 {
120 // store the pointer to exception info
121 wxGlobalSEInformation = pExcPtrs;
122
123 // give the user a chance to do something special about this
124 __try
125 {
126 wxTheApp->OnFatalException();
127 }
128 __except ( EXCEPTION_EXECUTE_HANDLER )
129 {
130 // nothing to do here, just ignore the exception inside the
131 // exception handler
132 ;
133 }
134
135 wxGlobalSEInformation = NULL;
136
137 // this will execute our handler and terminate the process
138 return EXCEPTION_EXECUTE_HANDLER;
139 }
140
141 return EXCEPTION_CONTINUE_SEARCH;
142 }
143
144 #ifdef __VISUALC__
145
146 static void wxSETranslator(unsigned int WXUNUSED(code), EXCEPTION_POINTERS *ep)
147 {
148 switch ( wxGlobalSEHandler(ep) )
149 {
150 default:
151 wxFAIL_MSG( _T("unexpected wxGlobalSEHandler() return value") );
152 // fall through
153
154 case EXCEPTION_EXECUTE_HANDLER:
155 // if wxApp::OnFatalException() had been called we should exit the
156 // application -- but we shouldn't kill our host when we're a DLL
157 #ifndef WXMAKINGDLL
158 wxFatalExit();
159 #endif // not a DLL
160 break;
161
162 case EXCEPTION_CONTINUE_SEARCH:
163 // we're called for each "catch ( ... )" and if we (re)throw from
164 // here, the catch handler body is not executed, so the effect is
165 // as if had inhibited translation of SE to C++ ones because the
166 // handler will never see any structured exceptions
167 throw;
168 }
169 }
170
171 #endif // __VISUALC__
172
173 bool wxHandleFatalExceptions(bool doit)
174 {
175 // assume this can only be called from the main thread
176 gs_handleExceptions = doit;
177
178 #if wxUSE_CRASHREPORT
179 if ( doit )
180 {
181 // try to find a place where we can put out report file later
182 wxChar fullname[MAX_PATH];
183 if ( !::GetTempPath(WXSIZEOF(fullname), fullname) )
184 {
185 wxLogLastError(_T("GetTempPath"));
186
187 // when all else fails...
188 wxStrcpy(fullname, _T("c:\\"));
189 }
190
191 // use PID and date to make the report file name more unique
192 wxString name = wxString::Format
193 (
194 _T("%s_%s_%lu.dmp"),
195 wxTheApp ? wxTheApp->GetAppName().c_str()
196 : _T("wxwindows"),
197 wxDateTime::Now().Format(_T("%Y%m%dT%H%M%S")).c_str(),
198 ::GetCurrentProcessId()
199 );
200
201 wxStrncat(fullname, name, WXSIZEOF(fullname) - wxStrlen(fullname) - 1);
202
203 wxCrashReport::SetFileName(fullname);
204 }
205 #endif // wxUSE_CRASHREPORT
206
207 return true;
208 }
209
210 int wxEntry(int& argc, wxChar **argv)
211 {
212 DisableAutomaticSETranslator();
213
214 __try
215 {
216 return wxEntryReal(argc, argv);
217 }
218 __except ( wxGlobalSEHandler(GetExceptionInformation()) )
219 {
220 wxFatalExit();
221
222 // this code is unreachable but put it here to suppress warnings
223 return -1;
224 }
225 }
226
227 #else // !wxUSE_ON_FATAL_EXCEPTION
228
229 static void
230 wxSETranslator(unsigned int WXUNUSED(code), EXCEPTION_POINTERS * WXUNUSED(ep))
231 {
232 // see wxSETranslator() version for wxUSE_ON_FATAL_EXCEPTION above
233 throw;
234 }
235
236 int wxEntry(int& argc, wxChar **argv)
237 {
238 DisableAutomaticSETranslator();
239
240 return wxEntryReal(argc, argv);
241 }
242
243 #endif // wxUSE_ON_FATAL_EXCEPTION/!wxUSE_ON_FATAL_EXCEPTION
244
245 #endif // wxUSE_BASE
246
247 #if wxUSE_GUI
248
249 // ----------------------------------------------------------------------------
250 // Windows-specific wxEntry
251 // ----------------------------------------------------------------------------
252
253 WXDLLEXPORT int wxEntry(HINSTANCE hInstance,
254 HINSTANCE WXUNUSED(hPrevInstance),
255 wxCmdLineArgType WXUNUSED(pCmdLine),
256 int nCmdShow)
257 {
258 // remember the parameters Windows gave us
259 wxSetInstance(hInstance);
260 wxApp::m_nCmdShow = nCmdShow;
261
262 // parse the command line: we can't use pCmdLine in Unicode build so it is
263 // simpler to never use it at all (this also results in a more correct
264 // argv[0])
265
266 // break the command line in words
267 wxArrayString args;
268
269 const wxChar *cmdLine = ::GetCommandLine();
270 if ( cmdLine )
271 {
272 args = wxCmdLineParser::ConvertStringToArgs(cmdLine);
273 }
274
275 #ifdef __WXWINCE__
276 // WinCE doesn't insert the program itself, so do it ourselves.
277 args.Insert(wxGetFullModuleName(), 0);
278 #endif
279
280 int argc = args.GetCount();
281
282 // +1 here for the terminating NULL
283 wxChar **argv = new wxChar *[argc + 1];
284 for ( int i = 0; i < argc; i++ )
285 {
286 argv[i] = wxStrdup(args[i]);
287 }
288
289 // argv[] must be NULL-terminated
290 argv[argc] = NULL;
291
292 return wxEntry(argc, argv);
293 }
294
295 // May wish not to have a DllMain or WinMain, e.g. if we're programming
296 // a Netscape plugin or if we're writing a console application
297 #if !defined(NOMAIN)
298
299 extern "C"
300 {
301
302 // ----------------------------------------------------------------------------
303 // WinMain
304 // ----------------------------------------------------------------------------
305
306 // Note that WinMain is also defined in dummy.obj, which is linked to
307 // an application that is using the DLL version of wxWidgets.
308
309 #if defined(_WINDLL)
310
311 // DLL entry point
312
313 BOOL WINAPI
314 DllMain(HANDLE hModule, DWORD fdwReason, LPVOID WXUNUSED(lpReserved))
315 {
316 // Only call wxEntry if the application itself is part of the DLL.
317 // If only the wxWidgets library is in the DLL, then the
318 // initialisation will be called when the application implicitly
319 // calls WinMain.
320 #ifndef WXMAKINGDLL
321 switch (fdwReason)
322 {
323 case DLL_PROCESS_ATTACH:
324 return wxEntry(hModule);
325
326 case DLL_PROCESS_DETACH:
327 wxEntryCleanup();
328 break;
329 }
330 #else
331 (void)hModule;
332 (void)fdwReason;
333 #endif // !WXMAKINGDLL
334
335 return TRUE;
336 }
337
338 #endif // _WINDLL
339
340 } // extern "C"
341
342 #endif // !NOMAIN
343
344 #endif // wxUSE_GUI
345
346 // ----------------------------------------------------------------------------
347 // global HINSTANCE
348 // ----------------------------------------------------------------------------
349
350 #if wxUSE_BASE
351
352 HINSTANCE wxhInstance = 0;
353
354 extern "C" HINSTANCE wxGetInstance()
355 {
356 return wxhInstance;
357 }
358
359 void wxSetInstance(HINSTANCE hInst)
360 {
361 wxhInstance = hInst;
362 }
363
364 #endif // wxUSE_BASE
365