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