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