DirectUI是一種策略而不是一種技術,所謂的DirectUI應該是繞開Windows的一套HWND的管理而是自己管理窗口。自己的Event機制,自己的繪圖策略等等等,,,
CWindowWnd::__WndProc;
代碼對錯誤檢測有冗余,使用ASSERT在測試階段盡可能的暴露bug,但是release一樣能對bug敏感!
HWND CWindowWnd::Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, int x, int y, int cx, int cy, HMENU hMenu)
{
if( GetSuperClassName() != NULL && !RegisterSuperclass() ) return NULL;
if( GetSuperClassName() == NULL && !RegisterWindowClass() ) return NULL;
m_hWnd = ::CreateWindowEx(dwExStyle, GetWindowClassName(), pstrName, dwStyle, x, y, cx, cy, hwndParent, hMenu, CPaintManagerUI::GetResourceInstance(), this);
ASSERT(m_hWnd!=NULL);
return m_hWnd;
}
創建窗口之前首先檢查有沒有父窗口,如果有記錄他的部分信息,如果沒有注冊默認窗口類。
然后調用CreateWindow執行創建窗口的工作。
然后其它都是在API上做一下簡單的包裝,,,
接下來看看兩個窗口回調函數:
LRESULT CALLBACK CWindowWnd::__WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CWindowWnd* pThis = NULL;
if( uMsg == WM_NCCREATE ) {
LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
pThis = static_cast<CWindowWnd*>(lpcs->lpCreateParams);
pThis->m_hWnd = hWnd;
::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis));
}
else {
pThis = reinterpret_cast<CWindowWnd*>(::GetWindowLongPtr(hWnd, GWLP_USERDATA));
if( uMsg == WM_NCDESTROY && pThis != NULL ) {
LRESULT lRes = ::CallWindowProc(pThis->m_OldWndProc, hWnd, uMsg, wParam, lParam);
::SetWindowLongPtr(pThis->m_hWnd, GWLP_USERDATA, 0L);
if( pThis->m_bSubclassed ) pThis->Unsubclass();
pThis->m_hWnd = NULL;
pThis->OnFinalMessage(hWnd);
return lRes;
}
}
if( pThis != NULL ) {
return pThis->HandleMessage(uMsg, wParam, lParam);
}
else {
return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
}
}
LRESULT CALLBACK CWindowWnd::__ControlProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CWindowWnd* pThis = NULL;
if( uMsg == WM_NCCREATE ) {
LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
pThis = static_cast<CWindowWnd*>(lpcs->lpCreateParams);
::SetProp(hWnd, "WndX", (HANDLE) pThis);
pThis->m_hWnd = hWnd;
}
else {
pThis = reinterpret_cast<CWindowWnd*>(::GetProp(hWnd, "WndX"));
if( uMsg == WM_NCDESTROY && pThis != NULL ) {
LRESULT lRes = ::CallWindowProc(pThis->m_OldWndProc, hWnd, uMsg, wParam, lParam);
if( pThis->m_bSubclassed ) pThis->Unsubclass();
::SetProp(hWnd, "WndX", NULL);
pThis->m_hWnd = NULL;
pThis->OnFinalMessage(hWnd);
return lRes;
}
}
if( pThis != NULL ) {
return pThis->HandleMessage(uMsg, wParam, lParam);
}
else {
return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
}
}
::SetProp(hWnd, "WndX", (HANDLE) pThis);
SetProp為窗口添加一個新的屬性,,,偶覺得沒有必要用這么奇淫的技巧,,,
當工作在Wnd模式時直接全部是調用自己的窗口回調,當工作在Control模式是調用super回調函數。
這里的實際上是通過控件的子例化間接的hook了窗口消息。
在創建窗口的時候完成的子例化窗口類。
回到分析之前的那個問題:HWND 和 窗口對象是如何關聯起來的?
LPVOID lpParam // window-creation data
使用CreateWindowEx的時候會有一個機會提供創建參數,回調中的WM_NCCREATE會響應它,,,然后在這里把窗口句柄摳出來,再使用SetWindowLog關聯到窗口句柄上,,,