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