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