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