wxWeights Demo学习(三)bombs

文章详细阐述了C++wxWidgets框架下,BombsApp应用程序如何从wxIMPLEMENT_APP宏开始,经过wxEntry和WinMain函数,到wxApp的初始化过程,包括wxAppConsole的实例化、OnInit调用等步骤,揭示了框架内部的工作机制。
摘要由CSDN通过智能技术生成

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();
}

终于看的比较清楚了,有点累。有空再补两个图,先歇了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值