// This is a part of the Active Template Library. // Copyright (C) 1996-1998 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Active Template Library Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Active Template Library product. #ifndef __ATLFRAME_H__ #define __ATLFRAME_H__ #ifndef __cplusplus #error ATL requires C++ compilation (use a .cpp suffix) #endif #ifndef __ATLWIN_H__ #error atlframe.h requires atlwin.h to be included first #endif #if (_ATL_VER < 0x0300) #ifndef __ATLWIN21_H__ #error atlframe.h requires atlwin21.h to be included first when used with ATL 2.0/2.1 #endif #endif //(_ATL_VER < 0x0300) #include #include namespace ATL { ///////////////////////////////////////////////////////////////////////////// // Forward declarations template class CFrameWindowImpl; #ifndef UNDER_CE class CMDIWindow; template class CMDIFrameWindowImpl; template class CMDIChildWindowImpl; #endif //!UNDER_CE template class COwnerDraw; class CUpdateUIBase; template class CUpdateUI; ///////////////////////////////////////////////////////////////////////////// // CFrameWndClassInfo - Manages frame window Windows class information class CFrameWndClassInfo { public: #ifndef UNDER_CE WNDCLASSEX m_wc; #else // CE specific WNDCLASS m_wc; #endif //!UNDER_CE LPCTSTR m_lpszOrigName; WNDPROC pWndProc; #ifndef UNDER_CE LPCTSTR m_lpszCursorID; BOOL m_bSystemCursor; #endif //!UNDER_CE ATOM m_atom; TCHAR m_szAutoName[sizeof("ATL:") + (sizeof(PVOID)*2)+1]; UINT m_uCommonResourceID; ATOM Register(WNDPROC* pProc) { if (m_atom == 0) { ::EnterCriticalSection(&_Module.m_csWindowCreate); if(m_atom == 0) { HINSTANCE hInst = _Module.GetModuleInstance(); if (m_lpszOrigName != NULL) { ATLASSERT(pProc != NULL); LPCTSTR lpsz = m_wc.lpszClassName; WNDPROC proc = m_wc.lpfnWndProc; #ifndef UNDER_CE WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); if(!::GetClassInfoEx(NULL, m_lpszOrigName, &wc)) #else // CE specific WNDCLASS wc; if(!::GetClassInfo(NULL, m_lpszOrigName, &wc)) #endif //!UNDER_CE { ::LeaveCriticalSection(&_Module.m_csWindowCreate); return 0; } #ifndef UNDER_CE memcpy(&m_wc, &wc, sizeof(WNDCLASSEX)); #else // CE specific memcpy(&m_wc, &wc, sizeof(WNDCLASS)); #endif //!UNDER_CE pWndProc = m_wc.lpfnWndProc; m_wc.lpszClassName = lpsz; m_wc.lpfnWndProc = proc; } else { #ifndef UNDER_CE m_wc.hCursor = ::LoadCursor(m_bSystemCursor ? NULL : hInst, m_lpszCursorID); #else // CE specific m_wc.hCursor = NULL; #endif //!UNDER_CE } m_wc.hInstance = hInst; m_wc.style &= ~CS_GLOBALCLASS; // we don't register global classes if (m_wc.lpszClassName == NULL) { #ifdef _WIN64 // %p isn't available on Win2k/Win9x wsprintf(m_szAutoName, _T("ATL:%p"), &m_wc); #else wsprintf(m_szAutoName, _T("ATL:%8.8X"), PtrToUlong(&m_wc)); #endif m_wc.lpszClassName = m_szAutoName; } #ifndef UNDER_CE WNDCLASSEX wcTemp; memcpy(&wcTemp, &m_wc, sizeof(WNDCLASSEX)); m_atom = (ATOM)::GetClassInfoEx(m_wc.hInstance, m_wc.lpszClassName, &wcTemp); #else // CE specific WNDCLASS wcTemp; memcpy(&wcTemp, &m_wc, sizeof(WNDCLASS)); m_atom = (ATOM)::GetClassInfo(m_wc.hInstance, m_wc.lpszClassName, &wcTemp); #endif //!UNDER_CE if (m_atom == 0) { if(m_uCommonResourceID != 0) // use it if not zero { m_wc.hIcon = (HICON)::LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR); #ifndef UNDER_CE m_wc.hIconSm = (HICON)::LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); #endif //!UNDER_CE } #ifndef UNDER_CE m_atom = ::RegisterClassEx(&m_wc); #else // CE specific m_atom = ::RegisterClass(&m_wc); #endif //!UNDER_CE } } ::LeaveCriticalSection(&_Module.m_csWindowCreate); } if (m_lpszOrigName != NULL) { ATLASSERT(pProc != NULL); ATLASSERT(pWndProc != NULL); *pProc = pWndProc; } return m_atom; } }; #ifndef UNDER_CE #define DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \ static CFrameWndClassInfo& GetWndClassInfo() \ { \ static CFrameWndClassInfo wc = \ { \ { sizeof(WNDCLASSEX), 0, StartWindowProc, \ 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL }, \ NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ }; \ return wc; \ } #define DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \ static CFrameWndClassInfo& GetWndClassInfo() \ { \ static CFrameWndClassInfo wc = \ { \ { sizeof(WNDCLASSEX), style, StartWindowProc, \ 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName, NULL }, \ NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \ }; \ return wc; \ } #define DECLARE_FRAME_WND_SUPERCLASS(WndClassName, OrigWndClassName, uCommonResourceID) \ static CFrameWndClassInfo& GetWndClassInfo() \ { \ static CFrameWndClassInfo wc = \ { \ { sizeof(WNDCLASSEX), 0, StartWindowProc, \ 0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName, NULL }, \ OrigWndClassName, NULL, NULL, TRUE, 0, _T(""), uCommonResourceID \ }; \ return wc; \ } #else // CE specific #define DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \ static CFrameWndClassInfo& GetWndClassInfo() \ { \ static CFrameWndClassInfo wc = \ { \ { 0, StartWindowProc, \ 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName }, \ NULL, NULL, 0, _T(""), uCommonResourceID \ }; \ return wc; \ } #define DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \ static CFrameWndClassInfo& GetWndClassInfo() \ { \ static CFrameWndClassInfo wc = \ { \ { style, StartWindowProc, \ 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName }, \ NULL, NULL, 0, _T(""), uCommonResourceID \ }; \ return wc; \ } #define DECLARE_FRAME_WND_SUPERCLASS(WndClassName, OrigWndClassName, uCommonResourceID) \ static CFrameWndClassInfo& GetWndClassInfo() \ { \ static CFrameWndClassInfo wc = \ { \ { NULL, StartWindowProc, \ 0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName }, \ OrigWndClassName, NULL, 0, _T(""), uCommonResourceID \ }; \ return wc; \ } #endif //!UNDER_CE // Command Chaining Macros #define CHAIN_COMMANDS(theChainClass) \ { \ if(uMsg == WM_COMMAND && theChainClass::ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult)) \ return TRUE; \ } #define CHAIN_COMMANDS_MEMBER(theChainMember) \ { \ if(uMsg == WM_COMMAND && theChainMember.ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult)) \ return TRUE; \ } #define CHAIN_COMMANDS_ALT(theChainClass, msgMapID) \ { \ if(uMsg == WM_COMMAND && theChainClass::ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, msgMapID)) \ return TRUE; \ } #define CHAIN_COMMANDS_ALT_MEMBER(theChainMember, msgMapID) \ { \ if(uMsg == WM_COMMAND && theChainMember.ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, msgMapID)) \ return TRUE; \ } // Client window command chaining macro #define CHAIN_CLIENT_COMMANDS() \ if(uMsg == WM_COMMAND && m_hWndClient != NULL) \ ::SendMessage(m_hWndClient, uMsg, wParam, lParam); ///////////////////////////////////////////////////////////////////////////// // CFrameWindowImpl template class ATL_NO_VTABLE CFrameWindowImplBase : public CWindowImplBaseT< TBase, TWinTraits > { public: HWND m_hWndToolBar; HWND m_hWndStatusBar; HWND m_hWndClient; HACCEL m_hAccel; CFrameWindowImplBase() : m_hWndToolBar(NULL), m_hWndStatusBar(NULL), m_hWndClient(NULL), m_hAccel(NULL) { } DECLARE_FRAME_WND_CLASS(NULL, 0) struct _AtlToolBarData { WORD wVersion; WORD wWidth; WORD wHeight; WORD wItemCount; //WORD aItems[wItemCount] WORD* items() { return (WORD*)(this+1); } }; static HWND CreateSimpleToolBarCtrl(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS, UINT nID = ATL_IDW_TOOLBAR) { HINSTANCE hInst = _Module.GetResourceInstance(); HRSRC hRsrc = ::FindResource(hInst, MAKEINTRESOURCE(nResourceID), RT_TOOLBAR); if (hRsrc == NULL) return NULL; HGLOBAL hGlobal = ::LoadResource(hInst, hRsrc); if (hGlobal == NULL) return NULL; _AtlToolBarData* pData = (_AtlToolBarData*)::LockResource(hGlobal); if (pData == NULL) return NULL; ATLASSERT(pData->wVersion == 1); WORD* pItems = pData->items(); int nItems = pData->wItemCount + (bInitialSeparator ? 1 : 0); TBBUTTON* pTBBtn = (TBBUTTON*)_alloca(nItems * sizeof(TBBUTTON)); // set initial separator (half width) if(bInitialSeparator) { pTBBtn[0].iBitmap = 4; pTBBtn[0].idCommand = 0; pTBBtn[0].fsState = 0; pTBBtn[0].fsStyle = TBSTYLE_SEP; pTBBtn[0].dwData = 0; pTBBtn[0].iString = 0; } int nBmp = 0; for(int i = 0, j = bInitialSeparator ? 1 : 0; i < pData->wItemCount; i++, j++) { if(pItems[i] != 0) { pTBBtn[j].iBitmap = nBmp++; pTBBtn[j].idCommand = pItems[i]; pTBBtn[j].fsState = TBSTATE_ENABLED; pTBBtn[j].fsStyle = TBSTYLE_BUTTON; pTBBtn[j].dwData = 0; pTBBtn[j].iString = 0; } else { pTBBtn[j].iBitmap = 8; pTBBtn[j].idCommand = 0; pTBBtn[j].fsState = 0; pTBBtn[j].fsStyle = TBSTYLE_SEP; pTBBtn[j].dwData = 0; pTBBtn[j].iString = 0; } } HWND hWnd = ::CreateWindowEx(0, TOOLBARCLASSNAME, NULL, dwStyle, 0,0,100,100, hWndParent, (HMENU)nID, _Module.GetModuleInstance(), NULL); ::SendMessage(hWnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0L); TBADDBITMAP tbab; tbab.hInst = hInst; tbab.nID = nResourceID; ::SendMessage(hWnd, TB_ADDBITMAP, nBmp, (LPARAM)&tbab); ::SendMessage(hWnd, TB_ADDBUTTONS, nItems, (LPARAM)pTBBtn); ::SendMessage(hWnd, TB_SETBITMAPSIZE, 0, MAKELONG(pData->wWidth, pData->wHeight)); ::SendMessage(hWnd, TB_SETBUTTONSIZE, 0, MAKELONG(pData->wWidth + 7, pData->wHeight + 7)); return hWnd; } BOOL CreateSimpleStatusBar(LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) { ATLASSERT(!::IsWindow(m_hWndStatusBar)); m_hWndStatusBar = ::CreateStatusWindow(dwStyle, lpstrText, m_hWnd, nID); return (m_hWndStatusBar != NULL); } BOOL CreateSimpleStatusBar(UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) { TCHAR szText[128]; // max text lentgth is 127 for status bars szText[0] = 0; ::LoadString(_Module.GetResourceInstance(), nTextID, szText, 127); return CreateSimpleStatusBar(szText, dwStyle, nID); } void UpdateLayout() { RECT rect; GetClientRect(&rect); // resize toolbar if(m_hWndToolBar != NULL && ((DWORD)::GetWindowLong(m_hWndToolBar, GWL_STYLE) & WS_VISIBLE)) { ::SendMessage(m_hWndToolBar, WM_SIZE, 0, 0); RECT rectTB; ::GetWindowRect(m_hWndToolBar, &rectTB); rect.top += rectTB.bottom - rectTB.top; } // resize status bar if(m_hWndToolBar != NULL && ((DWORD)::GetWindowLong(m_hWndStatusBar, GWL_STYLE) & WS_VISIBLE)) { ::SendMessage(m_hWndStatusBar, WM_SIZE, 0, 0); RECT rectSB; ::GetWindowRect(m_hWndStatusBar, &rectSB); rect.bottom -= rectSB.bottom - rectSB.top; } // resize client window if(m_hWndClient != NULL) ::SetWindowPos(m_hWndClient, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOACTIVATE); } BOOL PreTranslateMessage(MSG* pMsg) { if(m_hAccel != NULL && ::TranslateAccelerator(m_hWnd, m_hAccel, pMsg)) return TRUE; return FALSE; } typedef CFrameWindowImplBase< TBase, TWinTraits > thisClass; BEGIN_MSG_MAP(thisClass) MESSAGE_HANDLER(WM_SIZE, OnSize) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) #ifndef UNDER_CE MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect) #endif //!UNDER_CE MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) MESSAGE_HANDLER(WM_DESTROY, OnDestroy) NOTIFY_CODE_HANDLER(TTN_NEEDTEXT, OnToolTipText) END_MSG_MAP() LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { if(wParam != SIZE_MINIMIZED) UpdateLayout(); bHandled = FALSE; return 1; } LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { if(m_hWndClient != NULL) // view will paint itself instead return 1; bHandled = FALSE; return 0; } #ifndef UNDER_CE LRESULT OnMenuSelect(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { bHandled = FALSE; if(m_hWndStatusBar == NULL) return 1; WORD wFlags = HIWORD(wParam); if(wFlags == 0xFFFF && lParam == NULL) // menu closing ::SendMessage(m_hWndStatusBar, SB_SIMPLE, FALSE, 0L); else { TCHAR szBuff[256]; szBuff[0] = 0; if(!(wFlags & MF_POPUP)) { WORD wID = LOWORD(wParam); // check for special cases if(wID >= 0xF000 && wID < 0xF1F0) // system menu IDs wID = (WORD)(((wID - 0xF000) >> 4) + ATL_IDS_SCFIRST); else if(wID >= ID_FILE_MRU_FIRST && wID <= ID_FILE_MRU_LAST) // MRU items wID = ATL_IDS_MRU_FILE; else if(wID >= ATL_IDM_FIRST_MDICHILD) // MDI child windows wID = ATL_IDS_MDICHILD; if(::LoadString(_Module.GetResourceInstance(), wID, szBuff, 255)) { for(int i = 0; szBuff[i] != 0 && i < 256; i++) { if(szBuff[i] == _T('\n')) { szBuff[i] = 0; break; } } } } ::SendMessage(m_hWndStatusBar, SB_SIMPLE, TRUE, 0L); ::SendMessage(m_hWndStatusBar, SB_SETTEXT, (255 | SBT_NOBORDERS), (LPARAM)szBuff); } return 1; } #endif //!UNDER_CE LRESULT OnSetFocus(UINT, WPARAM, LPARAM, BOOL& bHandled) { if(m_hWndClient != NULL && ::IsWindowVisible(m_hWndClient)) ::SetFocus(m_hWndClient); bHandled = FALSE; return 1; } LRESULT OnDestroy(UINT, WPARAM, LPARAM, BOOL& bHandled) { if(!(GetStyle() & (WS_CHILD | WS_POPUP))) ::PostQuitMessage(1); bHandled = FALSE; return 1; } LRESULT OnToolTipText(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/) { TOOLTIPTEXT* pTTT = (TOOLTIPTEXT*)pnmh; pTTT->szText[0] = 0; if((idCtrl != 0) && !(pTTT->uFlags & TTF_IDISHWND)) { TCHAR szBuff[256]; szBuff[0] = 0; if(::LoadString(_Module.GetResourceInstance(), idCtrl, szBuff, 255)) { for(int i = 0; szBuff[i] != 0 && i < 256; i++) { if(szBuff[i] == _T('\n')) { lstrcpyn(pTTT->szText, &szBuff[i+1], sizeof(pTTT->szText)/sizeof(pTTT->szText[0])); break; } } } } return 0; } }; template class ATL_NO_VTABLE CFrameWindowImpl : public CFrameWindowImplBase< TBase, TWinTraits > { public: HWND Create(HWND hWndParent = NULL, RECT& Rect = CWindow::rcDefault, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, HMENU hMenu = NULL, LPVOID lpCreateParam = NULL) { T* pT = static_cast(this); return pT->Create(hWndParent, &Rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam); } HWND Create(HWND hWndParent = NULL, LPRECT lpRect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, HMENU hMenu = NULL, LPVOID lpCreateParam = NULL) { ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc); static RECT rect = { CW_USEDEFAULT, CW_USEDEFAULT, 0, 0 }; if(lpRect == NULL) lpRect = ▭ dwStyle = T::GetWndStyle(dwStyle); dwExStyle = T::GetWndExStyle(dwExStyle); return CWindowImplBaseT< TBase, TWinTraits >::Create(hWndParent, *lpRect, szWindowName, dwStyle, dwExStyle, (UINT)hMenu, atom, lpCreateParam); } HWND CreateEx(HWND hWndParent = NULL, LPRECT lpRect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL) { TCHAR szWindowName[256]; szWindowName[0] = 0; ::LoadString(_Module.GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, 255); HMENU hMenu = ::LoadMenu(_Module.GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); T* pT = static_cast(this); HWND hWnd = pT->Create(hWndParent, lpRect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam); if(hWnd != NULL) m_hAccel = ::LoadAccelerators(_Module.GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); return hWnd; } BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS, UINT nID = ATL_IDW_TOOLBAR) { ATLASSERT(!::IsWindow(m_hWndToolBar)); if(nResourceID == 0) nResourceID = T::GetWndClassInfo().m_uCommonResourceID; m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID); return (m_hWndToolBar != NULL); } }; ///////////////////////////////////////////////////////////////////////////// // CMDIWindow #ifndef UNDER_CE class CMDIWindow : public CWindow { public: HWND m_hWndMDIClient; HMENU m_hMenu; // Constructors CMDIWindow(HWND hWnd = NULL) : CWindow(hWnd), m_hWndMDIClient(NULL), m_hMenu(NULL) { } CMDIWindow& operator=(HWND hWnd) { m_hWnd = hWnd; return *this; } // Operations HWND MDIGetActive(BOOL* lpbMaximized = NULL) { ATLASSERT(::IsWindow(m_hWndMDIClient)); return (HWND)::SendMessage(m_hWndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)lpbMaximized); } void MDIActivate(HWND hWndChildToActivate) { ATLASSERT(::IsWindow(m_hWndMDIClient)); ATLASSERT(::IsWindow(hWndChildToActivate)); ::SendMessage(m_hWndMDIClient, WM_MDIACTIVATE, (WPARAM)hWndChildToActivate, 0); } void MDINext(HWND hWndChild, BOOL bPrevious = FALSE) { ATLASSERT(::IsWindow(m_hWndMDIClient)); ATLASSERT(hWndChild == NULL || ::IsWindow(hWndChild)); ::SendMessage(m_hWndMDIClient, WM_MDINEXT, (WPARAM)hWndChild, (LPARAM)bPrevious); } void MDIMaximize(HWND hWndChildToMaximize) { ATLASSERT(::IsWindow(m_hWndMDIClient)); ATLASSERT(::IsWindow(hWndChildToMaximize)); ::SendMessage(m_hWndMDIClient, WM_MDIMAXIMIZE, (WPARAM)hWndChildToMaximize, 0); } void MDIRestore(HWND hWndChildToRestore) { ATLASSERT(::IsWindow(m_hWndMDIClient)); ATLASSERT(::IsWindow(hWndChildToRestore)); ::SendMessage(m_hWndMDIClient, WM_MDIICONARRANGE, (WPARAM)hWndChildToRestore, 0); } void MDIDestroy(HWND hWndChildToDestroy) { ATLASSERT(::IsWindow(m_hWndMDIClient)); ATLASSERT(::IsWindow(hWndChildToDestroy)); ::SendMessage(m_hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChildToDestroy, 0); } BOOL MDICascade(UINT uFlags = 0) { ATLASSERT(::IsWindow(m_hWndMDIClient)); return (BOOL)::SendMessage(m_hWndMDIClient, WM_MDICASCADE, (WPARAM)uFlags, 0); } BOOL MDITile(UINT uFlags = MDITILE_HORIZONTAL) { ATLASSERT(::IsWindow(m_hWndMDIClient)); return (BOOL)::SendMessage(m_hWndMDIClient, WM_MDITILE, (WPARAM)uFlags, 0); } void MDIIconArrange() { ATLASSERT(::IsWindow(m_hWndMDIClient)); ::SendMessage(m_hWndMDIClient, WM_MDIICONARRANGE, 0, 0); } HMENU MDISetMenu(HMENU hMenuFrame, HMENU hMenuWindow) { ATLASSERT(::IsWindow(m_hWndMDIClient)); return (HMENU)::SendMessage(m_hWndMDIClient, WM_MDISETMENU, (WPARAM)hMenuFrame, (LPARAM)hMenuWindow); } HMENU MDIRefreshMenu() { ATLASSERT(::IsWindow(m_hWndMDIClient)); return (HMENU)::SendMessage(m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0); } // Additional operations static HMENU GetStandardWindowMenu(HMENU hMenu) { int nCount = ::GetMenuItemCount(hMenu); if(nCount == -1) return NULL; int nLen = ::GetMenuString(hMenu, nCount - 2, NULL, 0, MF_BYPOSITION); if(nLen == 0) return NULL; LPTSTR lpszText = (LPTSTR)_alloca((nLen + 1) * sizeof(TCHAR)); if(::GetMenuString(hMenu, nCount - 2, lpszText, nLen + 1, MF_BYPOSITION) != nLen) return NULL; if(lstrcmp(lpszText, _T("&Window"))) return NULL; return ::GetSubMenu(hMenu, nCount - 2); } void SetMDIFrameMenu() { HMENU hWindowMenu = GetStandardWindowMenu(m_hMenu); MDISetMenu(m_hMenu, hWindowMenu); MDIRefreshMenu(); ::DrawMenuBar(GetMDIFrame()); } HWND GetMDIFrame() { return ::GetParent(m_hWndMDIClient); } }; ///////////////////////////////////////////////////////////////////////////// // CMDIFrameWindowImpl // MDI child command chaining macro #define CHAIN_MDI_CHILD_COMMANDS() \ if(uMsg == WM_COMMAND) \ { \ HWND hWndChild = MDIGetActive(); \ if(hWndChild != NULL) \ ::SendMessage(hWndChild, uMsg, wParam, lParam); \ } template class ATL_NO_VTABLE CMDIFrameWindowImpl : public CFrameWindowImplBase { public: HWND Create(HWND hWndParent = NULL, LPRECT lpRect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, HMENU hMenu = NULL, LPVOID lpCreateParam = NULL) { m_hMenu = hMenu; ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc); static RECT rect = { CW_USEDEFAULT, CW_USEDEFAULT, 0, 0 }; if(lpRect == NULL) lpRect = ▭ dwStyle = T::GetWndStyle(dwStyle); dwExStyle = T::GetWndExStyle(dwExStyle); return CFrameWindowImplBase::Create(hWndParent, *lpRect, szWindowName, dwStyle, dwExStyle, (UINT)hMenu, atom, lpCreateParam); } HWND CreateEx(HWND hWndParent = NULL, LPRECT lpRect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL) { TCHAR szWindowName[256]; szWindowName[0] = 0; ::LoadString(_Module.GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, 255); HMENU hMenu = ::LoadMenu(_Module.GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); T* pT = static_cast(this); HWND hWnd = pT->Create(hWndParent, lpRect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam); if(hWnd != NULL) m_hAccel = ::LoadAccelerators(_Module.GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); return hWnd; } BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS, UINT nID = ATL_IDW_TOOLBAR) { ATLASSERT(!::IsWindow(m_hWndToolBar)); if(nResourceID == 0) nResourceID = T::GetWndClassInfo().m_uCommonResourceID; m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID); return (m_hWndToolBar != NULL); } virtual WNDPROC GetWindowProc() { return MDIFrameWindowProc; } static LRESULT CALLBACK MDIFrameWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CMDIFrameWindowImpl< T, TBase, TWinTraits >* pThis = (CMDIFrameWindowImpl< T, TBase, TWinTraits >*)hWnd; #if (_ATL_VER >= 0x0300) // set a ptr to this message and save the old value MSG msg = { pThis->m_hWnd, uMsg, wParam, lParam, 0, { 0, 0 } }; const MSG* pOldMsg = pThis->m_pCurrentMsg; pThis->m_pCurrentMsg = &msg; #endif //(_ATL_VER >= 0x0300) // pass to the message map to process LRESULT lRes; BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0); #if (_ATL_VER >= 0x0300) // restore saved value for the current message ATLASSERT(pThis->m_pCurrentMsg == &msg); pThis->m_pCurrentMsg = pOldMsg; #endif //(_ATL_VER >= 0x0300) // do the default processing if message was not handled if(!bRet) { if(uMsg != WM_NCDESTROY) lRes = pThis->DefWindowProc(uMsg, wParam, lParam); else { // unsubclass, if needed LONG_PTR pfnWndProc = ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC); lRes = pThis->DefWindowProc(uMsg, wParam, lParam); if(pThis->m_pfnSuperWindowProc != ::DefWindowProc && ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC) == pfnWndProc) ::SetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC, (LONG_PTR)pThis->m_pfnSuperWindowProc); // clear out window handle HWND hWnd = pThis->m_hWnd; pThis->m_hWnd = NULL; // clean up after window is destroyed pThis->OnFinalMessage(hWnd); } } return lRes; } #if (_ATL_VER >= 0x0300) // Overriden to call DefWindowProc which uses DefFrameProc LRESULT DefWindowProc() { const MSG* pMsg = m_pCurrentMsg; LRESULT lRes = 0; if (pMsg != NULL) lRes = DefWindowProc(pMsg->message, pMsg->wParam, pMsg->lParam); return lRes; } #endif //(_ATL_VER >= 0x0300) LRESULT DefWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) { return ::DefFrameProc(m_hWnd, m_hWndClient, uMsg, wParam, lParam); } BOOL PreTranslateMessage(MSG* pMsg) { if(CFrameWindowImplBase::PreTranslateMessage(pMsg)) return TRUE; return ::TranslateMDISysAccel(m_hWndClient, pMsg); } HWND CreateMDIClient(HMENU hWindowMenu = NULL, UINT nID = ATL_IDW_CLIENT, UINT nFirstChildID = ATL_IDM_FIRST_MDICHILD) { DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | MDIS_ALLCHILDSTYLES; DWORD dwExStyle = WS_EX_CLIENTEDGE; CLIENTCREATESTRUCT ccs; ccs.hWindowMenu = hWindowMenu; ccs.idFirstChild = nFirstChildID; if(GetStyle() & (WS_HSCROLL | WS_VSCROLL)) { // parent MDI frame's scroll styles move to the MDICLIENT dwStyle |= (GetStyle() & (WS_HSCROLL | WS_VSCROLL)); // fast way to turn off the scrollbar bits (without a resize) ModifyStyle(WS_HSCROLL | WS_VSCROLL, 0, SWP_NOREDRAW | SWP_FRAMECHANGED); } // Create MDICLIENT window m_hWndClient = ::CreateWindowEx(dwExStyle, _T("MDIClient"), NULL, dwStyle, 0, 0, 1, 1, m_hWnd, (HMENU)nID, _Module.GetModuleInstance(), (LPVOID)&ccs); if (m_hWndClient == NULL) { ATLTRACE2(atlTraceWindowing, 0, _T("MDI Frame failed to create MDICLIENT.\n")); return NULL; } // Move it to the top of z-order ::BringWindowToTop(m_hWndClient); // set as MDI client window m_hWndMDIClient = m_hWndClient; // update to proper size T* pT = static_cast(this); pT->UpdateLayout(); return m_hWndClient; } typedef CMDIFrameWindowImpl< T, TBase, TWinTraits > thisClass; typedef CFrameWindowImplBase baseClass; BEGIN_MSG_MAP(thisClass) MESSAGE_HANDLER(WM_SIZE, OnSize) MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) MESSAGE_HANDLER(WM_MDISETMENU, OnMDISetMenu) CHAIN_MSG_MAP(baseClass) END_MSG_MAP() LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { if(wParam != SIZE_MINIMIZED) { T* pT = static_cast(this); pT->UpdateLayout(); } // message must be handled, otherwise DefFrameProc would resize the client again return 0; } LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { // don't allow CFrameWindowImplBase to handle this one return DefWindowProc(uMsg, wParam, lParam); } LRESULT OnMDISetMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { SetMDIFrameMenu(); return 0; } }; ///////////////////////////////////////////////////////////////////////////// // CMDIChildWindowImpl template class ATL_NO_VTABLE CMDIChildWindowImpl : public CFrameWindowImplBase { public: HWND Create(HWND hWndParent, LPRECT lpRect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, UINT nMenuID = 0, LPVOID lpCreateParam = NULL) { ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc); static RECT rect = { CW_USEDEFAULT, CW_USEDEFAULT, 0, 0 }; if(lpRect == NULL) lpRect = ▭ if(nMenuID != 0) m_hMenu = ::LoadMenu(_Module.GetResourceInstance(), MAKEINTRESOURCE(nMenuID)); dwStyle = T::GetWndStyle(dwStyle); dwExStyle = T::GetWndExStyle(dwExStyle); dwExStyle |= WS_EX_MDICHILD; // force this one m_pfnSuperWindowProc = ::DefMDIChildProc; m_hWndMDIClient = hWndParent; ATLASSERT(::IsWindow(m_hWndMDIClient)); HWND hWnd = CFrameWindowImplBase::Create(hWndParent, *lpRect, szWindowName, dwStyle, dwExStyle, 0, atom, lpCreateParam); if(hWnd != NULL && ::IsWindowVisible(m_hWnd) && !::IsChild(hWnd, ::GetFocus())) ::SetFocus(hWnd); return hWnd; } HWND CreateEx(HWND hWndParent, LPRECT lpRect = NULL, LPCTSTR lpcstrWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL) { TCHAR szWindowName[256]; szWindowName[0] = 0; if(lpcstrWindowName == NULL) { ::LoadString(_Module.GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, 255); lpcstrWindowName = szWindowName; } T* pT = static_cast(this); HWND hWnd = pT->Create(hWndParent, lpRect, lpcstrWindowName, dwStyle, dwExStyle, T::GetWndClassInfo().m_uCommonResourceID, lpCreateParam); if(hWnd != NULL) m_hAccel = ::LoadAccelerators(_Module.GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID)); return hWnd; } BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS, UINT nID = ATL_IDW_TOOLBAR) { ATLASSERT(!::IsWindow(m_hWndToolBar)); if(nResourceID == 0) nResourceID = T::GetWndClassInfo().m_uCommonResourceID; m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID); return (m_hWndToolBar != NULL); } BOOL UpdateClientEdge(LPRECT lpRect = NULL) { // only adjust for active MDI child window HWND hWndChild = MDIGetActive(); if(hWndChild != NULL && hWndChild != m_hWnd) return FALSE; // need to adjust the client edge style as max/restore happens DWORD dwStyle = ::GetWindowLong(m_hWndMDIClient, GWL_EXSTYLE); DWORD dwNewStyle = dwStyle; if(hWndChild != NULL && !(GetExStyle() & WS_EX_CLIENTEDGE) && (GetStyle() & WS_MAXIMIZE)) dwNewStyle &= ~(WS_EX_CLIENTEDGE); else dwNewStyle |= WS_EX_CLIENTEDGE; if(dwStyle != dwNewStyle) { // SetWindowPos will not move invalid bits ::RedrawWindow(m_hWndMDIClient, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); // remove/add WS_EX_CLIENTEDGE to MDI client area ::SetWindowLong(m_hWndMDIClient, GWL_EXSTYLE, dwNewStyle); ::SetWindowPos(m_hWndMDIClient, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOCOPYBITS); // return new client area if (lpRect != NULL) ::GetClientRect(m_hWndMDIClient, lpRect); return TRUE; } return FALSE; } typedef CMDIChildWindowImpl< T, TBase, TWinTraits > thisClass; typedef CFrameWindowImplBase baseClass; BEGIN_MSG_MAP(thisClass) MESSAGE_HANDLER(WM_SIZE, OnSize) MESSAGE_HANDLER(WM_WINDOWPOSCHANGING, OnWindowPosChanging) MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect) MESSAGE_HANDLER(WM_MDIACTIVATE, OnMDIActivate) MESSAGE_HANDLER(WM_DESTROY, OnDestroy) CHAIN_MSG_MAP(baseClass) END_MSG_MAP() LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { DefWindowProc(uMsg, wParam, lParam); // needed for MDI children CFrameWindowImplBase::OnSize(uMsg, wParam, lParam, bHandled); bHandled = TRUE; return 0; } LRESULT OnWindowPosChanging(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { // update MDI client edge and adjust MDI child rect LPWINDOWPOS lpWndPos = (LPWINDOWPOS)lParam; if(!(lpWndPos->flags & SWP_NOSIZE)) { CWindow wnd(m_hWndMDIClient); RECT rectClient; if(UpdateClientEdge(&rectClient) && (GetStyle() & WS_MAXIMIZE)) { ::AdjustWindowRectEx(&rectClient, GetStyle(), FALSE, GetExStyle()); lpWndPos->x = rectClient.left; lpWndPos->y = rectClient.top; lpWndPos->cx = rectClient.right - rectClient.left; lpWndPos->cy = rectClient.bottom - rectClient.top; } } bHandled = FALSE; return 1; } LRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { return ::SendMessage(GetMDIFrame(), uMsg, wParam, lParam); } LRESULT OnMDIActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) { if((HWND)lParam == m_hWnd && m_hMenu != NULL) SetMDIFrameMenu(); else if((HWND)lParam == NULL) ::SendMessage(GetMDIFrame(), WM_MDISETMENU, 0, 0); bHandled = FALSE; return 1; } LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { UpdateClientEdge(); bHandled = FALSE; return 1; } }; #endif //!UNDER_CE ///////////////////////////////////////////////////////////////////////////// // COwnerDraw - MI class for owner-draw support template class COwnerDraw { public: BEGIN_MSG_MAP(COwnerDraw< T >) MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem) MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem) MESSAGE_HANDLER(WM_COMPAREITEM, OnCompareItem) MESSAGE_HANDLER(WM_DELETEITEM, OnDeleteItem) ALT_MSG_MAP(1) MESSAGE_HANDLER(OCM_DRAWITEM, OnDrawItem) MESSAGE_HANDLER(OCM_MEASUREITEM, OnMeasureItem) MESSAGE_HANDLER(OCM_COMPAREITEM, OnCompareItem) MESSAGE_HANDLER(OCM_DELETEITEM, OnDeleteItem) END_MSG_MAP() // message handlers LRESULT OnDrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { T* pT = static_cast(this); pT->DrawItem((LPDRAWITEMSTRUCT)lParam); return (LRESULT)TRUE; } LRESULT OnMeasureItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { T* pT = static_cast(this); pT->MeasureItem((LPMEASUREITEMSTRUCT)lParam); return (LRESULT)TRUE; } LRESULT OnCompareItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { T* pT = static_cast(this); return (LRESULT)pT->CompareItem((LPCOMPAREITEMSTRUCT)lParam); } LRESULT OnDeleteItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { T* pT = static_cast(this); pT->DeleteItem((LPDELETEITEMSTRUCT)lParam); return (LRESULT)TRUE; } // overrideables void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { // must be implemented ATLASSERT(FALSE); } void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) { if(lpMeasureItemStruct->CtlType != ODT_MENU) { // return default height for a system font T* pT = static_cast(this); HWND hWnd = pT->GetDlgItem(lpMeasureItemStruct->CtlID); CClientDC dc(hWnd); TEXTMETRIC tm; dc.GetTextMetrics(&tm); lpMeasureItemStruct->itemHeight = tm.tmHeight; } else lpMeasureItemStruct->itemHeight = ::GetSystemMetrics(SM_CYMENU); } int CompareItem(LPCOMPAREITEMSTRUCT lpCompareItemStruct) { // all items are equal return 0; } void DeleteItem(LPDELETEITEMSTRUCT lpDeleteItemStruct) { // default - nothing } }; ///////////////////////////////////////////////////////////////////////////// // Update UI structures and constants // UI element type #define UPDUI_MENUPOPUP 0x0001 #define UPDUI_MENUBAR 0x0002 #define UPDUI_CHILDWND 0x0004 #define UPDUI_TOOLBAR 0x0008 #define UPDUI_STATUSBAR 0x0010 // state #define UPDUI_ENABLED 0x0000 #define UPDUI_DISABLED 0x0100 #define UPDUI_CHECKED 0x0200 #define UPDUI_CHECKED2 0x0400 #define UPDUI_RADIO 0x0800 #define UPDUI_DEFAULT 0x1000 #define UPDUI_TEXT 0x2000 // element data struct _AtlUpdateUIElement { HWND m_hWnd; WORD m_wType; BOOL operator ==(_AtlUpdateUIElement e) { if(m_hWnd == e.m_hWnd && m_wType == e.m_wType) return TRUE; return FALSE; } }; // map data struct _AtlUpdateUIMap { WORD m_nID; WORD m_wType; }; // instance data struct _AtlUpdateUIData { WORD m_wState; void* m_lpData; }; // these should be inside the class definition #define BEGIN_UPDATE_UI_MAP(thisClass) \ static const _AtlUpdateUIMap* GetUpdateUIMap() \ { \ static const _AtlUpdateUIMap theMap[] = \ { #define UPDATE_ELEMENT(nID, wType) \ { nID, wType }, #define END_UPDATE_UI_MAP() \ { (WORD)-1, 0 } \ }; \ return theMap; \ } /////////////////////////////////////////////////////////////////////////////// // CUpdateUI - manages UI elements updating class CUpdateUIBase { public: CSimpleArray<_AtlUpdateUIElement> m_UIElements; // elements data const _AtlUpdateUIMap* m_pUIMap; // static UI data _AtlUpdateUIData* m_pUIData; // instance UI data WORD m_wDirtyType; // global dirty flag // Constructor, destructor CUpdateUIBase() : m_pUIMap(NULL), m_pUIData(NULL), m_wDirtyType(0) { } ~CUpdateUIBase() { if(m_pUIMap != NULL && m_pUIData != NULL) { const _AtlUpdateUIMap* pUIMap = m_pUIMap; _AtlUpdateUIData* pUIData = m_pUIData; while(pUIMap->m_nID != (WORD)-1) { if(pUIData->m_wState & UPDUI_TEXT) free(pUIData->m_lpData); pUIMap++; pUIData++; } delete [] m_pUIData; } } // Add elements BOOL UIAddMenu(HWND hWnd) // menu bar (main menu) { if(hWnd == NULL) return FALSE; _AtlUpdateUIElement e; e.m_hWnd = hWnd; e.m_wType = UPDUI_MENUBAR; return m_UIElements.Add(e); } BOOL UIAddToolBar(HWND hWnd) // toolbar { if(hWnd == NULL) return FALSE; _AtlUpdateUIElement e; e.m_hWnd = hWnd; e.m_wType = UPDUI_TOOLBAR; return m_UIElements.Add(e); } BOOL UIAddStatusBar(HWND hWnd) // status bar { if(hWnd == NULL) return FALSE; _AtlUpdateUIElement e; e.m_hWnd = hWnd; e.m_wType = UPDUI_STATUSBAR; return m_UIElements.Add(e); } BOOL UIAddWindow(HWND hWnd) // child window { if(hWnd == NULL) return FALSE; _AtlUpdateUIElement e; e.m_hWnd = hWnd; e.m_wType = UPDUI_CHILDWND; return m_UIElements.Add(e); } // message map for popup menu updates BEGIN_MSG_MAP(CUpdateUIBase) MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup) END_MSG_MAP() LRESULT OnInitMenuPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) { bHandled = FALSE; HMENU hMenu = (HMENU)wParam; if(hMenu == NULL) return 1; _AtlUpdateUIData* pUIData = m_pUIData; if(pUIData == NULL) return 1; const _AtlUpdateUIMap* pMap = m_pUIMap; while(pMap->m_nID != (WORD)-1) { if(pMap->m_wType & UPDUI_MENUPOPUP) UIUpdateMenuElement(pMap->m_nID, pUIData, hMenu, FALSE); pMap++; pUIData++; } return 0; } // methods for setting UI element state BOOL UIEnable(int nID, BOOL bEnable, BOOL bForceUpdate = FALSE) { BOOL bRet = FALSE; const _AtlUpdateUIMap* pMap = m_pUIMap; _AtlUpdateUIData* p = m_pUIData; for( ; pMap->m_nID != (WORD)-1; pMap++, p++) { if(nID == (int)pMap->m_nID) { if(bEnable) { if(p->m_wState & UPDUI_DISABLED) { p->m_wState |= pMap->m_wType; p->m_wState &= ~UPDUI_DISABLED; } } else { if(!(p->m_wState & UPDUI_DISABLED)) { p->m_wState |= pMap->m_wType; p->m_wState |= UPDUI_DISABLED; } } if(bForceUpdate) p->m_wState |= pMap->m_wType; if(p->m_wState & pMap->m_wType) m_wDirtyType |= pMap->m_wType; bRet = TRUE; break; } } return bRet; } BOOL UISetCheck(int nID, int nCheck, BOOL bForceUpdate = FALSE) { BOOL bRet = FALSE; const _AtlUpdateUIMap* pMap = m_pUIMap; _AtlUpdateUIData* p = m_pUIData; for( ; pMap->m_nID != (WORD)-1; pMap++, p++) { if(nID == (int)pMap->m_nID) { switch(nCheck) { case 0: if((p->m_wState & UPDUI_CHECKED) || (p->m_wState & UPDUI_CHECKED2)) { p->m_wState |= pMap->m_wType; p->m_wState &= ~(UPDUI_CHECKED | UPDUI_CHECKED2); } break; case 1: if(!(p->m_wState & UPDUI_CHECKED)) { p->m_wState |= pMap->m_wType; p->m_wState &= ~UPDUI_CHECKED2; p->m_wState |= UPDUI_CHECKED; } break; case 2: if(!(p->m_wState & UPDUI_CHECKED2)) { p->m_wState |= pMap->m_wType; p->m_wState &= ~UPDUI_CHECKED; p->m_wState |= UPDUI_CHECKED2; } break; } if(bForceUpdate) p->m_wState |= pMap->m_wType; if(p->m_wState & pMap->m_wType) m_wDirtyType |= pMap->m_wType; bRet = TRUE; break; } } return bRet; } BOOL UISetRadio(int nID, BOOL bRadio, BOOL bForceUpdate = FALSE) { BOOL bRet = FALSE; const _AtlUpdateUIMap* pMap = m_pUIMap; _AtlUpdateUIData* p = m_pUIData; for( ; pMap->m_nID != (WORD)-1; pMap++, p++) { if(nID == (int)pMap->m_nID) { if(bRadio) { if(!(p->m_wState & UPDUI_RADIO)) { p->m_wState |= pMap->m_wType; p->m_wState |= UPDUI_RADIO; } } else { if(p->m_wState & UPDUI_RADIO) { p->m_wState |= pMap->m_wType; p->m_wState &= ~UPDUI_RADIO; } } if(bForceUpdate) p->m_wState |= pMap->m_wType; if(p->m_wState & pMap->m_wType) m_wDirtyType |= pMap->m_wType; bRet = TRUE; break; } } return bRet; } BOOL UISetText(int nID, LPCTSTR lpstrText, BOOL bForceUpdate = FALSE) { ATLASSERT(lpstrText != NULL); BOOL bRet = FALSE; const _AtlUpdateUIMap* pMap = m_pUIMap; _AtlUpdateUIData* p = m_pUIData; for( ; pMap->m_nID != (WORD)-1; pMap++, p++) { if(nID == (int)pMap->m_nID) { if(p->m_lpData != NULL && lstrcmp((LPTSTR)p->m_lpData, lpstrText)) { if(p->m_lpData != NULL) free(p->m_lpData); int nStrLen = lstrlen(lpstrText); p->m_lpData = malloc(nStrLen + sizeof(TCHAR)); if(p->m_lpData == NULL) { ATLTRACE2(atlTraceWindowing, 0, _T("SetText - malloc failed\n")); break; } lstrcpy((LPTSTR)p->m_lpData, lpstrText); p->m_wState |= (UPDUI_TEXT | pMap->m_wType); } if(bForceUpdate) p->m_wState |= (UPDUI_TEXT | pMap->m_wType); if(p->m_wState | pMap->m_wType) m_wDirtyType |= pMap->m_wType; bRet = TRUE; break; } } return bRet; } // methods for complete state set/get BOOL UISetState(int nID, DWORD dwState) { BOOL bRet = FALSE; const _AtlUpdateUIMap* pMap = m_pUIMap; _AtlUpdateUIData* p = m_pUIData; for( ; pMap->m_nID != (WORD)-1; pMap++, p++) { if(nID == (int)pMap->m_nID) { p->m_wState |= dwState | pMap->m_wType; m_wDirtyType |= pMap->m_wType; bRet = TRUE; break; } } return bRet; } DWORD UIGetState(int nID) { const _AtlUpdateUIMap* pMap = m_pUIMap; _AtlUpdateUIData* p = m_pUIData; for( ; pMap->m_nID != (WORD)-1; pMap++, p++) { if(nID == (int)pMap->m_nID) return p->m_wState; } return 0; } // methods for updating UI #ifndef UNDER_CE //REVIEW BOOL UIUpdateMenu(BOOL bForceUpdate = FALSE) { if(!(m_wDirtyType & UPDUI_MENUBAR) && !bForceUpdate) return TRUE; _AtlUpdateUIData* pUIData = m_pUIData; if(pUIData == NULL) return FALSE; const _AtlUpdateUIMap* pMap = m_pUIMap; HMENU hMenu; for(int i = 0; i < m_UIElements.GetSize(); i++) { if(m_UIElements[i].m_wType == UPDUI_MENUBAR) { pMap = m_pUIMap; pUIData = m_pUIData; hMenu = ::GetMenu(m_UIElements[i].m_hWnd); if(hMenu == NULL) continue; while(pMap->m_nID != (WORD)-1) { if((pUIData->m_wState & UPDUI_MENUBAR) && (pMap->m_wType & UPDUI_MENUBAR)) UIUpdateMenuElement(pMap->m_nID, pUIData, hMenu, TRUE); pMap++; pUIData++; } //REVIEW ::DrawMenuBar(m_UIElements[i].m_hWnd); } } m_wDirtyType &= ~UPDUI_MENUBAR; return TRUE; } #endif //!UNDER_CE BOOL UIUpdateToolBar(BOOL bForceUpdate = FALSE) { if(!(m_wDirtyType & UPDUI_TOOLBAR) && !bForceUpdate) return TRUE; const _AtlUpdateUIMap* pMap = m_pUIMap; _AtlUpdateUIData* pUIData = m_pUIData; if(pUIData == NULL) return FALSE; for(int i = 0; i < m_UIElements.GetSize(); i++) { if(m_UIElements[i].m_wType == UPDUI_TOOLBAR) { pMap = m_pUIMap; pUIData = m_pUIData; while(pMap->m_nID != (WORD)-1) { if((pUIData->m_wState & UPDUI_TOOLBAR) && (pMap->m_wType & UPDUI_TOOLBAR)) UIUpdateToolBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd); pMap++; pUIData++; } } } m_wDirtyType &= ~UPDUI_TOOLBAR; return TRUE; } BOOL UIUpdateStatusBar(BOOL bForceUpdate = FALSE) { if(!(m_wDirtyType & UPDUI_STATUSBAR) && !bForceUpdate) return TRUE; const _AtlUpdateUIMap* pMap = m_pUIMap; _AtlUpdateUIData* pUIData = m_pUIData; if(pUIData == NULL) return FALSE; for(int i = 0; i < m_UIElements.GetSize(); i++) { if(m_UIElements[i].m_wType == UPDUI_STATUSBAR) { pMap = m_pUIMap; pUIData = m_pUIData; while(pMap->m_nID != (WORD)-1) { if((pUIData->m_wState & UPDUI_STATUSBAR) && (pMap->m_wType & UPDUI_STATUSBAR)) UIUpdateStatusBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd); pMap++; pUIData++; } } } m_wDirtyType &= ~UPDUI_STATUSBAR; return TRUE; } BOOL UIUpdateChildWnd(BOOL bForceUpdate = FALSE) { if(!(m_wDirtyType & UPDUI_CHILDWND) && !bForceUpdate) return TRUE; const _AtlUpdateUIMap* pMap = m_pUIMap; _AtlUpdateUIData* pUIData = m_pUIData; if(pUIData == NULL) return FALSE; for(int i = 0; i < m_UIElements.GetSize(); i++) { if(m_UIElements[i].m_wType == UPDUI_CHILDWND) { pMap = m_pUIMap; pUIData = m_pUIData; while(pMap->m_nID != (WORD)-1) { if((pUIData->m_wState & UPDUI_CHILDWND) && (pMap->m_wType & UPDUI_CHILDWND)) UIUpdateChildWndElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd); pMap++; pUIData++; } } } m_wDirtyType &= ~UPDUI_CHILDWND; return TRUE; } // internal element specific methods #ifndef UNDER_CE static void UIUpdateMenuElement(int nID, _AtlUpdateUIData* pUIData, HMENU hMenu, BOOL bClearState) { MENUITEMINFO mii; memset(&mii, 0, sizeof(MENUITEMINFO)); mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_STATE; mii.wID = nID; if(pUIData->m_wState & UPDUI_DISABLED) mii.fState |= MFS_DISABLED | MFS_GRAYED; else mii.fState |= MFS_ENABLED; if(pUIData->m_wState & UPDUI_CHECKED) mii.fState |= MFS_CHECKED; else mii.fState |= MFS_UNCHECKED; if(pUIData->m_wState & UPDUI_DEFAULT) mii.fState |= MFS_DEFAULT; if(pUIData->m_wState & UPDUI_TEXT) { mii.fMask |= MIIM_TYPE; mii.fType = MFT_STRING; mii.dwTypeData = (LPTSTR)pUIData->m_lpData; } ::SetMenuItemInfo(hMenu, nID, FALSE, &mii); if(pUIData->m_wState & UPDUI_TEXT) { free(pUIData->m_lpData); pUIData->m_wState &= ~UPDUI_TEXT; } if(bClearState) pUIData->m_wState &= ~UPDUI_MENUBAR; } #else // CE specific static void UIUpdateMenuElement(int nID, _AtlUpdateUIData* pUIData, HMENU hMenu, BOOL bClearState) { UINT uState = 0; if(pUIData->m_wState & UPDUI_DISABLED) uState = MF_GRAYED; else uState = MF_ENABLED; ::EnableMenuItem(hMenu, nID, uState); if(pUIData->m_wState & UPDUI_CHECKED) uState = 1; else uState = 0; ::CheckMenuItem(hMenu, nID, uState); //CE if(pUIData->m_wState & UPDUI_DEFAULT) //CE mii.fState |= MFS_DEFAULT; if(pUIData->m_wState & UPDUI_TEXT) { MENUITEMINFO mii; memset(&mii, 0, sizeof(MENUITEMINFO)); mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_TYPE; mii.wID = nID; mii.fType = MFT_STRING; mii.dwTypeData = (LPTSTR)pUIData->m_lpData; ::SetMenuItemInfo(hMenu, nID, FALSE, &mii); free(pUIData->m_lpData); pUIData->m_wState &= ~UPDUI_TEXT; } if(bClearState) pUIData->m_wState &= ~UPDUI_MENUBAR; } #endif //!UNDER_CE static void UIUpdateToolBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndToolBar) { //REVIEW: only handles enabled/disabled and checked state, and radio (press) ::SendMessage(hWndToolBar, TB_ENABLEBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE); ::SendMessage(hWndToolBar, TB_CHECKBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED) ? TRUE : FALSE); ::SendMessage(hWndToolBar, TB_INDETERMINATE, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED2) ? TRUE : FALSE); ::SendMessage(hWndToolBar, TB_PRESSBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_RADIO) ? TRUE : FALSE); pUIData->m_wState &= ~UPDUI_TOOLBAR; } static void UIUpdateStatusBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndStatusBar) { if(pUIData->m_wState | UPDUI_TEXT) { ::SendMessage(hWndStatusBar, SB_SETTEXT, nID, (LPARAM)pUIData->m_lpData); free(pUIData->m_lpData); pUIData->m_wState &= ~UPDUI_TEXT; } pUIData->m_wState &= ~UPDUI_STATUSBAR; } static void UIUpdateChildWndElement(int nID, _AtlUpdateUIData* pUIData, HWND hWnd) { HWND hChild = ::GetDlgItem(hWnd, nID); ::EnableWindow(hChild, (pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE); // for check and radio, assume that window is a button int nCheck = BST_UNCHECKED; if(pUIData->m_wState & UPDUI_CHECKED || pUIData->m_wState & UPDUI_RADIO) nCheck = BST_CHECKED; else if(pUIData->m_wState & UPDUI_CHECKED2) nCheck = BST_INDETERMINATE; ::SendMessage(hChild, BM_SETCHECK, nCheck, 0L); if(pUIData->m_wState & UPDUI_DEFAULT) { DWORD dwRet = ::SendMessage(hWnd, DM_GETDEFID, 0, 0L); if(HIWORD(dwRet) == DC_HASDEFID) { HWND hOldDef = ::GetDlgItem(hWnd, LOWORD(dwRet)); // remove BS_DEFPUSHBUTTON ::SendMessage(hOldDef, BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE, 0)); } ::SendMessage(hWnd, DM_SETDEFID, nID, 0L); } if(pUIData->m_wState & UPDUI_TEXT) { ::SetWindowText(hChild, (LPTSTR)pUIData->m_lpData); free(pUIData->m_lpData); pUIData->m_wState &= ~UPDUI_TEXT; } pUIData->m_wState &= ~UPDUI_CHILDWND; } }; template class CUpdateUI : public CUpdateUIBase { public: CUpdateUI() { T* pT = static_cast(this); pT; const _AtlUpdateUIMap* pMap = pT->GetUpdateUIMap(); m_pUIMap = pMap; ATLASSERT(m_pUIMap != NULL); for(int nCount = 1; pMap->m_nID != (WORD)-1; nCount++) pMap++; ATLTRY(m_pUIData = new _AtlUpdateUIData[nCount]); ATLASSERT(m_pUIData != NULL); if(m_pUIData != NULL) memset(m_pUIData, 0, sizeof(_AtlUpdateUIData) * nCount); } }; }; //namespace ATL #endif // __ATLFRAME_H__