Error

C++博客 首页 新随笔 联系 聚合 管理
  217 Posts :: 61 Stories :: 32 Comments :: 0 Trackbacks
首先谈谈我理解的DirectUI:
    DirectUI是一种策略而不是一种技术,所谓的DirectUI应该是绕开Windows的一套HWND的管理而是自己管理窗口。自己的Event机制,自己的绘图策略等等等,,,
    如果做的漂亮的话,应该是绘图API一层,窗口调度和消息派发处理一层,上面再是业务层,,,

    还是先看看UILib的代码先:

相关UML:
   
1.先复习下Windows窗口编程的基础:
    RegisterWindow -> CreateWindow -> ShowWindow -> UpdateWindow
    最为重要的参数:窗口类。
    窗口类中最重要的成员:窗口回调。
用上面的流程在追踪UILib:
bool CWindowWnd::RegisterWindowClass()
{
   WNDCLASS wc 
= { 0 };
   
   wc.lpfnWndProc 
= CWindowWnd::__WndProc;
   
   ATOM ret 
= ::RegisterClass(&wc);
   ASSERT(ret
!=NULL || ::GetLastError()==ERROR_CLASS_ALREADY_EXISTS);
   
return ret != NULL || ::GetLastError() == ERROR_CLASS_ALREADY_EXISTS;
}
复习中提到的最重要的最重要:wc.lpfnWndProc = 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关联到窗口句柄上,,,






posted on 2011-06-15 16:57 Enic 阅读(4973) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理