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关联到窗口句柄上,,,