|
|
#include "priv.h"
#include "sccls.h"
#include "iface.h"
#include "itbdrop.h"
#include "sftbar.h"
#include "resource.h"
#include "dpastuff.h"
#include "shlwapi.h"
#include "cobjsafe.h"
#include <iimgctx.h>
#include "uemapp.h"
#include "mluisupp.h"
extern UINT g_idFSNotify;
#define TF_SFTBAR 0x10000000 // Same ID as the AugMISF stuff
#define PGMP_RECALCSIZE 200
// do not set CMD_ID_FIRST to 0. we use this to see if anything is selected
#define CMD_ID_FIRST 1
#define CMD_ID_LAST 0x7fff
CSFToolbar::CSFToolbar() { #ifdef CASCADE_DEBUG
_fCascadeFolder = TRUE; #endif
_dwStyle = TBSTYLE_TOOLTIPS; _fDirty = TRUE; // we havn't enumerated, so our state is dirty
_fRegisterChangeNotify = TRUE; _fAllowReorder = TRUE;
_tbim.iButton = -1; _iDragSource = -1; _lEvents = SHCNE_DRIVEADD|SHCNE_CREATE|SHCNE_MKDIR|SHCNE_DRIVEREMOVED| SHCNE_DELETE|SHCNE_RMDIR|SHCNE_RENAMEITEM|SHCNE_RENAMEFOLDER| SHCNE_MEDIAINSERTED|SHCNE_MEDIAREMOVED|SHCNE_NETUNSHARE|SHCNE_NETSHARE| SHCNE_UPDATEITEM|SHCNE_UPDATEIMAGE|SHCNE_ASSOCCHANGED| SHCNE_UPDATEDIR|SHCNE_EXTENDED_EVENT; }
CSFToolbar::~CSFToolbar() { ATOMICRELEASE(_pcmSF);
_ReleaseShellFolder();
ILFree(_pidl);
ASSERT(NULL == _hdpa);
if (_hwndWorkerWindow) DestroyWindow(_hwndWorkerWindow);
OrderList_Destroy(&_hdpaOrder); }
HRESULT CSFToolbar::QueryInterface(REFIID riid, void **ppvObj) { static const QITAB qit[] = { QITABENT(CSFToolbar, IWinEventHandler), QITABENT(CSFToolbar, IShellChangeNotify), QITABENT(CSFToolbar, IDropTarget), QITABENT(CSFToolbar, IContextMenu), QITABENT(CSFToolbar, IShellFolderBand), { 0 }, };
return QISearch(this, qit, riid, ppvObj); }
HRESULT CSFToolbar::SetShellFolder(IShellFolder* psf, LPCITEMIDLIST pidl) { HRESULT hres = E_INVALIDARG; // Save the old values
LPITEMIDLIST pidlSave = _pidl; IShellFolder *psfSave = _psf; ITranslateShellChangeNotify *ptscnSave = _ptscn;
_psf = NULL; _pidl = NULL; _ptscn = NULL; ASSERT(NULL == psf || IS_VALID_CODE_PTR(psf, IShellFolder)); ASSERT(NULL == pidl || IS_VALID_PIDL(pidl));
if (psf || pidl) { if (psf) { _psf = psf; _psf->AddRef();
_psf->QueryInterface(IID_ITranslateShellChangeNotify, (LPVOID *)&_ptscn); } if (pidl) _pidl = ILClone(pidl); hres = S_OK; }
if (SUCCEEDED(hres)) { ILFree(pidlSave); if (psfSave) psfSave->Release(); if (ptscnSave) ptscnSave->Release(); } else { ASSERT(_psf == NULL); ASSERT(_pidl == NULL); ASSERT(_ptscn == NULL); // we failed -- restore the old values
_psf = psfSave; _pidl = pidlSave; _ptscn = ptscnSave; }
// This code is here for ShellFolderToolbar reuse. When setting a new shell folder
// into an existing band, we will refresh. Note that this is a noop on a new band.
_RememberOrder(); _SetDirty(TRUE); if (_fShow) _FillToolbar(); return hres; }
HWND CSFToolbar::_CreatePager(HWND hwndParent) { if (!_fMulticolumn) { _hwndPager = CreateWindowEx(0, WC_PAGESCROLLER, NULL, WS_CHILD | WS_TABSTOP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndParent, (HMENU) 0, HINST_THISDLL, NULL); if (_hwndPager) { hwndParent = _hwndPager; } }
return hwndParent; }
void CSFToolbar::_CreateToolbar(HWND hwndParent) { if (!_hwndTB) {
hwndParent = _CreatePager(hwndParent);
_hwndTB = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAME, NULL, WS_VISIBLE | WS_CHILD | TBSTYLE_FLAT | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE | _dwStyle, 0, 0, 0, 0, hwndParent, (HMENU) 0, HINST_THISDLL, NULL); if (_hwndPager) SendMessage(_hwndPager, PGM_SETCHILD, 0, (LPARAM)_hwndTB);
if (!_hwndTB) { TraceMsg(TF_ERROR, "_hwndTB failed"); return; } SendMessage(_hwndTB, TB_BUTTONSTRUCTSIZE, SIZEOF(TBBUTTON), 0);
// Set the format to ANSI or UNICODE as appropriate.
ToolBar_SetUnicodeFormat(_hwndTB, DLL_IS_UNICODE); if (_hwndPager) { // Set the format to ANSI or UNICODE as appropriate.
ToolBar_SetUnicodeFormat(_hwndPager, DLL_IS_UNICODE); }
#if 0 // Not going to do this for IE5.
ToolBar_SetExtendedStyle(_hwndTB, TBSTYLE_EX_HIDECLIPPEDBUTTONS, TBSTYLE_EX_HIDECLIPPEDBUTTONS); #endif
// Make sure we're on the same wavelength.
SendMessage(_hwndTB, CCM_SETVERSION, COMCTL32_VERSION, 0);
RECT rc; SIZE size;
SystemParametersInfoA(SPI_GETWORKAREA, SIZEOF(RECT), &rc, FALSE); if (!_hwndPager) { size.cx = RECTWIDTH(rc); size.cy = GetSystemMetrics(SM_CYSCREEN) - (2 * GetSystemMetrics(SM_CYEDGE)); // Need to subrtact off the borders
} else { //HACKHACK: THIS WILL FORCE NO WRAP TO HAPPEN FOR PROPER WIDTH CALC WHEN PAGER IS PRESENT.
size.cx = RECTWIDTH(rc); size.cy = 32000; } ToolBar_SetBoundingSize(_hwndTB, &size); } else { if (_hwndPager && GetParent(_hwndPager) != hwndParent) SetParent(_hwndPager, hwndParent); }
if (FAILED(_GetTopBrowserWindow(&_hwndDD))) _hwndDD = GetParent(_hwndTB); }
#define MAX_COMMANDID 0xFFFF // We're allowed one word of command ids (tested at 5)
int CSFToolbar::_GetCommandID() { int id = -1;
if (!_fCheckIds) { id = _nNextCommandID++; } else { // We are reusing command ids and must verify that
// the current one is not in use. This is slow, but
// I assume the number of buttons on one of these
// bands is relatively few.
//
for (int i = 0 ; i <= MAX_COMMANDID ; i++) { TBBUTTONINFO tbbiDummy = {0};
tbbiDummy.cbSize = SIZEOF(tbbiDummy); tbbiDummy.dwMask = 0; // we don't care about data, just existence
if (-1 != ToolBar_GetButtonInfo(_hwndTB, _nNextCommandID, &tbbiDummy)) { // A button by this id wasn't found, so the id must be free
//
id = _nNextCommandID++; break; }
_nNextCommandID++; _nNextCommandID %= MAX_COMMANDID; } }
if (_nNextCommandID > MAX_COMMANDID) { _nNextCommandID = 0; _fCheckIds = TRUE; }
return(id); }
/*----------------------------------------------------------
Purpose: This function determines the toolbar button style for the given pidl.
Returns S_OK if pdwMIFFlags is also set (i.e., the object supported IMenuBandItem to provide more info). S_FALSE if only *pdwTBStyle is set.
*/ HRESULT CSFToolbar::_TBStyleForPidl(LPCITEMIDLIST pidl, DWORD * pdwTBStyle, DWORD* pdwTBState, DWORD * pdwMIFFlags,int* piIcon) { HRESULT hres = S_FALSE; DWORD dwStyle = TBSTYLE_BUTTON; if (!_fAccelerators) dwStyle |= TBSTYLE_NOPREFIX;
*pdwMIFFlags = 0; *pdwTBStyle = dwStyle; *piIcon = -1; *pdwTBState = TBSTATE_ENABLED;
return hres; }
PIBDATA CSFToolbar::_CreateItemData(PORDERITEM poi) { return new IBDATA(poi); }
PIBDATA CSFToolbar::_AddOrderItemTB(PORDERITEM poi, int index, TBBUTTON* ptbb) { TCHAR szName[MAX_PATH];
// We need to do this even for NULL because _ObtainPIDLName cooks
// up the word "(Empty)" as necessary.
_ObtainPIDLName(poi ? poi->pidl : NULL, szName, SIZECHARS(szName));
TBBUTTON tbb = {0}; DWORD dwMIFFlags; DWORD dwStyle; DWORD dwState; int iIcon; int iCommandID = _GetCommandID(); BOOL bNoIcon = FALSE; if (!ptbb) ptbb = &tbb;
if (S_OK == _TBStyleForPidl(poi ? poi->pidl : NULL, &dwStyle, &dwState, &dwMIFFlags,&iIcon) && !(dwMIFFlags & SMIF_ICON)) { bNoIcon = TRUE; }
PIBDATA pibdata = _CreateItemData(poi); if (pibdata) { pibdata->SetFlags(dwMIFFlags); pibdata->SetNoIcon(bNoIcon);
if(!bNoIcon && iIcon != -1) ptbb->iBitmap = iIcon; else ptbb->iBitmap = I_IMAGECALLBACK;
ptbb->idCommand = iCommandID; ptbb->fsState = (BYTE)dwState; ptbb->fsStyle = (BYTE)dwStyle; ptbb->dwData = (DWORD_PTR)pibdata; ptbb->iString = (INT_PTR)szName;
// Disregard variablewidth if we are vertical
if (_fVariableWidth && !_fVertical) ptbb->fsStyle |= TBSTYLE_AUTOSIZE;
if (ptbb->idCommand != -1) { if (SendMessage(_hwndTB, TB_INSERTBUTTON, index, (LPARAM)ptbb)) { TraceMsg(TF_BAND, "SFToolbar::_AddPidl %d 0x%x [%s]", ptbb->idCommand, ptbb->dwData, ptbb->iString); } else { delete pibdata; pibdata = NULL; } }
}
return pibdata; }
void CSFToolbar::_ObtainPIDLName(LPCITEMIDLIST pidl, LPTSTR psz, int cchMax) { STRRET strret; if SUCCEEDED(_psf->GetDisplayNameOf(pidl, SHGDN_NORMAL, &strret)) { StrRetToBuf(&strret, pidl, psz, cchMax); } }
int CSFToolbar::_GetBitmap(int iCommandID, PIBDATA pibdata, BOOL fUseCache) { int iBitmap;
if(_fNoIcons || pibdata->GetNoIcon()) iBitmap = -1; else { iBitmap = OrderItem_GetSystemImageListIndex(pibdata->GetOrderItem(), _psf, fUseCache); }
return iBitmap; }
void CSFToolbar::_OnGetDispInfo(LPNMHDR pnm, BOOL fUnicode) { LPNMTBDISPINFO pdi = (LPNMTBDISPINFO)pnm; PIBDATA pibdata = (PIBDATA)pdi->lParam; LPITEMIDLIST pidl = pibdata->GetPidl(); if(pdi->dwMask & TBNF_IMAGE) { pdi->iImage = _GetBitmap(pdi->idCommand, pibdata, TRUE); } if(pdi->dwMask & TBNF_TEXT) { if(pdi->pszText) { if(fUnicode) { pdi->pszText[0] = TEXT('\0'); }else { pdi->pszText[0] = 0; } } } pdi->dwMask |= TBNF_DI_SETITEM;
return;
}
// Adds pidl as a new button, handles ILFree(pidl) for the caller
//
BOOL CSFToolbar::_AddPidl(LPITEMIDLIST pidl, int index) { if (_hdpa) { PORDERITEM poi = OrderItem_Create(pidl, index); if (poi) { int iPos = DPA_InsertPtr(_hdpa, index, poi); if (-1 != iPos) { // If we did not load an order, then new items should
// show up alphabetically in the list, not at the bottom.
if (!_fHasOrder) { // Sort by name
_SortDPA(_hdpa);
// Find the index of the order item. We use this index as
// the toolbar insert index.
index = DPA_GetPtrIndex(_hdpa, poi); }
if (_AddOrderItemTB(poi, index, NULL)) { return TRUE; } DPA_DeletePtr(_hdpa, iPos); }
OrderItem_Free(poi);
return FALSE; } }
ILFree(pidl);
return FALSE; }
BOOL CSFToolbar::_FilterPidl(LPCITEMIDLIST pidl) { return FALSE; }
void CSFToolbar::s_NewItem(LPVOID pvParam, LPCITEMIDLIST pidl) { CSFToolbar* psft = (CSFToolbar*)pvParam; psft->v_NewItem(pidl); }
HRESULT CSFToolbar::_GetIEnumIDList(DWORD dwEnumFlags, IEnumIDList **ppenum) { ASSERT(_psf); // Pass in a NULL hwnd so the enumerator does not show any UI while
// we're filling a band.
return IShellFolder_EnumObjects(_psf, NULL, dwEnumFlags, ppenum); }
void CSFToolbar::_FillDPA(HDPA hdpa, HDPA hdpaSort, DWORD dwEnumFlags) { IEnumIDList* penum; int cItems = 0; BOOL f9x = IsOS(OS_WINDOWS);
if (!_psf) return;
if (SUCCEEDED(_GetIEnumIDList(dwEnumFlags, &penum))) { LPITEMIDLIST pidl; ULONG ul;
while (S_OK == penum->Next(1, &pidl, &ul)) { cItems++; if (_FilterPidl(pidl) || !OrderList_Append(hdpa, pidl, -1)) { TraceMsg(TF_MENUBAND, "SFToolbar (0x%x)::_FillDPA : Did not Add Pidl (0x%x).", this, pidl); ILFree(pidl); } // Windows 9x issue
if (cItems > 1000 && f9x) { // Here's the deal:
// When enumerating NTdev, we have 10,000 items. If each item is 20 pixels
// long, we end up with 200,000 pixels. Windows can only display 32,000 pixels,
// or 1,600 items in the default case. I'm limiting to 1,000 items = 20,000 so that
// we have some room for reasonable font sizes.
break; } }
penum->Release(); }
ORDERINFO oinfo; int iInsertIndex = _tbim.iButton + 1; // This is the button where the cursor sat.
// So, We want to insert after that
if (iInsertIndex >= ToolBar_ButtonCount(_hwndTB)) // But, if it's at the end,
iInsertIndex = -1; // Convert the insert to an append.
// - Comments in rhyme by lamadio
oinfo.psf = _psf; (oinfo.psf)->AddRef(); oinfo.dwSortBy = (_fHasOrder || _fDropping)? ((_fNoNameSort ? OI_SORTBYORDINAL : OI_SORTBYNAME)): OI_MERGEBYNAME; OrderList_Merge(hdpa, hdpaSort, _fDropping ? iInsertIndex : _DefaultInsertIndex(), (LPARAM) &oinfo, s_NewItem, (LPVOID)this); ATOMICRELEASE(oinfo.psf); }
// This function re-enumerates the IShellFolder, keeping things ordered correctly.
// At some point it may reduce flicker by not removing buttons that don't change.
//
void CSFToolbar::_FillToolbar() { HDPA hdpaSort; HDPA hdpa;
if (!_fDirty || !_psf) return;
// If we have an order array, use that, otherwise
// use the currently viewed items
if (_hdpaOrder) hdpaSort = _hdpaOrder; // already sorted by name
else { hdpaSort = _hdpa; _SortDPA(hdpaSort); }
hdpa = DPA_Create(hdpaSort ? DPA_GetPtrCount(hdpaSort) : 12); if (hdpa) { _FillDPA(hdpa, hdpaSort, SHCONTF_FOLDERS|SHCONTF_NONFOLDERS);
// NOTE: if many buttons were moved at the same time
// the notifications may be spread out as the files
// are copied and we'd only insert the first time.
// This is probably okay.
//
_fDropping = FALSE;
// For the case of dragging a new item into the band (or one
// just showing up) we could re-sort _hdpa by ordinal (which
// would match the current button order), and iterate through hdpa
// to see where a button needs to be inserted or removed.
// This would be way less flicker and toolbar painting
// than always blowing away the current buttons and reinserting them...
//
// For now be lazy and do extra work.
//
// remove buttons and replace _hdpa with hdpa
if (_hdpa) { EmptyToolbar(); ASSERT(!_hdpa); } _hdpa = hdpa;
SendMessage(_hwndTB, WM_SETREDRAW, FALSE, 0);
// add buttons back in
DEBUG_CODE( BOOL bFailed = FALSE; ) int i = 0; while (i < DPA_GetPtrCount(_hdpa)) { PORDERITEM poi = (PORDERITEM)DPA_FastGetPtr(_hdpa, i);
// ASSERT(bFailed || poi->nOrder == i);
if (_AddOrderItemTB(poi, -1, NULL)) { i++; } else { DPA_DeletePtr(_hdpa, i); DEBUG_CODE( bFailed = TRUE; ) } } } SendMessage(_hwndTB, WM_SETREDRAW, TRUE, 0);
// if we used an _hdpaOrder then we don't need it any more
OrderList_Destroy(&_hdpaOrder); _UpdateButtons(); _SetDirty(FALSE);
_ToolbarChanged(); TraceMsg(TF_BAND, "SFToolbar::_FillToolbar found %d items", DPA_GetPtrCount(_hdpa)); }
void CSFToolbar::EmptyToolbar() { if (_hwndTB) { TraceMsg(TF_BAND, "SFToolbar::EmptyToolbar %d items", _hdpa ? DPA_GetPtrCount(_hdpa) : 0);
while (InlineDeleteButton(0)) { // delete the buttons
} }
OrderList_Destroy(&_hdpa);
_fDirty = TRUE; _nNextCommandID = 0; }
void CSFToolbar::_SetDirty(BOOL fDirty) { _fDirty = fDirty; }
UINT CSFToolbar::_IndexToID(int iIndex) { TBBUTTON tbb;
if (SendMessage(_hwndTB, TB_GETBUTTON, iIndex, (LPARAM)&tbb)) { return tbb.idCommand; } return (UINT)-1; }
// if ptbbi is specified, dwMask must be filled in
//
LPITEMIDLIST CSFToolbar::_GetButtonFromPidl(LPCITEMIDLIST pidl, TBBUTTONINFO * ptbbi, int * pIndex) { int i;
if (!_hdpa) return NULL;
for (i = DPA_GetPtrCount(_hdpa)-1 ; i >= 0 ; i--) { HRESULT hres; PORDERITEM poi = (PORDERITEM)DPA_FastGetPtr(_hdpa, i);
ASSERT(poi); if (poi->pidl) { hres = _psf->CompareIDs(0, pidl, poi->pidl); if (ResultFromShort(0) == hres) { if (pIndex) *pIndex = i;
if (ptbbi) { int id = _IndexToID(i);
if (id != -1) { ptbbi->cbSize = SIZEOF(*ptbbi); if (-1 == ToolBar_GetButtonInfo(_hwndTB, id, ptbbi)) { ZeroMemory(ptbbi, SIZEOF(*ptbbi)); } } else { ZeroMemory(ptbbi, SIZEOF(*ptbbi)); } }
return poi->pidl; } } }
return NULL; }
// On an add, tack the new button on the end
void CSFToolbar::_OnFSNotifyAdd(LPCITEMIDLIST pidl) { // be paranoid and make sure we don't duplicate an item
//
if (!_GetButtonFromPidl(pidl, NULL, NULL)) { LPITEMIDLIST pidlNew;
if (_fFSNotify && !_ptscn) { if (FAILED(SHGetRealIDL(_psf, pidl, &pidlNew))) pidlNew = NULL; } else { pidlNew = ILClone(pidl); }
if (pidlNew) { if (!_FilterPidl(pidlNew)) { int index = _DefaultInsertIndex();
if (_fDropping) { if (-1 == _tbim.iButton) index = 0; // if qlinks has no items, _tbim.iButton is -1, but you can't insert there...
else if (_tbim.dwFlags & TBIMHT_AFTER) index = _tbim.iButton + 1; else index = _tbim.iButton; }
// We need to store this as the new order because a drag and drop has occured.
// We will store this order and use it until the end of time.
if (_fDropping) { _fHasOrder = TRUE; _fChangedOrder = TRUE; }
_AddPidl(pidlNew, index); OrderList_Reorder(_hdpa); if (_fDropping) { _Dropped(index, FALSE); _fDropping = FALSE; } } else { ILFree(pidlNew); } } } }
// This function syncronously removes the button, and deletes it's contents.
// This avoids Reentrancy problems, as well as Leaks caused by unhooked toolbars
BOOL_PTR CSFToolbar::InlineDeleteButton(int iIndex) { BOOL_PTR fRet = FALSE; TBBUTTONINFO tbbi = {0}; tbbi.cbSize = SIZEOF(tbbi); tbbi.dwMask = TBIF_LPARAM | TBIF_BYINDEX; if (ToolBar_GetButtonInfo(_hwndTB, iIndex, &tbbi) >= 0) { PIBDATA pibdata = (PIBDATA)tbbi.lParam; tbbi.lParam = NULL;
ToolBar_SetButtonInfo(_hwndTB, iIndex, &tbbi);
fRet = SendMessage(_hwndTB, TB_DELETEBUTTON, iIndex, 0);
if (pibdata) delete pibdata;
}
return fRet; }
// On a remove, rip out the old button and adjust existing ones
void CSFToolbar::_OnFSNotifyRemove(LPCITEMIDLIST pidl) { int i; LPITEMIDLIST pidlButton = _GetButtonFromPidl(pidl, NULL, &i); if (pidlButton) { // remove it from the DPA before nuking the button. There is a rentrancy issue here.
DPA_DeletePtr(_hdpa, i); InlineDeleteButton(i); ILFree(pidlButton); _fChangedOrder = TRUE; } }
// On a rename, just change the text of the old button
//
void CSFToolbar::_OnFSNotifyRename(LPCITEMIDLIST pidlFrom, LPCITEMIDLIST pidlTo) { TBBUTTONINFO tbbi = {0}; LPITEMIDLIST pidlButton; int i; tbbi.cbSize = SIZEOF(tbbi); tbbi.dwMask = TBIF_COMMAND | TBIF_LPARAM; pidlButton = _GetButtonFromPidl(pidlFrom, &tbbi, &i); if (pidlButton) { LPITEMIDLIST pidlNew;
if (_fFSNotify && !_ptscn) { if (FAILED(SHGetRealIDL(_psf, pidlTo, &pidlNew))) pidlNew = NULL; } else { pidlNew = ILClone(pidlTo); }
if (pidlNew) { LPITEMIDLIST pidlFree = pidlNew; PORDERITEM poi = (PORDERITEM)DPA_FastGetPtr(_hdpa, i); if (EVAL(poi)) { pidlFree = poi->pidl; poi->pidl = pidlNew; STRRET strret; TCHAR szName[MAX_PATH]; if (SUCCEEDED(_psf->GetDisplayNameOf(pidlNew, SHGDN_NORMAL, &strret)) && SUCCEEDED(StrRetToBuf(&strret, pidlNew, szName, ARRAYSIZE(szName)))) { // _GetButtonFromPidl filled in tbbi.cbSize and tbbi.idCommand
//
PIBDATA pibdata = (PIBDATA)tbbi.lParam; if (pibdata) pibdata->SetOrderItem(poi);
tbbi.dwMask = TBIF_TEXT; tbbi.pszText = szName; EVAL(ToolBar_SetButtonInfo(_hwndTB, tbbi.idCommand, &tbbi)); // Just so that it's new location gets persisted
_fChangedOrder = TRUE; } }
ILFree(pidlFree); } } }
// On a complete update remove the old button and add it again
//
void CSFToolbar::_OnFSNotifyUpdate(LPCITEMIDLIST pidl) { TBBUTTONINFO tbbi = {0};
tbbi.cbSize = SIZEOF(tbbi); tbbi.dwMask = TBIF_COMMAND; LPITEMIDLIST pidlButton = _GetButtonFromPidl(pidl, &tbbi, NULL); if (pidlButton) { STRRET strret; TCHAR szName[MAX_PATH];
if (SUCCEEDED(_psf->GetDisplayNameOf(pidlButton, SHGDN_NORMAL, &strret)) && SUCCEEDED(StrRetToBuf(&strret, pidlButton, szName, ARRAYSIZE(szName)))) { int iBitmap = _GetBitmap(tbbi.idCommand, _IDToPibData(tbbi.idCommand, NULL), FALSE); if (iBitmap >= 0) { tbbi.dwMask = TBIF_IMAGE | TBIF_TEXT; tbbi.iImage = iBitmap; tbbi.pszText = szName;
ToolBar_SetButtonInfo(_hwndTB, tbbi.idCommand, &tbbi); } } } }
void CSFToolbar::_Refresh() { if (!_hdpa) return;
_RememberOrder();
_SetDirty(TRUE); if (_fShow) _FillToolbar(); }
LRESULT CSFToolbar::_OnTimer(WPARAM wParam) { return 0; }
LRESULT CSFToolbar::_DefWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_DRAWITEM: case WM_MEASUREITEM: case WM_INITMENUPOPUP: case WM_MENUSELECT: if (_pcm2) _pcm2->HandleMenuMsg(uMsg, wParam, lParam); break;
case WM_MENUCHAR: { LRESULT lres = 0; IContextMenu3* pcm3; if (_pcm2 && SUCCEEDED(_pcm2->QueryInterface(IID_IContextMenu3, (void**)&pcm3))) { pcm3->HandleMenuMsg2(uMsg, wParam, lParam, &lres); pcm3->Release(); } return lres; } break; case WM_TIMER: if (_OnTimer(wParam)) { return 1; } break; } return CNotifySubclassWndProc::_DefWindowProc(hwnd, uMsg, wParam, lParam); }
/*----------------------------------------------------------
Purpose: For future use. when renaming a parent of this shell folder we should rebind to it and refill us.
S_OK Indicates successful handling of this notification S_FALSE Indicates the notification is not a handled situation. The caller should handle the notification in this case. Other Failure code indicates a problem. Caller should abort operation or handle the notification itself.
*/ HRESULT CSFToolbar::_OnRenameFolder(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) { return S_FALSE; }
HRESULT CSFToolbar::OnChange(LONG lEvent, LPCITEMIDLIST pidlOrg1, LPCITEMIDLIST pidlOrg2) { HRESULT hres; LPITEMIDLIST pidl1 = (LPITEMIDLIST)pidlOrg1; LPITEMIDLIST pidl2 = (LPITEMIDLIST)pidlOrg2; LPITEMIDLIST pidl1ToFree = NULL; // Used if we allocate a pidl that needs to be freed. (::TranslateIDs())
LPITEMIDLIST pidl2ToFree = NULL; LPITEMIDLIST pidlOut1Event2 = NULL; // Used if we allocate a pidl that needs to be freed. (::TranslateIDs())
LPITEMIDLIST pidlOut2Event2 = NULL; LONG lEvent2 = (LONG)-1; if (_ptscn) { hres = _ptscn->TranslateIDs(&lEvent, pidlOrg1, pidlOrg2, &pidl1, &pidl2, &lEvent2, &pidlOut1Event2, &pidlOut2Event2); if (FAILED(hres)) return hres; else { // if pidl1 doesn't equal pidlOrg1, then pidl1 was allocated and needs to be freed.
pidl1ToFree = ((pidlOrg1 == pidl1) ? NULL : pidl1); pidl2ToFree = ((pidlOrg2 == pidl2) ? NULL : pidl2); }
ASSERT(NULL == pidl1 || IS_VALID_PIDL(pidl1)); ASSERT(NULL == pidl2 || IS_VALID_PIDL(pidl2)); }
hres = OnTranslatedChange(lEvent, pidl1, pidl2);
// Do we have a second event to process?
if (SUCCEEDED(hres) && lEvent2 != (LONG)-1) { // Yes, then go do it.
hres = OnTranslatedChange(lEvent2, pidlOut1Event2, pidlOut2Event2); } ILFree(pidlOut1Event2); ILFree(pidlOut2Event2); ILFree(pidl1ToFree); ILFree(pidl2ToFree);
return hres; }
#ifdef DEBUG
void DBPrPidl(LPCSTR szPre, LPCITEMIDLIST pidl) { TCHAR szName[MAX_PATH];
szName[0] = '\0'; if (pidl) SHGetNameAndFlags(pidl, SHGDN_FORPARSING, szName, SIZECHARS(szName), NULL);
TraceMsg(TF_WARNING, "%hs%s", szPre, szName); return; } #endif
HRESULT CSFToolbar::OnTranslatedChange(LONG lEvent, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) { HRESULT hres = S_OK; BOOL fSizeChanged = FALSE;
TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: lEvent=%x", lEvent);
// If we weren't given a pidl we won't register for
// SHChangeNotify calls, but our IShellChange interface
// can still be QI()d so someone could errantly call us.
//
// If we change to using QS() for IShellChange interface
// then we can put this check there...
//
if (NULL == _pidl) { // HACKHACK (scotth): resource-based menus (CMenuISF) don't set _pidl.
// Right now allow SHCNE_UPDATEDIR thru...
if (SHCNE_UPDATEDIR == lEvent) goto HandleUpdateDir;
TraceMsg(TF_WARNING, "CSFToolbar::OnChange - _pidl is NULL"); hres = E_FAIL; goto CleanUp; }
if ( lEvent != SHCNE_UPDATEIMAGE && lEvent != SHCNE_RENAMEITEM && lEvent != SHCNE_RENAMEFOLDER && lEvent != SHCNE_UPDATEDIR && lEvent != SHCNE_MEDIAREMOVED && lEvent != SHCNE_MEDIAINSERTED && lEvent != SHCNE_EXTENDED_EVENT) { // We only handle notifications for immediate kids. (except SHCNE_RENAMEFOLDER)
//
if (!_IsChildID(pidl1, TRUE)) { TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Not a child. Bailing"); hres = E_FAIL; goto CleanUp; } }
// Have we been shown yet?
if (_hdpa == NULL) { // No. Well, then punt this. We'll catch it on the first enum.
hres = E_FAIL; goto CleanUp; }
switch (lEvent) { case SHCNE_EXTENDED_EVENT: { SHChangeDWORDAsIDList UNALIGNED * pdwidl = (SHChangeDWORDAsIDList UNALIGNED *)pidl1; if (pdwidl->dwItem1 == SHCNEE_ORDERCHANGED) { TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Reorder event");
// Do this first so that we can say "We can handle it". This prevents the
// mnfolder code that works around a bug in some installers where they don't
// send a Create Folder before the create item in that folder. It causes an
// update dir...
if (!pidl2 || ILIsEqual(_pidl, pidl2)) { // if this reorder came from us, blow it off
if (!SHChangeMenuWasSentByMe(this, pidl1)) { // load new order stream
_LoadOrderStream();
// rebuild toolbar
_SetDirty(TRUE); if (_fShow) _FillToolbar(); } hres = S_OK; } } } break;
case SHCNE_DRIVEADD: case SHCNE_CREATE: case SHCNE_MKDIR: TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Adding item"); pidl1 = ILFindLastID(pidl1); _OnFSNotifyAdd(pidl1); fSizeChanged = TRUE; break;
case SHCNE_DRIVEREMOVED: case SHCNE_DELETE: case SHCNE_RMDIR: TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Removing item"); pidl1 = ILFindLastID(pidl1); _OnFSNotifyRemove(pidl1); fSizeChanged = TRUE; break;
case SHCNE_RENAMEFOLDER: TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: RenameFolder"); // Break if notif is handled or if this is not for our kid.
//
hres = _OnRenameFolder(pidl1, pidl2); if (S_OK == hres) { fSizeChanged = TRUE; break; }
TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: RenameFolder Falling through to RenameItem"); // fall through
case SHCNE_RENAMEITEM: { TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: RenameItem"); BOOL fOurKid1, fOurKid2; LPCITEMIDLIST p1 = pidl1; LPCITEMIDLIST p2 = pidl2;
pidl1 = ILFindLastID(pidl1); pidl2 = ILFindLastID(pidl2);
// An item can be renamed out of this folder.
// Convert that into a remove.
//
fOurKid1 = _IsChildID(p1, TRUE); fOurKid2 = _IsChildID(p2, TRUE); if (fOurKid1 && fOurKid2) { TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Rename: Both are children"); _OnFSNotifyRename(pidl1, pidl2); fSizeChanged = TRUE; hres = S_OK; break; } else if (fOurKid1) { TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Rename: Only one is a child. Removing pidl 1"); _OnFSNotifyRemove(pidl1); fSizeChanged = TRUE; break; } else if (fOurKid2) { // An item can be renamed into this folder.
// Convert that into an add.
//
TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Rename: Only one is a child. Adding pidl2"); _OnFSNotifyAdd(pidl2); fSizeChanged = TRUE; break; } else { // (we get here for guys below us who we don't care about,
// and also for the fallthru from SHCNE_RENAMEFOLDER)
TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: Rename: Not our children"); /*NOTHING*/ hres = E_FAIL; } break; }
case SHCNE_MEDIAINSERTED: case SHCNE_MEDIAREMOVED: case SHCNE_NETUNSHARE: if (_IsEqualID(pidl1)) goto HandleUpdateDir;
case SHCNE_NETSHARE: case SHCNE_UPDATEITEM: if (_IsChildID(pidl1, TRUE)) { pidl1 = ILFindLastID(pidl1);
_OnFSNotifyUpdate(pidl1); fSizeChanged = TRUE; } break;
case SHCNE_UPDATEDIR: // in OnChange we picked off update dir notify and we didn't translate ids
// now we can use ILIsEqual -- translate ids won't translate pidls in case
// of update dir because it looks for immediate child of its, and fails when
// it receives its own pidl
// NOTE: When sftbar is registered recursivly, we only get the pidl of the
// top pane. It is forwarded down to the children. Since this is now a "Child"
// of the top pane, we check to see if this pidl is a child of that pidl, hence the
// ILIsParent(pidl1, _pidl)
// HACKHACK, HUGE HACK: normaly w/ update dir pidl2 is NULL but in start menu
// augmergeisf can change some other notify (e.g. rename folder) to update dir
// in which case pidl2 is not null and we have to see if it is our child to do the
// update (11/18/98) reljai
if (_IsEqualID(pidl1) || // Calling UpdateDir on _THIS_ folder
_IsChildID(pidl1, FALSE) || // BUGBUG (lamadio) Is this needed?
(pidl2 && _IsChildID(pidl2, FALSE)) || // A changed to update (see comment)
_IsParentID(pidl1)) // Some parent in the chain (because it's recursive)
{ HandleUpdateDir: // NOTE: if a series of UPDATEIMAGE notifies gets
// translated to UPDATEDIR and we flicker-perf
// _FillToolbar, we may lose image updates
// (in which case, _Refresh would fix it)
//
TraceMsg(TF_SFTBAR, "CSFTBar::OnTranslateChange: ******* Evil Update Dir *******"); _Refresh(); // don't set this here because filltoolbar will update
//fSizeChanged = TRUE;
} break;
case SHCNE_ASSOCCHANGED: IEInvalidateImageList(); // We may need to use different icons.
_Refresh(); // full refresh for now.
break;
case SHCNE_UPDATEIMAGE: // global
if (pidl1) { int iImage = *(int UNALIGNED *)((BYTE *)pidl1 + 2);
IEInvalidateImageList(); // We may need to use different icons.
if ( pidl2 ) { iImage = SHHandleUpdateImage( pidl2 ); if ( iImage == -1 ) { break; } } if (iImage == -1 || TBHasImage(_hwndTB, iImage)) _Refresh(); } else _Refresh(); // BUGBUG do we need an _UpdateButtons and fSizeChanged?
break;
default: hres = E_FAIL; break; }
if (fSizeChanged) { if (_hwndPager) SendMessage(_hwndPager, PGMP_RECALCSIZE, (WPARAM) 0, (LPARAM) 0); _ToolbarChanged(); }
CleanUp: return hres; }
BOOL TBHasImage(HWND hwnd, int iImageIndex) { BOOL fRefresh = FALSE; for (int i = ToolBar_ButtonCount(hwnd) - 1 ; i >= 0 ; i--) { TBBUTTON tbb; if (SendMessage(hwnd, TB_GETBUTTON, i, (LPARAM)&tbb)) { if (tbb.iBitmap == iImageIndex) { fRefresh = TRUE; break; } } }
return fRefresh; }
void CSFToolbar::_SetToolbarState() { SHSetWindowBits(_hwndTB, GWL_STYLE, TBSTYLE_LIST, (_uIconSize != ISFBVIEWMODE_SMALLICONS || _fNoShowText) ? 0 : TBSTYLE_LIST); }
int CSFToolbar::_DefaultInsertIndex() { return DA_LAST; }
BOOL CSFToolbar::_IsParentID(LPCITEMIDLIST pidl) { // Is the pidl passed in a parent of one of the IDs in the namespace
// or the only one i've got?
if (_ptscn) return S_OK == _ptscn->IsEqualID(NULL, pidl); else return ILIsParent(pidl, _pidl, FALSE); }
BOOL CSFToolbar::_IsEqualID(LPCITEMIDLIST pidl) { if (_ptscn) return S_OK == _ptscn->IsEqualID(pidl, NULL); else return ILIsEqual(_pidl, pidl); }
BOOL CSFToolbar::_IsChildID(LPCITEMIDLIST pidlChild, BOOL fImmediate) { if (_ptscn) return S_OK == _ptscn->IsChildID(pidlChild, fImmediate); else return ILIsParent(_pidl, pidlChild, fImmediate); }
void CSFToolbar::v_CalcWidth(int* pcxMin, int* pcxMax) { ASSERT(IS_VALID_WRITE_PTR(pcxMin, int)); ASSERT(IS_VALID_WRITE_PTR(pcxMax, int)); // Calculate a decent button width given current state
HIMAGELIST himl; int cxMax = 0; int cxMin = 0;
himl = (HIMAGELIST)SendMessage(_hwndTB, TB_GETIMAGELIST, 0, 0); if (himl) { int cy; // Start with the width of the button
ImageList_GetIconSize(himl, &cxMax, &cy);
// We want at least a bit of space around the icon
if (_uIconSize != ISFBVIEWMODE_SMALLICONS) cxMax += 20; else cxMax += 4 * GetSystemMetrics(SM_CXEDGE);
}
// Add in any additional space needed
// Text takes up a bit more space
if (!_fNoShowText) { cxMax += 20;
// Horizontal text takes up a lot
// if we're smallicon with text (horizontal button)
// mode, use the minimized metric to mimic the taskbar
if (_uIconSize == ISFBVIEWMODE_SMALLICONS) cxMax = GetSystemMetrics(SM_CXMINIMIZED); }
*pcxMin = cxMin; *pcxMax = cxMax; }
// Adjust buttons based on current state.
//
void CSFToolbar::_UpdateButtons() { if (_hwndTB) { // set "list" (text on right) or not (text underneath)
// NOTE: list mode always displays some text, don't do it if no text
_SetToolbarState();
v_CalcWidth(&_cxMin, &_cxMax);
SendMessage(_hwndTB, TB_SETBUTTONWIDTH, 0, MAKELONG(_cxMin, _cxMax));
// We just changed the layout
//
SendMessage(_hwndTB, TB_AUTOSIZE, 0, 0); if (_hwndPager) { LRESULT lButtonSize = SendMessage(_hwndTB, TB_GETBUTTONSIZE, 0, 0); Pager_SetScrollInfo(_hwndPager, 50, 1, HIWORD(lButtonSize)); SendMessage(_hwndPager, PGMP_RECALCSIZE, (WPARAM) 0, (LPARAM) 0); } } }
/*----------------------------------------------------------
Purpose: Helper function that calls IShellFolder::GetUIObjectOf().
Returns: pointer to the requested interface NULL if failed */ LPVOID CSFToolbar::_GetUIObjectOfPidl(LPCITEMIDLIST pidl, REFIID riid) { LPCITEMIDLIST * apidl = &pidl; LPVOID pv; if (FAILED(_psf->GetUIObjectOf(GetHWNDForUIObject(), 1, apidl, riid, 0, &pv))) { pv = NULL; }
return(pv); }
INT_PTR CALLBACK CSFToolbar::_RenameDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: { ASSERT(lParam); SetWindowLongPtr(hDlg, DWLP_USER, lParam); EnableWindow(GetDlgItem(hDlg, IDOK), FALSE); // cross-lang platform support
SHSetDefaultDialogFont(hDlg, IDD_NAME); HWND hwndEdit = GetDlgItem(hDlg, IDD_NAME); SendMessage(hwndEdit, EM_LIMITTEXT, MAX_PATH - 1, 0);
TCHAR szText[MAX_PATH + 80]; TCHAR szTemplate[80]; HWND hwndLabel = GetDlgItem(hDlg, IDD_PROMPT); GetWindowText(hwndLabel, szTemplate, ARRAYSIZE(szTemplate)); StringCchPrintf(szText, ARRAYSIZE(szText), szTemplate, lParam); // truncation ok, it's just display text
SetWindowText(hwndLabel, szText); SetWindowText(hwndEdit, (LPTSTR)lParam); break; }
case WM_DESTROY: SHRemoveDefaultDialogFont(hDlg); return FALSE;
case WM_COMMAND: switch (GET_WM_COMMAND_ID(wParam, lParam)) { case IDD_NAME: { if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_UPDATE) { LPTSTR lpstrName = (LPTSTR) GetWindowLongPtr(hDlg, DWLP_USER); EnableOKButtonFromID(hDlg, IDD_NAME); GetDlgItemText(hDlg, IDD_NAME, lpstrName, MAX_PATH); } break; }
case IDOK: { TCHAR szTmp[MAX_PATH]; StringCchCopy(szTmp, ARRAYSIZE(szTmp), (LPTSTR) GetWindowLongPtr(hDlg, DWLP_USER)); // truncation is ok, this is just a renaming something
if (PathCleanupSpec(NULL,szTmp)) { HWND hwnd;
MLShellMessageBox(hDlg, MAKEINTRESOURCE(IDS_FAVS_INVALIDFN), MAKEINTRESOURCE(IDS_FAVS_ADDTOFAVORITES), MB_OK | MB_ICONHAND); hwnd = GetDlgItem(hDlg, IDD_NAME); SetWindowText(hwnd, TEXT('\0')); EnableWindow(GetDlgItem(hDlg, IDOK), FALSE); SetFocus(hwnd); break; } } // fall through
case IDCANCEL: EndDialog(hDlg, GET_WM_COMMAND_ID(wParam, lParam)); break;
default: return FALSE; } break;
default: return FALSE; }
return TRUE; }
// This window proc is used for a temporary worker window that is used to position dialogs
// as well as maintain the correct Z-Order
// NOTE: This is used in mnfolder as well.
LRESULT CALLBACK HiddenWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { // Make sure activation tracks back to the parent.
case WM_ACTIVATE: { if (WA_ACTIVE != LOWORD(wParam)) goto DefWnd;
SetActiveWindow(GetParent(hwnd)); return FALSE; }
case WM_WINDOWPOSCHANGING: { WINDOWPOS* pwp = (WINDOWPOS*)lParam; pwp->flags |= SWP_NOOWNERZORDER; } break; }
DefWnd: return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
HWND CSFToolbar::CreateWorkerWindow() { if (!_hwndWorkerWindow) { _hwndWorkerWindow = SHCreateWorkerWindow(HiddenWndProc, GetHWNDForUIObject(), WS_EX_TOOLWINDOW /*| WS_EX_TOPMOST */, WS_POPUP, 0, _hwndTB); }
return _hwndWorkerWindow; }
HRESULT CSFToolbar::_OnRename(POINT *ppt, int id) { ASSERT(_psf); TCHAR szName[MAX_PATH]; LPCITEMIDLIST pidl = _IDToPidl(id); _ObtainPIDLName(pidl, szName, ARRAYSIZE(szName));
// create a temp window so that placement of the dialog will be close to the point.
// do this so that we'll use USER's code to get placement correctly w/ respect to multimon and work area
_hwndWorkerWindow = CreateWorkerWindow();
SetWindowPos(_hwndWorkerWindow, NULL, ppt->x, ppt->y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
// Now the horrible work of disabling our UI parent window so we can go modal.
// In an ideal world, we would pass our true parent window and USER will do
// all the work of modality, but we have to use our worker window thingie
// to get the dialog positioned correctly with respect to multimon,
// so we have to find the modal parent and disable him the hard way.
//
IUnknown *punkSite; IUnknown *punkTLB;
// Doesn't matter what we SAFECAST "this" to; just pick something to keep the compiler happy
IUnknown_GetSite(SAFECAST(this, IWinEventHandler*), IID_PPV_ARG(IUnknown, &punkSite)); IUnknown_QueryService(punkSite, SID_STopLevelBrowser, IID_PPV_ARG(IUnknown, &punkTLB));
// Tell OLE to go modal
HRESULT hrModeless = IUnknown_EnableModless(punkTLB, FALSE);
// Tell USER to go modal
HWND hwndDisable; IUnknown_GetWindow(punkTLB, &hwndDisable); BOOL bPrevEnabled = FALSE; while (hwndDisable && (GetWindowLong(hwndDisable, GWL_STYLE) & WS_CHILD)) hwndDisable = GetParent(hwndDisable); if (hwndDisable) bPrevEnabled = !EnableWindow(hwndDisable, FALSE);
while (1) { if (DialogBoxParam(MLGetHinst(), MAKEINTRESOURCE(DLG_ISFBANDRENAME), _hwndWorkerWindow, _RenameDlgProc, (LPARAM)szName) != IDOK) break;
WCHAR wsz[MAX_PATH]; SHTCharToUnicode(szName, wsz, ARRAYSIZE(wsz));
if (SUCCEEDED(_psf->SetNameOf(_hwndWorkerWindow, pidl, wsz, 0, NULL))) { SHChangeNotifyHandleEvents(); _SaveOrderStream(); break; } }
// (must undo modality in reverse order)
// Tell USER to return to modeless (as appropriate)
if (hwndDisable) EnableWindow(hwndDisable, bPrevEnabled);
// Tell OLE to return to modeless (as appropriate)
if (SUCCEEDED(hrModeless)) IUnknown_EnableModless(punkTLB, TRUE);
ATOMICRELEASE(punkTLB); ATOMICRELEASE(punkSite);
return S_OK; }
BOOL CSFToolbar::_UpdateIconSize(UINT uIconSize, BOOL fUpdateButtons) { BOOL fChanged = (_uIconSize != uIconSize); _uIconSize = uIconSize;
TraceMsg(TF_BAND, "ISFBand::_UpdateIconSize going %hs", (_uIconSize == ISFBVIEWMODE_LARGEICONS ? "LARGE" : (_uIconSize == ISFBVIEWMODE_SMALLICONS ? "SMALL" : "LOGOS")));
if (_hwndTB) { HIMAGELIST himl = NULL; if (!_fNoIcons) { HIMAGELIST himlLarge, himlSmall;
// set the imagelist size
Shell_GetImageLists(&himlLarge, &himlSmall); himl = (_uIconSize == ISFBVIEWMODE_LARGEICONS ) ? himlLarge : himlSmall; }
// sending a null himl is significant.. it means no image list
SendMessage(_hwndTB, TB_SETIMAGELIST, 0, (LPARAM)himl); if (fUpdateButtons) _UpdateButtons(); } return fChanged; }
HMENU CSFToolbar::_GetContextMenu(IContextMenu* pcm, int* pid) { HMENU hmenu = CreatePopupMenu(); if (hmenu) {
UINT fFlags = CMF_CANRENAME; if (0 > GetKeyState(VK_SHIFT)) fFlags |= CMF_EXTENDEDVERBS;
pcm->QueryContextMenu(hmenu, 0, *pid, CMD_ID_LAST, fFlags); } return hmenu; }
void CSFToolbar::_OnDefaultContextCommand(int idCmd) { }
HRESULT CSFToolbar::_GetTopBrowserWindow(HWND* phwnd) { IUnknown * punkSite;
HRESULT hr = IUnknown_GetSite(SAFECAST(this, IWinEventHandler*), IID_IUnknown, (void**)&punkSite); if (SUCCEEDED(hr)) { hr = SHGetTopBrowserWindow(punkSite, phwnd); punkSite->Release(); }
return hr; }
HRESULT CSFToolbar::_OnOpen(int id, BOOL fExplore) { HRESULT hr = E_FAIL; LPCITEMIDLIST pidl = _IDToPidl(id); if (pidl) { IUnknown* punkSite;
hr = IUnknown_GetSite(SAFECAST(this, IWinEventHandler*), IID_IUnknown, (void**)&punkSite); if (SUCCEEDED(hr)) { DWORD dwFlags = SBSP_DEFBROWSER | SBSP_DEFMODE; if (fExplore) dwFlags |= SBSP_EXPLOREMODE;
hr = SHNavigateToFavorite(_psf, pidl, punkSite, dwFlags);
punkSite->Release(); } }
return hr; }
HRESULT CSFToolbar::_HandleSpecialCommand(IContextMenu* pcm, PPOINT ppt, int id, int idCmd) { TCHAR szCommandString[40];
HRESULT hres = ContextMenu_GetCommandStringVerb(pcm, idCmd, szCommandString, ARRAYSIZE(szCommandString));
if (SUCCEEDED(hres)) { if (lstrcmpi(szCommandString, TEXT("rename")) == 0) return _OnRename(ppt, id); else if (lstrcmpi(szCommandString, TEXT("open")) == 0) return _OnOpen(id, FALSE); else if (lstrcmpi(szCommandString, TEXT("explore")) == 0) return _OnOpen(id, TRUE); }
return S_FALSE; }
LRESULT CSFToolbar::_DoContextMenu(IContextMenu* pcm, LPPOINT ppt, int id, LPRECT prcExclude) { LRESULT lres = 0; int idCmdFirst = CMD_ID_FIRST; HMENU hmContext = _GetContextMenu(pcm, &idCmdFirst); if (hmContext) { int idCmd;
if (_hwndToolTips) SendMessage(_hwndToolTips, TTM_ACTIVATE, FALSE, 0L);
TPMPARAMS tpm; TPMPARAMS * ptpm = NULL;
if (prcExclude) { tpm.cbSize = SIZEOF(tpm); tpm.rcExclude = *((LPRECT)prcExclude); ptpm = &tpm; } idCmd = TrackPopupMenuEx(hmContext, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN, ppt->x, ppt->y, _hwndTB, ptpm);
if (_hwndToolTips) SendMessage(_hwndToolTips, TTM_ACTIVATE, TRUE, 0L); if (idCmd) { if (idCmd < idCmdFirst) { _OnDefaultContextCommand(idCmd); } else { idCmd -= idCmdFirst;
if (_HandleSpecialCommand(pcm, ppt, id, idCmd) != S_OK) { _hwndWorkerWindow = CreateWorkerWindow();
SetWindowPos(_hwndWorkerWindow, NULL, ppt->x, ppt->y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
CMINVOKECOMMANDINFO ici = { SIZEOF(CMINVOKECOMMANDINFO), 0, _hwndWorkerWindow, MAKEINTRESOURCEA(idCmd), NULL, NULL, SW_NORMAL, };
pcm->InvokeCommand(&ici); } } }
// if we get this far
// we need to return handled so that WM_CONTEXTMENU doesn't come through
lres = 1; DestroyMenu(hmContext); }
return lres; }
LRESULT CSFToolbar::_OnContextMenu(WPARAM wParam, LPARAM lParam) { LRESULT lres = 0; RECT rc; LPRECT prcExclude = NULL; POINT pt; int i;
if (lParam != (LPARAM)-1) { pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam);
POINT pt2 = pt; MapWindowPoints(HWND_DESKTOP, _hwndTB, &pt2, 1);
i = ToolBar_HitTest(_hwndTB, &pt2); } else { // keyboard context menu.
i = (int)SendMessage(_hwndTB, TB_GETHOTITEM, 0, 0); if (i >= 0) { SendMessage(_hwndTB, TB_GETITEMRECT, i, (LPARAM)&rc); MapWindowPoints(_hwndTB, HWND_DESKTOP, (LPPOINT)&rc, 2); pt.x = rc.left; pt.y = rc.bottom; prcExclude = &rc; } }
TraceMsg(TF_BAND, "NM_RCLICK %d,%d = %d", pt.x, pt.y, i);
if (i >= 0) { UINT id = _IndexToID(i); LPCITEMIDLIST pidl = _IDToPidl(id, NULL);
if (pidl) { LPCONTEXTMENU pcm = (LPCONTEXTMENU)_GetUIObjectOfPidl(pidl, IID_IContextMenu); if (pcm) { // grab pcm2 for owner draw support
pcm->QueryInterface(IID_IContextMenu2, (LPVOID *)&_pcm2);
ToolBar_MarkButton(_hwndTB, id, TRUE);
lres = _DoContextMenu(pcm, &pt, id, prcExclude);
ToolBar_MarkButton(_hwndTB, id, FALSE);
if (lres) _FlushNotifyMessages(_hwndTB);
ATOMICRELEASE(_pcm2); pcm->Release(); } } }
return lres; }
LRESULT CSFToolbar::_OnCustomDraw(NMCUSTOMDRAW* pnmcd) { return CDRF_DODEFAULT; }
void CSFToolbar::_OnDragBegin(int iItem, DWORD dwPreferedEffect) { LPCITEMIDLIST pidl = _IDToPidl(iItem, &_iDragSource); ToolBar_SetHotItem(_hwndTB, _iDragSource);
if (_hwndTB) DragDrop(_hwndTB, _psf, pidl, dwPreferedEffect, NULL); _iDragSource = -1; }
LRESULT CSFToolbar::_OnHotItemChange(NMTBHOTITEM * pnm) { LPNMTBHOTITEM lpnmhi = (LPNMTBHOTITEM)pnm;
if (_hwndPager && (lpnmhi->dwFlags & (HICF_ARROWKEYS | HICF_ACCELERATOR)) ) { int iOldPos, iNewPos; RECT rc, rcPager; int heightPager; int iSelected = lpnmhi->idNew; iOldPos = (int)SendMessage(_hwndPager, PGM_GETPOS, (WPARAM)0, (LPARAM)0); iNewPos = iOldPos; SendMessage(_hwndTB, TB_GETITEMRECT, (WPARAM)iSelected, (LPARAM)&rc); if (rc.top < iOldPos) { iNewPos =rc.top; } GetClientRect(_hwndPager, &rcPager); heightPager = RECTHEIGHT(rcPager); if (rc.top >= iOldPos + heightPager) { iNewPos += (rc.bottom - (iOldPos + heightPager)) ; } if (iNewPos != iOldPos) SendMessage(_hwndPager, PGM_SETPOS, (WPARAM)0, (LPARAM)iNewPos); }
return 0; }
void CSFToolbar::_OnToolTipsCreated(NMTOOLTIPSCREATED* pnm) { _hwndToolTips = pnm->hwndToolTips; SHSetWindowBits(_hwndToolTips, GWL_STYLE, TTS_ALWAYSTIP | TTS_TOPMOST | TTS_NOPREFIX, TTS_ALWAYSTIP | TTS_TOPMOST | TTS_NOPREFIX);
// set the AutoPopTime (the duration of showing the tooltip) to a large value
SendMessage(_hwndToolTips, TTM_SETDELAYTIME, TTDT_AUTOPOP, (LPARAM)MAXSHORT); }
LRESULT CSFToolbar::_OnNotify(LPNMHDR pnm) { LRESULT lres = 0;
//The following statement traps all pager control notification messages.
if((pnm->code <= PGN_FIRST) && (pnm->code >= PGN_LAST)) { return SendMessage(_hwndTB, WM_NOTIFY, (WPARAM)0, (LPARAM)pnm); }
switch (pnm->code) { case TBN_DRAGOUT: { TBNOTIFY *ptbn = (TBNOTIFY*)pnm; _OnDragBegin(ptbn->iItem, 0); lres = 1; break; } case TBN_HOTITEMCHANGE: _OnHotItemChange((LPNMTBHOTITEM)pnm); break;
case TBN_GETINFOTIP: { LPNMTBGETINFOTIP pnmTT = (LPNMTBGETINFOTIP)pnm; UINT uiCmd = pnmTT->iItem; DWORD dwFlags = _fNoShowText ? QITIPF_USENAME | QITIPF_LINKNOTARGET : QITIPF_LINKNOTARGET;
if (!GetInfoTipEx(_psf, dwFlags, _IDToPidl(uiCmd), pnmTT->pszText, pnmTT->cchTextMax)) { TBBUTTONINFO tbbi = { 0}; tbbi.cbSize = SIZEOF(tbbi); tbbi.dwMask = TBIF_TEXT; tbbi.pszText = pnmTT->pszText; tbbi.cchText = pnmTT->cchTextMax; lres = (-1 != ToolBar_GetButtonInfo(_hwndTB, uiCmd, &tbbi)); }
break; }
//BUGBUG: Right now I am calling the same function for both A and W version if this notification supports
// Strings then it needs to thunk. Right now its only used for image
case TBN_GETDISPINFOA: _OnGetDispInfo(pnm, FALSE); break; case TBN_GETDISPINFOW: _OnGetDispInfo(pnm, TRUE); break; case NM_TOOLTIPSCREATED: _OnToolTipsCreated((NMTOOLTIPSCREATED*)pnm); break;
case NM_RCLICK: lres = _OnContextMenu(NULL, GetMessagePos()); break;
case NM_CUSTOMDRAW: return _OnCustomDraw((NMCUSTOMDRAW*)pnm);
}
return(lres); }
DWORD CSFToolbar::_GetAttributesOfPidl(LPCITEMIDLIST pidl, DWORD dwAttribs) { if (FAILED(_psf->GetAttributesOf(1, &pidl, &dwAttribs))) dwAttribs = 0;
return dwAttribs;
}
PIBDATA CSFToolbar::_PosToPibData(UINT iPos) { ASSERT(IsWindow(_hwndTB));
// Initialize to NULL in case the GetButton Fails.
TBBUTTON tbb = {0}; PIBDATA pibData = NULL; if (ToolBar_GetButton(_hwndTB, iPos, &tbb)) { pibData = (PIBDATA)tbb.dwData; }
return pibData; }
PIBDATA CSFToolbar::_IDToPibData(UINT uiCmd, int * piPos) { PIBDATA pibdata = NULL;
// Initialize to NULL in case the GetButtonInfo Fails.
TBBUTTONINFO tbbi = {0}; int iPos;
tbbi.cbSize = SIZEOF(tbbi); tbbi.dwMask = TBIF_LPARAM;
iPos = ToolBar_GetButtonInfo(_hwndTB, uiCmd, &tbbi); if (iPos >= 0) pibdata = (PIBDATA)tbbi.lParam;
if (piPos) *piPos = iPos;
return pibdata; }
LPCITEMIDLIST CSFToolbar::_IDToPidl(UINT uiCmd, int *piPos) { LPCITEMIDLIST pidl; PIBDATA pibdata = _IDToPibData(uiCmd, piPos);
if (pibdata) pidl = pibdata->GetPidl(); else pidl = NULL;
return pidl; }
/*----------------------------------------------------------
Purpose: IWinEventHandler::OnWinEvent method
Processes messages passed on from the bandsite. */ HRESULT CSFToolbar::OnWinEvent(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres) { *plres = 0; // We are addref'n here because during the course of the
// Context menu, the view could be changed which free's the menu.
// We will release after we're sure the this pointer is no longer needed.
AddRef(); switch (uMsg) { case WM_WININICHANGE: if ((SHIsExplorerIniChange(wParam, lParam) == EICH_UNKNOWN) || (wParam == SPI_SETNONCLIENTMETRICS)) { _UpdateIconSize(_uIconSize, TRUE); _Refresh(); goto L_WM_SYSCOLORCHANGE; } break;
case WM_SYSCOLORCHANGE: L_WM_SYSCOLORCHANGE: SendMessage(_hwndTB, uMsg, wParam, lParam); InvalidateRect(_hwndTB, NULL, TRUE); break;
case WM_PALETTECHANGED: InvalidateRect( _hwndTB, NULL, FALSE ); SendMessage( _hwndTB, uMsg, wParam, lParam ); break; case WM_COMMAND: *plres = _OnCommand(wParam, lParam); break; case WM_NOTIFY: *plres = _OnNotify((LPNMHDR)lParam); break;
case WM_CONTEXTMENU: *plres = _OnContextMenu(wParam, lParam); break; }
Release(); return S_OK; }
// Map the information loaded (or ctor) into _psf, [_pidl]
//
HRESULT CSFToolbar::_AfterLoad() { HRESULT hres = S_OK;
// if we have a pidl then we need to get ready
// for notifications...
//
if (_pidl) { // pidls must be rooted off the desktop
//
_fFSNotify = TRUE;
// shortcut -- just specifying a pidl is good enough
//
if (!_psf) { _fPSFBandDesktop = TRUE; hres = IEBindToObject(_pidl, &_psf); } }
return(hres); } // IDropTarget implementation
//
/*----------------------------------------------------------
Purpose: CDelegateDropTarget::GetWindowsDDT
*/ HRESULT CSFToolbar::GetWindowsDDT(HWND * phwndLock, HWND * phwndScroll) { *phwndLock = _hwndTB; *phwndScroll = _hwndTB; return S_OK; }
/*----------------------------------------------------------
Purpose: CDelegateDropTarget::HitTestDDT
*/ HRESULT CSFToolbar::HitTestDDT(UINT nEvent, LPPOINT ppt, DWORD_PTR * pdwId, DWORD *pdwEffect) { TBINSERTMARK tbim;
switch (nEvent) { case HTDDT_ENTER: return S_OK;
case HTDDT_OVER: { int iButton = IBHT_BACKGROUND; // assume we hit the background
// if we're the source, this may be a move operation
//
*pdwEffect = (_iDragSource >= 0) ? DROPEFFECT_MOVE : DROPEFFECT_NONE; if (!ToolBar_InsertMarkHitTest(_hwndTB, ppt, &tbim)) { if (tbim.dwFlags & TBIMHT_BACKGROUND) { RECT rc; GetClientRect(_hwndTB, &rc);
// are we outside the toolbar window entirely?
if (!PtInRect(&rc, *ppt)) { // rebar already did the hittesting so we are on the rebar
// but not the toolbar => we are in the title part
if (!_AllowDropOnTitle()) { // yes; don't allow drop here
iButton = IBHT_OUTSIDEWINDOW; *pdwEffect = DROPEFFECT_NONE; }
// set tbim.iButton to invalid value so we don't draw insert mark
tbim.iButton = -1; } } else { // nope, we hit a real button
//
if (tbim.iButton == _iDragSource) { iButton = IBHT_SOURCE; // don't drop on the source button
} else { iButton = tbim.iButton; } tbim.iButton = IBHT_BACKGROUND;
// we never force a move operation if we're on a real button
*pdwEffect = DROPEFFECT_NONE; } }
*pdwId = iButton; } break;
case HTDDT_LEAVE: // Reset
tbim.iButton = IBHT_BACKGROUND; tbim.dwFlags = 0; break;
default: return E_INVALIDARG; }
// update ui
if (tbim.iButton != _tbim.iButton || tbim.dwFlags != _tbim.dwFlags) { if (ppt) _tbim = tbim;
// for now I don't want to rely on non-filesystem IShellFolder
// implementations to call our OnChange method when a drop occurs,
// so don't even show the insert mark.
//
if (_fFSNotify || _iDragSource >= 0) { DAD_ShowDragImage(FALSE); ToolBar_SetInsertMark(_hwndTB, &tbim); DAD_ShowDragImage(TRUE); } }
return S_OK; }
/*----------------------------------------------------------
Purpose: CDelegateDropTarget::GetObjectDDT
*/ HRESULT CSFToolbar::GetObjectDDT(DWORD_PTR dwId, REFIID riid, LPVOID * ppvObj) { HRESULT hres = E_NOINTERFACE;
*ppvObj = NULL;
if ((IBHT_SOURCE == dwId) || (IBHT_OUTSIDEWINDOW == dwId)) { // do nothing
} else if (IBHT_BACKGROUND == dwId) { // nash:41937: not sure how, but _psf can be NULL...
if (EVAL(_psf)) hres = _psf->CreateViewObject(_hwndTB, riid, ppvObj); } else { LPCITEMIDLIST pidl = _IDToPidl((UINT)dwId, NULL);
if (pidl) { *ppvObj = _GetUIObjectOfPidl(pidl, riid);
if (*ppvObj) hres = S_OK; } }
//TraceMsg(TF_BAND, "SFToolbar::GetObject(%d) returns %x", dwId, hres);
return hres; }
HRESULT CSFToolbar::_SaveOrderStream() { if (_fChangedOrder) { // Notify everyone that the order changed
SHSendChangeMenuNotify(this, SHCNEE_ORDERCHANGED, 0, _pidl); _fChangedOrder = FALSE; return S_OK; } else return S_FALSE; }
void CSFToolbar::_Dropped(int nIndex, BOOL fDroppedOnSource) { _fDropped = TRUE; _fChangedOrder = TRUE;
// Save new order stream
_SaveOrderStream();
if (fDroppedOnSource) _FlushNotifyMessages(_hwndTB); }
/*----------------------------------------------------------
Purpose: CDelegateDropTarget::OnDropDDT
*/ HRESULT CSFToolbar::OnDropDDT(IDropTarget *pdt, IDataObject *pdtobj, DWORD * pgrfKeyState, POINTL pt, DWORD *pdwEffect) { // Are we NOT the drag source?
if (_iDragSource == -1) { // No, we're not. Well, then the source may be the chevron menu
// representing the hidden items in this menu. Let's check
LPITEMIDLIST pidl; if (SUCCEEDED(SHPidlFromDataObject2(pdtobj, &pidl))) { // We've got a pidl, Are we the parent? Do we have a button?
int iIndex; if (ILIsParent(_pidl, pidl, TRUE) && _GetButtonFromPidl(ILFindLastID(pidl), NULL, &iIndex)) { // We are the parent! Then let's copy that down and set it
// as the drag source so that down below we reorder.
_iDragSource = iIndex; } ILFree(pidl); } }
if (_iDragSource >= 0) { if (_fAllowReorder) { TraceMsg(TF_BAND, "SFToolbar::OnDrop reorder %d to %d %s", _iDragSource, _tbim.iButton, _tbim.dwFlags & TBIMHT_AFTER ? "A" : "B");
int iNewLocation = _tbim.iButton; if (_tbim.dwFlags & TBIMHT_AFTER) iNewLocation++;
if (iNewLocation > _iDragSource) iNewLocation--;
if (ToolBar_MoveButton(_hwndTB, _iDragSource, iNewLocation)) { PORDERITEM poi = (PORDERITEM)DPA_FastGetPtr(_hdpa, _iDragSource); DPA_DeletePtr(_hdpa, _iDragSource); DPA_InsertPtr(_hdpa, iNewLocation, poi);
OrderList_Reorder(_hdpa);
// If we're dropping again, then we don't need the _hdpaOrder...
OrderList_Destroy(&_hdpaOrder);
// A reorder has occurred. We need to use the order stream as the order...
_fHasOrder = TRUE; _fDropping = TRUE; _Dropped(iNewLocation, TRUE); _fDropping = FALSE; _RememberOrder(); _SetDirty(TRUE); } }
// Don't forget to reset this!
_iDragSource = -1;
DragLeave(); } else { // We want to override the default to be LINK (SHIFT+CONTROL)
if ((GetPreferedDropEffect(pdtobj) == 0) && !(*pgrfKeyState & (MK_CONTROL | MK_SHIFT | MK_ALT))) { // NOTE: not all data objects will allow us to call SetData()
_SetPreferedDropEffect(pdtobj, DROPEFFECT_LINK); }
_fDropping = TRUE; return S_OK; }
return S_FALSE; }
void CSFToolbar::_SortDPA(HDPA hdpa) { // If we don't have a _psf, then we certainly can't sort it
// If we don't have a hdpa, then we certainly can't sort it
// If the hdpa is empty, then there's no point in sorting it
if (_psf && hdpa && DPA_GetPtrCount(hdpa)) { ORDERINFO oinfo; oinfo.psf = _psf; (oinfo.psf)->AddRef(); oinfo.dwSortBy = (_fNoNameSort ? OI_SORTBYORDINAL : OI_SORTBYNAME); DPA_Sort(hdpa, OrderItem_Compare, (LPARAM)&oinfo); ATOMICRELEASE(oinfo.psf); } }
void CSFToolbar::_RememberOrder() { OrderList_Destroy(&_hdpaOrder);
if (_hdpa) { _hdpaOrder = OrderList_Clone(_hdpa); _SortDPA(_hdpaOrder); } }
HMENU CSFToolbar::_GetBaseContextMenu() { HMENU hmenu = LoadMenuPopup_PrivateNoMungeW(MENU_ISFBAND); // no logo view, remove the menu item...
HMENU hView = GetSubMenu( hmenu, 0 ); DeleteMenu( hView, ISFBIDM_LOGOS, MF_BYCOMMAND ); return hmenu; }
HMENU CSFToolbar::_GetContextMenu() { HMENU hmenuSrc = _GetBaseContextMenu(); if (hmenuSrc) { MENUITEMINFO mii;
mii.cbSize = SIZEOF(mii); mii.fMask = MIIM_STATE; mii.fState = MF_CHECKED;
UINT uCmdId = ISFBIDM_LOGOS; if ( _uIconSize != ISFBVIEWMODE_LOGOS ) uCmdId = (_uIconSize == ISFBVIEWMODE_LARGEICONS ? ISFBIDM_LARGE : ISFBIDM_SMALL); SetMenuItemInfo(hmenuSrc, uCmdId, MF_BYCOMMAND, &mii); if (!_fNoShowText) SetMenuItemInfo(hmenuSrc, ISFBIDM_SHOWTEXT, MF_BYCOMMAND, &mii); if (!_fFSNotify || !_pidl || ILIsEmpty(_pidl)) DeleteMenu(hmenuSrc, ISFBIDM_OPEN, MF_BYCOMMAND);
HMENU hView = GetSubMenu( hmenuSrc, 0 ); DeleteMenu( hView, ISFBIDM_LOGOS, MF_BYCOMMAND );
}
return hmenuSrc; } // IContextMenu implementation
//
HRESULT CSFToolbar::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) { HMENU hmenuSrc = _GetContextMenu(); int i = 0; if ( hmenuSrc ) { i += Shell_MergeMenus(hmenu, hmenuSrc, indexMenu, idCmdFirst, idCmdLast, MM_ADDSEPARATOR); DestroyMenu(hmenuSrc); } if (!_pcmSF && _fAllowRename && _psf) { _psf->CreateViewObject(_hwndTB, IID_IContextMenu, (LPVOID*)&_pcmSF); } if (_pcmSF) { HRESULT hresT; _idCmdSF = i - idCmdFirst; hresT = _pcmSF->QueryContextMenu(hmenu, indexMenu + i, i, 0x7fff, CMF_BANDCMD); if (SUCCEEDED(hresT)) i += HRESULT_CODE(hresT); } return i; }
BOOL CSFToolbar::_UpdateShowText(BOOL fNoShowText) { BOOL fChanged = (!_fNoShowText != !fNoShowText); _fNoShowText = (fNoShowText != 0);
TraceMsg(TF_BAND, "ISFBand::_UpdateShowText turning text %hs", _fNoShowText ? "OFF" : "ON");
if (_hwndTB) { SendMessage(_hwndTB, TB_SETMAXTEXTROWS, _fNoShowText ? 0 : 1, 0L);
_UpdateButtons(); } return fChanged; }
HRESULT CSFToolbar::InvokeCommand(LPCMINVOKECOMMANDINFO lpici) { BOOL fChanged = FALSE; int idCmd = -1;
if (!HIWORD(lpici->lpVerb)) idCmd = LOWORD(lpici->lpVerb);
switch (idCmd) { case ISFBIDM_REFRESH: _Refresh(); break; case ISFBIDM_OPEN: OpenFolderPidl(_pidl); break; case ISFBIDM_LARGE: fChanged = _UpdateIconSize(ISFBVIEWMODE_LARGEICONS, TRUE); break; case ISFBIDM_SMALL: fChanged = _UpdateIconSize(ISFBVIEWMODE_SMALLICONS, TRUE); break;
case ISFBIDM_SHOWTEXT: fChanged = _UpdateShowText(!_fNoShowText); break; default: if (_pcmSF && idCmd >= _idCmdSF) { LPCSTR lpOldVerb = lpici->lpVerb; lpici->lpVerb = MAKEINTRESOURCEA(idCmd -= _idCmdSF); _pcmSF->InvokeCommand(lpici); _FlushNotifyMessages(_hwndTB);
lpici->lpVerb = lpOldVerb; } else TraceMsg(TF_BAND, "SFToolbar::InvokeCommand %d not handled", idCmd); break; } // Our minimum sizes have changed, notify the bandsite
//
if (fChanged) _ToolbarChanged();
return(S_OK); }
HRESULT CSFToolbar::GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax) { return(E_NOTIMPL); }
void CSFToolbar::_RegisterToolbar() { // Since _SubclassWindow protects against multiply subclassing,
// This call is safe, and ensures that the toolbar is subclassed before
// even trying to register it for change notify.
if (_hwndTB && _SubclassWindow(_hwndTB) && _fRegisterChangeNotify) _RegisterChangeNotify(); CDelegateDropTarget::Init(); }
void CSFToolbar::_UnregisterToolbar() { if (_hwndTB) { if (_fRegisterChangeNotify) _UnregisterChangeNotify(); _UnsubclassWindow(_hwndTB); } }
void CSFToolbar::_RegisterChangeNotify() { // Since we want to register for change notify ONLY once,
// and only if this is a file system toolbar.
if (!_fFSNRegistered && _fFSNotify) { if (_ptscn) _ptscn->Register(_hwndTB, g_idFSNotify, _lEvents); else _RegisterWindow(_hwndTB, _pidl, _lEvents);
_fFSNRegistered = TRUE; } }
void CSFToolbar::_UnregisterChangeNotify() { // Only unregister if we have been registered.
if (_hwndTB && _fFSNRegistered && _fFSNotify) { _fFSNRegistered = FALSE; if (_ptscn) _ptscn->Unregister(); else _UnregisterWindow(_hwndTB);
} }
void CSFToolbar::_ReleaseShellFolder() { if (_psf) { IUnknown_SetOwner(_psf, NULL); ATOMICRELEASE(_psf); } ATOMICRELEASE(_ptscn); }
/*----------------------------------------------------------
Purpose: IWinEventHandler::IsWindowOwner method.
*/ HRESULT CSFToolbar::IsWindowOwner(HWND hwnd) { if (hwnd == _hwndTB || hwnd == _hwndToolTips || hwnd == _hwndPager) return S_OK; return S_FALSE; }
|