PageRenderTime 73ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/thirdparty/wtl/atlframe.h

http://crashrpt.googlecode.com/
C Header | 3678 lines | 2942 code | 488 blank | 248 comment | 696 complexity | 418035ec778967ae3632c7f33f3fcf3c MD5 | raw file
Possible License(s): LGPL-3.0, BSD-3-Clause
  1. // Windows Template Library - WTL version 8.1
  2. // Copyright (C) Microsoft Corporation. All rights reserved.
  3. //
  4. // This file is a part of the Windows Template Library.
  5. // The use and distribution terms for this software are covered by the
  6. // Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
  7. // which can be found in the file CPL.TXT at the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by
  9. // the terms of this license. You must not remove this notice, or
  10. // any other, from this software.
  11. #ifndef __ATLFRAME_H__
  12. #define __ATLFRAME_H__
  13. #pragma once
  14. #ifndef __ATLAPP_H__
  15. #error atlframe.h requires atlapp.h to be included first
  16. #endif
  17. #ifndef __ATLWIN_H__
  18. #error atlframe.h requires atlwin.h to be included first
  19. #endif
  20. ///////////////////////////////////////////////////////////////////////////////
  21. // Classes in this file:
  22. //
  23. // CFrameWindowImpl<T, TBase, TWinTraits>
  24. // CMDIWindow
  25. // CMDIFrameWindowImpl<T, TBase, TWinTraits>
  26. // CMDIChildWindowImpl<T, TBase, TWinTraits>
  27. // COwnerDraw<T>
  28. // CUpdateUIBase
  29. // CUpdateUI<T>
  30. // CDynamicUpdateUI<T>
  31. // CAutoUpdateUI<T>
  32. // CDialogResize<T>
  33. // CDoubleBufferImpl<T>
  34. // CDoubleBufferWindowImpl<T, TBase, TWinTraits>
  35. //
  36. // Global functions:
  37. // AtlCreateSimpleToolBar()
  38. namespace WTL
  39. {
  40. ///////////////////////////////////////////////////////////////////////////////
  41. // CFrameWndClassInfo - Manages frame window Windows class information
  42. class CFrameWndClassInfo
  43. {
  44. public:
  45. #ifndef _WIN32_WCE
  46. enum { cchAutoName = 5 + sizeof(void*) * 2 }; // sizeof(void*) * 2 is the number of digits %p outputs
  47. WNDCLASSEX m_wc;
  48. #else // CE specific
  49. enum { cchAutoName = MAX_PATH }; // MAX_PATH because this can be set in the wizard generated CMainFrame::ActivatePreviousInstance to a user defined string.
  50. WNDCLASS m_wc;
  51. #endif // !_WIN32_WCE
  52. LPCTSTR m_lpszOrigName;
  53. WNDPROC pWndProc;
  54. LPCTSTR m_lpszCursorID;
  55. BOOL m_bSystemCursor;
  56. ATOM m_atom;
  57. TCHAR m_szAutoName[cchAutoName];
  58. UINT m_uCommonResourceID;
  59. #ifndef _WIN32_WCE
  60. ATOM Register(WNDPROC* pProc)
  61. {
  62. if (m_atom == 0)
  63. {
  64. CWindowCreateCriticalSectionLock lock;
  65. if(FAILED(lock.Lock()))
  66. {
  67. ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CFrameWndClassInfo::Register.\n"));
  68. ATLASSERT(FALSE);
  69. return 0;
  70. }
  71. if(m_atom == 0)
  72. {
  73. HINSTANCE hInst = ModuleHelper::GetModuleInstance();
  74. if (m_lpszOrigName != NULL)
  75. {
  76. ATLASSERT(pProc != NULL);
  77. LPCTSTR lpsz = m_wc.lpszClassName;
  78. WNDPROC proc = m_wc.lpfnWndProc;
  79. WNDCLASSEX wc = { sizeof(WNDCLASSEX) };
  80. // try process local class first
  81. if(!::GetClassInfoEx(ModuleHelper::GetModuleInstance(), m_lpszOrigName, &wc))
  82. {
  83. // try global class
  84. if(!::GetClassInfoEx(NULL, m_lpszOrigName, &wc))
  85. {
  86. lock.Unlock();
  87. return 0;
  88. }
  89. }
  90. m_wc = wc;
  91. pWndProc = m_wc.lpfnWndProc;
  92. m_wc.lpszClassName = lpsz;
  93. m_wc.lpfnWndProc = proc;
  94. }
  95. else
  96. {
  97. m_wc.hCursor = ::LoadCursor(m_bSystemCursor ? NULL : hInst, m_lpszCursorID);
  98. }
  99. m_wc.hInstance = hInst;
  100. m_wc.style &= ~CS_GLOBALCLASS; // we don't register global classes
  101. if (m_wc.lpszClassName == NULL)
  102. {
  103. #if (_WIN32_WINNT >= 0x0500) || defined(_WIN64)
  104. SecureHelper::wsprintf_x(m_szAutoName, cchAutoName, _T("ATL:%p"), &m_wc);
  105. #else // !((_WIN32_WINNT >= 0x0500) || defined(_WIN64))
  106. SecureHelper::wsprintf_x(m_szAutoName, cchAutoName, _T("ATL:%8.8X"), (DWORD_PTR)&m_wc);
  107. #endif // !((_WIN32_WINNT >= 0x0500) || defined(_WIN64))
  108. m_wc.lpszClassName = m_szAutoName;
  109. }
  110. WNDCLASSEX wcTemp = m_wc;
  111. m_atom = (ATOM)::GetClassInfoEx(m_wc.hInstance, m_wc.lpszClassName, &wcTemp);
  112. if (m_atom == 0)
  113. {
  114. if(m_uCommonResourceID != 0) // use it if not zero
  115. {
  116. m_wc.hIcon = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
  117. m_wc.hIconSm = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
  118. }
  119. m_atom = ::RegisterClassEx(&m_wc);
  120. }
  121. }
  122. lock.Unlock();
  123. }
  124. if (m_lpszOrigName != NULL)
  125. {
  126. ATLASSERT(pProc != NULL);
  127. ATLASSERT(pWndProc != NULL);
  128. *pProc = pWndProc;
  129. }
  130. return m_atom;
  131. }
  132. #else // CE specific
  133. ATOM Register(WNDPROC* pProc)
  134. {
  135. if (m_atom == 0)
  136. {
  137. CWindowCreateCriticalSectionLock lock;
  138. if(FAILED(lock.Lock()))
  139. {
  140. ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CFrameWndClassInfo::Register.\n"));
  141. ATLASSERT(FALSE);
  142. return 0;
  143. }
  144. if(m_atom == 0)
  145. {
  146. HINSTANCE hInst = ModuleHelper::GetModuleInstance();
  147. if (m_lpszOrigName != NULL)
  148. {
  149. ATLASSERT(pProc != NULL);
  150. LPCTSTR lpsz = m_wc.lpszClassName;
  151. WNDPROC proc = m_wc.lpfnWndProc;
  152. WNDCLASS wc = { 0 };
  153. // try process local class first
  154. if(!::GetClassInfo(ModuleHelper::GetModuleInstance(), m_lpszOrigName, &wc))
  155. {
  156. // try global class
  157. if(!::GetClassInfo(NULL, m_lpszOrigName, &wc))
  158. {
  159. lock.Unlock();
  160. return 0;
  161. }
  162. }
  163. m_wc = wc;
  164. pWndProc = m_wc.lpfnWndProc;
  165. m_wc.lpszClassName = lpsz;
  166. m_wc.lpfnWndProc = proc;
  167. }
  168. else
  169. {
  170. #if defined(GWES_CURSOR) || defined(GWES_MCURSOR)
  171. m_wc.hCursor = ::LoadCursor(m_bSystemCursor ? NULL : hInst, m_lpszCursorID);
  172. #else // !(defined(GWES_CURSOR) || defined(GWES_MCURSOR))
  173. m_wc.hCursor = NULL;
  174. #endif // !(defined(GWES_CURSOR) || defined(GWES_MCURSOR))
  175. }
  176. m_wc.hInstance = hInst;
  177. m_wc.style &= ~CS_GLOBALCLASS; // we don't register global classes
  178. if (m_wc.lpszClassName == NULL)
  179. {
  180. wsprintf(m_szAutoName, _T("ATL:%8.8X"), (DWORD_PTR)&m_wc);
  181. m_wc.lpszClassName = m_szAutoName;
  182. }
  183. WNDCLASS wcTemp = m_wc;
  184. m_atom = (ATOM)::GetClassInfo(m_wc.hInstance, m_wc.lpszClassName, &wcTemp);
  185. if (m_atom == 0)
  186. {
  187. if(m_uCommonResourceID != 0) // use it if not zero
  188. m_wc.hIcon = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
  189. m_atom = ::RegisterClass(&m_wc);
  190. }
  191. }
  192. lock.Unlock();
  193. }
  194. if (m_lpszOrigName != NULL)
  195. {
  196. ATLASSERT(pProc != NULL);
  197. ATLASSERT(pWndProc != NULL);
  198. *pProc = pWndProc;
  199. }
  200. return m_atom;
  201. }
  202. #endif // _WIN32_WCE
  203. };
  204. ///////////////////////////////////////////////////////////////////////////////
  205. // Macros for declaring frame window WNDCLASS
  206. #ifndef _WIN32_WCE
  207. #define DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \
  208. static WTL::CFrameWndClassInfo& GetWndClassInfo() \
  209. { \
  210. static WTL::CFrameWndClassInfo wc = \
  211. { \
  212. { sizeof(WNDCLASSEX), 0, StartWindowProc, \
  213. 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL }, \
  214. NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \
  215. }; \
  216. return wc; \
  217. }
  218. #define DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \
  219. static WTL::CFrameWndClassInfo& GetWndClassInfo() \
  220. { \
  221. static WTL::CFrameWndClassInfo wc = \
  222. { \
  223. { sizeof(WNDCLASSEX), style, StartWindowProc, \
  224. 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName, NULL }, \
  225. NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \
  226. }; \
  227. return wc; \
  228. }
  229. #define DECLARE_FRAME_WND_SUPERCLASS(WndClassName, OrigWndClassName, uCommonResourceID) \
  230. static WTL::CFrameWndClassInfo& GetWndClassInfo() \
  231. { \
  232. static WTL::CFrameWndClassInfo wc = \
  233. { \
  234. { sizeof(WNDCLASSEX), 0, StartWindowProc, \
  235. 0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName, NULL }, \
  236. OrigWndClassName, NULL, NULL, TRUE, 0, _T(""), uCommonResourceID \
  237. }; \
  238. return wc; \
  239. }
  240. #else // CE specific
  241. #define DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \
  242. static WTL::CFrameWndClassInfo& GetWndClassInfo() \
  243. { \
  244. static WTL::CFrameWndClassInfo wc = \
  245. { \
  246. { 0, StartWindowProc, \
  247. 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName }, \
  248. NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \
  249. }; \
  250. return wc; \
  251. }
  252. #define DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \
  253. static WTL::CFrameWndClassInfo& GetWndClassInfo() \
  254. { \
  255. static WTL::CFrameWndClassInfo wc = \
  256. { \
  257. { style, StartWindowProc, \
  258. 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName }, \
  259. NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \
  260. }; \
  261. return wc; \
  262. }
  263. #define DECLARE_FRAME_WND_SUPERCLASS(WndClassName, OrigWndClassName, uCommonResourceID) \
  264. static WTL::CFrameWndClassInfo& GetWndClassInfo() \
  265. { \
  266. static WTL::CFrameWndClassInfo wc = \
  267. { \
  268. { NULL, StartWindowProc, \
  269. 0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName }, \
  270. OrigWndClassName, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \
  271. }; \
  272. return wc; \
  273. }
  274. #endif // !_WIN32_WCE
  275. ///////////////////////////////////////////////////////////////////////////////
  276. // CFrameWindowImpl
  277. // Client window command chaining macro (only for frame windows)
  278. #define CHAIN_CLIENT_COMMANDS() \
  279. if(uMsg == WM_COMMAND && m_hWndClient != NULL) \
  280. ::SendMessage(m_hWndClient, uMsg, wParam, lParam);
  281. // standard toolbar styles
  282. #define ATL_SIMPLE_TOOLBAR_STYLE \
  283. (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS)
  284. // toolbar in a rebar pane
  285. #define ATL_SIMPLE_TOOLBAR_PANE_STYLE \
  286. (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT)
  287. // standard rebar styles
  288. #if (_WIN32_IE >= 0x0400)
  289. #define ATL_SIMPLE_REBAR_STYLE \
  290. (WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_AUTOSIZE)
  291. #else
  292. #define ATL_SIMPLE_REBAR_STYLE \
  293. (WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS)
  294. #endif // !(_WIN32_IE >= 0x0400)
  295. // rebar without borders
  296. #if (_WIN32_IE >= 0x0400)
  297. #define ATL_SIMPLE_REBAR_NOBORDER_STYLE \
  298. (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_AUTOSIZE | CCS_NODIVIDER)
  299. #else
  300. #define ATL_SIMPLE_REBAR_NOBORDER_STYLE \
  301. (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | CCS_NODIVIDER)
  302. #endif // !(_WIN32_IE >= 0x0400)
  303. // command bar support
  304. #if !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE)
  305. #define CBRM_GETCMDBAR (WM_USER + 301) // returns command bar HWND
  306. #define CBRM_GETMENU (WM_USER + 302) // returns loaded or attached menu
  307. #define CBRM_TRACKPOPUPMENU (WM_USER + 303) // displays a popup menu
  308. struct _AtlFrameWnd_CmdBarPopupMenu
  309. {
  310. int cbSize;
  311. HMENU hMenu;
  312. UINT uFlags;
  313. int x;
  314. int y;
  315. LPTPMPARAMS lptpm;
  316. };
  317. #define CBRPOPUPMENU _AtlFrameWnd_CmdBarPopupMenu
  318. #endif // !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE)
  319. template <class TBase = ATL::CWindow, class TWinTraits = ATL::CFrameWinTraits>
  320. class ATL_NO_VTABLE CFrameWindowImplBase : public ATL::CWindowImplBaseT< TBase, TWinTraits >
  321. {
  322. public:
  323. DECLARE_FRAME_WND_CLASS(NULL, 0)
  324. #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
  325. struct _ChevronMenuInfo
  326. {
  327. HMENU hMenu;
  328. LPNMREBARCHEVRON lpnm;
  329. bool bCmdBar;
  330. };
  331. #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
  332. // Data members
  333. HWND m_hWndToolBar;
  334. HWND m_hWndStatusBar;
  335. HWND m_hWndClient;
  336. #ifdef _WIN32_WCE
  337. HWND m_hWndCECommandBar;
  338. #endif // _WIN32_WCE
  339. HACCEL m_hAccel;
  340. // Constructor
  341. CFrameWindowImplBase() :
  342. m_hWndToolBar(NULL),
  343. m_hWndStatusBar(NULL),
  344. m_hWndClient(NULL),
  345. #ifdef _WIN32_WCE
  346. m_hWndCECommandBar(NULL),
  347. #endif // _WIN32_WCE
  348. m_hAccel(NULL)
  349. { }
  350. // Methods
  351. HWND Create(HWND hWndParent, ATL::_U_RECT rect, LPCTSTR szWindowName, DWORD dwStyle, DWORD dwExStyle, ATL::_U_MENUorID MenuOrID, ATOM atom, LPVOID lpCreateParam)
  352. {
  353. ATLASSERT(m_hWnd == NULL);
  354. if(atom == 0)
  355. return NULL;
  356. ModuleHelper::AddCreateWndData(&m_thunk.cd, this);
  357. if(MenuOrID.m_hMenu == NULL && (dwStyle & WS_CHILD))
  358. MenuOrID.m_hMenu = (HMENU)(UINT_PTR)this;
  359. if(rect.m_lpRect == NULL)
  360. rect.m_lpRect = &TBase::rcDefault;
  361. HWND hWnd = ::CreateWindowEx(dwExStyle, MAKEINTATOM(atom), szWindowName,
  362. dwStyle, rect.m_lpRect->left, rect.m_lpRect->top, rect.m_lpRect->right - rect.m_lpRect->left,
  363. rect.m_lpRect->bottom - rect.m_lpRect->top, hWndParent, MenuOrID.m_hMenu,
  364. ModuleHelper::GetModuleInstance(), lpCreateParam);
  365. ATLASSERT(hWnd == NULL || m_hWnd == hWnd);
  366. return hWnd;
  367. }
  368. static HWND CreateSimpleToolBarCtrl(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE,
  369. DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
  370. {
  371. HINSTANCE hInst = ModuleHelper::GetResourceInstance();
  372. HRSRC hRsrc = ::FindResource(hInst, MAKEINTRESOURCE(nResourceID), RT_TOOLBAR);
  373. if (hRsrc == NULL)
  374. return NULL;
  375. HGLOBAL hGlobal = ::LoadResource(hInst, hRsrc);
  376. if (hGlobal == NULL)
  377. return NULL;
  378. _AtlToolBarData* pData = (_AtlToolBarData*)::LockResource(hGlobal);
  379. if (pData == NULL)
  380. return NULL;
  381. ATLASSERT(pData->wVersion == 1);
  382. WORD* pItems = pData->items();
  383. int nItems = pData->wItemCount + (bInitialSeparator ? 1 : 0);
  384. CTempBuffer<TBBUTTON, _WTL_STACK_ALLOC_THRESHOLD> buff;
  385. TBBUTTON* pTBBtn = buff.Allocate(nItems);
  386. ATLASSERT(pTBBtn != NULL);
  387. if(pTBBtn == NULL)
  388. return NULL;
  389. const int cxSeparator = 8;
  390. // set initial separator (half width)
  391. if(bInitialSeparator)
  392. {
  393. pTBBtn[0].iBitmap = cxSeparator / 2;
  394. pTBBtn[0].idCommand = 0;
  395. pTBBtn[0].fsState = 0;
  396. pTBBtn[0].fsStyle = TBSTYLE_SEP;
  397. pTBBtn[0].dwData = 0;
  398. pTBBtn[0].iString = 0;
  399. }
  400. int nBmp = 0;
  401. for(int i = 0, j = bInitialSeparator ? 1 : 0; i < pData->wItemCount; i++, j++)
  402. {
  403. if(pItems[i] != 0)
  404. {
  405. pTBBtn[j].iBitmap = nBmp++;
  406. pTBBtn[j].idCommand = pItems[i];
  407. pTBBtn[j].fsState = TBSTATE_ENABLED;
  408. pTBBtn[j].fsStyle = TBSTYLE_BUTTON;
  409. pTBBtn[j].dwData = 0;
  410. pTBBtn[j].iString = 0;
  411. }
  412. else
  413. {
  414. pTBBtn[j].iBitmap = cxSeparator;
  415. pTBBtn[j].idCommand = 0;
  416. pTBBtn[j].fsState = 0;
  417. pTBBtn[j].fsStyle = TBSTYLE_SEP;
  418. pTBBtn[j].dwData = 0;
  419. pTBBtn[j].iString = 0;
  420. }
  421. }
  422. #ifndef _WIN32_WCE
  423. HWND hWnd = ::CreateWindowEx(0, TOOLBARCLASSNAME, NULL, dwStyle, 0, 0, 100, 100, hWndParent, (HMENU)LongToHandle(nID), ModuleHelper::GetModuleInstance(), NULL);
  424. if(hWnd == NULL)
  425. {
  426. ATLASSERT(FALSE);
  427. return NULL;
  428. }
  429. #else // CE specific
  430. dwStyle;
  431. nID;
  432. // The toolbar must go onto the existing CommandBar or MenuBar
  433. HWND hWnd = hWndParent;
  434. #endif // _WIN32_WCE
  435. ::SendMessage(hWnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0L);
  436. // check if font is taller than our bitmaps
  437. CFontHandle font = (HFONT)::SendMessage(hWnd, WM_GETFONT, 0, 0L);
  438. if(font.IsNull())
  439. font = (HFONT)::GetStockObject(SYSTEM_FONT);
  440. LOGFONT lf = { 0 };
  441. font.GetLogFont(lf);
  442. WORD cyFontHeight = (WORD)abs(lf.lfHeight);
  443. #ifndef _WIN32_WCE
  444. WORD bitsPerPixel = AtlGetBitmapResourceBitsPerPixel(nResourceID);
  445. if(bitsPerPixel > 4)
  446. {
  447. COLORREF crMask = CLR_DEFAULT;
  448. if(bitsPerPixel == 32)
  449. {
  450. // 32-bit color bitmap with alpha channel (valid for Windows XP and later)
  451. crMask = CLR_NONE;
  452. }
  453. HIMAGELIST hImageList = ImageList_LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(nResourceID), pData->wWidth, 1, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
  454. ATLASSERT(hImageList != NULL);
  455. ::SendMessage(hWnd, TB_SETIMAGELIST, 0, (LPARAM)hImageList);
  456. }
  457. else
  458. #endif // !_WIN32_WCE
  459. {
  460. TBADDBITMAP tbab = { 0 };
  461. tbab.hInst = hInst;
  462. tbab.nID = nResourceID;
  463. ::SendMessage(hWnd, TB_ADDBITMAP, nBmp, (LPARAM)&tbab);
  464. }
  465. ::SendMessage(hWnd, TB_ADDBUTTONS, nItems, (LPARAM)pTBBtn);
  466. ::SendMessage(hWnd, TB_SETBITMAPSIZE, 0, MAKELONG(pData->wWidth, max(pData->wHeight, cyFontHeight)));
  467. const int cxyButtonMargin = 7;
  468. ::SendMessage(hWnd, TB_SETBUTTONSIZE, 0, MAKELONG(pData->wWidth + cxyButtonMargin, max(pData->wHeight, cyFontHeight) + cxyButtonMargin));
  469. return hWnd;
  470. }
  471. #ifndef _WIN32_WCE
  472. static HWND CreateSimpleReBarCtrl(HWND hWndParent, DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
  473. {
  474. // Ensure style combinations for proper rebar painting
  475. if(dwStyle & CCS_NODIVIDER && dwStyle & WS_BORDER)
  476. dwStyle &= ~WS_BORDER;
  477. else if(!(dwStyle & WS_BORDER) && !(dwStyle & CCS_NODIVIDER))
  478. dwStyle |= CCS_NODIVIDER;
  479. // Create rebar window
  480. HWND hWndReBar = ::CreateWindowEx(0, REBARCLASSNAME, NULL, dwStyle, 0, 0, 100, 100, hWndParent, (HMENU)LongToHandle(nID), ModuleHelper::GetModuleInstance(), NULL);
  481. if(hWndReBar == NULL)
  482. {
  483. ATLTRACE2(atlTraceUI, 0, _T("Failed to create rebar.\n"));
  484. return NULL;
  485. }
  486. // Initialize and send the REBARINFO structure
  487. REBARINFO rbi = { sizeof(REBARINFO), 0 };
  488. if(::SendMessage(hWndReBar, RB_SETBARINFO, 0, (LPARAM)&rbi) == 0)
  489. {
  490. ATLTRACE2(atlTraceUI, 0, _T("Failed to initialize rebar.\n"));
  491. ::DestroyWindow(hWndReBar);
  492. return NULL;
  493. }
  494. return hWndReBar;
  495. }
  496. BOOL CreateSimpleReBar(DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
  497. {
  498. ATLASSERT(!::IsWindow(m_hWndToolBar));
  499. m_hWndToolBar = CreateSimpleReBarCtrl(m_hWnd, dwStyle, nID);
  500. return (m_hWndToolBar != NULL);
  501. }
  502. static BOOL AddSimpleReBarBandCtrl(HWND hWndReBar, HWND hWndBand, int nID = 0, LPCTSTR lpstrTitle = NULL, BOOL bNewRow = FALSE, int cxWidth = 0, BOOL bFullWidthAlways = FALSE)
  503. {
  504. ATLASSERT(::IsWindow(hWndReBar)); // must be already created
  505. #ifdef _DEBUG
  506. // block - check if this is really a rebar
  507. {
  508. TCHAR lpszClassName[sizeof(REBARCLASSNAME)] = { 0 };
  509. ::GetClassName(hWndReBar, lpszClassName, sizeof(REBARCLASSNAME));
  510. ATLASSERT(lstrcmp(lpszClassName, REBARCLASSNAME) == 0);
  511. }
  512. #endif // _DEBUG
  513. ATLASSERT(::IsWindow(hWndBand)); // must be already created
  514. // Get number of buttons on the toolbar
  515. int nBtnCount = (int)::SendMessage(hWndBand, TB_BUTTONCOUNT, 0, 0L);
  516. // Set band info structure
  517. REBARBANDINFO rbBand = { RunTimeHelper::SizeOf_REBARBANDINFO() };
  518. #if (_WIN32_IE >= 0x0400)
  519. rbBand.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE | RBBIM_IDEALSIZE;
  520. #else
  521. rbBand.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE;
  522. #endif // !(_WIN32_IE >= 0x0400)
  523. if(lpstrTitle != NULL)
  524. rbBand.fMask |= RBBIM_TEXT;
  525. rbBand.fStyle = RBBS_CHILDEDGE;
  526. #if (_WIN32_IE >= 0x0500)
  527. if(nBtnCount > 0) // add chevron style for toolbar with buttons
  528. rbBand.fStyle |= RBBS_USECHEVRON;
  529. #endif // (_WIN32_IE >= 0x0500)
  530. if(bNewRow)
  531. rbBand.fStyle |= RBBS_BREAK;
  532. rbBand.lpText = (LPTSTR)lpstrTitle;
  533. rbBand.hwndChild = hWndBand;
  534. if(nID == 0) // calc band ID
  535. nID = ATL_IDW_BAND_FIRST + (int)::SendMessage(hWndReBar, RB_GETBANDCOUNT, 0, 0L);
  536. rbBand.wID = nID;
  537. // Calculate the size of the band
  538. BOOL bRet = FALSE;
  539. RECT rcTmp = { 0 };
  540. if(nBtnCount > 0)
  541. {
  542. bRet = (BOOL)::SendMessage(hWndBand, TB_GETITEMRECT, nBtnCount - 1, (LPARAM)&rcTmp);
  543. ATLASSERT(bRet);
  544. rbBand.cx = (cxWidth != 0) ? cxWidth : rcTmp.right;
  545. rbBand.cyMinChild = rcTmp.bottom - rcTmp.top;
  546. if(bFullWidthAlways)
  547. {
  548. rbBand.cxMinChild = rbBand.cx;
  549. }
  550. else if(lpstrTitle == NULL)
  551. {
  552. bRet = (BOOL)::SendMessage(hWndBand, TB_GETITEMRECT, 0, (LPARAM)&rcTmp);
  553. ATLASSERT(bRet);
  554. rbBand.cxMinChild = rcTmp.right;
  555. }
  556. else
  557. {
  558. rbBand.cxMinChild = 0;
  559. }
  560. }
  561. else // no buttons, either not a toolbar or really has no buttons
  562. {
  563. bRet = ::GetWindowRect(hWndBand, &rcTmp);
  564. ATLASSERT(bRet);
  565. rbBand.cx = (cxWidth != 0) ? cxWidth : (rcTmp.right - rcTmp.left);
  566. rbBand.cxMinChild = bFullWidthAlways ? rbBand.cx : 0;
  567. rbBand.cyMinChild = rcTmp.bottom - rcTmp.top;
  568. }
  569. #if (_WIN32_IE >= 0x0400)
  570. rbBand.cxIdeal = rbBand.cx;
  571. #endif // (_WIN32_IE >= 0x0400)
  572. // Add the band
  573. LRESULT lRes = ::SendMessage(hWndReBar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand);
  574. if(lRes == 0)
  575. {
  576. ATLTRACE2(atlTraceUI, 0, _T("Failed to add a band to the rebar.\n"));
  577. return FALSE;
  578. }
  579. #if (_WIN32_IE >= 0x0501)
  580. DWORD dwExStyle = (DWORD)::SendMessage(hWndBand, TB_GETEXTENDEDSTYLE, 0, 0L);
  581. ::SendMessage(hWndBand, TB_SETEXTENDEDSTYLE, 0, dwExStyle | TBSTYLE_EX_HIDECLIPPEDBUTTONS);
  582. #endif // (_WIN32_IE >= 0x0501)
  583. return TRUE;
  584. }
  585. BOOL AddSimpleReBarBand(HWND hWndBand, LPCTSTR lpstrTitle = NULL, BOOL bNewRow = FALSE, int cxWidth = 0, BOOL bFullWidthAlways = FALSE)
  586. {
  587. ATLASSERT(::IsWindow(m_hWndToolBar)); // must be an existing rebar
  588. ATLASSERT(::IsWindow(hWndBand)); // must be created
  589. return AddSimpleReBarBandCtrl(m_hWndToolBar, hWndBand, 0, lpstrTitle, bNewRow, cxWidth, bFullWidthAlways);
  590. }
  591. #if (_WIN32_IE >= 0x0400)
  592. void SizeSimpleReBarBands()
  593. {
  594. ATLASSERT(::IsWindow(m_hWndToolBar)); // must be an existing rebar
  595. int nCount = (int)::SendMessage(m_hWndToolBar, RB_GETBANDCOUNT, 0, 0L);
  596. for(int i = 0; i < nCount; i++)
  597. {
  598. REBARBANDINFO rbBand = { RunTimeHelper::SizeOf_REBARBANDINFO() };
  599. rbBand.fMask = RBBIM_SIZE;
  600. BOOL bRet = (BOOL)::SendMessage(m_hWndToolBar, RB_GETBANDINFO, i, (LPARAM)&rbBand);
  601. ATLASSERT(bRet);
  602. RECT rect = { 0, 0, 0, 0 };
  603. ::SendMessage(m_hWndToolBar, RB_GETBANDBORDERS, i, (LPARAM)&rect);
  604. rbBand.cx += rect.left + rect.right;
  605. bRet = (BOOL)::SendMessage(m_hWndToolBar, RB_SETBANDINFO, i, (LPARAM)&rbBand);
  606. ATLASSERT(bRet);
  607. }
  608. }
  609. #endif // (_WIN32_IE >= 0x0400)
  610. #endif // _WIN32_WCE
  611. #ifndef _WIN32_WCE
  612. BOOL CreateSimpleStatusBar(LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR)
  613. #else // CE specific
  614. BOOL CreateSimpleStatusBar(LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, UINT nID = ATL_IDW_STATUS_BAR)
  615. #endif // _WIN32_WCE
  616. {
  617. ATLASSERT(!::IsWindow(m_hWndStatusBar));
  618. m_hWndStatusBar = ::CreateStatusWindow(dwStyle, lpstrText, m_hWnd, nID);
  619. return (m_hWndStatusBar != NULL);
  620. }
  621. #ifndef _WIN32_WCE
  622. 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)
  623. #else // CE specific
  624. BOOL CreateSimpleStatusBar(UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, UINT nID = ATL_IDW_STATUS_BAR)
  625. #endif // _WIN32_WCE
  626. {
  627. const int cchMax = 128; // max text length is 127 for status bars (+1 for null)
  628. TCHAR szText[cchMax] = { 0 };
  629. ::LoadString(ModuleHelper::GetResourceInstance(), nTextID, szText, cchMax);
  630. return CreateSimpleStatusBar(szText, dwStyle, nID);
  631. }
  632. #ifdef _WIN32_WCE
  633. BOOL CreateSimpleCECommandBar(LPTSTR pszMenu = NULL, WORD iButton = 0, DWORD dwFlags = 0, int nCmdBarID = 1)
  634. {
  635. ATLASSERT(m_hWndCECommandBar == NULL);
  636. ATLASSERT(m_hWndToolBar == NULL);
  637. m_hWndCECommandBar = ::CommandBar_Create(ModuleHelper::GetModuleInstance(), m_hWnd, nCmdBarID);
  638. if(m_hWndCECommandBar == NULL)
  639. return FALSE;
  640. m_hWndToolBar = m_hWndCECommandBar;
  641. BOOL bRet = TRUE;
  642. if(pszMenu != NULL)
  643. bRet &= ::CommandBar_InsertMenubarEx(m_hWndCECommandBar, IS_INTRESOURCE(pszMenu) ? ModuleHelper::GetResourceInstance() : NULL, pszMenu, iButton);
  644. bRet &= ::CommandBar_AddAdornments(m_hWndCECommandBar, dwFlags, 0);
  645. return bRet;
  646. }
  647. #if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)
  648. BOOL CreateSimpleCEMenuBar(UINT nToolBarId = ATL_IDW_MENU_BAR, DWORD dwFlags = 0, int nBmpId = 0, int cBmpImages = 0)
  649. {
  650. ATLASSERT(m_hWndCECommandBar == NULL);
  651. SHMENUBARINFO mbi = { 0 };
  652. mbi.cbSize = sizeof(mbi);
  653. mbi.hwndParent = m_hWnd;
  654. mbi.dwFlags = dwFlags;
  655. mbi.nToolBarId = nToolBarId;
  656. mbi.hInstRes = ModuleHelper::GetResourceInstance();
  657. mbi.nBmpId = nBmpId;
  658. mbi.cBmpImages = cBmpImages;
  659. mbi.hwndMB = NULL; // This gets set by SHCreateMenuBar
  660. BOOL bRet = ::SHCreateMenuBar(&mbi);
  661. if(bRet != FALSE)
  662. {
  663. m_hWndCECommandBar = mbi.hwndMB;
  664. SizeToMenuBar();
  665. }
  666. return bRet;
  667. }
  668. void SizeToMenuBar() // for menu bar only
  669. {
  670. ATLASSERT(::IsWindow(m_hWnd));
  671. ATLASSERT(::IsWindow(m_hWndCECommandBar));
  672. RECT rect = { 0 };
  673. GetWindowRect(&rect);
  674. RECT rectMB = { 0 };
  675. ::GetWindowRect(m_hWndCECommandBar, &rectMB);
  676. int cy = ::IsWindowVisible(m_hWndCECommandBar) ? rectMB.top - rect.top : rectMB.bottom - rect.top;
  677. SetWindowPos(NULL, 0, 0, rect.right - rect.left, cy, SWP_NOZORDER | SWP_NOMOVE);
  678. }
  679. #endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)
  680. #endif // _WIN32_WCE
  681. void UpdateLayout(BOOL bResizeBars = TRUE)
  682. {
  683. RECT rect = { 0 };
  684. GetClientRect(&rect);
  685. // position bars and offset their dimensions
  686. UpdateBarsPosition(rect, bResizeBars);
  687. // resize client window
  688. if(m_hWndClient != NULL)
  689. ::SetWindowPos(m_hWndClient, NULL, rect.left, rect.top,
  690. rect.right - rect.left, rect.bottom - rect.top,
  691. SWP_NOZORDER | SWP_NOACTIVATE);
  692. }
  693. void UpdateBarsPosition(RECT& rect, BOOL bResizeBars = TRUE)
  694. {
  695. // resize toolbar
  696. if(m_hWndToolBar != NULL && ((DWORD)::GetWindowLong(m_hWndToolBar, GWL_STYLE) & WS_VISIBLE))
  697. {
  698. if(bResizeBars != FALSE)
  699. {
  700. ::SendMessage(m_hWndToolBar, WM_SIZE, 0, 0);
  701. ::InvalidateRect(m_hWndToolBar, NULL, TRUE);
  702. }
  703. RECT rectTB = { 0 };
  704. ::GetWindowRect(m_hWndToolBar, &rectTB);
  705. rect.top += rectTB.bottom - rectTB.top;
  706. }
  707. // resize status bar
  708. if(m_hWndStatusBar != NULL && ((DWORD)::GetWindowLong(m_hWndStatusBar, GWL_STYLE) & WS_VISIBLE))
  709. {
  710. if(bResizeBars != FALSE)
  711. ::SendMessage(m_hWndStatusBar, WM_SIZE, 0, 0);
  712. RECT rectSB = { 0 };
  713. ::GetWindowRect(m_hWndStatusBar, &rectSB);
  714. rect.bottom -= rectSB.bottom - rectSB.top;
  715. }
  716. }
  717. BOOL PreTranslateMessage(MSG* pMsg)
  718. {
  719. if(m_hAccel != NULL && ::TranslateAccelerator(m_hWnd, m_hAccel, pMsg))
  720. return TRUE;
  721. return FALSE;
  722. }
  723. BEGIN_MSG_MAP(CFrameWindowImplBase)
  724. MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
  725. #ifndef _WIN32_WCE
  726. MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
  727. #endif // !_WIN32_WCE
  728. MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
  729. MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
  730. #ifndef _WIN32_WCE
  731. NOTIFY_CODE_HANDLER(TTN_GETDISPINFOA, OnToolTipTextA)
  732. NOTIFY_CODE_HANDLER(TTN_GETDISPINFOW, OnToolTipTextW)
  733. #endif // !_WIN32_WCE
  734. END_MSG_MAP()
  735. LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  736. {
  737. if(m_hWndClient != NULL) // view will paint itself instead
  738. return 1;
  739. bHandled = FALSE;
  740. return 0;
  741. }
  742. #ifndef _WIN32_WCE
  743. LRESULT OnMenuSelect(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  744. {
  745. bHandled = FALSE;
  746. if(m_hWndStatusBar == NULL)
  747. return 1;
  748. WORD wFlags = HIWORD(wParam);
  749. if(wFlags == 0xFFFF && lParam == NULL) // menu closing
  750. {
  751. ::SendMessage(m_hWndStatusBar, SB_SIMPLE, FALSE, 0L);
  752. }
  753. else
  754. {
  755. const int cchBuff = 256;
  756. TCHAR szBuff[cchBuff] = { 0 };
  757. if(!(wFlags & MF_POPUP))
  758. {
  759. WORD wID = LOWORD(wParam);
  760. // check for special cases
  761. if(wID >= 0xF000 && wID < 0xF1F0) // system menu IDs
  762. wID = (WORD)(((wID - 0xF000) >> 4) + ATL_IDS_SCFIRST);
  763. else if(wID >= ID_FILE_MRU_FIRST && wID <= ID_FILE_MRU_LAST) // MRU items
  764. wID = ATL_IDS_MRU_FILE;
  765. else if(wID >= ATL_IDM_FIRST_MDICHILD && wID <= ATL_IDM_LAST_MDICHILD) // MDI child windows
  766. wID = ATL_IDS_MDICHILD;
  767. int nRet = ::LoadString(ModuleHelper::GetResourceInstance(), wID, szBuff, cchBuff);
  768. for(int i = 0; i < nRet; i++)
  769. {
  770. if(szBuff[i] == _T('\n'))
  771. {
  772. szBuff[i] = 0;
  773. break;
  774. }
  775. }
  776. }
  777. ::SendMessage(m_hWndStatusBar, SB_SIMPLE, TRUE, 0L);
  778. ::SendMessage(m_hWndStatusBar, SB_SETTEXT, (255 | SBT_NOBORDERS), (LPARAM)szBuff);
  779. }
  780. return 1;
  781. }
  782. #endif // !_WIN32_WCE
  783. LRESULT OnSetFocus(UINT, WPARAM, LPARAM, BOOL& bHandled)
  784. {
  785. if(m_hWndClient != NULL)
  786. ::SetFocus(m_hWndClient);
  787. bHandled = FALSE;
  788. return 1;
  789. }
  790. LRESULT OnDestroy(UINT, WPARAM, LPARAM, BOOL& bHandled)
  791. {
  792. if((GetStyle() & (WS_CHILD | WS_POPUP)) == 0)
  793. ::PostQuitMessage(1);
  794. bHandled = FALSE;
  795. return 1;
  796. }
  797. #ifndef _WIN32_WCE
  798. LRESULT OnToolTipTextA(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/)
  799. {
  800. LPNMTTDISPINFOA pDispInfo = (LPNMTTDISPINFOA)pnmh;
  801. pDispInfo->szText[0] = 0;
  802. if((idCtrl != 0) && !(pDispInfo->uFlags & TTF_IDISHWND))
  803. {
  804. const int cchBuff = 256;
  805. char szBuff[cchBuff] = { 0 };
  806. int nRet = ::LoadStringA(ModuleHelper::GetResourceInstance(), idCtrl, szBuff, cchBuff);
  807. for(int i = 0; i < nRet; i++)
  808. {
  809. if(szBuff[i] == '\n')
  810. {
  811. SecureHelper::strncpyA_x(pDispInfo->szText, _countof(pDispInfo->szText), &szBuff[i + 1], _TRUNCATE);
  812. break;
  813. }
  814. }
  815. #if (_WIN32_IE >= 0x0300)
  816. if(nRet > 0) // string was loaded, save it
  817. pDispInfo->uFlags |= TTF_DI_SETITEM;
  818. #endif // (_WIN32_IE >= 0x0300)
  819. }
  820. return 0;
  821. }
  822. LRESULT OnToolTipTextW(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/)
  823. {
  824. LPNMTTDISPINFOW pDispInfo = (LPNMTTDISPINFOW)pnmh;
  825. pDispInfo->szText[0] = 0;
  826. if((idCtrl != 0) && !(pDispInfo->uFlags & TTF_IDISHWND))
  827. {
  828. const int cchBuff = 256;
  829. wchar_t szBuff[cchBuff] = { 0 };
  830. int nRet = ::LoadStringW(ModuleHelper::GetResourceInstance(), idCtrl, szBuff, cchBuff);
  831. for(int i = 0; i < nRet; i++)
  832. {
  833. if(szBuff[i] == L'\n')
  834. {
  835. SecureHelper::strncpyW_x(pDispInfo->szText, _countof(pDispInfo->szText), &szBuff[i + 1], _TRUNCATE);
  836. break;
  837. }
  838. }
  839. #if (_WIN32_IE >= 0x0300)
  840. if(nRet > 0) // string was loaded, save it
  841. pDispInfo->uFlags |= TTF_DI_SETITEM;
  842. #endif // (_WIN32_IE >= 0x0300)
  843. }
  844. return 0;
  845. }
  846. #endif // !_WIN32_WCE
  847. // Implementation - chevron menu support
  848. #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
  849. bool PrepareChevronMenu(_ChevronMenuInfo& cmi)
  850. {
  851. // get rebar and toolbar
  852. REBARBANDINFO rbbi = { RunTimeHelper::SizeOf_REBARBANDINFO() };
  853. rbbi.fMask = RBBIM_CHILD;
  854. BOOL bRet = (BOOL)::SendMessage(cmi.lpnm->hdr.hwndFrom, RB_GETBANDINFO, cmi.lpnm->uBand, (LPARAM)&rbbi);
  855. ATLASSERT(bRet);
  856. // assume the band is a toolbar
  857. ATL::CWindow wnd = rbbi.hwndChild;
  858. int nCount = (int)wnd.SendMessage(TB_BUTTONCOUNT);
  859. if(nCount <= 0) // probably not a toolbar
  860. return false;
  861. // check if it's a command bar
  862. CMenuHandle menuCmdBar = (HMENU)wnd.SendMessage(CBRM_GETMENU);
  863. cmi.bCmdBar = (menuCmdBar.m_hMenu != NULL);
  864. // build a menu from hidden items
  865. CMenuHandle menu;
  866. bRet = menu.CreatePopupMenu();
  867. ATLASSERT(bRet);
  868. RECT rcClient = { 0 };
  869. bRet = wnd.GetClientRect(&rcClient);
  870. ATLASSERT(bRet);
  871. for(int i = 0; i < nCount; i++)
  872. {
  873. TBBUTTON tbb = { 0 };
  874. bRet = (BOOL)wnd.SendMessage(TB_GETBUTTON, i, (LPARAM)&tbb);
  875. ATLASSERT(bRet);
  876. // skip hidden buttons
  877. if((tbb.fsState & TBSTATE_HIDDEN) != 0)
  878. continue;
  879. RECT rcButton = { 0 };
  880. bRet = (BOOL)wnd.SendMessage(TB_GETITEMRECT, i, (LPARAM)&rcButton);
  881. ATLASSERT(bRet);
  882. bool bEnabled = ((tbb.fsState & TBSTATE_ENABLED) != 0);
  883. if(rcButton.right > rcClient.right)
  884. {
  885. if(tbb.fsStyle & BTNS_SEP)
  886. {
  887. if(menu.GetMenuItemCount() > 0)
  888. menu.AppendMenu(MF_SEPARATOR);
  889. }
  890. else if(cmi.bCmdBar)
  891. {
  892. const int cchBuff = 200;
  893. TCHAR szBuff[cchBuff] = { 0 };
  894. CMenuItemInfo mii;
  895. mii.fMask = MIIM_TYPE | MIIM_SUBMENU;
  896. mii.dwTypeData = szBuff;
  897. mii.cch = cchBuff;
  898. bRet = menuCmdBar.GetMenuItemInfo(i, TRUE, &mii);
  899. ATLASSERT(bRet);
  900. // Note: CmdBar currently supports only drop-down items
  901. ATLASSERT(::IsMenu(mii.hSubMenu));
  902. bRet = menu.AppendMenu(MF_STRING | MF_POPUP | (bEnabled ? MF_ENABLED : MF_GRAYED), (UINT_PTR)mii.hSubMenu, mii.dwTypeData);
  903. ATLASSERT(bRet);
  904. }
  905. else
  906. {
  907. // get button's text
  908. const int cchBuff = 200;
  909. TCHAR szBuff[cchBuff] = { 0 };
  910. LPTSTR lpstrText = szBuff;
  911. TBBUTTONINFO tbbi = { 0 };
  912. tbbi.cbSize = sizeof(TBBUTTONINFO);
  913. tbbi.dwMask = TBIF_TEXT;
  914. tbbi.pszText = szBuff;
  915. tbbi.cchText = cchBuff;
  916. if(wnd.SendMessage(TB_GETBUTTONINFO, tbb.idCommand, (LPARAM)&tbbi) == -1 || lstrlen(szBuff) == 0)
  917. {
  918. // no text for this button, try a resource string
  919. lpstrText = _T("");
  920. int nRet = ::LoadString(ModuleHelper::GetResourceInstance(), tbb.idCommand, szBuff, cchBuff);
  921. for(int n = 0; n < nRet; n++)
  922. {
  923. if(szBuff[n] == _T('\n'))
  924. {
  925. lpstrText = &szBuff[n + 1];
  926. break;
  927. }
  928. }
  929. }
  930. bRet = menu.AppendMenu(MF_STRING | (bEnabled ? MF_ENABLED : MF_GRAYED), tbb.idCommand, lpstrText);
  931. ATLASSERT(bRet);
  932. }
  933. }
  934. }
  935. if(menu.GetMenuItemCount() == 0) // no hidden buttons after all
  936. {
  937. menu.DestroyMenu();
  938. ::MessageBeep((UINT)-1);
  939. return false;
  940. }
  941. cmi.hMenu = menu;
  942. return true;
  943. }
  944. void DisplayChevronMenu(_ChevronMenuInfo& cmi)
  945. {
  946. #ifndef TPM_VERPOSANIMATION
  947. const UINT TPM_VERPOSANIMATION = 0x1000L; // Menu animation flag
  948. #endif
  949. // convert chevron rect to screen coordinates
  950. ATL::CWindow wndFrom = cmi.lpnm->hdr.hwndFrom;
  951. POINT pt = { cmi.lpnm->rc.left, cmi.lpnm->rc.bottom };
  952. wndFrom.MapWindowPoints(NULL, &pt, 1);
  953. RECT rc = cmi.lpnm->rc;
  954. wndFrom.MapWindowPoints(NULL, &rc);
  955. // set up flags and rect
  956. UINT uMenuFlags = TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | (!AtlIsOldWindows() ? TPM_VERPOSANIMATION : 0);
  957. TPMPARAMS TPMParams = { 0 };
  958. TPMParams.cbSize = sizeof(TPMPARAMS);
  959. TPMParams.rcExclude = rc;
  960. // check if this window has a command bar
  961. HWND hWndCmdBar = (HWND)::SendMessage(m_hWnd, CBRM_GETCMDBAR, 0, 0L);
  962. if(::IsWindow(hWndCmdBar))
  963. {
  964. CBRPOPUPMENU CBRPopupMenu = { sizeof(CBRPOPUPMENU), cmi.hMenu, uMenuFlags, pt.x, pt.y, &TPMParams };
  965. ::SendMessage(hWndCmdBar, CBRM_TRACKPOPUPMENU, 0, (LPARAM)&CBRPopupMenu);
  966. }
  967. else
  968. {
  969. CMenuHandle menu = cmi.hMenu;
  970. menu.TrackPopupMenuEx(uMenuFlags, pt.x, pt.y, m_hWnd, &TPMParams);
  971. }
  972. }
  973. void CleanupChevronMenu(_ChevronMenuInfo& cmi)
  974. {
  975. CMenuHandle menu = cmi.hMenu;
  976. // if menu is from a command bar, detach submenus so they are not destroyed
  977. if(cmi.bCmdBar)
  978. {
  979. for(int i = menu.GetMenuItemCount() - 1; i >=0; i--)
  980. menu.RemoveMenu(i, MF_BYPOSITION);
  981. }
  982. // destroy menu
  983. menu.DestroyMenu();
  984. // convert chevron rect to screen coordinates
  985. ATL::CWindow wndFrom = cmi.lpnm->hdr.hwndFrom;
  986. RECT rc = cmi.lpnm->rc;
  987. wndFrom.MapWindowPoints(NULL, &rc);
  988. // eat next message if click is on the same button
  989. MSG msg = { 0 };
  990. if(::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rc, msg.pt))
  991. ::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE);
  992. }
  993. #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
  994. };
  995. template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CFrameWinTraits>
  996. class ATL_NO_VTABLE CFrameWindowImpl : public CFrameWindowImplBase< TBase, TWinTraits >
  997. {
  998. public:
  999. HWND Create(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
  1000. DWORD dwStyle = 0, DWORD dwExStyle = 0,
  1001. HMENU hMenu = NULL, LPVOID lpCreateParam = NULL)
  1002. {
  1003. ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);
  1004. dwStyle = T::GetWndStyle(dwStyle);
  1005. dwExStyle = T::GetWndExStyle(dwExStyle);
  1006. if(rect.m_lpRect == NULL)
  1007. rect.m_lpRect = &TBase::rcDefault;
  1008. return CFrameWindowImplBase< TBase, TWinTraits >::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, hMenu, atom, lpCreateParam);
  1009. }
  1010. HWND CreateEx(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL)
  1011. {
  1012. const int cchName = 256;
  1013. TCHAR szWindowName[cchName] = { 0 };
  1014. #ifndef _WIN32_WCE
  1015. ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName);
  1016. HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
  1017. #else // CE specific
  1018. ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName);
  1019. // This always needs to be NULL for Windows CE.
  1020. // Frame Window menus have to go onto the CommandBar.
  1021. // Use CreateSimpleCECommandBar
  1022. HMENU hMenu = NULL;
  1023. #endif // _WIN32_WCE
  1024. T* pT = static_cast<T*>(this);
  1025. HWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam);
  1026. if(hWnd != NULL)
  1027. m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
  1028. return hWnd;
  1029. }
  1030. BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
  1031. {
  1032. if(nResourceID == 0)
  1033. nResourceID = T::GetWndClassInfo().m_uCommonResourceID;
  1034. #ifndef _WIN32_WCE
  1035. ATLASSERT(!::IsWindow(m_hWndToolBar));
  1036. m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID);
  1037. return (m_hWndToolBar != NULL);
  1038. #else // CE specific
  1039. HWND hWnd= T::CreateSimpleToolBarCtrl(m_hWndCECommandBar, nResourceID, TRUE, dwStyle, nID);
  1040. return (hWnd != NULL);
  1041. #endif // _WIN32_WCE
  1042. }
  1043. #ifdef _WIN32_WCE
  1044. // CE specific variant that returns the handle of the toolbar
  1045. HWND CreateSimpleCEToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
  1046. {
  1047. if(nResourceID == 0)
  1048. nResourceID = T::GetWndClassInfo().m_uCommonResourceID;
  1049. return T::CreateSimpleToolBarCtrl(m_hWndCECommandBar, nResourceID, TRUE, dwStyle, nID);
  1050. }
  1051. #endif // _WIN32_WCE
  1052. // message map and handlers
  1053. typedef CFrameWindowImplBase< TBase, TWinTraits > _baseClass;
  1054. BEGIN_MSG_MAP(CFrameWindowImpl)
  1055. MESSAGE_HANDLER(WM_SIZE, OnSize)
  1056. #ifndef _ATL_NO_REBAR_SUPPORT
  1057. #if (_WIN32_IE >= 0x0400)
  1058. NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize)
  1059. #endif // (_WIN32_IE >= 0x0400)
  1060. #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
  1061. NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed)
  1062. #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
  1063. #endif // !_ATL_NO_REBAR_SUPPORT
  1064. CHAIN_MSG_MAP(_baseClass)
  1065. END_MSG_MAP()
  1066. LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
  1067. {
  1068. if(wParam != SIZE_MINIMIZED)
  1069. {
  1070. T* pT = static_cast<T*>(this);
  1071. pT->UpdateLayout();
  1072. }
  1073. bHandled = FALSE;
  1074. return 1;
  1075. }
  1076. #ifndef _ATL_NO_REBAR_SUPPORT
  1077. #if (_WIN32_IE >= 0x0400)
  1078. LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
  1079. {
  1080. T* pT = static_cast<T*>(this);
  1081. pT->UpdateLayout(FALSE);
  1082. return 0;
  1083. }
  1084. #endif // (_WIN32_IE >= 0x0400)
  1085. #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
  1086. LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
  1087. {
  1088. T* pT = static_cast<T*>(this);
  1089. _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false };
  1090. if(!pT->PrepareChevronMenu(cmi))
  1091. {
  1092. bHandled = FALSE;
  1093. return 1;
  1094. }
  1095. // display a popup menu with hidden items
  1096. pT->DisplayChevronMenu(cmi);
  1097. // cleanup
  1098. pT->CleanupChevronMenu(cmi);
  1099. return 0;
  1100. }
  1101. #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
  1102. #endif // !_ATL_NO_REBAR_SUPPORT
  1103. };
  1104. ///////////////////////////////////////////////////////////////////////////////
  1105. // AtlCreateSimpleToolBar - helper for creating simple toolbars
  1106. #ifndef _WIN32_WCE
  1107. inline HWND AtlCreateSimpleToolBar(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE,
  1108. DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
  1109. {
  1110. return CFrameWindowImplBase<>::CreateSimpleToolBarCtrl(hWndParent, nResourceID, bInitialSeparator, dwStyle, nID);
  1111. }
  1112. #endif // !_WIN32_WCE
  1113. ///////////////////////////////////////////////////////////////////////////////
  1114. // CMDIWindow
  1115. #ifndef _WIN32_WCE
  1116. #ifndef _WTL_MDIWINDOWMENU_TEXT
  1117. #define _WTL_MDIWINDOWMENU_TEXT _T("&Window")
  1118. #endif
  1119. class CMDIWindow : public ATL::CWindow
  1120. {
  1121. public:
  1122. // Data members
  1123. HWND m_hWndMDIClient;
  1124. HMENU m_hMenu;
  1125. // Constructors
  1126. CMDIWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd), m_hWndMDIClient(NULL), m_hMenu(NULL)
  1127. { }
  1128. CMDIWindow& operator =(HWND hWnd)
  1129. {
  1130. m_hWnd = hWnd;
  1131. return *this;
  1132. }
  1133. // Operations
  1134. HWND MDIGetActive(BOOL* lpbMaximized = NULL)
  1135. {
  1136. ATLASSERT(::IsWindow(m_hWndMDIClient));
  1137. return (HWND)::SendMessage(m_hWndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)lpbMaximized);
  1138. }
  1139. void MDIActivate(HWND hWndChildToActivate)
  1140. {
  1141. ATLASSERT(::IsWindow(m_hWndMDIClient));
  1142. ATLASSERT(::IsWindow(hWndChildToActivate));
  1143. ::SendMessage(m_hWndMDIClient, WM_MDIACTIVATE, (WPARAM)hWndChildToActivate, 0);
  1144. }
  1145. void MDINext(HWND hWndChild, BOOL bPrevious = FALSE)
  1146. {
  1147. ATLASSERT(::IsWindow(m_hWndMDIClient));
  1148. ATLASSERT(hWndChild == NULL || ::IsWindow(hWndChild));
  1149. ::SendMessage(m_hWndMDIClient, WM_MDINEXT, (WPARAM)hWndChild, (LPARAM)bPrevious);
  1150. }
  1151. void MDIMaximize(HWND hWndChildToMaximize)
  1152. {
  1153. ATLASSERT(::IsWindow(m_hWndMDIClient));
  1154. ATLASSERT(::IsWindow(hWndChildToMaximize));
  1155. ::SendMessage(m_hWndMDIClient, WM_MDIMAXIMIZE, (WPARAM)hWndChildToMaximize, 0);
  1156. }
  1157. void MDIRestore(HWND hWndChildToRestore)
  1158. {
  1159. ATLASSERT(::IsWindow(m_hWndMDIClient));
  1160. ATLASSERT(::IsWindow(hWndChildToRestore));
  1161. ::SendMessage(m_hWndMDIClient, WM_MDIRESTORE, (WPARAM)hWndChildToRestore, 0);
  1162. }
  1163. void MDIDestroy(HWND hWndChildToDestroy)
  1164. {
  1165. ATLASSERT(::IsWindow(m_hWndMDIClient));
  1166. ATLASSERT(::IsWindow(hWndChildToDestroy));
  1167. ::SendMessage(m_hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChildToDestroy, 0);
  1168. }
  1169. BOOL MDICascade(UINT uFlags = 0)
  1170. {
  1171. ATLASSERT(::IsWindow(m_hWndMDIClient));
  1172. return (BOOL)::SendMessage(m_hWndMDIClient, WM_MDICASCADE, (WPARAM)uFlags, 0);
  1173. }
  1174. BOOL MDITile(UINT uFlags = MDITILE_HORIZONTAL)
  1175. {
  1176. ATLASSERT(::IsWindow(m_hWndMDIClient));
  1177. return (BOOL)::SendMessage(m_hWndMDIClient, WM_MDITILE, (WPARAM)uFlags, 0);
  1178. }
  1179. void MDIIconArrange()
  1180. {
  1181. ATLASSERT(::IsWindow(m_hWndMDIClient));
  1182. ::SendMessage(m_hWndMDIClient, WM_MDIICONARRANGE, 0, 0);
  1183. }
  1184. HMENU MDISetMenu(HMENU hMenuFrame, HMENU hMenuWindow)
  1185. {
  1186. ATLASSERT(::IsWindow(m_hWndMDIClient));
  1187. return (HMENU)::SendMessage(m_hWndMDIClient, WM_MDISETMENU, (WPARAM)hMenuFrame, (LPARAM)hMenuWindow);
  1188. }
  1189. HMENU MDIRefreshMenu()
  1190. {
  1191. ATLASSERT(::IsWindow(m_hWndMDIClient));
  1192. return (HMENU)::SendMessage(m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0);
  1193. }
  1194. // Additional operations
  1195. static HMENU GetStandardWindowMenu(HMENU hMenu)
  1196. {
  1197. int nCount = ::GetMenuItemCount(hMenu);
  1198. if(nCount == -1)
  1199. return NULL;
  1200. int nLen = ::GetMenuString(hMenu, nCount - 2, NULL, 0, MF_BYPOSITION);
  1201. if(nLen == 0)
  1202. return NULL;
  1203. CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
  1204. LPTSTR lpszText = buff.Allocate(nLen + 1);
  1205. if(lpszText == NULL)
  1206. return NULL;
  1207. if(::GetMenuString(hMenu, nCount - 2, lpszText, nLen + 1, MF_BYPOSITION) != nLen)
  1208. return NULL;
  1209. if(lstrcmp(lpszText, _WTL_MDIWINDOWMENU_TEXT) != 0)
  1210. return NULL;
  1211. return ::GetSubMenu(hMenu, nCount - 2);
  1212. }
  1213. void SetMDIFrameMenu()
  1214. {
  1215. HMENU hWindowMenu = GetStandardWindowMenu(m_hMenu);
  1216. MDISetMenu(m_hMenu, hWindowMenu);
  1217. MDIRefreshMenu();
  1218. ::DrawMenuBar(GetMDIFrame());
  1219. }
  1220. HWND GetMDIFrame() const
  1221. {
  1222. return ::GetParent(m_hWndMDIClient);
  1223. }
  1224. };
  1225. #endif // !_WIN32_WCE
  1226. ///////////////////////////////////////////////////////////////////////////////
  1227. // CMDIFrameWindowImpl
  1228. #ifndef _WIN32_WCE
  1229. // MDI child command chaining macro (only for MDI frame windows)
  1230. #define CHAIN_MDI_CHILD_COMMANDS() \
  1231. if(uMsg == WM_COMMAND) \
  1232. { \
  1233. HWND hWndChild = MDIGetActive(); \
  1234. if(hWndChild != NULL) \
  1235. ::SendMessage(hWndChild, uMsg, wParam, lParam); \
  1236. }
  1237. template <class T, class TBase = CMDIWindow, class TWinTraits = ATL::CFrameWinTraits>
  1238. class ATL_NO_VTABLE CMDIFrameWindowImpl : public CFrameWindowImplBase<TBase, TWinTraits >
  1239. {
  1240. public:
  1241. HWND Create(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
  1242. DWORD dwStyle = 0, DWORD dwExStyle = 0,
  1243. HMENU hMenu = NULL, LPVOID lpCreateParam = NULL)
  1244. {
  1245. m_hMenu = hMenu;
  1246. ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);
  1247. dwStyle = T::GetWndStyle(dwStyle);
  1248. dwExStyle = T::GetWndExStyle(dwExStyle);
  1249. if(rect.m_lpRect == NULL)
  1250. rect.m_lpRect = &TBase::rcDefault;
  1251. return CFrameWindowImplBase<TBase, TWinTraits >::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, hMenu, atom, lpCreateParam);
  1252. }
  1253. HWND CreateEx(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL)
  1254. {
  1255. const int cchName = 256;
  1256. TCHAR szWindowName[cchName] = { 0 };
  1257. ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName);
  1258. HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
  1259. T* pT = static_cast<T*>(this);
  1260. HWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam);
  1261. if(hWnd != NULL)
  1262. m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
  1263. return hWnd;
  1264. }
  1265. BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
  1266. {
  1267. ATLASSERT(!::IsWindow(m_hWndToolBar));
  1268. if(nResourceID == 0)
  1269. nResourceID = T::GetWndClassInfo().m_uCommonResourceID;
  1270. m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID);
  1271. return (m_hWndToolBar != NULL);
  1272. }
  1273. virtual WNDPROC GetWindowProc()
  1274. {
  1275. return MDIFrameWindowProc;
  1276. }
  1277. static LRESULT CALLBACK MDIFrameWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1278. {
  1279. CMDIFrameWindowImpl< T, TBase, TWinTraits >* pThis = (CMDIFrameWindowImpl< T, TBase, TWinTraits >*)hWnd;
  1280. // set a ptr to this message and save the old value
  1281. #if (_ATL_VER >= 0x0700)
  1282. ATL::_ATL_MSG msg(pThis->m_hWnd, uMsg, wParam, lParam);
  1283. const ATL::_ATL_MSG* pOldMsg = pThis->m_pCurrentMsg;
  1284. #else // !(_ATL_VER >= 0x0700)
  1285. MSG msg = { pThis->m_hWnd, uMsg, wParam, lParam, 0, { 0, 0 } };
  1286. const MSG* pOldMsg = pThis->m_pCurrentMsg;
  1287. #endif // !(_ATL_VER >= 0x0700)
  1288. pThis->m_pCurrentMsg = &msg;
  1289. // pass to the message map to process
  1290. LRESULT lRes = 0;
  1291. BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0);
  1292. // restore saved value for the current message
  1293. ATLASSERT(pThis->m_pCurrentMsg == &msg);
  1294. pThis->m_pCurrentMsg = pOldMsg;
  1295. // do the default processing if message was not handled
  1296. if(!bRet)
  1297. {
  1298. if(uMsg != WM_NCDESTROY)
  1299. lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
  1300. else
  1301. {
  1302. // unsubclass, if needed
  1303. LONG_PTR pfnWndProc = ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC);
  1304. lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
  1305. if(pThis->m_pfnSuperWindowProc != ::DefWindowProc && ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC) == pfnWndProc)
  1306. ::SetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC, (LONG_PTR)pThis->m_pfnSuperWindowProc);
  1307. #if (_ATL_VER >= 0x0700)
  1308. // mark window as destryed
  1309. pThis->m_dwState |= WINSTATE_DESTROYED;
  1310. #else // !(_ATL_VER >= 0x0700)
  1311. // clear out window handle
  1312. HWND hWnd = pThis->m_hWnd;
  1313. pThis->m_hWnd = NULL;
  1314. // clean up after window is destroyed
  1315. pThis->OnFinalMessage(hWnd);
  1316. #endif // !(_ATL_VER >= 0x0700)
  1317. }
  1318. }
  1319. #if (_ATL_VER >= 0x0700)
  1320. if(pThis->m_dwState & WINSTATE_DESTROYED && pThis->m_pCurrentMsg == NULL)
  1321. {
  1322. // clear out window handle
  1323. HWND hWnd = pThis->m_hWnd;
  1324. pThis->m_hWnd = NULL;
  1325. pThis->m_dwState &= ~WINSTATE_DESTROYED;
  1326. // clean up after window is destroyed
  1327. pThis->OnFinalMessage(hWnd);
  1328. }
  1329. #endif // (_ATL_VER >= 0x0700)
  1330. return lRes;
  1331. }
  1332. // Overriden to call DefWindowProc which uses DefFrameProc
  1333. LRESULT DefWindowProc()
  1334. {
  1335. const MSG* pMsg = m_pCurrentMsg;
  1336. LRESULT lRes = 0;
  1337. if (pMsg != NULL)
  1338. lRes = DefWindowProc(pMsg->message, pMsg->wParam, pMsg->lParam);
  1339. return lRes;
  1340. }
  1341. LRESULT DefWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
  1342. {
  1343. return ::DefFrameProc(m_hWnd, m_hWndMDIClient, uMsg, wParam, lParam);
  1344. }
  1345. BOOL PreTranslateMessage(MSG* pMsg)
  1346. {
  1347. if(CFrameWindowImplBase<TBase, TWinTraits>::PreTranslateMessage(pMsg))
  1348. return TRUE;
  1349. return ::TranslateMDISysAccel(m_hWndMDIClient, pMsg);
  1350. }
  1351. HWND CreateMDIClient(HMENU hWindowMenu = NULL, UINT nID = ATL_IDW_CLIENT, UINT nFirstChildID = ATL_IDM_FIRST_MDICHILD)
  1352. {
  1353. DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | MDIS_ALLCHILDSTYLES;
  1354. DWORD dwExStyle = WS_EX_CLIENTEDGE;
  1355. CLIENTCREATESTRUCT ccs = { 0 };
  1356. ccs.hWindowMenu = hWindowMenu;
  1357. ccs.idFirstChild = nFirstChildID;
  1358. if((GetStyle() & (WS_HSCROLL | WS_VSCROLL)) != 0)
  1359. {
  1360. // parent MDI frame's scroll styles move to the MDICLIENT
  1361. dwStyle |= (GetStyle() & (WS_HSCROLL | WS_VSCROLL));
  1362. // fast way to turn off the scrollbar bits (without a resize)
  1363. ModifyStyle(WS_HSCROLL | WS_VSCROLL, 0, SWP_NOREDRAW | SWP_FRAMECHANGED);
  1364. }
  1365. // Create MDICLIENT window
  1366. m_hWndClient = ::CreateWindowEx(dwExStyle, _T("MDIClient"), NULL,
  1367. dwStyle, 0, 0, 1, 1, m_hWnd, (HMENU)LongToHandle(nID),
  1368. ModuleHelper::GetModuleInstance(), (LPVOID)&ccs);
  1369. if (m_hWndClient == NULL)
  1370. {
  1371. ATLTRACE2(atlTraceUI, 0, _T("MDI Frame failed to create MDICLIENT.\n"));
  1372. return NULL;
  1373. }
  1374. // Move it to the top of z-order
  1375. ::BringWindowToTop(m_hWndClient);
  1376. // set as MDI client window
  1377. m_hWndMDIClient = m_hWndClient;
  1378. // update to proper size
  1379. T* pT = static_cast<T*>(this);
  1380. pT->UpdateLayout();
  1381. return m_hWndClient;
  1382. }
  1383. typedef CFrameWindowImplBase<TBase, TWinTraits > _baseClass;
  1384. BEGIN_MSG_MAP(CMDIFrameWindowImpl)
  1385. MESSAGE_HANDLER(WM_SIZE, OnSize)
  1386. MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
  1387. MESSAGE_HANDLER(WM_MDISETMENU, OnMDISetMenu)
  1388. #ifndef _ATL_NO_REBAR_SUPPORT
  1389. #if (_WIN32_IE >= 0x0400)
  1390. NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize)
  1391. #endif // (_WIN32_IE >= 0x0400)
  1392. #if (_WIN32_IE >= 0x0500)
  1393. NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed)
  1394. #endif // (_WIN32_IE >= 0x0500)
  1395. #endif // !_ATL_NO_REBAR_SUPPORT
  1396. CHAIN_MSG_MAP(_baseClass)
  1397. END_MSG_MAP()
  1398. LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1399. {
  1400. if(wParam != SIZE_MINIMIZED)
  1401. {
  1402. T* pT = static_cast<T*>(this);
  1403. pT->UpdateLayout();
  1404. }
  1405. // message must be handled, otherwise DefFrameProc would resize the client again
  1406. return 0;
  1407. }
  1408. LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  1409. {
  1410. // don't allow CFrameWindowImplBase to handle this one
  1411. return DefWindowProc(uMsg, wParam, lParam);
  1412. }
  1413. LRESULT OnMDISetMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1414. {
  1415. SetMDIFrameMenu();
  1416. return 0;
  1417. }
  1418. #ifndef _ATL_NO_REBAR_SUPPORT
  1419. #if (_WIN32_IE >= 0x0400)
  1420. LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
  1421. {
  1422. T* pT = static_cast<T*>(this);
  1423. pT->UpdateLayout(FALSE);
  1424. return 0;
  1425. }
  1426. #endif // (_WIN32_IE >= 0x0400)
  1427. #if (_WIN32_IE >= 0x0500)
  1428. LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
  1429. {
  1430. T* pT = static_cast<T*>(this);
  1431. _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false };
  1432. if(!pT->PrepareChevronMenu(cmi))
  1433. {
  1434. bHandled = FALSE;
  1435. return 1;
  1436. }
  1437. // display a popup menu with hidden items
  1438. pT->DisplayChevronMenu(cmi);
  1439. // cleanup
  1440. pT->CleanupChevronMenu(cmi);
  1441. return 0;
  1442. }
  1443. #endif // (_WIN32_IE >= 0x0500)
  1444. #endif // !_ATL_NO_REBAR_SUPPORT
  1445. };
  1446. #endif // !_WIN32_WCE
  1447. ///////////////////////////////////////////////////////////////////////////////
  1448. // CMDIChildWindowImpl
  1449. #ifndef _WIN32_WCE
  1450. template <class T, class TBase = CMDIWindow, class TWinTraits = ATL::CMDIChildWinTraits>
  1451. class ATL_NO_VTABLE CMDIChildWindowImpl : public CFrameWindowImplBase<TBase, TWinTraits >
  1452. {
  1453. public:
  1454. HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
  1455. DWORD dwStyle = 0, DWORD dwExStyle = 0,
  1456. UINT nMenuID = 0, LPVOID lpCreateParam = NULL)
  1457. {
  1458. ATOM atom = T::GetWndClassInfo().Register(&m_pfnSuperWindowProc);
  1459. if(nMenuID != 0)
  1460. m_hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(nMenuID));
  1461. dwStyle = T::GetWndStyle(dwStyle);
  1462. dwExStyle = T::GetWndExStyle(dwExStyle);
  1463. dwExStyle |= WS_EX_MDICHILD; // force this one
  1464. m_pfnSuperWindowProc = ::DefMDIChildProc;
  1465. m_hWndMDIClient = hWndParent;
  1466. ATLASSERT(::IsWindow(m_hWndMDIClient));
  1467. if(rect.m_lpRect == NULL)
  1468. rect.m_lpRect = &TBase::rcDefault;
  1469. // If the currently active MDI child is maximized, we want to create this one maximized too
  1470. ATL::CWindow wndParent = hWndParent;
  1471. BOOL bMaximized = FALSE;
  1472. wndParent.SendMessage(WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized);
  1473. if(bMaximized)
  1474. wndParent.SetRedraw(FALSE);
  1475. HWND hWnd = CFrameWindowImplBase<TBase, TWinTraits >::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, (UINT)0U, atom, lpCreateParam);
  1476. if(bMaximized)
  1477. {
  1478. // Maximize and redraw everything
  1479. if(hWnd != NULL)
  1480. MDIMaximize(hWnd);
  1481. wndParent.SetRedraw(TRUE);
  1482. wndParent.RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
  1483. ::SetFocus(GetMDIFrame()); // focus will be set back to this window
  1484. }
  1485. else if(hWnd != NULL && ::IsWindowVisible(m_hWnd) && !::IsChild(hWnd, ::GetFocus()))
  1486. {
  1487. ::SetFocus(hWnd);
  1488. }
  1489. return hWnd;
  1490. }
  1491. HWND CreateEx(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR lpcstrWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL)
  1492. {
  1493. const int cchName = 256;
  1494. TCHAR szWindowName[cchName] = { 0 };
  1495. if(lpcstrWindowName == NULL)
  1496. {
  1497. ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName);
  1498. lpcstrWindowName = szWindowName;
  1499. }
  1500. T* pT = static_cast<T*>(this);
  1501. HWND hWnd = pT->Create(hWndParent, rect, lpcstrWindowName, dwStyle, dwExStyle, T::GetWndClassInfo().m_uCommonResourceID, lpCreateParam);
  1502. if(hWnd != NULL)
  1503. m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
  1504. return hWnd;
  1505. }
  1506. BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
  1507. {
  1508. ATLASSERT(!::IsWindow(m_hWndToolBar));
  1509. if(nResourceID == 0)
  1510. nResourceID = T::GetWndClassInfo().m_uCommonResourceID;
  1511. m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID);
  1512. return (m_hWndToolBar != NULL);
  1513. }
  1514. BOOL UpdateClientEdge(LPRECT lpRect = NULL)
  1515. {
  1516. // only adjust for active MDI child window
  1517. HWND hWndChild = MDIGetActive();
  1518. if(hWndChild != NULL && hWndChild != m_hWnd)
  1519. return FALSE;
  1520. // need to adjust the client edge style as max/restore happens
  1521. DWORD dwStyle = ::GetWindowLong(m_hWndMDIClient, GWL_EXSTYLE);
  1522. DWORD dwNewStyle = dwStyle;
  1523. if(hWndChild != NULL && ((GetExStyle() & WS_EX_CLIENTEDGE) == 0) && ((GetStyle() & WS_MAXIMIZE) != 0))
  1524. dwNewStyle &= ~(WS_EX_CLIENTEDGE);
  1525. else
  1526. dwNewStyle |= WS_EX_CLIENTEDGE;
  1527. if(dwStyle != dwNewStyle)
  1528. {
  1529. // SetWindowPos will not move invalid bits
  1530. ::RedrawWindow(m_hWndMDIClient, NULL, NULL,
  1531. RDW_INVALIDATE | RDW_ALLCHILDREN);
  1532. // remove/add WS_EX_CLIENTEDGE to MDI client area
  1533. ::SetWindowLong(m_hWndMDIClient, GWL_EXSTYLE, dwNewStyle);
  1534. ::SetWindowPos(m_hWndMDIClient, NULL, 0, 0, 0, 0,
  1535. SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE |
  1536. SWP_NOZORDER | SWP_NOCOPYBITS);
  1537. // return new client area
  1538. if (lpRect != NULL)
  1539. ::GetClientRect(m_hWndMDIClient, lpRect);
  1540. return TRUE;
  1541. }
  1542. return FALSE;
  1543. }
  1544. typedef CFrameWindowImplBase<TBase, TWinTraits > _baseClass;
  1545. BEGIN_MSG_MAP(CMDIChildWindowImpl)
  1546. MESSAGE_HANDLER(WM_SIZE, OnSize)
  1547. MESSAGE_HANDLER(WM_WINDOWPOSCHANGED, OnWindowPosChanged)
  1548. MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
  1549. MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
  1550. MESSAGE_HANDLER(WM_MDIACTIVATE, OnMDIActivate)
  1551. MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
  1552. #ifndef _ATL_NO_REBAR_SUPPORT
  1553. #if (_WIN32_IE >= 0x0400)
  1554. NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize)
  1555. #endif // (_WIN32_IE >= 0x0400)
  1556. #if (_WIN32_IE >= 0x0500)
  1557. NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed)
  1558. #endif // (_WIN32_IE >= 0x0500)
  1559. #endif // !_ATL_NO_REBAR_SUPPORT
  1560. CHAIN_MSG_MAP(_baseClass)
  1561. END_MSG_MAP()
  1562. LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  1563. {
  1564. DefWindowProc(uMsg, wParam, lParam); // needed for MDI children
  1565. if(wParam != SIZE_MINIMIZED)
  1566. {
  1567. T* pT = static_cast<T*>(this);
  1568. pT->UpdateLayout();
  1569. }
  1570. return 0;
  1571. }
  1572. LRESULT OnWindowPosChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1573. {
  1574. // update MDI client edge and adjust MDI child rect
  1575. LPWINDOWPOS lpWndPos = (LPWINDOWPOS)lParam;
  1576. if(!(lpWndPos->flags & SWP_NOSIZE))
  1577. {
  1578. RECT rectClient;
  1579. if(UpdateClientEdge(&rectClient) && ((GetStyle() & WS_MAXIMIZE) != 0))
  1580. {
  1581. ::AdjustWindowRectEx(&rectClient, GetStyle(), FALSE, GetExStyle());
  1582. lpWndPos->x = rectClient.left;
  1583. lpWndPos->y = rectClient.top;
  1584. lpWndPos->cx = rectClient.right - rectClient.left;
  1585. lpWndPos->cy = rectClient.bottom - rectClient.top;
  1586. }
  1587. }
  1588. bHandled = FALSE;
  1589. return 1;
  1590. }
  1591. LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  1592. {
  1593. LRESULT lRes = DefWindowProc(uMsg, wParam, lParam);
  1594. // Activate this MDI window if needed
  1595. if(lRes == MA_ACTIVATE || lRes == MA_ACTIVATEANDEAT)
  1596. {
  1597. if(MDIGetActive() != m_hWnd)
  1598. MDIActivate(m_hWnd);
  1599. }
  1600. return lRes;
  1601. }
  1602. LRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  1603. {
  1604. return ::SendMessage(GetMDIFrame(), uMsg, wParam, lParam);
  1605. }
  1606. LRESULT OnMDIActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1607. {
  1608. if((HWND)lParam == m_hWnd && m_hMenu != NULL)
  1609. SetMDIFrameMenu();
  1610. else if((HWND)lParam == NULL)
  1611. ::SendMessage(GetMDIFrame(), WM_MDISETMENU, 0, 0);
  1612. bHandled = FALSE;
  1613. return 1;
  1614. }
  1615. LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  1616. {
  1617. if(m_hMenu != NULL)
  1618. {
  1619. ::DestroyMenu(m_hMenu);
  1620. m_hMenu = NULL;
  1621. }
  1622. UpdateClientEdge();
  1623. bHandled = FALSE;
  1624. return 1;
  1625. }
  1626. #ifndef _ATL_NO_REBAR_SUPPORT
  1627. #if (_WIN32_IE >= 0x0400)
  1628. LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
  1629. {
  1630. T* pT = static_cast<T*>(this);
  1631. pT->UpdateLayout(FALSE);
  1632. return 0;
  1633. }
  1634. #endif // (_WIN32_IE >= 0x0400)
  1635. #if (_WIN32_IE >= 0x0500)
  1636. LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
  1637. {
  1638. T* pT = static_cast<T*>(this);
  1639. _ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false };
  1640. if(!pT->PrepareChevronMenu(cmi))
  1641. {
  1642. bHandled = FALSE;
  1643. return 1;
  1644. }
  1645. // display a popup menu with hidden items
  1646. pT->DisplayChevronMenu(cmi);
  1647. // cleanup
  1648. pT->CleanupChevronMenu(cmi);
  1649. return 0;
  1650. }
  1651. #endif // (_WIN32_IE >= 0x0500)
  1652. #endif // !_ATL_NO_REBAR_SUPPORT
  1653. };
  1654. #endif // !_WIN32_WCE
  1655. ///////////////////////////////////////////////////////////////////////////////
  1656. // COwnerDraw - MI class for owner-draw support
  1657. template <class T>
  1658. class COwnerDraw
  1659. {
  1660. public:
  1661. #if (_ATL_VER < 0x0700)
  1662. BOOL m_bHandledOD;
  1663. BOOL IsMsgHandled() const
  1664. {
  1665. return m_bHandledOD;
  1666. }
  1667. void SetMsgHandled(BOOL bHandled)
  1668. {
  1669. m_bHandledOD = bHandled;
  1670. }
  1671. #endif // (_ATL_VER < 0x0700)
  1672. // Message map and handlers
  1673. BEGIN_MSG_MAP(COwnerDraw< T >)
  1674. MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem)
  1675. MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem)
  1676. MESSAGE_HANDLER(WM_COMPAREITEM, OnCompareItem)
  1677. MESSAGE_HANDLER(WM_DELETEITEM, OnDeleteItem)
  1678. ALT_MSG_MAP(1)
  1679. MESSAGE_HANDLER(OCM_DRAWITEM, OnDrawItem)
  1680. MESSAGE_HANDLER(OCM_MEASUREITEM, OnMeasureItem)
  1681. MESSAGE_HANDLER(OCM_COMPAREITEM, OnCompareItem)
  1682. MESSAGE_HANDLER(OCM_DELETEITEM, OnDeleteItem)
  1683. END_MSG_MAP()
  1684. LRESULT OnDrawItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1685. {
  1686. T* pT = static_cast<T*>(this);
  1687. pT->SetMsgHandled(TRUE);
  1688. pT->DrawItem((LPDRAWITEMSTRUCT)lParam);
  1689. bHandled = pT->IsMsgHandled();
  1690. return (LRESULT)TRUE;
  1691. }
  1692. LRESULT OnMeasureItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1693. {
  1694. T* pT = static_cast<T*>(this);
  1695. pT->SetMsgHandled(TRUE);
  1696. pT->MeasureItem((LPMEASUREITEMSTRUCT)lParam);
  1697. bHandled = pT->IsMsgHandled();
  1698. return (LRESULT)TRUE;
  1699. }
  1700. LRESULT OnCompareItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1701. {
  1702. T* pT = static_cast<T*>(this);
  1703. pT->SetMsgHandled(TRUE);
  1704. bHandled = pT->IsMsgHandled();
  1705. return (LRESULT)pT->CompareItem((LPCOMPAREITEMSTRUCT)lParam);
  1706. }
  1707. LRESULT OnDeleteItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1708. {
  1709. T* pT = static_cast<T*>(this);
  1710. pT->SetMsgHandled(TRUE);
  1711. pT->DeleteItem((LPDELETEITEMSTRUCT)lParam);
  1712. bHandled = pT->IsMsgHandled();
  1713. return (LRESULT)TRUE;
  1714. }
  1715. // Overrideables
  1716. void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/)
  1717. {
  1718. // must be implemented
  1719. ATLASSERT(FALSE);
  1720. }
  1721. void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
  1722. {
  1723. if(lpMeasureItemStruct->CtlType != ODT_MENU)
  1724. {
  1725. // return default height for a system font
  1726. T* pT = static_cast<T*>(this);
  1727. HWND hWnd = pT->GetDlgItem(lpMeasureItemStruct->CtlID);
  1728. CClientDC dc(hWnd);
  1729. TEXTMETRIC tm = { 0 };
  1730. dc.GetTextMetrics(&tm);
  1731. lpMeasureItemStruct->itemHeight = tm.tmHeight;
  1732. }
  1733. else
  1734. lpMeasureItemStruct->itemHeight = ::GetSystemMetrics(SM_CYMENU);
  1735. }
  1736. int CompareItem(LPCOMPAREITEMSTRUCT /*lpCompareItemStruct*/)
  1737. {
  1738. // all items are equal
  1739. return 0;
  1740. }
  1741. void DeleteItem(LPDELETEITEMSTRUCT /*lpDeleteItemStruct*/)
  1742. {
  1743. // default - nothing
  1744. }
  1745. };
  1746. ///////////////////////////////////////////////////////////////////////////////
  1747. // Update UI macros
  1748. // these build the Update UI map inside a class definition
  1749. #define BEGIN_UPDATE_UI_MAP(thisClass) \
  1750. static const CUpdateUIBase::_AtlUpdateUIMap* GetUpdateUIMap() \
  1751. { \
  1752. static const _AtlUpdateUIMap theMap[] = \
  1753. {
  1754. #define UPDATE_ELEMENT(nID, wType) \
  1755. { nID, wType },
  1756. #define END_UPDATE_UI_MAP() \
  1757. { (WORD)-1, 0 } \
  1758. }; \
  1759. return theMap; \
  1760. }
  1761. ///////////////////////////////////////////////////////////////////////////////
  1762. // CUpdateUI - manages UI elements updating
  1763. class CUpdateUIBase
  1764. {
  1765. public:
  1766. // constants
  1767. enum
  1768. {
  1769. // UI element type
  1770. UPDUI_MENUPOPUP = 0x0001,
  1771. UPDUI_MENUBAR = 0x0002,
  1772. UPDUI_CHILDWINDOW = 0x0004,
  1773. UPDUI_TOOLBAR = 0x0008,
  1774. UPDUI_STATUSBAR = 0x0010,
  1775. // state
  1776. UPDUI_ENABLED = 0x0000,
  1777. UPDUI_DISABLED = 0x0100,
  1778. UPDUI_CHECKED = 0x0200,
  1779. UPDUI_CHECKED2 = 0x0400,
  1780. UPDUI_RADIO = 0x0800,
  1781. UPDUI_DEFAULT = 0x1000,
  1782. UPDUI_TEXT = 0x2000,
  1783. // internal state
  1784. UPDUI_CLEARDEFAULT = 0x4000,
  1785. };
  1786. // element data
  1787. struct _AtlUpdateUIElement
  1788. {
  1789. HWND m_hWnd;
  1790. WORD m_wType;
  1791. bool operator ==(const _AtlUpdateUIElement& e) const
  1792. { return (m_hWnd == e.m_hWnd && m_wType == e.m_wType); }
  1793. };
  1794. // map data
  1795. struct _AtlUpdateUIMap
  1796. {
  1797. WORD m_nID;
  1798. WORD m_wType;
  1799. bool operator ==(const _AtlUpdateUIMap& e) const
  1800. { return (m_nID == e.m_nID && m_wType == e.m_wType); }
  1801. };
  1802. // instance data
  1803. struct _AtlUpdateUIData
  1804. {
  1805. WORD m_wState;
  1806. union
  1807. {
  1808. void* m_lpData;
  1809. LPTSTR m_lpstrText;
  1810. struct
  1811. {
  1812. WORD m_nIDFirst;
  1813. WORD m_nIDLast;
  1814. };
  1815. };
  1816. bool operator ==(const _AtlUpdateUIData& e) const
  1817. { return (m_wState == e.m_wState && m_lpData == e.m_lpData); }
  1818. };
  1819. ATL::CSimpleArray<_AtlUpdateUIElement> m_UIElements; // elements data
  1820. const _AtlUpdateUIMap* m_pUIMap; // static UI data
  1821. _AtlUpdateUIData* m_pUIData; // instance UI data
  1822. WORD m_wDirtyType; // global dirty flag
  1823. bool m_bBlockAccelerators;
  1824. // Constructor, destructor
  1825. CUpdateUIBase() : m_pUIMap(NULL), m_pUIData(NULL), m_wDirtyType(0), m_bBlockAccelerators(false)
  1826. { }
  1827. ~CUpdateUIBase()
  1828. {
  1829. if(m_pUIMap != NULL && m_pUIData != NULL)
  1830. {
  1831. const _AtlUpdateUIMap* pUIMap = m_pUIMap;
  1832. _AtlUpdateUIData* pUIData = m_pUIData;
  1833. while(pUIMap->m_nID != (WORD)-1)
  1834. {
  1835. if(pUIData->m_wState & UPDUI_TEXT)
  1836. delete [] pUIData->m_lpstrText;
  1837. pUIMap++;
  1838. pUIData++;
  1839. }
  1840. delete [] m_pUIData;
  1841. }
  1842. }
  1843. // Check for disabled commands
  1844. bool UIGetBlockAccelerators() const
  1845. {
  1846. return m_bBlockAccelerators;
  1847. }
  1848. bool UISetBlockAccelerators(bool bBlock)
  1849. {
  1850. bool bOld = m_bBlockAccelerators;
  1851. m_bBlockAccelerators = bBlock;
  1852. return bOld;
  1853. }
  1854. // Add elements
  1855. BOOL UIAddMenuBar(HWND hWnd) // menu bar (main menu)
  1856. {
  1857. if(hWnd == NULL)
  1858. return FALSE;
  1859. _AtlUpdateUIElement e;
  1860. e.m_hWnd = hWnd;
  1861. e.m_wType = UPDUI_MENUBAR;
  1862. return m_UIElements.Add(e);
  1863. }
  1864. BOOL UIAddToolBar(HWND hWnd) // toolbar
  1865. {
  1866. if(hWnd == NULL)
  1867. return FALSE;
  1868. _AtlUpdateUIElement e;
  1869. e.m_hWnd = hWnd;
  1870. e.m_wType = UPDUI_TOOLBAR;
  1871. return m_UIElements.Add(e);
  1872. }
  1873. BOOL UIAddStatusBar(HWND hWnd) // status bar
  1874. {
  1875. if(hWnd == NULL)
  1876. return FALSE;
  1877. _AtlUpdateUIElement e;
  1878. e.m_hWnd = hWnd;
  1879. e.m_wType = UPDUI_STATUSBAR;
  1880. return m_UIElements.Add(e);
  1881. }
  1882. BOOL UIAddChildWindowContainer(HWND hWnd) // child window
  1883. {
  1884. if(hWnd == NULL)
  1885. return FALSE;
  1886. _AtlUpdateUIElement e;
  1887. e.m_hWnd = hWnd;
  1888. e.m_wType = UPDUI_CHILDWINDOW;
  1889. return m_UIElements.Add(e);
  1890. }
  1891. // Message map for popup menu updates and accelerator blocking
  1892. BEGIN_MSG_MAP(CUpdateUIBase)
  1893. MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup)
  1894. MESSAGE_HANDLER(WM_COMMAND, OnCommand)
  1895. END_MSG_MAP()
  1896. LRESULT OnInitMenuPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
  1897. {
  1898. bHandled = FALSE;
  1899. HMENU hMenu = (HMENU)wParam;
  1900. if(hMenu == NULL)
  1901. return 1;
  1902. _AtlUpdateUIData* pUIData = m_pUIData;
  1903. if(pUIData == NULL)
  1904. return 1;
  1905. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1906. while(pMap->m_nID != (WORD)-1)
  1907. {
  1908. if(pMap->m_wType & UPDUI_MENUPOPUP)
  1909. {
  1910. UIUpdateMenuBarElement(pMap->m_nID, pUIData, hMenu);
  1911. if((pUIData->m_wState & UPDUI_RADIO) != 0)
  1912. ::CheckMenuRadioItem(hMenu, pUIData->m_nIDFirst, pUIData->m_nIDLast, pMap->m_nID, MF_BYCOMMAND);
  1913. }
  1914. pMap++;
  1915. pUIData++;
  1916. }
  1917. return 0;
  1918. }
  1919. LRESULT OnCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
  1920. {
  1921. bHandled = FALSE;
  1922. if(m_bBlockAccelerators && HIWORD(wParam) == 1) // accelerators only
  1923. {
  1924. int nID = LOWORD(wParam);
  1925. if((UIGetState(nID) & UPDUI_DISABLED) == UPDUI_DISABLED)
  1926. {
  1927. ATLTRACE2(atlTraceUI, 0, _T("CUpdateUIBase::OnCommand - blocked disabled command 0x%4.4X\n"), nID);
  1928. bHandled = TRUE; // eat the command, UI item is disabled
  1929. }
  1930. }
  1931. return 0;
  1932. }
  1933. // methods for setting UI element state
  1934. BOOL UIEnable(int nID, BOOL bEnable, BOOL bForceUpdate = FALSE)
  1935. {
  1936. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1937. _AtlUpdateUIData* pUIData = m_pUIData;
  1938. if(pUIData == NULL)
  1939. return FALSE;
  1940. for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
  1941. {
  1942. if(nID == (int)pMap->m_nID)
  1943. {
  1944. if(bEnable)
  1945. {
  1946. if(pUIData->m_wState & UPDUI_DISABLED)
  1947. {
  1948. pUIData->m_wState |= pMap->m_wType;
  1949. pUIData->m_wState &= ~UPDUI_DISABLED;
  1950. }
  1951. }
  1952. else
  1953. {
  1954. if(!(pUIData->m_wState & UPDUI_DISABLED))
  1955. {
  1956. pUIData->m_wState |= pMap->m_wType;
  1957. pUIData->m_wState |= UPDUI_DISABLED;
  1958. }
  1959. }
  1960. if(bForceUpdate)
  1961. pUIData->m_wState |= pMap->m_wType;
  1962. if(pUIData->m_wState & pMap->m_wType)
  1963. m_wDirtyType |= pMap->m_wType;
  1964. break; // found
  1965. }
  1966. }
  1967. return TRUE;
  1968. }
  1969. BOOL UISetCheck(int nID, int nCheck, BOOL bForceUpdate = FALSE)
  1970. {
  1971. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1972. _AtlUpdateUIData* pUIData = m_pUIData;
  1973. if(pUIData == NULL)
  1974. return FALSE;
  1975. for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
  1976. {
  1977. if(nID == (int)pMap->m_nID)
  1978. {
  1979. switch(nCheck)
  1980. {
  1981. case 0:
  1982. if((pUIData->m_wState & UPDUI_CHECKED) || (pUIData->m_wState & UPDUI_CHECKED2))
  1983. {
  1984. pUIData->m_wState |= pMap->m_wType;
  1985. pUIData->m_wState &= ~(UPDUI_CHECKED | UPDUI_CHECKED2);
  1986. }
  1987. break;
  1988. case 1:
  1989. if(!(pUIData->m_wState & UPDUI_CHECKED))
  1990. {
  1991. pUIData->m_wState |= pMap->m_wType;
  1992. pUIData->m_wState &= ~UPDUI_CHECKED2;
  1993. pUIData->m_wState |= UPDUI_CHECKED;
  1994. }
  1995. break;
  1996. case 2:
  1997. if(!(pUIData->m_wState & UPDUI_CHECKED2))
  1998. {
  1999. pUIData->m_wState |= pMap->m_wType;
  2000. pUIData->m_wState &= ~UPDUI_CHECKED;
  2001. pUIData->m_wState |= UPDUI_CHECKED2;
  2002. }
  2003. break;
  2004. }
  2005. if(bForceUpdate)
  2006. pUIData->m_wState |= pMap->m_wType;
  2007. if(pUIData->m_wState & pMap->m_wType)
  2008. m_wDirtyType |= pMap->m_wType;
  2009. break; // found
  2010. }
  2011. }
  2012. return TRUE;
  2013. }
  2014. // variant that supports bool (checked/not-checked, no intermediate state)
  2015. BOOL UISetCheck(int nID, bool bCheck, BOOL bForceUpdate = FALSE)
  2016. {
  2017. return UISetCheck(nID, bCheck ? 1 : 0, bForceUpdate);
  2018. }
  2019. BOOL UISetRadio(int nID, BOOL bRadio, BOOL bForceUpdate = FALSE)
  2020. {
  2021. const _AtlUpdateUIMap* pMap = m_pUIMap;
  2022. _AtlUpdateUIData* pUIData = m_pUIData;
  2023. if(pUIData == NULL)
  2024. return FALSE;
  2025. for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
  2026. {
  2027. if(nID == (int)pMap->m_nID)
  2028. {
  2029. if(bRadio)
  2030. {
  2031. if(!(pUIData->m_wState & UPDUI_RADIO))
  2032. {
  2033. pUIData->m_wState |= pMap->m_wType;
  2034. pUIData->m_wState |= UPDUI_RADIO;
  2035. }
  2036. }
  2037. else
  2038. {
  2039. if(pUIData->m_wState & UPDUI_RADIO)
  2040. {
  2041. pUIData->m_wState |= pMap->m_wType;
  2042. pUIData->m_wState &= ~UPDUI_RADIO;
  2043. }
  2044. }
  2045. if(bForceUpdate)
  2046. pUIData->m_wState |= pMap->m_wType;
  2047. if(pUIData->m_wState & pMap->m_wType)
  2048. m_wDirtyType |= pMap->m_wType;
  2049. break; // found
  2050. }
  2051. }
  2052. return TRUE;
  2053. }
  2054. // for menu items
  2055. BOOL UISetRadioMenuItem(int nID, int nIDFirst, int nIDLast, BOOL bForceUpdate = FALSE)
  2056. {
  2057. const _AtlUpdateUIMap* pMap = m_pUIMap;
  2058. _AtlUpdateUIData* pUIData = m_pUIData;
  2059. if(pUIData == NULL)
  2060. return FALSE;
  2061. for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
  2062. {
  2063. if(nID == (int)pMap->m_nID)
  2064. {
  2065. pUIData->m_wState |= pMap->m_wType;
  2066. pUIData->m_wState |= UPDUI_RADIO;
  2067. pUIData->m_nIDFirst = (WORD)nIDFirst;
  2068. pUIData->m_nIDLast = (WORD)nIDLast;
  2069. if(bForceUpdate)
  2070. pUIData->m_wState |= pMap->m_wType;
  2071. if(pUIData->m_wState & pMap->m_wType)
  2072. m_wDirtyType |= pMap->m_wType;
  2073. }
  2074. else if(pMap->m_nID >= nIDFirst && pMap->m_nID <= nIDLast)
  2075. {
  2076. if(pUIData->m_wState & UPDUI_RADIO)
  2077. {
  2078. pUIData->m_wState &= ~pMap->m_wType;
  2079. pUIData->m_wState &= ~UPDUI_RADIO;
  2080. pUIData->m_nIDFirst = 0;
  2081. pUIData->m_nIDLast = 0;
  2082. }
  2083. }
  2084. if(pMap->m_nID == nIDLast)
  2085. break;
  2086. }
  2087. return TRUE;
  2088. }
  2089. BOOL UISetText(int nID, LPCTSTR lpstrText, BOOL bForceUpdate = FALSE)
  2090. {
  2091. const _AtlUpdateUIMap* pMap = m_pUIMap;
  2092. _AtlUpdateUIData* pUIData = m_pUIData;
  2093. if(pUIData == NULL)
  2094. return FALSE;
  2095. if(lpstrText == NULL)
  2096. lpstrText = _T("");
  2097. for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
  2098. {
  2099. if(nID == (int)pMap->m_nID)
  2100. {
  2101. if(pUIData->m_lpstrText == NULL || lstrcmp(pUIData->m_lpstrText, lpstrText))
  2102. {
  2103. delete [] pUIData->m_lpstrText;
  2104. pUIData->m_lpstrText = NULL;
  2105. int nStrLen = lstrlen(lpstrText);
  2106. ATLTRY(pUIData->m_lpstrText = new TCHAR[nStrLen + 1]);
  2107. if(pUIData->m_lpstrText == NULL)
  2108. {
  2109. ATLTRACE2(atlTraceUI, 0, _T("UISetText - memory allocation failed\n"));
  2110. break;
  2111. }
  2112. SecureHelper::strcpy_x(pUIData->m_lpstrText, nStrLen + 1, lpstrText);
  2113. pUIData->m_wState |= (UPDUI_TEXT | pMap->m_wType);
  2114. }
  2115. if(bForceUpdate)
  2116. pUIData->m_wState |= (UPDUI_TEXT | pMap->m_wType);
  2117. if(pUIData->m_wState & pMap->m_wType)
  2118. m_wDirtyType |= pMap->m_wType;
  2119. break; // found
  2120. }
  2121. }
  2122. return TRUE;
  2123. }
  2124. BOOL UISetDefault(int nID, BOOL bDefault, BOOL bForceUpdate = FALSE)
  2125. {
  2126. const _AtlUpdateUIMap* pMap = m_pUIMap;
  2127. _AtlUpdateUIData* pUIData = m_pUIData;
  2128. if(pUIData == NULL)
  2129. return FALSE;
  2130. for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
  2131. {
  2132. if(nID == (int)pMap->m_nID)
  2133. {
  2134. if(bDefault)
  2135. {
  2136. if((pUIData->m_wState & UPDUI_DEFAULT) == 0)
  2137. {
  2138. pUIData->m_wState |= pMap->m_wType;
  2139. pUIData->m_wState |= UPDUI_DEFAULT;
  2140. }
  2141. }
  2142. else
  2143. {
  2144. if((pUIData->m_wState & UPDUI_DEFAULT) != 0)
  2145. {
  2146. pUIData->m_wState |= pMap->m_wType;
  2147. pUIData->m_wState &= ~UPDUI_DEFAULT;
  2148. pUIData->m_wState |= UPDUI_CLEARDEFAULT;
  2149. }
  2150. }
  2151. if(bForceUpdate)
  2152. pUIData->m_wState |= pMap->m_wType;
  2153. if(pUIData->m_wState & pMap->m_wType)
  2154. m_wDirtyType |= pMap->m_wType;
  2155. break; // found
  2156. }
  2157. }
  2158. return TRUE;
  2159. }
  2160. // methods for complete state set/get
  2161. BOOL UISetState(int nID, DWORD dwState)
  2162. {
  2163. const _AtlUpdateUIMap* pMap = m_pUIMap;
  2164. _AtlUpdateUIData* pUIData = m_pUIData;
  2165. if(pUIData == NULL)
  2166. return FALSE;
  2167. for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
  2168. {
  2169. if(nID == (int)pMap->m_nID)
  2170. {
  2171. pUIData->m_wState = (WORD)(dwState | pMap->m_wType);
  2172. m_wDirtyType |= pMap->m_wType;
  2173. break; // found
  2174. }
  2175. }
  2176. return TRUE;
  2177. }
  2178. DWORD UIGetState(int nID)
  2179. {
  2180. const _AtlUpdateUIMap* pMap = m_pUIMap;
  2181. _AtlUpdateUIData* pUIData = m_pUIData;
  2182. if(pUIData == NULL)
  2183. return 0;
  2184. for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
  2185. {
  2186. if(nID == (int)pMap->m_nID)
  2187. return pUIData->m_wState;
  2188. }
  2189. return 0;
  2190. }
  2191. // methods for updating UI
  2192. #ifndef _WIN32_WCE
  2193. BOOL UIUpdateMenuBar(BOOL bForceUpdate = FALSE, BOOL bMainMenu = FALSE)
  2194. {
  2195. if(!(m_wDirtyType & UPDUI_MENUBAR) && !bForceUpdate)
  2196. return TRUE;
  2197. const _AtlUpdateUIMap* pMap = m_pUIMap;
  2198. _AtlUpdateUIData* pUIData = m_pUIData;
  2199. if(pUIData == NULL)
  2200. return FALSE;
  2201. while(pMap->m_nID != (WORD)-1)
  2202. {
  2203. for(int i = 0; i < m_UIElements.GetSize(); i++)
  2204. {
  2205. if(m_UIElements[i].m_wType == UPDUI_MENUBAR)
  2206. {
  2207. HMENU hMenu = ::GetMenu(m_UIElements[i].m_hWnd);
  2208. if(hMenu != NULL && (pUIData->m_wState & UPDUI_MENUBAR) && (pMap->m_wType & UPDUI_MENUBAR))
  2209. UIUpdateMenuBarElement(pMap->m_nID, pUIData, hMenu);
  2210. }
  2211. if(bMainMenu)
  2212. ::DrawMenuBar(m_UIElements[i].m_hWnd);
  2213. }
  2214. pMap++;
  2215. pUIData->m_wState &= ~UPDUI_MENUBAR;
  2216. if(pUIData->m_wState & UPDUI_TEXT)
  2217. {
  2218. delete [] pUIData->m_lpstrText;
  2219. pUIData->m_lpstrText = NULL;
  2220. pUIData->m_wState &= ~UPDUI_TEXT;
  2221. }
  2222. pUIData++;
  2223. }
  2224. m_wDirtyType &= ~UPDUI_MENUBAR;
  2225. return TRUE;
  2226. }
  2227. #endif // !_WIN32_WCE
  2228. BOOL UIUpdateToolBar(BOOL bForceUpdate = FALSE)
  2229. {
  2230. if(!(m_wDirtyType & UPDUI_TOOLBAR) && !bForceUpdate)
  2231. return TRUE;
  2232. const _AtlUpdateUIMap* pMap = m_pUIMap;
  2233. _AtlUpdateUIData* pUIData = m_pUIData;
  2234. if(pUIData == NULL)
  2235. return FALSE;
  2236. while(pMap->m_nID != (WORD)-1)
  2237. {
  2238. for(int i = 0; i < m_UIElements.GetSize(); i++)
  2239. {
  2240. if(m_UIElements[i].m_wType == UPDUI_TOOLBAR)
  2241. {
  2242. if((pUIData->m_wState & UPDUI_TOOLBAR) && (pMap->m_wType & UPDUI_TOOLBAR))
  2243. UIUpdateToolBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd);
  2244. }
  2245. }
  2246. pMap++;
  2247. pUIData->m_wState &= ~UPDUI_TOOLBAR;
  2248. pUIData++;
  2249. }
  2250. m_wDirtyType &= ~UPDUI_TOOLBAR;
  2251. return TRUE;
  2252. }
  2253. BOOL UIUpdateStatusBar(BOOL bForceUpdate = FALSE)
  2254. {
  2255. if(!(m_wDirtyType & UPDUI_STATUSBAR) && !bForceUpdate)
  2256. return TRUE;
  2257. const _AtlUpdateUIMap* pMap = m_pUIMap;
  2258. _AtlUpdateUIData* pUIData = m_pUIData;
  2259. if(pUIData == NULL)
  2260. return FALSE;
  2261. while(pMap->m_nID != (WORD)-1)
  2262. {
  2263. for(int i = 0; i < m_UIElements.GetSize(); i++)
  2264. {
  2265. if(m_UIElements[i].m_wType == UPDUI_STATUSBAR)
  2266. {
  2267. if((pUIData->m_wState & UPDUI_STATUSBAR) && (pMap->m_wType & UPDUI_STATUSBAR))
  2268. UIUpdateStatusBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd);
  2269. }
  2270. }
  2271. pMap++;
  2272. pUIData->m_wState &= ~UPDUI_STATUSBAR;
  2273. if(pUIData->m_wState & UPDUI_TEXT)
  2274. {
  2275. delete [] pUIData->m_lpstrText;
  2276. pUIData->m_lpstrText = NULL;
  2277. pUIData->m_wState &= ~UPDUI_TEXT;
  2278. }
  2279. pUIData++;
  2280. }
  2281. m_wDirtyType &= ~UPDUI_STATUSBAR;
  2282. return TRUE;
  2283. }
  2284. BOOL UIUpdateChildWindows(BOOL bForceUpdate = FALSE)
  2285. {
  2286. if(!(m_wDirtyType & UPDUI_CHILDWINDOW) && !bForceUpdate)
  2287. return TRUE;
  2288. const _AtlUpdateUIMap* pMap = m_pUIMap;
  2289. _AtlUpdateUIData* pUIData = m_pUIData;
  2290. if(pUIData == NULL)
  2291. return FALSE;
  2292. while(pMap->m_nID != (WORD)-1)
  2293. {
  2294. for(int i = 0; i < m_UIElements.GetSize(); i++)
  2295. {
  2296. if(m_UIElements[i].m_wType == UPDUI_CHILDWINDOW)
  2297. {
  2298. if((pUIData->m_wState & UPDUI_CHILDWINDOW) && (pMap->m_wType & UPDUI_CHILDWINDOW))
  2299. UIUpdateChildWindow(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd);
  2300. }
  2301. }
  2302. pMap++;
  2303. pUIData->m_wState &= ~UPDUI_CHILDWINDOW;
  2304. if(pUIData->m_wState & UPDUI_TEXT)
  2305. {
  2306. delete [] pUIData->m_lpstrText;
  2307. pUIData->m_lpstrText = NULL;
  2308. pUIData->m_wState &= ~UPDUI_TEXT;
  2309. }
  2310. pUIData++;
  2311. }
  2312. m_wDirtyType &= ~UPDUI_CHILDWINDOW;
  2313. return TRUE;
  2314. }
  2315. // internal element specific methods
  2316. static void UIUpdateMenuBarElement(int nID, _AtlUpdateUIData* pUIData, HMENU hMenu)
  2317. {
  2318. #ifndef _WIN32_WCE
  2319. if((pUIData->m_wState & UPDUI_CLEARDEFAULT) != 0)
  2320. {
  2321. ::SetMenuDefaultItem(hMenu, (UINT)-1, 0);
  2322. pUIData->m_wState &= ~UPDUI_CLEARDEFAULT;
  2323. }
  2324. #endif // !_WIN32_WCE
  2325. CMenuItemInfo mii;
  2326. mii.fMask = MIIM_STATE;
  2327. mii.wID = nID;
  2328. #ifndef _WIN32_WCE
  2329. if((pUIData->m_wState & UPDUI_DISABLED) != 0)
  2330. mii.fState |= MFS_DISABLED | MFS_GRAYED;
  2331. else
  2332. mii.fState |= MFS_ENABLED;
  2333. if((pUIData->m_wState & UPDUI_CHECKED) != 0)
  2334. mii.fState |= MFS_CHECKED;
  2335. else
  2336. mii.fState |= MFS_UNCHECKED;
  2337. if((pUIData->m_wState & UPDUI_DEFAULT) != 0)
  2338. mii.fState |= MFS_DEFAULT;
  2339. #else // CE specific
  2340. // ::SetMenuItemInfo() can't disable or check menu items
  2341. // on Windows CE, so we have to do that directly
  2342. UINT uEnable = MF_BYCOMMAND;
  2343. if((pUIData->m_wState & UPDUI_DISABLED) != 0)
  2344. uEnable |= MF_GRAYED;
  2345. else
  2346. uEnable |= MF_ENABLED;
  2347. ::EnableMenuItem(hMenu, nID, uEnable);
  2348. UINT uCheck = MF_BYCOMMAND;
  2349. if((pUIData->m_wState & UPDUI_CHECKED) != 0)
  2350. uCheck |= MF_CHECKED;
  2351. else
  2352. uCheck |= MF_UNCHECKED;
  2353. ::CheckMenuItem(hMenu, nID, uCheck);
  2354. #endif // _WIN32_WCE
  2355. if((pUIData->m_wState & UPDUI_TEXT) != 0)
  2356. {
  2357. CMenuItemInfo miiNow;
  2358. miiNow.fMask = MIIM_TYPE;
  2359. miiNow.wID = nID;
  2360. if(::GetMenuItemInfo(hMenu, nID, FALSE, &miiNow))
  2361. {
  2362. mii.fMask |= MIIM_TYPE;
  2363. // MFT_BITMAP and MFT_SEPARATOR don't go together with MFT_STRING
  2364. #ifndef _WIN32_WCE
  2365. mii.fType |= (miiNow.fType & ~(MFT_BITMAP | MFT_SEPARATOR)) | MFT_STRING;
  2366. #else // CE specific
  2367. mii.fType |= (miiNow.fType & ~(MFT_SEPARATOR)) | MFT_STRING;
  2368. #endif // _WIN32_WCE
  2369. mii.dwTypeData = pUIData->m_lpstrText;
  2370. }
  2371. }
  2372. ::SetMenuItemInfo(hMenu, nID, FALSE, &mii);
  2373. }
  2374. static void UIUpdateToolBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndToolBar)
  2375. {
  2376. // Note: only handles enabled/disabled, checked state, and radio (press)
  2377. ::SendMessage(hWndToolBar, TB_ENABLEBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE);
  2378. ::SendMessage(hWndToolBar, TB_CHECKBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED) ? TRUE : FALSE);
  2379. ::SendMessage(hWndToolBar, TB_INDETERMINATE, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED2) ? TRUE : FALSE);
  2380. ::SendMessage(hWndToolBar, TB_PRESSBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_RADIO) ? TRUE : FALSE);
  2381. }
  2382. static void UIUpdateStatusBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndStatusBar)
  2383. {
  2384. // Note: only handles text
  2385. if(pUIData->m_wState & UPDUI_TEXT)
  2386. ::SendMessage(hWndStatusBar, SB_SETTEXT, nID, (LPARAM)pUIData->m_lpstrText);
  2387. }
  2388. static void UIUpdateChildWindow(int nID, _AtlUpdateUIData* pUIData, HWND hWnd)
  2389. {
  2390. HWND hChild = ::GetDlgItem(hWnd, nID);
  2391. ::EnableWindow(hChild, (pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE);
  2392. // for check and radio, assume that window is a button
  2393. int nCheck = BST_UNCHECKED;
  2394. if(pUIData->m_wState & UPDUI_CHECKED || pUIData->m_wState & UPDUI_RADIO)
  2395. nCheck = BST_CHECKED;
  2396. else if(pUIData->m_wState & UPDUI_CHECKED2)
  2397. nCheck = BST_INDETERMINATE;
  2398. ::SendMessage(hChild, BM_SETCHECK, nCheck, 0L);
  2399. if(pUIData->m_wState & UPDUI_DEFAULT)
  2400. {
  2401. DWORD dwRet = (DWORD)::SendMessage(hWnd, DM_GETDEFID, 0, 0L);
  2402. if(HIWORD(dwRet) == DC_HASDEFID)
  2403. {
  2404. HWND hOldDef = ::GetDlgItem(hWnd, (int)(short)LOWORD(dwRet));
  2405. // remove BS_DEFPUSHBUTTON
  2406. ::SendMessage(hOldDef, BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE, 0));
  2407. }
  2408. ::SendMessage(hWnd, DM_SETDEFID, nID, 0L);
  2409. }
  2410. if(pUIData->m_wState & UPDUI_TEXT)
  2411. ::SetWindowText(hChild, pUIData->m_lpstrText);
  2412. }
  2413. };
  2414. template <class T>
  2415. class CUpdateUI : public CUpdateUIBase
  2416. {
  2417. public:
  2418. CUpdateUI()
  2419. {
  2420. T* pT = static_cast<T*>(this);
  2421. pT;
  2422. const _AtlUpdateUIMap* pMap = pT->GetUpdateUIMap();
  2423. m_pUIMap = pMap;
  2424. ATLASSERT(m_pUIMap != NULL);
  2425. int nCount;
  2426. for(nCount = 1; pMap->m_nID != (WORD)-1; nCount++)
  2427. pMap++;
  2428. // check for duplicates (debug only)
  2429. #ifdef _DEBUG
  2430. for(int i = 0; i < nCount; i++)
  2431. {
  2432. for(int j = 0; j < nCount; j++)
  2433. {
  2434. // shouldn't have duplicates in the update UI map
  2435. if(i != j)
  2436. ATLASSERT(m_pUIMap[j].m_nID != m_pUIMap[i].m_nID);
  2437. }
  2438. }
  2439. #endif // _DEBUG
  2440. ATLTRY(m_pUIData = new _AtlUpdateUIData[nCount]);
  2441. ATLASSERT(m_pUIData != NULL);
  2442. if(m_pUIData != NULL)
  2443. memset(m_pUIData, 0, sizeof(_AtlUpdateUIData) * nCount);
  2444. }
  2445. };
  2446. ///////////////////////////////////////////////////////////////////////////////
  2447. // CDynamicUpdateUI - allows update elements to dynamically added and removed
  2448. // in addition to a static update UI map
  2449. template <class T>
  2450. class CDynamicUpdateUI : public CUpdateUIBase
  2451. {
  2452. public:
  2453. // Data members
  2454. ATL::CSimpleArray<_AtlUpdateUIMap> m_arrUIMap; // copy of the static UI data
  2455. ATL::CSimpleArray<_AtlUpdateUIData> m_arrUIData; // instance UI data
  2456. // Constructor/destructor
  2457. CDynamicUpdateUI()
  2458. {
  2459. T* pT = static_cast<T*>(this);
  2460. pT;
  2461. const _AtlUpdateUIMap* pMap = pT->GetUpdateUIMap();
  2462. ATLASSERT(pMap != NULL);
  2463. for(;;)
  2464. {
  2465. BOOL bRet = m_arrUIMap.Add(*(_AtlUpdateUIMap*)pMap);
  2466. ATLASSERT(bRet);
  2467. if(bRet != FALSE)
  2468. {
  2469. _AtlUpdateUIData data = { 0, NULL };
  2470. bRet = m_arrUIData.Add(data);
  2471. ATLASSERT(bRet);
  2472. }
  2473. if(pMap->m_nID == (WORD)-1)
  2474. break;
  2475. pMap++;
  2476. }
  2477. ATLASSERT(m_arrUIMap.GetSize() == m_arrUIData.GetSize());
  2478. #ifdef _DEBUG
  2479. // check for duplicates (debug only)
  2480. for(int i = 0; i < m_arrUIMap.GetSize(); i++)
  2481. {
  2482. for(int j = 0; j < m_arrUIMap.GetSize(); j++)
  2483. {
  2484. // shouldn't have duplicates in the update UI map
  2485. if(i != j)
  2486. ATLASSERT(m_arrUIMap[j].m_nID != m_arrUIMap[i].m_nID);
  2487. }
  2488. }
  2489. #endif // _DEBUG
  2490. // Set internal data pointers to point to the new data arrays
  2491. m_pUIMap = m_arrUIMap.m_aT;
  2492. m_pUIData = m_arrUIData.m_aT;
  2493. }
  2494. ~CDynamicUpdateUI()
  2495. {
  2496. for(int i = 0; i < m_arrUIData.GetSize(); i++)
  2497. {
  2498. if((m_arrUIData[i].m_wState & UPDUI_TEXT) != 0)
  2499. delete [] m_arrUIData[i].m_lpstrText;
  2500. }
  2501. // Reset internal data pointers (memory will be released by CSimpleArray d-tor)
  2502. m_pUIMap = NULL;
  2503. m_pUIData = NULL;
  2504. }
  2505. // Methods for dynamically adding and removing update elements
  2506. bool UIAddUpdateElement(WORD nID, WORD wType)
  2507. {
  2508. // check for duplicates
  2509. for(int i = 0; i < m_arrUIMap.GetSize(); i++)
  2510. {
  2511. // shouldn't have duplicates in the update UI map
  2512. ATLASSERT(m_arrUIMap[i].m_nID != nID);
  2513. if(m_arrUIMap[i].m_nID == nID)
  2514. return false;
  2515. }
  2516. bool bRetVal = false;
  2517. // Add new end element
  2518. _AtlUpdateUIMap uumEnd = { (WORD)-1, 0 };
  2519. BOOL bRet = m_arrUIMap.Add(uumEnd);
  2520. ATLASSERT(bRet);
  2521. if(bRet != FALSE)
  2522. {
  2523. _AtlUpdateUIData uud = { 0, NULL };
  2524. bRet = m_arrUIData.Add(uud);
  2525. ATLASSERT(bRet);
  2526. // Set new data to the previous end element
  2527. if(bRet != FALSE)
  2528. {
  2529. int nSize = m_arrUIMap.GetSize();
  2530. _AtlUpdateUIMap uum = { nID, wType };
  2531. m_arrUIMap.SetAtIndex(nSize - 2, uum);
  2532. m_arrUIData.SetAtIndex(nSize - 2, uud);
  2533. // Set internal data pointers again, just in case that memory moved
  2534. m_pUIMap = m_arrUIMap.m_aT;
  2535. m_pUIData = m_arrUIData.m_aT;
  2536. bRetVal = true;
  2537. }
  2538. }
  2539. return bRetVal;
  2540. }
  2541. bool UIRemoveUpdateElement(WORD nID)
  2542. {
  2543. bool bRetVal = false;
  2544. for(int i = 0; i < m_arrUIMap.GetSize(); i++)
  2545. {
  2546. if(m_arrUIMap[i].m_nID == nID)
  2547. {
  2548. BOOL bRet = m_arrUIMap.RemoveAt(i);
  2549. ATLASSERT(bRet);
  2550. bRet = m_arrUIData.RemoveAt(i);
  2551. ATLASSERT(bRet);
  2552. bRetVal = true;
  2553. break;
  2554. }
  2555. }
  2556. return bRetVal;
  2557. }
  2558. };
  2559. ///////////////////////////////////////////////////////////////////////////////
  2560. // CAutoUpdateUI : Automatic mapping of UI elements
  2561. template <class T>
  2562. class CAutoUpdateUI : public CDynamicUpdateUI<T>
  2563. {
  2564. public:
  2565. LPCTSTR UIGetText(int nID)
  2566. {
  2567. for(int i = 0; i < m_arrUIMap.GetSize(); i++)
  2568. {
  2569. if(m_arrUIMap[i].m_nID == nID)
  2570. return m_arrUIData[i].m_lpstrText;
  2571. }
  2572. return NULL;
  2573. }
  2574. // Element
  2575. template <WORD t_wType>
  2576. bool UIAddElement(UINT nID)
  2577. {
  2578. // check for existing UI map element
  2579. for(int i = 0; i < m_arrUIMap.GetSize(); i++)
  2580. {
  2581. if(m_arrUIMap[i].m_nID == nID)
  2582. {
  2583. // set requested type
  2584. m_arrUIMap[i].m_wType |= t_wType;
  2585. return true;
  2586. }
  2587. }
  2588. // Add element to UI map with requested type
  2589. return UIAddUpdateElement((WORD)nID, t_wType);
  2590. }
  2591. template <WORD t_wType>
  2592. bool UIRemoveElement(UINT nID)
  2593. {
  2594. for(int i = 0; i < m_arrUIMap.GetSize(); i++)
  2595. {
  2596. if(m_arrUIMap[i].m_nID == nID) // matching UI map element
  2597. {
  2598. WORD wType = m_arrUIMap[i].m_wType & ~t_wType;
  2599. if (wType) // has other types
  2600. {
  2601. m_arrUIMap[i].m_wType = wType; // keep other types
  2602. return true;
  2603. }
  2604. else
  2605. {
  2606. return UIRemoveUpdateElement((WORD)nID);
  2607. }
  2608. }
  2609. }
  2610. return false;
  2611. }
  2612. // Menu
  2613. bool UIAddMenu(HMENU hMenu, bool bSetText = false)
  2614. {
  2615. #if defined(_WIN32_WCE) && (_ATL_VER >= 0x0800)
  2616. using ATL::GetMenuString;
  2617. #endif
  2618. ATLASSERT(::IsMenu(hMenu));
  2619. MENUITEMINFO mii = {sizeof(MENUITEMINFO), MIIM_TYPE | MIIM_ID | MIIM_SUBMENU};
  2620. // Complete the UI map
  2621. for (INT uItem = 0; CMenuHandle(hMenu).GetMenuItemInfo(uItem, TRUE, &mii); uItem++)
  2622. {
  2623. if(mii.hSubMenu)
  2624. {
  2625. // Add submenu to UI map
  2626. UIAddMenu(mii.hSubMenu, bSetText);
  2627. }
  2628. else if (mii.wID)
  2629. {
  2630. // Add element to UI map
  2631. UIAddElement<UPDUI_MENUPOPUP>(mii.wID);
  2632. #if !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800)
  2633. if (bSetText)
  2634. {
  2635. TCHAR sText[64] = { 0 };
  2636. if (GetMenuString(hMenu, uItem, sText, 64, MF_BYPOSITION))
  2637. UISetText(mii.wID, sText);
  2638. }
  2639. #else
  2640. bSetText;
  2641. #endif // !defined(_WIN32_WCE) || (_ATL_VER >= 0x0800)
  2642. }
  2643. }
  2644. return true;
  2645. }
  2646. bool UIAddMenu(UINT uID, bool bSetText = false)
  2647. {
  2648. CMenu menu;
  2649. ATLVERIFY(menu.LoadMenu(uID));
  2650. return UIAddMenu(menu, bSetText);
  2651. }
  2652. // ToolBar
  2653. #ifndef BTNS_SEP
  2654. #define BTNS_SEP TBSTYLE_SEP
  2655. #endif // BTNS_SEP compatibility
  2656. #if !defined(_WIN32_WCE) || (defined(_AUTOUI_CE_TOOLBAR) && defined(TBIF_BYINDEX))
  2657. bool UIAddToolBar(HWND hWndToolBar)
  2658. {
  2659. ATLASSERT(::IsWindow(hWndToolBar));
  2660. TBBUTTONINFO tbbi = {sizeof TBBUTTONINFO, TBIF_COMMAND | TBIF_STYLE | TBIF_BYINDEX};
  2661. // Add toolbar buttons
  2662. for (int uItem = 0; ::SendMessage(hWndToolBar, TB_GETBUTTONINFO, uItem, (LPARAM)&tbbi) != -1; uItem++)
  2663. {
  2664. if (tbbi.fsStyle ^ BTNS_SEP)
  2665. UIAddElement<UPDUI_TOOLBAR>(tbbi.idCommand);
  2666. }
  2667. // Add embedded controls if any
  2668. if (::GetWindow(hWndToolBar, GW_CHILD))
  2669. UIAddChildWindowContainer(hWndToolBar);
  2670. return (CUpdateUIBase::UIAddToolBar(hWndToolBar) != FALSE);
  2671. }
  2672. #endif // !defined(_WIN32_WCE) || (defined(_AUTOUI_CE_TOOLBAR) && defined(TBIF_BYINDEX))
  2673. // Container
  2674. bool UIAddChildWindowContainer(HWND hWnd)
  2675. {
  2676. ATLASSERT(::IsWindow(hWnd));
  2677. // Add children controls if any
  2678. for (ATL::CWindow wCtl = ::GetWindow(hWnd, GW_CHILD); wCtl.IsWindow(); wCtl = wCtl.GetWindow(GW_HWNDNEXT))
  2679. {
  2680. if (int id = wCtl.GetDlgCtrlID())
  2681. UIAddElement<UPDUI_CHILDWINDOW>(id);
  2682. }
  2683. return (CUpdateUIBase::UIAddChildWindowContainer(hWnd) != FALSE);
  2684. }
  2685. // StatusBar
  2686. BOOL UIUpdateStatusBar(BOOL bForceUpdate = FALSE)
  2687. {
  2688. if(!(m_wDirtyType & UPDUI_STATUSBAR) && !bForceUpdate)
  2689. return TRUE;
  2690. for(int i = 0; i < m_arrUIMap.GetSize(); i++)
  2691. {
  2692. for(int e = 0; e < m_UIElements.GetSize(); e++)
  2693. {
  2694. if((m_UIElements[e].m_wType == UPDUI_STATUSBAR) &&
  2695. (m_arrUIMap[i].m_wType & UPDUI_STATUSBAR) &&
  2696. (m_arrUIData[i].m_wState & UPDUI_STATUSBAR))
  2697. {
  2698. UIUpdateStatusBarElement(m_arrUIMap[i].m_nID, &m_arrUIData[i], m_UIElements[e].m_hWnd);
  2699. m_arrUIData[i].m_wState &= ~UPDUI_STATUSBAR;
  2700. if(m_arrUIData[i].m_wState & UPDUI_TEXT)
  2701. m_arrUIData[i].m_wState &= ~UPDUI_TEXT;
  2702. }
  2703. }
  2704. }
  2705. m_wDirtyType &= ~UPDUI_STATUSBAR;
  2706. return TRUE;
  2707. }
  2708. bool UIAddStatusBar(HWND hWndStatusBar, INT nPanes = 1)
  2709. {
  2710. ATLASSERT(::IsWindow(hWndStatusBar));
  2711. // Add StatusBar panes
  2712. for (int iPane = 0; iPane < nPanes; iPane++)
  2713. UIAddElement<UPDUI_STATUSBAR>(ID_DEFAULT_PANE + iPane);
  2714. return (CUpdateUIBase::UIAddStatusBar(hWndStatusBar) != FALSE);
  2715. }
  2716. // UI Map used if derived class has none
  2717. BEGIN_UPDATE_UI_MAP(CAutoUpdateUI)
  2718. END_UPDATE_UI_MAP()
  2719. };
  2720. ///////////////////////////////////////////////////////////////////////////////
  2721. // CDialogResize - provides support for resizing dialog controls
  2722. // (works for any window that has child controls)
  2723. // Put CDialogResize in the list of base classes for a dialog (or even plain window),
  2724. // then implement DLGRESIZE map by specifying controls and groups of control
  2725. // and using DLSZ_* values to specify how are they supposed to be resized.
  2726. //
  2727. // Notes:
  2728. // - Resizeable border (WS_THICKFRAME style) should be set in the dialog template
  2729. // for top level dialogs (popup or overlapped), so that users can resize the dialog.
  2730. // - Some flags cannot be combined; for instance DLSZ_CENTER_X overrides DLSZ_SIZE_X,
  2731. // DLSZ_SIZE_X overrides DLSZ_MOVE_X. X and Y flags can be combined.
  2732. // - Order of controls is important - group controls are resized and moved based
  2733. // on the position of the previous control in a group.
  2734. // dialog resize map macros
  2735. #define BEGIN_DLGRESIZE_MAP(thisClass) \
  2736. static const _AtlDlgResizeMap* GetDlgResizeMap() \
  2737. { \
  2738. static const _AtlDlgResizeMap theMap[] = \
  2739. {
  2740. #define END_DLGRESIZE_MAP() \
  2741. { -1, 0 }, \
  2742. }; \
  2743. return theMap; \
  2744. }
  2745. #define DLGRESIZE_CONTROL(id, flags) \
  2746. { id, flags },
  2747. #define BEGIN_DLGRESIZE_GROUP() \
  2748. { -1, _DLSZ_BEGIN_GROUP },
  2749. #define END_DLGRESIZE_GROUP() \
  2750. { -1, _DLSZ_END_GROUP },
  2751. template <class T>
  2752. class CDialogResize
  2753. {
  2754. public:
  2755. // Data declarations and members
  2756. enum
  2757. {
  2758. DLSZ_SIZE_X = 0x00000001,
  2759. DLSZ_SIZE_Y = 0x00000002,
  2760. DLSZ_MOVE_X = 0x00000004,
  2761. DLSZ_MOVE_Y = 0x00000008,
  2762. DLSZ_REPAINT = 0x00000010,
  2763. DLSZ_CENTER_X = 0x00000020,
  2764. DLSZ_CENTER_Y = 0x00000040,
  2765. // internal use only
  2766. _DLSZ_BEGIN_GROUP = 0x00001000,
  2767. _DLSZ_END_GROUP = 0x00002000,
  2768. _DLSZ_GRIPPER = 0x00004000
  2769. };
  2770. struct _AtlDlgResizeMap
  2771. {
  2772. int m_nCtlID;
  2773. DWORD m_dwResizeFlags;
  2774. };
  2775. struct _AtlDlgResizeData
  2776. {
  2777. int m_nCtlID;
  2778. DWORD m_dwResizeFlags;
  2779. RECT m_rect;
  2780. int GetGroupCount() const
  2781. {
  2782. return (int)LOBYTE(HIWORD(m_dwResizeFlags));
  2783. }
  2784. void SetGroupCount(int nCount)
  2785. {
  2786. ATLASSERT(nCount > 0 && nCount < 256);
  2787. DWORD dwCount = (DWORD)MAKELONG(0, MAKEWORD(nCount, 0));
  2788. m_dwResizeFlags &= 0xFF00FFFF;
  2789. m_dwResizeFlags |= dwCount;
  2790. }
  2791. bool operator ==(const _AtlDlgResizeData& r) const
  2792. { return (m_nCtlID == r.m_nCtlID && m_dwResizeFlags == r.m_dwResizeFlags); }
  2793. };
  2794. ATL::CSimpleArray<_AtlDlgResizeData> m_arrData;
  2795. SIZE m_sizeDialog;
  2796. POINT m_ptMinTrackSize;
  2797. bool m_bGripper;
  2798. // Constructor
  2799. CDialogResize() : m_bGripper(false)
  2800. {
  2801. m_sizeDialog.cx = 0;
  2802. m_sizeDialog.cy = 0;
  2803. m_ptMinTrackSize.x = -1;
  2804. m_ptMinTrackSize.y = -1;
  2805. }
  2806. // Operations
  2807. void DlgResize_Init(bool bAddGripper = true, bool bUseMinTrackSize = true, DWORD dwForceStyle = WS_CLIPCHILDREN)
  2808. {
  2809. T* pT = static_cast<T*>(this);
  2810. ATLASSERT(::IsWindow(pT->m_hWnd));
  2811. DWORD dwStyle = pT->GetStyle();
  2812. #ifdef _DEBUG
  2813. // Debug only: Check if top level dialogs have a resizeable border.
  2814. if(((dwStyle & WS_CHILD) == 0) && ((dwStyle & WS_THICKFRAME) == 0))
  2815. ATLTRACE2(atlTraceUI, 0, _T("DlgResize_Init - warning: top level dialog without the WS_THICKFRAME style - user cannot resize it\n"));
  2816. #endif // _DEBUG
  2817. // Force specified styles (default WS_CLIPCHILDREN reduces flicker)
  2818. if((dwStyle & dwForceStyle) != dwForceStyle)
  2819. pT->ModifyStyle(0, dwForceStyle);
  2820. // Adding this style removes an empty icon that dialogs with WS_THICKFRAME have.
  2821. // Setting icon to NULL is required when XP themes are active.
  2822. // Note: This will not prevent adding an icon for the dialog using SetIcon()
  2823. if((dwStyle & WS_CHILD) == 0)
  2824. {
  2825. pT->ModifyStyleEx(0, WS_EX_DLGMODALFRAME);
  2826. if(pT->GetIcon(FALSE) == NULL)
  2827. pT->SetIcon(NULL, FALSE);
  2828. }
  2829. // Cleanup in case of multiple initialization
  2830. // block: first check for the gripper control, destroy it if needed
  2831. {
  2832. ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR);
  2833. if(wndGripper.IsWindow() && m_arrData.GetSize() > 0 && (m_arrData[0].m_dwResizeFlags & _DLSZ_GRIPPER) != 0)
  2834. wndGripper.DestroyWindow();
  2835. }
  2836. // clear out everything else
  2837. m_arrData.RemoveAll();
  2838. m_sizeDialog.cx = 0;
  2839. m_sizeDialog.cy = 0;
  2840. m_ptMinTrackSize.x = -1;
  2841. m_ptMinTrackSize.y = -1;
  2842. // Get initial dialog client size
  2843. RECT rectDlg = { 0 };
  2844. pT->GetClientRect(&rectDlg);
  2845. m_sizeDialog.cx = rectDlg.right;
  2846. m_sizeDialog.cy = rectDlg.bottom;
  2847. #ifndef _WIN32_WCE
  2848. // Create gripper if requested
  2849. m_bGripper = false;
  2850. if(bAddGripper)
  2851. {
  2852. // shouldn't exist already
  2853. ATLASSERT(!::IsWindow(pT->GetDlgItem(ATL_IDW_STATUS_BAR)));
  2854. if(!::IsWindow(pT->GetDlgItem(ATL_IDW_STATUS_BAR)))
  2855. {
  2856. ATL::CWindow wndGripper;
  2857. wndGripper.Create(_T("SCROLLBAR"), pT->m_hWnd, rectDlg, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SBS_SIZEBOX | SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN, 0, ATL_IDW_STATUS_BAR);
  2858. ATLASSERT(wndGripper.IsWindow());
  2859. if(wndGripper.IsWindow())
  2860. {
  2861. m_bGripper = true;
  2862. RECT rectCtl = { 0 };
  2863. wndGripper.GetWindowRect(&rectCtl);
  2864. ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2);
  2865. _AtlDlgResizeData data = { ATL_IDW_STATUS_BAR, DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT | _DLSZ_GRIPPER, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } };
  2866. m_arrData.Add(data);
  2867. }
  2868. }
  2869. }
  2870. #else // CE specific
  2871. bAddGripper; // avoid level 4 warning
  2872. #endif // _WIN32_WCE
  2873. // Get min track position if requested
  2874. if(bUseMinTrackSize)
  2875. {
  2876. if((dwStyle & WS_CHILD) != 0)
  2877. {
  2878. RECT rect = { 0 };
  2879. pT->GetClientRect(&rect);
  2880. m_ptMinTrackSize.x = rect.right - rect.left;
  2881. m_ptMinTrackSize.y = rect.bottom - rect.top;
  2882. }
  2883. else
  2884. {
  2885. RECT rect = { 0 };
  2886. pT->GetWindowRect(&rect);
  2887. m_ptMinTrackSize.x = rect.right - rect.left;
  2888. m_ptMinTrackSize.y = rect.bottom - rect.top;
  2889. }
  2890. }
  2891. // Walk the map and initialize data
  2892. const _AtlDlgResizeMap* pMap = pT->GetDlgResizeMap();
  2893. ATLASSERT(pMap != NULL);
  2894. int nGroupStart = -1;
  2895. for(int nCount = 1; !(pMap->m_nCtlID == -1 && pMap->m_dwResizeFlags == 0); nCount++, pMap++)
  2896. {
  2897. if(pMap->m_nCtlID == -1)
  2898. {
  2899. switch(pMap->m_dwResizeFlags)
  2900. {
  2901. case _DLSZ_BEGIN_GROUP:
  2902. ATLASSERT(nGroupStart == -1);
  2903. nGroupStart = m_arrData.GetSize();
  2904. break;
  2905. case _DLSZ_END_GROUP:
  2906. {
  2907. ATLASSERT(nGroupStart != -1);
  2908. int nGroupCount = m_arrData.GetSize() - nGroupStart;
  2909. m_arrData[nGroupStart].SetGroupCount(nGroupCount);
  2910. nGroupStart = -1;
  2911. }
  2912. break;
  2913. default:
  2914. ATLASSERT(FALSE && _T("Invalid DLGRESIZE Map Entry"));
  2915. break;
  2916. }
  2917. }
  2918. else
  2919. {
  2920. // this ID conflicts with the default gripper one
  2921. ATLASSERT(m_bGripper ? (pMap->m_nCtlID != ATL_IDW_STATUS_BAR) : TRUE);
  2922. ATL::CWindow ctl = pT->GetDlgItem(pMap->m_nCtlID);
  2923. ATLASSERT(ctl.IsWindow());
  2924. RECT rectCtl = { 0 };
  2925. ctl.GetWindowRect(&rectCtl);
  2926. ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2);
  2927. DWORD dwGroupFlag = (nGroupStart != -1 && m_arrData.GetSize() == nGroupStart) ? _DLSZ_BEGIN_GROUP : 0;
  2928. _AtlDlgResizeData data = { pMap->m_nCtlID, pMap->m_dwResizeFlags | dwGroupFlag, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } };
  2929. m_arrData.Add(data);
  2930. }
  2931. }
  2932. ATLASSERT((nGroupStart == -1) && _T("No End Group Entry in the DLGRESIZE Map"));
  2933. }
  2934. void DlgResize_UpdateLayout(int cxWidth, int cyHeight)
  2935. {
  2936. T* pT = static_cast<T*>(this);
  2937. ATLASSERT(::IsWindow(pT->m_hWnd));
  2938. // Restrict minimum size if requested
  2939. if(((pT->GetStyle() & WS_CHILD) != 0) && m_ptMinTrackSize.x != -1 && m_ptMinTrackSize.y != -1)
  2940. {
  2941. if(cxWidth < m_ptMinTrackSize.x)
  2942. cxWidth = m_ptMinTrackSize.x;
  2943. if(cyHeight < m_ptMinTrackSize.y)
  2944. cyHeight = m_ptMinTrackSize.y;
  2945. }
  2946. BOOL bVisible = pT->IsWindowVisible();
  2947. if(bVisible)
  2948. pT->SetRedraw(FALSE);
  2949. for(int i = 0; i < m_arrData.GetSize(); i++)
  2950. {
  2951. if((m_arrData[i].m_dwResizeFlags & _DLSZ_BEGIN_GROUP) != 0) // start of a group
  2952. {
  2953. int nGroupCount = m_arrData[i].GetGroupCount();
  2954. ATLASSERT(nGroupCount > 0 && i + nGroupCount - 1 < m_arrData.GetSize());
  2955. RECT rectGroup = m_arrData[i].m_rect;
  2956. int j = 1;
  2957. for(j = 1; j < nGroupCount; j++)
  2958. {
  2959. rectGroup.left = min(rectGroup.left, m_arrData[i + j].m_rect.left);
  2960. rectGroup.top = min(rectGroup.top, m_arrData[i + j].m_rect.top);
  2961. rectGroup.right = max(rectGroup.right, m_arrData[i + j].m_rect.right);
  2962. rectGroup.bottom = max(rectGroup.bottom, m_arrData[i + j].m_rect.bottom);
  2963. }
  2964. for(j = 0; j < nGroupCount; j++)
  2965. {
  2966. _AtlDlgResizeData* pDataPrev = NULL;
  2967. if(j > 0)
  2968. pDataPrev = &(m_arrData[i + j - 1]);
  2969. pT->DlgResize_PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i + j], true, pDataPrev);
  2970. }
  2971. i += nGroupCount - 1; // increment to skip all group controls
  2972. }
  2973. else // one control entry
  2974. {
  2975. RECT rectGroup = { 0, 0, 0, 0 };
  2976. pT->DlgResize_PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i], false);
  2977. }
  2978. }
  2979. if(bVisible)
  2980. pT->SetRedraw(TRUE);
  2981. pT->RedrawWindow(NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
  2982. }
  2983. // Message map and handlers
  2984. BEGIN_MSG_MAP(CDialogResize)
  2985. MESSAGE_HANDLER(WM_SIZE, OnSize)
  2986. #ifndef _WIN32_WCE
  2987. MESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo)
  2988. #endif // _WIN32_WCE
  2989. END_MSG_MAP()
  2990. LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  2991. {
  2992. T* pT = static_cast<T*>(this);
  2993. #ifndef _WIN32_WCE
  2994. if(m_bGripper)
  2995. {
  2996. ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR);
  2997. if(wParam == SIZE_MAXIMIZED)
  2998. wndGripper.ShowWindow(SW_HIDE);
  2999. else if(wParam == SIZE_RESTORED)
  3000. wndGripper.ShowWindow(SW_SHOW);
  3001. }
  3002. #endif // _WIN32_WCE
  3003. if(wParam != SIZE_MINIMIZED)
  3004. {
  3005. ATLASSERT(::IsWindow(pT->m_hWnd));
  3006. pT->DlgResize_UpdateLayout(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
  3007. }
  3008. return 0;
  3009. }
  3010. #ifndef _WIN32_WCE
  3011. LRESULT OnGetMinMaxInfo(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
  3012. {
  3013. if(m_ptMinTrackSize.x != -1 && m_ptMinTrackSize.y != -1)
  3014. {
  3015. LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam;
  3016. lpMMI->ptMinTrackSize = m_ptMinTrackSize;
  3017. }
  3018. return 0;
  3019. }
  3020. #endif // _WIN32_WCE
  3021. // Implementation
  3022. bool DlgResize_PositionControl(int cxWidth, int cyHeight, RECT& rectGroup, _AtlDlgResizeData& data, bool bGroup,
  3023. _AtlDlgResizeData* pDataPrev = NULL)
  3024. {
  3025. T* pT = static_cast<T*>(this);
  3026. ATLASSERT(::IsWindow(pT->m_hWnd));
  3027. ATL::CWindow ctl;
  3028. RECT rectCtl = { 0 };
  3029. ctl = pT->GetDlgItem(data.m_nCtlID);
  3030. if(!ctl.GetWindowRect(&rectCtl))
  3031. return false;
  3032. ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2);
  3033. if(bGroup)
  3034. {
  3035. if((data.m_dwResizeFlags & DLSZ_CENTER_X) != 0)
  3036. {
  3037. int cxRight = rectGroup.right + cxWidth - m_sizeDialog.cx;
  3038. int cxCtl = data.m_rect.right - data.m_rect.left;
  3039. rectCtl.left = rectGroup.left + (cxRight - rectGroup.left - cxCtl) / 2;
  3040. rectCtl.right = rectCtl.left + cxCtl;
  3041. }
  3042. else if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0)
  3043. {
  3044. rectCtl.left = rectGroup.left + ::MulDiv(data.m_rect.left - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left);
  3045. if((data.m_dwResizeFlags & DLSZ_SIZE_X) != 0)
  3046. {
  3047. rectCtl.right = rectGroup.left + ::MulDiv(data.m_rect.right - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left);
  3048. if(pDataPrev != NULL)
  3049. {
  3050. ATL::CWindow ctlPrev = pT->GetDlgItem(pDataPrev->m_nCtlID);
  3051. RECT rcPrev = { 0 };
  3052. ctlPrev.GetWindowRect(&rcPrev);
  3053. ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcPrev, 2);
  3054. int dxAdjust = (rectCtl.left - rcPrev.right) - (data.m_rect.left - pDataPrev->m_rect.right);
  3055. rcPrev.right += dxAdjust;
  3056. ctlPrev.SetWindowPos(NULL, &rcPrev, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);
  3057. }
  3058. }
  3059. else
  3060. {
  3061. rectCtl.right = rectCtl.left + (data.m_rect.right - data.m_rect.left);
  3062. }
  3063. }
  3064. if((data.m_dwResizeFlags & DLSZ_CENTER_Y) != 0)
  3065. {
  3066. int cyBottom = rectGroup.bottom + cyHeight - m_sizeDialog.cy;
  3067. int cyCtl = data.m_rect.bottom - data.m_rect.top;
  3068. rectCtl.top = rectGroup.top + (cyBottom - rectGroup.top - cyCtl) / 2;
  3069. rectCtl.bottom = rectCtl.top + cyCtl;
  3070. }
  3071. else if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0)
  3072. {
  3073. rectCtl.top = rectGroup.top + ::MulDiv(data.m_rect.top - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top);
  3074. if((data.m_dwResizeFlags & DLSZ_SIZE_Y) != 0)
  3075. {
  3076. rectCtl.bottom = rectGroup.top + ::MulDiv(data.m_rect.bottom - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top);
  3077. if(pDataPrev != NULL)
  3078. {
  3079. ATL::CWindow ctlPrev = pT->GetDlgItem(pDataPrev->m_nCtlID);
  3080. RECT rcPrev = { 0 };
  3081. ctlPrev.GetWindowRect(&rcPrev);
  3082. ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcPrev, 2);
  3083. int dxAdjust = (rectCtl.top - rcPrev.bottom) - (data.m_rect.top - pDataPrev->m_rect.bottom);
  3084. rcPrev.bottom += dxAdjust;
  3085. ctlPrev.SetWindowPos(NULL, &rcPrev, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);
  3086. }
  3087. }
  3088. else
  3089. {
  3090. rectCtl.bottom = rectCtl.top + (data.m_rect.bottom - data.m_rect.top);
  3091. }
  3092. }
  3093. }
  3094. else // no group
  3095. {
  3096. if((data.m_dwResizeFlags & DLSZ_CENTER_X) != 0)
  3097. {
  3098. int cxCtl = data.m_rect.right - data.m_rect.left;
  3099. rectCtl.left = (cxWidth - cxCtl) / 2;
  3100. rectCtl.right = rectCtl.left + cxCtl;
  3101. }
  3102. else if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0)
  3103. {
  3104. rectCtl.right = data.m_rect.right + (cxWidth - m_sizeDialog.cx);
  3105. if((data.m_dwResizeFlags & DLSZ_MOVE_X) != 0)
  3106. rectCtl.left = rectCtl.right - (data.m_rect.right - data.m_rect.left);
  3107. }
  3108. if((data.m_dwResizeFlags & DLSZ_CENTER_Y) != 0)
  3109. {
  3110. int cyCtl = data.m_rect.bottom - data.m_rect.top;
  3111. rectCtl.top = (cyHeight - cyCtl) / 2;
  3112. rectCtl.bottom = rectCtl.top + cyCtl;
  3113. }
  3114. else if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0)
  3115. {
  3116. rectCtl.bottom = data.m_rect.bottom + (cyHeight - m_sizeDialog.cy);
  3117. if((data.m_dwResizeFlags & DLSZ_MOVE_Y) != 0)
  3118. rectCtl.top = rectCtl.bottom - (data.m_rect.bottom - data.m_rect.top);
  3119. }
  3120. }
  3121. if((data.m_dwResizeFlags & DLSZ_REPAINT) != 0)
  3122. ctl.Invalidate();
  3123. if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_SIZE_Y | DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT | DLSZ_CENTER_X | DLSZ_CENTER_Y)) != 0)
  3124. ctl.SetWindowPos(NULL, &rectCtl, SWP_NOZORDER | SWP_NOACTIVATE);
  3125. return true;
  3126. }
  3127. };
  3128. ///////////////////////////////////////////////////////////////////////////////
  3129. // CDoubleBufferImpl - Provides double-buffer painting support to any window
  3130. template <class T>
  3131. class CDoubleBufferImpl
  3132. {
  3133. public:
  3134. // Overrideables
  3135. void DoPaint(CDCHandle /*dc*/)
  3136. {
  3137. // must be implemented in a derived class
  3138. ATLASSERT(FALSE);
  3139. }
  3140. // Message map and handlers
  3141. BEGIN_MSG_MAP(CDoubleBufferImpl)
  3142. MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
  3143. MESSAGE_HANDLER(WM_PAINT, OnPaint)
  3144. #ifndef _WIN32_WCE
  3145. MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
  3146. #endif // !_WIN32_WCE
  3147. END_MSG_MAP()
  3148. LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  3149. {
  3150. return 1; // no background painting needed
  3151. }
  3152. LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  3153. {
  3154. T* pT = static_cast<T*>(this);
  3155. ATLASSERT(::IsWindow(pT->m_hWnd));
  3156. if(wParam != NULL)
  3157. {
  3158. RECT rect = { 0 };
  3159. pT->GetClientRect(&rect);
  3160. CMemoryDC dcMem((HDC)wParam, rect);
  3161. pT->DoPaint(dcMem.m_hDC);
  3162. }
  3163. else
  3164. {
  3165. CPaintDC dc(pT->m_hWnd);
  3166. CMemoryDC dcMem(dc.m_hDC, dc.m_ps.rcPaint);
  3167. pT->DoPaint(dcMem.m_hDC);
  3168. }
  3169. return 0;
  3170. }
  3171. };
  3172. ///////////////////////////////////////////////////////////////////////////////
  3173. // CDoubleBufferWindowImpl - Implements a double-buffer painting window
  3174. template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
  3175. class ATL_NO_VTABLE CDoubleBufferWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CDoubleBufferImpl< T >
  3176. {
  3177. public:
  3178. BEGIN_MSG_MAP(CDoubleBufferWindowImpl)
  3179. CHAIN_MSG_MAP(CDoubleBufferImpl< T >)
  3180. END_MSG_MAP()
  3181. };
  3182. // command bar support
  3183. #if !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE)
  3184. #undef CBRM_GETMENU
  3185. #undef CBRM_TRACKPOPUPMENU
  3186. #undef CBRM_GETCMDBAR
  3187. #undef CBRPOPUPMENU
  3188. #endif // !defined(__ATLCTRLW_H__) && !defined(_WIN32_WCE)
  3189. }; // namespace WTL
  3190. #endif // __ATLFRAME_H__