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