MFC 应用程序初始化与消息传递的 生死因果

原创 2012年03月27日 16:37:10

构造全局对象:   theApp
应用程序对象(Applicate Object)的产生,内存于是获得配置,初值也设立,也调用了CWinApp的构造函数。
于是: CWinApp::m_pCurrentWinApp = this(this的动态指针类型是CMyWinApp,即:CWinApp::m_pCurrentWinApp = &theApp)。

theApp 配置完成之后,WinMain 登场。但我们并未撰写 WinMain程序代码。其实这是 MFC 早已准备好并由链接器直接加到应用程序代码中的。
代码如下:
extern "C"
int WINAPI   _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    return   AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}

int AFXAPI   AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    int nReturnCode = -1;
 CWinApp *pApp = AfxGetApp();
 
 if ( !AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
     goto InitFailure;
  
 if (!pApp->InitApplcation())
     goto InitFailure;
  
 if (!pApp->InitInstance())
 {
     if (pApp->m_pMainWnd != NULL)
  {
      TRACE0("Warning: Destroying non-NULL m_pMainWnd\n");
   pApp->m_pMainWnd->DestroyWindow();
  }
  nReturnCode = pApp->ExitInstance();
  goto InitFailure;
 }
 
 nReturnCode = pApp->Run();
 
 AfxWinTerm();
 return nReturnCode;
}

稍加整理,重点是调用了如下几个函数:
     AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow)
  pApp->InitApplcation()
  pApp->InitInstance()
  pApp->Run()

 

下面我们着手分析这四个函数在调用中,都具体做了那些操作。

AFX 应用程序内部初始化操作
     AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow)
                     |
        AfxInitThread()
   
  
MFC 为内部管理而做一些设置   
 pApp->InitApplcation() 

 
注册窗口类,设置窗口样式,创建窗口 ,窗口显示与更新
  pApp->InitInstance()
 
  BOOL CMyWinApp::InitInstance()
  {
     m_pMainWnd = new CMyFrameWnd;   // 创建一个框架窗口,将调用 CMyFrameWnd 类的构造函数
  m_pMainWnd->ShowWindow(m_nCmdShow);
  m_pMainWnd->UpDateWindow();
  }
 
  CMyFrameWnd::CMyFrameWnd()
  {
     Create(...)                    // Create 函数是个虚函数。但 CMyFrameWnd 并没有重写他,所以这里调用的是其父类CFrameWnd的Create函数
  ...
  }
 
  BOOL CFrameWnd::Create(...)
  {
     CreateEx(...)                  // CreateEx 是类 CWnd 的一个成员函数
  }
 
  BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle,
                      int x, int y, int nWidth, int nHeight,
       HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)
 {
     CREATESTRUCT    cs;               // 这里我们将设置窗口产生时样式,cs用于保存窗口样式的名个参数
  
  ...
  
  PreCreateWindow(cs)              // 在这里注册窗口类。注意,cs.lpszClass 用于保存,是注册后的窗口类的名字
  
  ::CreateWindowEx(cs.?, cs.?...)  // 创建窗口
 }
 
 BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT &cs)
 {
     if (cs.lpszClass = NULL)
  {
      AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG);
   cs.lpszClass = _afxWndFrameOrView;
  }
 }
 
 #define AfxDeferRegisterClass(fClass) \
 ((afxRegisteredClasses & fClass) ? TRUE : AfxEndDeferRegisterClass(fClass))
 这个宏表示,如果已经注册了fClass 这种窗口, MFC 什么都不做;否则就调用 AfxEndDefRegisterClass(fClass) 来注册窗口类
 
 之后将调用
 BOOL AFXAPI AfxEndDeferRegisterClass(short fClass)
 {
     ...          // 在这里,将根据给出的fClass 注册窗口类
 }
 
 // 我们发现,当 fClass = AFX_WNDFRAMEORVIEW_REG 时,其窗口类的类名就为 _afxWndFrameOrView

窗口显示与更新
当创建窗口的操作完成之后,我们再看回InitInstance 这个函数
  BOOL CMyWinApp::InitInstance()
  {
     m_pMainWnd = new CMyFrameWnd;   // 创建一个框架窗口,将调用 CMyFrameWnd 类的构造函数
  m_pMainWnd->ShowWindow(m_nCmdShow);
  m_pMainWnd->UpDateWindow();
  }

