Win32程序与MFC程序构建顺序梳理

发布时间:2023年12月18日

Windows程序的生成顺序

Windows窗口的生命周期

初始化操作
  • 从WinMain函数开始,注册窗口;
  • 创建窗口;
    • 调用CreateWindow,为程序建立了一个窗口,作为程序的屏幕
      舞台。CreateWindow产生窗口之后会送出WM_CREATE消息给窗口函数,后者
      于是可以在此时做些初始化操作(例如配置内存、打开文件、设置窗口初始数据等)。
  • 显示刷新窗口
 ShowWindow (hwnd, iCmdShow) ;    //显示窗口
UpdateWindow (hwnd) ;    //刷新窗口
用户交互操作

GetMessage函数用于从消息队列中获取消息,DispatchMessage函数(在Windows USER模块的帮助下)则是将消息分派到相应的窗口函数进行处理。这是Windows编程中常见的一种机制,用于处理用户界面的交互和事件。

WM_QUIT是特定的消息类型,当接收到这个消息时,GetMessage会返回0并结束while循环,进而结束整个程序。
下图为Windows处理用户交互信息的过程:
在这里插入图片描述

关闭窗口

使用者按下系统菜单中的Close命令 -> 系统送出WM_CLOSE消息 -> DefWindowProc处理调用DestroyWindow -> Destroy Window送出WM_DESTROY消息 -> 程序对WM_DESTROY的标准反应是调用PostQuitMessage送出WM_QUIT消息 -> 消息循环中的GetMessage取得,如步骤2,结束消息循环.

MFC程序的生成顺序

通过Windows SDK程序可以得出程序运行的最重要的两部分为WinMain(初始化操作)、WinProcedure(处理信息)

MFC中类的派生关系:CObject->CCmdTarget->CWinThread->CWinApp

准备阶段1

MFC程序中WinMain函数的作用被CWinApp类取代了,它所负责的全部初始化工作和对消息解释及分派都有 CWinApp类的内部函数来完成,但是WinMain仍然存在,并且扮演着驾驭CWinApp的角色。CWinApp中几个最重要的函数如下:

virtual BOOL InitApplication();
virtual BOOL InitInstance();
virtual int Run();

在SDK程序设计中至关重要的主窗口句柄(就是那个hwnd,几乎程序所有有关窗口的操作都必须用到该句柄,它为Windows定位所要输出的信息 的目的窗口),它被存储在CWinThread中名为m_MainWnd的成员变量中,而CWinThread是CWinApp的父类。

准备阶段2

WndProc窗口函数与WinMain一样被变形后由单独生成的类进行了替代,替代它的是名为CFrameWnd的类,该类一般因程序不同而被继承为不同的模样,比较有代表性的一般形态如下:

class CMyFrameWnd : public CFrameWnd
{
public:
    CMyFrameWND();
    afx_msg void OnPaint();
    afx_msg boid OnAbout();
    DECLARE_MESSAGE_MAP();
};
程序构建及运行
  • 1、设置全局对象
    大量的CWinApp之中的成员变量由于theApp的诞生而进行了配置或被赋初值,因此我们完全可以说theApp这个Application object是整个程序的引爆器。
  • 2、the App配置完成之后,应有WinMain函数处理
    在…\Microsoft Visual Studio\VC98\MFC\SRC目录下可以找到一个名为WinMain.cpp的文件其中体现WinMain主要工作的代码为:
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow)
{
	...
	CWinApp* pApp = AfxGetApp();
	// AFX internal initialization
	if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
    goto InitFailure;
    if (pApp != NULL && !pApp->InitApplication())
    goto InitFailure;

    // Perform specific initializations
    if (!pThread->InitInstance())
    {...};
   nReturnCode = pThread->Run();
   }

重点为AfxWinInit函数调用、pApp->InitInstance(); nReturnCode=pApp->run();

  • 首先是AfxWinInit,它隐藏在APPINIT.CPP中,重要代码如下:
BOOL AFXAPI AfxWinInit(HINSTANCE hInstance, HINSTANCE hPrevInstance,
            LPTSTR lpCmdLine, int nCmdShow)
{	
		...
	    CWinApp* pApp = AfxGetApp();
	     if (pApp != NULL)
    {
        // Windows specific initialization (not done if no CWinApp)
        pApp->m_hInstance = hInstance;
       pApp->m_hPrevInstance = hPrevInstance;
       pApp->m_lpCmdLine = lpCmdLine;
       pApp->m_nCmdShow = nCmdShow;
        pApp->SetCurrentHandles();
    }
 }
  • pApp->InitInstance,CWinApp类中此函数是虚函数,由于程序改写了该函数,所以现在等于调用我们自己的InitInstance,我们的程序也将从这里开始自己主窗口的生命。生成的一个简单程序的这一段代码如下:
BOOL CTestApp::InitInstance()
{
	 ...	
	CMainFrame* pMainFrame = new CMainFrame;//调用了CMainFrame的构造函数
	 ...
	 if (!ProcessShellCommand(cmdInfo))
           return FALSE;

    m_pMainWnd->ShowWindow(SW_SHOW);    //这两行与SDK程序
    m_pMainWnd->UpdateWindow();         //极为相似
}
  • CWinApp::Run事实上指向CWinThread::Run,它位于THRDCORE.CPP中,代码如下:
int CWinThread::Run()
{
	while (bIdle &&
               !::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))
        {
            // call OnIdle while in bIdle state
            if (!OnIdle(lIdleCount++))
                bIdle = FALSE; // assume "no idle" state
        }

            // phase2: pump messages while available
        do
        {
            // pump message, but quit on WM_QUIT
            if (!PumpMessage())
                return ExitInstance();

            // reset "no idle" state after pumping "normal" message
            if (IsIdleMessage(&m_msgCur))
            {
                bIdle = TRUE;
                lIdleCount = 0;
            }

        } while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
    }

    ASSERT(FALSE); // not reachable
}
PumpMessage代码如下:
BOOL CWinThread::PumpMessage()
{
    ASSERT_VALID(this);
    if (!::GetMessage(&m_msgCur, NULL, NULL, NULL))
    {
        return FALSE;
    }

    // process this message

    if (m_msgCur.message != WM_KICKIDLE

          && !PreTranslateMessage(&m_msgCur))
    {
        ::TranslateMessage(&m_msgCur);//SDK相似代码
        ::DispatchMessage(&m_msgCur);
    }
    return TRUE;
}

MFC程序死亡调用顺序与Win32程序大同小异。
文章主要参考:
http://blog.chinaunix.net/uid-21169302-id-446230.html

文章来源:https://blog.csdn.net/usa_ham/article/details/134999303
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。