MenuXP.cpp
上传用户:ckg1000
上传日期:2013-01-26
资源大小:630k
文件大小:39k
源码类别:

CAD

开发平台:

Visual C++

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // MenuXP.cpp : implementation file
  4. //
  5. ///////////////////////////////////////////////////////////////////////////////
  6. #include "stdafx.h"
  7. #include "MenuXP.h"
  8. #include "Tools.h"
  9. #include "Draw.h"
  10. #ifdef _DEBUG
  11. #define new DEBUG_NEW
  12. #undef THIS_FILE
  13. static char THIS_FILE[] = __FILE__;
  14. #endif
  15. #ifndef DWORD_PTR
  16.     typedef ULONG DWORD_PTR;
  17.     typedef long LONG_PTR;
  18. #endif
  19. #ifndef ODS_HOTLIGHT
  20.     #define ODS_HOTLIGHT 0x0040
  21. #endif
  22. #ifndef ODS_INACTIVE
  23.     #define ODS_INACTIVE 0x0080
  24. #endif
  25. #ifndef ODS_NOACCEL
  26.     #define ODS_NOACCEL 0x0100
  27. #endif
  28. #ifndef DT_HIDEPREFIX
  29.     #define DT_HIDEPREFIX 0x00100000
  30. #endif
  31. #ifndef SPI_GETKEYBOARDCUES
  32.     #define SPI_GETKEYBOARDCUES 0x100A
  33. #endif
  34. // From <winuser.h>
  35. #ifndef OBM_CHECK
  36.     #define OBM_CHECK 32760
  37. #endif
  38. #define IMGWIDTH 16
  39. #define IMGHEIGHT 16
  40. #define IMGPADDING 6
  41. #define TEXTPADDING 8
  42. #define TEXTPADDING_MNUBR 4
  43. #define SM_CXSHADOW 4
  44. const TCHAR _WndPropName_OldProc[] = _T("XPWndProp_OldProc");
  45. const TCHAR _WndPropName_MenuXP[] = _T("XPWndProp_MenuXP");
  46. ///////////////////////////////////////////////////////////////////////////////
  47. // Menu item management class
  48. //
  49. class CMenuItem
  50. {
  51. protected:
  52.     MENUITEMINFO m_miInfo;
  53.     CString      m_sCaption;
  54.     CImgDesc     m_ImgDesc;
  55.     HIMAGELIST   m_hImgList;
  56.     int          m_nIndex;
  57. public:
  58.     CMenuItem ();
  59.     CMenuItem (HMENU hMenu, UINT uItem, bool fByPosition = true);
  60.    ~CMenuItem ();
  61. // Properties
  62. public:
  63.     int   GetCaption   (CString& sCaption) const;
  64.     int   GetShortCut  (CString& sShortCut) const;
  65.     bool  GetSeparator () const;
  66.     bool  GetChecked   () const;
  67.     bool  GetRadio     () const;
  68.     bool  GetDisabled  () const;
  69.     bool  GetDefault   () const;
  70.     HMENU GetPopup     () const;
  71.     UINT  GetID        () const;
  72. // Methods
  73. public:
  74.     int  GetCaptionWidth  (CDC* pDC) const;
  75.     int  GetShortCutWidth (CDC* pDC) const;
  76.     int  GetHeight        (CDC* pDC) const;
  77.     bool Draw             (CDC* pDC, LPCRECT pRect, bool bSelected, bool bMenuBar = false, bool bHotLight = false, bool bInactive = false, bool bNoAccel = false) const;
  78. public:
  79.     static BYTE ms_nCheck;
  80.     static CRect ms_rcMRUMenuBarItem;
  81. };
  82. ///////////////////////////////////////////////////////////////////////////////
  83. ///////////////////////////////////////////////////////////////////////////////
  84. BYTE CMenuItem::ms_nCheck = 0;
  85. CRect CMenuItem::ms_rcMRUMenuBarItem (0, 0, 0, 0);
  86. ///////////////////////////////////////////////////////////////////////////////
  87. CMenuItem::CMenuItem ()
  88. {
  89.     memset (&m_miInfo, 0, sizeof(MENUITEMINFO));
  90. }
  91. ///////////////////////////////////////////////////////////////////////////////
  92. CMenuItem::CMenuItem (HMENU hMenu, UINT uItem, bool fByPosition)
  93. {
  94.     memset (&m_miInfo, 0, sizeof(MENUITEMINFO));
  95.     m_miInfo.cbSize = sizeof(MENUITEMINFO);
  96.     m_miInfo.fMask = MIIM_STATE|MIIM_SUBMENU|MIIM_TYPE|MIIM_DATA|MIIM_ID;
  97.     VERIFY (::GetMenuItemInfo (hMenu, uItem, fByPosition, &m_miInfo));
  98.     if ( !(m_miInfo.fType & MFT_SEPARATOR) )
  99.     {
  100.         if ( m_miInfo.hSubMenu != NULL )
  101.         {
  102.             CMenuXP::ms_sSubMenuCaptions.Lookup (m_miInfo.hSubMenu, m_sCaption);
  103.             CMenuXP::ms_SubMenuImages.Lookup (m_miInfo.hSubMenu, m_ImgDesc);
  104.         }
  105.         else
  106.         {
  107.             CMenuXP::ms_sCaptions.Lookup (m_miInfo.wID, m_sCaption);
  108.             CMenuXP::ms_Images.Lookup (m_miInfo.wID, m_ImgDesc);
  109.         }
  110.     }
  111. }
  112. ///////////////////////////////////////////////////////////////////////////////
  113. CMenuItem::~CMenuItem ()
  114. {
  115. }
  116. ///////////////////////////////////////////////////////////////////////////////
  117. int CMenuItem::GetCaption (CString& sCaption) const
  118. {
  119.     ASSERT(m_miInfo.fMask & MIIM_TYPE);
  120.     sCaption = m_sCaption;
  121.     int nShortCutPos = sCaption.Find ('t');
  122.     if ( nShortCutPos == -1 )
  123.     {
  124.         return sCaption.GetLength();
  125.     }
  126.     sCaption = sCaption.Left (nShortCutPos);
  127.     return nShortCutPos-1;
  128. }
  129. ///////////////////////////////////////////////////////////////////////////////
  130. int CMenuItem::GetShortCut (CString& sShortCut) const
  131. {
  132.     ASSERT(m_miInfo.fMask & MIIM_TYPE);
  133.     CString sCaption = m_sCaption;
  134.     int nShortCutPos = sCaption.Find ('t');
  135.     if ( nShortCutPos == -1 )
  136.     {
  137.         sShortCut = "";
  138.         return 0;
  139.     }
  140.     int nLength = sCaption.GetLength()-nShortCutPos-1;
  141.     sShortCut = sCaption.Right (nLength);
  142.     return nLength;
  143. }
  144. ///////////////////////////////////////////////////////////////////////////////
  145. bool CMenuItem::GetSeparator () const
  146. {
  147.     ASSERT(m_miInfo.fMask & MIIM_TYPE);
  148.     return (m_miInfo.fType & MFT_SEPARATOR) == MFT_SEPARATOR;
  149. }
  150. ///////////////////////////////////////////////////////////////////////////////
  151. bool CMenuItem::GetChecked () const
  152. {
  153.     ASSERT(m_miInfo.fMask & MIIM_STATE);
  154.     return (m_miInfo.fState & MFS_CHECKED) == MFS_CHECKED;
  155. }
  156. ///////////////////////////////////////////////////////////////////////////////
  157. bool CMenuItem::GetRadio () const
  158. {
  159.     ASSERT(m_miInfo.fMask & MIIM_TYPE);
  160.     return (m_miInfo.fType & MFT_RADIOCHECK) == MFT_RADIOCHECK;
  161. }
  162. ///////////////////////////////////////////////////////////////////////////////
  163. bool CMenuItem::GetDisabled () const
  164. {
  165.     ASSERT(m_miInfo.fMask & MIIM_STATE);
  166.     return (m_miInfo.fState & MFS_GRAYED) == MFS_GRAYED;
  167. }
  168. ///////////////////////////////////////////////////////////////////////////////
  169. bool CMenuItem::GetDefault () const
  170. {
  171.     ASSERT(m_miInfo.fMask & MIIM_STATE);
  172.     return (m_miInfo.fState & MFS_DEFAULT) == MFS_DEFAULT;
  173. }
  174. ///////////////////////////////////////////////////////////////////////////////
  175. HMENU CMenuItem::GetPopup () const
  176. {
  177.     ASSERT(m_miInfo.fMask & MIIM_SUBMENU);
  178.     return m_miInfo.hSubMenu;
  179. }
  180. ///////////////////////////////////////////////////////////////////////////////
  181. UINT CMenuItem::GetID () const
  182. {
  183.     ASSERT(m_miInfo.fMask & MIIM_ID);
  184.     return m_miInfo.wID;
  185. }
  186. ///////////////////////////////////////////////////////////////////////////////
  187. int CMenuItem::GetCaptionWidth (CDC* pDC) const
  188. {
  189.     if ( GetSeparator() )
  190.     {
  191.         return 0;
  192.     }
  193.     CString sCaption;
  194.     int nLength = 0;
  195.     if ( GetCaption (sCaption) > 0 )
  196.     {
  197.         int nPos = sCaption.Find ('&');
  198.         CBoldDC bold (*pDC, GetDefault());
  199.         if ( nPos >= 0 )
  200.         {
  201.             sCaption = sCaption.Left (nPos) + sCaption.Right (sCaption.GetLength()-nPos-1);
  202.         }
  203.         nLength = pDC->GetTextExtent (sCaption).cx;
  204.     }
  205.     return nLength;
  206. }
  207. ///////////////////////////////////////////////////////////////////////////////
  208. int CMenuItem::GetShortCutWidth (CDC* pDC) const
  209. {
  210.     if ( GetSeparator() )
  211.     {
  212.         return 0;
  213.     }
  214.     CString sShortCut;
  215.     int nLength = 0;
  216.     if ( GetShortCut (sShortCut) > 0 )
  217.     {
  218.         CBoldDC bold (*pDC, GetDefault());
  219.         nLength = pDC->GetTextExtent (sShortCut).cx;
  220.     }
  221.     return nLength;
  222. }
  223. ///////////////////////////////////////////////////////////////////////////////
  224. int CMenuItem::GetHeight (CDC* pDC) const
  225. {
  226.     TEXTMETRIC tm;
  227.     pDC->GetTextMetrics (&tm);
  228.                      
  229.     return GetSeparator() ? tm.tmHeight/2+2 : tm.tmHeight+4;
  230. }
  231. ///////////////////////////////////////////////////////////////////////////////
  232. bool CMenuItem::Draw (CDC* pDC, LPCRECT pRect, bool bSelected, bool bMenuBar, bool bHotLight, bool bInactive, bool bNoAccel) const
  233. {
  234.     COLORREF crBackImg = CLR_NONE;
  235.     bool bMenuBarItemSelected = false;
  236.     if ( bMenuBar && bSelected )
  237.     {
  238.         CRect rc (pRect);
  239.         CPenDC pen (*pDC, ::GetSysColor (COLOR_3DDKSHADOW));
  240.         CBrushDC brush (*pDC, HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +20, 0));
  241.         rc.right -= TEXTPADDING_MNUBR;
  242.         ms_rcMRUMenuBarItem = rc;
  243.         bMenuBarItemSelected = true;
  244.         pDC->Rectangle (rc);
  245.         rc.left = rc.right;
  246.         rc.right += TEXTPADDING_MNUBR;
  247.         pDC->FillSolidRect (rc, ::GetSysColor (COLOR_3DFACE));
  248.         for ( int x = 0; x < SM_CXSHADOW; x++ )
  249.         {
  250.             for ( int y = ( x < 2 ) ? 2-x : 0; y < rc.Height()-x-((x>0)?1:2); y++ )
  251.             {
  252.                 int nMakeSpec = 78+(3-(y==0?0:(y==1?(x<2?0:1):(y==2?(x<2?x:2):x))))*5;
  253.                 COLORREF cr = pDC->GetPixel (rc.right-x-1, rc.top+y+SM_CXSHADOW);
  254.                 COLORREF cr2 = RGB(((nMakeSpec * int(GetRValue(cr))) / 100),
  255.                        ((nMakeSpec * int(GetGValue(cr))) / 100),
  256.                        ((nMakeSpec * int(GetBValue(cr))) / 100));
  257.     pDC->SetPixel (rc.right-x-1, rc.top+y+SM_CXSHADOW, cr2);
  258.             }
  259.         }
  260.     }
  261.     else if ( bSelected || (bHotLight && !bInactive) )
  262.     {
  263.         COLORREF crHighLight = ::GetSysColor (COLOR_HIGHLIGHT);
  264.         CPenDC pen (*pDC, crHighLight);
  265.         CBrushDC brush (*pDC, crBackImg = GetDisabled() ? HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +73, 0) : HLS_TRANSFORM (crHighLight, +70, -57));
  266.         if ( bMenuBar )
  267.         {
  268.             CRect rc (pRect);
  269.             rc.right -= TEXTPADDING_MNUBR;
  270.             pDC->Rectangle (rc);
  271.             rc.left = rc.right;
  272.             rc.right += TEXTPADDING_MNUBR;
  273.             pDC->FillSolidRect (rc, ::GetSysColor (COLOR_3DFACE));
  274.         }
  275.         else
  276.         {
  277.             pDC->Rectangle (pRect);
  278.         }
  279.     }
  280.     else if ( !bMenuBar )
  281.     {
  282.         CRect rc (pRect);
  283.         rc.right = IMGWIDTH+IMGPADDING;
  284.         pDC->FillSolidRect (rc, HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +20, 0));
  285.         rc.left = rc.right;
  286.         rc.right = pRect->right;
  287.         pDC->FillSolidRect (rc, HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +75, 0));
  288.     }
  289.     else
  290.     {
  291.         pDC->FillSolidRect (pRect, ::GetSysColor (COLOR_3DFACE));
  292.     }
  293.     if ( GetSeparator() )
  294.     {
  295.         CPenDC pen (*pDC, HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), -18, 0));
  296.         pDC->MoveTo (pRect->left+IMGWIDTH+IMGPADDING+TEXTPADDING,  (pRect->top+pRect->bottom)/2);
  297.         pDC->LineTo (pRect->right-1, (pRect->top+pRect->bottom)/2);
  298.     }
  299.     else
  300.     {
  301.         CRect rc (pRect);
  302.         CString sCaption;
  303.         if ( GetCaption (sCaption) > 0 )
  304.         {
  305.             pDC->SetTextColor (bInactive ? ::GetSysColor (COLOR_3DSHADOW) : (GetDisabled() ? HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), -18, 0) : ::GetSysColor (COLOR_MENUTEXT)));
  306.             pDC->SetBkMode (TRANSPARENT);
  307.             BOOL bKeyboardCues = true;
  308.             ::SystemParametersInfo (SPI_GETKEYBOARDCUES, 0, &bKeyboardCues, 0);
  309.             DWORD dwHidePrefix = ( bNoAccel && !bKeyboardCues ) ? DT_HIDEPREFIX : 0;
  310.             if ( bMenuBar )
  311.             {
  312.                 rc.right -= TEXTPADDING_MNUBR;
  313.                 pDC->DrawText (sCaption, rc, DT_SINGLELINE|DT_VCENTER|DT_CENTER|dwHidePrefix);
  314.             }
  315.             else
  316.             {
  317.                 CBoldDC bold (*pDC, GetDefault());
  318.                 rc.left = IMGWIDTH+IMGPADDING+TEXTPADDING;
  319.                 pDC->DrawText (sCaption, rc, DT_SINGLELINE|DT_VCENTER|DT_LEFT|dwHidePrefix);
  320.                 CString sShortCut;
  321.                 if ( GetShortCut (sShortCut) > 0 )
  322.                 {
  323.                     rc.right -= TEXTPADDING+4;
  324.                     pDC->DrawText (sShortCut, rc, DT_SINGLELINE|DT_VCENTER|DT_RIGHT);
  325.                 }
  326.                 if ( GetChecked() )
  327.                 {
  328.                     COLORREF crHighLight = ::GetSysColor (COLOR_HIGHLIGHT);
  329.                     CPenDC pen (*pDC, crHighLight);
  330.                     CBrushDC brush (*pDC, crBackImg = GetDisabled() ? HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +73, 0) :
  331.                                                                       (bSelected ? HLS_TRANSFORM (crHighLight, +50, -50) : HLS_TRANSFORM (crHighLight, +70, -57)));
  332.                     pDC->Rectangle (CRect (pRect->left+1, pRect->top+1, pRect->left+IMGWIDTH+4, pRect->bottom-1));
  333.                 }
  334.                 if ( m_ImgDesc.m_hImgList != NULL && m_ImgDesc.m_nIndex != -1 )
  335.                 {
  336.                     bool bOver = !GetDisabled() && bSelected;
  337.                     if ( GetDisabled() || (bSelected && !GetChecked()) )
  338.                     {
  339.                         HICON hIcon = ImageList_ExtractIcon (NULL, m_ImgDesc.m_hImgList, m_ImgDesc.m_nIndex);
  340.                         pDC->DrawState (CPoint (pRect->left + ( bOver ? 4 : 3 ), rc.top + ( bOver ? 4 : 3 )),
  341.                                         CSize (IMGWIDTH, IMGHEIGHT), hIcon, DSS_MONO,
  342.                                         CBrush (bOver ? HLS_TRANSFORM (::GetSysColor (COLOR_HIGHLIGHT), +50, -66) : HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), -27, 0)));
  343.                         DestroyIcon (hIcon);
  344.                     }
  345.                     if ( !GetDisabled() )
  346.                     {
  347.                         ::ImageList_Draw (m_ImgDesc.m_hImgList, m_ImgDesc.m_nIndex, pDC->m_hDC,
  348.                                           pRect->left+( (bSelected && !GetChecked()) ? 2 : 3 ), rc.top+( (bSelected && !GetChecked()) ? 2 : 3 ), ILD_TRANSPARENT);
  349.                     }
  350.                 }
  351.                 else if ( GetChecked() )
  352.                 {
  353.                     // Draw the check mark
  354.                     rc.left  = pRect->left+IMGWIDTH/4+1;
  355.                     rc.right = rc.left + IMGWIDTH-1;
  356.                     if ( GetRadio() )
  357.                     {
  358.                         CPoint ptCenter = rc.CenterPoint();
  359.                         COLORREF crBullet = GetDisabled() ? HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), -27, 0) : ::GetSysColor (COLOR_MENUTEXT);
  360.                         CPenDC pen (*pDC, crBullet);
  361.                         CBrushDC brush (*pDC, crBullet);
  362.                         
  363.                         pDC->Ellipse (CRect (ptCenter.x-4, ptCenter.y-3, ptCenter.x+3, ptCenter.y+4));
  364.                         pDC->SetPixel (ptCenter.x+1, ptCenter.y+2, crBackImg);
  365.                     }
  366.                     else
  367.                     {
  368.                         pDC->SetBkColor (crBackImg);
  369.                         HBITMAP hBmp = LoadBitmap (NULL, MAKEINTRESOURCE(OBM_CHECK));
  370.                         pDC->DrawState (CPoint (rc.left,rc.top+3), CSize(rc.Size()), hBmp, DSS_NORMAL, (HBRUSH)NULL);
  371.                         DeleteObject (hBmp);
  372.                     }
  373.                 }
  374.             }
  375.         }
  376.     }
  377.     return bMenuBarItemSelected;
  378. }
  379. ///////////////////////////////////////////////////////////////////////////////
  380. ///////////////////////////////////////////////////////////////////////////////
  381. CMap <int, int, CString, CString&> CMenuXP::ms_sCaptions;
  382. CMap <HMENU, HMENU, CString, CString&> CMenuXP::ms_sSubMenuCaptions;
  383. CMap <int, int, CImgDesc, CImgDesc&> CMenuXP::ms_Images;
  384. CMap <HMENU, HMENU, CImgDesc, CImgDesc&> CMenuXP::ms_SubMenuImages;
  385. ///////////////////////////////////////////////////////////////////////////////
  386. void CMenuXP::SetXPLookNFeel (CWnd* pWnd, bool bXPLook)
  387. {
  388.     if ( bXPLook )
  389.     {
  390.         ::SetProp (pWnd->GetSafeHwnd(), _WndPropName_MenuXP, (HANDLE)TRUE);
  391.     }
  392.     else
  393.     {
  394.         ::RemoveProp (pWnd->GetSafeHwnd(), _WndPropName_MenuXP);
  395.     }
  396. }
  397. ///////////////////////////////////////////////////////////////////////////////
  398. bool CMenuXP::GetXPLookNFeel (const CWnd* pWnd)
  399. {
  400.     return ::GetProp (pWnd->GetSafeHwnd(), _WndPropName_MenuXP) != NULL;
  401. }
  402. ///////////////////////////////////////////////////////////////////////////////
  403. void CMenuXP::UpdateMenuBar (CWnd* pWnd)
  404. {
  405.     if ( GetXPLookNFeel (pWnd) )
  406.     {
  407.         HMENU hMenu = pWnd->GetMenu()->GetSafeHmenu();
  408.         if ( hMenu != NULL )
  409.         {
  410.             SetXPLookNFeel (pWnd, hMenu, true, true);
  411.         }
  412.     }
  413. }
  414. ///////////////////////////////////////////////////////////////////////////////
  415. void CMenuXP::SetXPLookNFeel (CWnd* pWnd, HMENU hMenu, bool bXPLook, bool bMenuBar)
  416. {
  417.     if ( !bXPLook )
  418.     {
  419.         // TODO: Remove the ownerdraw style ?
  420.         return;
  421.     }
  422. //    TRACE(_T("Referenced captions : %in"), ms_sCaptions.GetCount()+ms_sSubMenuCaptions.GetCount());
  423.     // Clean up old references...
  424.     // ... for captions
  425.     POSITION pos = ms_sSubMenuCaptions.GetStartPosition();
  426.     while ( pos != NULL )
  427.     {
  428.         HMENU hSubMenu;
  429.         CString sBuff;
  430.         ms_sSubMenuCaptions.GetNextAssoc (pos, hSubMenu, sBuff);
  431.         if ( !::IsMenu (hSubMenu) )
  432.         {
  433.             ms_sSubMenuCaptions.RemoveKey (hSubMenu);
  434.         }
  435.     }
  436.     // ... for images
  437.     pos = ms_SubMenuImages.GetStartPosition();
  438.     while ( pos != NULL )
  439.     {
  440.         HMENU hSubMenu;
  441.         CImgDesc ImgDesc;
  442.         ms_SubMenuImages.GetNextAssoc (pos, hSubMenu, ImgDesc);
  443.         if ( !::IsMenu (hSubMenu) )
  444.         {
  445.             ms_SubMenuImages.RemoveKey (hSubMenu);
  446.         }
  447.     }
  448.     ASSERT(hMenu != NULL);
  449.     int nItemCount = ::GetMenuItemCount (hMenu);
  450.     MENUITEMINFO mii = { sizeof MENUITEMINFO, MIIM_ID|MIIM_TYPE|MIIM_SUBMENU };
  451.     CClientDC cDC (AfxGetMainWnd());
  452.     TEXTMETRIC tm;
  453.     CFontDC font (cDC, DEFAULT_GUI_FONT);
  454.     cDC.GetTextMetrics (&tm);
  455.     int nHeight = max(tm.tmHeight+2,IMGHEIGHT)+4;
  456.     int nSepHeight = tm.tmHeight/2+2;
  457.     int nCaptionLength = 0;
  458.     int nShortCutLength = 0;
  459.     CPtrList* pListControlBars = NULL;
  460.     if ( pWnd != NULL && !bMenuBar )
  461.     {
  462.         if ( pWnd->IsKindOf (RUNTIME_CLASS(CMDIFrameWnd)) )
  463.         {
  464.             CMDIChildWnd* pActiveChild = ((CMDIFrameWnd*)pWnd)->MDIGetActive();
  465.             if ( pActiveChild != NULL && pActiveChild->GetSystemMenu (false)->GetSafeHmenu() == hMenu )
  466.             {
  467.                 CMenuItem::ms_rcMRUMenuBarItem.SetRectEmpty();
  468.                 return;
  469.             }
  470.         }
  471.         if ( pWnd->IsKindOf (RUNTIME_CLASS(CFrameWnd)) && !((CFrameWnd*)pWnd)->m_listControlBars.IsEmpty() )
  472.         {
  473.             pListControlBars = &((CFrameWnd*)pWnd)->m_listControlBars;
  474.         }
  475.         else
  476.         {
  477.             CFrameWnd* pFrame = pWnd->GetParentFrame();
  478.             if ( pFrame != NULL && pFrame->IsKindOf (RUNTIME_CLASS(CMDIChildWnd)) )
  479.             {
  480.                 pFrame = pFrame->GetParentFrame();
  481.             }
  482.             if ( pFrame != NULL )
  483.             {
  484.                 pListControlBars = &pFrame->m_listControlBars;
  485.             }
  486.         }
  487.     }
  488.     for ( int i = 0; i < nItemCount; i++ )
  489.     {
  490.         TCHAR sCaption[256] = _T("");
  491.         mii.dwTypeData = sCaption;
  492.         mii.cch = 255;
  493.         mii.fMask &= ~MIIM_DATA;
  494.         ::GetMenuItemInfo (hMenu, i, true, &mii);
  495.         if ( (mii.fType & MFT_OWNERDRAW) == 0 && (!bMenuBar || (mii.fType & MFT_BITMAP) == 0) )
  496.         {
  497.             mii.fType |= MFT_OWNERDRAW;
  498.             if ( bMenuBar )
  499.             {
  500.                 CRect rcText (0, 0, 1000, 0);
  501.                 cDC.DrawText (sCaption, (int)_tcslen (sCaption), rcText, DT_SINGLELINE|DT_LEFT|DT_CALCRECT);
  502.                 mii.dwItemData = MAKELONG(MAKEWORD(0, 0), rcText.Width());
  503.                 mii.fMask |= MIIM_DATA;
  504.             }
  505.             ::SetMenuItemInfo (hMenu, i, true, &mii);
  506.             if ( (mii.fType & MFT_SEPARATOR) == 0 )
  507.             {
  508.                 CString sBuff(sCaption);
  509.                 if ( mii.hSubMenu != NULL )
  510.                 {
  511.                     ms_sSubMenuCaptions.SetAt (mii.hSubMenu, sBuff);
  512.                 }
  513.                 else
  514.                 {
  515.                     ms_sCaptions.SetAt (mii.wID, sBuff);
  516.                 }
  517.                 if ( pListControlBars != NULL )
  518.                 {
  519.                     POSITION pos = pListControlBars->GetHeadPosition();
  520.                     while ( pos != NULL )
  521.                     {
  522.                         CControlBar* pBar = (CControlBar*)pListControlBars->GetNext (pos);
  523.                         ASSERT(pBar != NULL);
  524.                         TCHAR sClassName[256];
  525.                         ::GetClassName (pBar->m_hWnd, sClassName, lengthof (sClassName));
  526.                         if ( !_tcsicmp (sClassName, _T("ToolbarWindow32")) )
  527.                         {
  528.                             TBBUTTONINFO tbbi = { sizeof(TBBUTTONINFO), TBIF_COMMAND|TBIF_IMAGE };
  529.                             if ( pBar->SendMessage (TB_GETBUTTONINFO, mii.wID, (LPARAM)&tbbi) != -1 &&
  530.                                  (UINT)tbbi.idCommand == mii.wID && tbbi.iImage != -1 )
  531.                             {
  532.                                 CImgDesc imgDesc ((HIMAGELIST)pBar->SendMessage (TB_GETIMAGELIST, 0, 0), tbbi.iImage);
  533.                                 if ( mii.hSubMenu != NULL )
  534.                                 {
  535.                                     ms_SubMenuImages.SetAt (mii.hSubMenu, imgDesc);
  536.                                 }
  537.                                 else
  538.                                 {
  539.                                     ms_Images.SetAt (mii.wID, imgDesc);
  540.                                 }
  541.                                 break;
  542.                             }
  543.                         }
  544.                     }
  545.                 }
  546.             }
  547.         }
  548.         if ( !bMenuBar )
  549.         {
  550.             CMenuItem mnuItem (hMenu, i);
  551.             int       nWidth = mnuItem.GetCaptionWidth (&cDC);
  552.             if ( nWidth > nCaptionLength )
  553.             {
  554.                 nCaptionLength = nWidth;
  555.             }
  556.             nWidth = mnuItem.GetShortCutWidth (&cDC);
  557.             if ( nWidth > nShortCutLength )
  558.             {
  559.                 nShortCutLength = nWidth;
  560.             }
  561.         }
  562.     }
  563.     if ( !bMenuBar )
  564.     {
  565.         for ( int j = 0; j < nItemCount; j++ )
  566.         {
  567.             mii.fMask = MIIM_TYPE;
  568.             ::GetMenuItemInfo (hMenu, j, true, &mii);
  569.             if ( (mii.fType & MFT_SEPARATOR) == 0 )
  570.             {
  571.                 mii.dwItemData = MAKELONG(MAKEWORD(nHeight, nShortCutLength), nCaptionLength);
  572.             }
  573.             else
  574.             {
  575.                 mii.dwItemData = nSepHeight;
  576.             }
  577.             mii.fMask = MIIM_DATA;
  578.             ::SetMenuItemInfo (hMenu, j, true, &mii);
  579.         }
  580.     }
  581. }
  582. ///////////////////////////////////////////////////////////////////////////////
  583. bool CMenuXP::IsOwnerDrawn (HMENU hMenu)
  584. {
  585.     MENUITEMINFO mii = { sizeof MENUITEMINFO, MIIM_TYPE };
  586.     ::GetMenuItemInfo (hMenu, 0, true, &mii);
  587.     return (mii.fType & MFT_OWNERDRAW) != 0;
  588. }
  589. ///////////////////////////////////////////////////////////////////////////////
  590. void CMenuXP::SetMRUMenuBarItem (RECT& rc)
  591. {
  592.     CMenuItem::ms_rcMRUMenuBarItem = rc;
  593. }
  594. ///////////////////////////////////////////////////////////////////////////////
  595. void CMenuXP::SetMenuItemImage (UINT nID, HIMAGELIST hImgList, int nIndex)
  596. {
  597.     CImgDesc imgDesc (hImgList, nIndex);
  598.     ms_Images.SetAt (nID, imgDesc);
  599. }
  600. ///////////////////////////////////////////////////////////////////////////////
  601. void CMenuXP::OnMeasureItem (MEASUREITEMSTRUCT* pMeasureItemStruct)
  602. {
  603.     if ( pMeasureItemStruct->CtlType == ODT_MENU )
  604.     {
  605.         pMeasureItemStruct->itemHeight = LOBYTE(LOWORD(pMeasureItemStruct->itemData));
  606.         if ( pMeasureItemStruct->itemHeight == 0 )
  607.         {
  608.             // This is a menubar item
  609.             pMeasureItemStruct->itemWidth = HIWORD(pMeasureItemStruct->itemData) + TEXTPADDING_MNUBR;
  610.         }
  611.         else
  612.         {
  613.             pMeasureItemStruct->itemWidth = IMGWIDTH + IMGPADDING + HIWORD(pMeasureItemStruct->itemData) + TEXTPADDING + HIBYTE(LOWORD(pMeasureItemStruct->itemData)) + TEXTPADDING + 4;
  614.         }
  615.     }
  616. }
  617. ///////////////////////////////////////////////////////////////////////////////
  618. bool CMenuXP::OnDrawItem (DRAWITEMSTRUCT* pDrawItemStruct, HWND hWnd)
  619. {
  620.     if ( pDrawItemStruct->CtlType != ODT_MENU )
  621.     {
  622.         return false;
  623.     }
  624.     ASSERT (pDrawItemStruct->CtlType == ODT_MENU);
  625.     CBufferDC cDC (pDrawItemStruct->hDC, pDrawItemStruct->rcItem);
  626.     CMenuItem item ((HMENU)pDrawItemStruct->hwndItem, pDrawItemStruct->itemID, false);
  627.     CFontDC font (cDC, DEFAULT_GUI_FONT);
  628.     if ( item.Draw (&cDC, &pDrawItemStruct->rcItem, (pDrawItemStruct->itemState&ODS_SELECTED)!=0, LOBYTE(LOWORD(pDrawItemStruct->itemData))==0, (pDrawItemStruct->itemState&ODS_HOTLIGHT)!=0, (pDrawItemStruct->itemState&ODS_INACTIVE)!=0, (pDrawItemStruct->itemState&ODS_NOACCEL)!=0) )
  629.     {
  630.         CRect rc;
  631.         ::GetMenuItemRect (hWnd, (HMENU)pDrawItemStruct->hwndItem, 0, rc);
  632.         ::ClientToScreen (hWnd, CMenuItem::ms_rcMRUMenuBarItem);
  633.         CMenuItem::ms_rcMRUMenuBarItem.top = rc.top;
  634.         CMenuItem::ms_rcMRUMenuBarItem.bottom = rc.bottom;
  635.         
  636.         if ( CWnd::FromHandle (hWnd)->IsKindOf (RUNTIME_CLASS(CDialog)) )
  637.         {
  638.             CMenuItem::ms_rcMRUMenuBarItem.OffsetRect (1, 0);
  639.         }
  640.     }
  641.     CMenuItem::ms_nCheck++;
  642.     
  643.     return true;
  644. }
  645. ///////////////////////////////////////////////////////////////////////////////
  646. LRESULT CMenuXP::OnMenuChar (HMENU hMenu, UINT nChar, UINT nFlags)
  647. {
  648.     if ( (nFlags & (MF_POPUP|MF_SYSMENU)) == MF_POPUP || nFlags == 0 )
  649.     {
  650.         int nItemCount = ::GetMenuItemCount (hMenu);
  651.         nChar = toupper (nChar);
  652.         for ( int i = 0; i < nItemCount; i++ )
  653.         {
  654.             CMenuItem mnuItem (hMenu, i);
  655.             CString sCaption;
  656.             mnuItem.GetCaption (sCaption);
  657.             sCaption.MakeUpper();
  658.             for ( int nPos = sCaption.GetLength()-2; nPos >= 0; nPos-- )
  659.             {
  660.                 if ( sCaption[nPos] == '&' && (UINT)toupper (sCaption[nPos+1]) == nChar &&
  661.                      (nPos == 0 || sCaption[nPos-1] != '&') )
  662.                 {
  663.                     return MAKELRESULT(i,2);
  664.                 }
  665.             }
  666.         }
  667.     }
  668.     return 0;
  669. }
  670. ///////////////////////////////////////////////////////////////////////////////
  671. ///////////////////////////////////////////////////////////////////////////////
  672. // CWndMenuXP class : management of the window used by system to display popup menus
  673. //
  674. class CWndMenuXP
  675. {
  676. public:
  677.     CWndMenuXP (HWND hWnd);
  678.    ~CWndMenuXP ();
  679. public:
  680.     static CWndMenuXP* FromHandle (HWND hWnd, bool bPermanent = true);
  681. protected:
  682.     void OnWindowPosChanging (WINDOWPOS* pWP);
  683.     void OnEraseBkgnd ();
  684.     void OnPrint (CDC* pDC, bool bOwnerDrawnItems);
  685.     void OnNcPaint ();
  686.     void OnShowWindow (bool bShow);
  687.     void OnNcDestroy ();
  688. private:
  689.     static LRESULT CALLBACK WindowsHook (int code, WPARAM wParam, LPARAM lParam);
  690.     static LRESULT CALLBACK SubClassMenuProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  691. protected:
  692.     HWND m_hWnd;
  693.     CRect m_rcMenu;
  694.     CPoint m_ptMenu;
  695.     CBitmap m_bmpBkGnd;
  696.     static CMap <HWND, HWND, CWndMenuXP*, CWndMenuXP*> ms_WndMenuMap;
  697.     static DWORD ms_dwRefCount;
  698.     static HHOOK ms_hHookOldMenuCbtFilter;
  699. friend class CMenuXP;
  700. };
  701. ///////////////////////////////////////////////////////////////////////////////
  702. void CMenuXP::InitializeHook ()
  703. {
  704.     CWndMenuXP::ms_dwRefCount++;
  705.     if ( CWndMenuXP::ms_hHookOldMenuCbtFilter == NULL )
  706.     {
  707.         CWndMenuXP::ms_hHookOldMenuCbtFilter = ::SetWindowsHookEx (WH_CALLWNDPROC, CWndMenuXP::WindowsHook, AfxGetApp()->m_hInstance, ::GetCurrentThreadId());
  708.     }
  709. }
  710. ///////////////////////////////////////////////////////////////////////////////
  711. void CMenuXP::UninitializeHook ()
  712. {
  713.     if ( CWndMenuXP::ms_dwRefCount == 0 )
  714.     {
  715.         return;
  716.     }
  717.     if ( --CWndMenuXP::ms_dwRefCount == 0 )
  718.     {
  719.         POSITION pos = CWndMenuXP::ms_WndMenuMap.GetStartPosition();
  720.         while ( pos != NULL )
  721.         {
  722.             HWND hKey;
  723.             CWndMenuXP* pVal;
  724.             CWndMenuXP::ms_WndMenuMap.GetNextAssoc (pos, hKey, pVal);
  725.             delete pVal;
  726.         }
  727.         CWndMenuXP::ms_WndMenuMap.RemoveAll();
  728.         if ( CWndMenuXP::ms_hHookOldMenuCbtFilter != NULL )
  729.         {
  730.             ::UnhookWindowsHookEx (CWndMenuXP::ms_hHookOldMenuCbtFilter);
  731.         }
  732.     }
  733. }
  734. ///////////////////////////////////////////////////////////////////////////////
  735. CMap <HWND, HWND, CWndMenuXP*, CWndMenuXP*> CWndMenuXP::ms_WndMenuMap;
  736. DWORD CWndMenuXP::ms_dwRefCount = 0;
  737. HHOOK CWndMenuXP::ms_hHookOldMenuCbtFilter = NULL;
  738. ///////////////////////////////////////////////////////////////////////////////
  739. CWndMenuXP::CWndMenuXP (HWND hWnd)
  740.     : m_hWnd (hWnd), m_rcMenu (0, 0, 0, 0), m_ptMenu (-0xFFFF, -0xFFFF)
  741. {
  742. }
  743. ///////////////////////////////////////////////////////////////////////////////
  744. CWndMenuXP::~CWndMenuXP ()
  745. {
  746.     WNDPROC oldWndProc = (WNDPROC)::GetProp (m_hWnd, _WndPropName_OldProc);
  747.     if ( oldWndProc != NULL )
  748.     {
  749.         ::SetWindowLong (m_hWnd, GWL_WNDPROC, (DWORD)(DWORD_PTR)oldWndProc);
  750.         ::RemoveProp (m_hWnd, _WndPropName_OldProc);
  751.     }
  752.     ms_WndMenuMap.RemoveKey (m_hWnd);
  753. }
  754. ///////////////////////////////////////////////////////////////////////////////
  755. CWndMenuXP* CWndMenuXP::FromHandle (HWND hWnd, bool bPermanent)
  756. {
  757.     CWndMenuXP* pWnd = NULL;
  758.     if ( ms_WndMenuMap.Lookup (hWnd, pWnd) )
  759.     {
  760.         return pWnd;
  761.     }
  762.     if ( bPermanent )
  763.     {
  764.         return NULL;
  765.     }
  766.     pWnd = new CWndMenuXP (hWnd);
  767.     ms_WndMenuMap.SetAt (hWnd, pWnd);
  768.     return pWnd;
  769. }
  770. ///////////////////////////////////////////////////////////////////////////////
  771. void CWndMenuXP::OnWindowPosChanging (WINDOWPOS* pWP)
  772. {
  773.     if ( GetWinVersion() < wvWinXP )
  774.     {
  775.         pWP->cx += SM_CXSHADOW;
  776.         pWP->cy += SM_CXSHADOW;
  777.     }
  778.     pWP->y--;
  779.     m_ptMenu.x = pWP->x;
  780.     m_ptMenu.y = pWP->y;
  781. }
  782. ///////////////////////////////////////////////////////////////////////////////
  783. void CWndMenuXP::OnEraseBkgnd ()
  784. {
  785.     if ( !IsWindowVisible (m_hWnd) )
  786.     {
  787.         CClientRect rc (m_hWnd);
  788.         if ( m_bmpBkGnd.m_hObject != NULL )
  789.         {
  790.             m_bmpBkGnd.DeleteObject();
  791.         }
  792.         m_bmpBkGnd.Attach (GetScreenBitmap (CRect (m_ptMenu.x, m_ptMenu.y, rc.right+m_ptMenu.x+10,
  793.                                                    rc.bottom+m_ptMenu.y+10)));
  794.     }
  795. }
  796. ///////////////////////////////////////////////////////////////////////////////
  797. void DrawShadow (HDC hDCIn, HDC hDCOut, RECT& rc)
  798. {
  799.     for ( int x = 0; x < rc.right-1; x++ )
  800.     {
  801.         int nEnd = ( x > rc.right-SM_CXSHADOW*2 ) ? rc.right-SM_CXSHADOW-x : SM_CXSHADOW;
  802.         for ( int y = ( x < 2 ) ? 2-x : x > rc.right-SM_CXSHADOW-3 ? x-rc.right+SM_CXSHADOW+3 : 0; y < nEnd; y++ )
  803.         {
  804.             int nMakeSpec = 78+(3-(x==0?0:(x==1?(y<2?0:1):(x==2?(y<2?y:2):y))))*5;
  805.             COLORREF cr = GetPixel (hDCIn, x+SM_CXSHADOW, rc.bottom-y-1);
  806.             COLORREF cr2 = RGB(((nMakeSpec * int(GetRValue(cr))) / 100),
  807.                    ((nMakeSpec * int(GetGValue(cr))) / 100),
  808.                    ((nMakeSpec * int(GetBValue(cr))) / 100));
  809. SetPixel (hDCOut, x+SM_CXSHADOW, rc.bottom-y-1, cr2);
  810.         }
  811.     }
  812.     for ( x = 0; x < SM_CXSHADOW; x++ )
  813.     {
  814.         for ( int y = ( x < 2 ) ? 2-x : 0; y < rc.bottom-x-SM_CXSHADOW-((x>0)?1:2); y++ )
  815.         {
  816.             int nMakeSpec = 78+(3-(y==0?0:(y==1?(x<2?0:1):(y==2?(x<2?x:2):x))))*5;
  817.             COLORREF cr = GetPixel (hDCIn, rc.right-x-1, y+SM_CXSHADOW);
  818.             COLORREF cr2 = RGB(((nMakeSpec * int(GetRValue(cr))) / 100),
  819.                    ((nMakeSpec * int(GetGValue(cr))) / 100),
  820.                    ((nMakeSpec * int(GetBValue(cr))) / 100));
  821. SetPixel (hDCOut, rc.right-x-1, y+SM_CXSHADOW, cr2);
  822.         }
  823.     }
  824. }
  825. ///////////////////////////////////////////////////////////////////////////////
  826. void CWndMenuXP::OnPrint (CDC* pDC, bool bOwnerDrawnItems)
  827. {
  828.     CWindowRect rc (m_hWnd);
  829.     CBrushDC br (pDC->m_hDC);
  830.     CPenDC pen (pDC->m_hDC, ::GetSysColor (COLOR_3DDKSHADOW));
  831.     rc.OffsetRect (-rc.TopLeft());
  832.     m_rcMenu = rc;
  833.     if ( GetWinVersion() < wvWinXP )
  834.     {
  835.         rc.right -= SM_CXSHADOW;
  836.         rc.bottom -= SM_CXSHADOW;
  837.     }
  838.     pDC->Rectangle (rc);
  839.     pen.Color (HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +75, 0));
  840.     rc.DeflateRect (1, 1);
  841.     pDC->Rectangle (rc);
  842.     rc.DeflateRect (1, 1);
  843.     pDC->Rectangle (rc);
  844.     if ( bOwnerDrawnItems && !CMenuItem::ms_rcMRUMenuBarItem.IsRectEmpty() &&
  845.          CMenuItem::ms_rcMRUMenuBarItem.bottom == m_ptMenu.y+1 )
  846.     {
  847.         pen.Color (HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +20, 0));
  848.         pDC->MoveTo (CMenuItem::ms_rcMRUMenuBarItem.left-m_ptMenu.x-3, 0);
  849.         pDC->LineTo (CMenuItem::ms_rcMRUMenuBarItem.left-m_ptMenu.x+CMenuItem::ms_rcMRUMenuBarItem.Width()-5, 0);
  850.     }
  851.     if ( GetWinVersion() < wvWinXP )
  852.     {
  853.         rc.right += SM_CXSHADOW+2;
  854.         rc.bottom += SM_CXSHADOW+2;
  855.         CDC cMemDC;
  856.         cMemDC.CreateCompatibleDC (pDC);
  857.         HGDIOBJ hOldBitmap = ::SelectObject (cMemDC.m_hDC, m_bmpBkGnd);
  858.         pDC->BitBlt (0, rc.bottom-SM_CXSHADOW, SM_CXSHADOW*2, SM_CXSHADOW, &cMemDC, 0, rc.bottom-SM_CXSHADOW, SRCCOPY);
  859.         pDC->BitBlt (rc.right-SM_CXSHADOW, rc.bottom-SM_CXSHADOW, SM_CXSHADOW, SM_CXSHADOW, &cMemDC, rc.right-SM_CXSHADOW, rc.bottom-SM_CXSHADOW, SRCCOPY);
  860.         pDC->BitBlt (rc.right-SM_CXSHADOW, 0, SM_CXSHADOW, SM_CXSHADOW*2, &cMemDC, rc.right-SM_CXSHADOW, 0, SRCCOPY);
  861.         DrawShadow (cMemDC.m_hDC, pDC->m_hDC, rc);
  862.         ::SelectObject (cMemDC.m_hDC, hOldBitmap);
  863.     }
  864. }
  865. ///////////////////////////////////////////////////////////////////////////////
  866. void CWndMenuXP::OnNcPaint ()
  867. {
  868.     CWindowDC cDC (CWnd::FromHandle (m_hWnd));
  869.     CDC* pDC = &cDC;
  870.     CWindowRect rc (m_hWnd);
  871.     m_ptMenu.x = rc.left;
  872.     m_ptMenu.y = rc.top;
  873.     rc.OffsetRect (-rc.TopLeft());
  874.     if ( rc != m_rcMenu )
  875.     {
  876.         m_rcMenu = rc;
  877.         CBrushDC br (pDC->m_hDC);
  878.         CPenDC pen (pDC->m_hDC, ::GetSysColor (COLOR_3DDKSHADOW));
  879.         if ( GetWinVersion() < wvWinXP )
  880.         {
  881.             rc.right -= SM_CXSHADOW;
  882.             rc.bottom -= SM_CXSHADOW;
  883.         }
  884.         pDC->Rectangle (rc);
  885.         pen.Color (HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +75, 0));
  886.         rc.DeflateRect (1, 1);
  887.         pDC->Rectangle (rc);
  888.         rc.DeflateRect (1, 1);
  889.         pDC->Rectangle (rc);
  890.         if ( !CMenuItem::ms_rcMRUMenuBarItem.IsRectEmpty() &&
  891.              CMenuItem::ms_rcMRUMenuBarItem.bottom == m_ptMenu.y+1 )
  892.         {
  893.             pen.Color (HLS_TRANSFORM (::GetSysColor (COLOR_3DFACE), +20, 0));
  894.             pDC->MoveTo (CMenuItem::ms_rcMRUMenuBarItem.left-m_ptMenu.x-3, 0);
  895.             pDC->LineTo (CMenuItem::ms_rcMRUMenuBarItem.left-m_ptMenu.x+CMenuItem::ms_rcMRUMenuBarItem.Width()-5, 0);
  896.         }
  897.         if ( GetWinVersion() < wvWinXP )
  898.         {
  899.             rc.right += SM_CXSHADOW+2;
  900.             rc.bottom += SM_CXSHADOW+2;
  901.             DrawShadow (pDC->m_hDC, pDC->m_hDC, rc);
  902.         }
  903.     }
  904. }
  905. ///////////////////////////////////////////////////////////////////////////////
  906. void CWndMenuXP::OnShowWindow (bool bShow)
  907. {
  908.     if ( !bShow )
  909.     {
  910.         delete this;
  911.     }
  912. }
  913. ///////////////////////////////////////////////////////////////////////////////
  914. void CWndMenuXP::OnNcDestroy ()
  915. {
  916.     delete this;
  917. }
  918. ///////////////////////////////////////////////////////////////////////////////
  919. LRESULT CALLBACK CWndMenuXP::WindowsHook (int code, WPARAM wParam, LPARAM lParam)
  920. {
  921.     CWPSTRUCT* pStruct = (CWPSTRUCT*)lParam;
  922.     // Not a real loop (just for 'break' branchment)
  923.     while ( code == HC_ACTION )
  924.     {
  925.         HWND hWnd = pStruct->hwnd;
  926.         // Normal and special handling for menu 0x10012
  927.         if ( pStruct->message != WM_CREATE && pStruct->message != 0x01E2 )
  928.         {
  929.             break;
  930.         }
  931.         CWnd* pFrame = CWnd::GetForegroundWindow();
  932.         if ( pFrame == NULL || !CMenuXP::GetXPLookNFeel (pFrame) )
  933.         {
  934.             break;
  935.         }
  936.         TCHAR sClassName[10];
  937.         int Count = ::GetClassName (hWnd, sClassName, lengthof(sClassName));
  938.         // Check for the menu-class
  939.         if ( Count != 6 || _tcscmp (sClassName, _T("#32768")) != 0 )
  940.         {
  941.             break;
  942.         }
  943.         VERIFY(CWndMenuXP::FromHandle (pStruct->hwnd, false) != NULL);
  944.         if ( ::GetProp (pStruct->hwnd, _WndPropName_OldProc) != NULL )
  945.         {
  946.             // Already subclassed
  947.             break;
  948.         }
  949.         // Subclass the window
  950.         WNDPROC oldWndProc = (WNDPROC)(LONG_PTR)::GetWindowLong (pStruct->hwnd, GWL_WNDPROC);
  951.         if ( oldWndProc == NULL )
  952.         {
  953.             break;
  954.         }
  955.         ASSERT(oldWndProc != SubClassMenuProc);
  956.         if ( !SetProp (pStruct->hwnd, _WndPropName_OldProc, oldWndProc) )
  957.         {
  958.             break;
  959.         }
  960.         if ( !SetWindowLong (pStruct->hwnd, GWL_WNDPROC,(DWORD)(DWORD_PTR)SubClassMenuProc) )
  961.         {
  962.             ::RemoveProp (pStruct->hwnd, _WndPropName_OldProc);
  963.             break;
  964.         }
  965.         // Success !
  966.         break;
  967.     }
  968.     return CallNextHookEx (CWndMenuXP::ms_hHookOldMenuCbtFilter, code, wParam, lParam);
  969. }
  970. ///////////////////////////////////////////////////////////////////////////////
  971. LRESULT CALLBACK CWndMenuXP::SubClassMenuProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  972. {
  973.     WNDPROC oldWndProc = (WNDPROC)::GetProp (hWnd, _WndPropName_OldProc);
  974.     CWndMenuXP* pWnd = NULL;
  975.     switch ( uMsg )
  976.     {
  977.     case WM_NCCALCSIZE:
  978.         {
  979.             LRESULT lResult = CallWindowProc (oldWndProc, hWnd, uMsg, wParam, lParam);
  980.             if ( GetWinVersion() < wvWinXP )
  981.             {
  982.                 NCCALCSIZE_PARAMS* lpncsp = (NCCALCSIZE_PARAMS*)lParam;
  983.                 lpncsp->rgrc[0].right -= SM_CXSHADOW;
  984.                 lpncsp->rgrc[0].bottom -= SM_CXSHADOW;
  985.             }
  986.             return lResult;
  987.         }
  988.     case WM_WINDOWPOSCHANGING:
  989.         if ( (pWnd=CWndMenuXP::FromHandle (hWnd)) != NULL )
  990.         {
  991.             pWnd->OnWindowPosChanging ((LPWINDOWPOS)lParam);
  992.         }
  993.         break;
  994.     case WM_ERASEBKGND:
  995.         if ( (pWnd=CWndMenuXP::FromHandle (hWnd)) != NULL )
  996.         {
  997.             pWnd->OnEraseBkgnd();
  998.         }
  999.         break;
  1000.     case WM_PRINT:
  1001.         {
  1002.             BYTE nCheck = CMenuItem::ms_nCheck;
  1003.             LRESULT lResult = CallWindowProc (oldWndProc, hWnd, uMsg, wParam, lParam);
  1004.             bool bOwnerDrawnItems = nCheck != CMenuItem::ms_nCheck;
  1005.             if ( (pWnd=CWndMenuXP::FromHandle (hWnd)) != NULL )
  1006.             {
  1007.                 pWnd->OnPrint (CDC::FromHandle ((HDC)wParam), bOwnerDrawnItems);
  1008.             }
  1009.             return lResult;
  1010.         }
  1011.     case WM_NCPAINT:
  1012.         if ( (pWnd=CWndMenuXP::FromHandle (hWnd)) != NULL )
  1013.         {
  1014.             pWnd->OnNcPaint();
  1015.             return 0;
  1016.         }
  1017.         break;
  1018.     case WM_SHOWWINDOW:
  1019.         if ( (pWnd=CWndMenuXP::FromHandle (hWnd)) != NULL )
  1020.         {
  1021.             pWnd->OnShowWindow (wParam != 0);
  1022.         }
  1023.         break;
  1024.     case WM_NCDESTROY:
  1025.         if ( (pWnd=CWndMenuXP::FromHandle (hWnd)) != NULL )
  1026.         {
  1027.             pWnd->OnNcDestroy();
  1028.         }
  1029.         break;
  1030.     }
  1031.     return CallWindowProc (oldWndProc, hWnd, uMsg, wParam, lParam);
  1032. }