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

Windows Kernel

Development Platform:

Visual C++

  1. #include "priv.h"
  2. #include "sccls.h"
  3. #include "iface.h"
  4. #include "itbdrop.h"
  5. #include "sftbar.h"
  6. #include "resource.h"
  7. #include "../lib/dpastuff.h"
  8. #include "shlwapi.h"
  9. #include "cobjsafe.h"
  10. #include <iimgctx.h>
  11. #include "dbgmem.h"
  12. #include "uemapp.h"
  13. #include "mluisupp.h"
  14. extern UINT g_idFSNotify;
  15. #define TF_SFTBAR   0x10000000      // Same ID as the AugMISF stuff
  16. #define PGMP_RECALCSIZE  200
  17. // do not set CMD_ID_FIRST to 0.  we use this to see if anything is selected
  18. #define CMD_ID_FIRST    1
  19. #define CMD_ID_LAST     0x7fff
  20. CSFToolbar::CSFToolbar()
  21. {
  22. #ifdef CASCADE_DEBUG
  23.     _fCascadeFolder = TRUE;
  24. #endif
  25.     _dwStyle = TBSTYLE_TOOLTIPS;
  26.     _fDirty = TRUE; // we havn't enumerated, so our state is dirty
  27.     _fRegisterChangeNotify = TRUE;
  28.     _fAllowReorder = TRUE;
  29.     _tbim.iButton = -1;
  30.     _iDragSource = -1;
  31.     _lEvents = SHCNE_DRIVEADD|SHCNE_CREATE|SHCNE_MKDIR|SHCNE_DRIVEREMOVED|
  32.                SHCNE_DELETE|SHCNE_RMDIR|SHCNE_RENAMEITEM|SHCNE_RENAMEFOLDER|
  33.                SHCNE_MEDIAINSERTED|SHCNE_MEDIAREMOVED|SHCNE_NETUNSHARE|SHCNE_NETSHARE|
  34.                SHCNE_UPDATEITEM|SHCNE_UPDATEIMAGE|SHCNE_ASSOCCHANGED|
  35.                SHCNE_UPDATEDIR|SHCNE_EXTENDED_EVENT;
  36. }
  37. CSFToolbar::~CSFToolbar()
  38. {
  39.     ATOMICRELEASE(_pcmSF);
  40.     _ReleaseShellFolder();
  41.     ILFree(_pidl);
  42.     ASSERT(NULL == _hdpa);
  43.     if (_hwndWorkerWindow)
  44.         DestroyWindow(_hwndWorkerWindow);
  45.     OrderList_Destroy(&_hdpaOrder);
  46. }
  47. HRESULT CSFToolbar::QueryInterface(REFIID riid, void **ppvObj)
  48. {
  49.     static const QITAB qit[] = {
  50.         QITABENT(CSFToolbar, IWinEventHandler),
  51.         QITABENT(CSFToolbar, IShellChangeNotify),
  52.         QITABENT(CSFToolbar, IDropTarget),
  53.         QITABENT(CSFToolbar, IContextMenu),
  54.         QITABENT(CSFToolbar, IShellFolderBand),
  55.         { 0 },
  56.     };
  57.     return QISearch(this, qit, riid, ppvObj);
  58. }
  59. HRESULT CSFToolbar::SetShellFolder(IShellFolder* psf, LPCITEMIDLIST pidl)
  60. {
  61.     HRESULT hres = E_INVALIDARG;
  62.     // Save the old values
  63.     LPITEMIDLIST pidlSave = _pidl;
  64.     IShellFolder *psfSave = _psf;
  65.     ITranslateShellChangeNotify *ptscnSave = _ptscn;
  66.     _psf = NULL;
  67.     _pidl = NULL;
  68.     _ptscn = NULL;
  69.     
  70.     ASSERT(NULL == psf || IS_VALID_CODE_PTR(psf, IShellFolder));
  71.     ASSERT(NULL == pidl || IS_VALID_PIDL(pidl));
  72.     if (psf || pidl)
  73.     {
  74.         if (psf)
  75.         {
  76.             _psf = psf;
  77.             _psf->AddRef();
  78.             _psf->QueryInterface(IID_ITranslateShellChangeNotify, (LPVOID *)&_ptscn);
  79.         }
  80.             
  81.         if (pidl)
  82.             _pidl = ILClone(pidl);
  83.         hres = S_OK;
  84.     }
  85.     if (SUCCEEDED(hres))
  86.     {
  87.         ILFree(pidlSave);
  88.         if (psfSave)
  89.             psfSave->Release();
  90.         if (ptscnSave)
  91.             ptscnSave->Release();
  92.     }
  93.     else
  94.     {
  95.         ASSERT(_psf == NULL);
  96.         ASSERT(_pidl == NULL);
  97.         ASSERT(_ptscn == NULL);
  98.         // we failed -- restore the old values
  99.         _psf = psfSave;
  100.         _pidl = pidlSave;
  101.         _ptscn = ptscnSave;
  102.     }
  103.     // This code is here for ShellFolderToolbar reuse. When setting a new shell folder
  104.     // into an existing band, we will refresh. Note that this is a noop on a new band.
  105.     _RememberOrder();
  106.     _SetDirty(TRUE);
  107.     if (_fShow)
  108.         _FillToolbar();
  109.     return hres;
  110. }
  111. HWND CSFToolbar::_CreatePager(HWND hwndParent)
  112. {
  113.     if (!_fMulticolumn)
  114.     {
  115.         _hwndPager = CreateWindowEx(0, WC_PAGESCROLLER, NULL,
  116.                                  WS_CHILD | WS_TABSTOP |
  117.                                  WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
  118.                                  0, 0, 0, 0, hwndParent, (HMENU) 0, HINST_THISDLL, NULL);
  119.         if (_hwndPager)
  120.         {
  121.             hwndParent = _hwndPager;
  122.         }
  123.     }
  124.     return hwndParent;
  125. }
  126. void CSFToolbar::_CreateToolbar(HWND hwndParent)
  127. {
  128.     if (!_hwndTB)
  129.     {
  130.         hwndParent = _CreatePager(hwndParent);
  131.         _hwndTB = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAME, NULL,
  132.                                  WS_VISIBLE | WS_CHILD | TBSTYLE_FLAT |
  133.                                  WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
  134.                                  CCS_NODIVIDER | CCS_NOPARENTALIGN |
  135.                                  CCS_NORESIZE | _dwStyle,
  136.                                  0, 0, 0, 0, hwndParent, (HMENU) 0, HINST_THISDLL, NULL);
  137.         if (_hwndPager)
  138.             SendMessage(_hwndPager, PGM_SETCHILD, 0, (LPARAM)_hwndTB);
  139.         if (!_hwndTB)
  140.         {
  141.             TraceMsg(TF_ERROR, "_hwndTB failed");
  142.             return;
  143.         }
  144.         
  145.         SendMessage(_hwndTB, TB_BUTTONSTRUCTSIZE,    SIZEOF(TBBUTTON), 0);
  146.         // Set the format to ANSI or UNICODE as appropriate.
  147.         ToolBar_SetUnicodeFormat(_hwndTB, DLL_IS_UNICODE);
  148.         if (_hwndPager)
  149.         {
  150.             // Set the format to ANSI or UNICODE as appropriate.
  151.             ToolBar_SetUnicodeFormat(_hwndPager, DLL_IS_UNICODE);
  152.         }
  153.         
  154. #if 0 // Not going to do this for IE5.
  155.         ToolBar_SetExtendedStyle(_hwndTB, 
  156.             TBSTYLE_EX_HIDECLIPPEDBUTTONS, 
  157.             TBSTYLE_EX_HIDECLIPPEDBUTTONS);
  158. #endif
  159.         // Make sure we're on the same wavelength.
  160.         SendMessage(_hwndTB, CCM_SETVERSION, COMCTL32_VERSION, 0);
  161.         RECT rc;
  162.         SIZE size;
  163.         SystemParametersInfoA(SPI_GETWORKAREA, SIZEOF(RECT), &rc, FALSE);
  164.         if (!_hwndPager)
  165.         {
  166.             size.cx = RECTWIDTH(rc);
  167.             size.cy = GetSystemMetrics(SM_CYSCREEN) - (2 * GetSystemMetrics(SM_CYEDGE));    // Need to subrtact off the borders
  168.         }
  169.         else
  170.         {
  171.             //HACKHACK:  THIS WILL FORCE NO WRAP TO HAPPEN FOR PROPER WIDTH CALC WHEN PAGER IS PRESENT.
  172.             size.cx = RECTWIDTH(rc);
  173.             size.cy = 32000;
  174.         }
  175.         ToolBar_SetBoundingSize(_hwndTB, &size);
  176.     }
  177.     else
  178.     {
  179.         if (_hwndPager && GetParent(_hwndPager) != hwndParent)
  180.             SetParent(_hwndPager, hwndParent);
  181.     }
  182.     if (FAILED(_GetTopBrowserWindow(&_hwndDD)))
  183.         _hwndDD = GetParent(_hwndTB);
  184. }
  185. #define MAX_COMMANDID 0xFFFF // We're allowed one word of command ids (tested at 5)
  186. int  CSFToolbar::_GetCommandID()
  187. {
  188.     int id = -1;
  189.     if (!_fCheckIds)
  190.     {
  191.         id = _nNextCommandID++;
  192.     }
  193.     else
  194.     {
  195.         // We are reusing command ids and must verify that
  196.         // the current one is not in use. This is slow, but
  197.         // I assume the number of buttons on one of these
  198.         // bands is relatively few.
  199.         //
  200.         for (int i = 0 ; i <= MAX_COMMANDID ; i++)
  201.         {
  202.             TBBUTTONINFO tbbiDummy;
  203.             tbbiDummy.cbSize = SIZEOF(tbbiDummy);
  204.             tbbiDummy.dwMask = 0; // we don't care about data, just existence
  205.             if (-1 != ToolBar_GetButtonInfo(_hwndTB, _nNextCommandID, &tbbiDummy))
  206.             {
  207.                 // A button by this id wasn't found, so the id must be free
  208.                 //
  209.                 id = _nNextCommandID++;
  210.                 break;
  211.             }
  212.             _nNextCommandID++;
  213.             _nNextCommandID %= MAX_COMMANDID;
  214.         }
  215.     }
  216.     if (_nNextCommandID > MAX_COMMANDID)
  217.     {
  218.         _nNextCommandID = 0;
  219.         _fCheckIds = TRUE;
  220.     }
  221.     return(id);
  222. }
  223. /*----------------------------------------------------------
  224. Purpose: This function determines the toolbar button style for the
  225.          given pidl.  
  226.          Returns S_OK if pdwMIFFlags is also set (i.e., the object
  227.          supported IMenuBandItem to provide more info).  S_FALSE if only
  228.          *pdwTBStyle is set.
  229. */
  230. HRESULT CSFToolbar::_TBStyleForPidl(LPCITEMIDLIST pidl, 
  231.                                    DWORD * pdwTBStyle, DWORD* pdwTBState, DWORD * pdwMIFFlags,int* piIcon)
  232. {
  233.     HRESULT hres = S_FALSE;
  234.     DWORD dwStyle = TBSTYLE_BUTTON;
  235.     if (!_fAccelerators)
  236.         dwStyle |= TBSTYLE_NOPREFIX;
  237.     *pdwMIFFlags = 0;
  238.     *pdwTBStyle = dwStyle;
  239.     *piIcon = -1;
  240.     *pdwTBState = TBSTATE_ENABLED;
  241.     return hres;
  242. }
  243. PIBDATA CSFToolbar::_CreateItemData(PORDERITEM poi)
  244. {
  245.     return new IBDATA(poi);
  246. }
  247. PIBDATA CSFToolbar::_AddOrderItemTB(PORDERITEM poi, int index, TBBUTTON* ptbb)
  248. {
  249.     TCHAR szName[MAX_PATH];
  250.     // We need to do this even for NULL because _ObtainPIDLName cooks
  251.     // up the word "(Empty)" as necessary.
  252.     _ObtainPIDLName(poi ? poi->pidl : NULL, szName, SIZECHARS(szName));
  253.     TBBUTTON tbb = {0};
  254.     DWORD dwMIFFlags;
  255.     DWORD dwStyle;
  256.     DWORD dwState;
  257.     int iIcon;
  258.     int iCommandID = _GetCommandID();
  259.     BOOL bNoIcon = FALSE;
  260.     if (!ptbb)
  261.         ptbb = &tbb;
  262.     if (S_OK == _TBStyleForPidl(poi ? poi->pidl : NULL, &dwStyle, &dwState, &dwMIFFlags,&iIcon) &&
  263.         !(dwMIFFlags & SMIF_ICON))
  264.     {
  265.         bNoIcon = TRUE;
  266.     }
  267.     PIBDATA pibdata = _CreateItemData(poi);
  268.     if (pibdata)
  269.     {
  270.         pibdata->SetFlags(dwMIFFlags);
  271.         pibdata->SetNoIcon(bNoIcon);
  272.         if(!bNoIcon && iIcon != -1)
  273.             ptbb->iBitmap = iIcon;
  274.         else
  275.             ptbb->iBitmap = I_IMAGECALLBACK;
  276.         ptbb->idCommand = iCommandID;
  277.         ptbb->fsState = (BYTE)dwState;
  278.         ptbb->fsStyle = (BYTE)dwStyle;
  279.         ptbb->dwData = (DWORD_PTR)pibdata;
  280.         ptbb->iString = (INT_PTR)szName;
  281.         // Disregard variablewidth if we are vertical
  282.         if (_fVariableWidth && !_fVertical)
  283.             ptbb->fsStyle |= TBSTYLE_AUTOSIZE;
  284.         if (ptbb->idCommand != -1)
  285.         {
  286.             if (SendMessage(_hwndTB, TB_INSERTBUTTON, index, (LPARAM)ptbb))
  287.             {
  288.                 TraceMsg(TF_BAND, "SFToolbar::_AddPidl %d 0x%x [%s]", ptbb->idCommand, ptbb->dwData, ptbb->iString);                                    
  289.             } 
  290.             else 
  291.             {
  292.                 delete pibdata;
  293.                 pibdata = NULL;
  294.             }
  295.         }
  296.     }
  297.     return pibdata;
  298. }
  299. void CSFToolbar::_ObtainPIDLName(LPCITEMIDLIST pidl, LPTSTR psz, int cchMax)
  300. {
  301.     STRRET strret;
  302.     
  303.     if SUCCEEDED(_psf->GetDisplayNameOf(pidl, SHGDN_NORMAL, &strret))
  304.     {
  305.         StrRetToBuf(&strret, pidl, psz, cchMax);
  306.     }
  307. }
  308. int CSFToolbar::_GetBitmap(int iCommandID, PIBDATA pibdata, BOOL fUseCache)
  309. {
  310.     int iBitmap;
  311.     if(_fNoIcons || pibdata->GetNoIcon())
  312.         iBitmap = -1;
  313.     else
  314.     {
  315.         iBitmap = OrderItem_GetSystemImageListIndex(pibdata->GetOrderItem(), _psf, fUseCache);
  316.     }
  317.     return iBitmap;
  318. }
  319. void CSFToolbar::_OnGetDispInfo(LPNMHDR pnm, BOOL fUnicode) 
  320. {
  321.     LPNMTBDISPINFO pdi = (LPNMTBDISPINFO)pnm;
  322.     PIBDATA pibdata = (PIBDATA)pdi->lParam;
  323.     LPITEMIDLIST pidl = pibdata->GetPidl();
  324.     
  325.     if(pdi->dwMask & TBNF_IMAGE) 
  326.     {
  327.         pdi->iImage = _GetBitmap(pdi->idCommand, pibdata, TRUE);
  328.     }
  329.     
  330.     if(pdi->dwMask & TBNF_TEXT) {
  331.         if(pdi->pszText) {
  332.             if(fUnicode) {
  333.                 pdi->pszText[0] = TEXT('');
  334.             }else {
  335.                 pdi->pszText[0] = 0;
  336.             }
  337.         }
  338.     }
  339.     pdi->dwMask |= TBNF_DI_SETITEM;
  340.     return;
  341.    
  342. }
  343. // Adds pidl as a new button, handles ILFree(pidl) for the caller
  344. //
  345. BOOL CSFToolbar::_AddPidl(LPITEMIDLIST pidl, int index)
  346. {
  347.     if (_hdpa)
  348.     {
  349.         PORDERITEM poi = OrderItem_Create(pidl, index);
  350.         if (poi)
  351.         {
  352.             int iPos = DPA_InsertPtr(_hdpa, index, poi);
  353.             if (-1 != iPos)
  354.             {
  355.                 // If we did not load an order, then new items should
  356.                 // show up alphabetically in the list, not at the bottom.
  357.                 if (!_fHasOrder)
  358.                 {
  359.                     // Sort by name
  360.                     _SortDPA(_hdpa);
  361.                     // Find the index of the order item. We use this index as
  362.                     // the toolbar insert index.
  363.                     index = DPA_GetPtrIndex(_hdpa, poi);
  364.                 }
  365.                 if (_AddOrderItemTB(poi, index, NULL))
  366.                 {
  367.                     return TRUE;
  368.                 }
  369.                 
  370.                 DPA_DeletePtr(_hdpa, iPos);
  371.             }
  372.             OrderItem_Free(poi);
  373.             return FALSE;
  374.         }
  375.     }
  376.     ILFree(pidl);
  377.     return FALSE;
  378. }
  379. BOOL CSFToolbar::_FilterPidl(LPCITEMIDLIST pidl)
  380. {
  381.     return FALSE;
  382. }
  383. void CSFToolbar::s_NewItem(LPVOID pvParam, LPCITEMIDLIST pidl)
  384. {
  385.     CSFToolbar* psft = (CSFToolbar*)pvParam;
  386.     psft->v_NewItem(pidl);
  387. }
  388. HRESULT CSFToolbar::_GetIEnumIDList(DWORD dwEnumFlags, IEnumIDList **ppenum)
  389. {
  390.     ASSERT(_psf);
  391.     // Pass in a NULL hwnd so the enumerator does not show any UI while
  392.     // we're filling a band.    
  393.     return IShellFolder_EnumObjects(_psf, NULL, dwEnumFlags, ppenum);
  394. }
  395. void CSFToolbar::_FillDPA(HDPA hdpa, HDPA hdpaSort, DWORD dwEnumFlags)
  396. {
  397.     IEnumIDList* penum;
  398.     if (!_psf)
  399.         return;
  400.     if (SUCCEEDED(_GetIEnumIDList(dwEnumFlags, &penum)))
  401.     {
  402.         LPITEMIDLIST pidl;
  403.         ULONG ul;
  404.         while (S_OK == penum->Next(1, &pidl, &ul))
  405.         {
  406.             if (_FilterPidl(pidl) || !OrderList_Append(hdpa, pidl, -1))
  407.             {
  408.                 TraceMsg(TF_MENUBAND, "SFToolbar (0x%x)::_FillDPA : Did not Add Pidl (0x%x).", this, pidl);
  409.                 ILFree(pidl);
  410.             }
  411.         }
  412.         penum->Release();
  413.     }
  414.     ORDERINFO   oinfo;
  415.     int iInsertIndex = _tbim.iButton + 1;               // This is the button where the cursor sat. 
  416.                                                         // So, We want to insert after that
  417.     if (iInsertIndex >= ToolBar_ButtonCount(_hwndTB))   // But, if it's at the end,
  418.         iInsertIndex = -1;                              // Convert the insert to an append.
  419.                                                         //      - Comments in rhyme by lamadio
  420.     oinfo.psf = _psf;
  421.     (oinfo.psf)->AddRef();
  422.     oinfo.dwSortBy = (_fHasOrder || _fDropping)? ((_fNoNameSort ? OI_SORTBYORDINAL : OI_SORTBYNAME)): OI_MERGEBYNAME;
  423.     OrderList_Merge(hdpa, hdpaSort, _fDropping ? iInsertIndex : _DefaultInsertIndex(), (LPARAM) &oinfo,
  424.         s_NewItem, (LPVOID)this);
  425.     ATOMICRELEASE(oinfo.psf);
  426. }
  427. // This function re-enumerates the IShellFolder, keeping things ordered correctly.
  428. // At some point it may reduce flicker by not removing buttons that don't change.
  429. //
  430. void CSFToolbar::_FillToolbar()
  431. {
  432.     HDPA hdpaSort;
  433.     HDPA hdpa;
  434.     if (!_fDirty)
  435.         return;
  436.     
  437.     // If we have an order array, use that, otherwise
  438.     // use the currently viewed items
  439.     if (_hdpaOrder)
  440.         hdpaSort = _hdpaOrder; // already sorted by name
  441.     else
  442.     {
  443.         hdpaSort = _hdpa;
  444.         _SortDPA(hdpaSort);
  445.     }
  446.     hdpa = DPA_Create(hdpaSort ? DPA_GetPtrCount(hdpaSort) : 12);
  447.     if (hdpa)
  448.     {
  449.         _FillDPA(hdpa, hdpaSort, SHCONTF_FOLDERS|SHCONTF_NONFOLDERS);
  450.         // NOTE: if many buttons were moved at the same time
  451.         // the notifications may be spread out as the files
  452.         // are copied and we'd only insert the first time.
  453.         // This is probably okay.
  454.         //
  455.         _fDropping = FALSE;
  456.         // For the case of dragging a new item into the band (or one
  457.         // just showing up) we could re-sort _hdpa by ordinal (which
  458.         // would match the current button order), and iterate through hdpa
  459.         // to see where a button needs to be inserted or removed.
  460.         // This would be way less flicker and toolbar painting
  461.         // than always blowing away the current buttons and reinserting them...
  462.         //
  463.         // For now be lazy and do extra work.
  464.         //
  465.         // remove buttons and replace _hdpa with hdpa
  466.         if (_hdpa)
  467.         {
  468.             EmptyToolbar();
  469.             ASSERT(!_hdpa);
  470.         }
  471.         _hdpa = hdpa;
  472.         SendMessage(_hwndTB, WM_SETREDRAW, FALSE, 0);
  473.         // add buttons back in
  474.         DEBUG_CODE( BOOL bFailed = FALSE; )
  475.         int i = 0;
  476.         while (i < DPA_GetPtrCount(_hdpa))
  477.         {
  478.             PORDERITEM poi = (PORDERITEM)DPA_FastGetPtr(_hdpa, i);
  479. //            ASSERT(bFailed || poi->nOrder == i);
  480.             if (_AddOrderItemTB(poi, -1, NULL))
  481.             {
  482.                 i++;
  483.             }
  484.             else
  485.             {
  486.                 DPA_DeletePtr(_hdpa, i);
  487.                 DEBUG_CODE( bFailed = TRUE; )
  488.             }
  489.         }
  490.                 
  491.     }
  492.     SendMessage(_hwndTB, WM_SETREDRAW, TRUE, 0);
  493.     // if we used an _hdpaOrder then we don't need it any more
  494.     OrderList_Destroy(&_hdpaOrder);
  495.     
  496.     _UpdateButtons();
  497.     _SetDirty(FALSE);
  498.     _ToolbarChanged();
  499.     TraceMsg(TF_BAND, "SFToolbar::_FillToolbar found %d items", DPA_GetPtrCount(_hdpa));
  500. }
  501. void CSFToolbar::EmptyToolbar()
  502. {
  503.     if (_hwndTB)
  504.     {
  505.         TraceMsg(TF_BAND, "SFToolbar::EmptyToolbar %d items", _hdpa ? DPA_GetPtrCount(_hdpa) : 0);
  506.         while (InlineDeleteButton(0))
  507.         {
  508.             // delete the buttons
  509.         }
  510.     }
  511.     OrderList_Destroy(&_hdpa);
  512.     _fDirty = TRUE;
  513.     
  514.     _nNextCommandID = 0;
  515. }
  516. void CSFToolbar::_SetDirty(BOOL fDirty)
  517. {
  518.     _fDirty = fDirty;
  519. }
  520. UINT CSFToolbar::_IndexToID(int iIndex)
  521. {
  522.     TBBUTTON tbb;
  523.     if (SendMessage(_hwndTB, TB_GETBUTTON, iIndex, (LPARAM)&tbb))
  524.     {
  525.         return tbb.idCommand;
  526.     }
  527.     return (UINT)-1;
  528. }
  529. // if ptbbi is specified, dwMask must be filled in
  530. //
  531. LPITEMIDLIST CSFToolbar::_GetButtonFromPidl(LPCITEMIDLIST pidl, TBBUTTONINFO * ptbbi, int * pIndex)
  532. {
  533.     int i;
  534.     if (!_hdpa)
  535.         return NULL;
  536.     for (i = DPA_GetPtrCount(_hdpa)-1 ; i >= 0 ; i--)
  537.     {
  538.         HRESULT hres;
  539.         PORDERITEM poi = (PORDERITEM)DPA_FastGetPtr(_hdpa, i);
  540.         ASSERT(poi);
  541.         if (poi->pidl) {
  542.             hres = _psf->CompareIDs(0, pidl, poi->pidl);
  543.             if (ResultFromShort(0) == hres)
  544.             {
  545.                 if (pIndex)
  546.                     *pIndex = i;
  547.                 if (ptbbi)
  548.                 {
  549.                     int id = _IndexToID(i);
  550.                     if (id != -1) {
  551.                         ptbbi->cbSize = SIZEOF(*ptbbi);
  552.                         ToolBar_GetButtonInfo(_hwndTB, id, ptbbi);
  553.                     }
  554.                     else
  555.                     {
  556.                         // What do we do on failure?
  557.                     }
  558.                 }
  559.                 return poi->pidl;
  560.             }
  561.         }
  562.     }
  563.     return NULL;
  564. }
  565. // On an add, tack the new button on the end
  566. void CSFToolbar::_OnFSNotifyAdd(LPCITEMIDLIST pidl)
  567. {
  568.     // be paranoid and make sure we don't duplicate an item
  569.     //
  570.     if (!_GetButtonFromPidl(pidl, NULL, NULL))
  571.     {
  572.         LPITEMIDLIST pidlNew;
  573.         if (_fFSNotify && !_ptscn)
  574.         {
  575.             if (FAILED(SHGetRealIDL(_psf, pidl, &pidlNew)))
  576.                 pidlNew = NULL;
  577.         }
  578.         else
  579.         {
  580.             pidlNew = ILClone(pidl);
  581.         }
  582.         if (pidlNew)
  583.         {
  584.             int index = _DefaultInsertIndex();
  585.             if (_fDropping)
  586.             {
  587.                 if (-1 == _tbim.iButton)
  588.                     index = 0; // if qlinks has no items, _tbim.iButton is -1, but you can't insert there...
  589.                 else if (_tbim.dwFlags & TBIMHT_AFTER)
  590.                     index = _tbim.iButton + 1;
  591.                 else
  592.                     index = _tbim.iButton;
  593.             }
  594.             // We need to store this as the new order because a drag and drop has occured.
  595.             // We will store this order and use it until the end of time.
  596.             if (_fDropping)
  597.             {
  598.                 _fHasOrder = TRUE;
  599.                 _fChangedOrder = TRUE;
  600.             }
  601.             _AddPidl(pidlNew, index);
  602.             OrderList_Reorder(_hdpa);
  603.            
  604.             if (_fDropping)
  605.             {
  606.                 _Dropped(index, FALSE);
  607.                 _fDropping = FALSE;
  608.             }
  609.             // BUGBUG: i'm nuking this call to SetDirty as it doesn't seem
  610.             // necessary and we don't have a matching call to _SetDirty(FALSE);
  611.             // mismatch of those calls causes nt5 bug #173868.  [tjgreen 5-15-98]
  612.             //_SetDirty(TRUE);
  613.         }
  614.     }
  615. }
  616. // This function syncronously removes the button, and deletes it's contents.
  617. // This avoids Reentrancy problems, as well as Leaks caused by unhooked toolbars
  618. BOOL_PTR CSFToolbar::InlineDeleteButton(int iIndex)
  619. {
  620.     BOOL_PTR fRet = FALSE;
  621.     TBBUTTONINFO tbbi;
  622.     tbbi.cbSize = SIZEOF(tbbi);
  623.     tbbi.dwMask = TBIF_LPARAM | TBIF_BYINDEX;
  624.     if (ToolBar_GetButtonInfo(_hwndTB, iIndex, &tbbi) >= 0)
  625.     {
  626.         PIBDATA pibdata = (PIBDATA)tbbi.lParam;
  627.         tbbi.lParam = NULL;
  628.         ToolBar_SetButtonInfo(_hwndTB, iIndex, &tbbi);
  629.         fRet = SendMessage(_hwndTB, TB_DELETEBUTTON, iIndex, 0);
  630.         if (pibdata)
  631.             delete pibdata;
  632.     }
  633.     return fRet;
  634. }
  635. // On a remove, rip out the old button and adjust existing ones
  636. void CSFToolbar::_OnFSNotifyRemove(LPCITEMIDLIST pidl)
  637. {
  638.     int i;
  639.     LPITEMIDLIST pidlButton = _GetButtonFromPidl(pidl, NULL, &i);
  640.     if (pidlButton)
  641.     {
  642.         // remove it from the DPA before nuking the button. There is a rentrancy issue here.
  643.         DPA_DeletePtr(_hdpa, i);
  644.         InlineDeleteButton(i);
  645.         ILFree(pidlButton);
  646.         _fChangedOrder = TRUE;
  647.     }
  648. }
  649. // On a rename, just change the text of the old button
  650. //
  651. void CSFToolbar::_OnFSNotifyRename(LPCITEMIDLIST pidlFrom, LPCITEMIDLIST pidlTo)
  652. {
  653.     TBBUTTONINFO tbbi;
  654.     LPITEMIDLIST pidlButton;
  655.     int i;
  656.     tbbi.dwMask = TBIF_COMMAND | TBIF_LPARAM;
  657.     pidlButton = _GetButtonFromPidl(pidlFrom, &tbbi, &i);
  658.     if (pidlButton)
  659.     {
  660.         LPITEMIDLIST pidlNew;
  661.         if (_fFSNotify && !_ptscn)
  662.         {
  663.             if (FAILED(SHGetRealIDL(_psf, pidlTo, &pidlNew)))
  664.                 pidlNew = NULL;
  665.         }
  666.         else
  667.         {
  668.             pidlNew = ILClone(pidlTo);
  669.         }
  670.         if (pidlNew)
  671.         {
  672.             LPITEMIDLIST pidlFree = pidlNew;
  673.             PORDERITEM poi = (PORDERITEM)DPA_FastGetPtr(_hdpa, i);
  674.             if (EVAL(poi))
  675.             {
  676.                 pidlFree = poi->pidl;
  677.                 poi->pidl = pidlNew;
  678.             
  679.                 STRRET strret;
  680.                 TCHAR szName[MAX_PATH];
  681.                 if (SUCCEEDED(_psf->GetDisplayNameOf(pidlNew, SHGDN_NORMAL, &strret)) &&
  682.                     SUCCEEDED(StrRetToBuf(&strret, pidlNew, szName, ARRAYSIZE(szName))))
  683.                 {
  684.                     // _GetButtonFromPidl filled in tbbi.cbSize and tbbi.idCommand
  685.                     //
  686.                     PIBDATA pibdata = (PIBDATA)tbbi.lParam;
  687.                     if (pibdata)
  688.                         pibdata->SetOrderItem(poi);
  689.                     tbbi.dwMask = TBIF_TEXT;
  690.                     tbbi.pszText = szName;
  691.                     EVAL(ToolBar_SetButtonInfo(_hwndTB, tbbi.idCommand, &tbbi));
  692.                     // Just so that it's new location gets persisted
  693.                     _fChangedOrder = TRUE;
  694.                 }
  695.             }
  696.             ILFree(pidlFree);
  697.         }
  698.     }
  699. }
  700. // On a complete update remove the old button and add it again
  701. //
  702. void CSFToolbar::_OnFSNotifyUpdate(LPCITEMIDLIST pidl)
  703. {
  704.     TBBUTTONINFO tbbi;
  705.     tbbi.dwMask = TBIF_COMMAND;
  706.     LPITEMIDLIST pidlButton = _GetButtonFromPidl(pidl, &tbbi, NULL);
  707.     if (pidlButton)
  708.     {
  709.         STRRET strret;
  710.         TCHAR szName[MAX_PATH];
  711.         if (SUCCEEDED(_psf->GetDisplayNameOf(pidlButton, SHGDN_NORMAL, &strret)) &&
  712.             SUCCEEDED(StrRetToBuf(&strret, pidlButton, szName, ARRAYSIZE(szName))))
  713.         {
  714.             int iBitmap = _GetBitmap(tbbi.idCommand, _IDToPibData(tbbi.idCommand, NULL), FALSE);
  715.             if (iBitmap >= 0)
  716.             {
  717.                 tbbi.dwMask = TBIF_IMAGE | TBIF_TEXT;
  718.                 tbbi.iImage = iBitmap;
  719.                 tbbi.pszText = szName;
  720.                 ToolBar_SetButtonInfo(_hwndTB, tbbi.idCommand, &tbbi);
  721.             }
  722.         }
  723.     }
  724. }
  725. void CSFToolbar::_Refresh()
  726. {
  727.     if (!_hdpa)
  728.         return;
  729.     _RememberOrder();
  730.     _SetDirty(TRUE);
  731.     if (_fShow)
  732.         _FillToolbar();
  733. }
  734. LRESULT CSFToolbar::_OnTimer(WPARAM wParam)
  735. {
  736.     return 0;
  737. }
  738. LRESULT CSFToolbar::_DefWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  739. {
  740.     switch (uMsg) 
  741.     {
  742.     case WM_DRAWITEM:
  743.     case WM_MEASUREITEM:
  744.     case WM_INITMENUPOPUP:
  745.     case WM_MENUSELECT:
  746.         if (_pcm2)
  747.             _pcm2->HandleMenuMsg(uMsg, wParam, lParam);
  748.         break;
  749.     case WM_MENUCHAR:
  750.         {
  751.             LRESULT lres = 0;
  752.             IContextMenu3* pcm3;
  753.             if (_pcm2 && SUCCEEDED(_pcm2->QueryInterface(IID_IContextMenu3, (void**)&pcm3)))
  754.             {
  755.                 pcm3->HandleMenuMsg2(uMsg, wParam, lParam, &lres);
  756.                 pcm3->Release();
  757.             }
  758.             return lres;
  759.         }
  760.         break;
  761.     
  762.     case WM_TIMER:
  763.         if (_OnTimer(wParam)) 
  764.         {
  765.             return 1;
  766.         }
  767.         break;
  768.     }
  769.     
  770.     return CNotifySubclassWndProc::_DefWindowProc(hwnd, uMsg, wParam, lParam);
  771. }
  772. /*----------------------------------------------------------
  773. Purpose:
  774. For future use. when renaming a parent of this shell folder
  775.  we should rebind to it and refill us.
  776. S_OK    Indicates successful handling of this notification
  777. S_FALSE Indicates the notification is not a handled situation.
  778.         The caller should handle the notification in this case.
  779. Other   Failure code indicates a problem.  Caller should abort
  780.         operation or handle the notification itself.
  781. */
  782. HRESULT CSFToolbar::_OnRenameFolder(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  783. {
  784.     HRESULT hres = S_FALSE;
  785. #if 0
  786.     // This code is just busted. It was for the case when we rename the parent. We don't support this
  787.     if (!_IsChildID(pidl1, FALSE) || !_IsChildID(pidl2, FALSE))
  788.     {
  789.         // Then this must be a parent of us. At this point we should rebind. The code that
  790.         // was here did not work. I've removed it so that we can recode it in the future, but
  791.         // now, we're just going to live with it
  792.         TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: RenameFolder: This is not a child folder.");
  793.         hres = S_OK;
  794.     }
  795. #endif
  796.     return hres;
  797. }
  798. HRESULT CSFToolbar::OnChange(LONG lEvent, LPCITEMIDLIST pidlOrg1, LPCITEMIDLIST pidlOrg2)
  799. {
  800.     HRESULT hres;
  801.     LPITEMIDLIST pidl1 = (LPITEMIDLIST)pidlOrg1;
  802.     LPITEMIDLIST pidl2 = (LPITEMIDLIST)pidlOrg2;
  803.     LPITEMIDLIST pidl1ToFree = NULL;        // Used if we allocate a pidl that needs to be freed. (::TranslateIDs())
  804.     LPITEMIDLIST pidl2ToFree = NULL;
  805.     LPITEMIDLIST pidlOut1Event2 = NULL;        // Used if we allocate a pidl that needs to be freed. (::TranslateIDs())
  806.     LPITEMIDLIST pidlOut2Event2 = NULL;
  807.     LONG lEvent2 = (LONG)-1;
  808.     if (_ptscn)
  809.     {
  810.         hres = _ptscn->TranslateIDs(&lEvent, pidlOrg1, pidlOrg2, &pidl1, &pidl2,
  811.                                     &lEvent2, &pidlOut1Event2, &pidlOut2Event2);
  812.             
  813.         if (FAILED(hres))
  814.             return hres;
  815.         else
  816.         {
  817.             // if pidl1 doesn't equal pidlOrg1, then pidl1 was allocated and needs to be freed.
  818.             pidl1ToFree = ((pidlOrg1 == pidl1) ? NULL : pidl1);
  819.             pidl2ToFree = ((pidlOrg2 == pidl2) ? NULL : pidl2);
  820.         }
  821.         ASSERT(NULL == pidl1 || IS_VALID_PIDL(pidl1));
  822.         ASSERT(NULL == pidl2 || IS_VALID_PIDL(pidl2));
  823.     }
  824.     hres = OnTranslatedChange(lEvent, pidl1, pidl2);
  825.     // Do we have a second event to process?
  826.     if (SUCCEEDED(hres) && lEvent2 != (LONG)-1)
  827.     {
  828.         // Yes, then go do it.
  829.         hres = OnTranslatedChange(lEvent2, pidlOut1Event2, pidlOut2Event2);
  830.     }
  831.     ILFree(pidlOut1Event2);
  832.     ILFree(pidlOut2Event2);
  833.     ILFree(pidl1ToFree);
  834.     ILFree(pidl2ToFree);
  835.     return hres;
  836. }
  837. #ifdef DEBUG
  838. void DBPrPidl(LPCSTR szPre, LPCITEMIDLIST pidl)
  839. {
  840.     TCHAR szName[MAX_PATH];
  841.     szName[0] = '';
  842.     if (pidl)
  843.         SHGetNameAndFlags(pidl, SHGDN_FORPARSING, szName, SIZECHARS(szName), NULL);
  844.     TraceMsg(TF_WARNING, "%hs%s", szPre, szName);
  845.     return;
  846. }
  847. #endif
  848. HRESULT CSFToolbar::OnTranslatedChange(LONG lEvent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  849. {
  850.     HRESULT hres = S_OK;
  851.     BOOL fSizeChanged = FALSE;
  852.     TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: lEvent=%x", lEvent);
  853.     // If we weren't given a pidl we won't register for
  854.     // SHChangeNotify calls, but our IShellChange interface
  855.     // can still be QI()d so someone could errantly call us.
  856.     //
  857.     // If we change to using QS() for IShellChange interface
  858.     // then we can put this check there...
  859.     //
  860.     if (NULL == _pidl)
  861.     {
  862.         // HACKHACK (scotth): resource-based menus (CMenuISF) don't set _pidl.
  863.         //                    Right now allow SHCNE_UPDATEDIR thru...
  864.         if (SHCNE_UPDATEDIR == lEvent)
  865.             goto HandleUpdateDir;
  866.         TraceMsg(TF_WARNING, "CSFToolbar::OnChange - _pidl is NULL");
  867.         hres = E_FAIL;
  868.         goto CleanUp;
  869.     }
  870.     if ( lEvent != SHCNE_UPDATEIMAGE && lEvent != SHCNE_RENAMEITEM && lEvent != SHCNE_RENAMEFOLDER &&
  871.          lEvent != SHCNE_UPDATEDIR && lEvent != SHCNE_MEDIAREMOVED && lEvent != SHCNE_MEDIAINSERTED &&
  872.          lEvent != SHCNE_EXTENDED_EVENT)
  873.     {
  874.         // We only handle notifications for immediate kids. (except SHCNE_RENAMEFOLDER)
  875.         //
  876.         
  877.         if (!_IsChildID(pidl1, TRUE))
  878.         {
  879.             TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Not a child. Bailing");
  880.             hres = E_FAIL;
  881.             goto CleanUp;
  882.         }
  883.     }
  884.     // This is no longer required. It also hinders us for several different notifications (Such as reorder notifies)
  885. #if 0
  886.     // If we're hidden we do not want to respond to any change notify
  887.     // messages, so we unregister the toolbar. We mark the toolbar as 
  888.     // dirty so the next time we are shown, we will reenumerate the filesystem.
  889.     if (!_fShow && !_fDropping)
  890.     {
  891.         _SetDirty(TRUE);
  892.         _UnregisterChangeNotify();
  893.         hres = E_FAIL;
  894.         goto CleanUp;
  895.     }
  896. #endif
  897.     // Have we been shown yet?
  898.     if (_hdpa == NULL)
  899.     {
  900.         // No. Well, then punt this. We'll catch it on the first enum.
  901.         hres = E_FAIL;
  902.         goto CleanUp;
  903.     }
  904.     switch (lEvent)
  905.     {
  906.     case SHCNE_EXTENDED_EVENT:
  907.         {
  908.             SHChangeDWORDAsIDList UNALIGNED * pdwidl = (SHChangeDWORDAsIDList UNALIGNED *)pidl1;
  909.             if (pdwidl->dwItem1 == SHCNEE_ORDERCHANGED)
  910.             {
  911.                 TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Reorder event");
  912.                 // Do this first so that we can say "We can handle it". This prevents the 
  913.                 // mnfolder code that works around a bug in some installers where they don't
  914.                 // send a Create Folder before the create item in that folder. It causes an
  915.                 // update dir...
  916.                 if (!pidl2 || ILIsEqual(_pidl, pidl2))
  917.                 {
  918.                     // if this reorder came from us, blow it off
  919.                     if (!SHChangeMenuWasSentByMe(this, pidl1))
  920.                     {
  921.                         // load new order stream
  922.                         _LoadOrderStream();
  923.                         // rebuild toolbar
  924.                         _SetDirty(TRUE);
  925.                         if (_fShow)
  926.                             _FillToolbar();
  927.                     }
  928.                     hres = S_OK;
  929.                 }
  930.             }
  931.         }
  932.         break;
  933.     case SHCNE_DRIVEADD:
  934.     case SHCNE_CREATE:
  935.     case SHCNE_MKDIR:
  936.         TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Adding item");
  937.         pidl1 = ILFindLastID(pidl1);
  938.         _OnFSNotifyAdd(pidl1);
  939.         fSizeChanged = TRUE;
  940.         break;
  941.     case SHCNE_DRIVEREMOVED:
  942.     case SHCNE_DELETE:
  943.     case SHCNE_RMDIR:
  944.         TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Removing item");
  945.         pidl1 = ILFindLastID(pidl1);
  946.         _OnFSNotifyRemove(pidl1);
  947.         fSizeChanged = TRUE;
  948.         break;
  949.     case SHCNE_RENAMEFOLDER:
  950.         TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: RenameFolder");
  951.         // Break if notif is handled or if this is not for our kid.
  952.         //
  953.         hres = _OnRenameFolder(pidl1, pidl2);
  954.         if (S_OK == hres)
  955.         {
  956.             fSizeChanged = TRUE;
  957.             break;
  958.         }
  959.         TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: RenameFolder Falling through to RenameItem");
  960.         // fall through
  961.     case SHCNE_RENAMEITEM:
  962.     {
  963.         TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: RenameItem");
  964.         BOOL fOurKid1, fOurKid2;
  965.         LPCITEMIDLIST p1 = pidl1;
  966.         LPCITEMIDLIST p2 = pidl2;
  967.         pidl1 = ILFindLastID(pidl1);
  968.         pidl2 = ILFindLastID(pidl2);
  969.         // An item can be renamed out of this folder.
  970.         // Convert that into a remove.
  971.         //
  972.         fOurKid1 = _IsChildID(p1, TRUE);
  973.         fOurKid2 = _IsChildID(p2, TRUE);
  974.         if (fOurKid1 && fOurKid2)
  975.         {
  976.             TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Rename: Both are children");
  977.             _OnFSNotifyRename(pidl1, pidl2);
  978.             fSizeChanged = TRUE;
  979.             hres = S_OK;
  980.             break;
  981.         }
  982.         else if (fOurKid1)
  983.         {
  984.             TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Rename: Only one is a child. Removing pidl 1");
  985.             _OnFSNotifyRemove(pidl1);
  986.             fSizeChanged = TRUE;
  987.             break;
  988.         }
  989.         else if (fOurKid2)
  990.         {
  991.             // An item can be renamed into this folder.
  992.             // Convert that into an add.
  993.             //
  994.             TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Rename: Only one is a child. Adding pidl2");
  995.             _OnFSNotifyAdd(pidl2);
  996.             fSizeChanged = TRUE;
  997.             break;
  998.         }
  999.         else 
  1000.         {
  1001.             // (we get here for guys below us who we don't care about,
  1002.             // and also for the fallthru from SHCNE_RENAMEFOLDER)
  1003.             TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Rename: Not our children");
  1004.             /*NOTHING*/
  1005.             hres = E_FAIL;
  1006.         }
  1007.         break;
  1008.     }
  1009.     case SHCNE_MEDIAINSERTED:
  1010.     case SHCNE_MEDIAREMOVED:
  1011.     case SHCNE_NETUNSHARE:
  1012.         if (_IsEqualID(pidl1))
  1013.             goto HandleUpdateDir;
  1014.     case SHCNE_NETSHARE:
  1015.     case SHCNE_UPDATEITEM:
  1016.         
  1017.         if (_IsChildID(pidl1, TRUE)) 
  1018.         {
  1019.             pidl1 = ILFindLastID(pidl1);
  1020.             _OnFSNotifyUpdate(pidl1);
  1021.             fSizeChanged = TRUE;
  1022.         }
  1023.         break;
  1024.     case SHCNE_UPDATEDIR:
  1025.         // in OnChange we picked off update dir notify and we didn't translate ids
  1026.         // now we can use ILIsEqual -- translate ids won't translate pidls in case
  1027.         // of update dir because it looks for immediate child of its, and fails when
  1028.         // it receives its own pidl
  1029.         // NOTE: When sftbar is registered recursivly, we only get the pidl of the
  1030.         // top pane. It is forwarded down to the children. Since this is now a "Child"
  1031.         // of the top pane, we check to see if this pidl is a child of that pidl, hence the
  1032.         // ILIsParent(pidl1, _pidl)
  1033.         // HACKHACK, HUGE HACK: normaly w/ update dir pidl2 is NULL but in start menu
  1034.         // augmergeisf can change some other notify (e.g. rename folder) to update dir
  1035.         // in which case pidl2 is not null and we have to see if it is our child to do the
  1036.         // update (11/18/98) reljai
  1037.         if (_IsEqualID(pidl1) ||                    // Calling UpdateDir on _THIS_ folder
  1038.             _IsChildID(pidl1, FALSE) ||             // BUGBUG (lamadio) Is this needed?
  1039.             (pidl2 && _IsChildID(pidl2, FALSE)) ||  // A changed to update (see comment)
  1040.             _IsParentID(pidl1))                     // Some parent in the chain (because it's recursive)
  1041.         {
  1042. HandleUpdateDir:
  1043.             // NOTE: if a series of UPDATEIMAGE notifies gets
  1044.             //       translated to UPDATEDIR and we flicker-perf
  1045.             //       _FillToolbar, we may lose image updates
  1046.             //       (in which case, _Refresh would fix it)
  1047.             //
  1048.             TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: ******* Evil Update Dir *******");
  1049.             _Refresh();
  1050.             // don't set this here because filltoolbar will update
  1051.             //fSizeChanged = TRUE;
  1052.         }
  1053.         break;
  1054.     case SHCNE_ASSOCCHANGED:
  1055.         IEInvalidateImageList();    // We may need to use different icons.
  1056.         _Refresh(); // full refresh for now.
  1057.         break;
  1058.     case SHCNE_UPDATEIMAGE: // global
  1059.         if (pidl1)
  1060.         {
  1061.             int iImage = *(int UNALIGNED *)((BYTE *)pidl1 + 2);
  1062.             IEInvalidateImageList();    // We may need to use different icons.
  1063.             if ( pidl2 )
  1064.             {
  1065.                 iImage = SHHandleUpdateImage( pidl2 );
  1066.                 if ( iImage == -1 )
  1067.                 {
  1068.                     break;
  1069.                 }
  1070.             }
  1071.             
  1072.             if (iImage == -1 || TBHasImage(_hwndTB, iImage))
  1073.                 _Refresh();
  1074.         } else
  1075.             _Refresh();
  1076.         // BUGBUG do we need an _UpdateButtons and fSizeChanged?
  1077.         break;
  1078.     default:
  1079.         hres = E_FAIL;
  1080.         break;
  1081.     }
  1082.     if (fSizeChanged)
  1083.     {
  1084.         if (_hwndPager)
  1085.             SendMessage(_hwndPager, PGMP_RECALCSIZE, (WPARAM) 0, (LPARAM) 0);
  1086.         _ToolbarChanged();
  1087.     }
  1088. CleanUp:
  1089.     return hres;
  1090. }
  1091. BOOL TBHasImage(HWND hwnd, int iImageIndex)
  1092. {
  1093.     BOOL fRefresh = FALSE;
  1094.     for (int i = ToolBar_ButtonCount(hwnd) - 1 ; i >= 0 ; i--)
  1095.     {
  1096.         TBBUTTON tbb;
  1097.         if (SendMessage(hwnd, TB_GETBUTTON, i, (LPARAM)&tbb)) 
  1098.         {
  1099.             if (tbb.iBitmap == iImageIndex) 
  1100.             {
  1101.                 fRefresh = TRUE;
  1102.                 break;
  1103.             }
  1104.         }
  1105.     }
  1106.     return fRefresh;
  1107. }
  1108. void CSFToolbar::_SetToolbarState()
  1109. {
  1110.     SHSetWindowBits(_hwndTB, GWL_STYLE, TBSTYLE_LIST, 
  1111.                   (_uIconSize != ISFBVIEWMODE_SMALLICONS || _fNoShowText) ? 0 : TBSTYLE_LIST);
  1112. }
  1113. int CSFToolbar::_DefaultInsertIndex()
  1114. {
  1115.     return DA_LAST;
  1116. }
  1117. BOOL CSFToolbar::_IsParentID(LPCITEMIDLIST pidl)
  1118. {
  1119.     // Is the pidl passed in a parent of one of the IDs in the namespace
  1120.     // or the only one i've got?
  1121.     if (_ptscn)
  1122.         return S_OK == _ptscn->IsEqualID(NULL, pidl);
  1123.     else
  1124.         return ILIsParent(pidl, _pidl, FALSE);
  1125. }
  1126. BOOL CSFToolbar::_IsEqualID(LPCITEMIDLIST pidl)
  1127. {
  1128.     if (_ptscn)
  1129.         return S_OK == _ptscn->IsEqualID(pidl, NULL);
  1130.     else
  1131.         return ILIsEqual(_pidl, pidl);
  1132. }
  1133. BOOL CSFToolbar::_IsChildID(LPCITEMIDLIST pidlChild, BOOL fImmediate)
  1134. {
  1135.     if (_ptscn)
  1136.         return S_OK == _ptscn->IsChildID(pidlChild, fImmediate);
  1137.     else
  1138.         return ILIsParent(_pidl, pidlChild, fImmediate);
  1139. }
  1140. void CSFToolbar::v_CalcWidth(int* pcxMin, int* pcxMax)
  1141. {
  1142.     ASSERT(IS_VALID_WRITE_PTR(pcxMin, int));
  1143.     ASSERT(IS_VALID_WRITE_PTR(pcxMax, int));
  1144.     // Calculate a decent button width given current state
  1145.     HIMAGELIST himl;
  1146.     int cxMax = 0;
  1147.     int cxMin = 0;
  1148.     himl = (HIMAGELIST)SendMessage(_hwndTB, TB_GETIMAGELIST, 0, 0);
  1149.     if (himl)
  1150.     {
  1151.         int cy;
  1152.         // Start with the width of the button
  1153.         ImageList_GetIconSize(himl, &cxMax, &cy);
  1154.         // We want at least a bit of space around the icon
  1155.         if (_uIconSize != ISFBVIEWMODE_SMALLICONS)
  1156.             cxMax += 20;
  1157.         else 
  1158.             cxMax += 4 * GetSystemMetrics(SM_CXEDGE);
  1159.     }
  1160.     // Add in any additional space needed
  1161.     // Text takes up a bit more space
  1162.     if (!_fNoShowText)
  1163.     {
  1164.         cxMax += 20;
  1165.         // Horizontal text takes up a lot
  1166.         // if we're smallicon with text (horizontal button)
  1167.         // mode, use the minimized metric to mimic the taskbar
  1168.         if (_uIconSize == ISFBVIEWMODE_SMALLICONS)
  1169.             cxMax = GetSystemMetrics(SM_CXMINIMIZED);
  1170.     }
  1171.     *pcxMin = cxMin;
  1172.     *pcxMax = cxMax;
  1173. }
  1174. // Adjust buttons based on current state.
  1175. //
  1176. void CSFToolbar::_UpdateButtons()
  1177. {
  1178.     if (_hwndTB)
  1179.     {
  1180.         // set "list" (text on right) or not (text underneath)
  1181.         // NOTE: list mode always displays some text, don't do it if no text
  1182.         _SetToolbarState();
  1183.         v_CalcWidth(&_cxMin, &_cxMax);
  1184.         SendMessage(_hwndTB, TB_SETBUTTONWIDTH, 0, MAKELONG(_cxMin, _cxMax));
  1185.         // We just changed the layout
  1186.         //
  1187.         SendMessage(_hwndTB, TB_AUTOSIZE, 0, 0);
  1188.         if (_hwndPager)
  1189.         {
  1190.             LRESULT lButtonSize = SendMessage(_hwndTB, TB_GETBUTTONSIZE, 0, 0);
  1191.             Pager_SetScrollInfo(_hwndPager, 50, 1, HIWORD(lButtonSize));
  1192.             SendMessage(_hwndPager, PGMP_RECALCSIZE, (WPARAM) 0, (LPARAM) 0);
  1193.         }
  1194.     }
  1195. }
  1196. /*----------------------------------------------------------
  1197. Purpose: Helper function that calls IShellFolder::GetUIObjectOf().
  1198. Returns: pointer to the requested interface
  1199.          NULL if failed
  1200. */
  1201. LPVOID CSFToolbar::_GetUIObjectOfPidl(LPCITEMIDLIST pidl, REFIID riid)
  1202. {
  1203.     LPCITEMIDLIST * apidl = &pidl;
  1204.     LPVOID pv;
  1205.     if (FAILED(_psf->GetUIObjectOf(GetHWNDForUIObject(), 1, apidl, riid, 0, &pv)))
  1206.     {
  1207.         pv = NULL;
  1208.     }
  1209.     return(pv);
  1210. }
  1211. INT_PTR CALLBACK CSFToolbar::_RenameDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1212. {
  1213.     switch (uMsg)
  1214.     {
  1215.     case WM_INITDIALOG:
  1216.     {
  1217.         ASSERT(lParam);
  1218.         SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  1219.         EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
  1220.         // cross-lang platform support
  1221.         SHSetDefaultDialogFont(hDlg, IDD_NAME);
  1222.         HWND hwndEdit = GetDlgItem(hDlg, IDD_NAME);
  1223.         SendMessage(hwndEdit, EM_LIMITTEXT, MAX_PATH - 1, 0);
  1224.         TCHAR szText[MAX_PATH + 80];
  1225.         TCHAR szTemplate[80];
  1226.         HWND hwndLabel = GetDlgItem(hDlg, IDD_PROMPT);
  1227.         GetWindowText(hwndLabel, szTemplate, ARRAYSIZE(szTemplate));
  1228.         wnsprintf(szText, ARRAYSIZE(szText), szTemplate, lParam);
  1229.         SetWindowText(hwndLabel, szText);
  1230.         SetWindowText(hwndEdit, (LPTSTR)lParam);
  1231.         break;
  1232.     }
  1233.     case WM_DESTROY:
  1234.         SHRemoveDefaultDialogFont(hDlg);
  1235.         return FALSE;
  1236.     case WM_COMMAND:
  1237.         switch (GET_WM_COMMAND_ID(wParam, lParam))
  1238.         {
  1239.         case IDD_NAME:
  1240.         {
  1241.             if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_UPDATE)
  1242.             {
  1243.                 LPTSTR lpstrName = (LPTSTR) GetWindowLongPtr(hDlg, DWLP_USER);
  1244.                 EnableOKButtonFromID(hDlg, IDD_NAME);
  1245.                 GetDlgItemText(hDlg, IDD_NAME, lpstrName, MAX_PATH);
  1246.             }
  1247.             break;
  1248.         }
  1249.         case IDOK:
  1250.         {
  1251.             TCHAR  pszTmp[MAX_PATH];
  1252.             StrCpy(pszTmp, (LPTSTR) GetWindowLongPtr(hDlg, DWLP_USER));
  1253.             if (PathCleanupSpec(NULL,pszTmp))
  1254.             {
  1255.                HWND hwnd;
  1256.                MLShellMessageBox(hDlg,
  1257.                                  MAKEINTRESOURCE(IDS_FAVS_INVALIDFN),
  1258.                                  MAKEINTRESOURCE(IDS_FAVS_ADDTOFAVORITES), MB_OK | MB_ICONHAND);
  1259.                hwnd = GetDlgItem(hDlg, IDD_NAME);
  1260.                SetWindowText(hwnd, TEXT(''));
  1261.                EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
  1262.                SetFocus(hwnd);
  1263.                break;
  1264.             }
  1265.         }
  1266.         // fall through
  1267.         case IDCANCEL:
  1268.             EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam));
  1269.             break;
  1270.         default:
  1271.             return FALSE;
  1272.         }
  1273.         break;
  1274.     default:
  1275.         return FALSE;
  1276.     }
  1277.     return TRUE;
  1278. }
  1279. // This window proc is used for a temporary worker window that is used to position dialogs 
  1280. // as well as maintain the correct Z-Order
  1281. // NOTE: This is used in mnfolder as well.
  1282. LRESULT CALLBACK HiddenWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1283. {
  1284.     switch(uMsg)
  1285.     {
  1286.         // Make sure activation tracks back to the parent.
  1287.     case WM_ACTIVATE:
  1288.         {
  1289.             if (WA_ACTIVE != LOWORD(wParam))
  1290.                 goto DefWnd;
  1291.             SetActiveWindow(GetParent(hwnd));
  1292.             return FALSE;
  1293.         }
  1294.     }
  1295. DefWnd:
  1296.     return DefWindowProc(hwnd, uMsg, wParam, lParam);
  1297. }
  1298. HWND CSFToolbar::CreateWorkerWindow()
  1299. {
  1300.     if (!_hwndWorkerWindow)
  1301.     {
  1302.         _hwndWorkerWindow = SHCreateWorkerWindow(HiddenWndProc, GetHWNDForUIObject(), WS_EX_TOOLWINDOW /*| WS_EX_TOPMOST */, WS_POPUP, 0, _hwndTB);
  1303.     }
  1304.     return _hwndWorkerWindow;
  1305. }
  1306. HRESULT CSFToolbar::_OnRename(POINT *ppt, int id)
  1307. {
  1308.     ASSERT(_psf);
  1309.     
  1310.     TCHAR szName[MAX_PATH];
  1311.     LPCITEMIDLIST pidl = _IDToPidl(id);
  1312.     
  1313.     _ObtainPIDLName(pidl, szName, ARRAYSIZE(szName));
  1314.     // create a temp window so that placement of the dialog will be close to the point.
  1315.     // do this so that we'll use USER's code to get placement correctly w/ respect to multimon and work area
  1316.     _hwndWorkerWindow = CreateWorkerWindow();
  1317.     SetWindowPos(_hwndWorkerWindow, NULL, ppt->x, ppt->y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
  1318.     while (1) 
  1319.     {
  1320.         if (DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(DLG_ISFBANDRENAME), _hwndWorkerWindow, _RenameDlgProc, (LPARAM)szName) != IDOK) 
  1321.             break;
  1322.         WCHAR wsz[MAX_PATH];
  1323.         SHTCharToUnicode(szName, wsz, ARRAYSIZE(wsz));
  1324.         if (SUCCEEDED(_psf->SetNameOf(_hwndWorkerWindow, pidl, wsz, 0, NULL))) 
  1325.         {
  1326.             SHChangeNotifyHandleEvents();
  1327.             _SaveOrderStream();
  1328.             break;
  1329.         }
  1330.     }
  1331.     return S_OK;
  1332. }
  1333. BOOL CSFToolbar::_UpdateIconSize(UINT uIconSize, BOOL fUpdateButtons)
  1334. {
  1335.     BOOL fChanged = (_uIconSize != uIconSize);
  1336.     
  1337.     _uIconSize = uIconSize;
  1338.     TraceMsg(TF_BAND, "ISFBand::_UpdateIconSize going %hs", (_uIconSize == ISFBVIEWMODE_LARGEICONS ? "LARGE" : (_uIconSize == ISFBVIEWMODE_SMALLICONS ? "SMALL" : "LOGOS")));
  1339.     if (_hwndTB)
  1340.     {
  1341.         HIMAGELIST himl = NULL;
  1342.         if (!_fNoIcons)
  1343.         {
  1344.             HIMAGELIST himlLarge, himlSmall;
  1345.             // set the imagelist size
  1346.             Shell_GetImageLists(&himlLarge, &himlSmall);
  1347.             himl = (_uIconSize == ISFBVIEWMODE_LARGEICONS ) ? himlLarge : himlSmall;
  1348.         }
  1349.         // sending a null himl is significant..  it means no image list
  1350.         SendMessage(_hwndTB, TB_SETIMAGELIST, 0, (LPARAM)himl);
  1351.                 
  1352.         if (fUpdateButtons)
  1353.             _UpdateButtons();
  1354.     }
  1355.     
  1356.     return fChanged;
  1357. }
  1358. HMENU CSFToolbar::_GetContextMenu(IContextMenu* pcm, int* pid)
  1359. {
  1360.     HMENU hmenu = CreatePopupMenu();
  1361.     if (hmenu) {
  1362.         UINT fFlags = CMF_CANRENAME;
  1363.         if (0 > GetKeyState(VK_SHIFT))
  1364.             fFlags |= CMF_EXTENDEDVERBS;
  1365.         pcm->QueryContextMenu(hmenu, 0, *pid, CMD_ID_LAST, fFlags);
  1366.     }
  1367.     return hmenu;
  1368. }
  1369. void CSFToolbar::_OnDefaultContextCommand(int idCmd)
  1370. {
  1371. }
  1372. HRESULT CSFToolbar::_GetTopBrowserWindow(HWND* phwnd)
  1373. {
  1374.     IUnknown * punkSite;
  1375.     HRESULT hr = IUnknown_GetSite(SAFECAST(this, IWinEventHandler*), IID_IUnknown, (void**)&punkSite);
  1376.     if (SUCCEEDED(hr))
  1377.     {
  1378.         hr = SHGetTopBrowserWindow(punkSite, phwnd);
  1379.         punkSite->Release();
  1380.     }
  1381.     return hr;
  1382. }
  1383. HRESULT CSFToolbar::_OnOpen(int id, BOOL fExplore)
  1384. {
  1385.     HRESULT hr = E_FAIL;
  1386.     LPCITEMIDLIST pidl = _IDToPidl(id);
  1387.     if (pidl)
  1388.     {
  1389.         IUnknown* punkSite;
  1390.         hr = IUnknown_GetSite(SAFECAST(this, IWinEventHandler*), IID_IUnknown, (void**)&punkSite);
  1391.         if (SUCCEEDED(hr))
  1392.         {
  1393.             DWORD dwFlags = SBSP_DEFBROWSER | SBSP_DEFMODE;
  1394.             if (fExplore)
  1395.                 dwFlags |= SBSP_EXPLOREMODE;
  1396.             hr = SHNavigateToFavorite(_psf, pidl, punkSite, dwFlags);
  1397.             punkSite->Release();
  1398.         }
  1399.     }
  1400.     return hr;
  1401. }
  1402. HRESULT CSFToolbar::_HandleSpecialCommand(IContextMenu* pcm, PPOINT ppt, int id, int idCmd)
  1403. {
  1404.     TCHAR szCommandString[40];
  1405.     HRESULT hres = ContextMenu_GetCommandStringVerb(pcm,
  1406.         idCmd,
  1407.         szCommandString,
  1408.         ARRAYSIZE(szCommandString));
  1409.     if (SUCCEEDED(hres))
  1410.     {
  1411.         if (lstrcmpi(szCommandString, TEXT("rename")) == 0)
  1412.             return _OnRename(ppt, id);
  1413.         else if (lstrcmpi(szCommandString, TEXT("open")) == 0)
  1414.             return _OnOpen(id, FALSE);
  1415.         else if (lstrcmpi(szCommandString, TEXT("explore")) == 0)
  1416.             return _OnOpen(id, TRUE);
  1417.     }
  1418.     return S_FALSE;
  1419. }
  1420. LRESULT CSFToolbar::_DoContextMenu(IContextMenu* pcm, LPPOINT ppt, int id, LPRECT prcExclude)
  1421. {
  1422.     LRESULT lres = 0;
  1423.     int idCmdFirst = CMD_ID_FIRST;
  1424.     HMENU hmContext = _GetContextMenu(pcm, &idCmdFirst);
  1425.     if (hmContext)
  1426.     {
  1427.         int idCmd;
  1428.         if (_hwndToolTips)
  1429.             SendMessage(_hwndToolTips, TTM_ACTIVATE, FALSE, 0L);
  1430.         TPMPARAMS tpm;
  1431.         TPMPARAMS * ptpm = NULL;
  1432.         if (prcExclude)
  1433.         {
  1434.             tpm.cbSize = SIZEOF(tpm);
  1435.             tpm.rcExclude = *((LPRECT)prcExclude);
  1436.             ptpm = &tpm;
  1437.         }
  1438.         idCmd = TrackPopupMenuEx(hmContext,
  1439.             TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
  1440.             ppt->x, ppt->y, _hwndTB, ptpm);
  1441.         if (_hwndToolTips)
  1442.             SendMessage(_hwndToolTips, TTM_ACTIVATE, TRUE, 0L);
  1443.         
  1444.         if (idCmd)
  1445.         {
  1446.             if (idCmd < idCmdFirst)
  1447.             {
  1448.                 _OnDefaultContextCommand(idCmd);
  1449.             }
  1450.             else
  1451.             {
  1452.                 idCmd -= idCmdFirst;
  1453.                 if (_HandleSpecialCommand(pcm, ppt, id, idCmd) != S_OK)
  1454.                 {
  1455.                     _hwndWorkerWindow = CreateWorkerWindow();
  1456.                     SetWindowPos(_hwndWorkerWindow, NULL, ppt->x, ppt->y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
  1457.                     CMINVOKECOMMANDINFO ici = {
  1458.                         SIZEOF(CMINVOKECOMMANDINFO),
  1459.                         0,
  1460.                         _hwndWorkerWindow,
  1461.                         MAKEINTRESOURCEA(idCmd),
  1462.                         NULL, NULL,
  1463.                         SW_NORMAL,
  1464.                     };
  1465.                     pcm->InvokeCommand(&ici);
  1466.                 }
  1467.             }
  1468.         }
  1469.         // if we get this far
  1470.         // we need to return handled so that WM_CONTEXTMENU doesn't come through
  1471.         lres = 1;
  1472.         
  1473.         DestroyMenu(hmContext);
  1474.     }
  1475.     return lres;
  1476. }
  1477. LRESULT CSFToolbar::_OnContextMenu(WPARAM wParam, LPARAM lParam)
  1478. {
  1479.     LRESULT lres = 0;
  1480.     RECT rc;
  1481.     LPRECT prcExclude = NULL;
  1482.     POINT pt;
  1483.     int i;
  1484.     if (lParam != (LPARAM)-1) {
  1485.         pt.x = GET_X_LPARAM(lParam);
  1486.         pt.y = GET_Y_LPARAM(lParam);
  1487.         POINT pt2 = pt;
  1488.         MapWindowPoints(HWND_DESKTOP, _hwndTB, &pt2, 1);
  1489.         i = ToolBar_HitTest(_hwndTB, &pt2);
  1490.     } else {
  1491.         // keyboard context menu.
  1492.         i = (int)SendMessage(_hwndTB, TB_GETHOTITEM, 0, 0);
  1493.         if (i >= 0) {
  1494.             SendMessage(_hwndTB, TB_GETITEMRECT, i, (LPARAM)&rc);
  1495.             MapWindowPoints(_hwndTB, HWND_DESKTOP, (LPPOINT)&rc, 2);
  1496.             pt.x = rc.left;
  1497.             pt.y = rc.bottom;
  1498.             prcExclude = &rc;
  1499.         }
  1500.     }
  1501.     TraceMsg(TF_BAND, "NM_RCLICK %d,%d = %d", pt.x, pt.y, i);
  1502.     if (i >= 0)
  1503.     {
  1504.         UINT id = _IndexToID(i);
  1505.         LPCITEMIDLIST pidl = _IDToPidl(id, NULL);
  1506.         if (pidl)
  1507.         {
  1508.             LPCONTEXTMENU pcm = (LPCONTEXTMENU)_GetUIObjectOfPidl(pidl, IID_IContextMenu);
  1509.             if (pcm)
  1510.             {
  1511.                 // grab pcm2 for owner draw support
  1512.                 pcm->QueryInterface(IID_IContextMenu2, (LPVOID *)&_pcm2);
  1513.                 ToolBar_MarkButton(_hwndTB, id, TRUE);
  1514.                 lres = _DoContextMenu(pcm, &pt, id, prcExclude);
  1515.                 ToolBar_MarkButton(_hwndTB, id, FALSE);
  1516.                 if (lres)
  1517.                     _FlushNotifyMessages(_hwndTB);
  1518.                 ATOMICRELEASE(_pcm2);
  1519.                 pcm->Release();
  1520.             }
  1521.         }
  1522.     }
  1523.     return lres;
  1524. }
  1525. LRESULT CSFToolbar::_OnCustomDraw(NMCUSTOMDRAW* pnmcd)
  1526. {
  1527.     return CDRF_DODEFAULT;
  1528. }
  1529. void CSFToolbar::_OnDragBegin(int iItem, DWORD dwPreferedEffect)
  1530. {
  1531.     LPCITEMIDLIST pidl = _IDToPidl(iItem, &_iDragSource);
  1532.     ToolBar_SetHotItem(_hwndTB, _iDragSource);
  1533.     if (_hwndTB)
  1534.         DragDrop(_hwndTB, _psf, pidl, dwPreferedEffect, NULL);
  1535.     
  1536.     _iDragSource = -1;
  1537. }
  1538. LRESULT CSFToolbar::_OnHotItemChange(NMTBHOTITEM * pnm)
  1539. {
  1540.     LPNMTBHOTITEM  lpnmhi = (LPNMTBHOTITEM)pnm;
  1541.     if (_hwndPager && (lpnmhi->dwFlags & (HICF_ARROWKEYS | HICF_ACCELERATOR)) )
  1542.     {
  1543.         int iOldPos, iNewPos;
  1544.         RECT rc, rcPager;
  1545.         int heightPager;            
  1546.         
  1547.         int iSelected = lpnmhi->idNew;        
  1548.         iOldPos = (int)SendMessage(_hwndPager, PGM_GETPOS, (WPARAM)0, (LPARAM)0);
  1549.         iNewPos = iOldPos;
  1550.         SendMessage(_hwndTB, TB_GETITEMRECT, (WPARAM)iSelected, (LPARAM)&rc);
  1551.         
  1552.         if (rc.top < iOldPos) 
  1553.         {
  1554.              iNewPos =rc.top;
  1555.         }
  1556.         
  1557.         GetClientRect(_hwndPager, &rcPager);
  1558.         heightPager = RECTHEIGHT(rcPager);
  1559.         
  1560.         if (rc.top >= iOldPos + heightPager)  
  1561.         {
  1562.              iNewPos += (rc.bottom - (iOldPos + heightPager)) ;
  1563.         }
  1564.         
  1565.         if (iNewPos != iOldPos)
  1566.             SendMessage(_hwndPager, PGM_SETPOS, (WPARAM)0, (LPARAM)iNewPos);
  1567.     }
  1568.     return 0;
  1569. }
  1570. void CSFToolbar::_OnToolTipsCreated(NMTOOLTIPSCREATED* pnm)
  1571. {
  1572.     _hwndToolTips = pnm->hwndToolTips;
  1573.     SHSetWindowBits(_hwndToolTips, GWL_STYLE, TTS_ALWAYSTIP | TTS_TOPMOST | TTS_NOPREFIX, TTS_ALWAYSTIP | TTS_TOPMOST | TTS_NOPREFIX);
  1574.     // set the AutoPopTime (the duration of showing the tooltip) to a large value
  1575.     SendMessage(_hwndToolTips, TTM_SETDELAYTIME, TTDT_AUTOPOP, (LPARAM)MAXSHORT);
  1576. }
  1577. LRESULT CSFToolbar::_OnNotify(LPNMHDR pnm)
  1578. {
  1579.     LRESULT lres = 0;
  1580.     //The following statement traps all pager control notification messages.
  1581.     if((pnm->code <= PGN_FIRST)  && (pnm->code >= PGN_LAST)) 
  1582.     {
  1583.         return SendMessage(_hwndTB, WM_NOTIFY, (WPARAM)0, (LPARAM)pnm);
  1584.     }
  1585.     switch (pnm->code)
  1586.     {
  1587.     case TBN_DRAGOUT:
  1588.     {
  1589.         TBNOTIFY *ptbn = (TBNOTIFY*)pnm;
  1590.         _OnDragBegin(ptbn->iItem, 0);
  1591.         lres = 1;
  1592.         break;
  1593.     }
  1594.     
  1595.     case TBN_HOTITEMCHANGE:
  1596.         _OnHotItemChange((LPNMTBHOTITEM)pnm);
  1597.         break;
  1598.     case TBN_GETINFOTIP:
  1599.     {
  1600.         LPNMTBGETINFOTIP pnmTT = (LPNMTBGETINFOTIP)pnm;
  1601.         UINT uiCmd = pnmTT->iItem;
  1602.         DWORD dwFlags = _fNoShowText ? QITIPF_USENAME | QITIPF_LINKNOTARGET : QITIPF_LINKNOTARGET;
  1603.         if (!GetInfoTipEx(_psf, dwFlags, _IDToPidl(uiCmd), pnmTT->pszText, pnmTT->cchTextMax))
  1604.         {
  1605.             TBBUTTONINFO tbbi;
  1606.     
  1607.             tbbi.cbSize = SIZEOF(tbbi);
  1608.             tbbi.dwMask = TBIF_TEXT;
  1609.             tbbi.pszText = pnmTT->pszText;
  1610.             tbbi.cchText = pnmTT->cchTextMax;
  1611.     
  1612.             lres = (-1 != ToolBar_GetButtonInfo(_hwndTB, uiCmd, &tbbi));
  1613.         }
  1614.         break;
  1615.     }
  1616.     //BUGBUG: Right now I am calling the same function for both A and W version if this notification supports 
  1617.     // Strings then  it needs to thunk. Right now its only used for image
  1618.     case  TBN_GETDISPINFOA:
  1619.         _OnGetDispInfo(pnm,  FALSE);
  1620.         break;
  1621.     case  TBN_GETDISPINFOW:
  1622.         _OnGetDispInfo(pnm,  TRUE);
  1623.         break;
  1624.         
  1625.     case NM_TOOLTIPSCREATED:
  1626.         _OnToolTipsCreated((NMTOOLTIPSCREATED*)pnm);
  1627.         break;
  1628.     case NM_RCLICK:
  1629.         lres = _OnContextMenu(NULL, GetMessagePos());
  1630.         break;
  1631.     case NM_CUSTOMDRAW:
  1632.         return _OnCustomDraw((NMCUSTOMDRAW*)pnm);
  1633.     }
  1634.     return(lres);
  1635. }
  1636. DWORD CSFToolbar::_GetAttributesOfPidl(LPCITEMIDLIST pidl, DWORD dwAttribs)
  1637. {
  1638.     if (FAILED(_psf->GetAttributesOf(1, &pidl, &dwAttribs)))
  1639.         dwAttribs = 0;
  1640.     return dwAttribs;
  1641. }
  1642. PIBDATA CSFToolbar::_PosToPibData(UINT iPos)
  1643. {
  1644.     ASSERT(IsWindow(_hwndTB));
  1645.     // Initialize to NULL in case the GetButton Fails.
  1646.     TBBUTTON tbb = {0};
  1647.     PIBDATA pibData = NULL;
  1648.     if (ToolBar_GetButton(_hwndTB, iPos, &tbb))
  1649.     {
  1650.         pibData = (PIBDATA)tbb.dwData;
  1651.     }
  1652.     return pibData;
  1653. }
  1654. PIBDATA CSFToolbar::_IDToPibData(UINT uiCmd, int * piPos)
  1655. {
  1656.     PIBDATA pibdata = NULL;
  1657.     // Initialize to NULL in case the GetButtonInfo Fails.
  1658.     TBBUTTONINFO tbbi = {0};
  1659.     int iPos;
  1660.     tbbi.cbSize = SIZEOF(tbbi);
  1661.     tbbi.dwMask = TBIF_LPARAM;
  1662.     iPos = ToolBar_GetButtonInfo(_hwndTB, uiCmd, &tbbi);
  1663.     if (iPos >= 0)
  1664.         pibdata = (PIBDATA)tbbi.lParam;
  1665.     if (piPos)
  1666.         *piPos = iPos;
  1667.     return pibdata;
  1668. }    
  1669. LPCITEMIDLIST CSFToolbar::_IDToPidl(UINT uiCmd, int *piPos)
  1670. {
  1671.     LPCITEMIDLIST pidl;
  1672.     PIBDATA pibdata = _IDToPibData(uiCmd, piPos);
  1673.     if (pibdata)
  1674.         pidl = pibdata->GetPidl();
  1675.     else
  1676.         pidl = NULL;
  1677.     return pidl;
  1678. }
  1679. /*----------------------------------------------------------
  1680. Purpose: IWinEventHandler::OnWinEvent method
  1681.          Processes messages passed on from the bandsite.
  1682. */
  1683. HRESULT CSFToolbar::OnWinEvent(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres)
  1684. {
  1685.     *plres = 0;
  1686.     // We are addref'n here because during the course of the
  1687.     // Context menu, the view could be changed which free's the menu.
  1688.     // We will release after we're sure the this pointer is no longer needed.
  1689.     AddRef();
  1690.     
  1691.     switch (uMsg) {
  1692.     case WM_WININICHANGE:
  1693.         if ((SHIsExplorerIniChange(wParam, lParam) == EICH_UNKNOWN) || 
  1694.             (wParam == SPI_SETNONCLIENTMETRICS))
  1695.         {
  1696.             _UpdateIconSize(_uIconSize, TRUE);
  1697.             _Refresh();
  1698.             goto L_WM_SYSCOLORCHANGE;
  1699.         }
  1700.         break;
  1701.     case WM_SYSCOLORCHANGE:
  1702.     L_WM_SYSCOLORCHANGE:
  1703.         SendMessage(_hwndTB, uMsg, wParam, lParam);
  1704.         InvalidateRect(_hwndTB, NULL, TRUE);
  1705.         break;
  1706.     case WM_PALETTECHANGED:
  1707.         InvalidateRect( _hwndTB, NULL, FALSE );
  1708.         SendMessage( _hwndTB, uMsg, wParam, lParam );
  1709.         break;
  1710.         
  1711.     case WM_COMMAND:
  1712.         *plres = _OnCommand(wParam, lParam);
  1713.         break;
  1714.         
  1715.     case WM_NOTIFY:
  1716.         *plres = _OnNotify((LPNMHDR)lParam);
  1717.         break;
  1718.     case WM_CONTEXTMENU:
  1719.         *plres = _OnContextMenu(wParam, lParam);
  1720.         break;
  1721.     }
  1722.     Release();
  1723.     return S_OK;
  1724. // Map the information loaded (or ctor) into _psf, [_pidl]
  1725. //
  1726. HRESULT CSFToolbar::_AfterLoad()
  1727. {
  1728.     HRESULT hres = S_OK;
  1729.     // if we have a pidl then we need to get ready
  1730.     // for notifications...
  1731.     //
  1732.     if (_pidl)
  1733.     {
  1734.         // pidls must be rooted off the desktop
  1735.         //
  1736.         _fFSNotify = TRUE;
  1737.         // shortcut -- just specifying a pidl is good enough
  1738.         //
  1739.         if (!_psf)
  1740.         {
  1741.             _fPSFBandDesktop = TRUE;
  1742.             hres = IEBindToObject(_pidl, &_psf);
  1743.         }
  1744.     }
  1745.     return(hres);
  1746. }
  1747. // IDropTarget implementation
  1748. //
  1749. /*----------------------------------------------------------
  1750. Purpose: CDelegateDropTarget::GetWindowsDDT
  1751. */
  1752. HRESULT CSFToolbar::GetWindowsDDT(HWND * phwndLock, HWND * phwndScroll)
  1753. {
  1754.     *phwndLock = _hwndTB;
  1755.     *phwndScroll = _hwndTB;
  1756.     return S_OK;
  1757. }
  1758. /*----------------------------------------------------------
  1759. Purpose: CDelegateDropTarget::HitTestDDT
  1760. */
  1761. HRESULT CSFToolbar::HitTestDDT(UINT nEvent, LPPOINT ppt, DWORD * pdwId, DWORD *pdwEffect)
  1762. {
  1763.     TBINSERTMARK tbim;
  1764.     switch (nEvent)
  1765.     {
  1766.     case HTDDT_ENTER:
  1767.         return S_OK;
  1768.     case HTDDT_OVER:
  1769.         {
  1770.             int iButton = IBHT_BACKGROUND; // assume we hit the background
  1771.             // if we're the source, this may be a move operation
  1772.             //
  1773.             *pdwEffect = (_iDragSource >= 0) ? DROPEFFECT_MOVE : DROPEFFECT_NONE;
  1774.             if (!ToolBar_InsertMarkHitTest(_hwndTB, ppt, &tbim))
  1775.             {
  1776.                 if (tbim.dwFlags & TBIMHT_BACKGROUND)
  1777.                 {
  1778.                     RECT rc;
  1779.                     GetClientRect(_hwndTB, &rc);
  1780.                     // are we outside the toolbar window entirely?
  1781.                     if (!PtInRect(&rc, *ppt))
  1782.                     {
  1783.                         // rebar already did the hittesting so we are on the rebar
  1784.                         // but not the toolbar => we are in the title part
  1785.                         if (!_AllowDropOnTitle())
  1786.                         {
  1787.                             // yes; don't allow drop here
  1788.                             iButton = IBHT_OUTSIDEWINDOW;
  1789.                             *pdwEffect = DROPEFFECT_NONE;
  1790.                         }
  1791.                         // set tbim.iButton to invalid value so we don't draw insert mark
  1792.                         tbim.iButton = -1;
  1793.                     }
  1794.                 }
  1795.                 else
  1796.                 {
  1797.                     // nope, we hit a real button
  1798.                     //
  1799.                     if (tbim.iButton == _iDragSource)
  1800.                     {
  1801.                         iButton = IBHT_SOURCE; // don't drop on the source button
  1802.                     }
  1803.                     else
  1804.                     {
  1805.                         iButton = tbim.iButton;
  1806.                     }
  1807.                     tbim.iButton = IBHT_BACKGROUND;
  1808.                     // we never force a move operation if we're on a real button
  1809.                     *pdwEffect = DROPEFFECT_NONE;
  1810.                 }
  1811.             }
  1812.             *pdwId = iButton;
  1813.         }
  1814.         break;
  1815.     case HTDDT_LEAVE:
  1816.         // Reset
  1817.         tbim.iButton = IBHT_BACKGROUND;
  1818.         tbim.dwFlags = 0;
  1819.         break;
  1820.     default:
  1821.         return E_INVALIDARG;
  1822.     }
  1823.     // update ui
  1824.     if (tbim.iButton != _tbim.iButton || tbim.dwFlags != _tbim.dwFlags)
  1825.     {
  1826.         if (ppt)
  1827.             _tbim = tbim;
  1828.         // for now I don't want to rely on non-filesystem IShellFolder
  1829.         // implementations to call our OnChange method when a drop occurs,
  1830.         // so don't even show the insert mark.
  1831.         //
  1832.         if (_fFSNotify || _iDragSource >= 0)
  1833.         {
  1834.             DAD_ShowDragImage(FALSE);
  1835.             ToolBar_SetInsertMark(_hwndTB, &tbim);
  1836.             DAD_ShowDragImage(TRUE);
  1837.         }
  1838.     }
  1839.     return S_OK;
  1840. }
  1841. /*----------------------------------------------------------
  1842. Purpose: CDelegateDropTarget::GetObjectDDT
  1843. */
  1844. HRESULT CSFToolbar::GetObjectDDT(DWORD dwId, REFIID riid, LPVOID * ppvObj)
  1845. {
  1846.     HRESULT hres = E_NOINTERFACE;
  1847.     *ppvObj = NULL;
  1848.     if ((IBHT_SOURCE == dwId) || (IBHT_OUTSIDEWINDOW == dwId))
  1849.     {
  1850.         // do nothing
  1851.     }
  1852.     else if (IBHT_BACKGROUND == dwId)
  1853.     {
  1854.         // nash:41937: not sure how, but _psf can be NULL...
  1855.         if (EVAL(_psf))
  1856.             hres = _psf->CreateViewObject(_hwndTB, riid, ppvObj);
  1857.     }
  1858.     else
  1859.     {
  1860.         LPCITEMIDLIST pidl = _IDToPidl(dwId, NULL);
  1861.         if (pidl)
  1862.         {
  1863.             *ppvObj = _GetUIObjectOfPidl(pidl, riid);
  1864.             if (*ppvObj)
  1865.                 hres = S_OK;
  1866.         }
  1867.     }
  1868.     //TraceMsg(TF_BAND, "SFToolbar::GetObject(%d) returns %x", dwId, hres);
  1869.     return hres;
  1870. }
  1871. HRESULT CSFToolbar::_SaveOrderStream()
  1872. {
  1873.     if (_fChangedOrder)
  1874.     {
  1875.         // Notify everyone that the order changed
  1876.         SHSendChangeMenuNotify(this, SHCNEE_ORDERCHANGED, 0, _pidl);
  1877.         _fChangedOrder = FALSE;
  1878.         return S_OK;
  1879.     }
  1880.     else
  1881.         return S_FALSE;
  1882. }
  1883. void CSFToolbar::_Dropped(int nIndex, BOOL fDroppedOnSource)
  1884. {
  1885.     _fDropped = TRUE;
  1886.     _fChangedOrder = TRUE;
  1887.     // Save new order stream
  1888.     _SaveOrderStream();
  1889.     if (fDroppedOnSource)
  1890.         _FlushNotifyMessages(_hwndTB);
  1891. }
  1892. /*----------------------------------------------------------
  1893. Purpose: CDelegateDropTarget::OnDropDDT
  1894. */
  1895. HRESULT CSFToolbar::OnDropDDT(IDropTarget *pdt, IDataObject *pdtobj, DWORD * pgrfKeyState, POINTL pt, DWORD *pdwEffect)
  1896. {
  1897.     // Are we NOT the drag source? 
  1898.     if (_iDragSource == -1)
  1899.     {
  1900.         // No, we're not. Well, then the source may be the chevron menu
  1901.         // representing the hidden items in this menu. Let's check
  1902.         LPITEMIDLIST pidl;
  1903.         if (SUCCEEDED(SHPidlFromDataObject2(pdtobj, &pidl)))
  1904.         {
  1905.             // We've got a pidl, Are we the parent? Do we have a button?
  1906.             int iIndex;
  1907.             if (ILIsParent(_pidl, pidl, TRUE) &&
  1908.                 _GetButtonFromPidl(ILFindLastID(pidl), NULL, &iIndex))
  1909.             {
  1910.                 // We are the parent! Then let's copy that down and set it
  1911.                 // as the drag source so that down below we reorder.
  1912.                 _iDragSource = iIndex;
  1913.             }
  1914.             ILFree(pidl);
  1915.         }
  1916.     }
  1917.     if (_iDragSource >= 0)
  1918.     {
  1919.         if (_fAllowReorder)
  1920.         {
  1921.             TraceMsg(TF_BAND, "SFToolbar::OnDrop reorder %d to %d %s", _iDragSource, _tbim.iButton, _tbim.dwFlags & TBIMHT_AFTER ? "A" : "B");
  1922.             int iNewLocation = _tbim.iButton;
  1923.             if (_tbim.dwFlags & TBIMHT_AFTER)
  1924.                 iNewLocation++;
  1925.             if (iNewLocation > _iDragSource)
  1926.                 iNewLocation--;
  1927.             if (ToolBar_MoveButton(_hwndTB, _iDragSource, iNewLocation))
  1928.             {
  1929.                 PORDERITEM poi = (PORDERITEM)DPA_FastGetPtr(_hdpa, _iDragSource);
  1930.                 DPA_DeletePtr(_hdpa, _iDragSource);
  1931.                 DPA_InsertPtr(_hdpa, iNewLocation, poi);
  1932.                 OrderList_Reorder(_hdpa);
  1933.                 // If we're dropping again, then we don't need the _hdpaOrder...
  1934.                 OrderList_Destroy(&_hdpaOrder);
  1935.                 // A reorder has occurred. We need to use the order stream as the order...
  1936.                 _fHasOrder = TRUE;
  1937.                 _fDropping = TRUE;
  1938.                 _Dropped(iNewLocation, TRUE);     
  1939.                 _fDropping = FALSE;
  1940.                 _RememberOrder();
  1941.                 _SetDirty(TRUE);
  1942.             }
  1943.         }
  1944.         // Don't forget to reset this!
  1945.         _iDragSource = -1;
  1946.         DragLeave();
  1947.     }
  1948.     else
  1949.     {
  1950. #ifndef UNIX
  1951.         // We want to override the default to be LINK (SHIFT+CONTROL)
  1952.         if ((GetPreferedDropEffect(pdtobj) == 0) &&
  1953.             !(*pgrfKeyState & (MK_CONTROL | MK_SHIFT | MK_ALT)))
  1954.         {
  1955.             // NOTE: not all data objects will allow us to call SetData()
  1956.             _SetPreferedDropEffect(pdtobj, DROPEFFECT_LINK);
  1957.         }
  1958. #endif
  1959.         _fDropping = TRUE;
  1960.         return S_OK;
  1961.     }
  1962.     return S_FALSE;
  1963. }
  1964. void CSFToolbar::_SortDPA(HDPA hdpa)
  1965. {
  1966.     // If we don't have a _psf, then we certainly can't sort it
  1967.     // If we don't have a hdpa, then we certainly can't sort it
  1968.     // If the hdpa is empty, then there's no point in sorting it
  1969.     if (_psf && hdpa && DPA_GetPtrCount(hdpa))
  1970.     {
  1971.         ORDERINFO   oinfo;
  1972.         oinfo.psf = _psf;
  1973.         (oinfo.psf)->AddRef();
  1974.         oinfo.dwSortBy = (_fNoNameSort ? OI_SORTBYORDINAL : OI_SORTBYNAME);
  1975.         DPA_Sort(hdpa, OrderItem_Compare, (LPARAM)&oinfo);
  1976.         ATOMICRELEASE(oinfo.psf);
  1977.     }
  1978. }
  1979. void CSFToolbar::_RememberOrder()
  1980. {
  1981.     OrderList_Destroy(&_hdpaOrder);
  1982.     if (_hdpa)
  1983.     {
  1984.         _hdpaOrder = OrderList_Clone(_hdpa);
  1985.         _SortDPA(_hdpaOrder);
  1986.     }
  1987. }
  1988. HMENU CSFToolbar::_GetBaseContextMenu()
  1989. {
  1990.     HMENU hmenu = LoadMenuPopup_PrivateNoMungeW(MENU_ISFBAND);
  1991.     // no logo view, remove the menu item...
  1992.     HMENU hView = GetSubMenu( hmenu, 0 );
  1993.     DeleteMenu( hView, ISFBIDM_LOGOS, MF_BYCOMMAND );
  1994.     return hmenu;
  1995. }
  1996. HMENU CSFToolbar::_GetContextMenu()
  1997. {
  1998.     HMENU hmenuSrc = _GetBaseContextMenu();
  1999.     if (hmenuSrc)
  2000.     {
  2001.         MENUITEMINFO mii;
  2002.         mii.cbSize = SIZEOF(mii);
  2003.         mii.fMask = MIIM_STATE;
  2004.         mii.fState = MF_CHECKED;
  2005.         UINT uCmdId = ISFBIDM_LOGOS;
  2006.         if ( _uIconSize != ISFBVIEWMODE_LOGOS )
  2007.             uCmdId = (_uIconSize == ISFBVIEWMODE_LARGEICONS ? ISFBIDM_LARGE : ISFBIDM_SMALL);
  2008.             
  2009.         SetMenuItemInfo(hmenuSrc, uCmdId, MF_BYCOMMAND, &mii);
  2010.         if (!_fNoShowText)
  2011.             SetMenuItemInfo(hmenuSrc, ISFBIDM_SHOWTEXT, MF_BYCOMMAND, &mii);
  2012.         
  2013.         if (!_fFSNotify || !_pidl || ILIsEmpty(_pidl))
  2014.             DeleteMenu(hmenuSrc, ISFBIDM_OPEN, MF_BYCOMMAND);
  2015.         HMENU hView = GetSubMenu( hmenuSrc, 0 );
  2016.         DeleteMenu( hView, ISFBIDM_LOGOS, MF_BYCOMMAND );
  2017.     }
  2018.     return hmenuSrc;
  2019. }
  2020. // IContextMenu implementation
  2021. //
  2022. HRESULT CSFToolbar::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
  2023. {
  2024.     HMENU hmenuSrc = _GetContextMenu();
  2025.     int i = 0;
  2026.     if ( hmenuSrc )
  2027.     {
  2028.         i += Shell_MergeMenus(hmenu, hmenuSrc, indexMenu, idCmdFirst, idCmdLast, MM_ADDSEPARATOR);
  2029.         DestroyMenu(hmenuSrc);
  2030.     }
  2031.     
  2032.     if (!_pcmSF && _fAllowRename && _psf)
  2033.     {
  2034.         _psf->CreateViewObject(_hwndTB, IID_IContextMenu, (LPVOID*)&_pcmSF);
  2035.     }
  2036.     
  2037.     if (_pcmSF)
  2038.     {
  2039.         HRESULT hresT;
  2040.         
  2041.         _idCmdSF = i - idCmdFirst;
  2042.         hresT = _pcmSF->QueryContextMenu(hmenu, indexMenu + i, i, 0x7fff, CMF_BANDCMD);
  2043.         if (SUCCEEDED(hresT))
  2044.             i += HRESULT_CODE(hresT);
  2045.     }
  2046.     
  2047.     return i;
  2048. }
  2049. BOOL CSFToolbar::_UpdateShowText(BOOL fNoShowText)
  2050. {
  2051.     BOOL fChanged = (!_fNoShowText != !fNoShowText);
  2052.         
  2053.     _fNoShowText = (fNoShowText != 0);
  2054.     TraceMsg(TF_BAND, "ISFBand::_UpdateShowText turning text %hs", _fNoShowText ? "OFF" : "ON");
  2055.     if (_hwndTB)
  2056.     {
  2057.         SendMessage(_hwndTB, TB_SETMAXTEXTROWS, _fNoShowText ? 0 : 1, 0L);
  2058.         _UpdateButtons();
  2059.     }
  2060.     
  2061.     return fChanged;
  2062. }
  2063. HRESULT CSFToolbar::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
  2064. {
  2065.     BOOL fChanged = FALSE;
  2066.     int idCmd = -1;
  2067.     if (!HIWORD(lpici->lpVerb))
  2068.         idCmd = LOWORD(lpici->lpVerb);
  2069.     switch (idCmd)
  2070.     {
  2071.     case ISFBIDM_REFRESH:
  2072.         _Refresh();
  2073.         break;
  2074.         
  2075.     case ISFBIDM_OPEN:
  2076.         OpenFolderPidl(_pidl);
  2077.         break;
  2078.                 
  2079.     case ISFBIDM_LARGE:
  2080.         fChanged = _UpdateIconSize(ISFBVIEWMODE_LARGEICONS, TRUE);
  2081.         break;
  2082.     case ISFBIDM_SMALL:
  2083.         fChanged = _UpdateIconSize(ISFBVIEWMODE_SMALLICONS, TRUE);
  2084.         break;
  2085.     case ISFBIDM_SHOWTEXT:
  2086.         fChanged = _UpdateShowText(!_fNoShowText);
  2087.         break;
  2088.         
  2089.     default:
  2090.         if (_pcmSF && idCmd >= _idCmdSF)
  2091.         {
  2092.             LPCSTR  lpOldVerb = lpici->lpVerb;
  2093.             
  2094.             lpici->lpVerb = MAKEINTRESOURCEA(idCmd -= _idCmdSF);
  2095.             
  2096.             _pcmSF->InvokeCommand(lpici);
  2097.             _FlushNotifyMessages(_hwndTB);
  2098.             lpici->lpVerb = lpOldVerb;
  2099.         }
  2100.         else
  2101.             TraceMsg(TF_BAND, "SFToolbar::InvokeCommand %d not handled", idCmd);
  2102.         break;
  2103.     }
  2104.     
  2105.     // Our minimum sizes have changed, notify the bandsite
  2106.     //
  2107.     if (fChanged)
  2108.         _ToolbarChanged();
  2109.     return(S_OK);
  2110. }
  2111. HRESULT CSFToolbar::GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax)
  2112. {
  2113.     return(E_NOTIMPL);
  2114. }
  2115. void CSFToolbar::_RegisterToolbar()
  2116. {
  2117.     // Since _SubclassWindow protects against multiply subclassing, 
  2118.     // This call is safe, and ensures that the toolbar is subclassed before
  2119.     // even trying to register it for change notify.
  2120.     if (_hwndTB && _SubclassWindow(_hwndTB) && _fRegisterChangeNotify)
  2121.         _RegisterChangeNotify();
  2122.     CDelegateDropTarget::Init();
  2123. }
  2124. void CSFToolbar::_UnregisterToolbar()
  2125. {
  2126.     if (_hwndTB)
  2127.     {
  2128.         if (_fRegisterChangeNotify) 
  2129.             _UnregisterChangeNotify();
  2130.         _UnsubclassWindow(_hwndTB);
  2131.     }
  2132. }
  2133. void CSFToolbar::_RegisterChangeNotify()
  2134. {
  2135.     // Since we want to register for change notify ONLY once,
  2136.     // and only if this is a file system toolbar.
  2137.     if (!_fFSNRegistered && _fFSNotify)
  2138.     {
  2139.         if (_ptscn)
  2140.             _ptscn->Register(_hwndTB, g_idFSNotify, _lEvents);
  2141.         else
  2142.             _RegisterWindow(_hwndTB, _pidl, _lEvents);
  2143.         _fFSNRegistered = TRUE;
  2144.     }
  2145. }
  2146. void CSFToolbar::_UnregisterChangeNotify()
  2147. {
  2148.     // Only unregister if we have been registered.
  2149.     if (_hwndTB && _fFSNRegistered && _fFSNotify)
  2150.     {
  2151.         _fFSNRegistered = FALSE;
  2152.         if (_ptscn)
  2153.             _ptscn->Unregister();
  2154.         else
  2155.             _UnregisterWindow(_hwndTB);
  2156.     }
  2157. }
  2158. void CSFToolbar::_ReleaseShellFolder()
  2159. {
  2160.     if (_psf)
  2161.     {
  2162.         IUnknown_SetOwner(_psf, NULL);
  2163.         ATOMICRELEASE(_psf);
  2164.     }
  2165.     ATOMICRELEASE(_ptscn);
  2166. }    
  2167. /*----------------------------------------------------------
  2168. Purpose: IWinEventHandler::IsWindowOwner method.
  2169. */
  2170. HRESULT CSFToolbar::IsWindowOwner(HWND hwnd)
  2171. {
  2172.     if (hwnd == _hwndTB ||
  2173.         hwnd == _hwndToolTips ||
  2174.         hwnd == _hwndPager)
  2175.         return S_OK;
  2176.     
  2177.     return S_FALSE;
  2178. }