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