现在的位置: 首页 > 综合 > 正文

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

2018年02月07日 ⁄ 综合 ⁄ 共 3913字 ⁄ 字号 评论关闭

构造全局对象:   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 来进行处理

 

抱歉!评论已关闭.