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