1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/main.cpp
3 // Purpose: WinMain/DllMain
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
33 #include "wx/cmdline.h"
34 #include "wx/scopeguard.h"
36 #include "wx/msw/private.h"
37 #include "wx/msw/seh.h"
39 #if wxUSE_ON_FATAL_EXCEPTION
40 #include "wx/datetime.h"
41 #include "wx/msw/crashrpt.h"
42 #endif // wxUSE_ON_FATAL_EXCEPTION
45 // there is no ExitProcess() under CE but exiting the main thread has the
48 #define ExitProcess ExitThread
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__
58 #if defined(__WXMICROWIN__)
59 #define HINSTANCE HANDLE
62 // defined in common/init.cpp
63 extern int wxEntryReal(int& argc
, wxChar
**argv
);
64 extern int wxEntryCleanupReal(int& argc
, wxChar
**argv
);
66 // ============================================================================
67 // implementation: various entry points
68 // ============================================================================
72 #if wxUSE_ON_FATAL_EXCEPTION && defined(__VISUALC__) && !defined(__WXWINCE__)
73 // VC++ (at least from 4.0 up to version 7.1) is incredibly broken in that
74 // a "catch ( ... )" will *always* catch SEH exceptions in it even though
75 // it should have never been the case... to prevent such catches from
76 // stealing the exceptions from our wxGlobalSEHandler which is only called
77 // if the exception is not handled elsewhere, we have to also call it from
78 // a special SEH translator function which is called by VC CRT when a Win32
81 // this warns that /EHa (async exceptions) should be used when using
82 // _set_se_translator but, in fact, this doesn't seem to change anything
83 // with VC++ up to 8.0
85 #pragma warning(disable:4535)
88 // note that the SE translator must be called wxSETranslator!
89 #define DisableAutomaticSETranslator() _set_se_translator(wxSETranslator)
91 #define DisableAutomaticSETranslator()
92 #endif // __VISUALC__/!__VISUALC__
94 // ----------------------------------------------------------------------------
95 // wrapper wxEntry catching all Win32 exceptions occurring in a wx program
96 // ----------------------------------------------------------------------------
98 // wrap real wxEntry in a try-except block to be able to call
99 // OnFatalException() if necessary
100 #if wxUSE_ON_FATAL_EXCEPTION
102 // global pointer to exception information, only valid inside OnFatalException,
103 // used by wxStackWalker and wxCrashReport
104 extern EXCEPTION_POINTERS
*wxGlobalSEInformation
= NULL
;
106 // flag telling us whether the application wants to handle exceptions at all
107 static bool gs_handleExceptions
= false;
109 static void wxFatalExit()
111 // use the same exit code as abort()
115 unsigned long wxGlobalSEHandler(EXCEPTION_POINTERS
*pExcPtrs
)
117 if ( gs_handleExceptions
&& wxTheApp
)
119 // store the pointer to exception info
120 wxGlobalSEInformation
= pExcPtrs
;
122 // give the user a chance to do something special about this
125 wxTheApp
->OnFatalException();
127 wxSEH_IGNORE
// ignore any exceptions inside the exception handler
129 wxGlobalSEInformation
= NULL
;
131 // this will execute our handler and terminate the process
132 return EXCEPTION_EXECUTE_HANDLER
;
135 return EXCEPTION_CONTINUE_SEARCH
;
140 void wxSETranslator(unsigned int WXUNUSED(code
), EXCEPTION_POINTERS
*ep
)
142 switch ( wxGlobalSEHandler(ep
) )
145 wxFAIL_MSG( _T("unexpected wxGlobalSEHandler() return value") );
148 case EXCEPTION_EXECUTE_HANDLER
:
149 // if wxApp::OnFatalException() had been called we should exit the
150 // application -- but we shouldn't kill our host when we're a DLL
156 case EXCEPTION_CONTINUE_SEARCH
:
157 // we're called for each "catch ( ... )" and if we (re)throw from
158 // here, the catch handler body is not executed, so the effect is
159 // as if had inhibited translation of SE to C++ ones because the
160 // handler will never see any structured exceptions
165 #endif // __VISUALC__
167 bool wxHandleFatalExceptions(bool doit
)
169 // assume this can only be called from the main thread
170 gs_handleExceptions
= doit
;
172 #if wxUSE_CRASHREPORT
175 // try to find a place where we can put out report file later
176 wxChar fullname
[MAX_PATH
];
177 if ( !::GetTempPath(WXSIZEOF(fullname
), fullname
) )
179 wxLogLastError(_T("GetTempPath"));
181 // when all else fails...
182 wxStrcpy(fullname
, _T("c:\\"));
185 // use PID and date to make the report file name more unique
186 wxString name
= wxString::Format
189 wxTheApp
? (const wxChar
*)wxTheApp
->GetAppDisplayName().c_str()
191 wxDateTime::Now().Format(_T("%Y%m%dT%H%M%S")).c_str(),
192 ::GetCurrentProcessId()
195 wxStrncat(fullname
, name
, WXSIZEOF(fullname
) - wxStrlen(fullname
) - 1);
197 wxCrashReport::SetFileName(fullname
);
199 #endif // wxUSE_CRASHREPORT
204 int wxEntry(int& argc
, wxChar
**argv
)
206 DisableAutomaticSETranslator();
210 return wxEntryReal(argc
, argv
);
215 #else // !wxUSE_ON_FATAL_EXCEPTION
217 #if defined(__VISUALC__) && !defined(__WXWINCE__)
220 wxSETranslator(unsigned int WXUNUSED(code
), EXCEPTION_POINTERS
* WXUNUSED(ep
))
222 // see wxSETranslator() version for wxUSE_ON_FATAL_EXCEPTION above
226 #endif // __VISUALC__
228 int wxEntry(int& argc
, wxChar
**argv
)
230 DisableAutomaticSETranslator();
232 return wxEntryReal(argc
, argv
);
235 #endif // wxUSE_ON_FATAL_EXCEPTION/!wxUSE_ON_FATAL_EXCEPTION
239 #if wxUSE_GUI && defined(__WXMSW__)
241 #if wxUSE_UNICODE && !defined(__WXWINCE__)
242 #define NEED_UNICODE_CHECK
245 #ifdef NEED_UNICODE_CHECK
247 // check whether Unicode is available
248 static bool wxIsUnicodeAvailable()
250 static const wchar_t *ERROR_STRING
= L
"wxWidgets Fatal Error";
252 if ( wxGetOsVersion() != wxOS_WINDOWS_NT
)
254 // we need to be built with MSLU support
255 #if !wxUSE_UNICODE_MSLU
256 // note that we can use MessageBoxW() as it's implemented even under
257 // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs
258 // used by wxLocale are not
262 L
"This program uses Unicode and requires Windows NT/2000/XP.\n"
270 #else // wxUSE_UNICODE_MSLU
271 // and the MSLU DLL must also be available
272 HMODULE hmod
= ::LoadLibraryA("unicows.dll");
278 L
"This program uses Unicode and requires unicows.dll to work "
279 L
"under current operating system.\n"
281 L
"Please install unicows.dll and relaunch the program.",
288 // this is not really necessary but be tidy
291 // finally do the last check: has unicows.lib initialized correctly?
292 hmod
= ::LoadLibraryW(L
"unicows.dll");
298 L
"This program uses Unicode but is not using unicows.dll\n"
299 L
"correctly and so cannot work under current operating system.\n"
300 L
"Please contact the program author for an updated version.\n"
311 #endif // !wxUSE_UNICODE_MSLU
317 #endif // NEED_UNICODE_CHECK
319 // ----------------------------------------------------------------------------
320 // Windows-specific wxEntry
321 // ----------------------------------------------------------------------------
323 struct wxMSWCommandLineArguments
325 wxMSWCommandLineArguments() { argc
= 0; argv
= NULL
; }
327 void Init(const wxArrayString
& args
)
331 // +1 here for the terminating NULL
332 argv
= new wxChar
*[argc
+ 1];
333 for ( int i
= 0; i
< argc
; i
++ )
335 argv
[i
] = wxStrdup(args
[i
].wx_str());
338 // argv[] must be NULL-terminated
347 for ( int i
= 0; i
< argc
; i
++ )
361 static wxMSWCommandLineArguments wxArgs
;
363 // common part of wxMSW-specific wxEntryStart() and wxEntry() overloads
365 wxMSWEntryCommon(HINSTANCE hInstance
, int nCmdShow
)
367 // the first thing to do is to check if we're trying to run an Unicode
368 // program under Win9x w/o MSLU emulation layer - if so, abort right now
369 // as it has no chance to work and has all chances to crash
370 #ifdef NEED_UNICODE_CHECK
371 if ( !wxIsUnicodeAvailable() )
373 #endif // NEED_UNICODE_CHECK
376 // remember the parameters Windows gave us
377 wxSetInstance(hInstance
);
378 wxApp::m_nCmdShow
= nCmdShow
;
380 // parse the command line: we can't use pCmdLine in Unicode build so it is
381 // simpler to never use it at all (this also results in a more correct
384 // break the command line in words
387 const wxChar
*cmdLine
= ::GetCommandLine();
390 args
= wxCmdLineParser::ConvertStringToArgs(cmdLine
);
394 // WinCE doesn't insert the program itself, so do it ourselves.
395 args
.Insert(wxGetFullModuleName(), 0);
403 WXDLLEXPORT
bool wxEntryStart(HINSTANCE hInstance
,
404 HINSTANCE
WXUNUSED(hPrevInstance
),
405 wxCmdLineArgType
WXUNUSED(pCmdLine
),
408 if ( !wxMSWEntryCommon(hInstance
, nCmdShow
) )
411 return wxEntryStart(wxArgs
.argc
, wxArgs
.argv
);
414 WXDLLEXPORT
int wxEntry(HINSTANCE hInstance
,
415 HINSTANCE
WXUNUSED(hPrevInstance
),
416 wxCmdLineArgType
WXUNUSED(pCmdLine
),
419 if ( !wxMSWEntryCommon(hInstance
, nCmdShow
) )
422 wxON_BLOCK_EXIT_OBJ0(wxArgs
, wxMSWCommandLineArguments::Free
);
424 return wxEntry(wxArgs
.argc
, wxArgs
.argv
);
427 #endif // wxUSE_GUI && __WXMSW__
429 // ----------------------------------------------------------------------------
431 // ----------------------------------------------------------------------------
435 HINSTANCE wxhInstance
= 0;
437 extern "C" HINSTANCE
wxGetInstance()
442 void wxSetInstance(HINSTANCE hInst
)