Files
wxWidgets/src/common/init.cpp
Vadim Zeitlin 70a499f635 Don't rely on argv being NULL-terminated under MSW
Since the changes of c9a458bfe8 ("Use Win32
::CommandLineToArgvW() to tokenize command line"), this is not guaranteed any
more as this Win32 function doesn't necessarily ensure it under older MSW
versions such as XP.

Just use "argc" explicitly instead of relying on this in wxCmdLineArgsArray to
fix crashing under XP.
2017-04-16 17:50:22 +02:00

566 lines
16 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/common/init.cpp
// Purpose: initialisation for the library
// Author: Vadim Zeitlin
// Modified by:
// Created: 04.10.99
// Copyright: (c) Vadim Zeitlin
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif //__BORLANDC__
#ifndef WX_PRECOMP
#include "wx/app.h"
#include "wx/filefn.h"
#include "wx/log.h"
#include "wx/intl.h"
#include "wx/module.h"
#endif
#include "wx/init.h"
#include "wx/thread.h"
#include "wx/scopedptr.h"
#include "wx/except.h"
#if defined(__WINDOWS__)
#include "wx/msw/private.h"
#include "wx/msw/msvcrt.h"
#ifdef wxCrtSetDbgFlag
static struct EnableMemLeakChecking
{
EnableMemLeakChecking()
{
// check for memory leaks on program exit (another useful flag
// is _CRTDBG_DELAY_FREE_MEM_DF which doesn't free deallocated
// memory which may be used to simulate low-memory condition)
wxCrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF);
}
} gs_enableLeakChecks;
#endif // wxCrtSetDbgFlag
#endif // __WINDOWS__
#if wxUSE_UNICODE && defined(__WXOSX__)
#include <locale.h>
#endif
// ----------------------------------------------------------------------------
// private classes
// ----------------------------------------------------------------------------
// we need a dummy app object if the user doesn't want to create a real one
class wxDummyConsoleApp : public wxAppConsole
{
public:
wxDummyConsoleApp() { }
virtual int OnRun() wxOVERRIDE { wxFAIL_MSG( wxT("unreachable code") ); return 0; }
virtual bool DoYield(bool, long) { return true; }
wxDECLARE_NO_COPY_CLASS(wxDummyConsoleApp);
};
// we need a special kind of auto pointer to wxApp which not only deletes the
// pointer it holds in its dtor but also resets the global application pointer
wxDECLARE_SCOPED_PTR(wxAppConsole, wxAppPtrBase)
wxDEFINE_SCOPED_PTR(wxAppConsole, wxAppPtrBase)
class wxAppPtr : public wxAppPtrBase
{
public:
explicit wxAppPtr(wxAppConsole *ptr = NULL) : wxAppPtrBase(ptr) { }
~wxAppPtr()
{
if ( get() )
{
// the pointer is going to be deleted in the base class dtor, don't
// leave the dangling pointer!
wxApp::SetInstance(NULL);
}
}
void Set(wxAppConsole *ptr)
{
reset(ptr);
wxApp::SetInstance(ptr);
}
wxDECLARE_NO_COPY_CLASS(wxAppPtr);
};
// class to ensure that wxAppBase::CleanUp() is called if our Initialize()
// fails
class wxCallAppCleanup
{
public:
wxCallAppCleanup(wxAppConsole *app) : m_app(app) { }
~wxCallAppCleanup() { if ( m_app ) m_app->CleanUp(); }
void Dismiss() { m_app = NULL; }
private:
wxAppConsole *m_app;
};
// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------
// suppress warnings about unused variables
static inline void Use(void *) { }
#define WX_SUPPRESS_UNUSED_WARN(x) Use(&x)
// ----------------------------------------------------------------------------
// initialization data
// ----------------------------------------------------------------------------
static struct InitData
{
InitData()
{
nInitCount = 0;
#if wxUSE_UNICODE
argc = argcOrig = 0;
// argv = argvOrig = NULL; -- not even really needed
#endif // wxUSE_UNICODE
}
// critical section protecting this struct
wxCRIT_SECT_DECLARE_MEMBER(csInit);
// number of times wxInitialize() was called minus the number of times
// wxUninitialize() was
size_t nInitCount;
#if wxUSE_UNICODE
int argc;
// if we receive the command line arguments as ASCII and have to convert
// them to Unicode ourselves (this is the case under Unix but not Windows,
// for example), we remember the converted argv here because we'll have to
// free it when doing cleanup to avoid memory leaks
wchar_t **argv;
// we also need to keep two copies, one passed to other functions, and one
// unmodified original; somebody may modify the former, so we need to have
// the latter to be able to free everything correctly
int argcOrig;
wchar_t **argvOrig;
#endif // wxUSE_UNICODE
wxDECLARE_NO_COPY_CLASS(InitData);
} gs_initData;
// ============================================================================
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// command line arguments ANSI -> Unicode conversion
// ----------------------------------------------------------------------------
#if wxUSE_UNICODE
static void ConvertArgsToUnicode(int argc, char **argv)
{
gs_initData.argvOrig = new wchar_t *[argc + 1];
gs_initData.argv = new wchar_t *[argc + 1];
int wargc = 0;
for ( int i = 0; i < argc; i++ )
{
#ifdef __DARWIN__
wxWCharBuffer buf(wxConvFileName->cMB2WX(argv[i]));
#else
wxWCharBuffer buf(wxConvLocal.cMB2WX(argv[i]));
#endif
if ( !buf )
{
wxLogWarning(_("Command line argument %d couldn't be converted to Unicode and will be ignored."),
i);
}
else // converted ok
{
gs_initData.argvOrig[wargc] = gs_initData.argv[wargc] = wxStrdup(buf);
wargc++;
}
}
gs_initData.argcOrig = gs_initData.argc = wargc;
gs_initData.argvOrig[wargc] =gs_initData.argv[wargc] = NULL;
}
static void FreeConvertedArgs()
{
if ( gs_initData.argvOrig )
{
for ( int i = 0; i < gs_initData.argcOrig; i++ )
{
free(gs_initData.argvOrig[i]);
// gs_initData.argv[i] normally points to the same data
}
wxDELETEA(gs_initData.argvOrig);
wxDELETEA(gs_initData.argv);
gs_initData.argcOrig = gs_initData.argc = 0;
}
}
#endif // wxUSE_UNICODE
// ----------------------------------------------------------------------------
// start up
// ----------------------------------------------------------------------------
// initialization which is always done (not customizable) before wxApp creation
static bool DoCommonPreInit()
{
#if wxUSE_UNICODE && defined(__WXOSX__)
// In OS X and iOS, wchar_t CRT functions convert to char* and fail under
// some locales. The safest fix is to set LC_CTYPE to UTF-8 to ensure that
// they can handle any input.
//
// Note that this must be done for any app, Cocoa or console, whether or
// not it uses wxLocale.
//
// See http://stackoverflow.com/questions/11713745/why-does-the-printf-family-of-functions-care-about-locale
setlocale(LC_CTYPE, "UTF-8");
#endif // wxUSE_UNICODE && defined(__WXOSX__)
#if wxUSE_LOG
// Reset logging in case we were cleaned up and are being reinitialized.
wxLog::DoCreateOnDemand();
// force wxLog to create a log target now: we do it because wxTheApp
// doesn't exist yet so wxLog will create a special log target which is
// safe to use even when the GUI is not available while without this call
// we could create wxApp in wxEntryStart() below, then log an error about
// e.g. failure to establish connection to the X server and wxLog would
// send it to wxLogGui (because wxTheApp does exist already) which, of
// course, can't be used in this case
//
// notice also that this does nothing if the user had set up a custom log
// target before -- which is fine as we want to give him this possibility
// (as it's impossible to override logging by overriding wxAppTraits::
// CreateLogTarget() before wxApp is created) and we just assume he knows
// what he is doing
wxLog::GetActiveTarget();
#endif // wxUSE_LOG
#ifdef __WINDOWS__
// GUI applications obtain HINSTANCE in their WinMain() but we also need to
// initialize the global wxhInstance variable for the console programs as
// they may need it too, so set it here if it wasn't done yet
if ( !wxGetInstance() )
{
wxSetInstance(::GetModuleHandle(NULL));
}
#endif // __WINDOWS__
return true;
}
// non customizable initialization done after wxApp creation and initialization
static bool DoCommonPostInit()
{
wxModule::RegisterModules();
if ( !wxModule::InitializeModules() )
{
wxLogError(_("Initialization failed in post init, aborting."));
return false;
}
return true;
}
bool wxEntryStart(int& argc, wxChar **argv)
{
// do minimal, always necessary, initialization
// --------------------------------------------
// initialize wxRTTI
if ( !DoCommonPreInit() )
return false;
// first of all, we need an application object
// -------------------------------------------
// the user might have already created it himself somehow
wxAppPtr app(wxTheApp);
if ( !app.get() )
{
// if not, he might have used wxIMPLEMENT_APP() to give us a
// function to create it
wxAppInitializerFunction fnCreate = wxApp::GetInitializerFunction();
if ( fnCreate )
{
// he did, try to create the custom wxApp object
app.Set((*fnCreate)());
}
}
if ( !app.get() )
{
// either wxIMPLEMENT_APP() was not used at all or it failed -- in
// any case we still need something
app.Set(new wxDummyConsoleApp);
}
// wxApp initialization: this can be customized
// --------------------------------------------
if ( !app->Initialize(argc, argv) )
return false;
// remember, possibly modified (e.g. due to removal of toolkit-specific
// parameters), command line arguments in member variables
app->argv.Init(argc, argv);
wxCallAppCleanup callAppCleanup(app.get());
// common initialization after wxTheApp creation
// ---------------------------------------------
if ( !DoCommonPostInit() )
return false;
// prevent the smart pointer from destroying its contents
app.release();
// and the cleanup object from doing cleanup
callAppCleanup.Dismiss();
#if wxUSE_LOG
// now that we have a valid wxApp (wxLogGui would have crashed if we used
// it before now), we can delete the temporary sink we had created for the
// initialization messages -- the next time logging function is called, the
// sink will be recreated but this time wxAppTraits will be used
delete wxLog::SetActiveTarget(NULL);
#endif // wxUSE_LOG
return true;
}
#if wxUSE_UNICODE
// we provide a wxEntryStart() wrapper taking "char *" pointer too
bool wxEntryStart(int& argc, char **argv)
{
ConvertArgsToUnicode(argc, argv);
if ( !wxEntryStart(gs_initData.argc, gs_initData.argv) )
{
FreeConvertedArgs();
return false;
}
return true;
}
#endif // wxUSE_UNICODE
// ----------------------------------------------------------------------------
// clean up
// ----------------------------------------------------------------------------
// cleanup done before destroying wxTheApp
static void DoCommonPreCleanup()
{
#if wxUSE_LOG
// flush the logged messages if any and don't use the current probably
// unsafe log target any more: the default one (wxLogGui) can't be used
// after the resources are freed which happens when we return and the user
// supplied one might be even more unsafe (using any wxWidgets GUI function
// is unsafe starting from now)
//
// notice that wxLog will still recreate a default log target if any
// messages are logged but that one will be safe to use until the very end
delete wxLog::SetActiveTarget(NULL);
#endif // wxUSE_LOG
}
// cleanup done after destroying wxTheApp
static void DoCommonPostCleanup()
{
wxModule::CleanUpModules();
// we can't do this in wxApp itself because it doesn't know if argv had
// been allocated
#if wxUSE_UNICODE
FreeConvertedArgs();
#endif // wxUSE_UNICODE
// use Set(NULL) and not Get() to avoid creating a message output object on
// demand when we just want to delete it
delete wxMessageOutput::Set(NULL);
#if wxUSE_LOG
// call this first as it has a side effect: in addition to flushing all
// logs for this thread, it also flushes everything logged from other
// threads
wxLog::FlushActive();
// and now delete the last logger as well
//
// we still don't disable log target auto-vivification even if any log
// objects created now will result in memory leaks because it seems better
// to leak memory which doesn't matter much considering the application is
// exiting anyhow than to not show messages which could still be logged
// from the user code (e.g. static dtors and such)
delete wxLog::SetActiveTarget(NULL);
#endif // wxUSE_LOG
}
void wxEntryCleanup()
{
DoCommonPreCleanup();
// delete the application object
if ( wxTheApp )
{
wxTheApp->CleanUp();
// reset the global pointer to it to NULL before destroying it as in
// some circumstances this can result in executing the code using
// wxTheApp and using half-destroyed object is no good
wxAppConsole * const app = wxApp::GetInstance();
wxApp::SetInstance(NULL);
delete app;
}
DoCommonPostCleanup();
}
// ----------------------------------------------------------------------------
// wxEntry
// ----------------------------------------------------------------------------
// for MSW the real wxEntry is defined in msw/main.cpp
#ifndef __WINDOWS__
#define wxEntryReal wxEntry
#endif // !__WINDOWS__
int wxEntryReal(int& argc, wxChar **argv)
{
// library initialization
wxInitializer initializer(argc, argv);
if ( !initializer.IsOk() )
{
#if wxUSE_LOG
// flush any log messages explaining why we failed
delete wxLog::SetActiveTarget(NULL);
#endif
return -1;
}
wxTRY
{
// app initialization
if ( !wxTheApp->CallOnInit() )
{
// don't call OnExit() if OnInit() failed
return -1;
}
// ensure that OnExit() is called if OnInit() had succeeded
class CallOnExit
{
public:
~CallOnExit() { wxTheApp->OnExit(); }
} callOnExit;
WX_SUPPRESS_UNUSED_WARN(callOnExit);
// app execution
return wxTheApp->OnRun();
}
wxCATCH_ALL( wxTheApp->OnUnhandledException(); return -1; )
}
#if wxUSE_UNICODE
// as with wxEntryStart, we provide an ANSI wrapper
int wxEntry(int& argc, char **argv)
{
ConvertArgsToUnicode(argc, argv);
return wxEntry(gs_initData.argc, gs_initData.argv);
}
#endif // wxUSE_UNICODE
// ----------------------------------------------------------------------------
// wxInitialize/wxUninitialize
// ----------------------------------------------------------------------------
bool wxInitialize()
{
int argc = 0;
return wxInitialize(argc, (wxChar**)NULL);
}
bool wxInitialize(int& argc, wxChar **argv)
{
wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit);
if ( gs_initData.nInitCount++ )
{
// already initialized
return true;
}
return wxEntryStart(argc, argv);
}
#if wxUSE_UNICODE
bool wxInitialize(int& argc, char **argv)
{
wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit);
if ( gs_initData.nInitCount++ )
{
// already initialized
return true;
}
return wxEntryStart(argc, argv);
}
#endif // wxUSE_UNICODE
void wxUninitialize()
{
wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit);
if ( --gs_initData.nInitCount == 0 )
{
wxEntryCleanup();
}
}