]> git.saurik.com Git - wxWidgets.git/blame - src/msw/main.cpp
document that the workaround used to make popup menus behave correctly is the one...
[wxWidgets.git] / src / msw / main.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
b568d04f 2// Name: msw/main.cpp
e2478fde 3// Purpose: WinMain/DllMain
2bda0e17
KB
4// Author: Julian Smart
5// Modified by:
6// Created: 04/01/98
7// RCS-ID: $Id$
6c9a19aa 8// Copyright: (c) Julian Smart
65571936 9// Licence: wxWindows licence
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
b568d04f
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
2bda0e17
KB
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
b568d04f 24 #pragma hdrstop
2bda0e17
KB
25#endif
26
2432b92d 27#include "wx/event.h"
2bda0e17 28#include "wx/app.h"
94826170 29#include "wx/cmdline.h"
48733d47 30#include "wx/scopeguard.h"
b568d04f
VZ
31
32#include "wx/msw/private.h"
33
8c125d13
VZ
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
226c11c0
VZ
46 #ifndef ExitProcess
47 #define ExitProcess ExitThread
48 #endif
49#endif // __WXWINCE__
8c125d13 50
e2478fde
VZ
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
226c11c0 55#endif // __BORLANDC__
e2478fde
VZ
56
57#if defined(__WXMICROWIN__)
58 #define HINSTANCE HANDLE
59#endif
beed393c 60
1ac4716d
VZ
61// defined in common/init.cpp
62extern int wxEntryReal(int& argc, wxChar **argv);
63
b568d04f 64// ============================================================================
e2478fde 65// implementation: various entry points
b568d04f
VZ
66// ============================================================================
67
226c11c0
VZ
68#if wxUSE_BASE
69
84bdb0d8 70#if wxUSE_ON_FATAL_EXCEPTION && defined(__VISUALC__) && !defined(__WXWINCE__)
226c11c0
VZ
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
8c125d13 92// ----------------------------------------------------------------------------
3103e8a9 93// wrapper wxEntry catching all Win32 exceptions occurring in a wx program
8c125d13
VZ
94// ----------------------------------------------------------------------------
95
96// wrap real wxEntry in a try-except block to be able to call
97// OnFatalException() if necessary
226c11c0
VZ
98#if wxUSE_ON_FATAL_EXCEPTION
99
8c125d13
VZ
100// global pointer to exception information, only valid inside OnFatalException,
101// used by wxStackWalker and wxCrashReport
102extern EXCEPTION_POINTERS *wxGlobalSEInformation = NULL;
103
104// flag telling us whether the application wants to handle exceptions at all
105static bool gs_handleExceptions = false;
106
226c11c0
VZ
107static void wxFatalExit()
108{
109 // use the same exit code as abort()
110 ::ExitProcess(3);
111}
112
8c125d13
VZ
113unsigned 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
143static void wxSETranslator(unsigned int WXUNUSED(code), EXCEPTION_POINTERS *ep)
144{
226c11c0
VZ
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 }
8c125d13
VZ
166}
167
168#endif // __VISUALC__
169
170bool wxHandleFatalExceptions(bool doit)
171{
172 // assume this can only be called from the main thread
173 gs_handleExceptions = doit;
174
8c125d13
VZ
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
207int wxEntry(int& argc, wxChar **argv)
208{
226c11c0
VZ
209 DisableAutomaticSETranslator();
210
8c125d13
VZ
211 __try
212 {
8c125d13
VZ
213 return wxEntryReal(argc, argv);
214 }
215 __except ( wxGlobalSEHandler(GetExceptionInformation()) )
216 {
226c11c0 217 wxFatalExit();
8c125d13 218
e5f67955 219#if !defined(_MSC_VER) || defined(__WXDEBUG__) || (defined(_MSC_VER) && _MSC_VER <= 1200)
3d104ec3
WS
220 // this code is unreachable but put it here to suppress warnings in some compilers
221 // and disable for others to supress warnings too
8c125d13 222 return -1;
ad44b2c7 223#endif // !__VISUALC__ in release build
8c125d13
VZ
224 }
225}
226
226c11c0
VZ
227#else // !wxUSE_ON_FATAL_EXCEPTION
228
b734b2ca 229#if defined(__VISUALC__) && !defined(__WXWINCE__)
1ac4716d 230
226c11c0
VZ
231static void
232wxSETranslator(unsigned int WXUNUSED(code), EXCEPTION_POINTERS * WXUNUSED(ep))
233{
234 // see wxSETranslator() version for wxUSE_ON_FATAL_EXCEPTION above
235 throw;
236}
237
1ac4716d
VZ
238#endif // __VISUALC__
239
226c11c0
VZ
240int 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
8c125d13 250
532d575b 251#if wxUSE_GUI && defined(__WXMSW__)
8c125d13 252
6f2df739
VZ
253#if wxUSE_UNICODE && !defined(__WXWINCE__)
254 #define NEED_UNICODE_CHECK
255#endif
94826170 256
6f2df739
VZ
257#ifdef NEED_UNICODE_CHECK
258
259// check whether Unicode is available
260static bool wxIsUnicodeAvailable()
94826170 261{
6f2df739
VZ
262 static const wchar_t *ERROR_STRING = L"wxWidgets Fatal Error";
263
bd866271
VZ
264 if ( wxGetOsVersion() != wxWINDOWS_NT )
265 {
69c54afe
VZ
266 // we need to be built with MSLU support
267#if !wxUSE_UNICODE_MSLU
bd866271
VZ
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,
6f2df739
VZ
274 L"This program uses Unicode and requires Windows NT/2000/XP.\n"
275 L"\n"
276 L"Program aborted.",
277 ERROR_STRING,
bd866271
VZ
278 MB_ICONERROR | MB_OK
279 );
280
6f2df739 281 return false;
774960ce 282#else // wxUSE_UNICODE_MSLU
69c54afe
VZ
283 // and the MSLU DLL must also be available
284 HMODULE hmod = ::LoadLibraryA("unicows.dll");
285 if ( !hmod )
286 {
287 ::MessageBox
288 (
289 NULL,
6f2df739
VZ
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,
69c54afe
VZ
295 MB_ICONERROR | MB_OK
296 );
6f2df739 297 return false;
69c54afe
VZ
298 }
299
300 // this is not really necessary but be tidy
301 ::FreeLibrary(hmod);
6f2df739
VZ
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);
774960ce 323#endif // !wxUSE_UNICODE_MSLU
bd866271 324 }
6f2df739
VZ
325
326 return true;
327}
328
329#endif // NEED_UNICODE_CHECK
330
331// ----------------------------------------------------------------------------
332// Windows-specific wxEntry
333// ----------------------------------------------------------------------------
334
48733d47
VZ
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
339static 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
6f2df739
VZ
349WXDLLEXPORT 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
bd866271
VZ
361
362
94826170 363 // remember the parameters Windows gave us
13bdd545 364 wxSetInstance(hInstance);
94826170
VZ
365 wxApp::m_nCmdShow = nCmdShow;
366
b2b1371c
VZ
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;
13a5a49f 373
b2b1371c
VZ
374 const wxChar *cmdLine = ::GetCommandLine();
375 if ( cmdLine )
376 {
377 args = wxCmdLineParser::ConvertStringToArgs(cmdLine);
378 }
379
13a5a49f 380#ifdef __WXWINCE__
77d8d6cd
VZ
381 // WinCE doesn't insert the program itself, so do it ourselves.
382 args.Insert(wxGetFullModuleName(), 0);
13a5a49f
JS
383#endif
384
b2b1371c
VZ
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;
94826170 396
48733d47
VZ
397 wxON_BLOCK_EXIT2(wxFreeArgs, argc, argv);
398
94826170
VZ
399 return wxEntry(argc, argv);
400}
401
532d575b 402#endif // wxUSE_GUI && __WXMSW__
94826170 403
b568d04f 404// ----------------------------------------------------------------------------
e2478fde 405// global HINSTANCE
b568d04f
VZ
406// ----------------------------------------------------------------------------
407
ec67cff1 408#if wxUSE_BASE
e2478fde
VZ
409
410HINSTANCE wxhInstance = 0;
411
028e7716 412extern "C" HINSTANCE wxGetInstance()
b568d04f
VZ
413{
414 return wxhInstance;
415}
416
417void wxSetInstance(HINSTANCE hInst)
418{
419 wxhInstance = hInst;
420}
2bda0e17 421
ec67cff1 422#endif // wxUSE_BASE
e2478fde 423