// Windows Template Library - WTL version 10.0 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved. // // This file is a part of the Windows Template Library. // The use and distribution terms for this software are covered by the // Microsoft Public License (http://opensource.org/licenses/MS-PL) // which can be found in the file MS-PL.txt at the root folder. #ifndef __ATLWINX_H__ #define __ATLWINX_H__ #pragma once #ifndef __ATLAPP_H__ #error atlwinx.h requires atlapp.h to be included first #endif #include /////////////////////////////////////////////////////////////////////////////// // Classes in this file: // // CWindowEx ///////////////////////////////////////////////////////////////////////////// // Additional macros needed for template classes #ifndef DECLARE_WND_CLASS_EX2 #define DECLARE_WND_CLASS_EX2(WndClassName, EnclosingClass, style, bkgnd) \ static ATL::CWndClassInfo& GetWndClassInfo() \ { \ static ATL::CWndClassInfo wc = \ { \ { sizeof(WNDCLASSEX), style, EnclosingClass::StartWindowProc, \ 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName, NULL }, \ NULL, NULL, IDC_ARROW, TRUE, 0, _T("") \ }; \ return wc; \ } #endif // DECLARE_WND_CLASS_EX2 #ifndef DECLARE_WND_SUPERCLASS2 #define DECLARE_WND_SUPERCLASS2(WndClassName, EnclosingClass, OrigWndClassName) \ static ATL::CWndClassInfo& GetWndClassInfo() \ { \ static ATL::CWndClassInfo wc = \ { \ { sizeof(WNDCLASSEX), 0, EnclosingClass::StartWindowProc, \ 0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName, NULL }, \ OrigWndClassName, NULL, NULL, TRUE, 0, _T("") \ }; \ return wc; \ } #endif // DECLARE_WND_SUPERCLASS2 /////////////////////////////////////////////////////////////////////////////// // Command Chaining Macros #define CHAIN_COMMANDS(theChainClass) \ if(uMsg == WM_COMMAND) \ CHAIN_MSG_MAP(theChainClass) #define CHAIN_COMMANDS_ALT(theChainClass, msgMapID) \ if(uMsg == WM_COMMAND) \ CHAIN_MSG_MAP_ALT(theChainClass, msgMapID) #define CHAIN_COMMANDS_MEMBER(theChainMember) \ if(uMsg == WM_COMMAND) \ CHAIN_MSG_MAP_MEMBER(theChainMember) #define CHAIN_COMMANDS_ALT_MEMBER(theChainMember, msgMapID) \ if(uMsg == WM_COMMAND) \ CHAIN_MSG_MAP_ALT_MEMBER(theChainMember, msgMapID) /////////////////////////////////////////////////////////////////////////////// // Macros for parent message map to selectively reflect control messages // NOTE: ReflectNotifications is a member of ATL's CWindowImplRoot // (and overridden in 2 cases - CContainedWindowT and CAxHostWindow) // Since we can't modify ATL, we'll provide the needed additions // in a separate function (that is not a member of CWindowImplRoot) namespace WTL { inline LRESULT WtlReflectNotificationsFiltered(HWND hWndParent, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled, UINT uMsgFilter = WM_NULL, UINT_PTR idFromFilter = 0, HWND hWndChildFilter = NULL) { if((uMsgFilter != WM_NULL) && (uMsgFilter != uMsg)) { // The notification message doesn't match the filter. bHandled = FALSE; return 1; } HWND hWndChild = NULL; UINT_PTR idFrom = 0; switch(uMsg) { case WM_COMMAND: if(lParam != NULL) // not from a menu { hWndChild = (HWND)lParam; idFrom = (UINT_PTR)LOWORD(wParam); } break; case WM_NOTIFY: hWndChild = ((LPNMHDR)lParam)->hwndFrom; idFrom = ((LPNMHDR)lParam)->idFrom; break; case WM_PARENTNOTIFY: switch(LOWORD(wParam)) { case WM_CREATE: case WM_DESTROY: hWndChild = (HWND)lParam; idFrom = (UINT_PTR)HIWORD(wParam); break; default: hWndChild = ::GetDlgItem(hWndParent, HIWORD(wParam)); idFrom = (UINT_PTR)::GetDlgCtrlID(hWndChild); break; } break; case WM_DRAWITEM: if(wParam) // not from a menu { hWndChild = ((LPDRAWITEMSTRUCT)lParam)->hwndItem; idFrom = (UINT_PTR)wParam; } break; case WM_MEASUREITEM: if(wParam) // not from a menu { hWndChild = ::GetDlgItem(hWndParent, ((LPMEASUREITEMSTRUCT)lParam)->CtlID); idFrom = (UINT_PTR)wParam; } break; case WM_COMPAREITEM: if(wParam) // not from a menu { hWndChild = ((LPCOMPAREITEMSTRUCT)lParam)->hwndItem; idFrom = (UINT_PTR)wParam; } break; case WM_DELETEITEM: if(wParam) // not from a menu { hWndChild = ((LPDELETEITEMSTRUCT)lParam)->hwndItem; idFrom = (UINT_PTR)wParam; } break; case WM_VKEYTOITEM: case WM_CHARTOITEM: case WM_HSCROLL: case WM_VSCROLL: case WM_CTLCOLORBTN: case WM_CTLCOLORDLG: case WM_CTLCOLOREDIT: case WM_CTLCOLORLISTBOX: case WM_CTLCOLORMSGBOX: case WM_CTLCOLORSCROLLBAR: case WM_CTLCOLORSTATIC: hWndChild = (HWND)lParam; idFrom = (UINT_PTR)::GetDlgCtrlID(hWndChild); break; default: break; } if((hWndChild == NULL) || ((hWndChildFilter != NULL) && (hWndChildFilter != hWndChild))) { // Either hWndChild isn't valid, or // hWndChild doesn't match the filter. bHandled = FALSE; return 1; } if((idFromFilter != 0) && (idFromFilter != idFrom)) { // The dialog control id doesn't match the filter. bHandled = FALSE; return 1; } ATLASSERT(::IsWindow(hWndChild)); LRESULT lResult = ::SendMessage(hWndChild, OCM__BASE + uMsg, wParam, lParam); if((lResult == 0) && (uMsg >= WM_CTLCOLORMSGBOX) && (uMsg <= WM_CTLCOLORSTATIC)) { // Try to prevent problems with WM_CTLCOLOR* messages when // the message wasn't really handled bHandled = FALSE; } return lResult; } } // namespace WTL // Try to prevent problems with WM_CTLCOLOR* messages when // the message wasn't really handled #define REFLECT_NOTIFICATIONS_EX() \ { \ bHandled = TRUE; \ lResult = this->ReflectNotifications(uMsg, wParam, lParam, bHandled); \ if((lResult == 0) && (uMsg >= WM_CTLCOLORMSGBOX) && (uMsg <= WM_CTLCOLORSTATIC)) \ bHandled = FALSE; \ if(bHandled) \ return TRUE; \ } #define REFLECT_NOTIFICATIONS_MSG_FILTERED(uMsgFilter) \ { \ bHandled = TRUE; \ lResult = WTL::WtlReflectNotificationsFiltered(this->m_hWnd, uMsg, wParam, lParam, bHandled, uMsgFilter, 0, NULL); \ if(bHandled) \ return TRUE; \ } #define REFLECT_NOTIFICATIONS_ID_FILTERED(idFromFilter) \ { \ bHandled = TRUE; \ lResult = WTL::WtlReflectNotificationsFiltered(this->m_hWnd, uMsg, wParam, lParam, bHandled, WM_NULL, idFromFilter, NULL); \ if(bHandled) \ return TRUE; \ } #define REFLECT_NOTIFICATIONS_HWND_FILTERED(hWndChildFilter) \ { \ bHandled = TRUE; \ lResult = WTL::WtlReflectNotificationsFiltered(this->m_hWnd, uMsg, wParam, lParam, bHandled, WM_NULL, 0, hWndChildFilter); \ if(bHandled) \ return TRUE; \ } #define REFLECT_NOTIFICATIONS_MSG_ID_FILTERED(uMsgFilter, idFromFilter) \ { \ bHandled = TRUE; \ lResult = WTL::WtlReflectNotificationsFiltered(this->m_hWnd, uMsg, wParam, lParam, bHandled, uMsgFilter, idFromFilter, NULL); \ if(bHandled) \ return TRUE; \ } #define REFLECT_NOTIFICATIONS_MSG_HWND_FILTERED(uMsgFilter, hWndChildFilter) \ { \ bHandled = TRUE; \ lResult = WTL::WtlReflectNotificationsFiltered(this->m_hWnd, uMsg, wParam, lParam, bHandled, uMsgFilter, 0, hWndChildFilter); \ if(bHandled) \ return TRUE; \ } #define REFLECT_COMMAND(id, code) \ if((uMsg == WM_COMMAND) && (id == LOWORD(wParam)) && (code == HIWORD(wParam))) \ { \ bHandled = TRUE; \ lResult = this->ReflectNotifications(uMsg, wParam, lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECT_COMMAND_ID(id) \ if((uMsg == WM_COMMAND) && (id == LOWORD(wParam))) \ { \ bHandled = TRUE; \ lResult = this->ReflectNotifications(uMsg, wParam, lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECT_COMMAND_CODE(code) \ if((uMsg == WM_COMMAND) && (code == HIWORD(wParam))) \ { \ bHandled = TRUE; \ lResult = this->ReflectNotifications(uMsg, wParam, lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECT_COMMAND_RANGE(idFirst, idLast) \ if((uMsg == WM_COMMAND) && (LOWORD(wParam) >= idFirst) && (LOWORD(wParam) <= idLast)) \ { \ bHandled = TRUE; \ lResult = this->ReflectNotifications(uMsg, wParam, lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECT_COMMAND_RANGE_CODE(idFirst, idLast, code) \ if((uMsg == WM_COMMAND) && (code == HIWORD(wParam)) && (LOWORD(wParam) >= idFirst) && (LOWORD(wParam) <= idLast)) \ { \ bHandled = TRUE; \ lResult = this->ReflectNotifications(uMsg, wParam, lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECT_NOTIFY(id, cd) \ if((uMsg == WM_NOTIFY) && (id == ((LPNMHDR)lParam)->idFrom) && (cd == ((LPNMHDR)lParam)->code)) \ { \ bHandled = TRUE; \ lResult = this->ReflectNotifications(uMsg, wParam, lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECT_NOTIFY_ID(id) \ if((uMsg == WM_NOTIFY) && (id == ((LPNMHDR)lParam)->idFrom)) \ { \ bHandled = TRUE; \ lResult = this->ReflectNotifications(uMsg, wParam, lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECT_NOTIFY_CODE(cd) \ if((uMsg == WM_NOTIFY) && (cd == ((LPNMHDR)lParam)->code)) \ { \ bHandled = TRUE; \ lResult = this->ReflectNotifications(uMsg, wParam, lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECT_NOTIFY_RANGE(idFirst, idLast) \ if((uMsg == WM_NOTIFY) && (((LPNMHDR)lParam)->idFrom >= idFirst) && (((LPNMHDR)lParam)->idFrom <= idLast)) \ { \ bHandled = TRUE; \ lResult = this->ReflectNotifications(uMsg, wParam, lParam, bHandled); \ if(bHandled) \ return TRUE; \ } #define REFLECT_NOTIFY_RANGE_CODE(idFirst, idLast, cd) \ if((uMsg == WM_NOTIFY) && (cd == ((LPNMHDR)lParam)->code) && (((LPNMHDR)lParam)->idFrom >= idFirst) && (((LPNMHDR)lParam)->idFrom <= idLast)) \ { \ bHandled = TRUE; \ lResult = this->ReflectNotifications(uMsg, wParam, lParam, bHandled); \ if(bHandled) \ return TRUE; \ } /////////////////////////////////////////////////////////////////////////////// // GetClassLong/SetClassLong redefinition to avoid problems with class members #ifdef SetClassLongPtrA #undef SetClassLongPtrA inline LONG_PTR SetClassLongPtrA(HWND hWnd, int nIndex, LONG_PTR dwNewLong) { return ::SetClassLongA(hWnd, nIndex, LONG(dwNewLong)); } #endif #ifdef SetClassLongPtrW #undef SetClassLongPtrW inline LONG_PTR SetClassLongPtrW(HWND hWnd, int nIndex, LONG_PTR dwNewLong) { return ::SetClassLongW(hWnd, nIndex, LONG(dwNewLong)); } #endif #ifdef GetClassLongPtrA #undef GetClassLongPtrA inline LONG_PTR GetClassLongPtrA(HWND hWnd, int nIndex) { return ::GetClassLongA(hWnd, nIndex); } #endif #ifdef GetClassLongPtrW #undef GetClassLongPtrW inline LONG_PTR GetClassLongPtrW(HWND hWnd, int nIndex) { return ::GetClassLongW(hWnd, nIndex); } #endif /////////////////////////////////////////////////////////////////////////////// // CWindowEx - extension of ATL::CWindow namespace WTL { class CWindowEx : public ATL::CWindow { public: CWindowEx(HWND hWnd = NULL) : ATL::CWindow(hWnd) { } CWindowEx& operator =(HWND hWnd) { m_hWnd = hWnd; return *this; } operator HWND() const { return m_hWnd; } // Methods BOOL PrintWindow(HDC hDC, UINT uFlags = 0) { ATLASSERT(::IsWindow(m_hWnd)); return ::PrintWindow(m_hWnd, hDC, uFlags); } BOOL DragDetect(POINT pt) { ATLASSERT(::IsWindow(m_hWnd)); return ::DragDetect(m_hWnd, pt); } BOOL DragDetect() { ATLASSERT(::IsWindow(m_hWnd)); POINT pt = {}; ::GetCursorPos(&pt); return ::DragDetect(m_hWnd, pt); } CWindowEx GetAncestor(UINT uFlags) const { ATLASSERT(::IsWindow(m_hWnd)); return CWindowEx(::GetAncestor(m_hWnd, uFlags)); } // Note: Does not work properly on Vista Aero and above BOOL AnimateWindow(DWORD dwFlags, DWORD dwTime = 200) { ATLASSERT(::IsWindow(m_hWnd)); return ::AnimateWindow(m_hWnd, dwTime, dwFlags); } BOOL FlashWindowEx(DWORD dwFlags, UINT uCount, DWORD dwTimeout = 0) { ATLASSERT(::IsWindow(m_hWnd)); FLASHWINFO fi = { sizeof(FLASHWINFO) }; fi.hwnd = m_hWnd; fi.dwFlags = dwFlags; fi.uCount = uCount; fi.dwTimeout = dwTimeout; return ::FlashWindowEx(&fi); } BOOL StopFlashWindowEx() { ATLASSERT(::IsWindow(m_hWnd)); FLASHWINFO fi = { sizeof(FLASHWINFO) }; fi.hwnd = m_hWnd; fi.dwFlags = FLASHW_STOP; return ::FlashWindowEx(&fi); } // Class long properties DWORD GetClassLong(int nIndex) const { ATLASSERT(::IsWindow(m_hWnd)); return ::GetClassLong(m_hWnd, nIndex); } DWORD SetClassLong(int nIndex, LONG dwNewLong) { ATLASSERT(::IsWindow(m_hWnd)); return ::SetClassLong(m_hWnd, nIndex, dwNewLong); } ULONG_PTR GetClassLongPtr(int nIndex) const { ATLASSERT(::IsWindow(m_hWnd)); return ::GetClassLongPtr(m_hWnd, nIndex); } ULONG_PTR SetClassLongPtr(int nIndex, LONG_PTR dwNewLong) { ATLASSERT(::IsWindow(m_hWnd)); return ::SetClassLongPtr(m_hWnd, nIndex, dwNewLong); } // Layered windows BOOL SetLayeredWindowAttributes(COLORREF crlKey, BYTE byteAlpha, DWORD dwFlags) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetExStyle() & WS_EX_LAYERED) != 0); return ::SetLayeredWindowAttributes(m_hWnd, crlKey, byteAlpha, dwFlags); } BOOL UpdateLayeredWindow(HDC hdcDst, LPPOINT pptDst, LPSIZE psize, HDC hdcSrc, LPPOINT pptSrc, COLORREF crlKey, BLENDFUNCTION* pblend, DWORD dwFlags) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetExStyle() & WS_EX_LAYERED) != 0); return ::UpdateLayeredWindow(m_hWnd, hdcDst, pptDst, psize, hdcSrc, pptSrc, crlKey, pblend, dwFlags); } BOOL UpdateLayeredWindow(LPPOINT pptDst = NULL) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetExStyle() & WS_EX_LAYERED) != 0); return ::UpdateLayeredWindow(m_hWnd, NULL, pptDst, NULL, NULL, NULL, CLR_NONE, NULL, 0); } BOOL GetLayeredWindowAttributes(COLORREF* pcrlKey, BYTE* pbyteAlpha, DWORD* pdwFlags) const { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT((GetExStyle() & WS_EX_LAYERED) != 0); return ::GetLayeredWindowAttributes(m_hWnd, pcrlKey, pbyteAlpha, pdwFlags); } // Mouse tracking BOOL StartTrackMouseLeave() { ATLASSERT(::IsWindow(m_hWnd)); TRACKMOUSEEVENT tme = {}; tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.dwFlags = TME_LEAVE; tme.hwndTrack = m_hWnd; return ::TrackMouseEvent(&tme); } BOOL StartTrackMouse(DWORD dwFlags, DWORD dwHoverTime = HOVER_DEFAULT) { ATLASSERT(::IsWindow(m_hWnd)); TRACKMOUSEEVENT tme = {}; tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.dwFlags = dwFlags; tme.hwndTrack = m_hWnd; tme.dwHoverTime = dwHoverTime; return ::TrackMouseEvent(&tme); } BOOL CancelTrackMouse(DWORD dwType) { ATLASSERT(::IsWindow(m_hWnd)); TRACKMOUSEEVENT tme = {}; tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.dwFlags = TME_CANCEL | dwType; tme.hwndTrack = m_hWnd; return ::TrackMouseEvent(&tme); } // CString support #ifdef __ATLSTR_H__ int GetWindowText(ATL::CString& strText) const { int nLength = GetWindowTextLength(); LPTSTR pszText = strText.GetBuffer(nLength + 1); nLength = ::GetWindowText(m_hWnd, pszText, nLength + 1); strText.ReleaseBuffer(nLength); return nLength; } UINT GetDlgItemText(int nID, ATL::CString& strText) const { ATLASSERT(::IsWindow(m_hWnd)); HWND hItem = GetDlgItem(nID); if(hItem != NULL) { int nLength = ::GetWindowTextLength(hItem); LPTSTR pszText = strText.GetBuffer(nLength + 1); nLength = ::GetWindowText(hItem, pszText, nLength + 1); strText.ReleaseBuffer(nLength); return nLength; } else { strText.Empty(); return 0; } } #endif // __ATLSTR_H__ // Dialog window only UINT DlgGetDefID() const { ATLASSERT(::IsWindow(m_hWnd)); LRESULT lRet = ::SendMessage(m_hWnd, DM_GETDEFID, 0, 0L); UINT uID = 0U; if(HIWORD(lRet) == DC_HASDEFID) uID = LOWORD(lRet); return uID; } void DlgSetDefID(UINT uID) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DM_SETDEFID, uID, 0L); } void DlgReposition() { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, DM_REPOSITION, 0, 0L); } }; } // namespace WTL #endif // __ATLWINX_H__