天天看点

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

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