zoukankan      html  css  js  c++  java
  • CWindowWnd类源码分析

    CWindowWnd代码在UIBase.h和UIBase.cpp文件里。主要实现的是一个基本窗口的创建与消息处理。

    相关代码:

    头文件:

    class UILIB_API CWindowWnd
        {
        public:
            CWindowWnd();
    
            HWND GetHWND() const;
            operator HWND() const;
    
            bool RegisterWindowClass();
            bool RegisterSuperclass();
    
            HWND Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, const RECT rc, HMENU hMenu = NULL);
            HWND Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, int x = CW_USEDEFAULT, int y = CW_USEDEFAULT, int cx = CW_USEDEFAULT, int cy = CW_USEDEFAULT, HMENU hMenu = NULL);
            HWND CreateDuiWindow(HWND hwndParent, LPCTSTR pstrWindowName,DWORD dwStyle =0, DWORD dwExStyle =0);
            HWND Subclass(HWND hWnd);
            void Unsubclass();
            void ShowWindow(bool bShow = true, bool bTakeFocus = true);
            UINT ShowModal();
            void Close(UINT nRet = IDOK);
            void CenterWindow();    // 居中,支持扩展屏幕
            void SetIcon(UINT nRes);
    
            LRESULT SendMessage(UINT uMsg, WPARAM wParam = 0, LPARAM lParam = 0L);
            LRESULT PostMessage(UINT uMsg, WPARAM wParam = 0, LPARAM lParam = 0L);
            void ResizeClient(int cx = -1, int cy = -1);
    
        protected:
            virtual LPCTSTR GetWindowClassName() const = 0;
            virtual LPCTSTR GetSuperClassName() const;
            virtual UINT GetClassStyle() const;
    
            virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
            virtual void OnFinalMessage(HWND hWnd);
    
            static LRESULT CALLBACK __WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
            static LRESULT CALLBACK __ControlProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    
        protected:
            HWND m_hWnd;
            WNDPROC m_OldWndProc;
            bool m_bSubclassed;
        };

    源文件:

    //////////////////////////////////////////////////////////////////////////
    ///
    CWindowWnd::CWindowWnd() : m_hWnd(NULL), m_OldWndProc(::DefWindowProc), m_bSubclassed(false)
    {
    }
    
    HWND CWindowWnd::GetHWND() const 
    { 
        return m_hWnd; 
    }
    
    UINT CWindowWnd::GetClassStyle() const
    {
        return 0;
    }
    
    LPCTSTR CWindowWnd::GetSuperClassName() const
    {
        return NULL;
    }
    
    CWindowWnd::operator HWND() const
    {
        return m_hWnd;
    }
    
    HWND CWindowWnd::CreateDuiWindow( HWND hwndParent, LPCTSTR pstrWindowName,DWORD dwStyle /*=0*/, DWORD dwExStyle /*=0*/ )
    {
        return Create(hwndParent,pstrWindowName,dwStyle,dwExStyle,0,0,0,0,NULL);
    }
    
    HWND CWindowWnd::Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, const RECT rc, HMENU hMenu)
    {
        return Create(hwndParent, pstrName, dwStyle, dwExStyle, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hMenu);
    }
    
    //调用创建win32创建窗口的API
    //如果是控件则GetSuperClassName返回非NULL 调用RegisterSuperclass
    //否则调用RegisterWindowClass
    //然后使用CreateWindowEx创建窗口
    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::GetInstance(), this);
        ASSERT(m_hWnd!=NULL);
        return m_hWnd;
    }
    
    //子类化一个控件 m_OldWndProc 保存旧消息处理函数
    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;
        ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(this));
        return m_hWnd;
    }
    
    //恢复之类化的控件
    void CWindowWnd::Unsubclass()
    {
        ASSERT(::IsWindow(m_hWnd));
        if( !::IsWindow(m_hWnd) ) return;
        if( !m_bSubclassed ) return;
        SubclassWindow(m_hWnd, m_OldWndProc);
        m_OldWndProc = ::DefWindowProc;
        m_bSubclassed = false;
    }
    
    void CWindowWnd::ShowWindow(bool bShow /*= true*/, bool bTakeFocus /*= false*/)
    {
        ASSERT(::IsWindow(m_hWnd));
        if( !::IsWindow(m_hWnd) ) return;
        ::ShowWindow(m_hWnd, bShow ? (bTakeFocus ? SW_SHOWNORMAL : SW_SHOWNOACTIVATE) : SW_HIDE);
    }
    
    //实现一个modal窗口 
    UINT CWindowWnd::ShowModal()
    {
        ASSERT(::IsWindow(m_hWnd));
        UINT nRet = 0;
        HWND hWndParent = GetWindowOwner(m_hWnd);
        ::ShowWindow(m_hWnd, SW_SHOWNORMAL);
        ::EnableWindow(hWndParent, FALSE);
        MSG msg = { 0 };
        while( ::IsWindow(m_hWnd) && ::GetMessage(&msg, NULL, 0, 0) ) {
            if( msg.message == WM_CLOSE && msg.hwnd == m_hWnd ) {
                nRet = msg.wParam;
                ::EnableWindow(hWndParent, TRUE);
                ::SetFocus(hWndParent);
            }
            if( !CPaintManagerUI::TranslateMessage(&msg) ) {
                ::TranslateMessage(&msg);
                ::DispatchMessage(&msg);
            }
            if( msg.message == WM_QUIT ) break;
        }
        ::EnableWindow(hWndParent, TRUE);
        ::SetFocus(hWndParent);
        if( msg.message == WM_QUIT ) ::PostQuitMessage(msg.wParam);
        return nRet;
    }
    
    void CWindowWnd::Close(UINT nRet)
    {
        ASSERT(::IsWindow(m_hWnd));
        if( !::IsWindow(m_hWnd) ) return;
        PostMessage(WM_CLOSE, (WPARAM)nRet, 0L);
    }
    
    void CWindowWnd::CenterWindow()
    {
        ASSERT(::IsWindow(m_hWnd));
        ASSERT((GetWindowStyle(m_hWnd)&WS_CHILD)==0);
        RECT rcDlg = { 0 };
        ::GetWindowRect(m_hWnd, &rcDlg);
        RECT rcArea = { 0 };
        RECT rcCenter = { 0 };
        HWND hWnd=*this;
        HWND hWndParent = ::GetParent(m_hWnd);
        HWND hWndCenter = ::GetWindowOwner(m_hWnd);
        if (hWndCenter!=NULL)
            hWnd=hWndCenter;
    
        // 处理多显示器模式下屏幕居中
        MONITORINFO oMonitor = {};
        oMonitor.cbSize = sizeof(oMonitor);
        ::GetMonitorInfo(::MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST), &oMonitor);
        rcArea = oMonitor.rcWork;
    
        if( hWndCenter == NULL )
            rcCenter = rcArea;
        else
            ::GetWindowRect(hWndCenter, &rcCenter);
    
        int DlgWidth = rcDlg.right - rcDlg.left;
        int DlgHeight = rcDlg.bottom - rcDlg.top;
    
        // Find dialog's upper left based on rcCenter
        int xLeft = (rcCenter.left + rcCenter.right) / 2 - DlgWidth / 2;
        int yTop = (rcCenter.top + rcCenter.bottom) / 2 - DlgHeight / 2;
    
        // The dialog is outside the screen, move it inside
        if( xLeft < rcArea.left ) xLeft = rcArea.left;
        else if( xLeft + DlgWidth > rcArea.right ) xLeft = rcArea.right - DlgWidth;
        if( yTop < rcArea.top ) yTop = rcArea.top;
        else if( yTop + DlgHeight > rcArea.bottom ) yTop = rcArea.bottom - DlgHeight;
        ::SetWindowPos(m_hWnd, NULL, xLeft, yTop, -1, -1, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
    }
    
    //从资源设置图标
    void CWindowWnd::SetIcon(UINT nRes)
    {
        HICON hIcon = (HICON)::LoadImage(CPaintManagerUI::GetInstance(), MAKEINTRESOURCE(nRes), IMAGE_ICON,
            (::GetSystemMetrics(SM_CXICON) + 15) & ~15, (::GetSystemMetrics(SM_CYICON) + 15) & ~15,    // 防止高DPI下图标模糊
            LR_DEFAULTCOLOR);
        ASSERT(hIcon);
        ::SendMessage(m_hWnd, WM_SETICON, (WPARAM) ICON_SMALL, (LPARAM) hIcon);
    
        hIcon = (HICON)::LoadImage(CPaintManagerUI::GetInstance(), MAKEINTRESOURCE(nRes), IMAGE_ICON,
            (::GetSystemMetrics(SM_CXICON) + 15) & ~15, (::GetSystemMetrics(SM_CYICON) + 15) & ~15,    // 防止高DPI下图标模糊
            LR_DEFAULTCOLOR);
        ASSERT(hIcon);
        ::SendMessage(m_hWnd, WM_SETICON, (WPARAM) ICON_BIG, (LPARAM) hIcon);
    }
    
    bool CWindowWnd::RegisterWindowClass()
    {
        WNDCLASS wc = { 0 };
        wc.style = GetClassStyle();
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hIcon = NULL;
        wc.lpfnWndProc = CWindowWnd::__WndProc;
        wc.hInstance = CPaintManagerUI::GetInstance();
        wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground = NULL;
        wc.lpszMenuName  = NULL;
        wc.lpszClassName = GetWindowClassName();
        ATOM ret = ::RegisterClass(&wc);
        ASSERT(ret!=NULL || ::GetLastError()==ERROR_CLASS_ALREADY_EXISTS);
        return ret != NULL || ::GetLastError() == ERROR_CLASS_ALREADY_EXISTS;
    }
    
    //这里应该是创建一个控件类,子类化过的
    bool CWindowWnd::RegisterSuperclass()
    {
        // Get the class information from an existing
        // window so we can subclass it later on...
        WNDCLASSEX wc = { 0 };
        wc.cbSize = sizeof(WNDCLASSEX);
        if( !::GetClassInfoEx(NULL, GetSuperClassName(), &wc) ) {
            if( !::GetClassInfoEx(CPaintManagerUI::GetInstance(), GetSuperClassName(), &wc) ) {
                ASSERT(!"Unable to locate window class");
                return NULL;
            }
        }
        m_OldWndProc = wc.lpfnWndProc;
        wc.lpfnWndProc = CWindowWnd::__ControlProc;
        wc.hInstance = CPaintManagerUI::GetInstance();
        wc.lpszClassName = GetWindowClassName();
        ATOM ret = ::RegisterClassEx(&wc);
        ASSERT(ret!=NULL || ::GetLastError()==ERROR_CLASS_ALREADY_EXISTS);
        return ret != NULL || ::GetLastError() == ERROR_CLASS_ALREADY_EXISTS;
    }
    
    //默认的消息处理函数 注册窗口时使用过
    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;
                //调用OnFinalMessage OnFinalMessage一般做最后的处理
                pThis->OnFinalMessage(hWnd);
                return lRes;
            }
        }
        if( pThis != NULL ) {
            //调用HandleMessage来处理消息
            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, _T("WndX"), (HANDLE) pThis);
            pThis->m_hWnd = hWnd;
        } 
        else {
            pThis = reinterpret_cast<CWindowWnd*>(::GetProp(hWnd, _T("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, _T("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);
        }
    }
    
    LRESULT CWindowWnd::SendMessage(UINT uMsg, WPARAM wParam /*= 0*/, LPARAM lParam /*= 0*/)
    {
        ASSERT(::IsWindow(m_hWnd));
        return ::SendMessage(m_hWnd, uMsg, wParam, lParam);
    } 
    
    LRESULT CWindowWnd::PostMessage(UINT uMsg, WPARAM wParam /*= 0*/, LPARAM lParam /*= 0*/)
    {
        ASSERT(::IsWindow(m_hWnd));
        return ::PostMessage(m_hWnd, uMsg, wParam, lParam);
    }
    
    void CWindowWnd::ResizeClient(int cx /*= -1*/, int cy /*= -1*/)
    {
        ASSERT(::IsWindow(m_hWnd));
        RECT rc = { 0 };
        if( !::GetClientRect(m_hWnd, &rc) ) return;
        if( cx != -1 ) rc.right = cx;
        if( cy != -1 ) rc.bottom = cy;
        if( !::AdjustWindowRectEx(&rc, GetWindowStyle(m_hWnd), (!(GetWindowStyle(m_hWnd) & WS_CHILD) && (::GetMenu(m_hWnd) != NULL)), GetWindowExStyle(m_hWnd)) ) return;
        ::SetWindowPos(m_hWnd, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
    }
    
    //虚函数 用于在子类里重写此函数接管消息
    LRESULT CWindowWnd::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        return ::CallWindowProc(m_OldWndProc, m_hWnd, uMsg, wParam, lParam);
    }
    
    void CWindowWnd::OnFinalMessage(HWND /*hWnd*/)
    {
    }
    
    //////////////////////////////////////////////////////////////////////////

    流程:

    调用Create创建一个窗口,使用RegisterSuperclass或RegisterWindowClass注册类,调用CreateWindowEx创建窗口返回句柄。
    RegisterSuperclass使用CWindowWnd::__ControlProc作为窗口消息处理函数,
    RegisterWindowClass使用CWindowWnd::__WndProc作为消息处理函数。
    两个消息处理函数除了WM_NCDESTROY以外其他消息都通过HandleMessage来处理,所以继承类中只要重载HandleMessage就可以处理大部分消息了。

  • 相关阅读:
    SAP全球企业官孙小群的生活智慧
    C++ vs Python向量运算速度评测
    C++ Error: no appropriate default constructor available
    危险的浮点数float
    Vagrant 手册之 Vagrantfile
    MySQL 服务器性能剖析
    Vagrant 手册之多个虚拟机 multi-machine
    Vagrant 手册之同步目录
    Vagrant 手册之同步目录
    MySQL 中的 information_schema 数据库
  • 原文地址:https://www.cnblogs.com/Reyzal/p/5137209.html
Copyright © 2011-2022 走看看