]> git.saurik.com Git - wxWidgets.git/blob - src/msw/main.cpp
wxMSW: return correct value from wxMessageDialog::GetReturnCode().
[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 // Copyright: (c) Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #ifndef WX_PRECOMP
27 #include "wx/event.h"
28 #include "wx/app.h"
29 #include "wx/utils.h"
30 #endif //WX_PRECOMP
31
32 #include "wx/cmdline.h"
33 #include "wx/dynlib.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( wxT("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(wxT("GetTempPath"));
158
159 // when all else fails...
160 wxStrcpy(fullname, wxT("c:\\"));
161 }
162
163 // use PID and date to make the report file name more unique
164 wxString name = wxString::Format
165 (
166 wxT("%s_%s_%lu.dmp"),
167 wxTheApp ? (const wxChar*)wxTheApp->GetAppDisplayName().c_str()
168 : wxT("wxwindows"),
169 wxDateTime::Now().Format(wxT("%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
205
206 namespace
207 {
208
209 #if wxUSE_UNICODE && !defined(__WXWINCE__)
210 #define NEED_UNICODE_CHECK
211 #endif
212
213 #ifdef NEED_UNICODE_CHECK
214
215 // check whether Unicode is available
216 bool wxIsUnicodeAvailable()
217 {
218 static const wchar_t *ERROR_STRING = L"wxWidgets Fatal Error";
219
220 if ( wxGetOsVersion() != wxOS_WINDOWS_NT )
221 {
222 // we need to be built with MSLU support
223 #if !wxUSE_UNICODE_MSLU
224 // note that we can use MessageBoxW() as it's implemented even under
225 // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs
226 // used by wxLocale are not
227 ::MessageBox
228 (
229 NULL,
230 L"This program uses Unicode and requires Windows NT/2000/XP.\n"
231 L"\n"
232 L"Program aborted.",
233 ERROR_STRING,
234 MB_ICONERROR | MB_OK
235 );
236
237 return false;
238 #else // wxUSE_UNICODE_MSLU
239 // and the MSLU DLL must also be available
240 HMODULE hmod = ::LoadLibraryA("unicows.dll");
241 if ( !hmod )
242 {
243 ::MessageBox
244 (
245 NULL,
246 L"This program uses Unicode and requires unicows.dll to work "
247 L"under current operating system.\n"
248 L"\n"
249 L"Please install unicows.dll and relaunch the program.",
250 ERROR_STRING,
251 MB_ICONERROR | MB_OK
252 );
253 return false;
254 }
255
256 // this is not really necessary but be tidy
257 ::FreeLibrary(hmod);
258
259 // finally do the last check: has unicows.lib initialized correctly?
260 hmod = ::LoadLibraryW(L"unicows.dll");
261 if ( !hmod )
262 {
263 ::MessageBox
264 (
265 NULL,
266 L"This program uses Unicode but is not using unicows.dll\n"
267 L"correctly and so cannot work under current operating system.\n"
268 L"Please contact the program author for an updated version.\n"
269 L"\n"
270 L"Program aborted.",
271 ERROR_STRING,
272 MB_ICONERROR | MB_OK
273 );
274
275 return false;
276 }
277
278 ::FreeLibrary(hmod);
279 #endif // !wxUSE_UNICODE_MSLU
280 }
281
282 return true;
283 }
284
285 #endif // NEED_UNICODE_CHECK
286
287 void wxSetProcessDPIAware()
288 {
289 #if wxUSE_DYNLIB_CLASS
290 typedef BOOL (WINAPI *SetProcessDPIAware_t)(void);
291 wxDynamicLibrary dllUser32(wxT("user32.dll"));
292 SetProcessDPIAware_t pfnSetProcessDPIAware =
293 (SetProcessDPIAware_t)dllUser32.RawGetSymbol(wxT("SetProcessDPIAware"));
294
295 if ( pfnSetProcessDPIAware )
296 pfnSetProcessDPIAware();
297 #endif // wxUSE_DYNLIB_CLASS
298 }
299
300 } //anonymous namespace
301
302 // ----------------------------------------------------------------------------
303 // Windows-specific wxEntry
304 // ----------------------------------------------------------------------------
305
306 struct wxMSWCommandLineArguments
307 {
308 wxMSWCommandLineArguments() { argc = 0; argv = NULL; }
309
310 void Init(const wxArrayString& args)
311 {
312 argc = args.size();
313
314 // +1 here for the terminating NULL
315 argv = new wxChar *[argc + 1];
316 for ( int i = 0; i < argc; i++ )
317 {
318 argv[i] = wxStrdup(args[i].t_str());
319 }
320
321 // argv[] must be NULL-terminated
322 argv[argc] = NULL;
323 }
324
325 void Free()
326 {
327 if ( !argc )
328 return;
329
330 for ( int i = 0; i < argc; i++ )
331 {
332 free(argv[i]);
333 }
334
335 wxDELETEA(argv);
336 argc = 0;
337 }
338
339 int argc;
340 wxChar **argv;
341 };
342
343 static wxMSWCommandLineArguments wxArgs;
344
345 // common part of wxMSW-specific wxEntryStart() and wxEntry() overloads
346 static bool
347 wxMSWEntryCommon(HINSTANCE hInstance, int nCmdShow)
348 {
349 // the first thing to do is to check if we're trying to run an Unicode
350 // program under Win9x w/o MSLU emulation layer - if so, abort right now
351 // as it has no chance to work and has all chances to crash
352 #ifdef NEED_UNICODE_CHECK
353 if ( !wxIsUnicodeAvailable() )
354 return false;
355 #endif // NEED_UNICODE_CHECK
356
357
358 // remember the parameters Windows gave us
359 wxSetInstance(hInstance);
360 #ifdef __WXMSW__
361 wxApp::m_nCmdShow = nCmdShow;
362 #endif
363
364 // parse the command line: we can't use pCmdLine in Unicode build so it is
365 // simpler to never use it at all (this also results in a more correct
366 // argv[0])
367
368 // break the command line in words
369 wxArrayString args;
370
371 const wxChar *cmdLine = ::GetCommandLine();
372 if ( cmdLine )
373 {
374 args = wxCmdLineParser::ConvertStringToArgs(cmdLine);
375 }
376
377 #ifdef __WXWINCE__
378 // WinCE doesn't insert the program itself, so do it ourselves.
379 args.Insert(wxGetFullModuleName(), 0);
380 #endif
381
382 wxArgs.Init(args);
383
384 return true;
385 }
386
387 WXDLLEXPORT bool wxEntryStart(HINSTANCE hInstance,
388 HINSTANCE WXUNUSED(hPrevInstance),
389 wxCmdLineArgType WXUNUSED(pCmdLine),
390 int nCmdShow)
391 {
392 if ( !wxMSWEntryCommon(hInstance, nCmdShow) )
393 return false;
394
395 return wxEntryStart(wxArgs.argc, wxArgs.argv);
396 }
397
398 WXDLLEXPORT int wxEntry(HINSTANCE hInstance,
399 HINSTANCE WXUNUSED(hPrevInstance),
400 wxCmdLineArgType WXUNUSED(pCmdLine),
401 int nCmdShow)
402 {
403 // wxWidgets library doesn't have problems with non-default DPI settings,
404 // so we can mark the app as "DPI aware" for Vista/Win7 (see
405 // http://msdn.microsoft.com/en-us/library/dd464659%28VS.85%29.aspx).
406 // Note that we intentionally do it here and not in wxApp, so that it
407 // doesn't happen if wx code is hosted in another app (e.g. a plugin).
408 wxSetProcessDPIAware();
409
410 if ( !wxMSWEntryCommon(hInstance, nCmdShow) )
411 return -1;
412
413 wxON_BLOCK_EXIT_OBJ0(wxArgs, wxMSWCommandLineArguments::Free);
414
415 return wxEntry(wxArgs.argc, wxArgs.argv);
416 }
417
418 #endif // wxUSE_GUI
419
420 // ----------------------------------------------------------------------------
421 // global HINSTANCE
422 // ----------------------------------------------------------------------------
423
424 #if wxUSE_BASE
425
426 HINSTANCE wxhInstance = 0;
427
428 extern "C" HINSTANCE wxGetInstance()
429 {
430 return wxhInstance;
431 }
432
433 void wxSetInstance(HINSTANCE hInst)
434 {
435 wxhInstance = hInst;
436 }
437
438 #endif // wxUSE_BASE