moved fatal exception handling code to msw/main.cpp from common code
[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 #define ExitProcess ExitThread
50 #endif
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
57
58 #if defined(__WXMICROWIN__)
59 #define HINSTANCE HANDLE
60 #endif
61
62 // ============================================================================
63 // implementation: various entry points
64 // ============================================================================
65
66 // ----------------------------------------------------------------------------
67 // wrapper wxEntry catching all Win32 exceptions occuring in a wx program
68 // ----------------------------------------------------------------------------
69
70 // wrap real wxEntry in a try-except block to be able to call
71 // OnFatalException() if necessary
72 #if wxUSE_ON_FATAL_EXCEPTION
73
74 // global pointer to exception information, only valid inside OnFatalException,
75 // used by wxStackWalker and wxCrashReport
76 extern EXCEPTION_POINTERS *wxGlobalSEInformation = NULL;
77
78 // flag telling us whether the application wants to handle exceptions at all
79 static bool gs_handleExceptions = false;
80
81 unsigned long wxGlobalSEHandler(EXCEPTION_POINTERS *pExcPtrs)
82 {
83 if ( gs_handleExceptions && wxTheApp )
84 {
85 // store the pointer to exception info
86 wxGlobalSEInformation = pExcPtrs;
87
88 // give the user a chance to do something special about this
89 __try
90 {
91 wxTheApp->OnFatalException();
92 }
93 __except ( EXCEPTION_EXECUTE_HANDLER )
94 {
95 // nothing to do here, just ignore the exception inside the
96 // exception handler
97 ;
98 }
99
100 wxGlobalSEInformation = NULL;
101
102 // this will execute our handler and terminate the process
103 return EXCEPTION_EXECUTE_HANDLER;
104 }
105
106 return EXCEPTION_CONTINUE_SEARCH;
107 }
108
109 #ifdef __VISUALC__
110
111 static void wxSETranslator(unsigned int WXUNUSED(code), EXCEPTION_POINTERS *ep)
112 {
113 wxGlobalSEHandler(ep);
114 }
115
116 #endif // __VISUALC__
117
118 bool wxHandleFatalExceptions(bool doit)
119 {
120 // assume this can only be called from the main thread
121 gs_handleExceptions = doit;
122
123 #ifdef __VISUALC__
124 // VC++ (at least from 4.0 up to version 7.1) is incredibly broken in that
125 // a "catch ( ... )" will *always* catch SEH exceptions in it even though
126 // it should have never been the case... to prevent such catches from
127 // stealing the exceptions from our wxGlobalSEHandler which is only called
128 // if the exception is not handled elsewhere, we have to also call it from
129 // a special SEH translator function which is called by VC CRT when a Win32
130 // exception occurs
131 _set_se_translator(doit ? wxSETranslator : NULL);
132 #endif
133
134 #if wxUSE_CRASHREPORT
135 if ( doit )
136 {
137 // try to find a place where we can put out report file later
138 wxChar fullname[MAX_PATH];
139 if ( !::GetTempPath(WXSIZEOF(fullname), fullname) )
140 {
141 wxLogLastError(_T("GetTempPath"));
142
143 // when all else fails...
144 wxStrcpy(fullname, _T("c:\\"));
145 }
146
147 // use PID and date to make the report file name more unique
148 wxString name = wxString::Format
149 (
150 _T("%s_%s_%lu.dmp"),
151 wxTheApp ? wxTheApp->GetAppName().c_str()
152 : _T("wxwindows"),
153 wxDateTime::Now().Format(_T("%Y%m%dT%H%M%S")).c_str(),
154 ::GetCurrentProcessId()
155 );
156
157 wxStrncat(fullname, name, WXSIZEOF(fullname) - wxStrlen(fullname) - 1);
158
159 wxCrashReport::SetFileName(fullname);
160 }
161 #endif // wxUSE_CRASHREPORT
162
163 return true;
164 }
165
166 int wxEntry(int& argc, wxChar **argv)
167 {
168 __try
169 {
170 extern int wxEntryReal(int& argc, wxChar **argv);
171
172 return wxEntryReal(argc, argv);
173 }
174 __except ( wxGlobalSEHandler(GetExceptionInformation()) )
175 {
176 ::ExitProcess(3); // the same exit code as abort()
177
178 #if !defined(_MSC_VER) || _MSC_VER < 1300
179 // this code is unreachable but put it here to suppress warnings
180 // from some compilers
181 return -1;
182 #endif
183 }
184 }
185
186 #endif // wxUSE_ON_FATAL_EXCEPTION
187
188 #if wxUSE_GUI
189
190 // ----------------------------------------------------------------------------
191 // Windows-specific wxEntry
192 // ----------------------------------------------------------------------------
193
194 WXDLLEXPORT int wxEntry(HINSTANCE hInstance,
195 HINSTANCE WXUNUSED(hPrevInstance),
196 wxCmdLineArgType WXUNUSED(pCmdLine),
197 int nCmdShow)
198 {
199 // remember the parameters Windows gave us
200 wxSetInstance(hInstance);
201 wxApp::m_nCmdShow = nCmdShow;
202
203 // parse the command line: we can't use pCmdLine in Unicode build so it is
204 // simpler to never use it at all (this also results in a more correct
205 // argv[0])
206
207 // break the command line in words
208 wxArrayString args;
209
210 const wxChar *cmdLine = ::GetCommandLine();
211 if ( cmdLine )
212 {
213 args = wxCmdLineParser::ConvertStringToArgs(cmdLine);
214 }
215
216 #ifdef __WXWINCE__
217 // WinCE doesn't insert the program itself, so do it ourselves.
218 args.Insert(wxGetFullModuleName(), 0);
219 #endif
220
221 int argc = args.GetCount();
222
223 // +1 here for the terminating NULL
224 wxChar **argv = new wxChar *[argc + 1];
225 for ( int i = 0; i < argc; i++ )
226 {
227 argv[i] = wxStrdup(args[i]);
228 }
229
230 // argv[] must be NULL-terminated
231 argv[argc] = NULL;
232
233 return wxEntry(argc, argv);
234 }
235
236 // May wish not to have a DllMain or WinMain, e.g. if we're programming
237 // a Netscape plugin or if we're writing a console application
238 #if !defined(NOMAIN)
239
240 extern "C"
241 {
242
243 // ----------------------------------------------------------------------------
244 // WinMain
245 // ----------------------------------------------------------------------------
246
247 // Note that WinMain is also defined in dummy.obj, which is linked to
248 // an application that is using the DLL version of wxWidgets.
249
250 #if defined(_WINDLL)
251
252 // DLL entry point
253
254 BOOL WINAPI
255 DllMain(HANDLE hModule, DWORD fdwReason, LPVOID WXUNUSED(lpReserved))
256 {
257 // Only call wxEntry if the application itself is part of the DLL.
258 // If only the wxWidgets library is in the DLL, then the
259 // initialisation will be called when the application implicitly
260 // calls WinMain.
261 #ifndef WXMAKINGDLL
262 switch (fdwReason)
263 {
264 case DLL_PROCESS_ATTACH:
265 return wxEntry(hModule);
266
267 case DLL_PROCESS_DETACH:
268 wxEntryCleanup();
269 break;
270 }
271 #else
272 (void)hModule;
273 (void)fdwReason;
274 #endif // !WXMAKINGDLL
275
276 return TRUE;
277 }
278
279 #endif // _WINDLL
280
281 } // extern "C"
282
283 #endif // !NOMAIN
284
285 #endif // wxUSE_GUI
286
287 // ----------------------------------------------------------------------------
288 // global HINSTANCE
289 // ----------------------------------------------------------------------------
290
291 #if wxUSE_BASE
292
293 HINSTANCE wxhInstance = 0;
294
295 extern "C" HINSTANCE wxGetInstance()
296 {
297 return wxhInstance;
298 }
299
300 void wxSetInstance(HINSTANCE hInst)
301 {
302 wxhInstance = hInst;
303 }
304
305 #endif // wxUSE_BASE
306