可以看到,程序在这里完成了窗口的显示和更新操作

消息循环
pApp->Run();
相当于调用:
CMyWinApp::Run()
后又调用
CWinThread::Run
do
{
    ::GetMessage(&msg,...);
 PreTranslateMessage(&msg);
 ::TranslateMessage(&msg);
 ::DispatchMessage(&msg);
}while (::PeekMessage(...));

之后,对于消息的处理将交由 窗口函数DefWindowProc来处理。
但 MFC 在这里又做了一些手脚,将消息送往了同是回调函数的::AfxWndProc,在AfxWndProc对消息进行处理

 

下面是消息的传递过程:
LRESULT CALLBACK AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
    CWnd *pWnd = CWnd::FromHandlePerManent(hWnd);
 return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);
}

LRESULT AFXAPI  AfxCallWndProc(CWnd *pWnd, HWND hWnd, UINT nMsg, WPARAM wParam = 0, LPARAM lParam = 0)
{
    lResult = pWnd->WindowProc(nMsg, wParam, lParam);    // WindowProc 是类 CWnd 的一个函数,其子类并没有重写
 ...
 return lResult;

 
 
LRESUTL CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lPararm)
{
    LRESULT lResult = 0;
 if (!OnWndMsg(message, wParam, lParam, &lResult))
     lResult = DefWindowProc(message, wParam, lParam);
  
 return lResult;
}

在 CWnd::WindowProc中调用了OnWndMsg,而当程序进入CWnd::OnWndMsg时,程序会对消息进行分类
如是标准消息,直线上溯
如是命令消息,拐弯上溯
如是通知消息,那又是另一种处理方式
因这里内容太多,我就不详细说明了

而如果没有找到消息的处理函数,将由 CWnd::DefWindowProc 来处理。
而在 CWnd::DefWindowProc 中,将由全局函数 DefWindowProc 来进行处理

 

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

MFC技术内幕系列之(一)---MFC应用程序“生死因果”内幕

 ///////////////////////////////////////////////////////////////////////////////////            ...

(转)将 MFC 应用程序移植到 Linux

http://www.ibm.com/developerworks/cn/linux/guitoolkit/l-mfc/index.html 循序渐进使用 wxWindows 的指南Markus Ne...

代码解释:智能设备的多平台 MFC 应用程序

无论是将 Visual Studio C++ 用于 Windows CE(移动)及其他流行的移动设备,还是使用嵌入式 Visual C++ 开发设备应用程序,您将发现针对智能设备的 C++ 多...

MFC 应用程序框架-程序入口和执行流程

一 MFC程序执行过程剖析 1)我们知道在WIN32API程序当中,程序的入口为WinMain函数,在这个函数当中我们完成注册窗口类,创建窗口,进入消息循环,最后由操作系统根据发送到程序窗口的消息调...

(八十五)应用程序间的跳转与消息传递

应用程序的跳转识别的是URL的协议头,每个应用都可以指定一个URL的协议头,以此作为跳转的依据,而URL的地址部分作为消息体。 【指定应用程序URL协议头的方法】 选择TARGETS->info-...

MFC程序的剖析及生死因果揭秘

SDK下Windows程序的编程:对于一般SDK下Windows程序的编程,其主要步骤如下: 各步骤说明: 1:WinMain函数:它是Windows程序的基础,也是入口点函数,当Windows系...
  • dby3579
  • dby3579
  • 2016年01月13日 20:01
  • 337

深入浅出MFC学习笔记(第6章 :MFC程序的生死因果)

第六章 :MFC程序的生死因果 本章主要是从MFC程序代码中,找出一个windows程序原本该有的程序入口点、窗口类注册、窗口产生、消息循环、窗口函数等操作。抽丝剥茧彻底理解一个MFC程序的诞生...

MFC应用程序中处理消息的顺序以及对话框关闭步骤

应用程序处理消息的过程: 1.AfxWndProc()        该函数负责接收消息,找到消息所属的CWnd对象,然后调用AfxCallWndProc  2.AfxCallWndProc()  该...

MFC的消息传递机制仿真

  • 2017年06月24日 20:27
  • 13.05MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:MFC 应用程序初始化与消息传递的 生死因果
举报原因:
原因补充:

(最多只允许输入30个字)