move the code freeing temporary argv array to wxEntry(HINSTANCE) overload to avoid...
[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 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #include "wx/event.h"
28 #include "wx/app.h"
29 #include "wx/cmdline.h"
30 #include "wx/scopeguard.h"
31
32 #include "wx/msw/private.h"
33
34 #if wxUSE_ON_FATAL_EXCEPTION
35 #include "wx/datetime.h"
36 #include "wx/msw/crashrpt.h"
37
38 #ifdef __VISUALC__
39 #include <eh.h>
40 #endif // __VISUALC__
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 __try
122 {
123 wxTheApp->OnFatalException();
124 }
125 __except ( EXCEPTION_EXECUTE_HANDLER )
126 {
127 // nothing to do here, just ignore the exception inside the
128 // exception handler
129 ;
130 }
131
132 wxGlobalSEInformation = NULL;
133
134 // this will execute our handler and terminate the process
135 return EXCEPTION_EXECUTE_HANDLER;
136 }
137
138 return EXCEPTION_CONTINUE_SEARCH;
139 }
140
141 #ifdef __VISUALC__
142
143 static void wxSETranslator(unsigned int WXUNUSED(code), EXCEPTION_POINTERS *ep)
144 {
145 switch ( wxGlobalSEHandler(ep) )
146 {
147 default:
148 wxFAIL_MSG( _T("unexpected wxGlobalSEHandler() return value") );
149 // fall through
150
151 case EXCEPTION_EXECUTE_HANDLER:
152 // if wxApp::OnFatalException() had been called we should exit the
153 // application -- but we shouldn't kill our host when we're a DLL
154 #ifndef WXMAKINGDLL
155 wxFatalExit();
156 #endif // not a DLL
157 break;
158
159 case EXCEPTION_CONTINUE_SEARCH:
160 // we're called for each "catch ( ... )" and if we (re)throw from
161 // here, the catch handler body is not executed, so the effect is
162 // as if had inhibited translation of SE to C++ ones because the
163 // handler will never see any structured exceptions
164 throw;
165 }
166 }
167
168 #endif // __VISUALC__
169
170 bool wxHandleFatalExceptions(bool doit)
171 {
172 // assume this can only be called from the main thread
173 gs_handleExceptions = doit;
174
175 #if wxUSE_CRASHREPORT
176 if ( doit )
177 {
178 // try to find a place where we can put out report file later
179 wxChar fullname[MAX_PATH];
180 if ( !::GetTempPath(WXSIZEOF(fullname), fullname) )
181 {
182 wxLogLastError(_T("GetTempPath"));
183
184 // when all else fails...
185 wxStrcpy(fullname, _T("c:\\"));
186 }
187
188 // use PID and date to make the report file name more unique
189 wxString name = wxString::Format
190 (
191 _T("%s_%s_%lu.dmp"),
192 wxTheApp ? wxTheApp->GetAppName().c_str()
193 : _T("wxwindows"),
194 wxDateTime::Now().Format(_T("%Y%m%dT%H%M%S")).c_str(),
195 ::GetCurrentProcessId()
196 );
197
198 wxStrncat(fullname, name, WXSIZEOF(fullname) - wxStrlen(fullname) - 1);
199
200 wxCrashReport::SetFileName(fullname);
201 }
202 #endif // wxUSE_CRASHREPORT
203
204 return true;
205 }
206
207 int wxEntry(int& argc, wxChar **argv)
208 {
209 DisableAutomaticSETranslator();
210
211 __try
212 {
213 return wxEntryReal(argc, argv);
214 }
215 __except ( wxGlobalSEHandler(GetExceptionInformation()) )
216 {
217 wxFatalExit();
218
219 #if !defined(_MSC_VER) || defined(__WXDEBUG__) || (defined(_MSC_VER) && _MSC_VER <= 1200)
220 // this code is unreachable but put it here to suppress warnings in some compilers
221 // and disable for others to supress warnings too
222 return -1;
223 #endif // !__VISUALC__ in release build
224 }
225 }
226
227 #else // !wxUSE_ON_FATAL_EXCEPTION
228
229 #if defined(__VISUALC__) && !defined(__WXWINCE__)
230
231 static void
232 wxSETranslator(unsigned int WXUNUSED(code), EXCEPTION_POINTERS * WXUNUSED(ep))
233 {
234 // see wxSETranslator() version for wxUSE_ON_FATAL_EXCEPTION above
235 throw;
236 }
237
238 #endif // __VISUALC__
239
240 int wxEntry(int& argc, wxChar **argv)
241 {
242 DisableAutomaticSETranslator();
243
244 return wxEntryReal(argc, argv);
245 }
246
247 #endif // wxUSE_ON_FATAL_EXCEPTION/!wxUSE_ON_FATAL_EXCEPTION
248
249 #endif // wxUSE_BASE
250
251 #if wxUSE_GUI && defined(__WXMSW__)
252
253 #if wxUSE_UNICODE && !defined(__WXWINCE__)
254 #define NEED_UNICODE_CHECK
255 #endif
256
257 #ifdef NEED_UNICODE_CHECK
258
259 // check whether Unicode is available
260 static bool wxIsUnicodeAvailable()
261 {
262 static const wchar_t *ERROR_STRING = L"wxWidgets Fatal Error";
263
264 if ( wxGetOsVersion() != wxWINDOWS_NT )
265 {
266 // we need to be built with MSLU support
267 #if !wxUSE_UNICODE_MSLU
268 // note that we can use MessageBoxW() as it's implemented even under
269 // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs
270 // used by wxLocale are not
271 ::MessageBox
272 (
273 NULL,
274 L"This program uses Unicode and requires Windows NT/2000/XP.\n"
275 L"\n"
276 L"Program aborted.",
277 ERROR_STRING,
278 MB_ICONERROR | MB_OK
279 );
280
281 return false;
282 #else // wxUSE_UNICODE_MSLU
283 // and the MSLU DLL must also be available
284 HMODULE hmod = ::LoadLibraryA("unicows.dll");
285 if ( !hmod )
286 {
287 ::MessageBox
288 (
289 NULL,
290 L"This program uses Unicode and requires unicows.dll to work "
291 L"under current operating system.\n"
292 L"\n"
293 L"Please install unicows.dll and relaunch the program.",
294 ERROR_STRING,
295 MB_ICONERROR | MB_OK
296 );
297 return false;
298 }
299
300 // this is not really necessary but be tidy
301 ::FreeLibrary(hmod);
302
303 // finally do the last check: has unicows.lib initialized correctly?
304 hmod = ::LoadLibraryW(L"unicows.dll");
305 if ( !hmod )
306 {
307 ::MessageBox
308 (
309 NULL,
310 L"This program uses Unicode but is not using unicows.dll\n"
311 L"correctly and so cannot work under current operating system.\n"
312 L"Please contact the program author for an updated version.\n"
313 L"\n"
314 L"Program aborted.",
315 ERROR_STRING,
316 MB_ICONERROR | MB_OK
317 );
318
319 return false;
320 }
321
322 ::FreeLibrary(hmod);
323 #endif // !wxUSE_UNICODE_MSLU
324 }
325
326 return true;
327 }
328
329 #endif // NEED_UNICODE_CHECK
330
331 // ----------------------------------------------------------------------------
332 // Windows-specific wxEntry
333 // ----------------------------------------------------------------------------
334
335 // helper function used to clean up in wxEntry() just below
336 //
337 // notice that argv elements are supposed to be allocated using malloc() while
338 // argv array itself is allocated with new
339 static void wxFreeArgs(int argc, wxChar **argv)
340 {
341 for ( int i = 0; i < argc; i++ )
342 {
343 free(argv[i]);
344 }
345
346 delete [] argv;
347 }
348
349 WXDLLEXPORT int wxEntry(HINSTANCE hInstance,
350 HINSTANCE WXUNUSED(hPrevInstance),
351 wxCmdLineArgType WXUNUSED(pCmdLine),
352 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 -1;
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 int argc = args.GetCount();
386
387 // +1 here for the terminating NULL
388 wxChar **argv = new wxChar *[argc + 1];
389 for ( int i = 0; i < argc; i++ )
390 {
391 argv[i] = wxStrdup(args[i]);
392 }
393
394 // argv[] must be NULL-terminated
395 argv[argc] = NULL;
396
397 wxON_BLOCK_EXIT2(wxFreeArgs, argc, argv);
398
399 return wxEntry(argc, argv);
400 }
401
402 #endif // wxUSE_GUI && __WXMSW__
403
404 // ----------------------------------------------------------------------------
405 // global HINSTANCE
406 // ----------------------------------------------------------------------------
407
408 #if wxUSE_BASE
409
410 HINSTANCE wxhInstance = 0;
411
412 extern "C" HINSTANCE wxGetInstance()
413 {
414 return wxhInstance;
415 }
416
417 void wxSetInstance(HINSTANCE hInst)
418 {
419 wxhInstance = hInst;
420 }
421
422 #endif // wxUSE_BASE
423