crashrpt
atlctrlw.h
1 // Windows Template Library - WTL version 8.1
2 // Copyright (C) Microsoft Corporation. All rights reserved.
3 //
4 // This file is a part of the Windows Template Library.
5 // The use and distribution terms for this software are covered by the
6 // Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
7 // which can be found in the file CPL.TXT at the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by
9 // the terms of this license. You must not remove this notice, or
10 // any other, from this software.
11 
12 #ifndef __ATLCTRLW_H__
13 #define __ATLCTRLW_H__
14 
15 #pragma once
16 
17 #ifdef _WIN32_WCE
18  #error atlctrlw.h is not supported on Windows CE
19 #endif
20 
21 #ifndef __ATLAPP_H__
22  #error atlctrlw.h requires atlapp.h to be included first
23 #endif
24 
25 #ifndef __ATLCTRLS_H__
26  #error atlctrlw.h requires atlctrls.h to be included first
27 #endif
28 
29 #if (_WIN32_IE < 0x0400)
30  #error atlctrlw.h requires _WIN32_IE >= 0x0400
31 #endif
32 
33 // Define _WTL_CMDBAR_VISTA_MENUS as 0 to exclude Vista menus support
34 #if !defined(_WTL_CMDBAR_VISTA_MENUS) && (WINVER >= 0x0500) && (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)
35  #define _WTL_CMDBAR_VISTA_MENUS 1
36 #endif
37 
38 #if _WTL_CMDBAR_VISTA_MENUS
39  #if !((_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501))
40  #error _WTL_CMDBAR_VISTA_MENUS requires (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)
41  #endif
42 #endif
43 
44 
46 // Classes in this file:
47 //
48 // CCommandBarCtrlImpl<T, TBase, TWinTraits>
49 // CCommandBarCtrl
50 // CMDICommandBarCtrlImpl<T, TBase, TWinTraits>
51 // CMDICommandBarCtrl
52 
53 
54 namespace WTL
55 {
56 
58 // Command Bars
59 
60 // Window Styles:
61 #define CBRWS_TOP CCS_TOP
62 #define CBRWS_BOTTOM CCS_BOTTOM
63 #define CBRWS_NORESIZE CCS_NORESIZE
64 #define CBRWS_NOPARENTALIGN CCS_NOPARENTALIGN
65 #define CBRWS_NODIVIDER CCS_NODIVIDER
66 
67 // Extended styles
68 #define CBR_EX_TRANSPARENT 0x00000001L
69 #define CBR_EX_SHAREMENU 0x00000002L
70 #define CBR_EX_ALTFOCUSMODE 0x00000004L
71 #define CBR_EX_TRACKALWAYS 0x00000008L
72 #define CBR_EX_NOVISTAMENUS 0x00000010L
73 
74 // standard command bar styles
75 #define ATL_SIMPLE_CMDBAR_PANE_STYLE \
76  (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CBRWS_NODIVIDER | CBRWS_NORESIZE | CBRWS_NOPARENTALIGN)
77 
78 // Messages - support chevrons for frame windows
79 #define CBRM_GETCMDBAR (WM_USER + 301) // returns command bar HWND
80 #define CBRM_GETMENU (WM_USER + 302) // returns loaded or attached menu
81 #define CBRM_TRACKPOPUPMENU (WM_USER + 303) // displays a popup menu
82 
83 typedef struct tagCBRPOPUPMENU
84 {
85  int cbSize;
86  HMENU hMenu; // popup menu do display
87  UINT uFlags; // TPM_* flags for ::TrackPopupMenuEx
88  int x;
89  int y;
90  LPTPMPARAMS lptpm; // ptr to TPMPARAMS for ::TrackPopupMenuEx
92 
93 // helper class
94 template <class T>
95 class CSimpleStack : public ATL::CSimpleArray< T >
96 {
97 public:
98  BOOL Push(T t)
99  {
100 #ifdef _CMDBAR_EXTRA_TRACE
101  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - STACK-PUSH (%8.8X) size = %i\n"), t, GetSize());
102 #endif
103  return Add(t);
104  }
105 
106  T Pop()
107  {
108  int nLast = GetSize() - 1;
109  if(nLast < 0)
110  return NULL; // must be able to convert to NULL
111  T t = m_aT[nLast];
112 #ifdef _CMDBAR_EXTRA_TRACE
113  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - STACK-POP (%8.8X) size = %i\n"), t, GetSize());
114 #endif
115  if(!RemoveAt(nLast))
116  return NULL;
117  return t;
118  }
119 
120  T GetCurrent()
121  {
122  int nLast = GetSize() - 1;
123  if(nLast < 0)
124  return NULL; // must be able to convert to NULL
125  return m_aT[nLast];
126  }
127 };
128 
129 
131 // CCommandBarCtrlBase - base class for the Command Bar implementation
132 
134 {
135 public:
137  {
138  HHOOK hMsgHook;
139  DWORD dwUsage;
140 
141  _MsgHookData() : hMsgHook(NULL), dwUsage(0)
142  { }
143  };
144 
145  typedef ATL::CSimpleMap<DWORD, _MsgHookData*> CMsgHookMap;
146  static CMsgHookMap* s_pmapMsgHook;
147 
148  static HHOOK s_hCreateHook;
149  static bool s_bW2K; // For animation flag
150  static CCommandBarCtrlBase* s_pCurrentBar;
151  static bool s_bStaticInit;
152 
153  CSimpleStack<HWND> m_stackMenuWnd;
154  CSimpleStack<HMENU> m_stackMenuHandle;
155 
156  HWND m_hWndHook;
157  DWORD m_dwMagic;
158 
159 
160  CCommandBarCtrlBase() : m_hWndHook(NULL), m_dwMagic(1314)
161  {
162  // init static variables
163  if(!s_bStaticInit)
164  {
166  if(FAILED(lock.Lock()))
167  {
168  ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlBase::CCommandBarCtrlBase.\n"));
169  ATLASSERT(FALSE);
170  return;
171  }
172 
173  if(!s_bStaticInit)
174  {
175  // Just in case...
176  AtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES);
177  // Animation on Win2000 only
178  s_bW2K = !AtlIsOldWindows();
179  // done
180  s_bStaticInit = true;
181  }
182 
183  lock.Unlock();
184  }
185  }
186 
187  bool IsCommandBarBase() const { return m_dwMagic == 1314; }
188 };
189 
190 __declspec(selectany) CCommandBarCtrlBase::CMsgHookMap* CCommandBarCtrlBase::s_pmapMsgHook = NULL;
191 __declspec(selectany) HHOOK CCommandBarCtrlBase::s_hCreateHook = NULL;
192 __declspec(selectany) CCommandBarCtrlBase* CCommandBarCtrlBase::s_pCurrentBar = NULL;
193 __declspec(selectany) bool CCommandBarCtrlBase::s_bW2K = false;
194 __declspec(selectany) bool CCommandBarCtrlBase::s_bStaticInit = false;
195 
196 
198 // CCommandBarCtrl - ATL implementation of Command Bars
199 
200 template <class T, class TBase = CCommandBarCtrlBase, class TWinTraits = ATL::CControlWinTraits>
201 class ATL_NO_VTABLE CCommandBarCtrlImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >
202 {
203 public:
204  DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())
205 
206 // Declarations
207  struct _MenuItemData // menu item data
208  {
209  DWORD dwMagic;
210  LPTSTR lpstrText;
211  UINT fType;
212  UINT fState;
213  int iButton;
214 
215  _MenuItemData() { dwMagic = 0x1313; }
216  bool IsCmdBarMenuItem() { return (dwMagic == 0x1313); }
217  };
218 
219  struct _ToolBarData // toolbar resource data
220  {
221  WORD wVersion;
222  WORD wWidth;
223  WORD wHeight;
224  WORD wItemCount;
225  //WORD aItems[wItemCount]
226 
227  WORD* items()
228  { return (WORD*)(this+1); }
229  };
230 
231 // Constants
232  enum _CmdBarDrawConstants
233  {
234  s_kcxGap = 1,
235  s_kcxTextMargin = 2,
236  s_kcxButtonMargin = 3,
237  s_kcyButtonMargin = 3
238  };
239 
240  enum
241  {
242  _nMaxMenuItemTextLength = 100,
243  _chChevronShortcut = _T('/')
244  };
245 
246 #ifndef DT_HIDEPREFIX
247  enum { DT_HIDEPREFIX = 0x00100000 };
248 #endif // !DT_HIDEPREFIX
249 
250 // Data members
251  HMENU m_hMenu;
252  HIMAGELIST m_hImageList;
253  ATL::CSimpleValArray<WORD> m_arrCommand;
254 
255  DWORD m_dwExtendedStyle; // Command Bar specific extended styles
256 
257  ATL::CContainedWindow m_wndParent;
258 
259  bool m_bMenuActive:1;
260  bool m_bAttachedMenu:1;
261  bool m_bImagesVisible:1;
262  bool m_bPopupItem:1;
263  bool m_bContextMenu:1;
264  bool m_bEscapePressed:1;
265  bool m_bSkipMsg:1;
266  bool m_bParentActive:1;
267  bool m_bFlatMenus:1;
268  bool m_bUseKeyboardCues:1;
269  bool m_bShowKeyboardCues:1;
270  bool m_bAllowKeyboardCues:1;
271  bool m_bKeyboardInput:1;
272  bool m_bAlphaImages:1;
273  bool m_bLayoutRTL:1;
274  bool m_bSkipPostDown:1;
275  bool m_bVistaMenus:1;
276 
277  int m_nPopBtn;
278  int m_nNextPopBtn;
279 
280  SIZE m_szBitmap;
281  SIZE m_szButton;
282 
283  COLORREF m_clrMask;
284  CFont m_fontMenu; // used internally, only to measure text
285 
286  UINT m_uSysKey;
287 
288  HWND m_hWndFocus; // Alternate focus mode
289 
290  int m_cxExtraSpacing;
291 
292 #if _WTL_CMDBAR_VISTA_MENUS
293  ATL::CSimpleValArray<HBITMAP> m_arrVistaBitmap; // Bitmaps for Vista menus
294 #endif // _WTL_CMDBAR_VISTA_MENUS
295 
296 // Constructor/destructor
298  m_hMenu(NULL),
299  m_hImageList(NULL),
300  m_wndParent(this, 1),
301  m_bMenuActive(false),
302  m_bAttachedMenu(false),
303  m_nPopBtn(-1),
304  m_nNextPopBtn(-1),
305  m_bPopupItem(false),
306  m_bImagesVisible(true),
307  m_bSkipMsg(false),
308  m_uSysKey(0),
309  m_hWndFocus(NULL),
310  m_bContextMenu(false),
311  m_bEscapePressed(false),
312  m_clrMask(RGB(192, 192, 192)),
313  m_dwExtendedStyle(CBR_EX_TRANSPARENT | CBR_EX_SHAREMENU | CBR_EX_TRACKALWAYS),
314  m_bParentActive(true),
315  m_bFlatMenus(false),
316  m_bUseKeyboardCues(false),
317  m_bShowKeyboardCues(false),
318  m_bAllowKeyboardCues(true),
319  m_bKeyboardInput(false),
320  m_cxExtraSpacing(0),
321  m_bAlphaImages(false),
322  m_bLayoutRTL(false),
323  m_bSkipPostDown(false),
324  m_bVistaMenus(false)
325  {
326  SetImageSize(16, 15); // default
327  }
328 
330  {
331  if(m_wndParent.IsWindow())
332 /*scary!*/ m_wndParent.UnsubclassWindow();
333 
334  if(m_hMenu != NULL && (m_dwExtendedStyle & CBR_EX_SHAREMENU) == 0)
335  ::DestroyMenu(m_hMenu);
336 
337  if(m_hImageList != NULL)
338  ::ImageList_Destroy(m_hImageList);
339  }
340 
341 // Attributes
342  DWORD GetCommandBarExtendedStyle() const
343  {
344  return m_dwExtendedStyle;
345  }
346 
347  DWORD SetCommandBarExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
348  {
349  DWORD dwPrevStyle = m_dwExtendedStyle;
350  if(dwMask == 0)
351  m_dwExtendedStyle = dwExtendedStyle;
352  else
353  m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
354  return dwPrevStyle;
355  }
356 
357  CMenuHandle GetMenu() const
358  {
359  ATLASSERT(::IsWindow(m_hWnd));
360  return m_hMenu;
361  }
362 
363  COLORREF GetImageMaskColor() const
364  {
365  return m_clrMask;
366  }
367 
368  COLORREF SetImageMaskColor(COLORREF clrMask)
369  {
370  COLORREF clrOld = m_clrMask;
371  m_clrMask = clrMask;
372  return clrOld;
373  }
374 
375  bool GetImagesVisible() const
376  {
377  return m_bImagesVisible;
378  }
379 
380  bool SetImagesVisible(bool bVisible)
381  {
382  bool bOld = m_bImagesVisible;
383  m_bImagesVisible = bVisible;
384  return bOld;
385  }
386 
387  void GetImageSize(SIZE& size) const
388  {
389  size = m_szBitmap;
390  }
391 
392  bool SetImageSize(SIZE& size)
393  {
394  return SetImageSize(size.cx, size.cy);
395  }
396 
397  bool SetImageSize(int cx, int cy)
398  {
399  if(m_hImageList != NULL)
400  {
401  if(::ImageList_GetImageCount(m_hImageList) == 0) // empty
402  {
403  ::ImageList_Destroy(m_hImageList);
404  m_hImageList = NULL;
405  }
406  else
407  {
408  return false; // can't set, image list exists
409  }
410  }
411 
412  if(cx == 0 || cy == 0)
413  return false;
414 
415  m_szBitmap.cx = cx;
416  m_szBitmap.cy = cy;
417  m_szButton.cx = m_szBitmap.cx + 2 * s_kcxButtonMargin;
418  m_szButton.cy = m_szBitmap.cy + 2 * s_kcyButtonMargin;
419 
420  return true;
421  }
422 
423  bool GetAlphaImages() const
424  {
425  return m_bAlphaImages;
426  }
427 
428  bool SetAlphaImages(bool bAlphaImages)
429  {
430  if(m_hImageList != NULL)
431  {
432  if(::ImageList_GetImageCount(m_hImageList) == 0) // empty
433  {
434  ::ImageList_Destroy(m_hImageList);
435  m_hImageList = NULL;
436  }
437  else
438  {
439  return false; // can't set, image list exists
440  }
441  }
442 
443  m_bAlphaImages = bAlphaImages;
444  return true;
445  }
446 
447  HWND GetCmdBar() const
448  {
449  ATLASSERT(::IsWindow(m_hWnd));
450  return (HWND)::SendMessage(m_hWnd, CBRM_GETCMDBAR, 0, 0L);
451  }
452 
453 // Methods
454  HWND Create(HWND hWndParent, RECT& rcPos, LPCTSTR szWindowName = NULL,
455  DWORD dwStyle = 0, DWORD dwExStyle = 0,
456  UINT nID = 0, LPVOID lpCreateParam = NULL)
457  {
458  // These styles are required for command bars
459  dwStyle |= TBSTYLE_LIST | TBSTYLE_FLAT;
460 #if (_MSC_VER >= 1300)
461  return ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam);
462 #else // !(_MSC_VER >= 1300)
463  typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass;
464  return _baseClass::Create(hWndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam);
465 #endif // !(_MSC_VER >= 1300)
466  }
467 
468  BOOL AttachToWindow(HWND hWnd)
469  {
470  ATLASSERT(m_hWnd == NULL);
471  ATLASSERT(::IsWindow(hWnd));
472  BOOL bRet = SubclassWindow(hWnd);
473  if(bRet)
474  {
475  m_bAttachedMenu = true;
476  T* pT = static_cast<T*>(this);
477  pT->GetSystemSettings();
478  }
479  return bRet;
480  }
481 
482  BOOL LoadMenu(ATL::_U_STRINGorID menu)
483  {
484  ATLASSERT(::IsWindow(m_hWnd));
485 
486  if(m_bAttachedMenu) // doesn't work in this mode
487  return FALSE;
488  if(menu.m_lpstr == NULL)
489  return FALSE;
490 
491  HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), menu.m_lpstr);
492  if(hMenu == NULL)
493  return FALSE;
494 
495  return AttachMenu(hMenu);
496  }
497 
498  BOOL AttachMenu(HMENU hMenu)
499  {
500  ATLASSERT(::IsWindow(m_hWnd));
501  ATLASSERT(hMenu == NULL || ::IsMenu(hMenu));
502  if(hMenu != NULL && !::IsMenu(hMenu))
503  return FALSE;
504 
505 #if _WTL_CMDBAR_VISTA_MENUS
506  // remove Vista bitmaps if used
507  if(m_bVistaMenus && (m_hMenu != NULL))
508  {
509  T* pT = static_cast<T*>(this);
510  pT->_RemoveVistaBitmapsFromMenu();
511  }
512 #endif // _WTL_CMDBAR_VISTA_MENUS
513 
514  // destroy old menu, if needed, and set new one
515  if(m_hMenu != NULL && (m_dwExtendedStyle & CBR_EX_SHAREMENU) == 0)
516  ::DestroyMenu(m_hMenu);
517 
518  m_hMenu = hMenu;
519 
520  if(m_bAttachedMenu) // Nothing else in this mode
521  return TRUE;
522 
523  // Build buttons according to menu
524  SetRedraw(FALSE);
525 
526  // Clear all buttons
527  int nCount = GetButtonCount();
528  for(int i = 0; i < nCount; i++)
529  ATLVERIFY(DeleteButton(0) != FALSE);
530 
531  // Add buttons for each menu item
532  if(m_hMenu != NULL)
533  {
534  int nItems = ::GetMenuItemCount(m_hMenu);
535 
536  T* pT = static_cast<T*>(this);
537  pT; // avoid level 4 warning
538  TCHAR szString[pT->_nMaxMenuItemTextLength] = { 0 };
539  for(int i = 0; i < nItems; i++)
540  {
541  CMenuItemInfo mii;
542  mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU;
543  mii.fType = MFT_STRING;
544  mii.dwTypeData = szString;
545  mii.cch = pT->_nMaxMenuItemTextLength;
546  BOOL bRet = ::GetMenuItemInfo(m_hMenu, i, TRUE, &mii);
547  ATLASSERT(bRet);
548  // If we have more than the buffer, we assume we have bitmaps bits
549  if(lstrlen(szString) > pT->_nMaxMenuItemTextLength - 1)
550  {
551  mii.fType = MFT_BITMAP;
552  ::SetMenuItemInfo(m_hMenu, i, TRUE, &mii);
553  szString[0] = 0;
554  }
555 
556  // NOTE: Command Bar currently supports only drop-down menu items
557  ATLASSERT(mii.hSubMenu != NULL);
558 
559  TBBUTTON btn = { 0 };
560  btn.iBitmap = 0;
561  btn.idCommand = i;
562  btn.fsState = (BYTE)(((mii.fState & MFS_DISABLED) == 0) ? TBSTATE_ENABLED : 0);
563  btn.fsStyle = TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE | TBSTYLE_DROPDOWN;
564  btn.dwData = 0;
565  btn.iString = 0;
566 
567  bRet = InsertButton(-1, &btn);
568  ATLASSERT(bRet);
569 
570  TBBUTTONINFO bi = { 0 };
571  bi.cbSize = sizeof(TBBUTTONINFO);
572  bi.dwMask = TBIF_TEXT;
573  bi.pszText = szString;
574 
575  bRet = SetButtonInfo(i, &bi);
576  ATLASSERT(bRet);
577  }
578  }
579 
580  SetRedraw(TRUE);
581  Invalidate();
582  UpdateWindow();
583 
584  return TRUE;
585  }
586 
587  BOOL LoadImages(ATL::_U_STRINGorID image)
588  {
589  return _LoadImagesHelper(image, false);
590  }
591 
592  BOOL LoadMappedImages(UINT nIDImage, UINT nFlags = 0, LPCOLORMAP lpColorMap = NULL, int nMapSize = 0)
593  {
594  return _LoadImagesHelper(nIDImage, true, nFlags , lpColorMap, nMapSize);
595  }
596 
597  BOOL _LoadImagesHelper(ATL::_U_STRINGorID image, bool bMapped, UINT nFlags = 0, LPCOLORMAP lpColorMap = NULL, int nMapSize = 0)
598  {
599  ATLASSERT(::IsWindow(m_hWnd));
600  HINSTANCE hInstance = ModuleHelper::GetResourceInstance();
601 
602  HRSRC hRsrc = ::FindResource(hInstance, image.m_lpstr, (LPTSTR)RT_TOOLBAR);
603  if(hRsrc == NULL)
604  return FALSE;
605 
606  HGLOBAL hGlobal = ::LoadResource(hInstance, hRsrc);
607  if(hGlobal == NULL)
608  return FALSE;
609 
610  _ToolBarData* pData = (_ToolBarData*)::LockResource(hGlobal);
611  if(pData == NULL)
612  return FALSE;
613  ATLASSERT(pData->wVersion == 1);
614 
615  WORD* pItems = pData->items();
616  int nItems = pData->wItemCount;
617 
618  // Set internal data
619  SetImageSize(pData->wWidth, pData->wHeight);
620 
621  // Create image list if needed
622  if(m_hImageList == NULL)
623  {
624  // Check if the bitmap is 32-bit (alpha channel) bitmap (valid for Windows XP only)
625  T* pT = static_cast<T*>(this);
626  m_bAlphaImages = AtlIsAlphaBitmapResource(image);
627 
628  if(!pT->CreateInternalImageList(pData->wItemCount))
629  return FALSE;
630  }
631 
632 #if _WTL_CMDBAR_VISTA_MENUS
633  int nOldImageCount = ::ImageList_GetImageCount(m_hImageList);
634 #endif // _WTL_CMDBAR_VISTA_MENUS
635 
636  // Add bitmap to our image list
637  CBitmap bmp;
638  if(bMapped)
639  {
640  ATLASSERT(HIWORD(PtrToUlong(image.m_lpstr)) == 0); // if mapped, must be a numeric ID
641  int nIDImage = (int)(short)LOWORD(PtrToUlong(image.m_lpstr));
642  bmp.LoadMappedBitmap(nIDImage, (WORD)nFlags, lpColorMap, nMapSize);
643  }
644  else
645  {
646  if(m_bAlphaImages)
647  bmp = (HBITMAP)::LoadImage(ModuleHelper::GetResourceInstance(), image.m_lpstr, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
648  else
649  bmp.LoadBitmap(image.m_lpstr);
650  }
651  ATLASSERT(bmp.m_hBitmap != NULL);
652  if(bmp.m_hBitmap == NULL)
653  return FALSE;
654  if(::ImageList_AddMasked(m_hImageList, bmp, m_clrMask) == -1)
655  return FALSE;
656 
657  // Fill the array with command IDs
658  for(int i = 0; i < nItems; i++)
659  {
660  if(pItems[i] != 0)
661  m_arrCommand.Add(pItems[i]);
662  }
663 
664  int nImageCount = ::ImageList_GetImageCount(m_hImageList);
665  ATLASSERT(nImageCount == m_arrCommand.GetSize());
666  if(nImageCount != m_arrCommand.GetSize())
667  return FALSE;
668 
669 #if _WTL_CMDBAR_VISTA_MENUS
670  if(RunTimeHelper::IsVista())
671  {
672  T* pT = static_cast<T*>(this);
673  pT->_AddVistaBitmapsFromImageList(nOldImageCount, nImageCount - nOldImageCount);
674  ATLASSERT(nImageCount == m_arrVistaBitmap.GetSize());
675  }
676 #endif // _WTL_CMDBAR_VISTA_MENUS
677 
678  return TRUE;
679  }
680 
681  BOOL AddBitmap(ATL::_U_STRINGorID bitmap, int nCommandID)
682  {
683  ATLASSERT(::IsWindow(m_hWnd));
684  CBitmap bmp;
685  bmp.LoadBitmap(bitmap.m_lpstr);
686  if(bmp.m_hBitmap == NULL)
687  return FALSE;
688  return AddBitmap(bmp, nCommandID);
689  }
690 
691  BOOL AddBitmap(HBITMAP hBitmap, UINT nCommandID)
692  {
693  ATLASSERT(::IsWindow(m_hWnd));
694  T* pT = static_cast<T*>(this);
695  // Create image list if it doesn't exist
696  if(m_hImageList == NULL)
697  {
698  if(!pT->CreateInternalImageList(1))
699  return FALSE;
700  }
701  // check bitmap size
702  CBitmapHandle bmp = hBitmap;
703  SIZE size = { 0, 0 };
704  bmp.GetSize(size);
705  if(size.cx != m_szBitmap.cx || size.cy != m_szBitmap.cy)
706  {
707  ATLASSERT(FALSE); // must match size!
708  return FALSE;
709  }
710  // add bitmap
711  int nRet = ::ImageList_AddMasked(m_hImageList, hBitmap, m_clrMask);
712  if(nRet == -1)
713  return FALSE;
714  BOOL bRet = m_arrCommand.Add((WORD)nCommandID);
715  ATLASSERT(::ImageList_GetImageCount(m_hImageList) == m_arrCommand.GetSize());
716 #if _WTL_CMDBAR_VISTA_MENUS
717  if(RunTimeHelper::IsVista())
718  {
719  pT->_AddVistaBitmapFromImageList(m_arrCommand.GetSize() - 1);
720  ATLASSERT(m_arrVistaBitmap.GetSize() == m_arrCommand.GetSize());
721  }
722 #endif // _WTL_CMDBAR_VISTA_MENUS
723  return bRet;
724  }
725 
726  BOOL AddIcon(ATL::_U_STRINGorID icon, UINT nCommandID)
727  {
728  ATLASSERT(::IsWindow(m_hWnd));
729  HICON hIcon = ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr);
730  if(hIcon == NULL)
731  return FALSE;
732  return AddIcon(hIcon, nCommandID);
733  }
734 
735  BOOL AddIcon(HICON hIcon, UINT nCommandID)
736  {
737  ATLASSERT(::IsWindow(m_hWnd));
738  T* pT = static_cast<T*>(this);
739  // create image list if it doesn't exist
740  if(m_hImageList == NULL)
741  {
742  if(!pT->CreateInternalImageList(1))
743  return FALSE;
744  }
745 
746  int nRet = ::ImageList_AddIcon(m_hImageList, hIcon);
747  if(nRet == -1)
748  return FALSE;
749  BOOL bRet = m_arrCommand.Add((WORD)nCommandID);
750  ATLASSERT(::ImageList_GetImageCount(m_hImageList) == m_arrCommand.GetSize());
751 #if _WTL_CMDBAR_VISTA_MENUS
752  if(RunTimeHelper::IsVista())
753  {
754  pT->_AddVistaBitmapFromImageList(m_arrCommand.GetSize() - 1);
755  ATLASSERT(m_arrVistaBitmap.GetSize() == m_arrCommand.GetSize());
756  }
757 #endif // _WTL_CMDBAR_VISTA_MENUS
758  return bRet;
759  }
760 
761  BOOL ReplaceBitmap(ATL::_U_STRINGorID bitmap, int nCommandID)
762  {
763  ATLASSERT(::IsWindow(m_hWnd));
764  CBitmap bmp;
765  bmp.LoadBitmap(bitmap.m_lpstr);
766  if(bmp.m_hBitmap == NULL)
767  return FALSE;
768  return ReplaceBitmap(bmp, nCommandID);
769  }
770 
771  BOOL ReplaceBitmap(HBITMAP hBitmap, UINT nCommandID)
772  {
773  ATLASSERT(::IsWindow(m_hWnd));
774  BOOL bRet = FALSE;
775  for(int i = 0; i < m_arrCommand.GetSize(); i++)
776  {
777  if(m_arrCommand[i] == nCommandID)
778  {
779  bRet = ::ImageList_Remove(m_hImageList, i);
780  if(bRet)
781  {
782  m_arrCommand.RemoveAt(i);
783 #if _WTL_CMDBAR_VISTA_MENUS
784  if(RunTimeHelper::IsVista())
785  {
786  if(m_arrVistaBitmap[i] != NULL)
787  ::DeleteObject(m_arrVistaBitmap[i]);
788  m_arrVistaBitmap.RemoveAt(i);
789  }
790 #endif // _WTL_CMDBAR_VISTA_MENUS
791  }
792  break;
793  }
794  }
795  if(bRet)
796  bRet = AddBitmap(hBitmap, nCommandID);
797  return bRet;
798  }
799 
800  BOOL ReplaceIcon(ATL::_U_STRINGorID icon, UINT nCommandID)
801  {
802  ATLASSERT(::IsWindow(m_hWnd));
803  HICON hIcon = ::LoadIcon(ModuleHelper::GetResourceInstance(), icon.m_lpstr);
804  if(hIcon == NULL)
805  return FALSE;
806  return ReplaceIcon(hIcon, nCommandID);
807  }
808 
809  BOOL ReplaceIcon(HICON hIcon, UINT nCommandID)
810  {
811  ATLASSERT(::IsWindow(m_hWnd));
812  BOOL bRet = FALSE;
813  for(int i = 0; i < m_arrCommand.GetSize(); i++)
814  {
815  if(m_arrCommand[i] == nCommandID)
816  {
817  bRet = (::ImageList_ReplaceIcon(m_hImageList, i, hIcon) != -1);
818 #if _WTL_CMDBAR_VISTA_MENUS
819  if(RunTimeHelper::IsVista() && bRet != FALSE)
820  {
821  T* pT = static_cast<T*>(this);
822  pT->_ReplaceVistaBitmapFromImageList(i);
823  }
824 #endif // _WTL_CMDBAR_VISTA_MENUS
825  break;
826  }
827  }
828  return bRet;
829  }
830 
831  BOOL RemoveImage(int nCommandID)
832  {
833  ATLASSERT(::IsWindow(m_hWnd));
834 
835  BOOL bRet = FALSE;
836  for(int i = 0; i < m_arrCommand.GetSize(); i++)
837  {
838  if(m_arrCommand[i] == nCommandID)
839  {
840  bRet = ::ImageList_Remove(m_hImageList, i);
841  if(bRet)
842  {
843  m_arrCommand.RemoveAt(i);
844 #if _WTL_CMDBAR_VISTA_MENUS
845  if(RunTimeHelper::IsVista())
846  {
847  if(m_arrVistaBitmap[i] != NULL)
848  ::DeleteObject(m_arrVistaBitmap[i]);
849  m_arrVistaBitmap.RemoveAt(i);
850  }
851 #endif // _WTL_CMDBAR_VISTA_MENUS
852  }
853  break;
854  }
855  }
856  return bRet;
857  }
858 
859  BOOL RemoveAllImages()
860  {
861  ATLASSERT(::IsWindow(m_hWnd));
862 
863  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Removing all images\n"));
864  BOOL bRet = ::ImageList_RemoveAll(m_hImageList);
865  if(bRet)
866  {
867  m_arrCommand.RemoveAll();
868 #if _WTL_CMDBAR_VISTA_MENUS
869  for(int i = 0; i < m_arrVistaBitmap.GetSize(); i++)
870  {
871  if(m_arrVistaBitmap[i] != NULL)
872  ::DeleteObject(m_arrVistaBitmap[i]);
873  }
874  m_arrVistaBitmap.RemoveAll();
875 #endif // _WTL_CMDBAR_VISTA_MENUS
876  }
877  return bRet;
878  }
879 
880  BOOL TrackPopupMenu(HMENU hMenu, UINT uFlags, int x, int y, LPTPMPARAMS lpParams = NULL)
881  {
882  ATLASSERT(::IsWindow(m_hWnd));
883  ATLASSERT(::IsMenu(hMenu));
884  if(!::IsMenu(hMenu))
885  return FALSE;
886  m_bContextMenu = true;
887  if(m_bUseKeyboardCues)
888  m_bShowKeyboardCues = m_bKeyboardInput;
889  T* pT = static_cast<T*>(this);
890  return pT->DoTrackPopupMenu(hMenu, uFlags, x, y, lpParams);
891  }
892 
893  BOOL SetMDIClient(HWND /*hWndMDIClient*/)
894  {
895  // Use CMDICommandBarCtrl for MDI support
896  ATLASSERT(FALSE);
897  return FALSE;
898  }
899 
900 // Message map and handlers
901  BEGIN_MSG_MAP(CCommandBarCtrlImpl)
902  MESSAGE_HANDLER(WM_CREATE, OnCreate)
903  MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
904  MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
905  MESSAGE_HANDLER(WM_INITMENU, OnInitMenu)
906  MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup)
907  MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
908  MESSAGE_HANDLER(GetAutoPopupMessage(), OnInternalAutoPopup)
909  MESSAGE_HANDLER(GetGetBarMessage(), OnInternalGetBar)
910  MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
911  MESSAGE_HANDLER(WM_MENUCHAR, OnMenuChar)
912 
913  MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
914  MESSAGE_HANDLER(WM_KEYUP, OnKeyUp)
915  MESSAGE_HANDLER(WM_CHAR, OnChar)
916  MESSAGE_HANDLER(WM_SYSKEYDOWN, OnSysKeyDown)
917  MESSAGE_HANDLER(WM_SYSKEYUP, OnSysKeyUp)
918  MESSAGE_HANDLER(WM_SYSCHAR, OnSysChar)
919 // public API handlers - these stay to support chevrons in atlframe.h
920  MESSAGE_HANDLER(CBRM_GETMENU, OnAPIGetMenu)
921  MESSAGE_HANDLER(CBRM_TRACKPOPUPMENU, OnAPITrackPopupMenu)
922  MESSAGE_HANDLER(CBRM_GETCMDBAR, OnAPIGetCmdBar)
923 
924  MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem)
925  MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem)
926 
927  MESSAGE_HANDLER(WM_FORWARDMSG, OnForwardMsg)
928  ALT_MSG_MAP(1) // Parent window messages
929  NOTIFY_CODE_HANDLER(TBN_HOTITEMCHANGE, OnParentHotItemChange)
930  NOTIFY_CODE_HANDLER(TBN_DROPDOWN, OnParentDropDown)
931  MESSAGE_HANDLER(WM_INITMENUPOPUP, OnParentInitMenuPopup)
932  MESSAGE_HANDLER(GetGetBarMessage(), OnParentInternalGetBar)
933  MESSAGE_HANDLER(WM_SYSCOMMAND, OnParentSysCommand)
934  MESSAGE_HANDLER(CBRM_GETMENU, OnParentAPIGetMenu)
935  MESSAGE_HANDLER(WM_MENUCHAR, OnParentMenuChar)
936  MESSAGE_HANDLER(CBRM_TRACKPOPUPMENU, OnParentAPITrackPopupMenu)
937  MESSAGE_HANDLER(CBRM_GETCMDBAR, OnParentAPIGetCmdBar)
938  MESSAGE_HANDLER(WM_SETTINGCHANGE, OnParentSettingChange)
939 
940  MESSAGE_HANDLER(WM_DRAWITEM, OnParentDrawItem)
941  MESSAGE_HANDLER(WM_MEASUREITEM, OnParentMeasureItem)
942 
943  MESSAGE_HANDLER(WM_ACTIVATE, OnParentActivate)
944  NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnParentCustomDraw)
945  ALT_MSG_MAP(2) // MDI client window messages
946  // Use CMDICommandBarCtrl for MDI support
947  ALT_MSG_MAP(3) // Message hook messages
948  MESSAGE_HANDLER(WM_MOUSEMOVE, OnHookMouseMove)
949  MESSAGE_HANDLER(WM_SYSKEYDOWN, OnHookSysKeyDown)
950  MESSAGE_HANDLER(WM_SYSKEYUP, OnHookSysKeyUp)
951  MESSAGE_HANDLER(WM_SYSCHAR, OnHookSysChar)
952  MESSAGE_HANDLER(WM_KEYDOWN, OnHookKeyDown)
953  MESSAGE_HANDLER(WM_NEXTMENU, OnHookNextMenu)
954  MESSAGE_HANDLER(WM_CHAR, OnHookChar)
955  END_MSG_MAP()
956 
957  LRESULT OnForwardMsg(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
958  {
959  LPMSG pMsg = (LPMSG)lParam;
960  if(pMsg->message >= WM_MOUSEFIRST && pMsg->message <= WM_MOUSELAST)
961  m_bKeyboardInput = false;
962  else if(pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)
963  m_bKeyboardInput = true;
964  LRESULT lRet = 0;
965  ProcessWindowMessage(pMsg->hwnd, pMsg->message, pMsg->wParam, pMsg->lParam, lRet, 3);
966  return lRet;
967  }
968 
969  LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
970  {
971  // Let the toolbar initialize itself
972  LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
973  // get and use system settings
974  T* pT = static_cast<T*>(this);
975  pT->GetSystemSettings();
976  // Parent init
977  ATL::CWindow wndParent = GetParent();
978  ATL::CWindow wndTopLevelParent = wndParent.GetTopLevelParent();
979  m_wndParent.SubclassWindow(wndTopLevelParent);
980  // Toolbar Init
981  SetButtonStructSize();
982  SetImageList(NULL);
983 
984  // Create message hook if needed
986  if(FAILED(lock.Lock()))
987  {
988  ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::OnCreate.\n"));
989  ATLASSERT(FALSE);
990  return -1;
991  }
992 
993  if(s_pmapMsgHook == NULL)
994  {
995  ATLTRY(s_pmapMsgHook = new CMsgHookMap);
996  ATLASSERT(s_pmapMsgHook != NULL);
997  }
998 
999  if(s_pmapMsgHook != NULL)
1000  {
1001  DWORD dwThreadID = ::GetCurrentThreadId();
1002  _MsgHookData* pData = s_pmapMsgHook->Lookup(dwThreadID);
1003  if(pData == NULL)
1004  {
1005  ATLTRY(pData = new _MsgHookData);
1006  ATLASSERT(pData != NULL);
1007  HHOOK hMsgHook = ::SetWindowsHookEx(WH_GETMESSAGE, MessageHookProc, ModuleHelper::GetModuleInstance(), dwThreadID);
1008  ATLASSERT(hMsgHook != NULL);
1009  if(pData != NULL && hMsgHook != NULL)
1010  {
1011  pData->hMsgHook = hMsgHook;
1012  pData->dwUsage = 1;
1013  BOOL bRet = s_pmapMsgHook->Add(dwThreadID, pData);
1014  bRet;
1015  ATLASSERT(bRet);
1016  }
1017  }
1018  else
1019  {
1020  (pData->dwUsage)++;
1021  }
1022  }
1023  lock.Unlock();
1024 
1025  // Get layout
1026 #if (WINVER >= 0x0500)
1027  m_bLayoutRTL = ((GetExStyle() & WS_EX_LAYOUTRTL) != 0);
1028 #endif // (WINVER >= 0x0500)
1029 
1030  return lRet;
1031  }
1032 
1033  LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
1034  {
1035  LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
1036 
1037 #if _WTL_CMDBAR_VISTA_MENUS
1038  if(m_bVistaMenus && (m_hMenu != NULL))
1039  {
1040  T* pT = static_cast<T*>(this);
1041  pT->_RemoveVistaBitmapsFromMenu();
1042  }
1043 
1044  for(int i = 0; i < m_arrVistaBitmap.GetSize(); i++)
1045  {
1046  if(m_arrVistaBitmap[i] != NULL)
1047  ::DeleteObject(m_arrVistaBitmap[i]);
1048  }
1049 #endif // _WTL_CMDBAR_VISTA_MENUS
1050 
1051  if(m_bAttachedMenu) // nothing to do in this mode
1052  return lRet;
1053 
1055  if(FAILED(lock.Lock()))
1056  {
1057  ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::OnDestroy.\n"));
1058  ATLASSERT(FALSE);
1059  return lRet;
1060  }
1061 
1062  if(s_pmapMsgHook != NULL)
1063  {
1064  DWORD dwThreadID = ::GetCurrentThreadId();
1065  _MsgHookData* pData = s_pmapMsgHook->Lookup(dwThreadID);
1066  if(pData != NULL)
1067  {
1068  (pData->dwUsage)--;
1069  if(pData->dwUsage == 0)
1070  {
1071  BOOL bRet = ::UnhookWindowsHookEx(pData->hMsgHook);
1072  ATLASSERT(bRet);
1073  bRet = s_pmapMsgHook->Remove(dwThreadID);
1074  ATLASSERT(bRet);
1075  if(bRet)
1076  delete pData;
1077  }
1078 
1079  if(s_pmapMsgHook->GetSize() == 0)
1080  {
1081  delete s_pmapMsgHook;
1082  s_pmapMsgHook = NULL;
1083  }
1084  }
1085  }
1086 
1087  lock.Unlock();
1088 
1089  return lRet;
1090  }
1091 
1092  LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1093  {
1094 #ifdef _CMDBAR_EXTRA_TRACE
1095  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnKeyDown\n"));
1096 #endif
1097  bHandled = FALSE;
1098  // Simulate Alt+Space for the parent
1099  if(wParam == VK_SPACE)
1100  {
1101  m_wndParent.PostMessage(WM_SYSKEYDOWN, wParam, lParam | (1 << 29));
1102  bHandled = TRUE;
1103  }
1104 #if (_WIN32_IE >= 0x0500)
1105  else if(wParam == VK_LEFT || wParam == VK_RIGHT)
1106  {
1107  WPARAM wpNext = m_bLayoutRTL ? VK_LEFT : VK_RIGHT;
1108 
1109  if(!m_bMenuActive)
1110  {
1111  T* pT = static_cast<T*>(this);
1112  int nBtn = GetHotItem();
1113  int nNextBtn = (wParam == wpNext) ? pT->GetNextMenuItem(nBtn) : pT->GetPreviousMenuItem(nBtn);
1114  if(nNextBtn == -2)
1115  {
1116  SetHotItem(-1);
1117  if(pT->DisplayChevronMenu())
1118  bHandled = TRUE;
1119  }
1120  }
1121  }
1122 #endif // (_WIN32_IE >= 0x0500)
1123  return 0;
1124  }
1125 
1126  LRESULT OnKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
1127  {
1128 #ifdef _CMDBAR_EXTRA_TRACE
1129  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnKeyUp\n"));
1130 #endif
1131  if(wParam != VK_SPACE)
1132  bHandled = FALSE;
1133  return 0;
1134  }
1135 
1136  LRESULT OnChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
1137  {
1138 #ifdef _CMDBAR_EXTRA_TRACE
1139  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnChar\n"));
1140 #endif
1141  if(wParam != VK_SPACE)
1142  bHandled = FALSE;
1143  else
1144  return 0;
1145  // Security
1146  if(!m_wndParent.IsWindowEnabled() || ::GetFocus() != m_hWnd)
1147  return 0;
1148 
1149  // Handle mnemonic press when we have focus
1150  int nBtn = 0;
1151  if(wParam != VK_RETURN && !MapAccelerator((TCHAR)LOWORD(wParam), nBtn))
1152  {
1153 #if (_WIN32_IE >= 0x0500)
1154  if((TCHAR)LOWORD(wParam) != _chChevronShortcut)
1155 #endif // (_WIN32_IE >= 0x0500)
1156  ::MessageBeep(0);
1157  }
1158  else
1159  {
1160 #if (_WIN32_IE >= 0x0500)
1161  RECT rcClient = { 0 };
1162  GetClientRect(&rcClient);
1163  RECT rcBtn = { 0 };
1164  GetItemRect(nBtn, &rcBtn);
1165  TBBUTTON tbb = { 0 };
1166  GetButton(nBtn, &tbb);
1167  if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0 && rcBtn.right <= rcClient.right)
1168  {
1169 #endif // (_WIN32_IE >= 0x0500)
1170  PostMessage(WM_KEYDOWN, VK_DOWN, 0L);
1171  if(wParam != VK_RETURN)
1172  SetHotItem(nBtn);
1173 #if (_WIN32_IE >= 0x0500)
1174  }
1175  else
1176  {
1177  ::MessageBeep(0);
1178  bHandled = TRUE;
1179  }
1180 #endif // (_WIN32_IE >= 0x0500)
1181  }
1182  return 0;
1183  }
1184 
1185  LRESULT OnSysKeyDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
1186  {
1187 #ifdef _CMDBAR_EXTRA_TRACE
1188  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnSysKeyDown\n"));
1189 #endif
1190  bHandled = FALSE;
1191  return 0;
1192  }
1193 
1194  LRESULT OnSysKeyUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
1195  {
1196 #ifdef _CMDBAR_EXTRA_TRACE
1197  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnSysKeyUp\n"));
1198 #endif
1199  bHandled = FALSE;
1200  return 0;
1201  }
1202 
1203  LRESULT OnSysChar(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
1204  {
1205 #ifdef _CMDBAR_EXTRA_TRACE
1206  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnSysChar\n"));
1207 #endif
1208  bHandled = FALSE;
1209  return 0;
1210  }
1211 
1212  LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
1213  {
1214  if(m_bAttachedMenu || (m_dwExtendedStyle & CBR_EX_TRANSPARENT))
1215  {
1216  bHandled = FALSE;
1217  return 0;
1218  }
1219 
1220  CDCHandle dc = (HDC)wParam;
1221  RECT rect = { 0 };
1222  GetClientRect(&rect);
1223  dc.FillRect(&rect, COLOR_MENU);
1224 
1225  return 1; // don't do the default erase
1226  }
1227 
1228  LRESULT OnInitMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
1229  {
1230  int nIndex = GetHotItem();
1231  SendMessage(WM_MENUSELECT, MAKEWPARAM(nIndex, MF_POPUP|MF_HILITE), (LPARAM)m_hMenu);
1232  bHandled = FALSE;
1233  return 1;
1234  }
1235 
1236  LRESULT OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1237  {
1238  if((BOOL)HIWORD(lParam)) // System menu, do nothing
1239  {
1240  bHandled = FALSE;
1241  return 1;
1242  }
1243 
1244  if(!(m_bAttachedMenu || m_bMenuActive)) // Not attached or ours, do nothing
1245  {
1246  bHandled = FALSE;
1247  return 1;
1248  }
1249 
1250 #ifdef _CMDBAR_EXTRA_TRACE
1251  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnInitMenuPopup\n"));
1252 #endif
1253  // forward to the parent or subclassed window, so it can handle update UI
1254  LRESULT lRet = 0;
1255  if(m_bAttachedMenu)
1256  lRet = DefWindowProc(uMsg, wParam, (lParam || m_bContextMenu) ? lParam : GetHotItem());
1257  else
1258  lRet = m_wndParent.DefWindowProc(uMsg, wParam, (lParam || m_bContextMenu) ? lParam : GetHotItem());
1259 
1260 #if _WTL_CMDBAR_VISTA_MENUS
1261  // If Vista menus are active, just set bitmaps and return
1262  if(m_bVistaMenus)
1263  {
1264  CMenuHandle menu = (HMENU)wParam;
1265  ATLASSERT(menu.m_hMenu != NULL);
1266 
1267  for(int i = 0; i < menu.GetMenuItemCount(); i++)
1268  {
1269  WORD nID = (WORD)menu.GetMenuItemID(i);
1270  int nIndex = m_arrCommand.Find(nID);
1271 
1272  CMenuItemInfo mii;
1273  mii.fMask = MIIM_BITMAP;
1274  mii.hbmpItem = (m_bImagesVisible && (nIndex != -1)) ? m_arrVistaBitmap[nIndex] : NULL;
1275  menu.SetMenuItemInfo(i, TRUE, &mii);
1276  }
1277 
1278  return lRet;
1279  }
1280 #endif // _WTL_CMDBAR_VISTA_MENUS
1281 
1282  // Convert menu items to ownerdraw, add our data
1283  if(m_bImagesVisible)
1284  {
1285  CMenuHandle menuPopup = (HMENU)wParam;
1286  ATLASSERT(menuPopup.m_hMenu != NULL);
1287 
1288  T* pT = static_cast<T*>(this);
1289  pT; // avoid level 4 warning
1290  TCHAR szString[pT->_nMaxMenuItemTextLength] = { 0 };
1291  BOOL bRet = FALSE;
1292  for(int i = 0; i < menuPopup.GetMenuItemCount(); i++)
1293  {
1294  CMenuItemInfo mii;
1295  mii.cch = pT->_nMaxMenuItemTextLength;
1296  mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE;
1297  mii.dwTypeData = szString;
1298  bRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii);
1299  ATLASSERT(bRet);
1300 
1301  if(!(mii.fType & MFT_OWNERDRAW)) // Not already an ownerdraw item
1302  {
1303  mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE;
1304  _MenuItemData* pMI = NULL;
1305  ATLTRY(pMI = new _MenuItemData);
1306  ATLASSERT(pMI != NULL);
1307  if(pMI != NULL)
1308  {
1309  pMI->fType = mii.fType;
1310  pMI->fState = mii.fState;
1311  mii.fType |= MFT_OWNERDRAW;
1312  pMI->iButton = -1;
1313  for(int j = 0; j < m_arrCommand.GetSize(); j++)
1314  {
1315  if(m_arrCommand[j] == mii.wID)
1316  {
1317  pMI->iButton = j;
1318  break;
1319  }
1320  }
1321  int cchLen = lstrlen(szString) + 1;
1322  pMI->lpstrText = NULL;
1323  ATLTRY(pMI->lpstrText = new TCHAR[cchLen]);
1324  ATLASSERT(pMI->lpstrText != NULL);
1325  if(pMI->lpstrText != NULL)
1326  SecureHelper::strcpy_x(pMI->lpstrText, cchLen, szString);
1327  mii.dwItemData = (ULONG_PTR)pMI;
1328  bRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii);
1329  ATLASSERT(bRet);
1330  }
1331  }
1332  }
1333 
1334  // Add it to the list
1335  m_stackMenuHandle.Push(menuPopup.m_hMenu);
1336  }
1337 
1338  return lRet;
1339  }
1340 
1341  LRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1342  {
1343  if(!m_bAttachedMenu) // Not attached, do nothing, forward to parent
1344  {
1345  m_bPopupItem = (lParam != NULL) && ((HMENU)lParam != m_hMenu) && (HIWORD(wParam) & MF_POPUP);
1346  if(m_wndParent.IsWindow())
1347  m_wndParent.SendMessage(uMsg, wParam, lParam);
1348  bHandled = FALSE;
1349  return 1;
1350  }
1351 
1352  // Check if a menu is closing, do a cleanup
1353  if(HIWORD(wParam) == 0xFFFF && lParam == NULL) // Menu closing
1354  {
1355 #ifdef _CMDBAR_EXTRA_TRACE
1356  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnMenuSelect - CLOSING!!!!\n"));
1357 #endif
1358  ATLASSERT(m_stackMenuWnd.GetSize() == 0);
1359  // Restore the menu items to the previous state for all menus that were converted
1360  if(m_bImagesVisible)
1361  {
1362  HMENU hMenu = NULL;
1363  while((hMenu = m_stackMenuHandle.Pop()) != NULL)
1364  {
1365  CMenuHandle menuPopup = hMenu;
1366  ATLASSERT(menuPopup.m_hMenu != NULL);
1367  // Restore state and delete menu item data
1368  BOOL bRet = FALSE;
1369  for(int i = 0; i < menuPopup.GetMenuItemCount(); i++)
1370  {
1371  CMenuItemInfo mii;
1372  mii.fMask = MIIM_DATA | MIIM_TYPE;
1373  bRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii);
1374  ATLASSERT(bRet);
1375 
1376  _MenuItemData* pMI = (_MenuItemData*)mii.dwItemData;
1377  if(pMI != NULL && pMI->IsCmdBarMenuItem())
1378  {
1379  mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE;
1380  mii.fType = pMI->fType;
1381  mii.dwTypeData = pMI->lpstrText;
1382  mii.cch = lstrlen(pMI->lpstrText);
1383  mii.dwItemData = NULL;
1384 
1385  bRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii);
1386  ATLASSERT(bRet);
1387 
1388  delete [] pMI->lpstrText;
1389  pMI->dwMagic = 0x6666;
1390  delete pMI;
1391  }
1392  }
1393  }
1394  }
1395  }
1396 
1397  bHandled = FALSE;
1398  return 1;
1399  }
1400 
1401  LRESULT OnInternalAutoPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
1402  {
1403  int nIndex = (int)wParam;
1404  T* pT = static_cast<T*>(this);
1405  pT->DoPopupMenu(nIndex, false);
1406  return 0;
1407  }
1408 
1409  LRESULT OnInternalGetBar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
1410  {
1411  // Let's make sure we're not embedded in another process
1412  if((LPVOID)wParam != NULL)
1413  *((DWORD*)wParam) = GetCurrentProcessId();
1414  if(IsWindowVisible())
1415  return (LRESULT)static_cast<CCommandBarCtrlBase*>(this);
1416  else
1417  return NULL;
1418  }
1419 
1420  LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
1421  {
1422 #ifndef SPI_GETKEYBOARDCUES
1423  const UINT SPI_SETKEYBOARDCUES = 0x100B;
1424 #endif // !SPI_GETKEYBOARDCUES
1425 #ifndef SPI_GETFLATMENU
1426  const UINT SPI_SETFLATMENU = 0x1023;
1427 #endif // !SPI_GETFLATMENU
1428 
1429  if(wParam == SPI_SETNONCLIENTMETRICS || wParam == SPI_SETKEYBOARDCUES || wParam == SPI_SETFLATMENU)
1430  {
1431  T* pT = static_cast<T*>(this);
1432  pT->GetSystemSettings();
1433  }
1434 
1435  return 0;
1436  }
1437 
1438  LRESULT OnWindowPosChanging(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
1439  {
1440  LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
1441 
1442  LPWINDOWPOS lpWP = (LPWINDOWPOS)lParam;
1443  int cyMin = ::GetSystemMetrics(SM_CYMENU);
1444  if(lpWP->cy < cyMin)
1445  lpWP->cy = cyMin;
1446 
1447  return lRet;
1448  }
1449 
1450  LRESULT OnMenuChar(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1451  {
1452 #ifdef _CMDBAR_EXTRA_TRACE
1453  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - OnMenuChar\n"));
1454 #endif
1455  bHandled = TRUE;
1456  T* pT = static_cast<T*>(this);
1457 
1458  LRESULT lRet;
1459  if(m_bMenuActive && LOWORD(wParam) != 0x0D)
1460  lRet = 0;
1461  else
1462  lRet = MAKELRESULT(1, 1);
1463 
1464  if(m_bMenuActive && HIWORD(wParam) == MF_POPUP)
1465  {
1466  // Convert character to lower/uppercase and possibly Unicode, using current keyboard layout
1467  TCHAR ch = (TCHAR)LOWORD(wParam);
1468  CMenuHandle menu = (HMENU)lParam;
1469  int nCount = ::GetMenuItemCount(menu);
1470  int nRetCode = MNC_EXECUTE;
1471  BOOL bRet = FALSE;
1472  TCHAR szString[pT->_nMaxMenuItemTextLength] = { 0 };
1473  WORD wMnem = 0;
1474  bool bFound = false;
1475  for(int i = 0; i < nCount; i++)
1476  {
1477  CMenuItemInfo mii;
1478  mii.cch = pT->_nMaxMenuItemTextLength;
1479  mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE;
1480  mii.dwTypeData = szString;
1481  bRet = menu.GetMenuItemInfo(i, TRUE, &mii);
1482  if(!bRet || (mii.fType & MFT_SEPARATOR))
1483  continue;
1484  _MenuItemData* pmd = (_MenuItemData*)mii.dwItemData;
1485  if(pmd != NULL && pmd->IsCmdBarMenuItem())
1486  {
1487  LPTSTR p = pmd->lpstrText;
1488 
1489  if(p != NULL)
1490  {
1491  while(*p && *p != _T('&'))
1492  p = ::CharNext(p);
1493  if(p != NULL && *p)
1494  {
1495  DWORD dwP = MAKELONG(*(++p), 0);
1496  DWORD dwC = MAKELONG(ch, 0);
1497  if(::CharLower((LPTSTR)ULongToPtr(dwP)) == ::CharLower((LPTSTR)ULongToPtr(dwC)))
1498  {
1499  if(!bFound)
1500  {
1501  wMnem = (WORD)i;
1502  bFound = true;
1503  }
1504  else
1505  {
1506  nRetCode = MNC_SELECT;
1507  break;
1508  }
1509  }
1510  }
1511  }
1512  }
1513  }
1514  if(bFound)
1515  {
1516  if(nRetCode == MNC_EXECUTE)
1517  {
1518  PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L);
1519  pT->GiveFocusBack();
1520  }
1521  bHandled = TRUE;
1522  lRet = MAKELRESULT(wMnem, nRetCode);
1523  }
1524  }
1525  else if(!m_bMenuActive)
1526  {
1527  int nBtn = 0;
1528  if(!MapAccelerator((TCHAR)LOWORD(wParam), nBtn))
1529  {
1530  bHandled = FALSE;
1531  PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L);
1532  pT->GiveFocusBack();
1533 
1534 #if (_WIN32_IE >= 0x0500)
1535  // check if we should display chevron menu
1536  if((TCHAR)LOWORD(wParam) == pT->_chChevronShortcut)
1537  {
1538  if(pT->DisplayChevronMenu())
1539  bHandled = TRUE;
1540  }
1541 #endif // (_WIN32_IE >= 0x0500)
1542  }
1543  else if(m_wndParent.IsWindowEnabled())
1544  {
1545 #if (_WIN32_IE >= 0x0500)
1546  RECT rcClient = { 0 };
1547  GetClientRect(&rcClient);
1548  RECT rcBtn = { 0 };
1549  GetItemRect(nBtn, &rcBtn);
1550  TBBUTTON tbb = { 0 };
1551  GetButton(nBtn, &tbb);
1552  if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0 && rcBtn.right <= rcClient.right)
1553  {
1554 #endif // (_WIN32_IE >= 0x0500)
1555  if(m_bUseKeyboardCues && !m_bShowKeyboardCues)
1556  {
1557  m_bAllowKeyboardCues = true;
1558  ShowKeyboardCues(true);
1559  }
1560  pT->TakeFocus();
1561  PostMessage(WM_KEYDOWN, VK_DOWN, 0L);
1562  SetHotItem(nBtn);
1563 #if (_WIN32_IE >= 0x0500)
1564  }
1565  else
1566  {
1567  ::MessageBeep(0);
1568  }
1569 #endif // (_WIN32_IE >= 0x0500)
1570  }
1571  }
1572 
1573  return lRet;
1574  }
1575 
1576  LRESULT OnDrawItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
1577  {
1578  LPDRAWITEMSTRUCT lpDrawItemStruct = (LPDRAWITEMSTRUCT)lParam;
1579  _MenuItemData* pmd = (_MenuItemData*)lpDrawItemStruct->itemData;
1580  if(lpDrawItemStruct->CtlType == ODT_MENU && pmd != NULL && pmd->IsCmdBarMenuItem())
1581  {
1582  T* pT = static_cast<T*>(this);
1583  pT->DrawItem(lpDrawItemStruct);
1584  }
1585  else
1586  {
1587  bHandled = FALSE;
1588  }
1589  return (LRESULT)TRUE;
1590  }
1591 
1592  LRESULT OnMeasureItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
1593  {
1594  LPMEASUREITEMSTRUCT lpMeasureItemStruct = (LPMEASUREITEMSTRUCT)lParam;
1595  _MenuItemData* pmd = (_MenuItemData*)lpMeasureItemStruct->itemData;
1596  if(lpMeasureItemStruct->CtlType == ODT_MENU && pmd != NULL && pmd->IsCmdBarMenuItem())
1597  {
1598  T* pT = static_cast<T*>(this);
1599  pT->MeasureItem(lpMeasureItemStruct);
1600  }
1601  else
1602  {
1603  bHandled = FALSE;
1604  }
1605  return (LRESULT)TRUE;
1606  }
1607 
1608 // API message handlers
1609  LRESULT OnAPIGetMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
1610  {
1611  return (LRESULT)m_hMenu;
1612  }
1613 
1614  LRESULT OnAPITrackPopupMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
1615  {
1616  if(lParam == NULL)
1617  return FALSE;
1618  LPCBRPOPUPMENU lpCBRPopupMenu = (LPCBRPOPUPMENU)lParam;
1619  if(lpCBRPopupMenu->cbSize != sizeof(CBRPOPUPMENU))
1620  return FALSE;
1621 
1622  T* pT = static_cast<T*>(this);
1623  return pT->TrackPopupMenu(lpCBRPopupMenu->hMenu, lpCBRPopupMenu->uFlags, lpCBRPopupMenu->x, lpCBRPopupMenu->y, lpCBRPopupMenu->lptpm);
1624  }
1625 
1626  LRESULT OnAPIGetCmdBar(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
1627  {
1628  return (LRESULT)m_hWnd;
1629  }
1630 
1631 // Parent window message handlers
1632  LRESULT OnParentHotItemChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
1633  {
1634  LPNMTBHOTITEM lpNMHT = (LPNMTBHOTITEM)pnmh;
1635 
1636  // Check if this comes from us
1637  if(pnmh->hwndFrom != m_hWnd)
1638  {
1639  bHandled = FALSE;
1640  return 0;
1641  }
1642 
1643  bool bBlockTracking = false;
1644  if((m_dwExtendedStyle & CBR_EX_TRACKALWAYS) == 0)
1645  {
1646  DWORD dwProcessID;
1647  ::GetWindowThreadProcessId(::GetActiveWindow(), &dwProcessID);
1648  bBlockTracking = (::GetCurrentProcessId() != dwProcessID);
1649  }
1650 
1651  if((!m_wndParent.IsWindowEnabled() || bBlockTracking) && (lpNMHT->dwFlags & HICF_MOUSE))
1652  {
1653  return 1;
1654  }
1655  else
1656  {
1657 #ifndef HICF_LMOUSE
1658  const DWORD HICF_LMOUSE = 0x00000080; // left mouse button selected
1659 #endif
1660  bHandled = FALSE;
1661 
1662  // Send WM_MENUSELECT to the app if it needs to display a status text
1663  if(!(lpNMHT->dwFlags & HICF_MOUSE)
1664  && !(lpNMHT->dwFlags & HICF_ACCELERATOR)
1665  && !(lpNMHT->dwFlags & HICF_LMOUSE))
1666  {
1667  if(lpNMHT->dwFlags & HICF_ENTERING)
1668  m_wndParent.SendMessage(WM_MENUSELECT, 0, (LPARAM)m_hMenu);
1669  if(lpNMHT->dwFlags & HICF_LEAVING)
1670  m_wndParent.SendMessage(WM_MENUSELECT, MAKEWPARAM(0, 0xFFFF), NULL);
1671  }
1672 
1673  return 0;
1674  }
1675  }
1676 
1677  LRESULT OnParentDropDown(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
1678  {
1679  // Check if this comes from us
1680  if(pnmh->hwndFrom != m_hWnd)
1681  {
1682  bHandled = FALSE;
1683  return 1;
1684  }
1685 
1686  T* pT = static_cast<T*>(this);
1687  if(::GetFocus() != m_hWnd)
1688  pT->TakeFocus();
1689  LPNMTOOLBAR pNMToolBar = (LPNMTOOLBAR)pnmh;
1690  int nIndex = CommandToIndex(pNMToolBar->iItem);
1691  m_bContextMenu = false;
1692  m_bEscapePressed = false;
1693  pT->DoPopupMenu(nIndex, true);
1694 
1695  return TBDDRET_DEFAULT;
1696  }
1697 
1698  LRESULT OnParentInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1699  {
1700  return OnInitMenuPopup(uMsg, wParam, lParam, bHandled);
1701  }
1702 
1703  LRESULT OnParentInternalGetBar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1704  {
1705  return OnInternalGetBar(uMsg, wParam, lParam, bHandled);
1706  }
1707 
1708  LRESULT OnParentSysCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
1709  {
1710  bHandled = FALSE;
1711  if((m_uSysKey == VK_MENU
1712  || (m_uSysKey == VK_F10 && !(::GetKeyState(VK_SHIFT) & 0x80))
1713  || m_uSysKey == VK_SPACE)
1714  && wParam == SC_KEYMENU)
1715  {
1716  T* pT = static_cast<T*>(this);
1717  if(::GetFocus() == m_hWnd)
1718  {
1719  pT->GiveFocusBack(); // exit menu "loop"
1720  PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L);
1721  }
1722  else if(m_uSysKey != VK_SPACE && !m_bSkipMsg)
1723  {
1724  if(m_bUseKeyboardCues && !m_bShowKeyboardCues && m_bAllowKeyboardCues)
1725  ShowKeyboardCues(true);
1726 
1727  pT->TakeFocus(); // enter menu "loop"
1728  bHandled = TRUE;
1729  }
1730  else if(m_uSysKey != VK_SPACE)
1731  {
1732  bHandled = TRUE;
1733  }
1734  }
1735  m_bSkipMsg = false;
1736  return 0;
1737  }
1738 
1739  LRESULT OnParentAPIGetMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1740  {
1741  return OnAPIGetMenu(uMsg, wParam, lParam, bHandled);
1742  }
1743 
1744  LRESULT OnParentMenuChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1745  {
1746  return OnMenuChar(uMsg, wParam, lParam, bHandled);
1747  }
1748 
1749  LRESULT OnParentAPITrackPopupMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1750  {
1751  return OnAPITrackPopupMenu(uMsg, wParam, lParam, bHandled);
1752  }
1753 
1754  LRESULT OnParentAPIGetCmdBar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1755  {
1756  return OnAPIGetCmdBar(uMsg, wParam, lParam, bHandled);
1757  }
1758 
1759  LRESULT OnParentSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1760  {
1761  OnSettingChange(uMsg, wParam, lParam, bHandled);
1762  bHandled = FALSE;
1763  return 1;
1764  }
1765 
1766  LRESULT OnParentDrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1767  {
1768  return OnDrawItem(uMsg, wParam, lParam, bHandled);
1769  }
1770 
1771  LRESULT OnParentMeasureItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
1772  {
1773  return OnMeasureItem(uMsg, wParam, lParam, bHandled);
1774  }
1775 
1776  LRESULT OnParentActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
1777  {
1778  m_bParentActive = (LOWORD(wParam) != WA_INACTIVE);
1779  if(!m_bParentActive && m_bUseKeyboardCues && m_bShowKeyboardCues)
1780  {
1781  ShowKeyboardCues(false); // this will repaint our window
1782  }
1783  else
1784  {
1785  Invalidate();
1786  UpdateWindow();
1787  }
1788  bHandled = FALSE;
1789  return 1;
1790  }
1791 
1792  LRESULT OnParentCustomDraw(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
1793  {
1794  LRESULT lRet = CDRF_DODEFAULT;
1795  bHandled = FALSE;
1796  if(pnmh->hwndFrom == m_hWnd)
1797  {
1798  LPNMTBCUSTOMDRAW lpTBCustomDraw = (LPNMTBCUSTOMDRAW)pnmh;
1799  if(lpTBCustomDraw->nmcd.dwDrawStage == CDDS_PREPAINT)
1800  {
1801  lRet = CDRF_NOTIFYITEMDRAW;
1802  bHandled = TRUE;
1803  }
1804  else if(lpTBCustomDraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
1805  {
1806  if(m_bFlatMenus)
1807  {
1808 #ifndef COLOR_MENUHILIGHT
1809  const int COLOR_MENUHILIGHT = 29;
1810 #endif // !COLOR_MENUHILIGHT
1811  bool bDisabled = ((lpTBCustomDraw->nmcd.uItemState & CDIS_DISABLED) == CDIS_DISABLED);
1812  if(!bDisabled && ((lpTBCustomDraw->nmcd.uItemState & CDIS_HOT) == CDIS_HOT ||
1813  (lpTBCustomDraw->nmcd.uItemState & CDIS_SELECTED) == CDIS_SELECTED))
1814  {
1815  ::FillRect(lpTBCustomDraw->nmcd.hdc, &lpTBCustomDraw->nmcd.rc, ::GetSysColorBrush(COLOR_MENUHILIGHT));
1816  ::FrameRect(lpTBCustomDraw->nmcd.hdc, &lpTBCustomDraw->nmcd.rc, ::GetSysColorBrush(COLOR_HIGHLIGHT));
1817  lpTBCustomDraw->clrText = ::GetSysColor(m_bParentActive ? COLOR_HIGHLIGHTTEXT : COLOR_GRAYTEXT);
1818  }
1819  else if(bDisabled || !m_bParentActive)
1820  {
1821  lpTBCustomDraw->clrText = ::GetSysColor(COLOR_GRAYTEXT);
1822  }
1823  CDCHandle dc = lpTBCustomDraw->nmcd.hdc;
1824  dc.SetTextColor(lpTBCustomDraw->clrText);
1825  dc.SetBkMode(lpTBCustomDraw->nStringBkMode);
1826  HFONT hFont = GetFont();
1827  HFONT hFontOld = NULL;
1828  if(hFont != NULL)
1829  hFontOld = dc.SelectFont(hFont);
1830  const int cchText = 200;
1831  TCHAR szText[cchText] = { 0 };
1832  TBBUTTONINFO tbbi = { 0 };
1833  tbbi.cbSize = sizeof(TBBUTTONINFO);
1834  tbbi.dwMask = TBIF_TEXT;
1835  tbbi.pszText = szText;
1836  tbbi.cchText = cchText;
1837  GetButtonInfo((int)lpTBCustomDraw->nmcd.dwItemSpec, &tbbi);
1838  dc.DrawText(szText, -1, &lpTBCustomDraw->nmcd.rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER | (m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX));
1839  if(hFont != NULL)
1840  dc.SelectFont(hFontOld);
1841  lRet = CDRF_SKIPDEFAULT;
1842  bHandled = TRUE;
1843  }
1844  else if(!m_bParentActive)
1845  {
1846  lpTBCustomDraw->clrText = ::GetSysColor(COLOR_GRAYTEXT);
1847  bHandled = TRUE;
1848  }
1849  }
1850  }
1851  return lRet;
1852  }
1853 
1854 // Message hook handlers
1855  LRESULT OnHookMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
1856  {
1857  static POINT s_point = { -1, -1 };
1858  DWORD dwPoint = ::GetMessagePos();
1859  POINT point = { GET_X_LPARAM(dwPoint), GET_Y_LPARAM(dwPoint) };
1860 
1861  bHandled = FALSE;
1862  if(m_bMenuActive)
1863  {
1864  if(::WindowFromPoint(point) == m_hWnd)
1865  {
1866  ScreenToClient(&point);
1867  int nHit = HitTest(&point);
1868 
1869  if((point.x != s_point.x || point.y != s_point.y) && nHit >= 0 && nHit < ::GetMenuItemCount(m_hMenu) && nHit != m_nPopBtn && m_nPopBtn != -1)
1870  {
1871  TBBUTTON tbb = { 0 };
1872  GetButton(nHit, &tbb);
1873  if((tbb.fsState & TBSTATE_ENABLED) != 0)
1874  {
1875  m_nNextPopBtn = nHit | 0xFFFF0000;
1876  HWND hWndMenu = m_stackMenuWnd.GetCurrent();
1877  ATLASSERT(hWndMenu != NULL);
1878 
1879  // this one is needed to close a menu if mouse button was down
1880  ::PostMessage(hWndMenu, WM_LBUTTONUP, 0, MAKELPARAM(point.x, point.y));
1881  // this one closes a popup menu
1882  ::PostMessage(hWndMenu, WM_KEYDOWN, VK_ESCAPE, 0L);
1883 
1884  bHandled = TRUE;
1885  }
1886  }
1887  }
1888  }
1889  else
1890  {
1891  ScreenToClient(&point);
1892  }
1893 
1894  s_point = point;
1895  return 0;
1896  }
1897 
1898  LRESULT OnHookSysKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
1899  {
1900  bHandled = FALSE;
1901 #ifdef _CMDBAR_EXTRA_TRACE
1902  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_SYSKEYDOWN (0x%2.2X)\n"), wParam);
1903 #endif
1904 
1905  if(wParam == VK_MENU && m_bParentActive && m_bUseKeyboardCues && !m_bShowKeyboardCues && m_bAllowKeyboardCues)
1906  ShowKeyboardCues(true);
1907 
1908  if(wParam != VK_SPACE && !m_bMenuActive && ::GetFocus() == m_hWnd)
1909  {
1910  m_bAllowKeyboardCues = false;
1911  PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L);
1912  T* pT = static_cast<T*>(this);
1913  pT->GiveFocusBack();
1914  m_bSkipMsg = true;
1915  }
1916  else
1917  {
1918  if(wParam == VK_SPACE && m_bUseKeyboardCues && m_bShowKeyboardCues)
1919  {
1920  m_bAllowKeyboardCues = true;
1921  ShowKeyboardCues(false);
1922  }
1923  m_uSysKey = (UINT)wParam;
1924  }
1925  return 0;
1926  }
1927 
1928  LRESULT OnHookSysKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
1929  {
1930  if(!m_bAllowKeyboardCues)
1931  m_bAllowKeyboardCues = true;
1932  bHandled = FALSE;
1933  wParam;
1934 #ifdef _CMDBAR_EXTRA_TRACE
1935  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_SYSKEYUP (0x%2.2X)\n"), wParam);
1936 #endif
1937  return 0;
1938  }
1939 
1940  LRESULT OnHookSysChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
1941  {
1942  bHandled = FALSE;
1943 #ifdef _CMDBAR_EXTRA_TRACE
1944  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_SYSCHAR (0x%2.2X)\n"), wParam);
1945 #endif
1946 
1947  if(!m_bMenuActive && m_hWndHook != m_hWnd && wParam != VK_SPACE)
1948  bHandled = TRUE;
1949  return 0;
1950  }
1951 
1952  LRESULT OnHookKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
1953  {
1954 #ifdef _CMDBAR_EXTRA_TRACE
1955  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_KEYDOWN (0x%2.2X)\n"), wParam);
1956 #endif
1957  bHandled = FALSE;
1958  T* pT = static_cast<T*>(this);
1959 
1960  if(wParam == VK_ESCAPE && m_stackMenuWnd.GetSize() <= 1)
1961  {
1962  if(m_bMenuActive && !m_bContextMenu)
1963  {
1964  int nHot = GetHotItem();
1965  if(nHot == -1)
1966  nHot = m_nPopBtn;
1967  if(nHot == -1)
1968  nHot = 0;
1969  SetHotItem(nHot);
1970  bHandled = TRUE;
1971  pT->TakeFocus();
1972  m_bEscapePressed = true; // To keep focus
1973  m_bSkipPostDown = false;
1974  }
1975  else if(::GetFocus() == m_hWnd && m_wndParent.IsWindow())
1976  {
1977  SetHotItem(-1);
1978  pT->GiveFocusBack();
1979  bHandled = TRUE;
1980  }
1981  }
1982  else if(wParam == VK_RETURN || wParam == VK_UP || wParam == VK_DOWN)
1983  {
1984  if(!m_bMenuActive && ::GetFocus() == m_hWnd && m_wndParent.IsWindow())
1985  {
1986  int nHot = GetHotItem();
1987  if(nHot != -1)
1988  {
1989  if(wParam != VK_RETURN)
1990  {
1991  if(!m_bSkipPostDown)
1992  {
1993 // IE4 only: WM_KEYDOWN doesn't generate TBN_DROPDOWN, we need to simulate a mouse click
1994 #if (_WIN32_IE < 0x0500)
1995  DWORD dwMajor = 0, dwMinor = 0;
1996  ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor);
1997  if(dwMajor <= 4 || (dwMajor == 5 && dwMinor < 80))
1998  {
1999  RECT rect;
2000  GetItemRect(nHot, &rect);
2001  PostMessage(WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(rect.left, rect.top));
2002  }
2003 #endif // (_WIN32_IE < 0x0500)
2004  PostMessage(WM_KEYDOWN, VK_DOWN, 0L);
2005  m_bSkipPostDown = true;
2006  }
2007  else
2008  {
2009  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - skipping posting another VK_DOWN\n"));
2010  m_bSkipPostDown = false;
2011  }
2012  }
2013  }
2014  else
2015  {
2016  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Can't find hot button\n"));
2017  }
2018  }
2019  if(wParam == VK_RETURN && m_bMenuActive)
2020  {
2021  PostMessage(TB_SETHOTITEM, (WPARAM)-1, 0L);
2022  m_nNextPopBtn = -1;
2023  pT->GiveFocusBack();
2024  }
2025  }
2026  else if(wParam == VK_LEFT || wParam == VK_RIGHT)
2027  {
2028  WPARAM wpNext = m_bLayoutRTL ? VK_LEFT : VK_RIGHT;
2029  WPARAM wpPrev = m_bLayoutRTL ? VK_RIGHT : VK_LEFT;
2030 
2031  if(m_bMenuActive && !m_bContextMenu && !(wParam == wpNext && m_bPopupItem))
2032  {
2033  bool bAction = false;
2034  if(wParam == wpPrev && s_pCurrentBar->m_stackMenuWnd.GetSize() == 1)
2035  {
2036  m_nNextPopBtn = pT->GetPreviousMenuItem(m_nPopBtn);
2037  if(m_nNextPopBtn != -1)
2038  bAction = true;
2039  }
2040  else if(wParam == wpNext)
2041  {
2042  m_nNextPopBtn = pT->GetNextMenuItem(m_nPopBtn);
2043  if(m_nNextPopBtn != -1)
2044  bAction = true;
2045  }
2046  HWND hWndMenu = m_stackMenuWnd.GetCurrent();
2047  ATLASSERT(hWndMenu != NULL);
2048 
2049  // Close the popup menu
2050  if(bAction)
2051  {
2052  ::PostMessage(hWndMenu, WM_KEYDOWN, VK_ESCAPE, 0L);
2053  if(wParam == wpNext)
2054  {
2055  int cItem = m_stackMenuWnd.GetSize() - 1;
2056  while(cItem >= 0)
2057  {
2058  hWndMenu = m_stackMenuWnd[cItem];
2059  if(hWndMenu != NULL)
2060  ::PostMessage(hWndMenu, WM_KEYDOWN, VK_ESCAPE, 0L);
2061  cItem--;
2062  }
2063  }
2064 #if (_WIN32_IE >= 0x0500)
2065  if(m_nNextPopBtn == -2)
2066  {
2067  m_nNextPopBtn = -1;
2068  pT->DisplayChevronMenu();
2069  }
2070 #endif // (_WIN32_IE >= 0x0500)
2071  bHandled = TRUE;
2072  }
2073  }
2074  }
2075  return 0;
2076  }
2077 
2078  LRESULT OnHookNextMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
2079  {
2080 #ifdef _CMDBAR_EXTRA_TRACE
2081  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_NEXTMENU\n"));
2082 #endif
2083  bHandled = FALSE;
2084  return 1;
2085  }
2086 
2087  LRESULT OnHookChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
2088  {
2089 #ifdef _CMDBAR_EXTRA_TRACE
2090  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook WM_CHAR (0x%2.2X)\n"), wParam);
2091 #endif
2092  bHandled = (wParam == VK_ESCAPE);
2093  return 0;
2094  }
2095 
2096 // Implementation - ownerdraw overrideables and helpers
2097  void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
2098  {
2099  T* pT = static_cast<T*>(this);
2100  if(m_bFlatMenus)
2101  pT->DrawItemFlat(lpDrawItemStruct);
2102  else
2103  pT->DrawItem3D(lpDrawItemStruct);
2104 
2105  }
2106 
2107  void DrawItem3D(LPDRAWITEMSTRUCT lpDrawItemStruct)
2108  {
2109  _MenuItemData* pmd = (_MenuItemData*)lpDrawItemStruct->itemData;
2110  CDCHandle dc = lpDrawItemStruct->hDC;
2111  const RECT& rcItem = lpDrawItemStruct->rcItem;
2112  T* pT = static_cast<T*>(this);
2113 
2114  if(pmd->fType & MFT_SEPARATOR)
2115  {
2116  // draw separator
2117  RECT rc = rcItem;
2118  rc.top += (rc.bottom - rc.top) / 2; // vertical center
2119  dc.DrawEdge(&rc, EDGE_ETCHED, BF_TOP); // draw separator line
2120  }
2121  else // not a separator
2122  {
2123  BOOL bDisabled = lpDrawItemStruct->itemState & ODS_GRAYED;
2124  BOOL bSelected = lpDrawItemStruct->itemState & ODS_SELECTED;
2125  BOOL bChecked = lpDrawItemStruct->itemState & ODS_CHECKED;
2126  BOOL bHasImage = FALSE;
2127 
2128  if(LOWORD(lpDrawItemStruct->itemID) == (WORD)-1)
2129  bSelected = FALSE;
2130  RECT rcButn = { rcItem.left, rcItem.top, rcItem.left + m_szButton.cx, rcItem.top + m_szButton.cy }; // button rect
2131  ::OffsetRect(&rcButn, 0, ((rcItem.bottom - rcItem.top) - (rcButn.bottom - rcButn.top)) / 2); // center vertically
2132 
2133  int iButton = pmd->iButton;
2134  if(iButton >= 0)
2135  {
2136  bHasImage = TRUE;
2137 
2138  // calc drawing point
2139  SIZE sz = { rcButn.right - rcButn.left - m_szBitmap.cx, rcButn.bottom - rcButn.top - m_szBitmap.cy };
2140  sz.cx /= 2;
2141  sz.cy /= 2;
2142  POINT point = { rcButn.left + sz.cx, rcButn.top + sz.cy };
2143 
2144  // fill background depending on state
2145  if(!bChecked || (bSelected && !bDisabled))
2146  {
2147  if(!bDisabled)
2148  dc.FillRect(&rcButn, (bChecked && !bSelected) ? COLOR_3DLIGHT : COLOR_MENU);
2149  else
2150  dc.FillRect(&rcButn, COLOR_MENU);
2151  }
2152  else
2153  {
2154  COLORREF crTxt = dc.SetTextColor(::GetSysColor(COLOR_BTNFACE));
2155  COLORREF crBk = dc.SetBkColor(::GetSysColor(COLOR_BTNHILIGHT));
2156  CBrush hbr(CDCHandle::GetHalftoneBrush());
2157  dc.SetBrushOrg(rcButn.left, rcButn.top);
2158  dc.FillRect(&rcButn, hbr);
2159  dc.SetTextColor(crTxt);
2160  dc.SetBkColor(crBk);
2161  }
2162 
2163  // draw disabled or normal
2164  if(!bDisabled)
2165  {
2166  // draw pushed-in or popped-out edge
2167  if(bSelected || bChecked)
2168  {
2169  RECT rc2 = rcButn;
2170  dc.DrawEdge(&rc2, bChecked ? BDR_SUNKENOUTER : BDR_RAISEDINNER, BF_RECT);
2171  }
2172  // draw the image
2173  ::ImageList_Draw(m_hImageList, iButton, dc, point.x, point.y, ILD_TRANSPARENT);
2174  }
2175  else
2176  {
2177  HBRUSH hBrushBackground = bChecked ? NULL : ::GetSysColorBrush(COLOR_MENU);
2178  pT->DrawBitmapDisabled(dc, iButton, point, hBrushBackground);
2179  }
2180  }
2181  else
2182  {
2183  // no image - look for custom checked/unchecked bitmaps
2185  info.fMask = MIIM_CHECKMARKS | MIIM_TYPE;
2186  ::GetMenuItemInfo((HMENU)lpDrawItemStruct->hwndItem, lpDrawItemStruct->itemID, MF_BYCOMMAND, &info);
2187  if(bChecked || info.hbmpUnchecked != NULL)
2188  {
2189  BOOL bRadio = ((info.fType & MFT_RADIOCHECK) != 0);
2190  bHasImage = pT->DrawCheckmark(dc, rcButn, bSelected, bDisabled, bRadio, bChecked ? info.hbmpChecked : info.hbmpUnchecked);
2191  }
2192  }
2193 
2194  // draw item text
2195  int cxButn = m_szButton.cx;
2196  COLORREF colorBG = ::GetSysColor(bSelected ? COLOR_HIGHLIGHT : COLOR_MENU);
2197  if(bSelected || lpDrawItemStruct->itemAction == ODA_SELECT)
2198  {
2199  RECT rcBG = rcItem;
2200  if(bHasImage)
2201  rcBG.left += cxButn + s_kcxGap;
2202  dc.FillRect(&rcBG, bSelected ? COLOR_HIGHLIGHT : COLOR_MENU);
2203  }
2204 
2205  // calc text rectangle and colors
2206  RECT rcText = rcItem;
2207  rcText.left += cxButn + s_kcxGap + s_kcxTextMargin;
2208  rcText.right -= cxButn;
2209  dc.SetBkMode(TRANSPARENT);
2210  COLORREF colorText = ::GetSysColor(bDisabled ? (bSelected ? COLOR_GRAYTEXT : COLOR_3DSHADOW) : (bSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT));
2211 
2212  // font already selected by Windows
2213  if(bDisabled && (!bSelected || colorText == colorBG))
2214  {
2215  // disabled - draw shadow text shifted down and right 1 pixel (unles selected)
2216  RECT rcDisabled = rcText;
2217  ::OffsetRect(&rcDisabled, 1, 1);
2218  pT->DrawMenuText(dc, rcDisabled, pmd->lpstrText, ::GetSysColor(COLOR_3DHILIGHT));
2219  }
2220  pT->DrawMenuText(dc, rcText, pmd->lpstrText, colorText); // finally!
2221  }
2222  }
2223 
2224  void DrawItemFlat(LPDRAWITEMSTRUCT lpDrawItemStruct)
2225  {
2226  _MenuItemData* pmd = (_MenuItemData*)lpDrawItemStruct->itemData;
2227  CDCHandle dc = lpDrawItemStruct->hDC;
2228  const RECT& rcItem = lpDrawItemStruct->rcItem;
2229  T* pT = static_cast<T*>(this);
2230 
2231 #ifndef COLOR_MENUHILIGHT
2232  const int COLOR_MENUHILIGHT = 29;
2233 #endif // !COLOR_MENUHILIGHT
2234 
2235  BOOL bDisabled = lpDrawItemStruct->itemState & ODS_GRAYED;
2236  BOOL bSelected = lpDrawItemStruct->itemState & ODS_SELECTED;
2237  BOOL bChecked = lpDrawItemStruct->itemState & ODS_CHECKED;
2238 
2239  // paint background
2240  if(bSelected || lpDrawItemStruct->itemAction == ODA_SELECT)
2241  {
2242  if(bSelected)
2243  {
2244  dc.FillRect(&rcItem, ::GetSysColorBrush(COLOR_MENUHILIGHT));
2245  dc.FrameRect(&rcItem, ::GetSysColorBrush(COLOR_HIGHLIGHT));
2246  }
2247  else
2248  {
2249  dc.FillRect(&rcItem, ::GetSysColorBrush(COLOR_MENU));
2250  }
2251  }
2252 
2253  if(pmd->fType & MFT_SEPARATOR)
2254  {
2255  // draw separator
2256  RECT rc = rcItem;
2257  rc.top += (rc.bottom - rc.top) / 2; // vertical center
2258  dc.DrawEdge(&rc, EDGE_ETCHED, BF_TOP); // draw separator line
2259  }
2260  else // not a separator
2261  {
2262  if(LOWORD(lpDrawItemStruct->itemID) == (WORD)-1)
2263  bSelected = FALSE;
2264  RECT rcButn = { rcItem.left, rcItem.top, rcItem.left + m_szButton.cx, rcItem.top + m_szButton.cy }; // button rect
2265  ::OffsetRect(&rcButn, 0, ((rcItem.bottom - rcItem.top) - (rcButn.bottom - rcButn.top)) / 2); // center vertically
2266 
2267  // draw background and border for checked items
2268  if(bChecked)
2269  {
2270  RECT rcCheck = rcButn;
2271  ::InflateRect(&rcCheck, -1, -1);
2272  if(bSelected)
2273  dc.FillRect(&rcCheck, ::GetSysColorBrush(COLOR_MENU));
2274  dc.FrameRect(&rcCheck, ::GetSysColorBrush(COLOR_HIGHLIGHT));
2275  }
2276 
2277  int iButton = pmd->iButton;
2278  if(iButton >= 0)
2279  {
2280  // calc drawing point
2281  SIZE sz = { rcButn.right - rcButn.left - m_szBitmap.cx, rcButn.bottom - rcButn.top - m_szBitmap.cy };
2282  sz.cx /= 2;
2283  sz.cy /= 2;
2284  POINT point = { rcButn.left + sz.cx, rcButn.top + sz.cy };
2285 
2286  // draw disabled or normal
2287  if(!bDisabled)
2288  {
2289  ::ImageList_Draw(m_hImageList, iButton, dc, point.x, point.y, ILD_TRANSPARENT);
2290  }
2291  else
2292  {
2293  HBRUSH hBrushBackground = ::GetSysColorBrush((bSelected && !(bDisabled && bChecked)) ? COLOR_MENUHILIGHT : COLOR_MENU);
2294  HBRUSH hBrushDisabledImage = ::GetSysColorBrush(COLOR_3DSHADOW);
2295  pT->DrawBitmapDisabled(dc, iButton, point, hBrushBackground, hBrushBackground, hBrushDisabledImage);
2296  }
2297  }
2298  else
2299  {
2300  // no image - look for custom checked/unchecked bitmaps
2302  info.fMask = MIIM_CHECKMARKS | MIIM_TYPE;
2303  ::GetMenuItemInfo((HMENU)lpDrawItemStruct->hwndItem, lpDrawItemStruct->itemID, MF_BYCOMMAND, &info);
2304  if(bChecked || info.hbmpUnchecked != NULL)
2305  {
2306  BOOL bRadio = ((info.fType & MFT_RADIOCHECK) != 0);
2307  pT->DrawCheckmark(dc, rcButn, bSelected, bDisabled, bRadio, bChecked ? info.hbmpChecked : info.hbmpUnchecked);
2308  }
2309  }
2310 
2311  // draw item text
2312  int cxButn = m_szButton.cx;
2313  // calc text rectangle and colors
2314  RECT rcText = rcItem;
2315  rcText.left += cxButn + s_kcxGap + s_kcxTextMargin;
2316  rcText.right -= cxButn;
2317  dc.SetBkMode(TRANSPARENT);
2318  COLORREF colorText = ::GetSysColor(bDisabled ? (bSelected ? COLOR_GRAYTEXT : COLOR_3DSHADOW) : (bSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT));
2319 
2320  pT->DrawMenuText(dc, rcText, pmd->lpstrText, colorText); // finally!
2321  }
2322  }
2323 
2324  void DrawMenuText(CDCHandle& dc, RECT& rc, LPCTSTR lpstrText, COLORREF color)
2325  {
2326  int nTab = -1;
2327  for(int i = 0; i < lstrlen(lpstrText); i++)
2328  {
2329  if(lpstrText[i] == _T('\t'))
2330  {
2331  nTab = i;
2332  break;
2333  }
2334  }
2335  dc.SetTextColor(color);
2336  dc.DrawText(lpstrText, nTab, &rc, DT_SINGLELINE | DT_LEFT | DT_VCENTER | (m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX));
2337  if(nTab != -1)
2338  dc.DrawText(&lpstrText[nTab + 1], -1, &rc, DT_SINGLELINE | DT_RIGHT | DT_VCENTER | (m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX));
2339  }
2340 
2341  void DrawBitmapDisabled(CDCHandle& dc, int nImage, POINT point,
2342  HBRUSH hBrushBackground = ::GetSysColorBrush(COLOR_3DFACE),
2343  HBRUSH hBrush3DEffect = ::GetSysColorBrush(COLOR_3DHILIGHT),
2344  HBRUSH hBrushDisabledImage = ::GetSysColorBrush(COLOR_3DSHADOW))
2345  {
2346 #if (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)
2347  if(m_bAlphaImages)
2348  {
2349  IMAGELISTDRAWPARAMS ildp = { 0 };
2350  ildp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
2351  ildp.himl = m_hImageList;
2352  ildp.i = nImage;
2353  ildp.hdcDst = dc;
2354  ildp.x = point.x;
2355  ildp.y = point.y;
2356  ildp.cx = 0;
2357  ildp.cy = 0;
2358  ildp.xBitmap = 0;
2359  ildp.yBitmap = 0;
2360  ildp.fStyle = ILD_TRANSPARENT;
2361  ildp.fState = ILS_SATURATE;
2362  ildp.Frame = 0;
2363  ::ImageList_DrawIndirect(&ildp);
2364  }
2365  else
2366 #endif // (_WIN32_WINNT >= 0x0501) && (_WIN32_IE >= 0x0501)
2367  {
2368  // create memory DC
2369  CDC dcMem;
2370  dcMem.CreateCompatibleDC(dc);
2371  // create mono or color bitmap
2372  CBitmap bmp;
2373  bmp.CreateCompatibleBitmap(dc, m_szBitmap.cx, m_szBitmap.cy);
2374  ATLASSERT(bmp.m_hBitmap != NULL);
2375  // draw image into memory DC--fill BG white first
2376  HBITMAP hBmpOld = dcMem.SelectBitmap(bmp);
2377  dcMem.PatBlt(0, 0, m_szBitmap.cx, m_szBitmap.cy, WHITENESS);
2378  // If white is the text color, we can't use the normal painting since
2379  // it would blend with the WHITENESS, but the mask is OK
2380  UINT uDrawStyle = (::GetSysColor(COLOR_BTNTEXT) == RGB(255, 255, 255)) ? ILD_MASK : ILD_NORMAL;
2381  ::ImageList_Draw(m_hImageList, nImage, dcMem, 0, 0, uDrawStyle);
2382  dc.DitherBlt(point.x, point.y, m_szBitmap.cx, m_szBitmap.cy, dcMem, NULL, 0, 0, hBrushBackground, hBrush3DEffect, hBrushDisabledImage);
2383  dcMem.SelectBitmap(hBmpOld); // restore
2384  }
2385  }
2386 
2387  // old name
2388  BOOL Draw3DCheckmark(CDCHandle& dc, const RECT& rc, BOOL bSelected, BOOL bDisabled, BOOL bRadio, HBITMAP hBmpCheck)
2389  {
2390  return DrawCheckmark(dc, rc, bSelected, bDisabled, bRadio, hBmpCheck);
2391  }
2392 
2393  BOOL DrawCheckmark(CDCHandle& dc, const RECT& rc, BOOL bSelected, BOOL bDisabled, BOOL bRadio, HBITMAP hBmpCheck)
2394  {
2395  // get checkmark bitmap, if none, use Windows standard
2396  SIZE size = { 0, 0 };
2397  CBitmapHandle bmp = hBmpCheck;
2398  if(hBmpCheck != NULL)
2399  {
2400  bmp.GetSize(size);
2401  }
2402  else
2403  {
2404  size.cx = ::GetSystemMetrics(SM_CXMENUCHECK);
2405  size.cy = ::GetSystemMetrics(SM_CYMENUCHECK);
2406  bmp.CreateCompatibleBitmap(dc, size.cx, size.cy);
2407  ATLASSERT(bmp.m_hBitmap != NULL);
2408  }
2409  // center bitmap in caller's rectangle
2410  RECT rcDest = rc;
2411  if((rc.right - rc.left) > size.cx)
2412  {
2413  rcDest.left = rc.left + (rc.right - rc.left - size.cx) / 2;
2414  rcDest.right = rcDest.left + size.cx;
2415  }
2416  if((rc.bottom - rc.top) > size.cy)
2417  {
2418  rcDest.top = rc.top + (rc.bottom - rc.top - size.cy) / 2;
2419  rcDest.bottom = rcDest.top + size.cy;
2420  }
2421  // paint background
2422  if(!m_bFlatMenus)
2423  {
2424  if(bSelected && !bDisabled)
2425  {
2426  dc.FillRect(&rcDest, COLOR_MENU);
2427  }
2428  else
2429  {
2430  COLORREF clrTextOld = dc.SetTextColor(::GetSysColor(COLOR_BTNFACE));
2431  COLORREF clrBkOld = dc.SetBkColor(::GetSysColor(COLOR_BTNHILIGHT));
2432  CBrush hbr(CDCHandle::GetHalftoneBrush());
2433  dc.SetBrushOrg(rcDest.left, rcDest.top);
2434  dc.FillRect(&rcDest, hbr);
2435  dc.SetTextColor(clrTextOld);
2436  dc.SetBkColor(clrBkOld);
2437  }
2438  }
2439 
2440  // create source image
2441  CDC dcSource;
2442  dcSource.CreateCompatibleDC(dc);
2443  HBITMAP hBmpOld = dcSource.SelectBitmap(bmp);
2444  // set colors
2445  const COLORREF clrBlack = RGB(0, 0, 0);
2446  const COLORREF clrWhite = RGB(255, 255, 255);
2447  COLORREF clrTextOld = dc.SetTextColor(clrBlack);
2448  COLORREF clrBkOld = dc.SetBkColor(clrWhite);
2449  // create mask
2450  CDC dcMask;
2451  dcMask.CreateCompatibleDC(dc);
2452  CBitmap bmpMask;
2453  bmpMask.CreateBitmap(size.cx, size.cy, 1, 1, NULL);
2454  HBITMAP hBmpOld1 = dcMask.SelectBitmap(bmpMask);
2455 
2456  // draw the checkmark transparently
2457  int cx = rcDest.right - rcDest.left;
2458  int cy = rcDest.bottom - rcDest.top;
2459  if(hBmpCheck != NULL)
2460  {
2461  // build mask based on transparent color
2462  dcSource.SetBkColor(m_clrMask);
2463  dcMask.SetBkColor(clrBlack);
2464  dcMask.SetTextColor(clrWhite);
2465  dcMask.BitBlt(0, 0, size.cx, size.cy, dcSource, 0, 0, SRCCOPY);
2466  // draw bitmap using the mask
2467  dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, SRCINVERT);
2468  dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcMask, 0, 0, SRCAND);
2469  dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, SRCINVERT);
2470  }
2471  else
2472  {
2473  const DWORD ROP_DSno = 0x00BB0226L;
2474  const DWORD ROP_DSa = 0x008800C6L;
2475  const DWORD ROP_DSo = 0x00EE0086L;
2476  const DWORD ROP_DSna = 0x00220326L;
2477 
2478  // draw mask
2479  RECT rcSource = { 0, 0, min(size.cx, rc.right - rc.left), min(size.cy, rc.bottom - rc.top) };
2480  dcMask.DrawFrameControl(&rcSource, DFC_MENU, bRadio ? DFCS_MENUBULLET : DFCS_MENUCHECK);
2481 
2482  // draw shadow if disabled
2483  if(!m_bFlatMenus && bDisabled)
2484  {
2485  // offset by one pixel
2486  int x = rcDest.left + 1;
2487  int y = rcDest.top + 1;
2488  // paint source bitmap
2489  const int nColor = COLOR_3DHILIGHT;
2490  dcSource.FillRect(&rcSource, nColor);
2491  // draw checkmark - special case black and white colors
2492  COLORREF clrCheck = ::GetSysColor(nColor);
2493  if(clrCheck == clrWhite)
2494  {
2495  dc.BitBlt(x, y, cx, cy, dcMask, 0, 0, ROP_DSno);
2496  dc.BitBlt(x, y, cx, cy, dcSource, 0, 0, ROP_DSa);
2497  }
2498  else
2499  {
2500  if(clrCheck != clrBlack)
2501  {
2502  ATLASSERT(dcSource.GetTextColor() == clrBlack);
2503  ATLASSERT(dcSource.GetBkColor() == clrWhite);
2504  dcSource.BitBlt(0, 0, size.cx, size.cy, dcMask, 0, 0, ROP_DSna);
2505  }
2506  dc.BitBlt(x, y, cx, cy, dcMask, 0, 0, ROP_DSa);
2507  dc.BitBlt(x, y, cx, cy, dcSource, 0, 0, ROP_DSo);
2508  }
2509  }
2510 
2511  // paint source bitmap
2512  const int nColor = bDisabled ? COLOR_BTNSHADOW : COLOR_MENUTEXT;
2513  dcSource.FillRect(&rcSource, nColor);
2514  // draw checkmark - special case black and white colors
2515  COLORREF clrCheck = ::GetSysColor(nColor);
2516  if(clrCheck == clrWhite)
2517  {
2518  dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcMask, 0, 0, ROP_DSno);
2519  dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, ROP_DSa);
2520  }
2521  else
2522  {
2523  if(clrCheck != clrBlack)
2524  {
2525  ATLASSERT(dcSource.GetTextColor() == clrBlack);
2526  ATLASSERT(dcSource.GetBkColor() == clrWhite);
2527  dcSource.BitBlt(0, 0, size.cx, size.cy, dcMask, 0, 0, ROP_DSna);
2528  }
2529  dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcMask, 0, 0, ROP_DSa);
2530  dc.BitBlt(rcDest.left, rcDest.top, cx, cy, dcSource, 0, 0, ROP_DSo);
2531  }
2532  }
2533  // restore all
2534  dc.SetTextColor(clrTextOld);
2535  dc.SetBkColor(clrBkOld);
2536  dcSource.SelectBitmap(hBmpOld);
2537  dcMask.SelectBitmap(hBmpOld1);
2538  if(hBmpCheck == NULL)
2539  bmp.DeleteObject();
2540  // draw pushed-in hilight
2541  if(!m_bFlatMenus && !bDisabled)
2542  {
2543  if(rc.right - rc.left > size.cx)
2544  ::InflateRect(&rcDest, 1,1); // inflate checkmark by one pixel all around
2545  dc.DrawEdge(&rcDest, BDR_SUNKENOUTER, BF_RECT);
2546  }
2547 
2548  return TRUE;
2549  }
2550 
2551  void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
2552  {
2553  _MenuItemData* pmd = (_MenuItemData*)lpMeasureItemStruct->itemData;
2554 
2555  if(pmd->fType & MFT_SEPARATOR) // separator - use half system height and zero width
2556  {
2557  lpMeasureItemStruct->itemHeight = ::GetSystemMetrics(SM_CYMENU) / 2;
2558  lpMeasureItemStruct->itemWidth = 0;
2559  }
2560  else
2561  {
2562  // compute size of text - use DrawText with DT_CALCRECT
2563  CWindowDC dc(NULL);
2564  CFont fontBold;
2565  HFONT hOldFont = NULL;
2566  if(pmd->fState & MFS_DEFAULT)
2567  {
2568  // need bold version of font
2569  LOGFONT lf = { 0 };
2570  m_fontMenu.GetLogFont(lf);
2571  lf.lfWeight += 200;
2572  fontBold.CreateFontIndirect(&lf);
2573  ATLASSERT(fontBold.m_hFont != NULL);
2574  hOldFont = dc.SelectFont(fontBold);
2575  }
2576  else
2577  {
2578  hOldFont = dc.SelectFont(m_fontMenu);
2579  }
2580 
2581  RECT rcText = { 0, 0, 0, 0 };
2582  dc.DrawText(pmd->lpstrText, -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT);
2583  int cx = rcText.right - rcText.left;
2584  dc.SelectFont(hOldFont);
2585 
2586  LOGFONT lf = { 0 };
2587  m_fontMenu.GetLogFont(lf);
2588  int cy = lf.lfHeight;
2589  if(cy < 0)
2590  cy = -cy;
2591  const int cyMargin = 8;
2592  cy += cyMargin;
2593 
2594  // height of item is the bigger of these two
2595  lpMeasureItemStruct->itemHeight = max(cy, (int)m_szButton.cy);
2596 
2597  // width is width of text plus a bunch of stuff
2598  cx += 2 * s_kcxTextMargin; // L/R margin for readability
2599  cx += s_kcxGap; // space between button and menu text
2600  cx += 2 * m_szButton.cx; // button width (L=button; R=empty margin)
2601  cx += m_cxExtraSpacing; // extra between item text and accelerator keys
2602 
2603  // Windows adds 1 to returned value
2604  cx -= ::GetSystemMetrics(SM_CXMENUCHECK) - 1;
2605  lpMeasureItemStruct->itemWidth = cx; // done deal
2606  }
2607  }
2608 
2609 // Implementation - Hook procs
2610  static LRESULT CALLBACK CreateHookProc(int nCode, WPARAM wParam, LPARAM lParam)
2611  {
2612  const int cchClassName = 7;
2613  TCHAR szClassName[cchClassName] = { 0 };
2614 
2615  if(nCode == HCBT_CREATEWND)
2616  {
2617  HWND hWndMenu = (HWND)wParam;
2618 #ifdef _CMDBAR_EXTRA_TRACE
2619  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - HCBT_CREATEWND (HWND = %8.8X)\n"), hWndMenu);
2620 #endif
2621 
2622  ::GetClassName(hWndMenu, szClassName, cchClassName);
2623  if(!lstrcmp(_T("#32768"), szClassName))
2624  s_pCurrentBar->m_stackMenuWnd.Push(hWndMenu);
2625  }
2626  else if(nCode == HCBT_DESTROYWND)
2627  {
2628  HWND hWndMenu = (HWND)wParam;
2629 #ifdef _CMDBAR_EXTRA_TRACE
2630  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - HCBT_DESTROYWND (HWND = %8.8X)\n"), hWndMenu);
2631 #endif
2632 
2633  ::GetClassName(hWndMenu, szClassName, cchClassName);
2634  if(!lstrcmp(_T("#32768"), szClassName))
2635  {
2636  ATLASSERT(hWndMenu == s_pCurrentBar->m_stackMenuWnd.GetCurrent());
2637  s_pCurrentBar->m_stackMenuWnd.Pop();
2638  }
2639  }
2640 
2641  return ::CallNextHookEx(s_hCreateHook, nCode, wParam, lParam);
2642  }
2643 
2644  static LRESULT CALLBACK MessageHookProc(int nCode, WPARAM wParam, LPARAM lParam)
2645  {
2646  LPMSG pMsg = (LPMSG)lParam;
2647 
2648  if(nCode == HC_ACTION && wParam == PM_REMOVE && pMsg->message != GetGetBarMessage() && pMsg->message != WM_FORWARDMSG)
2649  {
2650  CCommandBarCtrlBase* pCmdBar = NULL;
2651  HWND hWnd = pMsg->hwnd;
2652  DWORD dwPID = 0;
2653  while(pCmdBar == NULL && hWnd != NULL)
2654  {
2655  pCmdBar = (CCommandBarCtrlBase*)::SendMessage(hWnd, GetGetBarMessage(), (WPARAM)&dwPID, 0L);
2656  hWnd = ::GetParent(hWnd);
2657  }
2658 
2659  if(pCmdBar != NULL && dwPID == GetCurrentProcessId())
2660  {
2661  pCmdBar->m_hWndHook = pMsg->hwnd;
2662  ATLASSERT(pCmdBar->IsCommandBarBase());
2663 
2664  if(::IsWindow(pCmdBar->m_hWnd))
2665  pCmdBar->SendMessage(WM_FORWARDMSG, 0, (LPARAM)pMsg);
2666  else
2667  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - Hook skipping message, can't find command bar!\n"));
2668  }
2669  }
2670 
2671  LRESULT lRet = 0;
2672  ATLASSERT(s_pmapMsgHook != NULL);
2673  if(s_pmapMsgHook != NULL)
2674  {
2675  DWORD dwThreadID = ::GetCurrentThreadId();
2676  _MsgHookData* pData = s_pmapMsgHook->Lookup(dwThreadID);
2677  if(pData != NULL)
2678  {
2679  lRet = ::CallNextHookEx(pData->hMsgHook, nCode, wParam, lParam);
2680  }
2681  }
2682  return lRet;
2683  }
2684 
2685 // Implementation
2686  void DoPopupMenu(int nIndex, bool bAnimate)
2687  {
2688 #ifdef _CMDBAR_EXTRA_TRACE
2689  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - DoPopupMenu, bAnimate = %s\n"), bAnimate ? "true" : "false");
2690 #endif
2691 
2692  // Menu animation flags
2693 #ifndef TPM_VERPOSANIMATION
2694  const UINT TPM_VERPOSANIMATION = 0x1000L;
2695 #endif
2696 #ifndef TPM_NOANIMATION
2697  const UINT TPM_NOANIMATION = 0x4000L;
2698 #endif
2699  T* pT = static_cast<T*>(this);
2700 
2701  // get popup menu and it's position
2702  RECT rect = { 0 };
2703  GetItemRect(nIndex, &rect);
2704  POINT pt = { rect.left, rect.bottom };
2705  MapWindowPoints(NULL, &pt, 1);
2706  MapWindowPoints(NULL, &rect);
2707  TPMPARAMS TPMParams = { 0 };
2708  TPMParams.cbSize = sizeof(TPMPARAMS);
2709  TPMParams.rcExclude = rect;
2710  HMENU hMenuPopup = ::GetSubMenu(m_hMenu, nIndex);
2711  ATLASSERT(hMenuPopup != NULL);
2712 
2713  // get button ID
2714  TBBUTTON tbb = { 0 };
2715  GetButton(nIndex, &tbb);
2716  int nCmdID = tbb.idCommand;
2717 
2718  m_nPopBtn = nIndex; // remember current button's index
2719 
2720  // press button and display popup menu
2721  PressButton(nCmdID, TRUE);
2722  SetHotItem(nCmdID);
2723  pT->DoTrackPopupMenu(hMenuPopup, TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN |
2724  (s_bW2K ? (bAnimate ? TPM_VERPOSANIMATION : TPM_NOANIMATION) : 0), pt.x, pt.y, &TPMParams);
2725  PressButton(nCmdID, FALSE);
2726  if(::GetFocus() != m_hWnd)
2727  SetHotItem(-1);
2728 
2729  m_nPopBtn = -1; // restore
2730 
2731  // eat next message if click is on the same button
2732  MSG msg = { 0 };
2733  if(::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rect, msg.pt))
2734  ::PeekMessage(&msg, m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE);
2735 
2736  // check if another popup menu should be displayed
2737  if(m_nNextPopBtn != -1)
2738  {
2739  PostMessage(GetAutoPopupMessage(), m_nNextPopBtn & 0xFFFF);
2740  if(!(m_nNextPopBtn & 0xFFFF0000) && !m_bPopupItem)
2741  PostMessage(WM_KEYDOWN, VK_DOWN, 0);
2742  m_nNextPopBtn = -1;
2743  }
2744  else
2745  {
2746  m_bContextMenu = false;
2747  // If user didn't hit escape, give focus back
2748  if(!m_bEscapePressed)
2749  {
2750  if(m_bUseKeyboardCues && m_bShowKeyboardCues)
2751  m_bAllowKeyboardCues = false;
2752  pT->GiveFocusBack();
2753  }
2754  else
2755  {
2756  SetHotItem(nCmdID);
2757  SetAnchorHighlight(TRUE);
2758  }
2759  }
2760  }
2761 
2762  BOOL DoTrackPopupMenu(HMENU hMenu, UINT uFlags, int x, int y, LPTPMPARAMS lpParams = NULL)
2763  {
2764  CMenuHandle menuPopup = hMenu;
2765 
2767  if(FAILED(lock.Lock()))
2768  {
2769  ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::DoTrackPopupMenu.\n"));
2770  ATLASSERT(FALSE);
2771  return FALSE;
2772  }
2773 
2774  ATLASSERT(s_hCreateHook == NULL);
2775 
2776  s_pCurrentBar = static_cast<CCommandBarCtrlBase*>(this);
2777 
2778  s_hCreateHook = ::SetWindowsHookEx(WH_CBT, CreateHookProc, ModuleHelper::GetModuleInstance(), GetCurrentThreadId());
2779  ATLASSERT(s_hCreateHook != NULL);
2780 
2781  m_bPopupItem = false;
2782  m_bMenuActive = true;
2783 
2784  BOOL bTrackRet = menuPopup.TrackPopupMenuEx(uFlags, x, y, m_hWnd, lpParams);
2785  m_bMenuActive = false;
2786 
2787  ::UnhookWindowsHookEx(s_hCreateHook);
2788 
2789  s_hCreateHook = NULL;
2790  s_pCurrentBar = NULL;
2791 
2792  lock.Unlock();
2793 
2794  // cleanup - convert menus back to original state
2795 #ifdef _CMDBAR_EXTRA_TRACE
2796  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - TrackPopupMenu - cleanup\n"));
2797 #endif
2798 
2799  ATLASSERT(m_stackMenuWnd.GetSize() == 0);
2800 
2801  UpdateWindow();
2802  ATL::CWindow wndTL = GetTopLevelParent();
2803  wndTL.UpdateWindow();
2804 
2805  // restore the menu items to the previous state for all menus that were converted
2806  if(m_bImagesVisible)
2807  {
2808  HMENU hMenuSav = NULL;
2809  while((hMenuSav = m_stackMenuHandle.Pop()) != NULL)
2810  {
2811  menuPopup = hMenuSav;
2812  BOOL bRet = FALSE;
2813  // restore state and delete menu item data
2814  for(int i = 0; i < menuPopup.GetMenuItemCount(); i++)
2815  {
2816  CMenuItemInfo mii;
2817  mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID;
2818  bRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii);
2819  ATLASSERT(bRet);
2820 
2821  _MenuItemData* pMI = (_MenuItemData*)mii.dwItemData;
2822  if(pMI != NULL && pMI->IsCmdBarMenuItem())
2823  {
2824  mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE;
2825  mii.fType = pMI->fType;
2826  mii.fState = pMI->fState;
2827  mii.dwTypeData = pMI->lpstrText;
2828  mii.cch = lstrlen(pMI->lpstrText);
2829  mii.dwItemData = NULL;
2830 
2831  bRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii);
2832  // this one triggers WM_MEASUREITEM
2833  menuPopup.ModifyMenu(i, MF_BYPOSITION | mii.fType | mii.fState, mii.wID, pMI->lpstrText);
2834  ATLASSERT(bRet);
2835 
2836  delete [] pMI->lpstrText;
2837  delete pMI;
2838  }
2839  }
2840  }
2841  }
2842  return bTrackRet;
2843  }
2844 
2845  int GetPreviousMenuItem(int nBtn) const
2846  {
2847  if(nBtn == -1)
2848  return -1;
2849 #if (_WIN32_IE >= 0x0500)
2850  RECT rcClient;
2851  GetClientRect(&rcClient);
2852 #endif // (_WIN32_IE >= 0x0500)
2853  int nNextBtn;
2854  for(nNextBtn = nBtn - 1; nNextBtn != nBtn; nNextBtn--)
2855  {
2856  if(nNextBtn < 0)
2857  nNextBtn = ::GetMenuItemCount(m_hMenu) - 1;
2858  TBBUTTON tbb = { 0 };
2859  GetButton(nNextBtn, &tbb);
2860 #if (_WIN32_IE >= 0x0500)
2861  RECT rcBtn;
2862  GetItemRect(nNextBtn, &rcBtn);
2863  if(rcBtn.right > rcClient.right)
2864  {
2865  nNextBtn = -2; // chevron
2866  break;
2867  }
2868 #endif // (_WIN32_IE >= 0x0500)
2869  if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0)
2870  break;
2871  }
2872  return (nNextBtn != nBtn) ? nNextBtn : -1;
2873  }
2874 
2875  int GetNextMenuItem(int nBtn) const
2876  {
2877  if(nBtn == -1)
2878  return -1;
2879 #if (_WIN32_IE >= 0x0500)
2880  RECT rcClient = { 0 };
2881  GetClientRect(&rcClient);
2882 #endif // (_WIN32_IE >= 0x0500)
2883  int nNextBtn = 0;
2884  int nCount = ::GetMenuItemCount(m_hMenu);
2885  for(nNextBtn = nBtn + 1; nNextBtn != nBtn; nNextBtn++)
2886  {
2887  if(nNextBtn >= nCount)
2888  nNextBtn = 0;
2889  TBBUTTON tbb = { 0 };
2890  GetButton(nNextBtn, &tbb);
2891 #if (_WIN32_IE >= 0x0500)
2892  RECT rcBtn = { 0 };
2893  GetItemRect(nNextBtn, &rcBtn);
2894  if(rcBtn.right > rcClient.right)
2895  {
2896  nNextBtn = -2; // chevron
2897  break;
2898  }
2899 #endif // (_WIN32_IE >= 0x0500)
2900  if((tbb.fsState & TBSTATE_ENABLED) != 0 && (tbb.fsState & TBSTATE_HIDDEN) == 0)
2901  break;
2902  }
2903  return (nNextBtn != nBtn) ? nNextBtn : -1;
2904  }
2905 
2906 #if (_WIN32_IE >= 0x0500)
2907  bool DisplayChevronMenu()
2908  {
2909  // assume we are in a rebar
2910  HWND hWndReBar = GetParent();
2911  int nCount = (int)::SendMessage(hWndReBar, RB_GETBANDCOUNT, 0, 0L);
2912  bool bRet = false;
2913  for(int i = 0; i < nCount; i++)
2914  {
2915  REBARBANDINFO rbbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_STYLE };
2916  BOOL bRetBandInfo = (BOOL)::SendMessage(hWndReBar, RB_GETBANDINFO, i, (LPARAM)&rbbi);
2917  if(bRetBandInfo && rbbi.hwndChild == m_hWnd)
2918  {
2919  if((rbbi.fStyle & RBBS_USECHEVRON) != 0)
2920  {
2921  ::PostMessage(hWndReBar, RB_PUSHCHEVRON, i, 0L);
2922  PostMessage(WM_KEYDOWN, VK_DOWN, 0L);
2923  bRet = true;
2924  }
2925  break;
2926  }
2927  }
2928  return bRet;
2929  }
2930 #endif // (_WIN32_IE >= 0x0500)
2931 
2932  void GetSystemSettings()
2933  {
2934  // refresh our font
2935  NONCLIENTMETRICS info = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() };
2936  BOOL bRet = ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
2937  ATLASSERT(bRet);
2938  if(bRet)
2939  {
2940  LOGFONT logfont = { 0 };
2941  if(m_fontMenu.m_hFont != NULL)
2942  m_fontMenu.GetLogFont(logfont);
2943  if(logfont.lfHeight != info.lfMenuFont.lfHeight ||
2944  logfont.lfWidth != info.lfMenuFont.lfWidth ||
2945  logfont.lfEscapement != info.lfMenuFont.lfEscapement ||
2946  logfont.lfOrientation != info.lfMenuFont.lfOrientation ||
2947  logfont.lfWeight != info.lfMenuFont.lfWeight ||
2948  logfont.lfItalic != info.lfMenuFont.lfItalic ||
2949  logfont.lfUnderline != info.lfMenuFont.lfUnderline ||
2950  logfont.lfStrikeOut != info.lfMenuFont.lfStrikeOut ||
2951  logfont.lfCharSet != info.lfMenuFont.lfCharSet ||
2952  logfont.lfOutPrecision != info.lfMenuFont.lfOutPrecision ||
2953  logfont.lfClipPrecision != info.lfMenuFont.lfClipPrecision ||
2954  logfont.lfQuality != info.lfMenuFont.lfQuality ||
2955  logfont.lfPitchAndFamily != info.lfMenuFont.lfPitchAndFamily ||
2956  lstrcmp(logfont.lfFaceName, info.lfMenuFont.lfFaceName) != 0)
2957  {
2958  HFONT hFontMenu = ::CreateFontIndirect(&info.lfMenuFont);
2959  ATLASSERT(hFontMenu != NULL);
2960  if(hFontMenu != NULL)
2961  {
2962  if(m_fontMenu.m_hFont != NULL)
2963  m_fontMenu.DeleteObject();
2964  m_fontMenu.Attach(hFontMenu);
2965  SetFont(m_fontMenu);
2966  AddStrings(_T("NS\0")); // for proper item height
2967  AutoSize();
2968  }
2969  }
2970  }
2971 
2972  // check if we need extra spacing for menu item text
2973  CWindowDC dc(m_hWnd);
2974  HFONT hFontOld = dc.SelectFont(m_fontMenu);
2975  RECT rcText = { 0, 0, 0, 0 };
2976  dc.DrawText(_T("\t"), -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT);
2977  if((rcText.right - rcText.left) < 4)
2978  {
2979  ::SetRectEmpty(&rcText);
2980  dc.DrawText(_T("x"), -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT);
2981  m_cxExtraSpacing = rcText.right - rcText.left;
2982  }
2983  else
2984  {
2985  m_cxExtraSpacing = 0;
2986  }
2987  dc.SelectFont(hFontOld);
2988 
2989  // get Windows version
2990  OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) };
2991  ::GetVersionEx(&ovi);
2992 
2993  // query keyboard cues mode (Windows 2000 or later)
2994  if(ovi.dwMajorVersion >= 5)
2995  {
2996 #ifndef SPI_GETKEYBOARDCUES
2997  const UINT SPI_GETKEYBOARDCUES = 0x100A;
2998 #endif // !SPI_GETKEYBOARDCUES
2999  BOOL bRetVal = TRUE;
3000  bRet = ::SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &bRetVal, 0);
3001  m_bUseKeyboardCues = (bRet && !bRetVal);
3002  m_bAllowKeyboardCues = true;
3003  ShowKeyboardCues(!m_bUseKeyboardCues);
3004  }
3005 
3006  // query flat menu mode (Windows XP or later)
3007  if((ovi.dwMajorVersion == 5 && ovi.dwMinorVersion >= 1) || (ovi.dwMajorVersion > 5))
3008  {
3009 #ifndef SPI_GETFLATMENU
3010  const UINT SPI_GETFLATMENU = 0x1022;
3011 #endif // !SPI_GETFLATMENU
3012  BOOL bRetVal = FALSE;
3013  bRet = ::SystemParametersInfo(SPI_GETFLATMENU, 0, &bRetVal, 0);
3014  m_bFlatMenus = (bRet && bRetVal);
3015  }
3016 
3017 #if _WTL_CMDBAR_VISTA_MENUS
3018  // check if we should use Vista menus
3019  bool bVistaMenus = (RunTimeHelper::IsVista() && RunTimeHelper::IsCommCtrl6() && ((m_dwExtendedStyle & CBR_EX_NOVISTAMENUS) == 0));
3020 
3021  if(bVistaMenus)
3022  {
3023  HMODULE hThemeDLL = ::LoadLibrary(_T("uxtheme.dll"));
3024  if(hThemeDLL != NULL)
3025  {
3026  typedef BOOL (STDAPICALLTYPE *PFN_IsThemeActive)();
3027  PFN_IsThemeActive pfnIsThemeActive = (PFN_IsThemeActive)::GetProcAddress(hThemeDLL, "IsThemeActive");
3028  ATLASSERT(pfnIsThemeActive != NULL);
3029  bVistaMenus = bVistaMenus && (pfnIsThemeActive != NULL) && (pfnIsThemeActive() != FALSE);
3030 
3031  typedef BOOL (STDAPICALLTYPE *PFN_IsAppThemed)();
3032  PFN_IsAppThemed pfnIsAppThemed = (PFN_IsAppThemed)::GetProcAddress(hThemeDLL, "IsAppThemed");
3033  ATLASSERT(pfnIsAppThemed != NULL);
3034  bVistaMenus = bVistaMenus && (pfnIsAppThemed != NULL) && (pfnIsAppThemed() != FALSE);
3035 
3036  ::FreeLibrary(hThemeDLL);
3037  }
3038  }
3039 
3040  if(!bVistaMenus && m_bVistaMenus && (m_hMenu != NULL) && (m_arrCommand.GetSize() > 0))
3041  {
3042  T* pT = static_cast<T*>(this);
3043  pT->_RemoveVistaBitmapsFromMenu();
3044  }
3045 
3046  m_bVistaMenus = bVistaMenus;
3047 #endif // _WTL_CMDBAR_VISTA_MENUS
3048 
3049 #ifdef _CMDBAR_EXTRA_TRACE
3050  ATLTRACE2(atlTraceUI, 0, _T("CmdBar - GetSystemSettings:\n m_bFlatMenus = %s\n m_bUseKeyboardCues = %s m_bVistaMenus = %s\n"),
3051  m_bFlatMenus ? "true" : "false", m_bUseKeyboardCues ? "true" : "false", m_bVistaMenus ? "true" : "false");
3052 #endif
3053  }
3054 
3055 // Implementation - alternate focus mode support
3056  void TakeFocus()
3057  {
3058  if((m_dwExtendedStyle & CBR_EX_ALTFOCUSMODE) && m_hWndFocus == NULL)
3059  m_hWndFocus = ::GetFocus();
3060  SetFocus();
3061  }
3062 
3063  void GiveFocusBack()
3064  {
3065  if(m_bParentActive)
3066  {
3067  if((m_dwExtendedStyle & CBR_EX_ALTFOCUSMODE) && ::IsWindow(m_hWndFocus))
3068  ::SetFocus(m_hWndFocus);
3069  else if(!(m_dwExtendedStyle & CBR_EX_ALTFOCUSMODE) && m_wndParent.IsWindow())
3070  m_wndParent.SetFocus();
3071  }
3072  m_hWndFocus = NULL;
3073  SetAnchorHighlight(FALSE);
3074  if(m_bUseKeyboardCues && m_bShowKeyboardCues)
3075  ShowKeyboardCues(false);
3076  m_bSkipPostDown = false;
3077  }
3078 
3079  void ShowKeyboardCues(bool bShow)
3080  {
3081  m_bShowKeyboardCues = bShow;
3082  SetDrawTextFlags(DT_HIDEPREFIX, m_bShowKeyboardCues ? 0 : DT_HIDEPREFIX);
3083  Invalidate();
3084  UpdateWindow();
3085  }
3086 
3087 // Implementation - internal message helpers
3088  static UINT GetAutoPopupMessage()
3089  {
3090  static UINT uAutoPopupMessage = 0;
3091  if(uAutoPopupMessage == 0)
3092  {
3094  if(FAILED(lock.Lock()))
3095  {
3096  ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::GetAutoPopupMessage.\n"));
3097  ATLASSERT(FALSE);
3098  return 0;
3099  }
3100 
3101  if(uAutoPopupMessage == 0)
3102  uAutoPopupMessage = ::RegisterWindowMessage(_T("WTL_CmdBar_InternalAutoPopupMsg"));
3103 
3104  lock.Unlock();
3105  }
3106  ATLASSERT(uAutoPopupMessage != 0);
3107  return uAutoPopupMessage;
3108  }
3109 
3110  static UINT GetGetBarMessage()
3111  {
3112  static UINT uGetBarMessage = 0;
3113  if(uGetBarMessage == 0)
3114  {
3116  if(FAILED(lock.Lock()))
3117  {
3118  ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CCommandBarCtrlImpl::GetGetBarMessage.\n"));
3119  ATLASSERT(FALSE);
3120  return 0;
3121  }
3122 
3123  if(uGetBarMessage == 0)
3124  uGetBarMessage = ::RegisterWindowMessage(_T("WTL_CmdBar_InternalGetBarMsg"));
3125 
3126  lock.Unlock();
3127  }
3128  ATLASSERT(uGetBarMessage != 0);
3129  return uGetBarMessage;
3130  }
3131 
3132 // Implementation
3133  bool CreateInternalImageList(int cImages)
3134  {
3135  UINT uFlags = (m_bAlphaImages ? ILC_COLOR32 : ILC_COLOR24) | ILC_MASK;
3136  m_hImageList = ::ImageList_Create(m_szBitmap.cx, m_szBitmap.cy, uFlags, cImages, 1);
3137  ATLASSERT(m_hImageList != NULL);
3138  return (m_hImageList != NULL);
3139  }
3140 
3141 // Implementation - support for Vista menus
3142 #if _WTL_CMDBAR_VISTA_MENUS
3143  void _AddVistaBitmapsFromImageList(int nStartIndex, int nCount)
3144  {
3145  // Create display compatible memory DC
3146  CClientDC dc(NULL);
3147  CDC dcMem;
3148  dcMem.CreateCompatibleDC(dc);
3149  HBITMAP hBitmapSave = dcMem.GetCurrentBitmap();
3150 
3151  T* pT = static_cast<T*>(this);
3152  // Create bitmaps for all menu items
3153  for(int i = 0; i < nCount; i++)
3154  {
3155  HBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nStartIndex + i, dc, dcMem);
3156  dcMem.SelectBitmap(hBitmapSave);
3157  m_arrVistaBitmap.Add(hBitmap);
3158  }
3159  }
3160 
3161  void _AddVistaBitmapFromImageList(int nIndex)
3162  {
3163  // Create display compatible memory DC
3164  CClientDC dc(NULL);
3165  CDC dcMem;
3166  dcMem.CreateCompatibleDC(dc);
3167  HBITMAP hBitmapSave = dcMem.GetCurrentBitmap();
3168 
3169  // Create bitmap for menu item
3170  T* pT = static_cast<T*>(this);
3171  HBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nIndex, dc, dcMem);
3172 
3173  // Select saved bitmap back and add bitmap to the array
3174  dcMem.SelectBitmap(hBitmapSave);
3175  m_arrVistaBitmap.Add(hBitmap);
3176  }
3177 
3178  void _ReplaceVistaBitmapFromImageList(int nIndex)
3179  {
3180  // Delete existing bitmap
3181  if(m_arrVistaBitmap[nIndex] != NULL)
3182  ::DeleteObject(m_arrVistaBitmap[nIndex]);
3183 
3184  // Create display compatible memory DC
3185  CClientDC dc(NULL);
3186  CDC dcMem;
3187  dcMem.CreateCompatibleDC(dc);
3188  HBITMAP hBitmapSave = dcMem.GetCurrentBitmap();
3189 
3190  // Create bitmap for menu item
3191  T* pT = static_cast<T*>(this);
3192  HBITMAP hBitmap = pT->_CreateVistaBitmapHelper(nIndex, dc, dcMem);
3193 
3194  // Select saved bitmap back and replace bitmap in the array
3195  dcMem.SelectBitmap(hBitmapSave);
3196  m_arrVistaBitmap.SetAtIndex(nIndex, hBitmap);
3197  }
3198 
3199  HBITMAP _CreateVistaBitmapHelper(int nIndex, HDC hDCSource, HDC hDCTarget)
3200  {
3201  // Create 32-bit bitmap
3202  BITMAPINFO bi = { 0 };
3203  bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
3204  bi.bmiHeader.biWidth = m_szBitmap.cx;
3205  bi.bmiHeader.biHeight = m_szBitmap.cy;
3206  bi.bmiHeader.biPlanes = 1;
3207  bi.bmiHeader.biBitCount = 32;
3208  bi.bmiHeader.biCompression = BI_RGB;
3209  bi.bmiHeader.biSizeImage = 0;
3210  bi.bmiHeader.biXPelsPerMeter = 0;
3211  bi.bmiHeader.biYPelsPerMeter = 0;
3212  bi.bmiHeader.biClrUsed = 0;
3213  bi.bmiHeader.biClrImportant = 0;
3214  HBITMAP hBitmap = ::CreateDIBSection(hDCSource, &bi, DIB_RGB_COLORS, NULL, NULL, 0);
3215  ATLASSERT(hBitmap != NULL);
3216 
3217  // Select bitmap into target DC and draw from image list to it
3218  if(hBitmap != NULL)
3219  {
3220  ::SelectObject(hDCTarget, hBitmap);
3221 
3222  IMAGELISTDRAWPARAMS ildp = { 0 };
3223  ildp.cbSize = sizeof(IMAGELISTDRAWPARAMS);
3224  ildp.himl = m_hImageList;
3225  ildp.i = nIndex;
3226  ildp.hdcDst = hDCTarget;
3227  ildp.x = 0;
3228  ildp.y = 0;
3229  ildp.cx = 0;
3230  ildp.cy = 0;
3231  ildp.xBitmap = 0;
3232  ildp.yBitmap = 0;
3233  ildp.fStyle = ILD_TRANSPARENT;
3234  ildp.fState = ILS_ALPHA;
3235  ildp.Frame = 255;
3236  ::ImageList_DrawIndirect(&ildp);
3237  }
3238 
3239  return hBitmap;
3240  }
3241 
3242  void _RemoveVistaBitmapsFromMenu()
3243  {
3244  CMenuHandle menu = m_hMenu;
3245  for(int i = 0; i < m_arrCommand.GetSize(); i++)
3246  {
3247  CMenuItemInfo mii;
3248  mii.fMask = MIIM_BITMAP;
3249  mii.hbmpItem = NULL;
3250  menu.SetMenuItemInfo(m_arrCommand[i], FALSE, &mii);
3251  }
3252  }
3253 #endif // _WTL_CMDBAR_VISTA_MENUS
3254 };
3255 
3256 
3257 class CCommandBarCtrl : public CCommandBarCtrlImpl<CCommandBarCtrl>
3258 {
3259 public:
3260  DECLARE_WND_SUPERCLASS(_T("WTL_CommandBar"), GetWndClassName())
3261 };
3262 
3263 
3265 // CMDICommandBarCtrl - ATL implementation of Command Bars for MDI apps
3266 
3267 template <class T, class TBase = CCommandBarCtrlBase, class TWinTraits = ATL::CControlWinTraits>
3268 class ATL_NO_VTABLE CMDICommandBarCtrlImpl : public CCommandBarCtrlImpl< T, TBase, TWinTraits>
3269 {
3270 public:
3271 // Data members
3272  ATL::CContainedWindow m_wndMDIClient;
3273  bool m_bChildMaximized;
3274  HWND m_hWndChildMaximized;
3275  HICON m_hIconChildMaximized;
3276  int m_nBtnPressed;
3277  int m_nBtnWasPressed;
3278 
3279  int m_cxyOffset; // offset between nonclient elements
3280  int m_cxIconWidth; // small icon width
3281  int m_cyIconHeight; // small icon height
3282  int m_cxBtnWidth; // nonclient button width
3283  int m_cyBtnHeight; // nonclient button height
3284  int m_cxLeft; // left nonclient area width
3285  int m_cxRight; // right nonclient area width
3286 
3287 // Theme declarations and data members
3288 #ifndef _WTL_NO_AUTO_THEME
3289 #ifndef _UXTHEME_H_
3290  typedef HANDLE HTHEME;
3291 #endif // !_UXTHEME_H_
3292  typedef HTHEME (STDAPICALLTYPE *PFN_OpenThemeData)(HWND hwnd, LPCWSTR pszClassList);
3293  typedef HRESULT (STDAPICALLTYPE *PFN_CloseThemeData)(HTHEME hTheme);
3294  typedef HRESULT (STDAPICALLTYPE *PFN_DrawThemeBackground)(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, OPTIONAL const RECT *pClipRect);
3295  typedef HRESULT (STDAPICALLTYPE *PFN_DrawThemeParentBackground)(HWND hwnd, HDC hdc, OPTIONAL RECT* prc);
3296 
3297  HMODULE m_hThemeDLL;
3298  HTHEME m_hTheme;
3299  PFN_DrawThemeBackground m_pfnDrawThemeBackground;
3300  PFN_DrawThemeParentBackground m_pfnDrawThemeParentBackground;
3301 #endif // !_WTL_NO_AUTO_THEME
3302 
3303 // Constructor/destructor
3305  m_wndMDIClient(this, 2), m_bChildMaximized(false),
3306  m_hWndChildMaximized(NULL), m_hIconChildMaximized(NULL),
3307  m_nBtnPressed(-1), m_nBtnWasPressed(-1),
3308 #ifndef _WTL_NO_AUTO_THEME
3309  m_hThemeDLL(NULL), m_hTheme(NULL), m_pfnDrawThemeBackground(NULL), m_pfnDrawThemeParentBackground(NULL),
3310 #endif // !_WTL_NO_AUTO_THEME
3311  m_cxyOffset(2),
3312  m_cxIconWidth(16), m_cyIconHeight(16),
3313  m_cxBtnWidth(16), m_cyBtnHeight(14),
3314  m_cxLeft(20), m_cxRight(55)
3315  { }
3316 
3318  {
3319  if(m_wndMDIClient.IsWindow())
3320 /*scary!*/ m_wndMDIClient.UnsubclassWindow();
3321  }
3322 
3323 // Operations
3324  BOOL SetMDIClient(HWND hWndMDIClient)
3325  {
3326  ATLASSERT(::IsWindow(m_hWnd));
3327  ATLASSERT(::IsWindow(hWndMDIClient));
3328  if(!::IsWindow(hWndMDIClient))
3329  return FALSE;
3330 
3331 #ifdef _DEBUG
3332  // BLOCK: Test if the passed window is MDICLIENT
3333  {
3334  LPCTSTR lpszMDIClientClass = _T("MDICLIENT");
3335  const int nNameLen = 9 + 1; // "MDICLIENT" + NULL
3336  TCHAR szClassName[nNameLen] = { 0 };
3337  ::GetClassName(hWndMDIClient, szClassName, nNameLen);
3338  ATLASSERT(lstrcmpi(szClassName, lpszMDIClientClass) == 0);
3339  }
3340 #endif // _DEBUG
3341 
3342  if(m_wndMDIClient.IsWindow())
3343 /*scary!*/ m_wndMDIClient.UnsubclassWindow();
3344 
3345  return m_wndMDIClient.SubclassWindow(hWndMDIClient);
3346  }
3347 
3348 // Message maps
3350  BEGIN_MSG_MAP(CMDICommandBarCtrlImpl)
3351  MESSAGE_HANDLER(WM_CREATE, OnCreate)
3352  MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
3353 #ifndef _WTL_NO_AUTO_THEME
3354  MESSAGE_HANDLER(_GetThemeChangedMsg(), OnThemeChanged)
3355 #endif // !_WTL_NO_AUTO_THEME
3356  MESSAGE_HANDLER(WM_SIZE, OnSize)
3357  MESSAGE_HANDLER(WM_NCCALCSIZE, OnNcCalcSize)
3358  MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint)
3359  MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)
3360  MESSAGE_HANDLER(WM_NCLBUTTONDOWN, OnNcLButtonDown)
3361  MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
3362  MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
3363  MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnNcLButtonDblClk)
3364  MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)
3365  CHAIN_MSG_MAP(_baseClass)
3366  ALT_MSG_MAP(1) // Parent window messages
3367  MESSAGE_HANDLER(WM_ACTIVATE, OnParentActivate)
3368  CHAIN_MSG_MAP_ALT(_baseClass, 1)
3369  ALT_MSG_MAP(2) // MDI client window messages
3370  MESSAGE_HANDLER(WM_MDISETMENU, OnMDISetMenu)
3371  // no chaining needed since this was moved from the base class here
3372  ALT_MSG_MAP(3) // Message hook messages
3373  MESSAGE_RANGE_HANDLER(0, 0xFFFF, OnAllHookMessages)
3374  CHAIN_MSG_MAP_ALT(_baseClass, 3)
3375  END_MSG_MAP()
3376 
3377 // Additional MDI message handlers
3378  LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
3379  {
3380  LRESULT lRet = _baseClass::OnCreate(uMsg, wParam, lParam, bHandled);
3381  if(lRet == (LRESULT)-1)
3382  return lRet;
3383 
3384 #ifndef _WTL_NO_AUTO_THEME
3385  // this will fail if theming is not supported
3386  m_hThemeDLL = ::LoadLibrary(_T("uxtheme.dll"));
3387  if(m_hThemeDLL != NULL)
3388  {
3389  m_pfnDrawThemeBackground = (PFN_DrawThemeBackground)::GetProcAddress(m_hThemeDLL, "DrawThemeBackground");
3390  ATLASSERT(m_pfnDrawThemeBackground != NULL);
3391  if(m_pfnDrawThemeBackground != NULL)
3392  {
3393  T* pT = static_cast<T*>(this);
3394  pT->_OpenThemeData();
3395  }
3396  else
3397  {
3398  ::FreeLibrary(m_hThemeDLL);
3399  m_hThemeDLL = NULL;
3400  }
3401  m_pfnDrawThemeParentBackground = (PFN_DrawThemeParentBackground)::GetProcAddress(m_hThemeDLL, "DrawThemeParentBackground");
3402  ATLASSERT(m_pfnDrawThemeParentBackground != NULL);
3403  }
3404 #endif // !_WTL_NO_AUTO_THEME
3405 
3406  return lRet;
3407  }
3408 
3409  LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
3410  {
3411  LRESULT lRet = _baseClass::OnDestroy(uMsg, wParam, lParam, bHandled);
3412 
3413 #ifndef _WTL_NO_AUTO_THEME
3414  if(m_hThemeDLL != NULL)
3415  {
3416  T* pT = static_cast<T*>(this);
3417  pT->_CloseThemeData();
3418  ::FreeLibrary(m_hThemeDLL);
3419  m_hThemeDLL = NULL;
3420  }
3421 #endif // !_WTL_NO_AUTO_THEME
3422 
3423  return lRet;
3424  }
3425 
3426 #ifndef _WTL_NO_AUTO_THEME
3427  LRESULT OnThemeChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
3428  {
3429  if(m_hThemeDLL != NULL)
3430  {
3431  T* pT = static_cast<T*>(this);
3432  pT->_CloseThemeData();
3433  pT->_OpenThemeData();
3434  }
3435  return 0;
3436  }
3437 #endif // !_WTL_NO_AUTO_THEME
3438 
3439  LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
3440  {
3441  LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
3442  T* pT = static_cast<T*>(this);
3443  pT->_AdjustBtnSize(GET_Y_LPARAM(lParam));
3444  return lRet;
3445  }
3446 
3447  LRESULT OnNcCalcSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
3448  {
3449  LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
3450 
3451  if(m_bChildMaximized && (BOOL)wParam)
3452  {
3453  LPNCCALCSIZE_PARAMS lpParams = (LPNCCALCSIZE_PARAMS)lParam;
3454  if(m_bLayoutRTL)
3455  {
3456  lpParams->rgrc[0].left += m_cxRight;
3457  lpParams->rgrc[0].right -= m_cxLeft;
3458  }
3459  else
3460  {
3461  lpParams->rgrc[0].left += m_cxLeft;
3462  lpParams->rgrc[0].right -= m_cxRight;
3463  }
3464  }
3465 
3466  return lRet;
3467  }
3468 
3469  LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
3470  {
3471  LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
3472 
3473  if(!m_bChildMaximized)
3474  return lRet;
3475 
3476  ATLASSERT(m_hWndChildMaximized != NULL && m_hIconChildMaximized != NULL);
3477 
3478  // get DC and window rectangle
3479  CWindowDC dc(m_hWnd);
3480  RECT rect;
3481  GetWindowRect(&rect);
3482  int cxWidth = rect.right - rect.left;
3483  int cyHeight = rect.bottom - rect.top;
3484 
3485  // paint left side nonclient background and draw icon
3486  ::SetRect(&rect, 0, 0, m_cxLeft, cyHeight);
3487 #ifndef _WTL_NO_AUTO_THEME
3488  if(m_hTheme != NULL)
3489  {
3490  if(m_pfnDrawThemeParentBackground != NULL)
3491  m_pfnDrawThemeParentBackground(m_hWnd, dc, &rect);
3492  else
3493  dc.FillRect(&rect, COLOR_WINDOW);
3494  }
3495  else
3496 #endif // !_WTL_NO_AUTO_THEME
3497  {
3498  if((m_dwExtendedStyle & CBR_EX_TRANSPARENT) != 0)
3499  dc.FillRect(&rect, COLOR_3DFACE);
3500  else
3501  dc.FillRect(&rect, COLOR_MENU);
3502  }
3503 
3504  RECT rcIcon = { 0 };
3505  T* pT = static_cast<T*>(this);
3506  pT->_CalcIconRect(cxWidth, cyHeight, rcIcon);
3507  dc.DrawIconEx(rcIcon.left, rcIcon.top, m_hIconChildMaximized, m_cxIconWidth, m_cyIconHeight);
3508 
3509  // paint right side nonclient background
3510  ::SetRect(&rect, cxWidth - m_cxRight, 0, cxWidth, cyHeight);
3511 #ifndef _WTL_NO_AUTO_THEME
3512  if(m_hTheme != NULL)
3513  {
3514  if(m_pfnDrawThemeParentBackground != NULL)
3515  {
3516  // this is to account for the left non-client area
3517  POINT ptOrg = { 0, 0 };
3518  dc.GetViewportOrg(&ptOrg);
3519  dc.SetViewportOrg(ptOrg.x + m_cxLeft, ptOrg.y);
3520  ::OffsetRect(&rect, -m_cxLeft, 0);
3521 
3522  m_pfnDrawThemeParentBackground(m_hWnd, dc, &rect);
3523 
3524  // restore
3525  dc.SetViewportOrg(ptOrg);
3526  ::OffsetRect(&rect, m_cxLeft, 0);
3527  }
3528  else
3529  {
3530  dc.FillRect(&rect, COLOR_3DFACE);
3531  }
3532  }
3533  else
3534 #endif // !_WTL_NO_AUTO_THEME
3535  {
3536  if((m_dwExtendedStyle & CBR_EX_TRANSPARENT) != 0)
3537  dc.FillRect(&rect, COLOR_3DFACE);
3538  else
3539  dc.FillRect(&rect, COLOR_MENU);
3540  }
3541 
3542  // draw buttons
3543  RECT arrRect[3] = { 0 };
3544  pT->_CalcBtnRects(cxWidth, cyHeight, arrRect);
3545  pT->_DrawMDIButton(dc, arrRect, -1); // draw all buttons
3546 
3547  return lRet;
3548  }
3549 
3550  LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
3551  {
3552  LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
3553  if(m_bChildMaximized)
3554  {
3555  RECT rect = { 0 };
3556  GetWindowRect(&rect);
3557  POINT pt = { GET_X_LPARAM(lParam) - rect.left, GET_Y_LPARAM(lParam) - rect.top };
3558  if(m_bLayoutRTL)
3559  {
3560  if((pt.x < m_cxRight) || (pt.x > ((rect.right - rect.left) - m_cxLeft)))
3561  lRet = HTBORDER;
3562  }
3563  else
3564  {
3565  if((pt.x < m_cxLeft) || (pt.x > ((rect.right - rect.left) - m_cxRight)))
3566  lRet = HTBORDER;
3567  }
3568  }
3569  return lRet;
3570  }
3571 
3572  LRESULT OnNcLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
3573  {
3574  if(!m_bChildMaximized)
3575  {
3576  bHandled = FALSE;
3577  return 1;
3578  }
3579 
3580  ATLASSERT(_DebugCheckChild());
3581 
3582  POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
3583  RECT rect = { 0 };
3584  GetWindowRect(&rect);
3585  pt.x -= rect.left;
3586  pt.y -= rect.top;
3587 
3588  RECT rcIcon = { 0 };
3589  T* pT = static_cast<T*>(this);
3590  pT->_CalcIconRect(rect.right - rect.left, rect.bottom - rect.top, rcIcon, m_bLayoutRTL);
3591  RECT arrRect[3] = { 0 };
3592  pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL);
3593 
3594  if(::PtInRect(&rcIcon, pt))
3595  {
3596 #ifdef _CMDBAR_EXTRA_TRACE
3597  ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: icon\n"));
3598 #endif
3599 #ifndef TPM_VERPOSANIMATION
3600  const UINT TPM_VERPOSANIMATION = 0x1000L; // Menu animation flag
3601 #endif
3602  CMenuHandle menu = ::GetSystemMenu(m_hWndChildMaximized, FALSE);
3603  UINT uRet = (UINT)menu.TrackPopupMenu(TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD |
3604  (s_bW2K ? TPM_VERPOSANIMATION : 0), m_bLayoutRTL ? rect.right : rect.left, rect.bottom, m_hWndChildMaximized);
3605 
3606  // eat next message if click is on the same button
3607  ::OffsetRect(&rcIcon, rect.left, rect.top);
3608  MSG msg = { 0 };
3609  if(::PeekMessage(&msg, m_hWnd, WM_NCLBUTTONDOWN, WM_NCLBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rcIcon, msg.pt))
3610  ::PeekMessage(&msg, m_hWnd, WM_NCLBUTTONDOWN, WM_NCLBUTTONDOWN, PM_REMOVE);
3611 
3612  if(uRet != 0)
3613  ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, uRet, 0L);
3614  }
3615  else if(::PtInRect(&arrRect[0], pt))
3616  {
3617 #ifdef _CMDBAR_EXTRA_TRACE
3618  ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: close button\n"));
3619 #endif
3620  m_nBtnWasPressed = m_nBtnPressed = 0;
3621  }
3622  else if(::PtInRect(&arrRect[1], pt))
3623  {
3624 #ifdef _CMDBAR_EXTRA_TRACE
3625  ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: restore button\n"));
3626 #endif
3627  m_nBtnWasPressed = m_nBtnPressed = 1;
3628  }
3629  else if(::PtInRect(&arrRect[2], pt))
3630  {
3631 #ifdef _CMDBAR_EXTRA_TRACE
3632  ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonDown: minimize button\n"));
3633 #endif
3634  m_nBtnWasPressed = m_nBtnPressed = 2;
3635  }
3636  else
3637  {
3638  bHandled = FALSE;
3639  }
3640 
3641  // draw the button state if it was pressed
3642  if(m_nBtnPressed != -1)
3643  {
3644  SetCapture();
3645  CWindowDC dc(m_hWnd);
3646  pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect);
3647  pT->_DrawMDIButton(dc, arrRect, m_nBtnPressed);
3648  }
3649 
3650  return 0;
3651  }
3652 
3653  LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
3654  {
3655  if(!m_bChildMaximized || ::GetCapture() != m_hWnd || m_nBtnWasPressed == -1)
3656  {
3657  bHandled = FALSE;
3658  return 1;
3659  }
3660 
3661  POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
3662  ClientToScreen(&pt);
3663  RECT rect = { 0 };
3664  GetWindowRect(&rect);
3665  pt.x -= rect.left;
3666  pt.y -= rect.top;
3667  RECT arrRect[3] = { 0 };
3668  T* pT = static_cast<T*>(this);
3669  pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL);
3670  int nOldBtnPressed = m_nBtnPressed;
3671  m_nBtnPressed = ::PtInRect(&arrRect[m_nBtnWasPressed], pt) ? m_nBtnWasPressed : -1;
3672  if(nOldBtnPressed != m_nBtnPressed)
3673  {
3674  CWindowDC dc(m_hWnd);
3675  pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect);
3676  pT->_DrawMDIButton(dc, arrRect, (m_nBtnPressed != -1) ? m_nBtnPressed : nOldBtnPressed);
3677  }
3678 
3679  return 0;
3680  }
3681 
3682  LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
3683  {
3684  if(!m_bChildMaximized || ::GetCapture() != m_hWnd || m_nBtnWasPressed == -1)
3685  {
3686  bHandled = FALSE;
3687  return 1;
3688  }
3689 
3690  ATLASSERT(_DebugCheckChild());
3691 
3692  POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
3693  ClientToScreen(&pt);
3694  RECT rect = { 0 };
3695  GetWindowRect(&rect);
3696  pt.x -= rect.left;
3697  pt.y -= rect.top;
3698 
3699  int nBtn = m_nBtnWasPressed;
3700  ReleaseCapture();
3701 
3702  RECT arrRect[3] = { 0 };
3703  T* pT = static_cast<T*>(this);
3704  pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL);
3705  if(::PtInRect(&arrRect[nBtn], pt))
3706  {
3707  switch(nBtn)
3708  {
3709  case 0: // close
3710 #ifdef _CMDBAR_EXTRA_TRACE
3711  ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonUp: close button\n"));
3712 #endif
3713  ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, SC_CLOSE, 0L);
3714  break;
3715  case 1: // restore
3716 #ifdef _CMDBAR_EXTRA_TRACE
3717  ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonUp: restore button\n"));
3718 #endif
3719  ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, SC_RESTORE, 0L);
3720  break;
3721  case 2: // minimize
3722 #ifdef _CMDBAR_EXTRA_TRACE
3723  ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - LButtonUp: minimize button\n"));
3724 #endif
3725  ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, SC_MINIMIZE, 0L);
3726  break;
3727  default:
3728  break;
3729  }
3730  }
3731 
3732  return 0;
3733  }
3734 
3735  LRESULT OnNcLButtonDblClk(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
3736  {
3737  if(!m_bChildMaximized || m_nBtnWasPressed != -1)
3738  {
3739  bHandled = FALSE;
3740  return 1;
3741  }
3742 
3743  ATLASSERT(_DebugCheckChild());
3744 
3745  POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
3746  RECT rect = { 0 };
3747  GetWindowRect(&rect);
3748  pt.x -= rect.left;
3749  pt.y -= rect.top;
3750 
3751  RECT rcIcon = { 0 };
3752  T* pT = static_cast<T*>(this);
3753  pT->_CalcIconRect(rect.right - rect.left, rect.bottom - rect.top, rcIcon, m_bLayoutRTL);
3754  RECT arrRect[3] = { 0 };
3755  pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect, m_bLayoutRTL);
3756 
3757  if(::PtInRect(&rcIcon, pt))
3758  {
3759  CMenuHandle menu = ::GetSystemMenu(m_hWndChildMaximized, FALSE);
3760  UINT uDefID = menu.GetMenuDefaultItem();
3761  if(uDefID == (UINT)-1)
3762  uDefID = SC_CLOSE;
3763  ::SendMessage(m_hWndChildMaximized, WM_SYSCOMMAND, uDefID, 0L);
3764  }
3765 
3766  return 0;
3767  }
3768 
3769  LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
3770  {
3771  if(m_bChildMaximized)
3772  {
3773  if(m_nBtnPressed != -1)
3774  {
3775  ATLASSERT(m_nBtnPressed == m_nBtnWasPressed); // must be
3776  m_nBtnPressed = -1;
3777  RECT rect = { 0 };
3778  GetWindowRect(&rect);
3779  RECT arrRect[3] = { 0 };
3780  T* pT = static_cast<T*>(this);
3781  pT->_CalcBtnRects(rect.right - rect.left, rect.bottom - rect.top, arrRect);
3782  CWindowDC dc(m_hWnd);
3783  pT->_DrawMDIButton(dc, arrRect, m_nBtnWasPressed);
3784  }
3785  m_nBtnWasPressed = -1;
3786  }
3787  else
3788  {
3789  bHandled = FALSE;
3790  }
3791  return 0;
3792  }
3793 
3794 // Parent window message handlers
3795  LRESULT OnParentActivate(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
3796  {
3797  m_bParentActive = (LOWORD(wParam) != WA_INACTIVE);
3798  RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW);
3799  bHandled = FALSE;
3800  return 1;
3801  }
3802 
3803 // MDI client window message handlers
3804  LRESULT OnMDISetMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
3805  {
3806  m_wndMDIClient.DefWindowProc(uMsg, NULL, lParam);
3807  HMENU hOldMenu = GetMenu();
3808  BOOL bRet = AttachMenu((HMENU)wParam);
3809  bRet; // avoid level 4 warning
3810  ATLASSERT(bRet);
3811 
3812 #if (_WIN32_IE >= 0x0400)
3813  T* pT = static_cast<T*>(this);
3814  pT->UpdateRebarBandIdealSize();
3815 #endif // (_WIN32_IE >= 0x0400)
3816 
3817  return (LRESULT)hOldMenu;
3818  }
3819 
3820 // All messages from the message hook
3821  LRESULT OnAllHookMessages(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
3822  {
3823  T* pT = static_cast<T*>(this);
3824  pT->_ProcessAllHookMessages(uMsg, wParam, lParam);
3825 
3826  bHandled = FALSE;
3827  return 1;
3828  }
3829 
3830 // Overrideables
3831  // override this to provide different ideal size
3832  void UpdateRebarBandIdealSize()
3833  {
3834  // assuming we are in a rebar, change ideal size to our size
3835  // we hope that if we are not in a rebar, nCount will be 0
3836  int nCount = (int)::SendMessage(GetParent(), RB_GETBANDCOUNT, 0, 0L);
3837  for(int i = 0; i < nCount; i++)
3838  {
3839  REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE };
3840  ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi);
3841  if(rbi.hwndChild == m_hWnd)
3842  {
3843  rbi.fMask = RBBIM_IDEALSIZE;
3844  rbi.cxIdeal = m_bChildMaximized ? m_cxLeft + m_cxRight : 0;
3845  int nBtnCount = GetButtonCount();
3846  if(nBtnCount > 0)
3847  {
3848  RECT rect = { 0 };
3849  GetItemRect(nBtnCount - 1, &rect);
3850  rbi.cxIdeal += rect.right;
3851  }
3852  ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi);
3853  break;
3854  }
3855  }
3856  }
3857 
3858  // all hook messages - check for the maximized MDI child window change
3859  void _ProcessAllHookMessages(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/)
3860  {
3861  if(uMsg == WM_MDIGETACTIVE || uMsg == WM_MDISETMENU)
3862  return;
3863 
3864  BOOL bMaximized = FALSE;
3865  HWND hWndChild = (HWND)::SendMessage(m_wndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized);
3866  bool bMaxOld = m_bChildMaximized;
3867  m_bChildMaximized = (hWndChild != NULL && bMaximized);
3868  HICON hIconOld = m_hIconChildMaximized;
3869 
3870  if(m_bChildMaximized)
3871  {
3872  if(m_hWndChildMaximized != hWndChild)
3873  {
3874  ATL::CWindow wnd = m_hWndChildMaximized = hWndChild;
3875  m_hIconChildMaximized = wnd.GetIcon(FALSE);
3876  if(m_hIconChildMaximized == NULL)
3877  {
3878  m_hIconChildMaximized = wnd.GetIcon(TRUE);
3879  if(m_hIconChildMaximized == NULL)
3880  {
3881  // no icon set with WM_SETICON, get the class one
3882 // need conditional code because types don't match in winuser.h
3883 #ifdef _WIN64
3884  m_hIconChildMaximized = (HICON)::GetClassLongPtr(wnd, GCLP_HICONSM);
3885 #else
3886  m_hIconChildMaximized = (HICON)LongToHandle(::GetClassLongPtr(wnd, GCLP_HICONSM));
3887 #endif
3888  }
3889  }
3890  }
3891  }
3892  else
3893  {
3894  m_hWndChildMaximized = NULL;
3895  m_hIconChildMaximized = NULL;
3896  }
3897 
3898  if(bMaxOld != m_bChildMaximized)
3899  {
3900 #ifdef _CMDBAR_EXTRA_TRACE
3901  ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - All messages hook change: m_bChildMaximized = %s\n"), m_bChildMaximized ? "true" : "false");
3902 #endif
3903  // assuming we are in a rebar, change our size to accomodate new state
3904  // we hope that if we are not in a rebar, nCount will be 0
3905  int nCount = (int)::SendMessage(GetParent(), RB_GETBANDCOUNT, 0, 0L);
3906  int cxDiff = (m_bChildMaximized ? 1 : -1) * (m_cxLeft + m_cxRight);
3907  for(int i = 0; i < nCount; i++)
3908  {
3909 #if (_WIN32_IE >= 0x0500)
3910  REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE | RBBIM_STYLE };
3911  ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi);
3912  if(rbi.hwndChild == m_hWnd)
3913  {
3914  if((rbi.fStyle & RBBS_USECHEVRON) != 0)
3915  {
3916  rbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE;
3917  rbi.cxMinChild += cxDiff;
3918  rbi.cxIdeal += cxDiff;
3919  ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi);
3920  }
3921  break;
3922  }
3923 #elif (_WIN32_IE >= 0x0400)
3924  REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE };
3925  ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi);
3926  if(rbi.hwndChild == m_hWnd)
3927  {
3928  rbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE;
3929  rbi.cxMinChild += cxDiff;
3930  rbi.cxIdeal += cxDiff;
3931  ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi);
3932  break;
3933  }
3934 #else // (_WIN32_IE < 0x0400)
3935  REBARBANDINFO rbi = { RunTimeHelper::SizeOf_REBARBANDINFO(), RBBIM_CHILD | RBBIM_CHILDSIZE };
3936  ::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi);
3937  if(rbi.hwndChild == m_hWnd)
3938  {
3939  rbi.fMask = RBBIM_CHILDSIZE;
3940  rbi.cxMinChild += cxDiff;
3941  ::SendMessage(GetParent(), RB_SETBANDINFO, i, (LPARAM)&rbi);
3942  break;
3943  }
3944 #endif // (_WIN32_IE < 0x0400)
3945  }
3946  }
3947 
3948  if(bMaxOld != m_bChildMaximized || hIconOld != m_hIconChildMaximized)
3949  {
3950  // force size change and redraw everything
3951  RECT rect = { 0 };
3952  GetWindowRect(&rect);
3953  ::MapWindowPoints(NULL, GetParent(), (LPPOINT)&rect, 2);
3954  SetRedraw(FALSE);
3955  SetWindowPos(NULL, 0, 0, 1, 1, SWP_NOZORDER | SWP_NOMOVE);
3956  SetWindowPos(NULL, &rect, SWP_NOZORDER | SWP_NOMOVE);
3957  SetRedraw(TRUE);
3958  RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW);
3959  }
3960  }
3961 
3962 // Implementation
3963  void GetSystemSettings()
3964  {
3965 #ifdef _CMDBAR_EXTRA_TRACE
3966  ATLTRACE2(atlTraceUI, 0, _T("MDI CmdBar - GetSystemSettings\n"));
3967 #endif
3968  _baseClass::GetSystemSettings();
3969 
3970  NONCLIENTMETRICS info = { RunTimeHelper::SizeOf_NONCLIENTMETRICS() };
3971  BOOL bRet = ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
3972  ATLASSERT(bRet);
3973  if(bRet)
3974  {
3975  m_cxIconWidth = ::GetSystemMetrics(SM_CXSMICON);
3976  m_cyIconHeight = ::GetSystemMetrics(SM_CYSMICON);
3977  m_cxLeft = m_cxIconWidth;
3978 
3979 #ifndef _WTL_NO_AUTO_THEME
3980  if(m_hTheme != NULL)
3981  {
3982  m_cxBtnWidth = info.iCaptionWidth - 2 * m_cxyOffset;
3983  m_cyBtnHeight = info.iCaptionHeight - 2 * m_cxyOffset;
3984  m_cxRight = 3 * m_cxBtnWidth;
3985  }
3986  else
3987 #endif // !_WTL_NO_AUTO_THEME
3988  {
3989  m_cxBtnWidth = info.iCaptionWidth - m_cxyOffset;
3990  m_cyBtnHeight = info.iCaptionHeight - 2 * m_cxyOffset;
3991  m_cxRight = 3 * m_cxBtnWidth + m_cxyOffset;
3992  }
3993  }
3994 
3995  RECT rect = { 0 };
3996  GetClientRect(&rect);
3997  T* pT = static_cast<T*>(this);
3998  pT->_AdjustBtnSize(rect.bottom);
3999  }
4000 
4001  void _AdjustBtnSize(int cyHeight)
4002  {
4003  if(cyHeight > 1 && m_cyBtnHeight > cyHeight)
4004  {
4005 #ifndef _WTL_NO_AUTO_THEME
4006  if(m_hTheme != NULL)
4007  {
4008  m_cyBtnHeight = cyHeight;
4009  m_cxBtnWidth = cyHeight;
4010  m_cxRight = 3 * m_cxBtnWidth;
4011  }
4012  else
4013 #endif // !_WTL_NO_AUTO_THEME
4014  {
4015  m_cyBtnHeight = cyHeight;
4016  m_cxBtnWidth = cyHeight + m_cxyOffset;
4017  m_cxRight = 3 * m_cxBtnWidth + m_cxyOffset;
4018  }
4019  }
4020  }
4021 
4022  void _CalcIconRect(int cxWidth, int cyHeight, RECT& rect, bool bInvertX = false) const
4023  {
4024  int xStart = (m_cxLeft - m_cxIconWidth) / 2;
4025  if(xStart < 0)
4026  xStart = 0;
4027  int yStart = (cyHeight - m_cyIconHeight) / 2;
4028  if(yStart < 0)
4029  yStart = 0;
4030 
4031  if(bInvertX)
4032  ::SetRect(&rect, cxWidth - (xStart + m_cxBtnWidth), yStart, cxWidth - xStart, yStart + m_cyBtnHeight);
4033  else
4034  ::SetRect(&rect, xStart, yStart, xStart + m_cxBtnWidth, yStart + m_cyBtnHeight);
4035  }
4036 
4037  void _CalcBtnRects(int cxWidth, int cyHeight, RECT arrRect[3], bool bInvertX = false) const
4038  {
4039  int yStart = (cyHeight - m_cyBtnHeight) / 2;
4040  if(yStart < 0)
4041  yStart = 0;
4042 
4043  RECT rcBtn = { cxWidth - m_cxBtnWidth, yStart, cxWidth, yStart + m_cyBtnHeight };
4044  int nDirection = -1;
4045  if(bInvertX)
4046  {
4047  ::SetRect(&rcBtn, 0, yStart, m_cxBtnWidth, yStart + m_cyBtnHeight);
4048  nDirection = 1;
4049  }
4050 
4051  arrRect[0] = rcBtn;
4052 #ifndef _WTL_NO_AUTO_THEME
4053  if(m_hTheme != NULL)
4054  ::OffsetRect(&rcBtn, nDirection * m_cxBtnWidth, 0);
4055  else
4056 #endif // !_WTL_NO_AUTO_THEME
4057  ::OffsetRect(&rcBtn, nDirection * (m_cxBtnWidth + m_cxyOffset), 0);
4058  arrRect[1] = rcBtn;
4059  ::OffsetRect(&rcBtn, nDirection * m_cxBtnWidth, 0);
4060  arrRect[2] = rcBtn;
4061  }
4062 
4063  void _DrawMDIButton(CWindowDC& dc, LPRECT pRects, int nBtn)
4064  {
4065 #ifndef _WTL_NO_AUTO_THEME
4066  if(m_hTheme != NULL)
4067  {
4068 #ifndef TMSCHEMA_H
4069  const int WP_MDICLOSEBUTTON = 20;
4070  const int CBS_NORMAL = 1;
4071  const int CBS_PUSHED = 3;
4072  const int CBS_DISABLED = 4;
4073  const int WP_MDIRESTOREBUTTON = 22;
4074  const int RBS_NORMAL = 1;
4075  const int RBS_PUSHED = 3;
4076  const int RBS_DISABLED = 4;
4077  const int WP_MDIMINBUTTON = 16;
4078  const int MINBS_NORMAL = 1;
4079  const int MINBS_PUSHED = 3;
4080  const int MINBS_DISABLED = 4;
4081 #endif // TMSCHEMA_H
4082  if(nBtn == -1 || nBtn == 0)
4083  m_pfnDrawThemeBackground(m_hTheme, dc, WP_MDICLOSEBUTTON, m_bParentActive ? ((m_nBtnPressed == 0) ? CBS_PUSHED : CBS_NORMAL) : CBS_DISABLED, &pRects[0], NULL);
4084  if(nBtn == -1 || nBtn == 1)
4085  m_pfnDrawThemeBackground(m_hTheme, dc, WP_MDIRESTOREBUTTON, m_bParentActive ? ((m_nBtnPressed == 1) ? RBS_PUSHED : RBS_NORMAL) : RBS_DISABLED, &pRects[1], NULL);
4086  if(nBtn == -1 || nBtn == 2)
4087  m_pfnDrawThemeBackground(m_hTheme, dc, WP_MDIMINBUTTON, m_bParentActive ? ((m_nBtnPressed == 2) ? MINBS_PUSHED : MINBS_NORMAL) : MINBS_DISABLED, &pRects[2], NULL);
4088  }
4089  else
4090 #endif // !_WTL_NO_AUTO_THEME
4091  {
4092  if(nBtn == -1 || nBtn == 0)
4093  dc.DrawFrameControl(&pRects[0], DFC_CAPTION, DFCS_CAPTIONCLOSE | ((m_nBtnPressed == 0) ? DFCS_PUSHED : 0));
4094  if(nBtn == -1 || nBtn == 1)
4095  dc.DrawFrameControl(&pRects[1], DFC_CAPTION, DFCS_CAPTIONRESTORE | ((m_nBtnPressed == 1) ? DFCS_PUSHED : 0));
4096  if(nBtn == -1 || nBtn == 2)
4097  dc.DrawFrameControl(&pRects[2], DFC_CAPTION, DFCS_CAPTIONMIN | ((m_nBtnPressed == 2) ? DFCS_PUSHED : 0));
4098  }
4099  }
4100 
4101 #ifndef _WTL_NO_AUTO_THEME
4102  static UINT _GetThemeChangedMsg()
4103  {
4104 #ifndef WM_THEMECHANGED
4105  static const UINT WM_THEMECHANGED = 0x031A;
4106 #endif // !WM_THEMECHANGED
4107  return WM_THEMECHANGED;
4108  }
4109 
4110  void _OpenThemeData()
4111  {
4112  ATLASSERT(m_hThemeDLL != NULL);
4113 
4114  PFN_OpenThemeData pfnOpenThemeData = (PFN_OpenThemeData)::GetProcAddress(m_hThemeDLL, "OpenThemeData");
4115  ATLASSERT(pfnOpenThemeData != NULL);
4116  if(pfnOpenThemeData != NULL)
4117  m_hTheme = pfnOpenThemeData(m_hWnd, L"Window");
4118  }
4119 
4120  void _CloseThemeData()
4121  {
4122  ATLASSERT(m_hThemeDLL != NULL);
4123 
4124  if(m_hTheme == NULL)
4125  return; // nothing to do
4126 
4127  PFN_CloseThemeData pfnCloseThemeData = (PFN_CloseThemeData)::GetProcAddress(m_hThemeDLL, "CloseThemeData");
4128  ATLASSERT(pfnCloseThemeData != NULL);
4129  if(pfnCloseThemeData != NULL)
4130  {
4131  pfnCloseThemeData(m_hTheme);
4132  m_hTheme = NULL;
4133  }
4134  }
4135 #endif // !_WTL_NO_AUTO_THEME
4136 
4137  bool _DebugCheckChild()
4138  {
4139 #ifdef _DEBUG
4140  BOOL bMaximized = FALSE;
4141  HWND hWndChild = (HWND)::SendMessage(m_wndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized);
4142  return (bMaximized && hWndChild == m_hWndChildMaximized);
4143 #else // !_DEBUG
4144  return true;
4145 #endif // !_DEBUG
4146  }
4147 };
4148 
4149 class CMDICommandBarCtrl : public CMDICommandBarCtrlImpl<CMDICommandBarCtrl>
4150 {
4151 public:
4152  DECLARE_WND_SUPERCLASS(_T("WTL_MDICommandBar"), GetWndClassName())
4153 };
4154 
4155 }; // namespace WTL
4156 
4157 #endif // __ATLCTRLW_H__
Definition: atlwinx.h:455
Definition: atlctrlw.h:3268
Definition: atlctrlw.h:3257
Definition: nestegg.c:186
Definition: atlgdi.h:3388
Definition: atlctrlw.h:83
Definition: atlctrlw.h:95
Definition: atlapp.h:1262
Definition: atlctrlw.h:136
Definition: atlapp.h:484
Definition: atlctrlw.h:219
Definition: atlgdi.h:1211
Definition: atlgdi.h:230
Definition: atlgdi.h:3409
Definition: atlctrlw.h:133
Definition: atlctrlw.h:207
Definition: atlctrlw.h:4149
Definition: atluser.h:129
Definition: atlctrlw.h:201