DirectUI笔记(一)窗口子类化

来源:互联网 发布:千语淘客助手软件下载 编辑:程序博客网 时间:2024/05/18 00:20
在看DirectUI的代码,尝试着写一些理解,可能有误,同时也不知道能写多少。写到哪算哪吧。

先谈谈窗口的子类化。

什么是DirectUI呢?
DirectUI界面库取名自微软的一个窗口类名“DirectUIHWND”,意为Paint on parent dc directly。即子窗口不以窗口句柄的形式创建,只是逻辑上的窗口,绘制在父窗口之上。这个父窗口就是使用windows sdk API CreateWindowEx 创建出来的窗口。这个窗口可以说是最原始的窗口了,当然,它拥有hWnd。我们之后的所有渲染工作(加载图片,营造各种绚丽效果)都是基于这个进行的。

我们还知道,Windows软件一个典型的特点是基于消息机制的。如果我们什么也不做,那么,当我们在界面上进行点击按钮,最大最小化窗口等操作的时候,它依然会“我行我素”。于是,为了使得软件按照我们设想的那样来处理消息,我们必须指定窗口过程,这个就是子类化的思想。窗口子类化技术最大的特点就是能够截取 Windows 的消息。一旦我们定义了窗口函数截取传向原窗口函数的消息,就可以对被截取的消息进行如下处理了。

怎么子类化呢?答案就是使用SubclassWindow和SetWindowLongPtr(可以用于64位系统)。SubclassWindow简单来说就是“动态地继承”窗口,一旦调用,就可以在原有基础上扩展自定义功能。(MFC的空间集成就是基于这个思想,只不过一切都预先封装好了)。比如:
CListCtrl   m_List   =   GetListCtrl(); 
CMyListCtrl   m_myList; 
m_myList.SubclassWindow(m_List); 

m_myList就具备了CListCtrl的所有特性了。
具体到DirectUI,我们要想使用我们自定义的窗口过程,同样需要子类化:

HWND CWindowWnd::Subclass(HWND hWnd)
{
    ASSERT(::IsWindow(hWnd));
    ASSERT(m_hWnd==NULL);
    m_OldWndProc = SubclassWindow(hWnd, __WndProc);
    if( m_OldWndProc == NULL ) return NULL;
    m_bSubclassed = true;
    m_hWnd = hWnd;
    return m_hWnd;
}

__WndProc就是自定义窗口过程,我们再来看看它的定义:
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);
    }
}
WM_NCCREATE消息是窗口收到的第一消息,在这个消息的处理里加入存在窗口对象的代码,那么,再收到后续的消息的时候,就可以使用GetWindowLongPtr来获取这个窗口对象,从而一步一步的下发消息到具体的控件(每个控件使用HandleMessage关注自身的消息,其它消息由系统处理)。
原创粉丝点击