menubar.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 45k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include "priv.h"
  2. #include "sccls.h"
  3. #include "basebar.h"
  4. #include "bands.h"
  5. #include "multimon.h"
  6. #include "menubar.h"
  7. #include "menuband.h"           // for CMenuBand_Create
  8. #include "isfband.h"
  9. #include "apithk.h"
  10. // BUGBUG (lamadio): Conflicts with one defined in winuserp.h
  11. #undef WINEVENT_VALID       //It's tripping on this...
  12. #include "winable.h"
  13. #include "oleacc.h"
  14. #ifdef UNIX
  15. #include "unixstuff.h"
  16. #endif
  17. #define THISCLASS CMenuDeskBar
  18. #define SUPERCLASS CBaseBar
  19. // Don't fade the menu if it's larger than this magical number. Based on experiments
  20. // on a Pentium II - 233
  21. #define MAGICAL_NO_FADE_HEIGHT  600
  22. // For TraceMsg
  23. #define DM_POPUP   DM_TRACE
  24. #define UP    0
  25. #define DOWN  1
  26. #define LEFT  2
  27. #define RIGHT 3
  28. #ifdef ENABLE_CHANNELS
  29. IDeskBand * ChannelBand_Create(LPCITEMIDLIST pidl);
  30. #endif  // ENABLE_CHANNELS
  31. // Used by performance timing mode
  32. extern DWORD g_dwStopWatchMode;  // Shell performance mode
  33. extern HMENU g_hmenuStopWatch;
  34. extern UINT g_idCmdStopWatch;
  35. HRESULT CMenuDeskBar_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  36. {
  37.     // aggregation checking is handled in class factory
  38.     CMenuDeskBar *pwbar = new CMenuDeskBar();
  39.     if (pwbar) {
  40.         *ppunk = SAFECAST(pwbar, IMenuPopup*);
  41.         return S_OK;
  42.     }
  43.     return E_OUTOFMEMORY;
  44. }
  45. CMenuDeskBar::CMenuDeskBar() : SUPERCLASS()
  46. {
  47.     _dwMode = DBIF_VIEWMODE_VERTICAL; 
  48.     
  49.     _iIconSize = BMICON_SMALL;
  50. }
  51. CMenuDeskBar::~CMenuDeskBar()
  52. {
  53.     SetSite(NULL);
  54. }
  55. STDMETHODIMP CMenuDeskBar::QueryInterface(REFIID riid, void **ppvObj)
  56. {
  57.     HRESULT hres;
  58.     static const QITAB qit[] = {
  59.         QITABENT(THISCLASS, IMenuPopup),
  60.         QITABENT(THISCLASS, IObjectWithSite),
  61.         QITABENT(THISCLASS, IBanneredBar),
  62.         QITABENT(THISCLASS, IInitializeObject),
  63.         { 0 },
  64.     };
  65.     hres = QISearch(this, (LPCQITAB)qit, riid, ppvObj);
  66.     if (FAILED(hres))
  67.         hres = SUPERCLASS::QueryInterface(riid, ppvObj);
  68.     return hres;
  69. }
  70. /*----------------------------------------------------------
  71. Purpose: IMenuPopup::SetSubmenu method
  72. */
  73. STDMETHODIMP CMenuDeskBar::SetSubMenu(IMenuPopup* pmp, BOOL fSet)
  74. {
  75.     if (fSet) {
  76.         if (_pmpChild)
  77.             _pmpChild->Release();
  78.         
  79.         _pmpChild = pmp;
  80.         _pmpChild->AddRef();
  81.         
  82.     } else {
  83.         
  84.         if (_pmpChild && SHIsSameObject(pmp, _pmpChild)) {
  85.             _pmpChild->Release();
  86.             _pmpChild = NULL;
  87.         }
  88.     }
  89.     return S_OK;
  90. }
  91. void CMenuDeskBar::_PopDown()
  92. {
  93.     DAD_ShowDragImage(FALSE);
  94.     if (_pmpChild)
  95.         _pmpChild->OnSelect(MPOS_CANCELLEVEL);
  96.     
  97. //    ShowWindow(_hwnd, SW_HIDE);
  98.     SetWindowPos(_hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW);
  99.     ShowDW(FALSE);
  100.     if (_pmpParent) {
  101.         _pmpParent->SetSubMenu(this, FALSE);
  102.     }
  103.     UIActivateIO(FALSE, NULL);
  104.     _fActive = FALSE;
  105.     DAD_ShowDragImage(TRUE);
  106. }
  107. /*----------------------------------------------------------
  108. Purpose: IMenuPopup::OnSelect method
  109. */
  110. STDMETHODIMP CMenuDeskBar::OnSelect(DWORD dwSelectType)
  111. {
  112.     switch (dwSelectType)
  113.     {
  114.     case MPOS_CHILDTRACKING:
  115.         if (_pmpParent)
  116.             _pmpParent->OnSelect(dwSelectType);
  117.         break;
  118.         
  119.     case MPOS_SELECTRIGHT:
  120.     case MPOS_SELECTLEFT:
  121.         if (_pmpParent)
  122.             _pmpParent->OnSelect(dwSelectType);
  123.         break;
  124.     case MPOS_EXECUTE:
  125.     case MPOS_FULLCANCEL:
  126.         _PopDown();
  127.         if (_pmpParent)
  128.             _pmpParent->OnSelect(dwSelectType);
  129.         break;
  130.     case MPOS_CANCELLEVEL:
  131.         _PopDown();
  132.         break;
  133.         
  134.     }
  135.     
  136.     return S_OK;
  137. void SetExpandedBorder(HWND hwnd, BOOL fExpanded)
  138. {
  139. #ifdef MAINWIN
  140.     // IEUNIX : WS_DLGFRAME implementaion looks ugly on UNIX.
  141.     fExpanded = TRUE;
  142. #endif
  143.     DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE);
  144.     DWORD dwExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
  145.     if (fExpanded)
  146.     {
  147.         dwStyle |= WS_BORDER;
  148.         dwStyle &= ~WS_DLGFRAME;
  149.     }
  150.     else
  151.     {
  152.         dwStyle &= ~WS_BORDER;
  153.         dwStyle |= WS_DLGFRAME;
  154.     }
  155.     SetWindowLong(hwnd, GWL_STYLE, dwStyle);
  156.     SetWindowLong(hwnd, GWL_EXSTYLE, dwExStyle);
  157.     SetWindowPos(hwnd, NULL, 0, 0, 0, 0, 
  158.         SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
  159.     UpdateWindow(hwnd);
  160. }
  161. void CMenuDeskBar::_OnCreate()
  162. {
  163.     SetExpandedBorder(_hwnd, _fExpanded);
  164. }
  165. DWORD CMenuDeskBar::_GetClassStyle()
  166. {
  167.     // Faster repaint for menus when they go away
  168.     return CS_SAVEBITS;
  169. }
  170. DWORD CMenuDeskBar::_GetExStyle()
  171. {
  172. #ifndef MAINWIN
  173.     return WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
  174. #else
  175.     return WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_MW_UNMANAGED_WINDOW;
  176. #endif
  177. }
  178. // We use the following structure to pass a whole bunch of information from 
  179. // the GetPopupWindowPosition to WillFit function. We have WillFit function 
  180. // to cut the amount of duplicate code in getpopup window position. The order 
  181. // in which different the sides are checked is the only difference for popping 
  182. // up a window on a particular side.
  183. //
  184. // Having this function helps us to do that check by means of a parameter instead 
  185. // of repeating portions of code again and again.
  186. typedef struct  {
  187.     RECT rcAvail;           // Available dimensions b/t monitor edge and exclude edge
  188.     SIZE sizeAdjust;          // Size of menu edge
  189.     int  cyMonitor;         // Size of monitor 
  190.     int  cxMonitor;
  191.     int  cx;                // Size of menu
  192.     int  cy;
  193.     int  cyExtendDiff;      // Difference b/t calc'd size and available size
  194.     RECT *prcResult;
  195.     RECT *prcExclude;       // Exclude rect
  196.     RECT *prcMonitor;
  197. } PopupInfo;
  198. #define TOP     0
  199. #define BOTTOM  1
  200. #define LEFT    2
  201. #define RIGHT   3 
  202. /*----------------------------------------------------------
  203. Purpose: Attempt to fit and position a menu in the given direction
  204.          relative to an exclude rect.
  205.          Setting fForce to TRUE will cause the menu size to be adjusted
  206.          to fit, if necessary.
  207.          This function only sets the top and left coords, not the bottom
  208.          and right coords.
  209.          
  210.          Returns TRUE if the desired direction can be accomplished.
  211. */
  212. BOOL WillFit(PopupInfo * pinfo, int side, BOOL fForce)
  213. {
  214.     BOOL bRet = FALSE;
  215.     LPRECT prcResult = pinfo->prcResult;
  216.     
  217.     pinfo->cyExtendDiff = 0;
  218.     
  219.     switch(side)
  220.     {
  221.     case TOP:
  222.         pinfo->cyExtendDiff = pinfo->cy - pinfo->rcAvail.top;
  223.         if (fForce)
  224.         {
  225.             // Doesn't make sense to subtract a negative value
  226.             ASSERT(pinfo->cyExtendDiff >= 0);    
  227.             // +2 for some breathing room at the edge of the screen
  228.             pinfo->cy -= pinfo->cyExtendDiff + 2;    
  229.         }
  230.         // Can the menu be positioned above?
  231.         if (pinfo->cy <= pinfo->rcAvail.top)
  232.         {
  233.             // Yes
  234.             prcResult->top  = pinfo->prcExclude->top - pinfo->cy;
  235.             
  236.             goto AdjustHorzPos;
  237.         }
  238.         break;
  239.         
  240.     case BOTTOM:
  241.         pinfo->cyExtendDiff = pinfo->cy - pinfo->rcAvail.bottom;
  242.         if (fForce)
  243.         {
  244.             // Doesn't make sense to subtract a negative value
  245.             ASSERT(pinfo->cyExtendDiff >= 0);    
  246.             
  247.             // +2 for some breathing room at the edge of the screen
  248.             pinfo->cy -= pinfo->cyExtendDiff + 2;
  249.         }
  250.         // Can the menu be positioned below?
  251.         if (pinfo->cy <= pinfo->rcAvail.bottom)
  252.         {
  253.             // Yes
  254.             prcResult->top = pinfo->prcExclude->bottom;
  255. AdjustHorzPos:            
  256.             prcResult->left = max(pinfo->prcExclude->left, pinfo->prcMonitor->left);
  257.             // Can the menu be positioned relative to its left edge (hanging right)?
  258.             if (prcResult->left + pinfo->cx >= pinfo->prcMonitor->right)
  259.             {
  260.                 // No; move it in so it is on the screen
  261.                 //  (cx has already been adjusted to fit inside the monitor dimensions)
  262.                 prcResult->left = pinfo->prcMonitor->right - pinfo->cx - 1;
  263.             }
  264.             bRet = TRUE;
  265.         }
  266.         break;
  267.         
  268.     case LEFT:
  269.         // Can the menu be positioned to the left?
  270.         if (pinfo->cx <= pinfo->rcAvail.left || fForce)
  271.         {
  272.             // Yes
  273.             
  274.             // When cascading left, the menu does not overlap.  Also align
  275.             // so the client rect is vertically aligned with the exclude top.
  276.             prcResult->left = pinfo->prcExclude->left - pinfo->cx - 1;
  277.             goto AdjustVerticalPos;
  278.         }
  279.         break;
  280.     case RIGHT:
  281.         // Can the menu be positioned to the right?
  282.         if (pinfo->cx  <=  pinfo->rcAvail.right || fForce)
  283.         {
  284.             // Yes
  285.             
  286.             // Adjust the menu to slightly overlap the parent menu.  Also align
  287.             // so the client rect is vertically aligned with the exclude top.
  288.             prcResult->left = pinfo->prcExclude->right - pinfo->sizeAdjust.cx;
  289. AdjustVerticalPos:            
  290.             prcResult->top = pinfo->prcExclude->top - pinfo->sizeAdjust.cy;
  291.             // Can the menu be positioned relative to its top edge (hanging down)?
  292.             if (prcResult->top + pinfo->cy >= pinfo->prcMonitor->bottom)
  293.             {
  294.                 // No; can it be positioned relative to its bottom edge (hanging up)?
  295.                 prcResult->top = pinfo->prcExclude->bottom + pinfo->sizeAdjust.cy - pinfo->cy;
  296.                 
  297.                 if (prcResult->top < pinfo->prcMonitor->top)
  298.                 {
  299.                     // No; move the menu so it fits, but isn't vertically snapped.
  300.                     //  (cy has already been adjusted to fit inside the monitor
  301.                     //  dimensions)
  302.                     prcResult->top = pinfo->prcMonitor->bottom - pinfo->cy - 1;
  303.                 }
  304.             }
  305.             
  306.             bRet = TRUE;
  307.         }
  308.         break;
  309.     }
  310.     return bRet;
  311. }
  312. void CMenuDeskBar::_GetPopupWindowPosition(RECT* prcDesired, RECT* prcExclude, 
  313.                                            RECT *prcResult, SIZE * psizeAdjust, UINT uSide) 
  314. {
  315.     PopupInfo info;
  316.     MONITORINFO mi;
  317.     HMONITOR hMonitor;
  318.     RECT rcMonitor;
  319.     int cyExtendDiff = 0;
  320.     // Is this going to display the banner bitmap?
  321.     if (_iIconSize == BMICON_LARGE)
  322.     {
  323.         // Yes; add that to the dimensions
  324.         prcDesired->right += _sizeBmp.cx;
  325.     }
  326.     // First get the monitor information
  327.     hMonitor = MonitorFromRect(prcExclude, MONITOR_DEFAULTTONEAREST);
  328.     mi.cbSize = sizeof(mi);
  329.     GetMonitorInfo(hMonitor, &mi);
  330.     rcMonitor = mi.rcMonitor;
  331.     // Set the result rectangle same as the desired window
  332.     prcResult->left = prcDesired->left;
  333.     prcResult->top  = prcDesired->top;
  334.     // Calculate some sizes needed for calculation
  335.     info.rcAvail.left   = prcExclude->left - rcMonitor.left;
  336.     info.rcAvail.right  = rcMonitor.right - prcExclude->right;
  337.     info.rcAvail.top    = prcExclude->top - rcMonitor.top;
  338.     info.rcAvail.bottom = rcMonitor.bottom - prcExclude->bottom;
  339.     info.sizeAdjust = *psizeAdjust;
  340.     
  341.     info.cyMonitor = RECTHEIGHT(rcMonitor); 
  342.     info.cxMonitor = RECTWIDTH(rcMonitor); 
  343.     info.cx  = RECTWIDTH(*prcDesired);
  344.     info.cy = RECTHEIGHT(*prcDesired);
  345.     // If the desired rect is bigger than monitor then clip it to the monitor size
  346.     if (info.cy > info.cyMonitor)
  347.         info.cy = info.cyMonitor;
  348.     if (info.cx > info.cxMonitor)
  349.         info.cx = info.cxMonitor;
  350.     info.prcResult = prcResult;
  351.     info.prcExclude = prcExclude;
  352.     info.prcMonitor = &rcMonitor;
  353.     //Now Adjust the rectangle for the correct position
  354.     switch(uSide)
  355.     {
  356.     int iSide;
  357.     case MENUBAR_TOP:
  358.     
  359.         if (WillFit(&info, TOP, FALSE))
  360.         {
  361.             _uSide = MENUBAR_TOP;
  362.         }
  363.         else 
  364.         {
  365.             // We couldn't fit it above, how badly did we fall short?
  366.             cyExtendDiff = info.cyExtendDiff;
  367.             if (WillFit(&info, BOTTOM, FALSE))
  368.                 _uSide = MENUBAR_BOTTOM;
  369.             // We can't fit it below either, which dir was closest?
  370.             // If they are equal, default to requested direction
  371.             else if (info.cyExtendDiff < cyExtendDiff)
  372.             {
  373.                 _uSide = MENUBAR_BOTTOM;
  374.                 WillFit(&info, BOTTOM, TRUE);
  375.             }
  376.             else
  377.             {
  378.                 _uSide = MENUBAR_TOP;
  379.                 WillFit(&info, TOP, TRUE);
  380.             }
  381.         }
  382.         break;
  383.     case MENUBAR_BOTTOM:
  384.     
  385.         if (WillFit(&info, BOTTOM, FALSE))
  386.         {
  387.             _uSide = MENUBAR_BOTTOM;
  388.         }
  389.         else
  390.         {   
  391.             // We couldn't fit it below, how badly did we fall short?
  392.             cyExtendDiff = info.cyExtendDiff;
  393.             if (WillFit(&info, TOP, FALSE))
  394.                 _uSide = MENUBAR_TOP;
  395.             // We can't fit it above either, which dir was closest?
  396.             // If they are equal, default to requested direction
  397.             else if (info.cyExtendDiff < cyExtendDiff)
  398.             {
  399.                 _uSide = MENUBAR_TOP;
  400.                 WillFit(&info, TOP, TRUE);
  401.             }
  402.             else
  403.             {
  404.                 _uSide = MENUBAR_BOTTOM;
  405.                 WillFit(&info, BOTTOM, TRUE);
  406.             }
  407.         }
  408.         break;
  409.     case MENUBAR_LEFT:
  410.         if (WillFit(&info, LEFT, FALSE))
  411.         {
  412.             _uSide = MENUBAR_LEFT;
  413.         }else if (WillFit(&info, RIGHT, FALSE))
  414.         {
  415.             _uSide = MENUBAR_RIGHT;
  416.         }else {
  417.             // fit where have most room and can show most of menu.
  418.             if ((info.cx - (info.prcExclude)->right) > (info.prcExclude)->left)
  419.             {
  420.                 _uSide = MENUBAR_RIGHT;
  421.                 iSide = RIGHT;
  422.             }
  423.             else
  424.             {
  425.                 _uSide = MENUBAR_LEFT;
  426.                 iSide = LEFT;
  427.             }
  428.             WillFit(&info, iSide, TRUE);
  429.         }
  430.         break;
  431.     case MENUBAR_RIGHT:
  432.         if (WillFit(&info, RIGHT, FALSE))
  433.         {
  434.             _uSide = MENUBAR_RIGHT;
  435.         }else if (WillFit(&info, LEFT, FALSE))
  436.         {
  437.             _uSide = MENUBAR_LEFT;
  438.         }else {
  439.             // fit where have most room and can show most of menu.
  440.             if ((info.cx - (info.prcExclude)->right) >= (info.prcExclude)->left)
  441.             {
  442.                 _uSide = MENUBAR_RIGHT;
  443.                 iSide = RIGHT;
  444.             }
  445.             else
  446.             {
  447.                 _uSide = MENUBAR_LEFT;
  448.                 iSide = LEFT;
  449.             }
  450.             WillFit(&info, iSide, TRUE);
  451.         }
  452.         break;
  453.     }
  454.     
  455.     // Finally set the bottom and right
  456.     if (prcResult->top < rcMonitor.top)
  457.         prcResult->top = rcMonitor.top;
  458.     if (prcResult->left < rcMonitor.left)
  459.         prcResult->left = rcMonitor.left;
  460.     prcResult->bottom = prcResult->top  + info.cy;
  461.     prcResult->right  = prcResult->left + info.cx;
  462.     if (prcResult->bottom > rcMonitor.bottom)
  463.     {
  464.         // -2 for some breathing room at the edge of the screen
  465.         prcResult->bottom = rcMonitor.bottom - 2;
  466.         prcResult->top = prcResult->bottom - info.cy;
  467.     }
  468. }
  469. HRESULT CMenuDeskBar::_PositionWindow(POINTL *ppt, RECTL* prcExclude, DWORD dwFlags)
  470. {
  471.     ASSERT(IS_VALID_READ_PTR(ppt, POINTL));
  472.     ASSERT(NULL == prcExclude || IS_VALID_READ_PTR(prcExclude, RECTL));
  473.     BOOL bSetFocus = (dwFlags & MPPF_SETFOCUS);
  474.     RECT rcDesired;
  475.     RECT rcExclude;
  476.     RECT rc;
  477.     SIZE sizeAdjust;
  478.     UINT uAnimateSide;
  479.     BOOL bMirroredWindow=IS_WINDOW_RTL_MIRRORED(_hwnd);
  480.     static const iPosition[] = {MENUBAR_TOP, MENUBAR_LEFT, MENUBAR_RIGHT, MENUBAR_BOTTOM};
  481.     if (dwFlags & MPPF_POS_MASK)
  482.     {
  483.         UINT uPosIndex = ((dwFlags & MPPF_POS_MASK) >> 29) - 1;
  484.         ASSERT(uPosIndex < 4);
  485.         _uSide = iPosition[uPosIndex];
  486.     }
  487.     if (bSetFocus)
  488.         SetForegroundWindow(_hwnd);
  489.     
  490.     _pt = *(POINT*)ppt;
  491.     // Get the size of the ideal client rect of the child
  492.     RECT rcChild = {0};
  493.     // BUGBUG (scotth): This only sets the bottom and the right values
  494.     _pDBC->GetSize(DBC_GS_IDEAL, &rcChild);
  495.     DWORD dwStyle = GetWindowLong(_hwnd, GWL_STYLE);
  496.     DWORD dwExStyle = GetWindowLong(_hwnd, GWL_EXSTYLE);
  497.     // Adjust for the window border style
  498.     rcDesired = rcChild;        // use rcDesired as a temp variable
  499.     AdjustWindowRectEx(&rcChild, dwStyle, FALSE, dwExStyle);
  500.     // Calculate the edge of the menu border, and add a fudge factor so
  501.     // left/right-cascaded menus overlap the parent menu a bit and are
  502.     // correctly aligned vertically.
  503.     sizeAdjust.cx = (RECTWIDTH(rcChild) - RECTWIDTH(rcDesired)) / 2;
  504.     sizeAdjust.cy = (RECTHEIGHT(rcChild) - RECTHEIGHT(rcDesired)) / 2;
  505.     if (prcExclude)
  506.     {
  507.         CopyRect(&rcExclude, (RECT*)prcExclude);
  508.         //
  509.         // If mirroring is enabled, let's mirror this guy
  510.         // by simulating a different mirrored rect. This is
  511.         // only for dropdown menus. [samera]
  512.         //  
  513.         if (bMirroredWindow)           
  514.         {
  515.             if ((_uSide != MENUBAR_LEFT)    &&
  516.                 (_uSide != MENUBAR_RIGHT) )
  517.             {  
  518.                 int x;
  519.                 int iW  = rcExclude.right-rcExclude.left;
  520.                 int icW = (rcChild.right-rcChild.left);
  521.                 if( icW > iW )
  522.                 {
  523.                     x = icW - iW;
  524.                     rcExclude.left  -= x ;
  525.                     rcExclude.right -= x ;
  526.                 }
  527.                 else
  528.                 {
  529.                     x = iW - icW;
  530.                     rcExclude.left  += x;
  531.                     rcExclude.right += x;
  532.                 }
  533.                 ppt->x = rcExclude.left;
  534.             }
  535.         }
  536.         TraceMsg(DM_POPUP, "Parent Side is %d ", _uSide);
  537.         switch(_uSide) 
  538.         {
  539.         case MENUBAR_LEFT :
  540.             rcDesired.left = rcExclude.left - rcChild.right;  // right is width
  541.             rcDesired.top  = rcExclude.top;
  542.             break;
  543.         case MENUBAR_RIGHT :
  544.             rcDesired.left = rcExclude.right;
  545.             rcDesired.top  = rcExclude.top;
  546.             break;
  547.             
  548.         case MENUBAR_TOP:
  549.             rcDesired.left = rcExclude.left;
  550.             rcDesired.top  = rcExclude.top - rcChild.bottom;  // bottom is height
  551.             break;
  552.         case MENUBAR_BOTTOM:
  553.             rcDesired.left = rcExclude.left;
  554.             rcDesired.top  = rcExclude.bottom;
  555.             break;
  556.         default:
  557.             rcDesired.left   = _pt.x;
  558.             rcDesired.top    = _pt.y;
  559.         }
  560.     }
  561.     else
  562.     {
  563.         SetRectEmpty(&rcExclude);
  564.         rcDesired.left   = _pt.x;
  565.         rcDesired.top    = _pt.y;
  566.     }
  567.     rcDesired.right  =  rcDesired.left + RECTWIDTH(rcChild);
  568.     rcDesired.bottom =  rcDesired.top + RECTHEIGHT(rcChild);
  569.     _GetPopupWindowPosition(&rcDesired, &rcExclude, &rc, &sizeAdjust, _uSide);
  570.     UINT uFlags = 0;
  571.     if (!bSetFocus)
  572.         uFlags |= SWP_NOACTIVATE;
  573.     //
  574.     // Open the menus properly. In case of a RTL mirrored window,
  575.     // flip the animation side. [samera]
  576.     //
  577.     if( bMirroredWindow )
  578.     {
  579.         switch( _uSide )
  580.         {
  581.         case MENUBAR_LEFT:
  582.             uAnimateSide = MENUBAR_RIGHT;
  583.         break;
  584.         case MENUBAR_RIGHT:
  585.             uAnimateSide = MENUBAR_LEFT;
  586.         break;
  587.         default:
  588.             uAnimateSide = _uSide;
  589.         }
  590.     }
  591.     else
  592.     {
  593.         uAnimateSide = _uSide;
  594.     }
  595.     TraceMsg(TF_MENUBAND, "CMenuBar::_PositionWindow (%d,%d,%d,%d)",
  596.         rc.left, rc.top, rc.right, rc.bottom);
  597.     // Last minuite tweak. Since we're in large icon, we need to add this
  598.     // so that the bitmap is painted correctly.
  599.     if(_iIconSize == BMICON_LARGE && _fExpanded)
  600.         rc.right += 1;
  601.     // We _DO_ want to do a Z-Order position when this flag is specified. This is
  602.     // for full repositioning where we need to preserve the overlap state of all bands.
  603.     // Otherwize we just want to size the bar without changing it's z-order.
  604.     if (!(dwFlags & MPPF_FORCEZORDER) && 
  605.         (S_OK == IUnknown_QueryServiceExec(_punkChild, SID_SMenuBandChild,
  606.          &CGID_MenuBand, MBANDCID_ISINSUBMENU, 0, NULL, NULL)))
  607.     {
  608.         uFlags |= SWP_NOZORDER;
  609.     }
  610.     // If it's bigger than this magical number, then we don't animate. change to taste
  611.   
  612.     if (RECTHEIGHT(rc) > MAGICAL_NO_FADE_HEIGHT)
  613.         dwFlags |= MPPF_NOANIMATE;
  614.     AnimateSetMenuPos(_hwnd, &rc, uFlags, uAnimateSide, dwFlags & MPPF_NOANIMATE);
  615.     // Save information so we can later resize this window
  616.     // We already have: _pt, _uSide
  617.     if (prcExclude)
  618.     {
  619.         _fExcludeRect = TRUE;
  620.         CopyRect(&_rcExclude, (RECT*)prcExclude);
  621.     }
  622.     else
  623.         _fExcludeRect = FALSE;
  624.     return S_OK;
  625. /*----------------------------------------------------------
  626. Purpose: IMenuPopup::Popup method
  627. */
  628. STDMETHODIMP CMenuDeskBar::Popup(POINTL* ppt, RECTL* prcExclude, DWORD dwFlags)
  629. {
  630.     HRESULT hres;
  631.     // Is the caller telling us to reposition?
  632.     if (dwFlags & MPPF_REPOSITION)
  633.     {
  634.         if (ppt == NULL)
  635.             ppt = (POINTL*)&_pt;
  636.         if (prcExclude == NULL)
  637.             prcExclude = (RECTL*)&_rcExclude;
  638.         // Yes; Then we don't need to do any First show stuff.
  639.         _PositionWindow(ppt, prcExclude, dwFlags);
  640.         return S_OK;
  641.     }
  642.     ASSERT(IS_VALID_READ_PTR(ppt, POINTL));
  643.     ASSERT(NULL == prcExclude || IS_VALID_READ_PTR(prcExclude, RECTL));
  644.     if (g_dwProfileCAP & 0x00002000) 
  645.         StartCAP();
  646.     if (g_dwStopWatchMode)
  647.         StopWatch_Start(SWID_MENU, TEXT("Menu Start"), SPMODE_SHELL | SPMODE_DEBUGOUT);
  648.     
  649.     if (_pmpParent) 
  650.     {
  651.         _pmpParent->SetSubMenu(this, TRUE);
  652.     }
  653.     IOleCommandTarget* poct;
  654.     hres = IUnknown_QueryService(_punkChild, SID_SMenuBandChild, IID_IOleCommandTarget, 
  655.                                  (LPVOID *)&poct);
  656.     if (SUCCEEDED(hres))
  657.     {
  658.         // We need to do this before the ShowDW. This saves us from doing the setting twice
  659.         // Because in the ShowDW of MenuBand, we actually go an initialize the toolbar with
  660.         // the current default setting which should be "No Keyboard Cues." If we set the state
  661.         // here, then the state will be "Show keyboard cues." Then we will update the toolbar. 
  662.         if (dwFlags & MPPF_KEYBOARD)
  663.             poct->Exec(&CGID_MenuBand, MBANDCID_KEYBOARD, 0, NULL, NULL);
  664.     }
  665.     else
  666.     {
  667.         ASSERT(poct == NULL);
  668.     }
  669.     
  670.     _NotifyModeChange(_dwMode);
  671.     ShowDW(TRUE);
  672.     if(_pmpParent) {
  673.         VARIANT varg;
  674.         hres = IUnknown_Exec(_pmpParent, &CGID_MENUDESKBAR, MBCID_GETSIDE, 0, NULL, &varg);
  675.         if(SUCCEEDED(hres)) {
  676.             if(varg.vt ==  VT_I4) {
  677.                 _uSide = (UINT) varg.lVal;
  678.             }
  679.         }
  680.     }
  681.     IEPlaySound(TEXT("MenuPopup"), TRUE);
  682.     _PositionWindow(ppt, prcExclude, dwFlags);
  683.     // Set focus
  684.     UIActivateIO(TRUE, NULL);
  685.     
  686.     _fActive = TRUE;
  687.     // Select the first/last item?
  688.     if ((dwFlags & (MPPF_INITIALSELECT | MPPF_FINALSELECT)) && poct)
  689.     {
  690.         DWORD nCmd = (dwFlags & MPPF_INITIALSELECT) ? MBSI_FIRSTITEM : MBSI_LASTITEM;
  691.         poct->Exec(&CGID_MenuBand, MBANDCID_SELECTITEM, nCmd, NULL, NULL);
  692.     }
  693.     ATOMICRELEASE(poct);
  694.     
  695.     if (g_dwStopWatchMode)
  696.     {
  697.         TCHAR szMenu[32];
  698.         TCHAR szText[256];
  699.         *szMenu = '';
  700.         if(g_hmenuStopWatch != NULL)
  701.             GetMenuString(g_hmenuStopWatch, 0, szMenu, ARRAYSIZE(szMenu)-1, MF_BYPOSITION);
  702.         wnsprintf(szText, ARRAYSIZE(szText) - 1, TEXT("Menu %d %s%sStop"), g_idCmdStopWatch, szMenu, *szMenu ?TEXT(" ") :TEXT(""));
  703.         StopWatch_Stop(SWID_MENU, (LPCTSTR)szText, SPMODE_SHELL | SPMODE_DEBUGOUT);
  704.     }
  705.     if (g_dwProfileCAP & 0x00002000) 
  706.         StopCAP();
  707.         
  708.     return S_OK;
  709. /*----------------------------------------------------------
  710. Purpose: IInputObjectSite::OnFocusChangeIS
  711. Returns: 
  712. Cond:    --
  713. */
  714. HRESULT CMenuDeskBar::OnFocusChangeIS(IUnknown *punk, BOOL fSetFocus)
  715. {
  716.     return NOERROR;
  717. }
  718. /*----------------------------------------------------------
  719. Purpose: IObjectWithSite::SetSite method
  720. */
  721. STDMETHODIMP CMenuDeskBar::SetSite(IUnknown* punkSite)
  722. {
  723.     ASSERT(NULL == punkSite || IS_VALID_CODE_PTR(punkSite, IUnknown));
  724.     if (_fShow)
  725.         _PopDown();
  726.     ATOMICRELEASE(_punkSite);
  727.     ATOMICRELEASE(_pmpParent);
  728.     
  729.     _punkSite = punkSite;
  730.     
  731.     if (_punkSite) {
  732.         
  733.         _punkSite->AddRef();
  734.         IUnknown_QueryService(_punkSite, SID_SMenuPopup, IID_IMenuPopup, (LPVOID*)&_pmpParent);
  735.     } else {
  736.         CloseDW(0);
  737.     }
  738.         
  739.     return S_OK;
  740. /*----------------------------------------------------------
  741. Purpose: IObjectWithSite::GetSite method
  742. */
  743. STDMETHODIMP CMenuDeskBar::GetSite(REFIID riid, LPVOID* ppvSite)
  744. {
  745.     if (_punkSite)
  746.     {
  747.         return _punkSite->QueryInterface(riid, ppvSite);
  748.     }
  749.     *ppvSite = NULL;
  750.     return E_FAIL;
  751. /*----------------------------------------------------------
  752. Purpose: IOleCommandTarget::Exec method
  753. */
  754. STDMETHODIMP CMenuDeskBar::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt,
  755.                         VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
  756. {
  757.     if (pguidCmdGroup == NULL) 
  758.     {
  759.         
  760.     } 
  761.     else if (IsEqualGUID(CGID_DeskBarClient, *pguidCmdGroup))
  762.     {
  763.         switch (nCmdID) {
  764.         case DBCID_EMPTY:
  765.             // if we have no bands left, close
  766.             OnSelect(MPOS_FULLCANCEL);
  767.             return S_OK;
  768.         default:
  769.             return OLECMDERR_E_NOTSUPPORTED;
  770.         }
  771.     }
  772.     else if (IsEqualGUID(CGID_MENUDESKBAR, *pguidCmdGroup))
  773.     {
  774.         switch(nCmdID) {
  775.             case MBCID_GETSIDE :
  776.                 pvarargOut->vt = VT_I4;
  777.                 pvarargOut->lVal = _GetSide();
  778.                 return S_OK;
  779.             case MBCID_RESIZE:
  780.                 if (_fActive)
  781.                 {
  782.                     if (_fExcludeRect)
  783.                         _PositionWindow((POINTL *)&_pt, (RECTL *)&_rcExclude, 0);
  784.                     else
  785.                         _PositionWindow((POINTL *)&_pt, NULL, 0);
  786.                 }
  787.                 return S_OK;
  788.             case MBCID_SETEXPAND:
  789.                 if ((BOOL)_fExpanded != (BOOL)nCmdexecopt)
  790.                 {
  791.                     _fExpanded = nCmdexecopt;
  792.                     SetExpandedBorder(_hwnd, _fExpanded);
  793.                 }
  794.                 return S_OK;
  795.             default : 
  796.                 return OLECMDERR_E_NOTSUPPORTED;
  797.         }   
  798.     }
  799.     
  800.     return SUPERCLASS::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
  801. }    
  802.     
  803. /*----------------------------------------------------------
  804. Purpose: IServiceProvider::QueryService method
  805. */
  806. STDMETHODIMP CMenuDeskBar::QueryService(REFGUID guidService, REFIID riid, void **ppvObj)
  807. {
  808.     if (IsEqualGUID(guidService, SID_SMenuPopup)) 
  809.     {
  810.         return QueryInterface(riid, ppvObj);
  811.     }
  812.     else if (IsEqualIID(guidService, SID_SMenuBandBottom) ||
  813.              IsEqualIID(guidService, SID_SMenuBandBottomSelected)||
  814.              IsEqualIID(guidService, SID_SMenuBandChild))
  815.     {
  816.         // SID_SMenuBandBottom queries down
  817.         return IUnknown_QueryService(_punkChild, guidService, riid, ppvObj);
  818.     }
  819.     else
  820.     {
  821.         HRESULT hres = SUPERCLASS::QueryService(guidService, riid, ppvObj);
  822.         
  823.         if (FAILED(hres)) {
  824.             hres = IUnknown_QueryService(_punkSite, guidService, riid, ppvObj);
  825.         }
  826.         
  827.         return hres;
  828.     }
  829.         
  830. /*----------------------------------------------------------
  831. Purpose: IServiceProvider::QueryService method
  832. */
  833. STDMETHODIMP CMenuDeskBar::SetIconSize(DWORD iIcon)
  834. {
  835.     HRESULT hres;
  836.     _iIconSize = iIcon;
  837.     hres = IUnknown_QueryServiceExec(_punkChild, SID_SMenuBandChild, &CGID_MenuBand, 
  838.         MBANDCID_SETICONSIZE, iIcon == BMICON_SMALL? ISFBVIEWMODE_SMALLICONS: ISFBVIEWMODE_LARGEICONS, NULL, NULL);
  839.     return hres;
  840. }
  841. /*----------------------------------------------------------
  842. Purpose: IServiceProvider::QueryService method
  843. */
  844. STDMETHODIMP CMenuDeskBar::SetBitmap(HBITMAP hBitmap)
  845. {
  846.     ASSERT(hBitmap);
  847.     BITMAP bm;
  848.     _hbmp = hBitmap;
  849.     if (_hbmp)
  850.     {
  851.         if(!GetObject(_hbmp, sizeof(bm), &bm))
  852.             return E_FAIL;
  853.         _sizeBmp.cx = bm.bmWidth;
  854.         _sizeBmp.cy = bm.bmHeight;
  855.         // Hack to get color
  856.         HDC hdc = GetDC(_hwnd);
  857.         if (hdc)
  858.         {
  859.             HDC hdcMem = CreateCompatibleDC(hdc);
  860.             if (hdcMem)
  861.             {
  862.                 HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcMem, _hbmp);
  863.                 _rgb = GetPixel(hdcMem, 0, 0);
  864.                 SelectObject(hdcMem, hbmpOld);
  865.                 DeleteDC(hdcMem);
  866.             }
  867.             ReleaseDC(_hwnd, hdc);
  868.         }
  869.     }
  870.     return NOERROR;
  871. }
  872. void CMenuDeskBar::_OnSize()
  873. {
  874.     RECT rc;
  875.     if (!_hwndChild)
  876.         return;
  877.     GetClientRect(_hwnd, &rc);
  878.     if(_iIconSize == BMICON_LARGE)
  879.     {
  880.         rc.left += _sizeBmp.cx;
  881.         if (_fExpanded)
  882.             rc.left++;
  883.     }
  884.     SetWindowPos(_hwndChild, 0,
  885.             rc.left, rc.top, RECTWIDTH(rc), RECTHEIGHT(rc),
  886.             SWP_NOACTIVATE|SWP_NOZORDER|SWP_FRAMECHANGED);
  887.     rc.right = rc.left;
  888.     rc.left -= _sizeBmp.cx;
  889.     if (_fShow)
  890.         InvalidateRect(_hwnd, &rc, TRUE);
  891. }
  892. LRESULT CMenuDeskBar::_DoPaint(HWND hwnd, HDC hdc, DWORD dwFlags)
  893. {
  894.     HDC hdcmem;
  895.     HBITMAP hbmpOld;
  896.     RECT rc;
  897.     HBRUSH   hbrush;
  898.     int iDC = SaveDC(hdc);
  899.     GetClientRect(hwnd, &rc);
  900.     //Create a compatable DC
  901.     hdcmem = CreateCompatibleDC(hdc);
  902.     if(hdcmem)
  903.     {
  904.         // Offset the stuff we're paining if we're expanded
  905.         BYTE bOffset = _fExpanded? 1 : 0;
  906.         // Store this for the Bar fill cycle
  907.         int cyBitmap = 0;
  908.         if (_sizeBmp.cy <= RECTHEIGHT(rc) + 1)
  909.         {
  910.             //Select the bitmap into the memory DC
  911.             hbmpOld = (HBITMAP)SelectObject(hdcmem, _hbmp);
  912.             //Blit to the window
  913.             BitBlt(hdc, bOffset, rc.bottom - _sizeBmp.cy - bOffset, _sizeBmp.cx, _sizeBmp.cy, hdcmem, 0, 0, SRCCOPY);
  914.             // Ok, We need to subtract this value to see how much we need to paint for the banner.
  915.             cyBitmap = _sizeBmp.cy;
  916.             //Restore the DC
  917.             SelectObject(hdcmem, hbmpOld);
  918.         }
  919.         rc.right = _sizeBmp.cx + bOffset;
  920.         if (_fExpanded)
  921.             DrawEdge(hdc, &rc, BDR_RAISEDINNER, BF_LEFT | BF_TOP | BF_BOTTOM);
  922.         //Paint the rest
  923.         hbrush = CreateSolidBrush(_rgb);
  924.         if(hbrush)
  925.         {
  926.             rc.bottom -= cyBitmap + bOffset;
  927.             if (_fExpanded)
  928.             {
  929.                 rc.left += bOffset;
  930.                 rc.top += bOffset;
  931.             }
  932.             FillRect(hdc, &rc, hbrush);
  933.             DeleteObject(hbrush);
  934.         }
  935.         //Delete the DC.
  936.         DeleteDC(hdcmem);
  937.     }
  938.     RestoreDC(hdc, iDC);
  939.     return 0;
  940. }
  941. void CMenuDeskBar::_DoNCPaint(HWND hwnd, HDC hdc)
  942. {
  943.     RECT rc;
  944.     // Since we need to paint the border, we get the window rect
  945.     GetWindowRect(hwnd, &rc);
  946.     // then change the rect so that it represents values relative to 
  947.     // the origin.
  948.     OffsetRect(&rc, -rc.left, -rc.top);
  949.     if (hdc)
  950.     {
  951.         DrawEdge(hdc, &rc, BDR_RAISEDOUTER, BF_RECT);
  952.     }
  953. }
  954. LRESULT CMenuDeskBar::v_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  955. {
  956.     
  957.     LRESULT lres;
  958.     switch (uMsg) 
  959.     {
  960. #ifdef MAINWIN
  961.     case WM_NCPAINTSPECIALFRAME:
  962.         // In  case  of  motif look  the  MwPaintBorder paints a Etched In
  963.         // border if WM_NCPAINTSPECIALFRAME returns FALSE. We are handling
  964.         // this message here and drawing the Etched Out frame explicitly.
  965.         // wParam - HDC
  966.         if (MwCurrentLook() == LOOK_MOTIF)
  967.         {
  968.             MwPaintSpecialEOBorder( hwnd, (HDC)wParam );
  969.             return TRUE;
  970.         }
  971.         break;
  972. #endif
  973.     case WM_GETOBJECT:
  974.         if (lParam == OBJID_MENU)
  975.         {
  976.             IAccessible* pacc;
  977.             if (SUCCEEDED(QueryService(SID_SMenuBandChild, IID_IAccessible, (void**)&pacc)))
  978.             {
  979.                 lres = LresultFromObject(IID_IAccessible, wParam, SAFECAST(pacc, IAccessible*));
  980.                 pacc->Release();
  981.                 return lres;
  982.             }
  983.         }
  984.         break;
  985.     case WM_NCCREATE:
  986.         //
  987.         // Since this is a mirrored menu, then open it
  988.         // on the left (mirrored) edge if possible. WillFit(...) will
  989.         // ensure this for us [samera]
  990.         //
  991.         // Mirror the menu initially if its window is mirrored
  992.         //
  993.         ASSERT(_uSide == 0);
  994.         if (IS_WINDOW_RTL_MIRRORED(_hwnd))
  995.             _uSide = MENUBAR_LEFT;
  996.         else
  997.             _uSide = MENUBAR_RIGHT;
  998.         break;
  999.     case WM_ACTIVATE:
  1000.         if (LOWORD(wParam) == WA_INACTIVE) 
  1001.         {
  1002.             if (_fActive && !_pmpChild) 
  1003.             {
  1004.                 
  1005.                 // if we were active, and the thing going active now
  1006.                 // is not one of our parent menubars, then cancel everything.
  1007.                 
  1008.                 // if it's a parent of ours going active, assume that
  1009.                 // they will tell us to die when they want us to...
  1010.                 if (!_IsMyParent((HWND)lParam))
  1011.                     OnSelect(MPOS_FULLCANCEL);
  1012.             }
  1013.         } 
  1014.         else 
  1015.         {
  1016.             if (_pmpChild) 
  1017.             {
  1018.                 // if we're becoming active, and we have a child, that child should go away
  1019.                 _pmpChild->OnSelect(MPOS_CANCELLEVEL);
  1020.             }
  1021.         }
  1022.         break;
  1023.     case WM_PRINTCLIENT:
  1024.         if (_iIconSize == BMICON_LARGE)
  1025.         {
  1026.             _DoPaint(hwnd, (HDC)wParam, (DWORD)lParam);
  1027.             return 0;
  1028.         }
  1029.         break;
  1030.     case WM_PAINT:
  1031.         // Paint the banner if we're in showing large icons
  1032.         if (_iIconSize == BMICON_LARGE)
  1033.         {
  1034.             PAINTSTRUCT ps;
  1035.             BeginPaint(hwnd, &ps);
  1036.             _DoPaint(hwnd, ps.hdc, 0);
  1037.             EndPaint(hwnd, &ps);
  1038.             return 0;
  1039.         }
  1040.         break;
  1041.    case WM_PRINT:
  1042.         if (_fExpanded && PRF_NONCLIENT & lParam)
  1043.         {
  1044.             HDC hdc = (HDC)wParam;
  1045.             DefWindowProcWrap(hwnd, WM_PRINT, wParam, lParam);
  1046.             // Do this after so that we look right...
  1047.             _DoNCPaint(hwnd, hdc);
  1048.             return 1;
  1049.         }
  1050.         break;
  1051.     case WM_NCPAINT:
  1052.         if (_fExpanded)
  1053.         {    
  1054.             HDC hdc;    
  1055.             hdc = GetWindowDC(hwnd);
  1056.             _DoNCPaint(hwnd, hdc);
  1057.             ReleaseDC(hwnd, hdc);
  1058.             return 1;
  1059.         } 
  1060.         break;
  1061.     case WM_NCHITTEST:
  1062.         lres = SUPERCLASS::v_WndProc(hwnd, uMsg, wParam, lParam);
  1063.         switch (lres)
  1064.         {
  1065.         case HTBOTTOM:
  1066.         case HTBOTTOMLEFT:
  1067.         case HTBOTTOMRIGHT:
  1068.         case HTLEFT:
  1069.         case HTRIGHT:
  1070.         case HTTOP:
  1071.         case HTTOPLEFT:
  1072.         case HTTOPRIGHT:
  1073.             // Don't allow the window to be resized
  1074.             lres = HTBORDER;
  1075.             break;
  1076.         case HTTRANSPARENT:
  1077.             // Don't let a click go thru to the window underneath
  1078.             lres = HTCLIENT;
  1079.             break;
  1080.         }
  1081.         return lres;
  1082.         // HACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACKHACK
  1083.         // (lamadio) 1.25.99
  1084.         // This hack is here to fix a problem on down level Windows with Integrated
  1085.         // IE4.01, IE5 and Office 2000.
  1086.         // The bug revolves around Start Menu not being destroyed when Explorer.exe shuts
  1087.         // down. Start Menu unregisters itself at CloseDW, but since the menubar never gets
  1088.         // destroyed, Start Menu never deregisters itself.
  1089.         // When an System service, such as MSTASK.dll keeps shell32 alive in the background,
  1090.         // it leaves an outstanding reference to a change notify. When a new user logs in,
  1091.         // O2k and IE5 fire up group conv, generating more than 10 change notify events in the
  1092.         // start menu. This causes the batching code to be fired up: Which does not really
  1093.         // work without the shell started. GroupConv also adds these events using memory 
  1094.         // alloced from it's process heap. Since there is an outstanding change notify handler
  1095.         // these pidls get forced to be handled. Shell32 then faults derefing a bad pidl.
  1096.         // By detecting an Endsession, we can eliminate this problem. Doing a SetClient(NULL)
  1097.         // cause Menubar to free it's references to MenuSite. Menusite, calls CloseDW on menuband
  1098.         // menuband then causes MNFolder to unregister itself. Since no one is listening any more
  1099.         // the crash is avoided.
  1100.     case WM_ENDSESSION:
  1101.         if (wParam != 0)
  1102.         {
  1103.             SetClient(NULL);
  1104.         }
  1105.         break;
  1106.     }
  1107.     
  1108.     return SUPERCLASS::v_WndProc(hwnd, uMsg, wParam, lParam);
  1109. IMenuPopup* CMenuDeskBar::_GetMenuBarParent(IUnknown* punk)
  1110. {
  1111.     IMenuPopup *pmp = NULL;
  1112.     IObjectWithSite* pows;
  1113.     punk->QueryInterface(IID_IObjectWithSite, (LPVOID*)&pows);
  1114.     if (pows) {
  1115.         
  1116.         IServiceProvider* psp;
  1117.         pows->GetSite(IID_IServiceProvider, (LPVOID*)&psp);
  1118.         
  1119.         if (psp) {
  1120.             
  1121.             psp->QueryService(SID_SMenuPopup, IID_IMenuPopup, (LPVOID*)&pmp);
  1122.             psp->Release();
  1123.         }
  1124.         
  1125.         pows->Release();
  1126.     }
  1127.     
  1128.     return pmp;
  1129. }
  1130. // this assumes that hwnd is a toplevel window and that the menudeskbars are also 
  1131. // the only hosts and are themselves toplevel
  1132. BOOL CMenuDeskBar::_IsMyParent(HWND hwnd)
  1133. {
  1134.     BOOL fRet = FALSE;
  1135.     if (hwnd) {
  1136.         HWND hwndMenu;
  1137.         
  1138.         IMenuPopup *pmpParent = _pmpParent;
  1139.         if (pmpParent)
  1140.             pmpParent->AddRef();
  1141.         
  1142.         while (pmpParent && !fRet &&
  1143.                SUCCEEDED(IUnknown_GetWindow(pmpParent, &hwndMenu))) {
  1144.             
  1145.             if (hwndMenu == hwnd) {
  1146.                 fRet = TRUE;
  1147.             }
  1148.             
  1149.             IMenuPopup* pmpNext = _GetMenuBarParent(pmpParent);
  1150.             pmpParent->Release();
  1151.             pmpParent = pmpNext;
  1152.         }
  1153.     }
  1154.     return fRet;
  1155. }
  1156. IBandSite* BandSiteFromBar(IMenuPopup* pmp)
  1157. {
  1158.     ASSERT(IS_VALID_CODE_PTR(pmp, IMenuPopup));
  1159.     IDeskBar* pdbar;
  1160.     IBandSite* pbs = NULL;
  1161.     pmp->QueryInterface(IID_IDeskBar, (LPVOID*)&pdbar);
  1162.     if (pdbar) 
  1163.     {
  1164.         IUnknown *punk;
  1165.         pdbar->GetClient(&punk);
  1166.         if (punk) 
  1167.         {
  1168.             punk->QueryInterface(IID_IBandSite, (LPVOID*)&pbs);
  1169.             ASSERT(IS_VALID_CODE_PTR(pbs, IBandSite));
  1170.             punk->Release();
  1171.         }
  1172.         pdbar->Release();
  1173.     }
  1174.     return pbs;
  1175. }
  1176. HRESULT FindBandInBandSite(IMenuPopup* pmpParent, IBandSite** ppbs, LPCITEMIDLIST pidl, REFIID riid, void** ppvOut)
  1177. {
  1178.     ASSERT(IS_VALID_CODE_PTR(pmpParent, IMenuPopup));
  1179.     ASSERT(pidl && IS_VALID_PIDL(pidl));
  1180.     ASSERT(ppvOut);
  1181.     HRESULT hres = E_FAIL;
  1182.     IBandSite* pbs;
  1183.     /* 
  1184.         the first part finds the deskband if pmpParent has it.  
  1185.         if it cannot find it, the second block creates a menu popup deskbar and bandsite.
  1186.     */
  1187.     *ppvOut = NULL;
  1188.     pbs = BandSiteFromBar(pmpParent);
  1189.     if (pbs) 
  1190.     {
  1191.         // find the deskband with pidl as it's content
  1192.         int i = 0;  
  1193.         DWORD dwID;
  1194.         IDeskBand *pdeskband;
  1195.         *ppvOut = NULL;
  1196.         while(*ppvOut && SUCCEEDED(pbs->EnumBands(i, &dwID)) &&
  1197.               SUCCEEDED(pbs->QueryBand(dwID, &pdeskband, NULL, NULL, 0))) 
  1198.         {
  1199.             CISFBand* pisfband;
  1200.             i++;
  1201.             if (SUCCEEDED(pdeskband->QueryInterface(CLSID_ISFBand, (LPVOID*)&pisfband))) 
  1202.             {
  1203.                 TraceMsg(TF_MENUBAND, "FindBandInBar : Looking for (0x%x) Got (0x%x)", 
  1204.                     pidl, pisfband->_pidl);
  1205.                 if (pisfband->_pidl && ILIsEqual(pidl, pisfband->_pidl)) 
  1206.                 {
  1207.                     TraceMsg(TF_MENUBAND, "FindBandInBar : Found this pidl (0x%x) in"
  1208.                         " the bandsite. Using it", pidl);
  1209.                     // found it!
  1210.                     // this will end the loop
  1211.                     hres = pdeskband->QueryInterface(riid, ppvOut);
  1212.                 }
  1213.                 pisfband->Release();
  1214.             }
  1215.             pdeskband->Release();
  1216.         }
  1217.         // If the caller wants to know what the band site is, then let them have it.
  1218.         if (ppbs && SUCCEEDED(hres))
  1219.         {
  1220.             *ppbs = pbs;
  1221.         }
  1222.         else
  1223.             pbs->Release();
  1224.     }
  1225.     return hres;
  1226. }
  1227. HRESULT ShowBandInBandSite(IUnknown* punkBS, IUnknown* punkDB)
  1228. {
  1229.     ASSERT(IS_VALID_CODE_PTR(punkBS, IUnknown));
  1230.     ASSERT(IS_VALID_CODE_PTR(punkDB, IUnknown));
  1231.     HRESULT hres = E_FAIL;
  1232.     if (punkDB) 
  1233.     {
  1234.         // make this guy the one and only one shown
  1235.         VARIANTARG vaIn = { 0 };
  1236.         vaIn.vt = VT_UNKNOWN;
  1237.         vaIn.punkVal = punkDB;
  1238.         punkDB->AddRef();
  1239.         hres = IUnknown_Exec(punkBS, &CGID_DeskBand, DBID_SHOWONLY, OLECMDEXECOPT_PROMPTUSER, &vaIn, NULL);
  1240.         VariantClearLazy(&vaIn);
  1241.     }
  1242.     return hres;
  1243. }
  1244. IMenuPopup* CreateMenuPopup(IMenuPopup* pmpParent, IShellFolder* psf, LPCITEMIDLIST pidl, 
  1245.                             BANDINFOSFB * pbi, BOOL bMenuBand)
  1246. {
  1247.     return CreateMenuPopup2(pmpParent, NULL, psf, pidl, pbi, bMenuBand);
  1248. }
  1249. IMenuPopup* CreateMenuPopup2(IMenuPopup* pmpParent, IMenuBand* pmb, IShellFolder* psf, LPCITEMIDLIST pidl, 
  1250.                             BANDINFOSFB * pbi, BOOL bMenuBand)
  1251. {
  1252.     
  1253.     ASSERT(pmb == NULL || IS_VALID_CODE_PTR(pmb, IMenuBand));
  1254.     ASSERT(psf == NULL || IS_VALID_CODE_PTR(psf, IShellFolder));
  1255.     ASSERT(pmpParent == NULL || IS_VALID_CODE_PTR(pmpParent, IMenuPopup));
  1256.     ASSERT(pidl && IS_VALID_PIDL(pidl));
  1257.     ASSERT(pbi == NULL || IS_VALID_READ_PTR(pbi, BANDINFOSFB));
  1258.     IMenuPopup* pmp = NULL;
  1259.     IDeskBand *pdb = NULL;
  1260.     IBandSite *pbs = NULL;
  1261.     HRESULT hres = E_FAIL;
  1262.     // Assume that if they pass a band, that it's not in the band site.
  1263.     if (pmpParent && !pmb) 
  1264.     {
  1265.         FindBandInBandSite(pmpParent, &pbs, pidl, IID_IDeskBand, (void**)&pdb);
  1266.     }
  1267.     // Part 2: create the deskband itself if it's not found
  1268.     
  1269.     if (!pdb) 
  1270.     {
  1271.         TraceMsg(TF_MENUBAND, "CreateMenuPopup2 : Did not find a this (0x%x) band.", pidl);
  1272.         if (bMenuBand)
  1273.         {
  1274.             if (pmb)
  1275.             {
  1276.                 pmb->QueryInterface(IID_IDeskBand, (void**)&pdb);
  1277.                 TraceMsg(TF_MENUBAND, "CreateMenuPopup2 : I was given a band.");
  1278.             }
  1279.             else
  1280.                 pdb = CMenuBand_Create(psf, pidl, FALSE);
  1281.         }
  1282.         else
  1283.             pdb = CISFBand_CreateEx(psf, pidl);
  1284.         if (pdb) 
  1285.         {
  1286.             if (pbi) 
  1287.             {
  1288.                 IShellFolderBand *pisfBand;
  1289.                 if (SUCCEEDED(pdb->QueryInterface(IID_IShellFolderBand, (LPVOID*)&pisfBand))) 
  1290.                 {
  1291.                     pisfBand->SetBandInfoSFB(pbi);
  1292.                     pisfBand->Release();
  1293.                 }
  1294.             }
  1295.             if (!pmpParent) 
  1296.             {
  1297.                 const CLSID * pclsid;
  1298.                 if (bMenuBand)
  1299.                     pclsid = &CLSID_MenuBandSite;
  1300.                 else
  1301.                     pclsid = &CLSID_RebarBandSite;
  1302.                 CoCreateInstance(*pclsid, NULL, CLSCTX_INPROC_SERVER, IID_IBandSite, (LPVOID*)&pbs);
  1303.                 if (pbs) 
  1304.                 {
  1305.                     if (bMenuBand)
  1306.                     {
  1307.                         BANDSITEINFO bsinfo;
  1308.                         // Don't show the gripper for vertical menubands
  1309.                         bsinfo.dwMask = BSIM_STYLE;
  1310.                         bsinfo.dwStyle = BSIS_NOGRIPPER | BSIS_NODROPTARGET;
  1311.                         pbs->SetBandSiteInfo(&bsinfo);
  1312.                     }
  1313.                     CMenuDeskBar *pcmdb = new CMenuDeskBar();
  1314.                     if (pcmdb)
  1315.                     {
  1316.                         if (SUCCEEDED(pcmdb->SetClient(pbs))) 
  1317.                             pcmdb->QueryInterface(IID_IMenuPopup, (LPVOID *)&pmp);
  1318.                         pcmdb->Release();
  1319.                     }
  1320.                 }
  1321.             }
  1322.             else if (!pbs)
  1323.             {
  1324.                 pbs = BandSiteFromBar(pmpParent);
  1325.             }
  1326.                  
  1327.             if (pbs) 
  1328.             {
  1329.                 pbs->AddBand(pdb);
  1330.             }
  1331.         }
  1332.     }
  1333.     
  1334.     ShowBandInBandSite(pbs, pdb);
  1335.     ATOMICRELEASE(pdb);
  1336.     ATOMICRELEASE(pbs);
  1337.     if (!pmp)
  1338.         IUnknown_Set((IUnknown**) &pmp, pmpParent);
  1339.     
  1340.     return pmp;
  1341. }