WTL/ATL CWindoesImp 組成筆記

CWindoesImp

template <class T, class TBase /* = CWindow */, class TWinTraits /* = CControlWinTraits */>
class ATL_NO_VTABLE CWindowImpl :

任何需要為特定 Control 填寫自己的 message handler callback,就需要繼承此 template。
並要求 Client 提供下列三件事

  • 將自身 class, 傳入當第一個 template T 參數(CRTP)
  • DECLARE_WND_CLASS, or DECLARE_WND_CLASS_EX
  • BEGIN_MSG_MAP(YOUR_CLASS) 與 END_MSG_MAP() 包起來的 Message Handler Map
  • (optional) Window Style 的 Traits
Predefined Traits
typedef CWinTraits<WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0>                  CControlWinTraits;
typedef CWinTraits<WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE>        CFrameWinTraits;
typedef CWinTraits<WS_OVERLAPPEDWINDOW | WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_MDICHILD>  CMDIChildWinTraits;

typedef CWinTraits<0, 0> CNullTraits;

繼承關係

CWindowImplRoot<TBase, Traits> 
     ^
CWindowImplBaseT<TBase, Traits>  
     ^
CWindowImpl<T, TBase, Traits>  
    ^
class YouWinImp : CWindowImpl<YouWinImp, CWindow, YourWinStyleTraits> 

CWindow

  • HWND Wrapper Class
  • 只有帶一個 data member HWND, cheap to copy
  • 包裝大部份圍繞著 HWND 的 window API

CWindowImpl

自帶 Handler Window 下游結構中,負責 window 註冊的相關職責。

  • 在 Create 裡做 Register,得到 atom 後,再 Chain 給 CWindowImplBaseT::Create。
  • 只留下 Window 註冊需要的名字, Style, 與背景顏色,以 Macro 的形式讓 Client 調整
    • DECLARE_WND_CLASS(NAME)
    • DECLARE_WND_CLASS_EX(NAME, STYLE, BKG_COLOR)
  • 並在 Window Create Function 提供大部份的 default 參數,降低使用難度。
template <class T, class TBase /* = CWindow */, class TWinTraits /* = CControlWinTraits */>
class ATL_NO_VTABLE CWindowImpl :
    public CWindowImplBaseT< TBase, TWinTraits >;

CWindowImplBaseT

自帶 Handler Window 中間結構中,負責 procedure 調換/重組相關職責。

  • 以 thunk 手法去重新改造 message procedure 的架構
    • 試著 subclass WNDCLASSEX::WNDPROC 導到 CWindowImplRoot 架好的 ProcessWindowMessage
    • Thunk 相關的 Setup 動作埋進 StartWindowProc
    • 接著在 Create 做實際的 CreateWindow
template <class TBase = CWindow, class TWinTraits = CControlWinTraits>
class ATL_NO_VTABLE CWindowImplBaseT : 
    public CWindowImplRoot< TBase >;

Consists of:

  - WNDPROC m_pfnSuperWindowProc
  - static DWORD GetWndStyle(_In_ DWORD dwStyle);
  - static DWORD GetWndExStyle(_In_ DWORD dwExStyle);
  - static LRESULT CALLBACK StartWindowProc();
  - static LRESULT CALLBACK WindowProc();
  - HWND Create();
  - BOOL DestroyWindow();
  - BOOL SubclassWindow(_In_ HWND hWnd);
  - HWND UnsubclassWindow(_In_ BOOL bForce = FALSE;
  - LRESULT DefWindowProc();
  - virtual void OnFinalMessage(;

CWindowImplRoot:

自帶 Handler Window 最上層結構中,負責 Messge Routing 的架構。

  • 讓 Client 得以依 BEGIN_MSG_MAP / END_MSG_MAP Marco 對中,放置自訂的 Message Handler Map。
template <class TBase /* = CWindow */>
class ATL_NO_VTABLE CWindowImplRoot : 
    public TBase, 
    public CMessageMap;

Consist of

- BEGIN_MSG_MAP/END_MSG_MAP -(Extract)-> ProcessWindowMessage
- LRESULT ForwardNotifications();
- LRESULT ReflectNotifications();
- static _Success_(return != FALSE) BOOL DefaultReflectionHandler);

Example:

不需要自帶 Message Handler 的 Window Example:

CTabCtrl<CWindow>
    - 只是單純要為額外的 HWND 訊息(TabCtrl相關),而擴充。且沒有需要自己的 Message callback
    ex:
        int HitTest(TC_HITTESTINFO* pHitTestInfo) const
        {
            ATLASSERT(::IsWindow(m_hWnd));
            return (int)::SendMessage(m_hWnd, TCM_HITTEST, 0, (LPARAM)pHitTestInfo);
        }

想自己寫 Message Handler 的 WIndow Example:

CTabCtrlImp: CWindowImp<CTabCtrlImp, CWindow, ATL::CControlWinTraits>
                        ^            ^        ^-- 使用 Control Style
                        CRTP         |---最基本的 Window Wrapper  
{
    DECLARE_WND_CLASS_EX(NULL, 0, COLOR_APPWORKSPACE) <-- 背景顏色用 COLOR_APPWORKSPACE
                         ^     ^-- 無特定 style
                         |-由 ATL 幫忙 Gen
    ...
}
comments powered by Disqus