ATL和MFC的C++類和HWND的映射機制

最近看深入解析ATL這本書的時候看到ATL中的窗口類實現的時候,很是驚異於ATLThunk的運用技術,ATL運用Thunk技術把C++的成員函數置換成Windows窗口的消息處理函數。那麼更古老的MFC框架又是怎麼實現CWnd類到HWND窗口類之間的映射的呢? 下面的文章將ATLMFC的窗口封裝機制做個對比.

 

如果讓我完成C++類到HWND窗口的映射,我會寫如下的代碼

BOOL  CMyWnd::Create(...)

{

      ...

      HWND  hWnd  =  ::CreateWindowEx(...);

      this->m_hWnd = hWnd;

      //置換hWnd窗口過程

      ...

}

我相信很多程序員都會像這樣封裝的,但是這樣有一個很大的問題,API函數CreateWindowEx在創建返回之前,Windows已經發送了一些消息給創建好的窗口,其中包括很重要的WM_CREATE消息,而將C++的成員函數置換hWnd的窗口例程是在CreateWindowEx返回之後,因此C++的成員函數就沒辦法處理WM_CREATE消息,這可就不行了。看看MFCATL是怎麼完成的。

 

1. MFC的實現過程:

      MFCCWnd封裝了Windows窗口,其創建函數爲CreateEx成員函數,CreateEx函數在調用CreateWindowEx方法之前首先通過AfxHookWindowCreate函數建立一個CBT鉤子,該鉤子的作用在於鉤取創建窗口的事件.趕在創建窗口完成之前建立HWNDCWnd的全局映射,之後置換窗口處理函數爲AfxWndProc標準函數,這樣做的目的在於CreateEx函數內部調用CreateWindowEx API創建HWND, CreateWindowEx函數返回之後調用AfxUnhookWindowCreate卸載CBT鉤子。

AfxWndProc函數過程:

      從全局映射中取出與句柄HWND相對應的CWnd對象,找到後調用CWnd:: WindowProc的成員函數,剩下的調用就在於CWnd中消息和消息處理函數的映射表了.

 

2.ATL的實現過程:

      ATL中的宏DECLARE_WND_CLASSCWindowImpl類提供Windows窗口的註冊信息,其定義如下:

#define DECLARE_WND_CLASS(WndClassName) /

static ATL::CWndClassInfo& GetWndClassInfo() /

{ /

      static ATL::CWndClassInfo wc = /

      { /

           { sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, StartWindowProc, /

             0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL }, /

           NULL, NULL, IDC_ARROW, TRUE, 0, _T("") /

      }; /

      return wc; /

}

通過宏代碼可以看出,其提供給註冊的窗口例程爲StartWindowProc函數, StartWindowProc函數代碼如下:

 

Windows發送第一個消息給hWnd窗口時,ATL完成CWindowImplhWnd的映射。據《深入解析ATL》介紹:第一個窗口消息發生在Windows 第一次把新的HWND傳遞給應用程序時。它發生在CreateWindow(Ex)返回HWND之前。完成窗口類映射之後,接着應用Thunk技術把pThis的成員函數替換成hWnd的窗口例程,

最後調用pProc處理這次接收到的消息。真是嚴謹啊,一條消息都不會漏掉.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章