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