MFC学习笔记——应用程序框架分析(CWinApp)

本文介绍了MFC程序的启动过程,包括初始化、窗口注册与创建、消息循环等关键步骤。详细分析了从WinMain函数到消息循环的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://www.jizhuomi.com/school/c/154.html
程序运行都要有入口函数,在之前的C++教程中都是main函数,而Windows应用程序的入口函数是WinMain函数,MFC程序也是从WinMain函数开始的。

Windows SDK开发程序就是不使用MFC类库,直接用Windows API函数进行软件开发。

关于消息循环再简单说下,Windows应用程序是消息驱动的,系统或用户让应用程序进行某项操作或完成某个任务时会发送消息,进入程序的消息队列,然后消息循环会将消息队列中的消息取出,交予相应的窗口过程处理。由窗口过程函数指定具体的操作。

MFC应用程序
下面是MFC应用程序的运行流程,通过MFC库中代码进行分析:

首先在HelloWorld.cpp中定义全局对象theApp:

CHelloWorldApp theApp;

调用CWinApp和CHelloWorldApp的构造函数后,进入WinMain函数(位于appmodul.cpp中)。

extern "C" int WINAPI   
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,   
    _In_ LPTSTR lpCmdLine, int nCmdShow)   
#pragma warning(suppress: 4985)   
{   
    // call shared/exported WinMain   
    return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);   
}

在TCHAR.h中,有此定义:#define _tWinMain WinMain,所以这里的_tWinMain就是WinMain函数。它调用了AfxWinMain函数(位于WinMain.cpp中)。

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow)   
{    
       //.............略   
       // App global initializations (rare)   
       if (pApp != NULL && !pApp->InitApplication())   
              goto InitFailure;   

       if (!pThread->InitInstance())   
       {   
              //.........略   
       }   

       // Run函数位于THRDCORE.cpp中,由此函数进入消息循环   
       nReturnCode = pThread->Run();   

       //..............略   

       return nReturnCode;   
}

上面InitInstance函数的代码如下:

BOOL CTestApp::InitInstance()        
{       
       //.............略       
       CSingleDocTemplate* pDocTemplate;       
       pDocTemplate = new CSingleDocTemplate(       
              IDR_MAINFRAME,       
              RUNTIME_CLASS(CTestDoc),       
              RUNTIME_CLASS(CMainFrame),// main SDI frame window       
              RUNTIME_CLASS(CTestView));     
       if (!pDocTemplate)   
             return FALSE;     
       AddDocTemplate(pDocTemplate);       
       // Parse command line for standard shell commands, DDE, file open       

       CCommandLineInfo cmdInfo;       
       ParseCommandLine(cmdInfo);       

       //ProcessShellCommand位于AppUI2.cpp中,注册并创建窗口       
       if (!ProcessShellCommand(cmdInfo))       
             return FALSE;       

       m_pMainWnd->ShowWindow(SW_SHOW);       
       m_pMainWnd->UpdateWindow();       

       return TRUE;       
}

InitInstance中的ProcessShellCommand函数又调用了CMainFrame的LoadFrame函数注册并创建了窗口,执行完ProcessShellCommand函数以后,调用了m_pMainWnd的ShowWindow和UpdateWindow函数显示并更新框架窗口。

接下来该是消息循环了,上面的AfxWinMain函数中调用了pThread的Run函数(位于THRDCORE.cpp中),在Run中包含了消息循环。Run函数的代码如下:

int CWinThread::Run()       
{       
        .............// 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));       
       ..............略       
}       

BOOL CWinThread::PumpMessage()       
{     
       return AfxInternalPumpMessage();    
}    

BOOL AFXAPI AfxInternalPumpMessage()   
{   
       _AFX_THREAD_STATE *pState = AfxGetThreadState();   

       if (!::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL))          
       {       
             .............略       
       }       
       ...............if (pState->m_msgCur.message != WM_KICKIDLE && !AfxPreTranslateMessage(&(pState->m_msgCur)))   
       {   
             ::TranslateMessage(&(pState->m_msgCur));   
             ::DispatchMessage(&(pState->m_msgCur));   
       }     

       return TRUE;       
}

我们看到PumpMessage中通过调用GetMessage、TranslateMessage、DispatchMessage等建立了消息循环并投递消息。

窗口过程函数AfxWinProc形式如下:

LRESULT CALLBACK AfxWndProc(HWND hWnd,UINT nMsg,WPARAM wParam, LPARAM lParam)   
{   
      ……   
      CWnd*pWnd=CWnd::FromHandlePermanent(hWnd);  
      ReturnAfxCallWndProc(pWnd,hWnd,nMsg,wParam,lParam);   
}

MFC应用程序的运行流程与SDK程序是类似的,都是先进行一些初始化过程,再注册并创建窗口,然后显示、更新窗口,最后进入消息循环,消息都由窗口过程函数处理。现在大家是不是觉得有些头绪了?在运行流程上有基本的掌握即可。

  • CHelloWorldApp类处理消息,将收到的消息分发给相应的对象。
  • CMainFrame是视图CHelloWorldView的父窗口,视图CHelloWorldView就显示在CMainFrame的客户区中。
  • 视图类CHelloWorldView用来显示文档类CHelloWorldDoc中的数据,并根据对视图类的操作修改文档类的数据。一个视图类只能跟一个文档类相联系,而一个文档类可以跟多个视图类相联系。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值