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就可以处理大部分消息了。