Use the standard function in Unicode build instead of our own emulation, it should give better results and is marginally more efficient as it does fewer heap allocations than our own wxCmdLineParser::ConvertStringToArgs().
338 lines
8.8 KiB
C++
338 lines
8.8 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/msw/main.cpp
|
|
// Purpose: WinMain/DllMain
|
|
// Author: Julian Smart
|
|
// Modified by:
|
|
// Created: 04/01/98
|
|
// Copyright: (c) Julian Smart
|
|
// Licence: wxWindows licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ============================================================================
|
|
// declarations
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// headers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// For compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/event.h"
|
|
#include "wx/app.h"
|
|
#include "wx/utils.h"
|
|
#endif //WX_PRECOMP
|
|
|
|
// wxCmdLineParser is only used when we can't use ::CommandLineToArgvW().
|
|
#if !wxUSE_UNICODE
|
|
#include "wx/cmdline.h"
|
|
#endif
|
|
#include "wx/dynlib.h"
|
|
|
|
#include "wx/msw/private.h"
|
|
#include "wx/msw/seh.h"
|
|
|
|
#if wxUSE_ON_FATAL_EXCEPTION
|
|
#include "wx/datetime.h"
|
|
#include "wx/msw/crashrpt.h"
|
|
#endif // wxUSE_ON_FATAL_EXCEPTION
|
|
|
|
#ifdef __BORLANDC__
|
|
// BC++ has to be special: its run-time expects the DLL entry point to be
|
|
// named DllEntryPoint instead of the (more) standard DllMain
|
|
#define DllMain DllEntryPoint
|
|
#endif // __BORLANDC__
|
|
|
|
// defined in common/init.cpp
|
|
extern int wxEntryReal(int& argc, wxChar **argv);
|
|
extern int wxEntryCleanupReal(int& argc, wxChar **argv);
|
|
|
|
// ============================================================================
|
|
// implementation: various entry points
|
|
// ============================================================================
|
|
|
|
#if wxUSE_BASE
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wrapper wxEntry catching all Win32 exceptions occurring in a wx program
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// wrap real wxEntry in a try-except block to be able to call
|
|
// OnFatalException() if necessary
|
|
#if wxUSE_ON_FATAL_EXCEPTION
|
|
|
|
// global pointer to exception information, only valid inside OnFatalException,
|
|
// used by wxStackWalker and wxCrashReport
|
|
extern EXCEPTION_POINTERS *wxGlobalSEInformation = NULL;
|
|
|
|
// flag telling us whether the application wants to handle exceptions at all
|
|
static bool gs_handleExceptions = false;
|
|
|
|
static void wxFatalExit()
|
|
{
|
|
// use the same exit code as abort()
|
|
::ExitProcess(3);
|
|
}
|
|
|
|
unsigned long wxGlobalSEHandler(EXCEPTION_POINTERS *pExcPtrs)
|
|
{
|
|
if ( gs_handleExceptions && wxTheApp )
|
|
{
|
|
// store the pointer to exception info
|
|
wxGlobalSEInformation = pExcPtrs;
|
|
|
|
// give the user a chance to do something special about this
|
|
wxSEH_TRY
|
|
{
|
|
wxTheApp->OnFatalException();
|
|
}
|
|
wxSEH_IGNORE // ignore any exceptions inside the exception handler
|
|
|
|
wxGlobalSEInformation = NULL;
|
|
|
|
// this will execute our handler and terminate the process
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
}
|
|
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
|
|
#ifdef __VISUALC__
|
|
|
|
void wxSETranslator(unsigned int WXUNUSED(code), EXCEPTION_POINTERS *ep)
|
|
{
|
|
switch ( wxGlobalSEHandler(ep) )
|
|
{
|
|
default:
|
|
wxFAIL_MSG( wxT("unexpected wxGlobalSEHandler() return value") );
|
|
// fall through
|
|
|
|
case EXCEPTION_EXECUTE_HANDLER:
|
|
// if wxApp::OnFatalException() had been called we should exit the
|
|
// application -- but we shouldn't kill our host when we're a DLL
|
|
#ifndef WXMAKINGDLL
|
|
wxFatalExit();
|
|
#endif // not a DLL
|
|
break;
|
|
|
|
case EXCEPTION_CONTINUE_SEARCH:
|
|
// we're called for each "catch ( ... )" and if we (re)throw from
|
|
// here, the catch handler body is not executed, so the effect is
|
|
// as if had inhibited translation of SE to C++ ones because the
|
|
// handler will never see any structured exceptions
|
|
throw;
|
|
}
|
|
}
|
|
|
|
#endif // __VISUALC__
|
|
|
|
bool wxHandleFatalExceptions(bool doit)
|
|
{
|
|
// assume this can only be called from the main thread
|
|
gs_handleExceptions = doit;
|
|
|
|
#if wxUSE_CRASHREPORT
|
|
if ( doit )
|
|
{
|
|
// try to find a place where we can put out report file later
|
|
wxChar fullname[MAX_PATH];
|
|
if ( !::GetTempPath(WXSIZEOF(fullname), fullname) )
|
|
{
|
|
wxLogLastError(wxT("GetTempPath"));
|
|
|
|
// when all else fails...
|
|
wxStrcpy(fullname, wxT("c:\\"));
|
|
}
|
|
|
|
// use PID and date to make the report file name more unique
|
|
wxString name = wxString::Format
|
|
(
|
|
#if wxUSE_DATETIME
|
|
wxT("%s_%s_%lu.dmp"),
|
|
#else
|
|
wxT("%s_%lu.dmp"),
|
|
#endif
|
|
wxTheApp ? (const wxChar*)wxTheApp->GetAppDisplayName().c_str()
|
|
: wxT("wxwindows"),
|
|
#if wxUSE_DATETIME
|
|
wxDateTime::Now().Format(wxT("%Y%m%dT%H%M%S")).c_str(),
|
|
#endif
|
|
::GetCurrentProcessId()
|
|
);
|
|
|
|
wxStrncat(fullname, name, WXSIZEOF(fullname) - wxStrlen(fullname) - 1);
|
|
|
|
wxCrashReport::SetFileName(fullname);
|
|
}
|
|
#endif // wxUSE_CRASHREPORT
|
|
|
|
return true;
|
|
}
|
|
|
|
int wxEntry(int& argc, wxChar **argv)
|
|
{
|
|
DisableAutomaticSETranslator();
|
|
|
|
wxSEH_TRY
|
|
{
|
|
return wxEntryReal(argc, argv);
|
|
}
|
|
wxSEH_HANDLE(-1)
|
|
}
|
|
|
|
#else // !wxUSE_ON_FATAL_EXCEPTION
|
|
|
|
int wxEntry(int& argc, wxChar **argv)
|
|
{
|
|
return wxEntryReal(argc, argv);
|
|
}
|
|
|
|
#endif // wxUSE_ON_FATAL_EXCEPTION/!wxUSE_ON_FATAL_EXCEPTION
|
|
|
|
#endif // wxUSE_BASE
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Windows-specific wxEntry
|
|
// ----------------------------------------------------------------------------
|
|
|
|
struct wxMSWCommandLineArguments
|
|
{
|
|
wxMSWCommandLineArguments() { argc = 0; argv = NULL; }
|
|
|
|
// Initialize this object from the current process command line.
|
|
//
|
|
// In Unicode build prefer to use the standard function for tokenizing the
|
|
// command line, but we can't use it with narrow strings, so use our own
|
|
// approximation instead then.
|
|
#if wxUSE_UNICODE
|
|
void Init()
|
|
{
|
|
argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
|
|
}
|
|
|
|
~wxMSWCommandLineArguments()
|
|
{
|
|
if ( argc )
|
|
::LocalFree(argv);
|
|
}
|
|
#else // !wxUSE_UNICODE
|
|
void Init()
|
|
{
|
|
// Get the command line.
|
|
const wxChar* const cmdLine = ::GetCommandLine();
|
|
if ( !cmdLine )
|
|
return;
|
|
|
|
// And tokenize it.
|
|
const wxArrayString args = wxCmdLineParser::ConvertStringToArgs(cmdLine);
|
|
|
|
argc = args.size();
|
|
|
|
// +1 here for the terminating NULL
|
|
argv = new wxChar *[argc + 1];
|
|
for ( int i = 0; i < argc; i++ )
|
|
{
|
|
argv[i] = wxStrdup(args[i].t_str());
|
|
}
|
|
|
|
// argv[] must be NULL-terminated
|
|
argv[argc] = NULL;
|
|
}
|
|
|
|
~wxMSWCommandLineArguments()
|
|
{
|
|
if ( !argc )
|
|
return;
|
|
|
|
for ( int i = 0; i < argc; i++ )
|
|
{
|
|
free(argv[i]);
|
|
}
|
|
|
|
wxDELETEA(argv);
|
|
argc = 0;
|
|
}
|
|
#endif // wxUSE_UNICODE/!wxUSE_UNICODE
|
|
|
|
int argc;
|
|
wxChar **argv;
|
|
};
|
|
|
|
static wxMSWCommandLineArguments wxArgs;
|
|
|
|
#if wxUSE_GUI
|
|
|
|
// common part of wxMSW-specific wxEntryStart() and wxEntry() overloads
|
|
static bool
|
|
wxMSWEntryCommon(HINSTANCE hInstance, int nCmdShow)
|
|
{
|
|
// remember the parameters Windows gave us
|
|
wxSetInstance(hInstance);
|
|
#ifdef __WXMSW__
|
|
wxApp::m_nCmdShow = nCmdShow;
|
|
#endif
|
|
|
|
wxArgs.Init();
|
|
|
|
return true;
|
|
}
|
|
|
|
WXDLLEXPORT bool wxEntryStart(HINSTANCE hInstance,
|
|
HINSTANCE WXUNUSED(hPrevInstance),
|
|
wxCmdLineArgType WXUNUSED(pCmdLine),
|
|
int nCmdShow)
|
|
{
|
|
if ( !wxMSWEntryCommon(hInstance, nCmdShow) )
|
|
return false;
|
|
|
|
return wxEntryStart(wxArgs.argc, wxArgs.argv);
|
|
}
|
|
|
|
WXDLLEXPORT int wxEntry(HINSTANCE hInstance,
|
|
HINSTANCE WXUNUSED(hPrevInstance),
|
|
wxCmdLineArgType WXUNUSED(pCmdLine),
|
|
int nCmdShow)
|
|
{
|
|
if ( !wxMSWEntryCommon(hInstance, nCmdShow) )
|
|
return -1;
|
|
|
|
return wxEntry(wxArgs.argc, wxArgs.argv);
|
|
}
|
|
|
|
#else // !wxUSE_GUI
|
|
|
|
int wxEntry()
|
|
{
|
|
wxArgs.Init();
|
|
|
|
return wxEntry(wxArgs.argc, wxArgs.argv);
|
|
}
|
|
|
|
#endif // wxUSE_GUI/!wxUSE_GUI
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// global HINSTANCE
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#if wxUSE_BASE
|
|
|
|
HINSTANCE wxhInstance = 0;
|
|
|
|
extern "C" HINSTANCE wxGetInstance()
|
|
{
|
|
return wxhInstance;
|
|
}
|
|
|
|
void wxSetInstance(HINSTANCE hInst)
|
|
{
|
|
wxhInstance = hInst;
|
|
}
|
|
|
|
#endif // wxUSE_BASE
|