Bombs 是怎样工作起来的?
BombsApp
声明
/*
* Class representing the entire Application
*/
class BombsApp: public wxApp
{
public:
virtual bool OnInit() wxOVERRIDE;
//……
};
wxDECLARE_APP(BombsApp);
程序的初始化在OnInit中实现,但是windows程序的入口是winMain()怎么调过来的呢?
叮(Debug一下)
Oh!这么容易
双击WinMain跳到了 wxIMPLEMENT_APP 宏,果然C++的宏是最神奇的存在。
人肉展开
#define wxIMPLEMENT_APP(appname) \
wxIMPLEMENT_WX_THEME_SUPPORT \
wxIMPLEMENT_APP_NO_THEMES(appname)
#define wxIMPLEMENT_WX_THEME_SUPPORT
wxIMPLEMENT_WX_THEME_SUPPORT 等于空格
#define wxIMPLEMENT_APP_NO_THEMES(appname) \
wxIMPLEMENT_WXWIN_MAIN \
wxIMPLEMENT_APP_NO_MAIN(appname)
#define wxIMPLEMENT_WXWIN_MAIN \
extern "C" int WINAPI WinMain(HINSTANCE hInstance, \
HINSTANCE hPrevInstance, \
wxCmdLineArgType lpCmdLine, \
int nCmdShow) \
{ \
wxDISABLE_DEBUG_SUPPORT(); \
\
return wxEntry(hInstance, hPrevInstance, lpCmdLine, nCmdShow); \
}
OH! WinMain在这里
#define wxIMPLEMENT_APP_NO_MAIN(appname) \
appname& wxGetApp() { return *static_cast<appname*>(wxApp::GetInstance()); } \
wxAppConsole *wxCreateApp() \
{ \
wxAppConsole::CheckBuildOptions(WX_BUILD_OPTIONS_SIGNATURE, \
"your program"); \
return new appname; \
} \
wxAppInitializer \
wxTheAppInitializer((wxAppInitializerFunction) wxCreateApp)
还提供了 appname& wxGetApp() 函数的实现
工程右键 Proterties,如图位置设置一下预编译到文件。Rebuild一下,编不过无所谓。
把这个文件抓出来看下
845K行!!!我嘞个乖乖。搜WinMain找到关键的行,wxIMPLEMENT_APP(BombsApp); 就被展开为这一行了。
547个字符,我们还是格式化一下再看吧。
extern "C" int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, wxCmdLineArgType lpCmdLine, int nCmdShow)
{
;
;
return wxEntry(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
BombsApp& wxGetApp() {
return *static_cast<BombsApp*>(wxApp::GetInstance());
}
wxAppConsole* wxCreateApp()
{
wxAppConsole::CheckBuildOptions("3"
"."
"2"
" ("
"wchar_t"
",Visual C++ "
"1900"
",wx containers"
",compatible with 3.0"
")",
"your program");
return new BombsApp;
}
wxAppInitializer wxTheAppInitializer((wxAppInitializerFunction)wxCreateApp);
// Called to initialize the program
bool BombsApp::OnInit()
{
srand((unsigned)time(NULL));
m_frame = new BombsFrame(&m_game);
m_frame->NewGame(bombsID_EASY, false);
return true;
}
WinMain 执行之前,会先做全局变量(wxTheAppInitializer
)初始化。看名字就知道,这是初始化app用的对象。初始化wxAppInitializer
构造函数传入了 wxCreateApp()
函数指针,以备初始化时调用。wxCreateApp()
函数一共两行,抛去第一行支线情节,只做了创建并返回BombsApp这个工作。
起初我以为真实初始化时会再使用wxTheAppInitializer
,其实不然,这个对象在构造函数里就完成了自己的使命,此行执行过后它就没有存在的意义了。去看看 wxAppInitializer
的实现。
class WXDLLIMPEXP_BASE wxAppInitializer
{
public:
wxAppInitializer(wxAppInitializerFunction fn)
{ wxApp::SetInitializerFunction(fn); }
};
简单明了,把app初始化函数指针Set到了wxApp
里。
static void SetInitializerFunction(wxAppInitializerFunction fn)
{ ms_appInitFn = fn; }
static wxAppInitializerFunction GetInitializerFunction()
{ return ms_appInitFn; }
于是 wxApp::ms_appInitFn
中保存了初始化函数。
正式开始WinMain
WinMain
调用 wxEntry(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
WXDLLEXPORT int wxEntry(HINSTANCE hInstance,
HINSTANCE WXUNUSED(hPrevInstance),
wxCmdLineArgType WXUNUSED(pCmdLine),
int nCmdShow)
{
if ( !wxMSWEntryCommon(hInstance, nCmdShow) )
return -1;
return wxEntry(wxMSWCommandLineGetArgc(), wxMSWCommandLineGetArgv());
}
处理完参数继续调用wxEntry(wxMSWCommandLineGetArgc(), wxMSWCommandLineGetArgv());
int wxEntry(int& argc, wxChar **argv)
{
DisableAutomaticSETranslator();
wxSEH_TRY
{
return wxEntryReal(argc, argv);
}
wxSEH_HANDLE(-1)
}
支线情节先不要关注,继续执行wxEntryReal(argc, argv);
真的入口哈哈哈
int wxEntryReal(int& argc, wxChar **argv)
{
// library initialization
wxInitializer initializer(argc, argv);
……
// 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();
……
}
wxInitializer
这名字感觉有点熟悉,不出意外又是构造函数干活的一次性对象。
class WXDLLIMPEXP_BASE wxInitializer
{
public:
wxInitializer(int& argc, wxChar **argv)
{
m_ok = wxInitialize(argc, argv);
}
bool IsOk() const { return m_ok; }
~wxInitializer() { if ( m_ok ) wxUninitialize(); }
private:
bool m_ok;
};
这次明长一些,构造函数调用全局函数 wxInitialize(argc, argv);
做初始化工作,析构函数在必要的时候调用全局函数 wxUninitialize();
做反初始化。还有个状态查询函数,给使用者查看是不是初始化成功了。然后看 wxInitialize(argc, argv);
bool wxInitialize(int& argc, wxChar **argv)
{
if ( wxAtomicInc(gs_initData.nInitCount) != 1 )
{
// already initialized
return true;
}
return wxEntryStart(argc, argv);
}
防止重入然后调用 wxEntryStart(argc, argv);
bool wxEntryStart(int& argc, wxChar **argv)
{
// initialize wxRTTI
if ( !DoCommonPreInit() )
return false;
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)());
}
}
//省略大量支线情节
……
return true;
}
DoCommonPreInit()
看注释是在初始RTTI机制,挺重要的,但不是主线情节,略。
突然冒出一个 wxTheApp
以为是对象,其实是个宏。这个写法着实有点不推荐啊。
#define wxTheApp static_cast<wxApp*>(wxApp::GetInstance())
继续看看wxApp::GetInstance()
wxAppConsole *wxAppConsoleBase::ms_appInstance = NULL;
static wxAppConsole *GetInstance() { return ms_appInstance; }
static void SetInstance(wxAppConsole *app) { ms_appInstance = app; }
这里没有调用过SetInstance
,因此wxAppPtr app(wxTheApp);
获取到的是ms_appInstance的默认值NULL。wxAppPtr
是个指针包装,就不详细看了。很自然走到了wxAppInitializerFunction fnCreate = wxApp::GetInitializerFunction();
最早wxIMPLEMENT_APP
宏展开时设置进wxApp的初始化函数出场了。然后app.Set((*fnCreate)());
调用初始化函数,生成BombsApp
对象并调用wxAppPtr的Set函数。
void Set(wxAppConsole *ptr)
{
reset(ptr);
wxApp::SetInstance(ptr);
}
更新了wxAppPtr对象的指针,并且调用了wxApp::SetInstance
wxInitializer
看完回wxEntryReal(argc, argv);
,再抄一遍代码
int wxEntryReal(int& argc, wxChar **argv)
{
// library initialization
wxInitializer initializer(argc, argv);
……
// 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();
……
}
此时,wxTheApp
已经可以正确取到 BombsApp
了。wxTheApp->CallOnInit()
,于是我们终于看到了BombsApp的某一层基类。
class WXDLLIMPEXP_BASE wxAppConsoleBase
{
virtual bool CallOnInit() { return OnInit(); }
}
然后 return OnInit();
调用到了我们自己写的 OnInit()
。
然后 定义了一个 CallOnExit
内部类,和 他的唯一对象callOnExit
,又一个临时工。这位只在析构函数里干活。也就是出了自己的作用域就调用wxTheApp->OnExit();
不出意外的话,后面是启动消息循环了。wxTheApp->OnRun();
在某一层基类里有这样一个OnRun
int wxAppConsoleBase::OnRun()
{
return MainLoop();
}
终于看的比较清楚了,有点累。有空再补两个图,先歇了。