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