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/dynlib.h"
35 #include "wx/scopeguard.h"
37 #include "wx/msw/private.h"
38 #include "wx/msw/seh.h"
40 #if wxUSE_ON_FATAL_EXCEPTION
41 #include "wx/datetime.h"
42 #include "wx/msw/crashrpt.h"
43 #endif // wxUSE_ON_FATAL_EXCEPTION
46 // there is no ExitProcess() under CE but exiting the main thread has the
49 #define ExitProcess ExitThread
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__
59 #if defined(__WXMICROWIN__)
60 #define HINSTANCE HANDLE
63 // defined in common/init.cpp
64 extern int wxEntryReal(int& argc
, wxChar
**argv
);
65 extern int wxEntryCleanupReal(int& argc
, wxChar
**argv
);
67 // ============================================================================
68 // implementation: various entry points
69 // ============================================================================
73 // ----------------------------------------------------------------------------
74 // wrapper wxEntry catching all Win32 exceptions occurring in a wx program
75 // ----------------------------------------------------------------------------
77 // wrap real wxEntry in a try-except block to be able to call
78 // OnFatalException() if necessary
79 #if wxUSE_ON_FATAL_EXCEPTION
81 // global pointer to exception information, only valid inside OnFatalException,
82 // used by wxStackWalker and wxCrashReport
83 extern EXCEPTION_POINTERS
*wxGlobalSEInformation
= NULL
;
85 // flag telling us whether the application wants to handle exceptions at all
86 static bool gs_handleExceptions
= false;
88 static void wxFatalExit()
90 // use the same exit code as abort()
94 unsigned long wxGlobalSEHandler(EXCEPTION_POINTERS
*pExcPtrs
)
96 if ( gs_handleExceptions
&& wxTheApp
)
98 // store the pointer to exception info
99 wxGlobalSEInformation
= pExcPtrs
;
101 // give the user a chance to do something special about this
104 wxTheApp
->OnFatalException();
106 wxSEH_IGNORE
// ignore any exceptions inside the exception handler
108 wxGlobalSEInformation
= NULL
;
110 // this will execute our handler and terminate the process
111 return EXCEPTION_EXECUTE_HANDLER
;
114 return EXCEPTION_CONTINUE_SEARCH
;
119 void wxSETranslator(unsigned int WXUNUSED(code
), EXCEPTION_POINTERS
*ep
)
121 switch ( wxGlobalSEHandler(ep
) )
124 wxFAIL_MSG( wxT("unexpected wxGlobalSEHandler() return value") );
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
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
144 #endif // __VISUALC__
146 bool wxHandleFatalExceptions(bool doit
)
148 // assume this can only be called from the main thread
149 gs_handleExceptions
= doit
;
151 #if wxUSE_CRASHREPORT
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
) )
158 wxLogLastError(wxT("GetTempPath"));
160 // when all else fails...
161 wxStrcpy(fullname
, wxT("c:\\"));
164 // use PID and date to make the report file name more unique
165 wxString name
= wxString::Format
167 wxT("%s_%s_%lu.dmp"),
168 wxTheApp
? (const wxChar
*)wxTheApp
->GetAppDisplayName().c_str()
170 wxDateTime::Now().Format(wxT("%Y%m%dT%H%M%S")).c_str(),
171 ::GetCurrentProcessId()
174 wxStrncat(fullname
, name
, WXSIZEOF(fullname
) - wxStrlen(fullname
) - 1);
176 wxCrashReport::SetFileName(fullname
);
178 #endif // wxUSE_CRASHREPORT
183 int wxEntry(int& argc
, wxChar
**argv
)
185 DisableAutomaticSETranslator();
189 return wxEntryReal(argc
, argv
);
194 #else // !wxUSE_ON_FATAL_EXCEPTION
196 int wxEntry(int& argc
, wxChar
**argv
)
198 return wxEntryReal(argc
, argv
);
201 #endif // wxUSE_ON_FATAL_EXCEPTION/!wxUSE_ON_FATAL_EXCEPTION
210 #if wxUSE_UNICODE && !defined(__WXWINCE__)
211 #define NEED_UNICODE_CHECK
214 #ifdef NEED_UNICODE_CHECK
216 // check whether Unicode is available
217 bool wxIsUnicodeAvailable()
219 static const wchar_t *ERROR_STRING
= L
"wxWidgets Fatal Error";
221 if ( wxGetOsVersion() != wxOS_WINDOWS_NT
)
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
231 L
"This program uses Unicode and requires Windows NT/2000/XP.\n"
239 #else // wxUSE_UNICODE_MSLU
240 // and the MSLU DLL must also be available
241 HMODULE hmod
= ::LoadLibraryA("unicows.dll");
247 L
"This program uses Unicode and requires unicows.dll to work "
248 L
"under current operating system.\n"
250 L
"Please install unicows.dll and relaunch the program.",
257 // this is not really necessary but be tidy
260 // finally do the last check: has unicows.lib initialized correctly?
261 hmod
= ::LoadLibraryW(L
"unicows.dll");
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"
280 #endif // !wxUSE_UNICODE_MSLU
286 #endif // NEED_UNICODE_CHECK
288 void wxSetProcessDPIAware()
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"));
296 if ( pfnSetProcessDPIAware
)
297 pfnSetProcessDPIAware();
298 #endif // wxUSE_DYNLIB_CLASS
301 } //anonymous namespace
303 // ----------------------------------------------------------------------------
304 // Windows-specific wxEntry
305 // ----------------------------------------------------------------------------
307 struct wxMSWCommandLineArguments
309 wxMSWCommandLineArguments() { argc
= 0; argv
= NULL
; }
311 void Init(const wxArrayString
& args
)
315 // +1 here for the terminating NULL
316 argv
= new wxChar
*[argc
+ 1];
317 for ( int i
= 0; i
< argc
; i
++ )
319 argv
[i
] = wxStrdup(args
[i
].t_str());
322 // argv[] must be NULL-terminated
331 for ( int i
= 0; i
< argc
; i
++ )
344 static wxMSWCommandLineArguments wxArgs
;
346 // common part of wxMSW-specific wxEntryStart() and wxEntry() overloads
348 wxMSWEntryCommon(HINSTANCE hInstance
, int nCmdShow
)
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() )
356 #endif // NEED_UNICODE_CHECK
359 // remember the parameters Windows gave us
360 wxSetInstance(hInstance
);
362 wxApp::m_nCmdShow
= nCmdShow
;
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
369 // break the command line in words
372 const wxChar
*cmdLine
= ::GetCommandLine();
375 args
= wxCmdLineParser::ConvertStringToArgs(cmdLine
);
379 // WinCE doesn't insert the program itself, so do it ourselves.
380 args
.Insert(wxGetFullModuleName(), 0);
388 WXDLLEXPORT
bool wxEntryStart(HINSTANCE hInstance
,
389 HINSTANCE
WXUNUSED(hPrevInstance
),
390 wxCmdLineArgType
WXUNUSED(pCmdLine
),
393 if ( !wxMSWEntryCommon(hInstance
, nCmdShow
) )
396 return wxEntryStart(wxArgs
.argc
, wxArgs
.argv
);
399 WXDLLEXPORT
int wxEntry(HINSTANCE hInstance
,
400 HINSTANCE
WXUNUSED(hPrevInstance
),
401 wxCmdLineArgType
WXUNUSED(pCmdLine
),
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();
411 if ( !wxMSWEntryCommon(hInstance
, nCmdShow
) )
414 wxON_BLOCK_EXIT_OBJ0(wxArgs
, wxMSWCommandLineArguments::Free
);
416 return wxEntry(wxArgs
.argc
, wxArgs
.argv
);
421 // ----------------------------------------------------------------------------
423 // ----------------------------------------------------------------------------
427 HINSTANCE wxhInstance
= 0;
429 extern "C" HINSTANCE
wxGetInstance()
434 void wxSetInstance(HINSTANCE hInst
)