bandsite.cpp
上传用户:xhy777
上传日期:2007-02-14
资源大小:24088k
文件大小:85k
源码类别:

系统编程

开发平台:

Visual C++

  1. #include "priv.h"
  2. #include "sccls.h"
  3. #include <shguidp.h>
  4. #define WANT_CBANDSITE_CLASS
  5. #include "bandsite.h"
  6. #include "bandobj.h"
  7. #include "caggunk.h"
  8. #include "droptgt.h"
  9. #include "inpobj.h"
  10. #include "resource.h"
  11. #include "bands.h"
  12. #include "tbmenu.h"
  13. #include "mluisupp.h"
  14. #define TF_BANDDD   0x00400000
  15. #define DM_INIT     0               //
  16. #define DM_PERSIST  0               // trace IPS::Load, ::Save, etc.
  17. #define DM_MENU     0               // menu code
  18. #define DM_DRAG     0               // drag&drop
  19. #define DM_FOCUS    0               // focus
  20. #define DM_PERF     0               // perf tune
  21. #define DM_PERF2    0               // perf tune (verbose)
  22. #define IDM_DRAGDROP    1
  23. #define ISMOVEDDISABLED(dwBandID)   ((S_OK == _IsRestricted(dwBandID, RA_MOVE, BAND_ADMIN_NOMOVE)) ? TRUE : FALSE)
  24. #define ISDDCLOSEDISABLED(dwBandID) ((S_OK == _IsRestricted(dwBandID, RA_DRAG, BAND_ADMIN_NODDCLOSE)) ? TRUE : FALSE)
  25. // drag state (BUGBUG from dockbar.h)
  26. #define DRAG_NIL        0       // nil
  27. #define DRAG_MOVE       1       // moving
  28. #define DRAG_SIZE       2       // sizing
  29. typedef struct {
  30.     UINT cx;
  31.     UINT fStyle;
  32.     UINT cxMinChild;
  33.     UINT cyMinChild;
  34.     UINT cyIntegral;
  35.     UINT cyMaxChild;
  36.     UINT cyChild;
  37. } PERSISTBANDINFO_V3;
  38. typedef struct {
  39.     UINT cx;
  40.     UINT fStyle;
  41.     UINT cxMinChild;  // UNUSED. reclaim!
  42.     UINT cyMinChild;
  43.     UINT cyIntegral;   // UNUSED
  44.     UINT cyMaxChild;    // UNUSED.
  45.     UINT cyChild;
  46.     DWORD dwAdminSettings;
  47.     BITBOOL fNoTitle:1;
  48. } PERSISTBANDINFO;
  49. #define RBBIM_XPERSIST  (RBBIM_SIZE | RBBIM_CHILDSIZE | RBBIM_STYLE)
  50. #ifdef DEBUG
  51. extern unsigned long DbStreamTell(IStream *pstm);
  52. #else
  53. #define DbStreamTell(pstm)      ((ULONG) 0)
  54. #endif
  55. UINT _FixMenuIndex(HMENU hmenu, UINT indexMenu)
  56. {
  57.     UINT i;
  58.     i = GetMenuItemCount(hmenu);
  59.     if (indexMenu > i)
  60.         indexMenu = i;
  61.     return indexMenu;
  62. }
  63. #define SUPERCLASS CAggregatedUnknown
  64. HRESULT CBandSite::v_InternalQueryInterface(REFIID riid, void **ppvObj)
  65. {
  66.     static const QITAB qit[] = {
  67.         // perf: last tuned 980728
  68.         QITABENT(CBandSite, IBandSite),             // IID_IBandSite
  69.         QITABENT(CBandSite, IInputObject),          // IID_IInputObject
  70.         QITABENT(CBandSite, IServiceProvider),      // IID_IServiceProvider
  71.         QITABENT(CBandSite, IOleCommandTarget),     // IID_IOleCommandTarget
  72.         QITABENTMULTI(CBandSite, IOleWindow, IDeskBarClient),   // IID_IOleWindow
  73.         QITABENT(CBandSite, IWinEventHandler),      // IID_IWinEventHandler
  74.         QITABENT(CBandSite, IInputObjectSite),      // IID_IInputObjectSite
  75.         QITABENT(CBandSite, IDeskBarClient),        // IID_IDeskBarClient
  76.         QITABENTMULTI(CBandSite, IPersist, IPersistStream),     // rare IID_IPersist
  77.         QITABENT(CBandSite, IPersistStream),        // rare IID_IPersistStream
  78.         QITABENT(CBandSite, IBandSiteHelper),       // rare IBandSiteHelper
  79.         QITABENT(CBandSite, IDropTarget),           // rare IID_IDropTarget
  80.         { 0 },
  81.     };
  82.     
  83.     return QISearch(this, qit, riid, ppvObj);
  84. }
  85. /////  impl of IServiceProvider
  86. HRESULT CBandSite::QueryService(REFGUID guidService, REFIID riid, void **ppvObj)
  87. {
  88.     HRESULT hres = E_FAIL;
  89.     *ppvObj = NULL; // assume error
  90.     if (IsEqualIID(guidService, SID_IBandProxy)) 
  91.     {
  92.         hres =  QueryService_SID_IBandProxy(_punkSite, riid, &_pbp, ppvObj);
  93.         if(!_pbp)
  94.         {
  95.             // We need to create it ourselves since our parent couldn't help
  96.             ASSERT(FALSE == _fCreatedBandProxy);
  97.             hres = CreateIBandProxyAndSetSite(_punkSite, riid, &_pbp, ppvObj);
  98.             if(_pbp)
  99.             {
  100.                 ASSERT(S_OK == hres);
  101.                 _fCreatedBandProxy = TRUE;   
  102.             }
  103.         }
  104.     } 
  105.     else if (IsEqualIID(guidService, SID_ITopViewHost)) 
  106.     {
  107.         return QueryInterface(riid, ppvObj);
  108.     } 
  109.     else if (IsEqualIID(guidService, IID_IBandSite))
  110.     {
  111.         // It is common for bands to save/load pidls for persistence.
  112.         // CShellLink is a robust way to do this, so let's share one
  113.         // among all the bands.
  114.         //
  115.         // NOTE: This is shared between bands, so if you request it
  116.         // you must complete your use of it within the scope of your
  117.         // function call!
  118.         //
  119.         if (IsEqualIID(riid, IID_IShellLinkA))
  120.         {
  121.             if (NULL == _plink)
  122.                 CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkA, (void **)&_plink);
  123.             if (_plink)
  124.             {
  125.                 *ppvObj = _plink;
  126.                 _plink->AddRef();
  127.                 hres = S_OK;
  128.             }
  129.         }
  130.     } 
  131.     else if (_punkSite) 
  132.     {
  133.         hres = IUnknown_QueryService(_punkSite, guidService, riid, ppvObj);
  134.     }
  135.     return hres;
  136. }
  137. HRESULT CBandSite::GetWindow(HWND * lphwnd)
  138. {
  139.     *lphwnd = _hwnd;
  140.     return *lphwnd ?  S_OK : E_FAIL;
  141. }
  142. CBandSite::CBandSite(IUnknown* punkAgg) : SUPERCLASS(punkAgg)
  143. {
  144.     DWORD dwData = 0;
  145.     DWORD dwSize = SIZEOF(dwData);
  146.     // We assume this object was zero inited.
  147.     ASSERT(!_pbp);
  148.     ASSERT(FALSE == _fCreatedBandProxy);
  149.     SHRegGetUSValue(SZ_REGKEY_GLOBALADMINSETTINGS, SZ_REGVALUE_GLOBALADMINSETTINGS,
  150.         NULL, (LPVOID) &dwData, &dwSize, FALSE, NULL, 0);
  151.     if (IsFlagSet(dwData, BAND_ADMIN_ADMINMACHINE))
  152.         _fIEAKInstalled = TRUE;
  153.     else
  154.         _fIEAKInstalled = FALSE;
  155.     _dwStyle = BSIS_AUTOGRIPPER;
  156.     //
  157.     //  We check whether or not this succeeded in CBandSite::_Initialize
  158.     //
  159.     _QueryOuterInterface(IID_IBandSite, (void **)&_pbsOuter);
  160.     DllAddRef();
  161. }
  162. void CBandSite::_ReleaseBandItemData(LPBANDITEMDATA pbid, int iIndex)
  163. {
  164.     if (pbid->pdb) 
  165.     {
  166.         REBARBANDINFO rbbi;
  167.         pbid->pdb->CloseDW(0);
  168.         if (-1 != iIndex)
  169.         {
  170.             // The band's hwnd is typically destroyed in CloseDW
  171.             rbbi.cbSize = sizeof(rbbi);
  172.             rbbi.fMask = RBBIM_CHILD | RBBIM_LPARAM;
  173.             rbbi.hwndChild = NULL;
  174.             rbbi.lParam = NULL;
  175.             EVAL( SendMessage(_hwnd, RB_SETBANDINFO, iIndex, (LPARAM) &rbbi) );
  176.         }
  177.         // this is called from remove and the destroy.
  178.         IUnknown_SetSite(pbid->pdb, NULL);
  179.         ATOMICRELEASE(pbid->pdb);
  180.     }
  181.     if (pbid->pweh == _pwehCache)
  182.         ATOMICRELEASE(_pwehCache);
  183.     ATOMICRELEASE(pbid->pweh);
  184.     LocalFree(pbid);
  185. }
  186. CBandSite::~CBandSite()
  187. {
  188.     ATOMICRELEASE(_pdtobj);
  189.     if(_pbp && _fCreatedBandProxy)
  190.         _pbp->SetSite(NULL);
  191.         
  192.     ATOMICRELEASE(_pbp);
  193.     ATOMICRELEASE(_pwehCache);
  194.     _CacheActiveBand(NULL);
  195.     _Close();
  196.     SetDeskBarSite(NULL);
  197.     if (_plink)
  198.         _plink->Release();
  199.     RELEASEOUTERINTERFACE(_pbsOuter);
  200.     DllRelease();
  201. }
  202. //***   _IsBandDeleteable --
  203. // ENTRY/EXIT
  204. //  idBand  band ID
  205. //  ret     TRUE if deletable, o.w. FALSE (also FALSE on bogus band)
  206. BOOL CBandSite::_IsBandDeleteable(DWORD dwBandID)
  207. {
  208.     DWORD dwState;
  209.     if (FAILED(_pbsOuter->QueryBand(dwBandID, NULL, &dwState, NULL, 0))
  210.       || (dwState & BSSF_UNDELETEABLE)) {
  211.         return FALSE;
  212.     }
  213.     ASSERT(dwBandID != (DWORD)-1);  // make sure QueryBand catches this
  214.     return TRUE;
  215. }
  216. DWORD CBandSite::_GetAdminSettings(DWORD dwBandID)
  217. {
  218.     LPBANDITEMDATA pbid = _GetBandItem(_BandIDToIndex(dwBandID)); 
  219.     if (EVAL(pbid))
  220.         return pbid->dwAdminSettings;
  221.     return BAND_ADMIN_NORMAL;
  222. }
  223. void CBandSite::_SetAdminSettings(DWORD dwBandID, DWORD dwNewAdminSettings)
  224. {
  225.     LPBANDITEMDATA pbid = _GetBandItem(_BandIDToIndex(dwBandID)); 
  226.     if (EVAL(pbid))
  227.         pbid->dwAdminSettings = dwNewAdminSettings;
  228. }
  229. //***   CBandSite::IBandSite::* {
  230. /*----------------------------------------------------------
  231. Purpose: IBandSite::EnumBands method
  232. */
  233. HRESULT CBandSite::EnumBands(UINT uBand, DWORD* pdwBandID)
  234. {
  235.     ASSERT((NULL == pdwBandID && (UINT)-1 == uBand) || 
  236.            IS_VALID_WRITE_PTR(pdwBandID, DWORD));
  237.     if (uBand == (UINT)-1)
  238.         return _GetBandItemCount();      // query count
  239.     LPBANDITEMDATA pbid = _GetBandItem(uBand);
  240.     if (pbid)
  241.     {
  242.         *pdwBandID = pbid->dwBandID;
  243.         return S_OK;
  244.     }
  245.     return E_FAIL;
  246. }
  247. /*----------------------------------------------------------
  248. Purpose: IBandSite::QueryBand method
  249. */
  250. HRESULT CBandSite::QueryBand(DWORD dwBandID, IDeskBand** ppstb, DWORD* pdwState, LPWSTR pszName, int cchName)
  251. {
  252.     ASSERT(NULL == ppstb || IS_VALID_WRITE_PTR(ppstb, IDeskBand));
  253.     ASSERT(NULL == pdwState || IS_VALID_WRITE_PTR(pdwState, DWORD));
  254.     ASSERT(NULL == pszName || IS_VALID_WRITE_BUFFER(pszName, WCHAR, cchName));
  255.     if (ppstb)
  256.         *ppstb = NULL;
  257.     LPBANDITEMDATA pbid = _GetBandItemDataStructByID(dwBandID);
  258.     if (!pbid)
  259.         return E_FAIL;
  260.     if (pszName) {
  261.         StrCpyNW(pszName, pbid->szTitle, cchName);
  262.     }
  263.     if (ppstb) {
  264.         *ppstb = pbid->pdb;
  265.         pbid->pdb->AddRef();
  266.     }
  267.     
  268.     if (pdwState) {
  269.         *pdwState = 0;
  270.         if (pbid->fShow)
  271.             *pdwState = BSSF_VISIBLE;
  272.         if (pbid->fNoTitle)
  273.             *pdwState |= BSSF_NOTITLE;
  274.         if (pbid->dwModeFlags & DBIMF_UNDELETEABLE)
  275.             *pdwState |= BSSF_UNDELETEABLE;
  276.     }
  277.     return S_OK;
  278. }
  279. /*----------------------------------------------------------
  280. Purpose: IBandSite::SetBandState
  281. * NOTES
  282. *   failure handling is inconsistent (1 band vs. all bands case)
  283. */
  284. HRESULT CBandSite::SetBandState(DWORD dwBandID, DWORD dwMask, DWORD dwState)
  285. {
  286.     LPBANDITEMDATA pbid;
  287.     HRESULT hr;
  288.     if (dwBandID == (DWORD) -1)
  289.     {
  290.         BOOL fChange = FALSE;
  291.         for (int i = _GetBandItemCount() - 1; i >= 0; i--)
  292.         {
  293.             pbid = _GetBandItem(i);
  294.             if (pbid)
  295.             {
  296.                 hr = _SetBandStateHelper(pbid->dwBandID, dwMask, dwState);
  297.                 ASSERT(SUCCEEDED(hr));
  298.                 fChange |= (hr != S_OK);
  299.             }
  300.             else
  301.             {
  302.                 return E_FAIL;
  303.             }
  304.         }
  305.         if (fChange)
  306.             _UpdateAllBands(FALSE, FALSE);
  307.         return S_OK;
  308.     }
  309.     else
  310.     {
  311.         hr = _SetBandStateHelper(dwBandID, dwMask, dwState);
  312.         if (SUCCEEDED(hr) && hr != S_OK)
  313.         {
  314.             _UpdateBand(dwBandID);
  315.             return S_OK;
  316.         }
  317.     }
  318.     return E_FAIL;
  319. }
  320. //***
  321. // ENTRY/EXIT
  322. //  ret     S_OK|changed on success, o.w. E_*.
  323. // NOTES
  324. //  only a helper for SetBandState, don't call directly
  325. HRESULT CBandSite::_SetBandStateHelper(DWORD dwBandID, DWORD dwMask, DWORD dwState)
  326. {
  327.     LPBANDITEMDATA pbid;
  328.     pbid = _GetBandItem(_BandIDToIndex(dwBandID));
  329.     if (pbid) {
  330.         DWORD dwOldState;
  331.         if (FAILED(QueryBand(dwBandID, NULL, &dwOldState, NULL, 0))) {
  332.             ASSERT(0);  // 'impossible'
  333.             dwOldState = (DWORD)-1;
  334.         }
  335.         if (dwMask & BSSF_VISIBLE)
  336.             _ShowBand(pbid, dwState & BSSF_VISIBLE);
  337.         if (dwMask & BSSF_NOTITLE)
  338.             pbid->fNoTitle = BOOLIFY(dwState & BSSF_NOTITLE);
  339.             
  340.         // BUGBUG (kkahl): BSSF_UNDELETABLE cannot currently be modified with
  341.         // this interface.
  342.         return ResultFromShort((dwOldState ^ dwState) & dwMask);
  343.     }
  344.     return E_FAIL;
  345. }
  346. //***   _CheckNotifyOnAddRemove -- handle notifies for add/remove/empty
  347. // DESCRIPTION
  348. //  add/remove always sends a BSID_BANDADDED/BSID_BANDREMOVED.
  349. //  remove of last always sends a DBCID_EMPTY.
  350. //  in floating mode, a transition to/from 1 band does a refresh.
  351. //
  352. void CBandSite::_CheckNotifyOnAddRemove(DWORD dwBandID, int iCode)
  353. {
  354.     int cBands;
  355.     if (!_pct)
  356.         return;
  357.     if (iCode == CNOAR_CLOSEBAR) {
  358.         // Shut down the whole thing
  359.         cBands = 0;
  360.     } else {
  361.         VARIANTARG var;
  362.         int nCmdID;
  363.         cBands = _GetBandItemCount();   // post-op # (since op happened in caller)
  364.         VariantInit(&var);
  365.         var.vt = VT_UI4;
  366.         var.ulVal = dwBandID;
  367.         BOOL fOne = FALSE;
  368.         switch (iCode) {
  369.         case CNOAR_ADDBAND:
  370.             fOne = (cBands == 2);   // 1->2
  371.             nCmdID = BSID_BANDADDED;
  372.             break;
  373.         case CNOAR_REMOVEBAND:
  374.             fOne = (cBands == 1);   // 2->1
  375.             nCmdID = BSID_BANDREMOVED;
  376.             break;
  377.         default:
  378.             ASSERT(0);
  379.             return;
  380.         }
  381.         if ((fOne && (_dwMode & DBIF_VIEWMODE_FLOATING))) {
  382.             // n.b. fBSOnly *must* be TRUE for perf
  383.             _UpdateAllBands(TRUE, TRUE);  // force refresh of optional gripper/title
  384.         }
  385.         _pct->Exec(&CGID_BandSite, nCmdID, 0, &var, NULL);
  386.     }
  387.     if (cBands == 0) {
  388.         ASSERT(iCode != CNOAR_ADDBAND);     // sanity check
  389.         _pct->Exec(&CGID_DeskBarClient, DBCID_EMPTY, 0, NULL, NULL);
  390.     }
  391.     return;
  392. }
  393. /*----------------------------------------------------------
  394. Purpose: IBandSite::RemoveBand method
  395. */
  396. HRESULT CBandSite::RemoveBand(DWORD dwBandID)
  397. {
  398.     int iIndex = _BandIDToIndex(dwBandID);
  399.     LPBANDITEMDATA pbid = _GetBandItem(iIndex);
  400.     if (pbid)
  401.     {
  402.         // Release the banditem data first, while it can still
  403.         // receive cleanup notifications from its control.  *Then*
  404.         // delete the band item.
  405.         _ReleaseBandItemData(pbid, iIndex);
  406.         _DeleteBandItem(iIndex);    // unhook from host (rebar)
  407.         _CheckNotifyOnAddRemove(dwBandID, CNOAR_REMOVEBAND);
  408.         return S_OK;
  409.     }
  410.     return E_FAIL;
  411. }
  412. void CBandSite::_OnCloseBand(DWORD dwBandID)
  413. {
  414.     if (dwBandID == -1) {
  415.         // Close everything
  416.         _CheckNotifyOnAddRemove(dwBandID, CNOAR_CLOSEBAR);
  417.     } else {
  418.         // Close just this band
  419.         LPBANDITEMDATA pbid = _GetBandItemDataStructByID(dwBandID);
  420.         USES_CONVERSION;
  421.         if (EVAL(pbid) && ConfirmRemoveBand(_hwnd, IDS_CONFIRMCLOSEBAND,W2T(pbid->szTitle)))
  422.             RemoveBand(dwBandID);
  423.     }
  424. }
  425. void CBandSite::_MaximizeBand(DWORD dwBandID)
  426. {
  427.     SendMessage(_hwnd, RB_MAXIMIZEBAND, _BandIDToIndex(dwBandID), TRUE);
  428. }
  429. //
  430. // private insert a band into the container control by ID
  431. // returns the band ID in ShortFromResult(hres)
  432. //
  433. HRESULT CBandSite::_AddBandByID(IUnknown *punk, DWORD dwID)
  434. {
  435.     IDeskBand *pdb;
  436.     HRESULT hres = punk->QueryInterface(IID_IDeskBand, (void **)&pdb);
  437.     if (SUCCEEDED(hres)) 
  438.     {
  439.         BANDITEMDATA *pbid = (BANDITEMDATA *)LocalAlloc(LPTR, sizeof(BANDITEMDATA));
  440.         if (pbid)
  441.         {
  442.             pbid->dwBandID = dwID;
  443.             pbid->pdb = pdb;      // ref held by QI above
  444.             pbid->fShow = TRUE;     // initially visible
  445.             pbid->pdb->QueryInterface(IID_IWinEventHandler, (void **)&pbid->pweh);
  446.             IUnknown_SetSite(pbid->pdb, SAFECAST(this, IBandSite*));
  447.             pbid->pdb->GetWindow(&pbid->hwnd);
  448.             
  449.             if (_AddBandItem(pbid))
  450.             {
  451.                 if (_dwShowState == DBC_SHOW) 
  452.                 {
  453.                     ASSERT(pbid->fShow);
  454.                     pbid->pdb->ShowDW(TRUE);
  455.                     _MaximizeBand(pbid->dwBandID);
  456.                 }
  457.             
  458.                 _CheckNotifyOnAddRemove(pbid->dwBandID, CNOAR_ADDBAND);
  459.                 hres = ResultFromShort(pbid->dwBandID); // success
  460.             }
  461.             else
  462.             {
  463.                 _ReleaseBandItemData(pbid, -1);
  464.             }
  465.             //
  466.             // Now that we've added the band, clear the _SendToToolband cache.
  467.             //
  468.             // We need to do this because we might have gotten a message for
  469.             // the band before it was inserted, in which case we'll have cached
  470.             // a NULL handler for the band's hwnd (preventing the band from
  471.             // getting any messages thereafter).
  472.             //
  473.             ATOMICRELEASE(_pwehCache);
  474.             _hwndCache = NULL;
  475.         } 
  476.         else
  477.         {
  478.             hres = E_OUTOFMEMORY;
  479.             pdb->Release();    // don't hold on to this
  480.         }
  481.     }
  482.     return hres;
  483. }
  484. /*----------------------------------------------------------
  485. Purpose: IBandSite::AddBand method.
  486.          Insert a band into the container control.
  487. Returns: the band ID in ShortFromResult(hres)
  488. */
  489. HRESULT CBandSite::AddBand(IUnknown *punk)
  490. {
  491.     HRESULT hres = _AddBandByID(punk, _dwBandIDNext);
  492.     if (SUCCEEDED(hres)) {
  493.         ASSERT(ShortFromResult(hres) == (int)_dwBandIDNext);
  494.         _dwBandIDNext++;
  495.     }
  496.     return hres;
  497. }
  498. void CBandSite::_UpdateBand(DWORD dwBandID)
  499. {
  500.     LPBANDITEMDATA pbid = _GetBandItem(_BandIDToIndex(dwBandID)); 
  501.     if (pbid) {
  502.         _UpdateBandInfo(pbid, FALSE);
  503.         _OnRBAutoSize(NULL);
  504.     }
  505. }
  506. void CBandSite::_UpdateAllBands(BOOL fBSOnly, BOOL fNoAutoSize)
  507. {
  508.     BOOL_PTR fRedraw = SendMessage(_hwnd, WM_SETREDRAW, FALSE, 0);
  509.     for (int i = _GetBandItemCount() - 1; i >= 0; i--)
  510.     {
  511.         LPBANDITEMDATA pbid = _GetBandItem(i);
  512.         if (pbid)
  513.             _UpdateBandInfo(pbid, fBSOnly);
  514.     }    
  515.     SendMessage(_hwnd, WM_SETREDRAW, fRedraw, 0);
  516.     if (!fNoAutoSize) {
  517.         SendMessage(_hwnd, RB_SIZETORECT, 0, 0);
  518.         _OnRBAutoSize(NULL);
  519.     }
  520. }
  521. // *** IOleCommandTarget ***
  522. HRESULT CBandSite::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
  523. {
  524.     HRESULT hres = OLECMDERR_E_UNKNOWNGROUP;
  525.     if (pguidCmdGroup)
  526.     {
  527.         if (IsEqualIID(*pguidCmdGroup, IID_IDockingWindow))
  528.         {
  529.             for (ULONG i=0 ; i<cCmds ; i++)
  530.             {
  531.                 switch (rgCmds[i].cmdID)
  532.                 {
  533.                 case DBID_BANDINFOCHANGED:
  534.                 case DBID_PUSHCHEVRON:
  535.                     rgCmds[i].cmdf = OLECMDF_ENABLED;
  536.                     break;
  537.     
  538.                 default:
  539.                     rgCmds[i].cmdf = 0;
  540.                     break;
  541.                 }
  542.             }
  543.             hres = S_OK;
  544.             goto Lret;
  545.         }
  546.         else if (IsEqualIID(*pguidCmdGroup, CGID_Explorer))
  547.         {
  548.             hres = IUnknown_QueryStatus(_ptbActive, pguidCmdGroup, cCmds, rgCmds, pcmdtext);
  549.             goto Lret;
  550.         }
  551.     }
  552.     // if we got here, we didn't handle it
  553.     // forward it down
  554.     hres = MayQSForward(_ptbActive, OCTD_DOWN, pguidCmdGroup, cCmds, rgCmds, pcmdtext);
  555. Lret:
  556.     return hres;
  557. }
  558. int _QueryServiceCallback(LPBANDITEMDATA pbid, void *pv)
  559. {
  560.     QSDATA* pqsd = (QSDATA*)pv;
  561.     if (pbid->fShow)
  562.         pqsd->hres = IUnknown_QueryService(pbid->pdb, *(pqsd->pguidService), *(pqsd->piid), pqsd->ppvObj);
  563.     // stop if we found the service
  564.     return SUCCEEDED(pqsd->hres) ? FALSE : TRUE;
  565. }
  566. typedef struct {
  567.     HRESULT hres;
  568.     const GUID *pguidCmdGroup;
  569.     DWORD nCmdID;
  570.     DWORD nCmdexecopt;
  571.     VARIANTARG *pvarargIn;
  572.     VARIANTARG *pvarargOut;
  573. } EXECDATA;
  574. int _ExecCallback(LPBANDITEMDATA pbid, void *pv)
  575. {
  576.     EXECDATA* ped = (EXECDATA*)pv;
  577.     
  578.     ped->hres = IUnknown_Exec(pbid->pdb, ped->pguidCmdGroup, ped->nCmdID, ped->nCmdexecopt,
  579.         ped->pvarargIn, ped->pvarargOut);
  580.     return 1;
  581. }
  582. HRESULT CBandSite::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
  583. {
  584.     HRESULT hres = OLECMDERR_E_UNKNOWNGROUP;
  585.     HRESULT hresTmp;
  586.     if (pguidCmdGroup == NULL) {
  587.         /*NOTHING*/
  588.         ;
  589.     }
  590.     else if (IsEqualIID(*pguidCmdGroup, CGID_DeskBand)) {
  591.         switch (nCmdID) {
  592.         case DBID_BANDINFOCHANGED:
  593.             if (!pvarargIn)
  594.                 _UpdateAllBands(FALSE, FALSE);
  595.             else if (pvarargIn->vt == VT_I4) 
  596.                 _UpdateBand(pvarargIn->lVal);
  597.             hres = S_OK;
  598.             
  599.             // forward this up.
  600.             if (_pct) {
  601.                 _pct->Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
  602.             }
  603.             goto Lret;
  604.         case DBID_PUSHCHEVRON:
  605.             if (pvarargIn && pvarargIn->vt == VT_I4) {
  606.                 int iIndex = _BandIDToIndex(nCmdexecopt);
  607.                 SendMessage(_hwnd, RB_PUSHCHEVRON, iIndex, pvarargIn->lVal);
  608.                 hres = S_OK;
  609.             }
  610.             goto Lret;
  611.         case DBID_MAXIMIZEBAND:
  612.             if (pvarargIn && pvarargIn->vt == VT_UI4)
  613.                 _MaximizeBand(pvarargIn->ulVal);
  614.             hres = S_OK;
  615.             goto Lret;
  616. #if 1 // { BUGBUG temporary until add cbs::Select() mfunc
  617.         case DBID_SHOWONLY:
  618.             {
  619.                 int iCount = _GetBandItemCount();
  620.                 
  621.                 // pvaIn->punkVal:
  622.                 //  punk hide everyone except me
  623.                 //  0    hide everyone
  624.                 //  1    show everyone
  625.                 // BUGBUG we should use pvaIn->lVal not punkVal since we're
  626.                 // allowing 0 & 1 !!! (and not doing addref/release)
  627.                 ASSERT(pvarargIn && pvarargIn->vt == VT_UNKNOWN);
  628.                 if (pvarargIn->punkVal == NULL || pvarargIn->punkVal == (IUnknown*)1)
  629.                     TraceMsg(TF_BANDDD, "cbs.e: (id=DBID_SHOWONLY, punk=%x)", pvarargIn->punkVal);
  630.                 // show myself, hide everyone else
  631.                 TraceMsg(TF_BANDDD, "cbs.Exec(DBID_SHOWONLY): n=%d", _GetBandItemCount());
  632.                 // wait to show this band until we've hidden the others
  633.                 LPBANDITEMDATA pbidShow = NULL;
  634.                 // BUGBUG: this (IUnknown*)1 crap is bogus!
  635.                 BOOL bShowAll = (pvarargIn->punkVal == (IUnknown*)1);
  636.                 for (int i = iCount - 1; i >= 0; i--) {
  637.                     LPBANDITEMDATA pbid = _GetBandItem(i);
  638.                     if (pbid) {
  639.                         BOOL fShow;
  640.                         fShow = bShowAll || SHIsSameObject(pbid->pdb, pvarargIn->punkVal);
  641.                         if (!fShow || bShowAll)
  642.                             _ShowBand(pbid, fShow);
  643.                         else
  644.                             pbidShow = pbid;
  645.                     }
  646.                 }
  647.                 if (pbidShow) {
  648.                     _ShowBand(pbidShow, TRUE);
  649.                     // nash:37290 set focus to band on open
  650.                     if (_dwShowState == DBC_SHOW)
  651.                         UnkUIActivateIO(pbidShow->pdb, TRUE, NULL);
  652.                     else
  653.                         ASSERT(0);
  654.                 }
  655.             }
  656.             break;
  657. #endif // }
  658.         }
  659.     }
  660.     else if (IsEqualIID(*pguidCmdGroup, CGID_Explorer)) {
  661.         return IUnknown_Exec(_ptbActive, pguidCmdGroup, nCmdID, nCmdexecopt,
  662.                 pvarargIn, pvarargOut);
  663.     }
  664.     else if (IsEqualIID(*pguidCmdGroup, CGID_DeskBarClient)) {
  665.         switch (nCmdID) {
  666.         case DBCID_ONDRAG:
  667.             if (EVAL(pvarargIn->vt == VT_I4)) {
  668.                 ASSERT(pvarargIn->lVal == 0 || pvarargIn->lVal == DRAG_MOVE);
  669.                 TraceMsg(DM_TRACE, "cbs.e: DBCID_ONDRAG i=%d", pvarargIn->lVal);
  670.                 _fDragging = pvarargIn->lVal;
  671.             }
  672.             break;
  673.         }
  674.     }
  675.     // if we got here, we didn't handle it
  676.     // see if we should forward it down
  677.     hresTmp = IsExecForward(pguidCmdGroup, nCmdID);
  678.     if (SUCCEEDED(hresTmp) && HRESULT_CODE(hresTmp) > 0) {
  679.         // down (singleton or broadcast)
  680.         if (HRESULT_CODE(hresTmp) == OCTD_DOWN) {
  681.             // down (singleton)
  682.             hres = IUnknown_Exec(_ptbActive, pguidCmdGroup, nCmdID, nCmdexecopt,
  683.                 pvarargIn, pvarargOut);
  684.         }
  685.         else {
  686.             // down (broadcast)
  687.             // n.b. hres is a bit weird: 'last one wins'
  688.             // BUGBUG should we just return S_OK?
  689.             ASSERT(HRESULT_CODE(hresTmp) == OCTD_DOWNBROADCAST);
  690.             EXECDATA ctd = { hres, pguidCmdGroup, nCmdID, nCmdexecopt,
  691.                 pvarargIn, pvarargOut };
  692.             _BandItemEnumCallback(1, _ExecCallback, &ctd);
  693.             hres = ctd.hres;
  694.         }
  695.     }
  696. Lret:
  697.     return hres;
  698. }
  699. /***    _ShowBand -- show/hide band (cached state, band, and rebar band)
  700.  */
  701. void CBandSite::_ShowBand(LPBANDITEMDATA pbid, BOOL fShow)
  702. {
  703.     int i;
  704.     pbid->fShow = BOOLIFY(fShow);
  705.     pbid->pdb->ShowDW(fShow && (_dwShowState == DBC_SHOW));
  706.     i = _BandIDToIndex(pbid->dwBandID);
  707.     SendMessage(_hwnd, RB_SHOWBAND, i, fShow);
  708.     // get me a window to draw D&D curosors on. . .
  709.     SHGetTopBrowserWindow(SAFECAST(this, IBandSite*), &_hwndDD);
  710. }
  711. /*----------------------------------------------------------
  712. Purpose: IBandSite::GetBandSiteInfo
  713. */
  714. HRESULT CBandSite::GetBandSiteInfo(BANDSITEINFO * pbsinfo)
  715. {
  716.     ASSERT(IS_VALID_WRITE_PTR(pbsinfo, BANDSITEINFO));
  717.     if (pbsinfo->dwMask & BSIM_STATE)
  718.         pbsinfo->dwState = _dwMode;
  719.     if (pbsinfo->dwMask & BSIM_STYLE)
  720.         pbsinfo->dwStyle = _dwStyle;
  721.     return S_OK;
  722. }
  723. /*----------------------------------------------------------
  724. Purpose: IBandSite::SetBandSiteInfo
  725. */
  726. HRESULT CBandSite::SetBandSiteInfo(const BANDSITEINFO * pbsinfo)
  727. {
  728.     ASSERT(IS_VALID_READ_PTR(pbsinfo, BANDSITEINFO));
  729.     if (pbsinfo->dwMask & BSIM_STATE)
  730.         _dwMode = pbsinfo->dwState;
  731.     if (pbsinfo->dwMask & BSIM_STYLE)
  732.     {
  733.         // If the BSIS_SINGLECLICK style changed, change the rebar style
  734.         if ( _hwnd && ((_dwStyle ^ pbsinfo->dwStyle) & BSIS_SINGLECLICK) )
  735.             SHSetWindowBits(_hwnd, GWL_STYLE, RBS_DBLCLKTOGGLE, (pbsinfo->dwStyle & BSIS_SINGLECLICK)?0:RBS_DBLCLKTOGGLE);
  736.             
  737.         _dwStyle = pbsinfo->dwStyle;
  738.     }
  739.     return S_OK;
  740. }
  741. /*----------------------------------------------------------
  742. Purpose: IBandSite::GetBandObject
  743. */
  744. HRESULT CBandSite::GetBandObject(DWORD dwBandID, REFIID riid, void **ppvObj)
  745. {
  746.     HRESULT hres = E_FAIL;
  747.     
  748.     *ppvObj = NULL;
  749.     if (IsEqualIID(riid, IID_IDataObject)) 
  750.     {
  751.         *ppvObj = _DataObjForBand(dwBandID);
  752.         if (*ppvObj)
  753.             hres = S_OK;
  754.     }
  755.     else 
  756.     {
  757.         LPBANDITEMDATA pbid = _GetBandItemDataStructByID(dwBandID);
  758.         if (pbid)
  759.         {
  760.             hres = pbid->pdb->QueryInterface(riid, ppvObj);
  761.         }
  762.     }
  763.     return hres;
  764. }
  765. /*----------------------------------------------------------
  766. Purpose: Returns a pointer to the band item data given an
  767.          externally known band ID.
  768. Returns: NULL if band ID is illegal
  769. */
  770. LPBANDITEMDATA CBandSite::_GetBandItemDataStructByID(DWORD uID)
  771. {
  772.     int iBand = _BandIDToIndex(uID);
  773.     if (iBand == -1)
  774.         return NULL;
  775.     return _GetBandItem(iBand);
  776. }
  777. __inline HRESULT _FwdWinEvent(IWinEventHandler* pweh, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres)
  778. {
  779.     ASSERT(pweh);
  780.     ASSERT(hwnd == HWND_BROADCAST || pweh->IsWindowOwner(hwnd) == S_OK);
  781.     return pweh->OnWinEvent(hwnd, uMsg, wParam, lParam, plres);
  782. }
  783. /*----------------------------------------------------------
  784. Purpose: Forwards messages to the band that owns the window.
  785. Returns: TRUE if the message was forwarded
  786. */
  787. BOOL CBandSite::_SendToToolband(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres)
  788. {
  789.     BOOL fSent = FALSE;
  790.     LRESULT lres = 0;
  791.     if (hwnd)
  792.     {
  793.         if (hwnd == _hwndCache)
  794.         {
  795.             ASSERT(hwnd != HWND_BROADCAST);
  796.             if (_pwehCache)
  797.             {
  798.                 _FwdWinEvent(_pwehCache, hwnd, uMsg, wParam, lParam, &lres);
  799.                 fSent = TRUE;
  800.             }
  801.         }
  802.         else
  803.         {
  804.             LPBANDITEMDATA pbid;
  805.             int i;
  806.             for (i = _GetBandItemCount() - 1; i >= 0; i--)
  807.             {
  808.                 pbid = _GetBandItem(i);
  809.                 if (pbid)
  810.                 {
  811.                     if (pbid->pweh)
  812.                     {
  813.                         if (hwnd == HWND_BROADCAST || 
  814.                           (pbid->pweh->IsWindowOwner(hwnd) == S_OK))
  815.                         {
  816.                             _FwdWinEvent(pbid->pweh, hwnd, uMsg, wParam, lParam, &lres);
  817.                             fSent = TRUE;
  818.                             if (hwnd != HWND_BROADCAST)
  819.                             {
  820.                                 break;
  821.                             }
  822.                         }
  823.                     }
  824.                     else
  825.                     {
  826.                         if (hwnd == HWND_BROADCAST && pbid->hwnd)
  827.                         {
  828.                             lres = SendMessage(pbid->hwnd, uMsg, wParam, lParam);
  829.                             fSent = TRUE;
  830.                         }
  831.                     }
  832.                 }
  833.             }
  834.             if (hwnd != HWND_BROADCAST)
  835.             {
  836.                 ATOMICRELEASE(_pwehCache);
  837.                 _hwndCache = hwnd;
  838.                 if (fSent)
  839.                 {
  840.                     _pwehCache = pbid->pweh;
  841.                     _pwehCache->AddRef();
  842.                 }
  843.             }
  844.         }
  845.     }
  846.     if (plres)
  847.         *plres = lres;
  848.     
  849.     return fSent;
  850. }
  851. typedef struct {
  852.     HWND hwnd;
  853.     HRESULT hres;
  854. } WINDOWOWNERDATA;
  855. int _IsWindowOwnerCallback(LPBANDITEMDATA pbid, void *pv)
  856. {
  857.     WINDOWOWNERDATA* pwod = (WINDOWOWNERDATA*)pv;
  858.     
  859.     if (pbid->pweh && (pbid->pweh->IsWindowOwner(pwod->hwnd) == S_OK)) 
  860.     {
  861.         pwod->hres = S_OK;
  862.         return 0;
  863.     }
  864.     return 1;
  865. }
  866. HRESULT CBandSite::IsWindowOwner(HWND hwnd)
  867. {
  868.     if (hwnd == _hwnd)
  869.         return S_OK;
  870.     
  871.     WINDOWOWNERDATA wod = { hwnd, S_FALSE };
  872.     _BandItemEnumCallback(1, _IsWindowOwnerCallback, &wod);
  873.     return wod.hres;
  874. }
  875. //***   CBandSite::IDeskBarClient::* {
  876. HRESULT CBandSite::GetSize(DWORD dwWhich, LPRECT prc)
  877. {
  878.     HRESULT hres = E_FAIL;
  879.     switch (dwWhich) {
  880.     case DBC_GS_IDEAL:
  881.         prc->right = 0;
  882.         prc->bottom = 0;
  883.         BOOL_PTR fRedraw = SendMessage(_hwnd, WM_SETREDRAW, FALSE, 0);
  884.         for (int i = _GetBandItemCount() - 1; i >= 0; i--)
  885.         {
  886.             LPBANDITEMDATA pbid = _GetBandItem(i);
  887.             if (pbid)
  888.             {
  889.                 RECT rc;
  890.             
  891.                 SendMessage(_hwnd, RB_GETBANDBORDERS, _BandIDToIndex(pbid->dwBandID), (LPARAM) &rc);
  892.                 _UpdateBandInfo(pbid, FALSE);
  893.                 if (pbid->fShow) {
  894.                     if (_dwMode & (DBIF_VIEWMODE_FLOATING | DBIF_VIEWMODE_VERTICAL)) {
  895.                         prc->right = max(prc->right, pbid->ptActual.x + (rc.left + rc.right));
  896.                         prc->bottom += pbid->ptActual.y + rc.top + rc.bottom;
  897.                     } else {
  898.                         prc->bottom = max(prc->right, pbid->ptActual.x + (rc.left + rc.right));
  899.                         prc->right += pbid->ptActual.y + rc.top + rc.bottom;
  900.                     }
  901.                 }
  902.                 hres = S_OK;
  903.             }
  904.         }
  905.         SendMessage(_hwnd, WM_SETREDRAW, fRedraw, 0);
  906.         
  907.         break;
  908.     }
  909.     return hres;
  910.     
  911. }
  912. void CBandSite::_Close() 
  913. {        
  914.     if (_hwnd) {
  915.         // BUGBUG (scotth): This method is getting called by the destructor,
  916.         //  and calls _DeleteAllBandItems, which sends messages to _hwnd.
  917.         //  _hwnd is already destroyed by this time.  If you hit this assert
  918.         //  it is because in debug windows it RIPs like crazy.
  919.         // 970508 (adp): pblm was that we weren't doing DestroyWnd etc.
  920.         //  
  921.         //  Do no remove this assert....please fix the root problem.
  922.         ASSERT(IS_VALID_HANDLE(_hwnd, WND));
  923.         SendMessage(_hwnd, WM_SETREDRAW, 0, 0);
  924.         _DeleteAllBandItems(); 
  925.         DestroyWindow(_hwnd);
  926.         _hwnd = 0;
  927.     }
  928. }
  929.     
  930. HRESULT CBandSite::UIActivateDBC(DWORD dwState)
  931. {
  932.     if (dwState != _dwShowState) {
  933.         BOOL fShow = dwState;
  934.         _dwShowState = dwState;
  935.         // map UIActivateDBC to ShowDW
  936.         if (DBC_SHOWOBSCURE == dwState)
  937.             fShow = FALSE;
  938.         BOOL_PTR fRedraw = SendMessage(_hwnd, WM_SETREDRAW, FALSE, 0);
  939.         for (int i = _GetBandItemCount() - 1; i >= 0; i--)
  940.         {
  941.             LPBANDITEMDATA pbid = _GetBandItem(i);
  942.             if (pbid)
  943.                 pbid->pdb->ShowDW(fShow && pbid->fShow);
  944.         }
  945.         // do this now intead of at creation so that 
  946.         // rebar doesn't keep trying to autosize us while
  947.         // we're not even visible
  948.         SHSetWindowBits(_hwnd, GWL_STYLE, RBS_AUTOSIZE, RBS_AUTOSIZE);
  949.         SendMessage(_hwnd, WM_SIZE, 0, 0);
  950.         SendMessage(_hwnd, WM_SETREDRAW, (DBC_SHOW == dwState) ? TRUE : fRedraw, 0);
  951.     }
  952.     return S_OK;
  953. }
  954. DWORD CBandSite::_GetWindowStyle(DWORD* pdwExStyle)
  955. {
  956.     *pdwExStyle = WS_EX_TOOLWINDOW;
  957.     DWORD dwStyle = RBS_REGISTERDROP | RBS_VARHEIGHT | RBS_BANDBORDERS |
  958.                     WS_VISIBLE |  WS_CHILD | WS_CLIPCHILDREN |
  959.                     WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN;
  960.     if (_dwStyle & BSIS_LEFTALIGN) {
  961.         dwStyle |= RBS_VERTICALGRIPPER;
  962.     }
  963.     if (!(_dwStyle & BSIS_SINGLECLICK)) {
  964.         dwStyle |= RBS_DBLCLKTOGGLE;
  965.     }
  966.     return dwStyle;
  967. }
  968. HRESULT CBandSite::_Initialize(HWND hwndParent)
  969. {
  970.     //
  971.     //  I hope we have an IBandSite to talk to.
  972.     //
  973.     if (!_pbsOuter)
  974.         return E_FAIL;
  975.     if (!_hwnd) 
  976.     {
  977.         DWORD dwExStyle;
  978.         DWORD dwStyle = _GetWindowStyle(&dwExStyle);
  979.         _hwnd = CreateWindowEx(dwExStyle, REBARCLASSNAME, NULL, dwStyle,
  980.                                0, 0, 0, 0, hwndParent, (HMENU) FCIDM_REBAR, HINST_THISDLL, NULL);
  981.         if (_hwnd)
  982.         {
  983.             SendMessage(_hwnd, RB_SETTEXTCOLOR, 0, CLR_DEFAULT);
  984.             SendMessage(_hwnd, RB_SETBKCOLOR, 0, CLR_DEFAULT);
  985.             SendMessage(_hwnd, WM_SETREDRAW, FALSE, 0);
  986.         }
  987.     }
  988.     
  989.     return _hwnd ? S_OK : E_OUTOFMEMORY;
  990. }
  991. HRESULT CBandSite::SetDeskBarSite(IUnknown* punkSite)
  992. {
  993.     HRESULT hr = S_OK;
  994.     if (!punkSite)
  995.     {
  996.         // Time to tell the bands to free their
  997.         // back pointers on us or we never get freed...
  998.         // 970325 for now bs::SetDeskBarSite(NULL) is 'overloaded'
  999.         // to mean do both a CloseDW and a SetSite.
  1000.         // when we clean up our act and have a bs::Close iface
  1001.         // we'll go back to the '#else' code below.
  1002.         if (_hwnd)
  1003.             _Close();
  1004.     }
  1005.     ATOMICRELEASE(_pct);
  1006.     ATOMICRELEASE(_pdb);
  1007.     ATOMICRELEASE(_punkSite);
  1008.     if (_pbp && _fCreatedBandProxy)
  1009.         _pbp->SetSite(punkSite);
  1010.     if (punkSite)
  1011.     {
  1012.         _punkSite = punkSite;
  1013.         _punkSite->AddRef();
  1014.         if (!_hwnd) 
  1015.         {
  1016.             HWND hwndParent;
  1017.             IUnknown_GetWindow(punkSite, &hwndParent);
  1018.             hr = _Initialize(hwndParent);
  1019.         }
  1020.         punkSite->QueryInterface(IID_IOleCommandTarget, (void **)&_pct);
  1021.         punkSite->QueryInterface(IID_IDeskBar, (void **)&_pdb);
  1022.     }
  1023.     
  1024.     return hr;
  1025. }
  1026. HRESULT CBandSite::SetModeDBC(DWORD dwMode)
  1027. {
  1028.     if (dwMode != _dwMode) {
  1029.         _dwMode = dwMode;
  1030.         if (_hwnd) {
  1031.             DWORD dwStyle = 0;
  1032.             if (dwMode & (DBIF_VIEWMODE_FLOATING | DBIF_VIEWMODE_VERTICAL)) {
  1033.                 dwStyle |= CCS_VERT;
  1034.             }
  1035.             SHSetWindowBits(_hwnd, GWL_STYLE, CCS_VERT, dwStyle);
  1036.         }
  1037.         _UpdateAllBands(FALSE, FALSE);
  1038.     }
  1039.     return S_OK;
  1040. }
  1041. // }
  1042. IDropTarget* CBandSite::_WrapDropTargetForBand(IDropTarget* pdtBand)
  1043. {
  1044.     if (!pdtBand || (_dwStyle & BSIS_NODROPTARGET)) {
  1045.         // addref it for the new pointer
  1046.         if (pdtBand)
  1047.             pdtBand->AddRef();
  1048.         return pdtBand;
  1049.     } else {
  1050.         return DropTargetWrap_CreateInstance(pdtBand, SAFECAST(this, IDropTarget*), _hwndDD);
  1051.     }
  1052. }
  1053. LRESULT CBandSite::_OnNotify(LPNMHDR pnm)
  1054. {
  1055.     NMOBJECTNOTIFY *pnmon = (NMOBJECTNOTIFY *)pnm;
  1056.     
  1057.     switch (pnm->code) {
  1058.     case RBN_GETOBJECT:
  1059.     {
  1060.         pnmon->hResult = E_FAIL;
  1061.         
  1062.         // if we're the drag source, then a band is dragging... we want to only
  1063.         // give out the bandsite's drop target
  1064.         if (pnmon->iItem != -1 && !_fDragSource) 
  1065.         {
  1066.             LPBANDITEMDATA pbid = _GetBandItemDataStructByID(pnmon->iItem);
  1067.             if (EVAL(pbid))
  1068.             {
  1069.                 pnmon->hResult = pbid->pdb->QueryInterface(*pnmon->piid, &pnmon->pObject);
  1070.                 // give a wrapped droptarget instead of the band's droptarget
  1071.                 if (IsEqualIID(*pnmon->piid, IID_IDropTarget))
  1072.                 {
  1073.                     IDropTarget* pdtBand;
  1074.                     BOOL fNeedReleasePdtBand = FALSE;
  1075.                     if (SUCCEEDED(pnmon->hResult)) {
  1076.                         pdtBand = (IDropTarget*)(pnmon->pObject);
  1077.                     } else {
  1078.                         CDropDummy *pdtgt = new CDropDummy(_hwndDD);
  1079.                         pdtBand = SAFECAST(pdtgt, IDropTarget*);
  1080.                         fNeedReleasePdtBand = TRUE;
  1081.                     }
  1082.                     IDropTarget* pdt = _WrapDropTargetForBand(pdtBand);
  1083.                     if (pdt)
  1084.                     {
  1085.                         pnmon->pObject = pdt;
  1086.                         pnmon->hResult = S_OK;
  1087.                         // we've handed off pdtBand to pdt
  1088.                         fNeedReleasePdtBand = TRUE;
  1089.                     }
  1090.                     if (fNeedReleasePdtBand && pdtBand)
  1091.                         pdtBand->Release();
  1092.                 }
  1093.                 if (FAILED(pnmon->hResult) && !(_dwStyle & BSIS_NODROPTARGET)) 
  1094.                     pnmon->hResult = QueryInterface(*pnmon->piid, &pnmon->pObject);
  1095.             }
  1096.         } 
  1097.         break;
  1098.     }
  1099.     case RBN_BEGINDRAG:
  1100.         return _OnBeginDrag((NMREBAR*)pnm);
  1101.     case RBN_AUTOSIZE:
  1102.         _OnRBAutoSize((NMRBAUTOSIZE*)pnm);
  1103.         break;
  1104.     case RBN_CHEVRONPUSHED:
  1105.     {
  1106.         LPNMREBARCHEVRON pnmch = (LPNMREBARCHEVRON) pnm;
  1107.         LPBANDITEMDATA pbid = _GetBandItem(pnmch->uBand);
  1108.         if (EVAL(pbid)) {
  1109.             MapWindowPoints(_hwnd, HWND_DESKTOP, (LPPOINT)&pnmch->rc, 2);
  1110.             ToolbarMenu_Popup(_hwnd, &pnmch->rc, pbid->pdb, pbid->hwnd, 0, (DWORD)pnmch->lParamNM);
  1111.         }
  1112.         break;
  1113.     }
  1114.     }
  1115.     return 0;
  1116. }
  1117. void CBandSite::_OnRBAutoSize(NMRBAUTOSIZE* pnm)
  1118. {
  1119.     // DRAG_MOVE: we turn off autosize during (most of) a move because
  1120.     // fVertical is out of sync until the very end
  1121.     if (_pdb && _GetBandItemCount() && _fDragging != DRAG_MOVE) {
  1122.         RECT rc;
  1123.         int iHeightCur;
  1124.         int iHeight = (int)SendMessage(_hwnd, RB_GETBARHEIGHT, 0, 0);
  1125. #ifdef DEBUG
  1126.         DWORD dwStyle = GetWindowLong(_hwnd, GWL_STYLE);
  1127. #endif
  1128.         GetWindowRect(_hwnd, &rc);
  1129.         MapWindowRect(HWND_DESKTOP, GetParent(_hwnd), &rc);
  1130.         if (_dwMode & (DBIF_VIEWMODE_FLOATING | DBIF_VIEWMODE_VERTICAL))
  1131.         {
  1132.             ASSERT((dwStyle & CCS_VERT));
  1133.             iHeightCur = RECTWIDTH(rc);
  1134.             rc.right = rc.left + iHeight;
  1135.         }
  1136.         else
  1137.         {
  1138.             ASSERT(!(dwStyle & CCS_VERT));
  1139.             iHeightCur = RECTHEIGHT(rc);
  1140.             rc.bottom = rc.top + iHeight;
  1141.         }
  1142.         if (iHeightCur != iHeight)
  1143.             _pdb->OnPosRectChangeDB(&rc);
  1144.     }
  1145. }
  1146. IDataObject* CBandSite::_DataObjForBand(DWORD dwBandID)
  1147. {
  1148.     IDataObject* pdtobjReturn = NULL;
  1149.     LPBANDITEMDATA pbid = _GetBandItemDataStructByID(dwBandID);
  1150.     if (EVAL(pbid) && pbid->pdb)
  1151.     {
  1152.         HRESULT hres;
  1153.         
  1154.         CBandDataObject* pdtobj = new CBandDataObject();
  1155.         if (pdtobj) {
  1156.             hres = pdtobj->Init(pbid->pdb, this, dwBandID);
  1157.             if (SUCCEEDED(hres)) {
  1158.                 pdtobjReturn = pdtobj;
  1159.                 pdtobjReturn->AddRef();
  1160.             }
  1161.             
  1162.             pdtobj->Release();
  1163.         }
  1164.     }
  1165.     return pdtobjReturn;
  1166. }
  1167. LRESULT CBandSite::_OnBeginDrag(NMREBAR* pnm)
  1168. {
  1169.     LRESULT lres = 0;
  1170.     DWORD dwBandID = _IndexToBandID(pnm->uBand);
  1171.     IDataObject* pdtobj = _DataObjForBand(dwBandID);
  1172.     ATOMICRELEASE(_pdtobj);
  1173.     _uDragBand = pnm->uBand;
  1174.     _pdtobj = pdtobj;
  1175.     // because the RBN_BEGINDRAG is synchronous and so is SHDoDragDrop
  1176.     // post this message to ourselves instead of calling dragdrop directly.
  1177.     // note that we don't have a window of our own, so we post to our parent
  1178.     // and let the message reflector send it back to us
  1179.     PostMessage(GetParent(_hwnd), WM_COMMAND, MAKELONG(0, IDM_DRAGDROP), (LPARAM)_hwnd);
  1180.     return 1;
  1181. }
  1182. // return TRUE if the user drags out of the rect of the rebar meaning that we should
  1183. // go into ole drag drop.
  1184. BOOL CBandSite::_PreDragDrop()
  1185. {
  1186.     BOOL f = FALSE;
  1187.     RECT rc;
  1188.     POINT pt;
  1189.     DWORD dwBandID = _IndexToBandID(_uDragBand);    // Find the BandID before an reordering that may happen.
  1190.     
  1191.     GetWindowRect(_hwnd, &rc);
  1192.     SetCapture(_hwnd);
  1193.     InflateRect(&rc, GetSystemMetrics(SM_CXEDGE) * 3, GetSystemMetrics(SM_CYEDGE) * 3);
  1194.     while (GetCapture() == _hwnd) {
  1195.         MSG msg;
  1196.         
  1197.         if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  1198.             switch (msg.message) {
  1199.                 
  1200.             case WM_MOUSEMOVE:
  1201.                 GetCursorPos(&pt);
  1202.                 if (!ISMOVEDDISABLED(dwBandID))
  1203.                 {
  1204.                     if (PtInRect(&rc, pt))
  1205.                     {
  1206.                         SendMessage(_hwnd, RB_DRAGMOVE, 0, (LPARAM)-1);
  1207.                     } else if (!ISDDCLOSEDISABLED(dwBandID) && _pdtobj)
  1208.                     {
  1209.                         // we've moved out of the bounds of the rebar..  switch to ole drag
  1210.                         f = TRUE;
  1211.                         SetCapture(NULL);
  1212.                     }
  1213.                 }
  1214.                 break;
  1215.             case WM_LBUTTONUP:
  1216.             case WM_LBUTTONDOWN:
  1217.             case WM_MBUTTONUP:
  1218.             case WM_MBUTTONDOWN:
  1219.             case WM_RBUTTONUP:
  1220.             case WM_RBUTTONDOWN:
  1221.                 // bail on any mouse button action
  1222.                 SetCapture(NULL);
  1223.                 break;
  1224.                 
  1225.             case WM_KEYDOWN:
  1226.                 switch (msg.wParam) {
  1227.                 case VK_ESCAPE:
  1228.                     SetCapture(NULL);
  1229.                     break;
  1230.                 }
  1231.                 // fall through
  1232.                 
  1233.             default:
  1234.                 TranslateMessage(&msg);
  1235.                 DispatchMessage(&msg);
  1236.             }
  1237.         }
  1238.     }
  1239.     if (ISDDCLOSEDISABLED(dwBandID) || !_IsBandDeleteable(dwBandID))
  1240.     {
  1241.         /// if don't allow close, never return true for ole drag.
  1242.         f = FALSE;
  1243.     }
  1244.     return f;
  1245. }
  1246. void CBandSite::_DoDragDrop()
  1247. {
  1248.     DWORD dwBandID = _IndexToBandID(_uDragBand);
  1249.     DWORD dwEffect = DROPEFFECT_MOVE;
  1250.     _fDragSource = TRUE;
  1251.     SendMessage(_hwnd, RB_BEGINDRAG, _uDragBand, (LPARAM)-2);
  1252.     HRESULT hres = S_OK;
  1253.     // first check to see if we even need to go into Ole drag, or if
  1254.     // it can all be contained within the rebar
  1255.     if (_PreDragDrop()) {
  1256.         SHLoadOLE(SHELLNOTIFY_OLELOADED); // Browser Only - our shell32 doesn't know ole has been loaded
  1257.         hres = SHDoDragDrop(_hwnd, _pdtobj, NULL, dwEffect, &dwEffect);
  1258.     } else {
  1259.         // if we kept it all within win32 dragging, then set no drop effect
  1260.         dwEffect = DROPEFFECT_NONE;
  1261.     }
  1262.     SendMessage(_hwnd, RB_ENDDRAG, 0, 0);
  1263.     _fDragSource = FALSE;
  1264.     if (dwEffect & DROPEFFECT_MOVE) 
  1265.     {
  1266.         RemoveBand(dwBandID);
  1267.     } 
  1268.     else if (!dwEffect && hres == DRAGDROP_S_DROP) 
  1269.     {
  1270.         // if the drop was done, but the target didn't allow
  1271.         // then we float the band.
  1272.     }
  1273.     ATOMICRELEASE(_pdtobj);
  1274. }
  1275. HMENU CBandSite::_LoadContextMenu()
  1276. {
  1277.     return LoadMenuPopup_PrivateNoMungeW(MENU_BANDSITE1);
  1278. }
  1279. HRESULT CBandSite::_OnBSCommand(int idCmd, DWORD idBandActive, LPBANDITEMDATA pbid)
  1280. {
  1281.     HRESULT hr = S_OK;
  1282.     switch (idCmd) {
  1283.     case BSIDM_CLOSEBAND:
  1284.         _OnCloseBand(idBandActive);
  1285.         break;
  1286.     case BSIDM_SHOWTITLEBAND:
  1287.         ASSERT(idBandActive != (DWORD)-1 && pbid);
  1288.         if (pbid) {
  1289.             pbid->fNoTitle = !pbid->fNoTitle;
  1290.             _UpdateBandInfo(pbid, FALSE);
  1291.         }
  1292.         break;
  1293.     case BSIDM_IEAK_DISABLE_MOVE:
  1294.     case BSIDM_IEAK_DISABLE_DDCLOSE:
  1295.         ASSERT(idBandActive != (DWORD)-1);
  1296.         if (idBandActive != (DWORD)-1) {
  1297.             static const int idCmds[]  = { BSIDM_IEAK_DISABLE_MOVE,   BSIDM_IEAK_DISABLE_DDCLOSE  };
  1298.             static const int idFlags[] = { BAND_ADMIN_NOMOVE,         BAND_ADMIN_NODDCLOSE        };
  1299.             DWORD dwFlag = SHSearchMapInt(idCmds, idFlags, ARRAYSIZE(idCmds), idCmd);
  1300.             DWORD dwAdminSettings = _GetAdminSettings(idBandActive);
  1301.             // Toggle Setting.
  1302.             ToggleFlag(dwAdminSettings, dwFlag);
  1303.             // Set Menu Item Check Mark appropriately.
  1304.             _SetAdminSettings(idBandActive, dwAdminSettings);
  1305.         }
  1306.         break;
  1307.     default:
  1308.         ASSERT(0);
  1309.         hr = E_FAIL;
  1310.         break;
  1311.     }
  1312.     return hr;
  1313. }
  1314. // returns the index of the band hit by lParam using context menu semantics (lParam == -1 for keyboard)
  1315. int CBandSite::_ContextMenuHittest(LPARAM lParam, POINT* ppt)
  1316. {
  1317.     int iBandIndex;
  1318.     if (lParam == (LPARAM) -1)
  1319.     {
  1320.         // Keyboard activation.  Use active band.
  1321.         DWORD dwBandID = _BandIDFromPunk(_ptbActive);
  1322.         iBandIndex = _BandIDToIndex(dwBandID);
  1323.         LPBANDITEMDATA pbid = _GetBandItem(iBandIndex);
  1324.         if (pbid)
  1325.         {
  1326.             RECT rc;
  1327.             GetWindowRect(pbid->hwnd, &rc);
  1328.             ppt->x = rc.left;
  1329.             ppt->y = rc.top;
  1330.         }
  1331.     }
  1332.     else
  1333.     {
  1334.         // Mouse activation.  Figure out which band got clicked.
  1335.         RBHITTESTINFO rbht;
  1336.         ppt->x = GET_X_LPARAM(lParam);
  1337.         ppt->y = GET_Y_LPARAM(lParam);
  1338.         rbht.pt = *ppt;
  1339.         ScreenToClient(_hwnd, &rbht.pt);
  1340.         SendMessage(_hwnd, RB_HITTEST, 0, (LPARAM)&rbht);
  1341.         iBandIndex = rbht.iBand;
  1342.     }
  1343.     return iBandIndex;
  1344. }
  1345. HRESULT CBandSite::_OnContextMenu(WPARAM wParam, LPARAM lParam)
  1346. {
  1347.     HRESULT hres = S_OK;
  1348.     HMENU hmenu = CreatePopupMenu();
  1349.     if (hmenu)
  1350.     {
  1351.         HRESULT hresT;
  1352.         int idCmd = 1;
  1353.         IContextMenu *pcm, *pcmParent = NULL, *pcmChild = NULL;
  1354.         POINT pt;
  1355.         int iBandIndex = _ContextMenuHittest(lParam, &pt);
  1356.         // map rebar index to band id
  1357.         // get band info for that band id
  1358.         DWORD idBandActive = _IndexToBandID(iBandIndex);
  1359.         LPBANDITEMDATA pbid = _GetBandItemDataStructByID(idBandActive);
  1360.         //
  1361.         // self (top)
  1362.         //
  1363.         int idCmdBS1 = idCmd;
  1364.         HMENU hmenuMe = _LoadContextMenu();
  1365.         if (hmenuMe) {
  1366.             if (pbid) {
  1367.                 DESKBANDINFO dbi;
  1368.                 CheckMenuItem(hmenuMe, BSIDM_SHOWTITLEBAND,
  1369.                     pbid->fNoTitle ? MF_BYCOMMAND|MF_UNCHECKED : MF_BYCOMMAND|MF_CHECKED);
  1370.                 dbi.dwMask = 0;     // paranoia (and needed for taskband!)
  1371.                 _GetBandInfo(pbid, &dbi);
  1372.                 // make sure pbid in sync
  1373.                 ASSERT((dbi.dwMask & DBIM_TITLE) || pbid->fNoTitle);
  1374.                 if (!(dbi.dwMask & DBIM_TITLE) || !_IsEnableTitle(pbid)) {
  1375.         Lnotitle:
  1376.                     DeleteMenu(hmenuMe, BSIDM_SHOWTITLEBAND, MF_BYCOMMAND);
  1377.                 }
  1378.             }
  1379.             else {
  1380.                 goto Lnotitle;
  1381.             }
  1382.             idCmd += Shell_MergeMenus(hmenu, hmenuMe, 0, idCmd, 0x7fff, MM_ADDSEPARATOR) - (idCmd);
  1383.             DestroyMenu(hmenuMe);
  1384.         }
  1385.         //
  1386.         // child
  1387.         //
  1388.         int idCmdChild = idCmd;
  1389.         if (pbid && pbid->pdb) {
  1390.             // merge in band's menu (at front)
  1391.             hresT = pbid->pdb->QueryInterface(IID_IContextMenu, (void **)&pcmChild);
  1392.             if (SUCCEEDED(hresT)) {
  1393.                 // 0=at front
  1394.                 hresT = pcmChild->QueryContextMenu(hmenu, 0, idCmd, 0x7fff, 0);
  1395.                 ASSERT(SUCCEEDED(hresT));
  1396.                 idCmd += HRESULT_CODE(hresT);
  1397.             }
  1398.         }
  1399.         //
  1400.         // parent
  1401.         //
  1402.         int idCmdParent = idCmd;
  1403.         
  1404.         if (_punkSite) {
  1405.             
  1406.             _punkSite->QueryInterface(IID_IContextMenu, (void **)&pcmParent);
  1407.             if (pcmParent) {
  1408.                 // BUGBUG todo: fix parents and kids to handle...
  1409.                 // we'd like to pass in -1 but not everyone handles that.
  1410.                 // workaround: use _FixMenuIndex...
  1411.                 hresT = pcmParent->QueryContextMenu(hmenu, _FixMenuIndex(hmenu, (UINT)-1), idCmd, 0x7fff, 0);
  1412.                 ASSERT(SUCCEEDED(hresT));
  1413.                 idCmd += HRESULT_CODE(hresT);
  1414.             }
  1415.         }
  1416.         
  1417.         //
  1418.         // self (bottom)
  1419.         //
  1420.         int idCmdBS2 = idCmd;
  1421.         if (!(_dwStyle & BSIS_NOCONTEXTMENU))
  1422.         {
  1423.             hmenuMe = LoadMenuPopup_PrivateNoMungeW(MENU_BANDSITE2);
  1424.             if (hmenuMe) {
  1425.                 // disable 'Close Band' if it's marked undeleteable
  1426.                 // nash:17821: don't disable when 0 bands (so user can easily
  1427.                 // get out of toasted mode)
  1428.                 if ((idBandActive == (DWORD)-1) || // if mouse not over a band, delete close menu item
  1429.                     (!_IsBandDeleteable(idBandActive) ||
  1430.                      ISDDCLOSEDISABLED(idBandActive)))
  1431.                 {
  1432.                     DeleteMenu(hmenuMe, BSIDM_CLOSEBAND, MF_BYCOMMAND);
  1433.                 }
  1434.                 if (!_fIEAKInstalled) {
  1435.                     DeleteMenu(hmenuMe, BSIDM_IEAK_DISABLE_DDCLOSE, MF_BYCOMMAND);
  1436.                     DeleteMenu(hmenuMe, BSIDM_IEAK_DISABLE_MOVE, MF_BYCOMMAND);
  1437.                 }
  1438.                 else {
  1439.                     DWORD dwAdminSettings = _GetAdminSettings(idBandActive);
  1440.                     if (IsFlagSet(dwAdminSettings, BAND_ADMIN_NODDCLOSE))
  1441.                         _CheckMenuItem(hmenuMe, BSIDM_IEAK_DISABLE_DDCLOSE, TRUE);
  1442.                     if (IsFlagSet(dwAdminSettings, BAND_ADMIN_NOMOVE))
  1443.                         _CheckMenuItem(hmenuMe, BSIDM_IEAK_DISABLE_MOVE, TRUE);
  1444.                 }
  1445.                 idCmd += Shell_MergeMenus(hmenu, hmenuMe, (UINT) -1, idCmd, 0x7fff, MM_ADDSEPARATOR) - (idCmd);
  1446.                 DestroyMenu(hmenuMe);
  1447.             }
  1448.         }
  1449.         //
  1450.         // do it
  1451.         //
  1452.         {
  1453.             HWND hwndParent = GetParent(_hwnd);
  1454.             if (!hwndParent)
  1455.                 hwndParent = _hwnd;
  1456.             idCmd = TrackPopupMenu(hmenu,
  1457.                             TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
  1458.                                    pt.x, pt.y, 0, hwndParent, NULL);
  1459.         }
  1460.         if (idCmd) {
  1461.             // must test from smallest to largest
  1462.             ASSERT(idCmdBS1 <= idCmdChild);
  1463.             ASSERT(idCmdChild <= idCmdParent);    // o.w. test in wrong order
  1464.             ASSERT(idCmdParent <= idCmdBS2);
  1465.             if (idCmd < idCmdChild || idCmd >= idCmdBS2)
  1466.             {
  1467.                 // A bandsite command
  1468.                 if (idCmd < idCmdChild)
  1469.                     idCmd -= idCmdBS1;
  1470.                 else
  1471.                     idCmd -= idCmdBS2;
  1472.                 hres = _OnBSCommand(idCmd, idBandActive, pbid);
  1473.             }
  1474.             else
  1475.             {
  1476.                 // A parent or child command
  1477.                 if (idCmd < idCmdParent) {
  1478.                     pcm = pcmChild;
  1479.                     idCmd -= idCmdChild;
  1480.                 } else {
  1481.                     pcm = pcmParent;
  1482.                     idCmd -= idCmdParent;
  1483.                 }
  1484.                 ASSERT(pcm);
  1485.                 BANDSITEINVOKEPARAM bsip = { idBandActive, _GetOuter() };
  1486.             
  1487.                 //
  1488.                 // Call InvokeCommand
  1489.                 //
  1490.                 CMINVOKECOMMANDINFOEX ici = {
  1491.                     SIZEOF(CMINVOKECOMMANDINFOEX),
  1492.                     0L,
  1493.                     _hwnd,
  1494.                     (LPSTR)MAKEINTRESOURCE(idCmd),
  1495.                     (LPSTR) &bsip, NULL,
  1496.                     SW_NORMAL,
  1497.                 };
  1498.                 hres = pcm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici);
  1499.             }
  1500.         }
  1501.         if (pcmParent)
  1502.             pcmParent->Release();
  1503.         if (pcmChild)
  1504.             pcmChild->Release();
  1505.         
  1506.         DestroyMenu(hmenu);
  1507.     }
  1508.     
  1509.     return hres;
  1510. }
  1511. /*----------------------------------------------------------
  1512. Purpose: IWinEventHandler::OnWinEvent
  1513.          Processes messages passed on from the bar.  Forward
  1514.          messages to the bands as appropriate.
  1515. */
  1516. HRESULT CBandSite::OnWinEvent(HWND h, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres)
  1517. {
  1518.     HRESULT hres = E_FAIL;
  1519.     HWND hwnd = HWND_BROADCAST;
  1520.     
  1521.     switch (uMsg) {
  1522.     case WM_WININICHANGE:
  1523.         _UpdateAllBands(FALSE, FALSE);
  1524.         // fall through
  1525.     case WM_SYSCOLORCHANGE:
  1526.     case WM_PALETTECHANGED:
  1527.         // propagate to rebar
  1528.         if (_hwnd)
  1529.             SendMessage(_hwnd, uMsg, wParam, lParam);
  1530. #if 0 // COM side propagates, don't double-propagate to win32 side!
  1531.         // propagate it to child windows incase they handle it,
  1532.         PropagateMessage(_hwnd, uMsg, wParam, lParam, TRUE);
  1533. #endif
  1534.         // by not returning here, it will get forwarded to the bands also... 
  1535.         break;
  1536.         
  1537.     case WM_CONTEXTMENU:
  1538.         // if it came from the keyboard, wParam is somewhat useless.  it's always out hwnd
  1539.         if (IS_WM_CONTEXTMENU_KEYBOARD(lParam))
  1540.             hwnd = GetFocus();
  1541.         else
  1542.             hwnd = (HWND)wParam;
  1543.         break;
  1544.     case WM_COMMAND:
  1545.         hwnd = GET_WM_COMMAND_HWND(wParam, lParam);
  1546.         break;
  1547.             
  1548.     case WM_NOTIFY:
  1549.         hwnd = ((LPNMHDR)lParam)->hwndFrom;
  1550.         break;
  1551.         
  1552.     default:
  1553.         return E_FAIL;
  1554.     }
  1555.     
  1556.     LRESULT lres = 0;
  1557.     
  1558.     if (hwnd) {
  1559.         if(_hwnd == hwnd) {
  1560.             // a message for us
  1561.             switch (uMsg) {
  1562.             case WM_NOTIFY:
  1563.                 lres = _OnNotify((LPNMHDR)lParam);
  1564.                 hres = S_OK;
  1565.                 break;
  1566.             case WM_COMMAND:
  1567.                 switch (GET_WM_COMMAND_CMD(wParam, lParam)) {
  1568.                 case IDM_DRAGDROP:
  1569.                     _DoDragDrop();
  1570.                     break;
  1571.                 }
  1572.                 break;
  1573.             }
  1574.             
  1575.         } else {
  1576.             if (_SendToToolband(hwnd, uMsg, wParam, lParam, &lres))
  1577.                 hres = S_OK;
  1578.         }
  1579.     }
  1580.     
  1581.     
  1582.     switch (uMsg) {
  1583.     case WM_WININICHANGE:
  1584.         SendMessage(_hwnd, WM_SIZE, 0, 0);
  1585.         break;
  1586.     case WM_CONTEXTMENU:
  1587.         if (!lres)
  1588.             return _OnContextMenu(wParam, lParam);
  1589.         break;
  1590.     }
  1591.     if (plres)
  1592.         *plres = lres;
  1593.     
  1594.     return hres;
  1595. }
  1596. HRESULT CBandSite_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  1597. {
  1598.     CBandSite *pbs = new CBandSite(pUnkOuter);
  1599.     if (pbs)
  1600.     {
  1601.         *ppunk = pbs->_GetInner();
  1602.         return S_OK;
  1603.     }
  1604.     *ppunk = NULL;
  1605.     return E_OUTOFMEMORY;
  1606. }
  1607. #ifdef DEBUG
  1608. void DbPrBandInfo(REBARBANDINFO* prbbi)
  1609. {
  1610.     TraceMsg(DM_PERSIST,
  1611.         "fMask=%x fStyle=%x clrFore=%x clrBack=%x",
  1612.         prbbi->fMask, prbbi->fStyle, prbbi->clrFore, prbbi->clrBack);
  1613.     TraceMsg(DM_PERSIST, "lpText=%s", prbbi->lpText ? prbbi->lpText : TEXT("<nil>"));
  1614.     TraceMsg(DM_PERSIST,
  1615.         "cch=%d iImage=%d hwndChild=%x",
  1616.         prbbi->cch, prbbi->iImage, prbbi->hwndChild);
  1617.     TraceMsg(DM_PERSIST,
  1618.         "cxMinChild=%d cyMinChild=%d cx=%d hbmBack=%x",
  1619.         prbbi->cxMinChild, prbbi->cyMinChild, prbbi->cx, prbbi->hbmBack);
  1620.     TraceMsg(DM_PERSIST,
  1621.         "wID=%d cyMaxChild=%d cyIntegral=%d cyChild=%d",
  1622.         prbbi->wID, prbbi->cyMaxChild, prbbi->cyIntegral, prbbi->cyChild);
  1623.     return;
  1624. }
  1625. #else
  1626. #define DbPrBandInfo(prbbi) 0
  1627. #endif
  1628. //*** CBandSite::IPersistStream*::* {
  1629. //
  1630. HRESULT CBandSite::GetClassID(CLSID *pClassID)
  1631. {
  1632.     *pClassID = CLSID_RebarBandSite;
  1633.     return S_OK;
  1634. }
  1635. HRESULT CBandSite::IsDirty(void)
  1636. {
  1637.     ASSERT(0);
  1638.     return S_FALSE; // BUGBUG: never be dirty?
  1639. }
  1640. HRESULT CBandSite::_AddBand(IUnknown* punk)
  1641. {
  1642.     if (_pbsOuter)
  1643.     {
  1644.         // Give the outer guy first crack
  1645.         return _pbsOuter->AddBand(punk);
  1646.     }
  1647.     else
  1648.     {
  1649.         return AddBand(punk);
  1650.     }
  1651. }
  1652. //
  1653. // Persisted CBandSite, use types that have fixes sizes
  1654. //
  1655. struct SBandSite
  1656. {
  1657.     DWORD   cbSize;
  1658.     DWORD   cbVersion;
  1659.     DWORD   cBands;
  1660.     // ...followed by length-preceded bands
  1661. };
  1662. #define SBS_WOADMIN_VERSION 3   // Before we added admin settings.
  1663. #define SBS_VERSION 8
  1664. //***   CBandSite::Load, Save -- 
  1665. // DESCRIPTION
  1666. //  for each band...
  1667. //  Load            Read (i); OLFS(obj)+AddBand; Read (rbbi); RB_SBI
  1668. //  Save    RB_GBI; Write(i); OSTS(obj)+nil    ; Write(rbbi)
  1669. // NOTES
  1670. //  BUGBUG needs error recovery
  1671. //  BUGBUG we might have done a CreateBand w/o an AddBand; if so our
  1672. //  assumption about the rebar bands and the iunknowns being 'parallel'
  1673. //  is bogus.
  1674. HRESULT CBandSite::Load(IStream *pstm)
  1675. {
  1676.     HRESULT hres;
  1677.     SBandSite sfoo;
  1678.     hres = IStream_Read(pstm, &sfoo, SIZEOF(sfoo));     // pstm->Read
  1679.     if (hres == S_OK)
  1680.     {
  1681.         if (!(sfoo.cbSize == SIZEOF(SBandSite) &&
  1682.           (sfoo.cbVersion == SBS_VERSION || sfoo.cbVersion == SBS_WOADMIN_VERSION)))
  1683.         {
  1684.             hres = E_FAIL;
  1685.         }
  1686.         IBandSiteHelper *pbsh;
  1687.         hres = QueryInterface(IID_IBandSiteHelper, (void **)&pbsh);
  1688.         if (EVAL(SUCCEEDED(hres)))
  1689.         {
  1690.             BOOL_PTR fRedraw = SendMessage(_hwnd, WM_SETREDRAW, FALSE, 0);
  1691.             for (DWORD i = 0; i < sfoo.cBands && SUCCEEDED(hres); ++i)
  1692.             {
  1693.                 DWORD j;
  1694.                 hres = IStream_Read(pstm, &j, SIZEOF(j));   // pstm->Read
  1695.                 if (hres == S_OK)
  1696.                 {
  1697.                     if (j == i)             // for sanity check
  1698.                     {
  1699.                         IUnknown* punk;
  1700.                         hres = pbsh->LoadFromStreamBS(pstm, IID_IUnknown, (void **)&punk);
  1701.                         if (SUCCEEDED(hres))
  1702.                         {
  1703.                             hres = _AddBand(punk);
  1704.                             if (SUCCEEDED(hres))
  1705.                             {
  1706.                                 hres = _LoadBandInfo(pstm, i, sfoo.cbVersion);
  1707.                             }
  1708.                             punk->Release();
  1709.                         }
  1710.                     }
  1711.                     else
  1712.                     {
  1713.                         hres = E_FAIL;
  1714.                     }
  1715.                 }
  1716.             }
  1717.             SendMessage(_hwnd, WM_SETREDRAW, fRedraw, 0);
  1718.             pbsh->Release();
  1719.         }
  1720.         _UpdateAllBands(FALSE, TRUE);     // force refresh
  1721.     }
  1722.     return hres;
  1723. }
  1724. HRESULT CBandSite::Save(IStream *pstm, BOOL fClearDirty)
  1725. {
  1726.     HRESULT hres;
  1727.     SBandSite sfoo;
  1728.     
  1729.     TraceMsg(DM_PERSIST, "cbs.s enter(this=%x pstm=%x) tell()=%x", this, pstm, DbStreamTell(pstm));
  1730.     sfoo.cbSize = SIZEOF(SBandSite);
  1731.     sfoo.cbVersion = SBS_VERSION;
  1732.     sfoo.cBands = _GetBandItemCount();
  1733.     TraceMsg(DM_PERSIST, "cdb.s: cbands=%d", sfoo.cBands);
  1734.     hres = pstm->Write(&sfoo, SIZEOF(sfoo), NULL);
  1735.     if (SUCCEEDED(hres))
  1736.     {
  1737.         for (DWORD i = 0; i < sfoo.cBands; i++) 
  1738.         {
  1739.             // BUGBUG todo: put seek ptr so can resync after bogus streams
  1740.             hres = pstm->Write(&i, SIZEOF(i), NULL);    // for sanity check
  1741.             if (SUCCEEDED(hres))
  1742.             {
  1743.                 LPBANDITEMDATA pbid = _GetBandItem(i);
  1744.                 if (EVAL(pbid) && pbid->pdb)
  1745.                 {
  1746.                     IBandSiteHelper *pbsh;
  1747.                     hres = QueryInterface(IID_IBandSiteHelper, (void **)&pbsh);
  1748.                     if (SUCCEEDED(hres)) 
  1749.                     {
  1750.                         hres = pbsh->SaveToStreamBS(SAFECAST(pbid->pdb, IUnknown*), pstm);
  1751.                         pbsh->Release();
  1752.                     }
  1753.                 }
  1754.                 hres = _SaveBandInfo(pstm, i);
  1755.                 ASSERT(SUCCEEDED(hres));
  1756.             }
  1757.         }
  1758.     }
  1759.     TraceMsg(DM_PERSIST, "cbs.s leave tell()=%x", DbStreamTell(pstm));
  1760.     return hres;
  1761. }
  1762. HRESULT CBandSite::GetSizeMax(ULARGE_INTEGER *pcbSize)
  1763. {
  1764.     static const ULARGE_INTEGER cbMax = { SIZEOF(SBandSite), 0 };
  1765.     *pcbSize = cbMax;
  1766.     return S_OK;
  1767. }
  1768. // returns: IStream::Read() semantics, S_OK means complete read
  1769. HRESULT CBandSite::_LoadBandInfo(IStream *pstm, int i, DWORD dwVersion)
  1770. {
  1771.     PERSISTBANDINFO bi;
  1772.     HRESULT hres;
  1773.     DWORD dwSize = SIZEOF(bi);
  1774.     bi.dwAdminSettings = BAND_ADMIN_NORMAL;     // Assume Normal since it's not specified
  1775.     if (SBS_WOADMIN_VERSION == dwVersion)
  1776.         dwSize = SIZEOF(PERSISTBANDINFO_V3);
  1777.     hres = IStream_Read(pstm, &bi, dwSize);     // pstm->Read
  1778.     if (hres == S_OK)
  1779.     {
  1780.         REBARBANDINFO rbbi;
  1781.         LPBANDITEMDATA pbid;
  1782.         rbbi.cbSize = SIZEOF(rbbi);
  1783.         rbbi.fMask = RBBIM_XPERSIST;
  1784.         rbbi.cx = bi.cx;
  1785.         rbbi.fStyle = bi.fStyle;
  1786.         
  1787.         // these things can change from instantiation to instantiation.
  1788.         // we want to restore the visual state, not the sizing rules.
  1789.         // the sizing rules re retreived each time in getbandinfo
  1790.         rbbi.cyMinChild = -1;
  1791.         rbbi.cyMaxChild = -1;
  1792.         rbbi.cyIntegral = -1;
  1793.         rbbi.cxMinChild = -1;
  1794.         if (rbbi.fStyle & RBBS_VARIABLEHEIGHT) {
  1795.             rbbi.cyChild = bi.cyChild;
  1796.         } else {
  1797.             rbbi.cyMinChild = bi.cyMinChild;
  1798.         }
  1799.         if (!SendMessage(_hwnd, RB_SETBANDINFO, i, (LPARAM) &rbbi)) 
  1800.         {
  1801.             TraceMsg(DM_PERSIST, "cbs.l: RB_SETBANDINFO failed");
  1802.             ASSERT(0);
  1803.             hres = E_FAIL;
  1804.         }
  1805.         pbid = _GetBandItem(i);
  1806.         if (pbid) {
  1807.             pbid->dwAdminSettings = bi.dwAdminSettings;
  1808.             pbid->fNoTitle = bi.fNoTitle;
  1809.         }
  1810.     }
  1811.     return hres;
  1812. }
  1813. HRESULT CBandSite::_SaveBandInfo(IStream *pstm, int i)
  1814. {
  1815.     REBARBANDINFO rbbi;
  1816.     PERSISTBANDINFO bi = {0};
  1817.     LPBANDITEMDATA pbid;
  1818.     rbbi.cbSize = SIZEOF(rbbi);
  1819.     rbbi.fMask = RBBIM_XPERSIST;
  1820.     SendMessage(_hwnd, RB_GETBANDINFO, i, (LPARAM) &rbbi);
  1821.     ASSERT((rbbi.fMask & RBBIM_XPERSIST) == RBBIM_XPERSIST);
  1822.     bi.cx = rbbi.cx;
  1823.     bi.fStyle = rbbi.fStyle;
  1824.     bi.cyMinChild = rbbi.cyMinChild;
  1825.     bi.cyChild = rbbi.cyChild;
  1826.     pbid = _GetBandItem(i);
  1827.     if (pbid) {
  1828.         bi.dwAdminSettings = pbid->dwAdminSettings;
  1829.         bi.fNoTitle = pbid->fNoTitle;
  1830.     }
  1831.     return pstm->Write(&bi, SIZEOF(bi), NULL);
  1832. }
  1833. // }
  1834. void CBandSite::_CacheActiveBand(IUnknown *ptb)
  1835. {
  1836.     if (ptb == _ptbActive)
  1837.         return;
  1838.     if (SHIsSameObject(ptb, _ptbActive))
  1839.         return;
  1840.     ATOMICRELEASE(_ptbActive);
  1841.     if (ptb != NULL) {
  1842. #ifdef DEBUG
  1843.         {
  1844.         IUnknown *pxTmp;
  1845.         // better be an IInputObject or else why did you call us?
  1846.         if (EVAL(SUCCEEDED(ptb->QueryInterface(IID_IInputObject, (void **)&pxTmp))))
  1847.             pxTmp->Release();
  1848.         // overly strict, but in our case it's true...
  1849.         if (EVAL(SUCCEEDED(ptb->QueryInterface(IID_IDeskBand, (void **)&pxTmp))))
  1850.             pxTmp->Release();
  1851.         }
  1852. #endif
  1853.         _ptbActive = ptb;
  1854.         _ptbActive->AddRef();
  1855.     }
  1856.     return;
  1857. }
  1858. DWORD CBandSite::_BandIDFromPunk(IUnknown* punk)
  1859. {
  1860.     DWORD dwBandID = -1;
  1861.     DWORD dwBandIDTest;
  1862.     int cBands = EnumBands(-1, NULL);
  1863.     IUnknown* punkTest;
  1864.     if (punk)
  1865.     {
  1866.         for (int i = 0; i < cBands; i++)
  1867.         {
  1868.             if (SUCCEEDED(EnumBands(i, &dwBandIDTest)))
  1869.             {
  1870.                 if (SUCCEEDED(GetBandObject(dwBandIDTest, IID_IUnknown, (void**)&punkTest)))
  1871.                 {
  1872.                     BOOL fEq = SHIsSameObject(punk, punkTest);
  1873.                     punkTest->Release();
  1874.                     if (fEq)
  1875.                     {
  1876.                         dwBandID = dwBandIDTest;
  1877.                         break;
  1878.                     }
  1879.                 }
  1880.             }
  1881.         }
  1882.     }
  1883.     return dwBandID;
  1884. }
  1885. //*** IInputObjectSite methods ***
  1886. HRESULT CBandSite::OnFocusChangeIS(IUnknown *punk, BOOL fSetFocus)
  1887. {
  1888.     if (_ptbActive)
  1889.     {
  1890.         if (!SHIsSameObject(_ptbActive, punk))
  1891.         {
  1892.             // Deactivate current band since the current band is 
  1893.             // not the caller
  1894.             UIActivateIO(FALSE, NULL);
  1895.         }
  1896.     }
  1897.     if (fSetFocus)
  1898.         _CacheActiveBand(punk);
  1899.     return UnkOnFocusChangeIS(_punkSite, SAFECAST(this, IInputObject*), fSetFocus);
  1900. }
  1901. //*** IInputObject methods ***
  1902. HRESULT CBandSite::UIActivateIO(BOOL fActivate, LPMSG lpMsg)
  1903. {
  1904.     HRESULT hres = E_FAIL;
  1905.     ASSERT(NULL == lpMsg || IS_VALID_WRITE_PTR(lpMsg, MSG));
  1906.     if (_ptbActive)
  1907.     {
  1908.         hres = UnkUIActivateIO(_ptbActive, fActivate, lpMsg);
  1909.     }
  1910.     else
  1911.     {
  1912.         hres = OnFocusChangeIS(NULL, fActivate);
  1913.     }
  1914.     if (fActivate)
  1915.     {
  1916.         if (!_ptbActive)
  1917.         {
  1918.             if (IsVK_TABCycler(lpMsg))
  1919.                 hres = _CycleFocusBS(lpMsg);
  1920.             else
  1921.                 hres = S_OK;
  1922.         }
  1923.     }
  1924.     else
  1925.     {
  1926.         _CacheActiveBand(NULL);
  1927.     }
  1928.     return hres;
  1929. }
  1930. HRESULT CBandSite::HasFocusIO()
  1931. {
  1932.     // Rebar should never get focus
  1933.     // NT #288832 Is one case where (GetFocus() == _hwnd)
  1934.     //    which is caused when the "Folder Bar" disappears.
  1935.     //    CExplorerBand::ShowDW() calls ShowWindow(hwndTreeView, SW_HIDE)
  1936.     //    which by default sets focus to the parent (us).
  1937.     //    This is ok because when this function is called,
  1938.     //    it will return E_FAIL which the caller will treat
  1939.     //    as S_FALSE and give the focus to the next deserving
  1940.     //    dude in line.
  1941.     return UnkHasFocusIO(_ptbActive);
  1942. }
  1943. HRESULT CBandSite::TranslateAcceleratorIO(LPMSG lpMsg)
  1944. {
  1945.     if (UnkTranslateAcceleratorIO(_ptbActive, lpMsg) == S_OK)
  1946.     {
  1947.         // active band handled it
  1948.         return S_OK;
  1949.     }
  1950.     else if (IsVK_TABCycler(lpMsg))
  1951.     {
  1952.         // it's a tab; cycle focus
  1953.         return _CycleFocusBS(lpMsg);
  1954.     }
  1955.     return S_FALSE;
  1956. }
  1957. int CBandSite::_BandIndexFromPunk(IUnknown *punk)
  1958. {
  1959.     for (int i = 0; i < _GetBandItemCount(); i++)
  1960.     {
  1961.         LPBANDITEMDATA pbid = _GetBandItem(i);
  1962.         if (EVAL(pbid) && SHIsSameObject(pbid->pdb, punk))
  1963.             return i;
  1964.     }
  1965.     return -1;
  1966. }
  1967. BOOL CBandSite::_IsBandTabstop(LPBANDITEMDATA pbid)
  1968. {
  1969.     // A band is a tabstop if it is visible and has WS_TABSTOP
  1970.     if (pbid->fShow && pbid->hwnd)
  1971.     {
  1972.         ASSERT(IsWindowVisible(pbid->hwnd));
  1973.         if (WS_TABSTOP & GetWindowStyle(pbid->hwnd))
  1974.             return TRUE;
  1975.     }
  1976.     return FALSE;
  1977. }
  1978. #define INCDEC(i, fDec)   (fDec ? i - 1 : i + 1)
  1979. IUnknown* CBandSite::_GetNextTabstopBand(IUnknown* ptb, BOOL fBackwards)
  1980. {
  1981.     // Find the first tabstop candidate
  1982.     int iBandCount = _GetBandItemCount();
  1983.     int iBand = _BandIndexFromPunk(ptb);
  1984.     
  1985.     if (iBand == -1)
  1986.     {
  1987.         // Start at the end/beginning
  1988.         if (fBackwards)
  1989.             iBand = iBandCount - 1;
  1990.         else
  1991.             iBand = 0;
  1992.     }
  1993.     else
  1994.     {
  1995.         // Start one off the current band
  1996.         iBand = INCDEC(iBand, fBackwards);
  1997.     }
  1998.     // Loop til we find a tabstop band or we run off the end
  1999.     while (0 <= iBand && iBand < iBandCount)
  2000.     {
  2001.         LPBANDITEMDATA pbid = _GetBandItem(iBand);
  2002.         if (EVAL(pbid))
  2003.         {
  2004.             if (_IsBandTabstop(pbid))
  2005.                 return pbid->pdb;
  2006.         }
  2007.         // Try the next band
  2008.         iBand = INCDEC(iBand, fBackwards);
  2009.     }
  2010.     return NULL;
  2011. }
  2012. HRESULT CBandSite::_CycleFocusBS(LPMSG lpMsg)
  2013. {
  2014.     HRESULT hr = S_FALSE;
  2015.     IUnknown* ptbSave = NULL;
  2016.     if (_ptbActive)
  2017.     {
  2018.         // Save off the active band in ptbSave
  2019.         ptbSave = _ptbActive;
  2020.         ptbSave->AddRef();
  2021.         // Deactivate active band and clear cache
  2022.         UnkUIActivateIO(_ptbActive, FALSE, NULL);
  2023.         _CacheActiveBand(NULL);
  2024.     }
  2025.     if (ptbSave && IsVK_CtlTABCycler(lpMsg))
  2026.     {
  2027.         // If ctl-tab and a band was active, then reject focus
  2028.         ASSERT(hr == S_FALSE);
  2029.     }
  2030.     else
  2031.     {
  2032.         BOOL fShift = (GetKeyState(VK_SHIFT) < 0);
  2033.         // Loop til we find a tabstop and successfully activate it
  2034.         // or til we run out of bands.
  2035.         // BUGBUG: todo -- call SetFocus if UIActivateIO fails?
  2036.         IUnknown* ptbNext = ptbSave;
  2037.         while (ptbNext = _GetNextTabstopBand(ptbNext, fShift))
  2038.         {
  2039.             if (UnkUIActivateIO(ptbNext, TRUE, lpMsg) == S_OK)
  2040.             {
  2041.                 hr = S_OK;
  2042.                 break;
  2043.             }
  2044.         }
  2045.     }
  2046.     ATOMICRELEASE(ptbSave);
  2047.     return hr;
  2048. }
  2049. //*** CBandSite::IBandSiteHelper::* {
  2050. // stuff to make it possible to overload the OleLoad/Save stuff so the
  2051. // taskbar band does not have to be CoCreat able. kinda a hack...
  2052. HRESULT CBandSite::LoadFromStreamBS(IStream *pstm, REFIID riid, void **ppv)
  2053. {
  2054.     return OleLoadFromStream(pstm, riid, ppv);
  2055. }
  2056. HRESULT CBandSite::SaveToStreamBS(IUnknown *punk, IStream *pstm)
  2057. {
  2058.     IPersistStream *ppstm;
  2059.     HRESULT hres = punk->QueryInterface(IID_IPersistStream, (void **)&ppstm);
  2060.     if (SUCCEEDED(hres)) 
  2061.     {
  2062.         hres = OleSaveToStream(ppstm, pstm);
  2063.         ppstm->Release();
  2064.     }
  2065.     return hres;
  2066. }
  2067. // }
  2068. // *** IDropTarget *** {
  2069. HRESULT CBandSite::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  2070. {
  2071.     TraceMsg(TF_BANDDD, "BandSite::DragEnter %d %d", pt.x, pt.y);
  2072.     if (!_fDragSource) {
  2073.         FORMATETC fmte = {g_cfDeskBand, NULL, 0, -1, TYMED_ISTREAM};
  2074.         _dwDropEffect = DROPEFFECT_NONE;
  2075.         
  2076.         if (pdtobj->QueryGetData(&fmte) == S_OK) {
  2077.             _dwDropEffect = DROPEFFECT_MOVE;
  2078.         } else {
  2079.             LPITEMIDLIST pidl;
  2080.             if (SUCCEEDED(SHPidlFromDataObject(pdtobj, &pidl, NULL, 0))) {
  2081.                 ASSERT(pidl && IS_VALID_PIDL(pidl));
  2082.                 DWORD dwAttrib = SFGAO_FOLDER | SFGAO_BROWSABLE;
  2083.                 IEGetAttributesOf(pidl, &dwAttrib);
  2084.                 ILFree(pidl);
  2085.                 DWORD   dwRAction;
  2086.         
  2087.                 if (FAILED(IUnknown_HandleIRestrict(_punkSite, &RID_RDeskBars, RA_DROP, NULL, &dwRAction)))
  2088.                     dwRAction = RR_ALLOW;
  2089.                 if (dwRAction == RR_DISALLOW)
  2090.                     _dwDropEffect = DROPEFFECT_NONE;
  2091.                 else {                
  2092.                     // if it's not a folder nor a browseable object, we can't host it.
  2093.                     if ((dwAttrib & SFGAO_FOLDER) ||
  2094.                         (dwAttrib & SFGAO_BROWSABLE) && (grfKeyState & (MK_CONTROL | MK_SHIFT)) == (MK_CONTROL | MK_SHIFT)) 
  2095.                         _dwDropEffect = DROPEFFECT_LINK | DROPEFFECT_COPY;
  2096.                     _dwDropEffect |= GetPreferedDropEffect(pdtobj);
  2097.                 }
  2098.             }
  2099.         }
  2100.         *pdwEffect &= _dwDropEffect;
  2101.     }
  2102.     
  2103.     return S_OK;
  2104. }
  2105. HRESULT CBandSite::DragOver(DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  2106. {
  2107.     TraceMsg(TF_BANDDD, "BandSite::DragOver %d %d", ptl.x, ptl.y);
  2108.     if (_fDragSource) {
  2109.         RECT rc;
  2110.         POINT pt;
  2111.         pt.x = ptl.x;
  2112.         pt.y = ptl.y;
  2113.         GetWindowRect(_hwnd, &rc);
  2114.         if (PtInRect(&rc, pt))
  2115.             SendMessage(_hwnd, RB_DRAGMOVE, 0, (LPARAM)-1);
  2116.     } else {
  2117.         *pdwEffect &= _dwDropEffect;
  2118.     }
  2119.     return S_OK;    
  2120. }
  2121. HRESULT CBandSite::DragLeave(void)
  2122. {
  2123.     return S_OK;
  2124. }
  2125. HRESULT CBandSite::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  2126. {
  2127.     HRESULT hres = E_FAIL;
  2128.     
  2129.     TraceMsg(TF_BANDDD, "BandSite::Drop");
  2130.     if (_fDragSource)
  2131.     {
  2132.         SendMessage(_hwnd, RB_ENDDRAG, 0, 0);
  2133.         *pdwEffect = DROPEFFECT_NONE;
  2134.         hres = S_OK;
  2135.     }
  2136.     else
  2137.     {
  2138.         FORMATETC fmte = {g_cfDeskBand, NULL, 0, -1, TYMED_ISTREAM};
  2139.         STGMEDIUM stg;
  2140.         IUnknown *punk = NULL;
  2141.         LPITEMIDLIST pidl;
  2142.         
  2143.         // if it was an object of our type, create it!
  2144.         if ((*pdwEffect & DROPEFFECT_MOVE) &&
  2145.             SUCCEEDED(pdtobj->GetData(&fmte, &stg)))
  2146.         {
  2147.             hres = OleLoadFromStream(stg.pstm, IID_IUnknown, (void **)&punk);
  2148.             if (SUCCEEDED(hres))
  2149.             {
  2150.                 *pdwEffect = DROPEFFECT_MOVE;
  2151.             }
  2152.             ReleaseStgMedium(&stg);
  2153.         } 
  2154.         else if ((*pdwEffect & (DROPEFFECT_COPY | DROPEFFECT_LINK)) &&
  2155.                  SUCCEEDED(SHPidlFromDataObject(pdtobj, &pidl, NULL, 0)))
  2156.         {
  2157.             hres = SHCreateBandForPidl(pidl, &punk, (grfKeyState & (MK_CONTROL | MK_SHIFT)) == (MK_CONTROL | MK_SHIFT));
  2158.             ILFree(pidl);
  2159.             if (SUCCEEDED(hres))
  2160.             {
  2161.                 if (*pdwEffect & DROPEFFECT_LINK)
  2162.                     *pdwEffect = DROPEFFECT_LINK;
  2163.                 else
  2164.                     *pdwEffect = DROPEFFECT_COPY;
  2165.             }
  2166.         }
  2167.     
  2168.         if (punk)
  2169.         {
  2170.             hres = _AddBand(punk);
  2171.             if (SUCCEEDED(hres))
  2172.             {
  2173.                 DWORD dwState;
  2174.                 dwState = IDataObject_GetDeskBandState(pdtobj);
  2175.                 SetBandState(ShortFromResult(hres), BSSF_NOTITLE, dwState & BSSF_NOTITLE);
  2176.             }
  2177.             punk->Release();
  2178.         }
  2179.     }
  2180.     
  2181.     if (FAILED(hres)) 
  2182.         *pdwEffect = DROPEFFECT_NONE;
  2183.     return hres;
  2184. }
  2185. // }
  2186. //***   ::_MergeBS -- merge two bandsites into one
  2187. // ENTRY/EXIT
  2188. //  pdtDst  [INOUT] destination DropTarget (always from bandsite)
  2189. //  pbsSrc  [INOUT] source bandsite; deleted if all bands moved successfully
  2190. //  ret     S_OK if all bands moved; S_FALSE if some moved; E_* o.w.
  2191. // NOTES
  2192. //  note that if all the bands are moved successfully, pbsSrc will be deleted
  2193. //  as a side-effect.
  2194. //  pdtDst is assumed to accept multiple drops (bandsite does).
  2195. //  pdtDst may be from marshal/unmarshal (tray bandsite).
  2196. HRESULT _MergeBS(IDropTarget *pdtDst, IBandSite *pbsSrc)
  2197. {
  2198.     HRESULT hres = E_FAIL;
  2199.     DWORD idBand;
  2200.     pbsSrc->AddRef();           // don't go away until we're all done!
  2201.     // drag each band in turn
  2202.     while (SUCCEEDED(pbsSrc->EnumBands(0, &idBand))) {
  2203.         // note our (bogus?) assumption that bands which can't be
  2204.         // dragged will percolate down to a contiguous range of
  2205.         // iBands 0..n.  if that's bogus i'm not sure how we can
  2206.         // keep track of where we are.
  2207.         IDataObject *pdoSrc;
  2208.         hres = pbsSrc->GetBandObject(idBand, IID_IDataObject, (void **)&pdoSrc);
  2209.         if (SUCCEEDED(hres)) {
  2210.             DWORD dwEffect = DROPEFFECT_MOVE | DROPEFFECT_COPY;
  2211.             hres = SHSimulateDrop(pdtDst, pdoSrc, 0, NULL, &dwEffect);
  2212.             pdoSrc->Release();
  2213.             if (SUCCEEDED(hres) && (dwEffect & DROPEFFECT_MOVE)) {
  2214.                 hres = pbsSrc->RemoveBand(idBand);
  2215.                 ASSERT(SUCCEEDED(hres));
  2216.             }
  2217.         }
  2218.         // we failed to move the band, bail
  2219.         if (FAILED(hres)) {
  2220.             ASSERT(0);
  2221.             break;
  2222.         }
  2223.     }
  2224.     pbsSrc->Release();
  2225.     TraceMsg(DM_DRAG, "dba.ms: ret hres=%x", hres);
  2226.     return hres;
  2227. }
  2228. void CBandSite::_BandItemEnumCallback(int dincr, PFNBANDITEMENUMCALLBACK pfnCB, void *pv)
  2229. {
  2230.     UINT iFirst = 0;
  2231.     ASSERT(dincr == 1 || dincr == -1);
  2232.     if (dincr < 0) {
  2233.         iFirst = _GetBandItemCount() - 1;  // start from last
  2234.     }
  2235.     for (UINT i = iFirst; i < (UINT) _GetBandItemCount(); i += dincr) {
  2236.         LPBANDITEMDATA pbid = _GetBandItem(i);
  2237.         if (pbid && !pfnCB(pbid, pv))
  2238.             break;
  2239.     }
  2240. }
  2241. void CBandSite::_DeleteAllBandItems()
  2242. {
  2243.     for (int i = _GetBandItemCount() - 1; i >= 0; i--)
  2244.     {
  2245.         LPBANDITEMDATA pbid = _GetBandItem(i);
  2246.         // Release the banditem data first, while it can still
  2247.         // receive cleanup notifications from its control.  *Then*
  2248.         // delete the band item.
  2249.         if (pbid)
  2250.             _ReleaseBandItemData(pbid, i);
  2251.         // BUGBUG chrisfra 5/13/97 if you skip deleting, rebar can
  2252.         // rearrange on delete, moving a band so that it is never seen
  2253.         // and consequently we leak BrandBand and much else
  2254.         _DeleteBandItem(i);    // unhook from host (rebar)
  2255.     }
  2256. }
  2257. LPBANDITEMDATA CBandSite::_GetBandItem(int i)
  2258. {
  2259.     REBARBANDINFO rbbi;
  2260.     rbbi.cbSize = SIZEOF(rbbi);
  2261.     rbbi.fMask = RBBIM_LPARAM;
  2262.     rbbi.lParam = NULL; // in case of failure below
  2263.     if (_hwnd)
  2264.         SendMessage(_hwnd, RB_GETBANDINFO, i, (LPARAM)&rbbi);
  2265.     return (LPBANDITEMDATA)rbbi.lParam;
  2266. }
  2267. int CBandSite::_GetBandItemCount()
  2268. {
  2269.     int cel = 0;
  2270.     if (_hwnd)
  2271.     {
  2272.         ASSERT(IS_VALID_HANDLE(_hwnd, WND));
  2273.         cel = (int)SendMessage(_hwnd, RB_GETBANDCOUNT, 0, 0);
  2274.     }
  2275.     return cel;
  2276. }
  2277. void CBandSite::_GetBandInfo(LPBANDITEMDATA pbid, DESKBANDINFO *pdbi)
  2278. {
  2279.     pdbi->dwMask = DBIM_MINSIZE | DBIM_MAXSIZE | DBIM_INTEGRAL | DBIM_ACTUAL | DBIM_TITLE | DBIM_MODEFLAGS | DBIM_BKCOLOR;
  2280.                  
  2281.     pdbi->ptMinSize = pbid->ptMinSize;
  2282.     pdbi->ptMaxSize = pbid->ptMaxSize;
  2283.     pdbi->ptIntegral = pbid->ptIntegral;
  2284.     pdbi->ptActual = pbid->ptActual;
  2285.     StrCpyW(pdbi->wszTitle, pbid->szTitle);
  2286.     pdbi->dwModeFlags = pbid->dwModeFlags;
  2287.     pdbi->crBkgnd = pbid->crBkgnd;
  2288.     
  2289.     pbid->pdb->GetBandInfo(pbid->dwBandID, _dwMode, pdbi);
  2290.     if (pdbi->wszTitle[0] == 0) {
  2291.         pdbi->dwMask &= ~DBIM_TITLE;
  2292.     }
  2293.     pbid->ptMinSize = pdbi->ptMinSize;
  2294.     pbid->ptMaxSize = pdbi->ptMaxSize;
  2295.     pbid->ptIntegral = pdbi->ptIntegral;
  2296.     pbid->ptActual = pdbi->ptActual;
  2297.     StrCpyW(pbid->szTitle, pdbi->wszTitle);
  2298.     pbid->dwModeFlags = pdbi->dwModeFlags;
  2299.     pbid->crBkgnd = pdbi->crBkgnd;
  2300.     if (!(pdbi->dwMask & DBIM_TITLE))   // title not supported
  2301.         pbid->fNoTitle = TRUE;
  2302.     ASSERT(pdbi->dwModeFlags & DBIMF_VARIABLEHEIGHT ? pbid->ptIntegral.y : TRUE);
  2303. }
  2304. void CBandSite::_BandInfoFromBandItem(REBARBANDINFO *prbbi, LPBANDITEMDATA pbid, BOOL fBSOnly)
  2305. {
  2306.     // REVIEW: could be optimized more
  2307.     DESKBANDINFO dbi;
  2308.     if (!fBSOnly)
  2309.         _GetBandInfo(/*INOUT*/ pbid, &dbi);
  2310.     // now add the view as a band in the rebar
  2311.     // add links band
  2312.     prbbi->fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_IDEALSIZE | RBBIM_TEXT;
  2313.     if (fBSOnly)
  2314.         prbbi->fMask = RBBIM_STYLE|RBBIM_TEXT;
  2315.     // clear the bits the are band settable
  2316.     prbbi->fStyle |= RBBS_FIXEDBMP;
  2317.     prbbi->fStyle &= ~(RBBS_GRIPPERALWAYS | RBBS_VARIABLEHEIGHT | RBBS_USECHEVRON);
  2318.     if (_dwStyle & BSIS_NOGRIPPER)    
  2319.         prbbi->fStyle |= RBBS_NOGRIPPER;
  2320.     else if (_dwStyle & BSIS_ALWAYSGRIPPER)    
  2321.         prbbi->fStyle |= RBBS_GRIPPERALWAYS;
  2322.     else {
  2323.         // BSIS_AUTOGRIPPER...
  2324.         if (!(prbbi->fStyle & RBBS_FIXEDSIZE) &&
  2325.             !(_dwMode & DBIF_VIEWMODE_FLOATING))
  2326.             prbbi->fStyle |= RBBS_GRIPPERALWAYS;
  2327.     }
  2328.     if (pbid->dwModeFlags & DBIMF_VARIABLEHEIGHT) 
  2329.         prbbi->fStyle |= RBBS_VARIABLEHEIGHT;
  2330.     if (pbid->dwModeFlags & DBIMF_USECHEVRON)
  2331.         prbbi->fStyle |= RBBS_USECHEVRON;
  2332.     if (pbid->dwModeFlags & DBIMF_BREAK)
  2333.         prbbi->fStyle |= RBBS_BREAK;
  2334.     if (!fBSOnly) {
  2335.         prbbi->hwndChild = pbid->hwnd;
  2336.         prbbi->wID = pbid->dwBandID;
  2337.         // set up the geometries
  2338.         prbbi->cxMinChild = pbid->ptMinSize.x;
  2339.         prbbi->cyMinChild = pbid->ptMinSize.y;
  2340.         prbbi->cyMaxChild = pbid->ptMaxSize.y;
  2341.         prbbi->cyIntegral = pbid->ptIntegral.y;
  2342.         if (_dwMode & (DBIF_VIEWMODE_FLOATING | DBIF_VIEWMODE_VERTICAL)) 
  2343.         {
  2344.             // after we're up, it's the "ideal" point
  2345.             prbbi->cxIdeal = pbid->ptActual.y;
  2346.         } 
  2347.         else 
  2348.         {
  2349.             // after we're up, it's the "ideal" point
  2350.             prbbi->cxIdeal = pbid->ptActual.x;
  2351.         }
  2352.         if (prbbi->cxIdeal == (UINT)-1)
  2353.             prbbi->cxIdeal = 0;
  2354.         if (pbid->dwModeFlags & DBIMF_BKCOLOR)
  2355.         {
  2356.             if (dbi.dwMask & DBIM_BKCOLOR)
  2357.             {
  2358.                 prbbi->fMask |= RBBIM_COLORS;
  2359.                 prbbi->clrFore = CLR_DEFAULT;
  2360.                 prbbi->clrBack = dbi.crBkgnd;
  2361.             }
  2362.         }
  2363.         ASSERT(pbid->fNoTitle || (dbi.dwMask & DBIM_TITLE));    // pbid in sync?
  2364.     }
  2365.     SHUnicodeToTChar(pbid->szTitle, prbbi->lpText, prbbi->cch);
  2366.     if (!pbid->fNoTitle && _IsEnableTitle(pbid))
  2367.     {
  2368.         prbbi->fStyle &= ~RBBS_HIDETITLE;
  2369.     }
  2370.     else
  2371.     {
  2372.         // No text please
  2373.         prbbi->fStyle |= RBBS_HIDETITLE;
  2374.     }
  2375.         
  2376.     // Make this band a tabstop.  Itbar will override v_SetTabstop
  2377.     // since for the browser we don't want every band to be a tabstop.
  2378.     v_SetTabstop(prbbi);
  2379. }
  2380. void CBandSite::v_SetTabstop(LPREBARBANDINFO prbbi)
  2381. {
  2382.     // We specify that a band should be a tabstop by setting the WS_TABSTOP
  2383.     // bit.  Never make RBBS_FIXEDSIZE bands (i.e., the brand) tabstops.
  2384.     if (prbbi && prbbi->hwndChild && !(prbbi->fStyle & RBBS_FIXEDSIZE))
  2385.         SHSetWindowBits(prbbi->hwndChild, GWL_STYLE, WS_TABSTOP, WS_TABSTOP);
  2386. }
  2387. //***   cbs::_IsEnableTitle -- should we enable (ungray) title
  2388. // DESCRIPTION
  2389. //  used for handing back title and for enabling menu
  2390. // NOTES
  2391. //  pbid unused...
  2392. //
  2393. #ifndef UNIX
  2394. _inline
  2395. #endif
  2396. BOOL CBandSite::_IsEnableTitle(LPBANDITEMDATA pbid)
  2397. {
  2398.     ASSERT(pbid);
  2399.     return (/*pbid && !pbid->fNoTitle &&*/
  2400.       !((_dwMode & DBIF_VIEWMODE_FLOATING) && _GetBandItemCount() <= 1));
  2401. }
  2402. BOOL CBandSite::_UpdateBandInfo(LPBANDITEMDATA pbid, BOOL fBSOnly)
  2403. {
  2404.     REBARBANDINFO rbbi = {SIZEOF(rbbi)};
  2405.     int iRB = _BandIDToIndex(pbid->dwBandID);
  2406.     // now update the info
  2407.     rbbi.fMask = RBBIM_ID | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE;
  2408.     if (fBSOnly)
  2409.         rbbi.fMask = RBBIM_STYLE;
  2410.     SendMessage(_hwnd, RB_GETBANDINFO, iRB, (LPARAM)&rbbi);
  2411.     if (!fBSOnly) {
  2412.         if (_dwMode & (DBIF_VIEWMODE_FLOATING | DBIF_VIEWMODE_VERTICAL)) 
  2413.         {
  2414.             pbid->ptActual.x = rbbi.cyChild;
  2415.             pbid->ptActual.y = rbbi.cxIdeal;
  2416.         } 
  2417.         else 
  2418.         {
  2419.             pbid->ptActual.x = rbbi.cxIdeal;
  2420.             pbid->ptActual.y = rbbi.cyChild;
  2421.         }
  2422.         pbid->ptMinSize.x = rbbi.cxMinChild;
  2423.         pbid->ptMinSize.y = rbbi.cyMinChild;
  2424.         pbid->ptMaxSize.y = rbbi.cyMaxChild;
  2425.     }
  2426.     TCHAR szBand[40];
  2427.     rbbi.lpText = szBand;
  2428.     rbbi.cch = ARRAYSIZE(szBand);
  2429.     _BandInfoFromBandItem(&rbbi, pbid, fBSOnly);
  2430.     
  2431.     return BOOLFROMPTR(SendMessage(_hwnd, RB_SETBANDINFO, (UINT)iRB, (LPARAM)&rbbi));
  2432. }
  2433. BOOL CBandSite::_AddBandItem(LPBANDITEMDATA pbid)
  2434. {
  2435.     REBARBANDINFO rbbi = {SIZEOF(rbbi)};
  2436.     pbid->ptActual.x = -1;
  2437.     pbid->ptActual.y = -1;
  2438.     TCHAR szBand[40];
  2439.     rbbi.lpText = szBand;
  2440.     rbbi.cch = ARRAYSIZE(szBand);
  2441.     _BandInfoFromBandItem(&rbbi, pbid, FALSE);
  2442.     rbbi.cyChild = pbid->ptActual.y;
  2443.     rbbi.fMask |= RBBIM_LPARAM;
  2444.     rbbi.lParam = (LPARAM)pbid;
  2445.     ASSERT(rbbi.fMask & RBBIM_ID);
  2446.     return BOOLFROMPTR(SendMessage(_hwnd, RB_INSERTBAND, (UINT) -1, (LPARAM)&rbbi));
  2447. }
  2448. void CBandSite::_DeleteBandItem(int i)
  2449. {
  2450.     SendMessage(_hwnd, RB_DELETEBAND, i, 0);
  2451. }
  2452. DWORD CBandSite::_IndexToBandID(int i)
  2453. {
  2454.     REBARBANDINFO rbbi = {SIZEOF(rbbi)};
  2455.     rbbi.fMask = RBBIM_ID;
  2456.     if (SendMessage(_hwnd, RB_GETBANDINFO, i, (LPARAM)&rbbi))
  2457.         return rbbi.wID;
  2458.     else
  2459.         return -1;
  2460. }
  2461. /*----------------------------------------------------------
  2462. Purpose: Given the band ID, returns the internal band index.
  2463. */
  2464. int CBandSite::_BandIDToIndex(DWORD dwBandID)
  2465. {
  2466.     int nRet = -1;
  2467.     if (_hwnd)
  2468.         nRet = (int)SendMessage(_hwnd, RB_IDTOINDEX, (WPARAM) dwBandID, (LPARAM) 0);
  2469.     return nRet;
  2470. }
  2471. /*----------------------------------------------------------
  2472. Purpose: The Parent Site may want to override what the admin
  2473.          specified.
  2474. Return Values:
  2475.     S_OK: Do lock band.
  2476.     S_FALSE: Do NOT Lock band.
  2477. */
  2478. HRESULT CBandSite::_IsRestricted(DWORD dwBandID, DWORD dwRestrictAction, DWORD dwBandFlags)
  2479. {
  2480.     HRESULT hr;
  2481.     DWORD dwRestrictionAction;
  2482.     hr = IUnknown_HandleIRestrict(_punkSite, &RID_RDeskBars, dwRestrictAction, NULL, &dwRestrictionAction);
  2483.     if (RR_NOCHANGE == dwRestrictionAction)    // If our parent didn't handle it, we will.
  2484.         dwRestrictionAction = IsFlagSet(_GetAdminSettings(dwBandID), dwBandFlags) ? RR_DISALLOW : RR_ALLOW;
  2485.     if (RR_DISALLOW == dwRestrictionAction)
  2486.         hr = S_OK;
  2487.     else
  2488.         hr = S_FALSE;
  2489.     ASSERT(SUCCEEDED(hr));  // FAIL(hr) other than hr == E_NOTIMPLE; is not good.
  2490.     return hr;
  2491. }
  2492. BOOL ConfirmRemoveBand(HWND hwnd, UINT uID, LPCTSTR pszName)
  2493. {
  2494.     TCHAR szTemp[1024], *pszTemp2, *pszStr, szTitle[80];
  2495.     BOOL bRet = TRUE;
  2496.     DWORD dwLen;
  2497.     MLLoadString(IDS_CONFIRMCLOSETITLE, szTitle, ARRAYSIZE(szTitle));
  2498.     // Calling FormatMessage with FORMAT_MESSAGE_FROM_HMODULE fails
  2499.     MLLoadString(uID, szTemp, ARRAYSIZE(szTemp));
  2500.     dwLen = (lstrlen(szTemp) + lstrlen(pszName) + 1) * sizeof(TCHAR);
  2501.     if((pszTemp2 = (TCHAR *)LocalAlloc(LPTR, dwLen)) != NULL)
  2502.     {
  2503.         _FormatMessage(szTemp, pszTemp2, dwLen, pszName);
  2504.         MLLoadString(IDS_CONFIRMCLOSETEXT, szTemp, ARRAYSIZE(szTemp));
  2505.         dwLen = (lstrlen(szTemp) + lstrlen(pszTemp2) + 1) * sizeof(TCHAR);
  2506.         if((pszStr = (TCHAR *)LocalAlloc(LPTR, dwLen)) != NULL)
  2507.         {
  2508.             _FormatMessage(szTemp, pszStr, dwLen, pszTemp2);
  2509.             bRet = (IDOK == SHMessageBoxCheck(hwnd, pszStr, szTitle, MB_OKCANCEL, IDOK, TEXT("WarnBeforeCloseBand")));
  2510.             LocalFree(pszStr);
  2511.         }
  2512.         LocalFree(pszTemp2);
  2513.     }
  2514.     return bRet;
  2515. }