|
|
/**************************************************************\
FILE: NSCBand.cpp
DESCRIPTION: implementation of CNSCBand. the class CNSCBand exists to support name space control bands. A name space control uses IShellFolder rooted in various namespaces including Favorites, history, Shell Name Space, etc. to depict a hierarchical UI representation of the given name space. AUTHOR: chrisny
\**************************************************************/ #include "priv.h"
#include "sccls.h"
#include "util.h"
#include "resource.h"
#include "dhuihand.h"
#include "nscband.h"
#include <varutil.h>
#include <mluisupp.h>
HRESULT CNSCBand::_Init(LPCITEMIDLIST pidl) { // further initialization happens in ShowDW
_fInited = FALSE; _fVisible = FALSE; _fCanFocus = TRUE; _haccTree = LoadAccelerators(MLGetHinst(), MAKEINTRESOURCE(ACCEL_FAVBAR));
// pidl can be real or a CSIDL_ constant
if (HIWORD(pidl)) _pidl = ILClone(pidl); else SHGetSpecialFolderLocation(NULL, LOWORD(pidl), &_pidl);
return _pidl ? S_OK : E_FAIL; }
CNSCBand::~CNSCBand() { if (_pidl) ILFree(_pidl); ATOMICRELEASE(_pns); ATOMICRELEASE(_pweh);
if (_himlNormal) ImageList_Destroy(_himlNormal); if (_himlHot) ImageList_Destroy(_himlHot); }
HRESULT CNSCBand::QueryInterface(REFIID riid, void **ppvObj) { static const QITAB qit[] = { QITABENT(CNSCBand, IContextMenu), // IID_IContextMenu
QITABENT(CNSCBand, IWinEventHandler), // IID_IWinEventHandler
QITABENT(CNSCBand, IBandNavigate), // IID_IBandNavigate
QITABENT(CNSCBand, INamespaceProxy), // IID_INamespaceProxy
{ 0 }, }; HRESULT hres = QISearch(this, qit, riid, ppvObj); if (FAILED(hres)) hres = CToolBand::QueryInterface(riid, ppvObj); return hres; }
#ifndef ENABLE_CCHANNELBAND
HRESULT CNSCBand_CreateInstanceEx(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi, LPCITEMIDLIST pidl) { // aggregation checking is handled in class factory
HRESULT hres; CNSCBand * p = new CNSCBand(); if (p) { hres = p->_Init(pidl); if (SUCCEEDED(hres)) { p->_pns = CNscTree_CreateInstance(); if (p->_pns) { p->_poi = poi; // if you change this cast, fix up CChannelBand_CreateInstance
*ppunk = SAFECAST(p, IDeskBand *);
IUnknown_SetSite(p->_pns, *ppunk); hres = S_OK; } } p->Release(); } else hres = E_OUTOFMEMORY; return hres; } #endif
#ifdef ENABLE_CHANNELS
extern LPITEMIDLIST Channel_GetFolderPidl();
HRESULT CChannelBand_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi) { #ifndef ENABLE_CCHANNELBAND
ASSERT(FALSE); return E_FAIL; #else
HRESULT hres = CNSCBand_CreateInstanceEx(punkOuter, ppunk, poi, Channel_GetFolderPidl()); if (*ppunk) { CNSCBand* p = (CNSCBand*)(IDeskBand*)*ppunk; p->_SetNscMode(MODE_CHANNELS); } return hres; #endif
}
#endif // ENABLE_CHANNELS
extern HRESULT GetHistoryPIDL(LPITEMIDLIST *ppidlHistory);
HRESULT CNSCBand::CloseDW(DWORD dw) { if (_fVisible) { _UnregisterBand(); }
if (_pns) { IUnknown_SetSite(_pns, NULL); // Break the ref-count cycle.
}
return CToolBand::CloseDW(dw); }
void CNSCBand::_UnregisterBand() { IBrowserService *pswProxy; QueryService(SID_SProxyBrowser, IID_IBrowserService, (LPVOID*)&pswProxy); ASSERT(pswProxy); if (pswProxy) { IOleCommandTarget *poctProxy;
if (SUCCEEDED(pswProxy->QueryInterface(IID_IOleCommandTarget, (void **)&poctProxy))) { VARIANT var; VariantInit(&var); // Register ourselves for SBCMDID_SELECTHISTPIDL,SBCMDID_INITFILECTXMENU
var.vt = VT_UNKNOWN; QueryInterface(IID_IUnknown, (void **)&var.punkVal); poctProxy->Exec(&CGID_Explorer, SBCMDID_UNREGISTERNSCBAND, OLECMDEXECOPT_PROMPTUSER, &var, NULL); VariantClear(&var); poctProxy->Release(); } pswProxy->Release(); } }
HRESULT CNSCBand::_InitializeNsc() { return _pns->Initialize(_pidl, _GetEnumFlags(), NSS_DROPTARGET | NSS_BROWSERSELECT); }
HRESULT CNSCBand::ShowDW(BOOL fShow) { BOOL fIsHistory = IsEqualCLSID(*_poi->pclsid, CLSID_HistBand); if (fShow && _hwnd && !_fVisible) { IBrowserService *pswProxy;
QueryService(SID_SProxyBrowser, IID_PPV_ARG(IBrowserService, &pswProxy)); ASSERT(pswProxy); if (!_fInited) { _InitializeNsc(); } else { _pns->ShowWindow(TRUE); }
if (pswProxy) { IOleCommandTarget *poctProxy;
if (SUCCEEDED(pswProxy->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &poctProxy)))) { VARIANT var; VariantInit(&var); // Register ourselves for SBCMDID_SELECTHISTPIDL,SBCMDID_INITFILECTXMENU
var.vt = VT_UNKNOWN; QueryInterface(IID_PPV_ARG(IUnknown, &var.punkVal));
poctProxy->Exec(&CGID_Explorer, SBCMDID_REGISTERNSCBAND, OLECMDEXECOPT_PROMPTUSER, &var, NULL);
//clear the variant cheaply
var.vt = VT_EMPTY; Release();
// do any special registration if necessary
_OnRegisterBand(poctProxy); poctProxy->Release(); } pswProxy->Release(); } _fInited = TRUE; _fVisible = TRUE; } else if (!fShow && _fVisible) { _pns->ShowWindow(FALSE); _UnregisterBand(); _fVisible = FALSE; }
return CToolBand::ShowDW(fShow); }
HRESULT CNSCBand::GetWindow(HWND *phwnd) { INSCTree2 *pns2; HRESULT hr = _pns->QueryInterface(IID_PPV_ARG(INSCTree2, &pns2)); if (SUCCEEDED(hr)) { pns2->CreateTree2(_hwndParent, _GetTVStyle(), _GetTVExStyle(), &_hwnd); hr = CToolBand::GetWindow(phwnd); pns2->Release(); }
return hr; }
DWORD CNSCBand::_GetTVStyle() { DWORD dwFlags = TVS_FULLROWSELECT | TVS_TRACKSELECT | TVS_INFOTIP; DWORD dwValue; DWORD dwSize = SIZEOF(dwValue); BOOL fDefault = TRUE;
SHRegGetUSValue(L"Software\\Microsoft\\Internet Explorer\\Main", L"NscSingleExpand", NULL, (LPBYTE)&dwValue, &dwSize, FALSE, (void *) &fDefault, SIZEOF(fDefault));
if (dwValue) dwFlags |= TVS_SINGLEEXPAND;
return dwFlags; }
HRESULT CNSCBand::GetBandInfo(DWORD dwBandID, DWORD fViewMode, DESKBANDINFO* pdbi) { _dwBandID = dwBandID; pdbi->dwModeFlags = DBIMF_FIXEDBMP | DBIMF_VARIABLEHEIGHT; pdbi->ptMinSize.x = 16; pdbi->ptMinSize.y = 0; pdbi->ptMaxSize.x = 32000; // random
pdbi->ptMaxSize.y = 32000; // random
pdbi->ptActual.y = -1; pdbi->ptActual.x = -1; pdbi->ptIntegral.y = 1;
if (_szTitle[0]) { StrCpyNW(pdbi->wszTitle, _szTitle, ARRAYSIZE(pdbi->wszTitle)); } else { CLSID clsid; UINT ids; GetClassID(&clsid); if (IsEqualIID(clsid, CLSID_FavBand)) ids = IDS_BAND_FAVORITES; else if (IsEqualIID(clsid, CLSID_HistBand)) ids = IDS_BAND_HISTORY; else if (IsEqualIID(clsid, CLSID_ExplorerBand)) ids = IDS_BAND_EXPLORER; else { ASSERT(FALSE); // BOGUS BAND!!!
return S_FALSE; } MLLoadStringW(ids, pdbi->wszTitle, ARRAYSIZE(pdbi->wszTitle)); } return S_OK; }
void _InitColors(BOOL fReinit);
// *** IWinEventHandler methods ***
HRESULT CNSCBand::OnWinEvent(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres) { HRESULT hr = E_FAIL;
if (!_pweh && _pns) _pns->QueryInterface(IID_IWinEventHandler, (void **) &_pweh);
// We need to tell the bandsite that we have become active if we're getting a
// click focus or something
if (uMsg == WM_NOTIFY && ((LPNMHDR)lParam)->code == NM_SETFOCUS) { IUnknown_OnFocusChangeIS(_punkSite, SAFECAST(this, IInputObject*), TRUE); }
if (_pweh) hr = _pweh->OnWinEvent(hwnd, uMsg, wParam, lParam, plres);
return hr; }
HRESULT CNSCBand::IsWindowOwner(HWND hwnd) { HRESULT hres;
hres = SHIsChildOrSelf(_hwnd, hwnd); ASSERT(hwnd != NULL || hres == S_FALSE); ASSERT(_hwnd != NULL || hres == S_FALSE); return hres; }
//*** CNSCBand::IPersistStream::* {
HRESULT CNSCBand::GetClassID(CLSID *pClassID) { ASSERT(_poi->pclsid != NULL); *pClassID = *(_poi->pclsid); return S_OK; }
HRESULT CNSCBand::Load(IStream *pstm) { return S_OK; }
HRESULT CNSCBand::Save(IStream *pstm, BOOL fClearDirty) { return S_OK; }
// }
//*** CNSCBand::IContextMenu::* {
HRESULT CNSCBand::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) { int i = 0; #if 0
HMENU hmenuMe = LoadMenuPopup(MENU_IWBBAND);
i += Shell_MergeMenus(hmenu, hmenuMe, indexMenu, idCmdFirst + i, idCmdLast, MM_ADDSEPARATOR) - (idCmdFirst + i); DestroyMenu(hmenuMe); #endif
// aka (S_OK|i)
return MAKE_HRESULT(ERROR_SUCCESS, FACILITY_NULL, i); }
HRESULT CNSCBand::InvokeCommand(LPCMINVOKECOMMANDINFO pici) { #if 0
int idCmd = -1;
if (!HIWORD(pici->lpVerb)) idCmd = LOWORD(pici->lpVerb); switch (idCmd) { case default: TraceMsg(DM_ERROR, "cbb::ic cmd=%d not handled", idCmd); break; } #endif
return S_OK; }
HRESULT CNSCBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext) { if (pguidCmdGroup && IsEqualGUID(CGID_Explorer, *pguidCmdGroup)) { for (UINT i=0; i < cCmds; i++) { rgCmds[i].cmdf = 0; switch (rgCmds[i].cmdID) { case SBCMDID_INITFILECTXMENU: if (_hwnd && _fVisible) { rgCmds->cmdf = 0; if (pcmdtext) pcmdtext->cmdtextf = 0;
if (pcmdtext) { if (SUCCEEDED(_pns->GetSelectedItemName(pcmdtext->rgwz, pcmdtext->cwBuf))) { rgCmds->cmdf = OLECMDF_ENABLED; pcmdtext->cmdtextf = OLECMDTEXTF_NAME; pcmdtext->cwActual = lstrlenW(pcmdtext->rgwz) + 1; } } } break;
case SBCMDID_FILERENAME: case SBCMDID_FILEDELETE: case SBCMDID_FILEPROPERTIES: { LPITEMIDLIST pidl;
// get selected item can return NULL pidl and S_FALSE
if (_pns->GetSelectedItem(&pidl, 0) == S_OK) { DWORD rgfAttrib = SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET; // CAN_LINK
if (SUCCEEDED(IEGetAttributesOf(pidl, &rgfAttrib))) { DWORD nCmdID; static const DWORD tbtab[] = { SBCMDID_FILEDELETE, SBCMDID_FILEPROPERTIES, SBCMDID_FILERENAME }; static const DWORD cttab[] = { SFGAO_CANDELETE, SFGAO_HASPROPSHEET, SFGAO_CANRENAME };
nCmdID = SHSearchMapInt((int*)tbtab, (int*)cttab, ARRAYSIZE(tbtab), rgCmds[i].cmdID);
if (nCmdID != -1 && (rgfAttrib & nCmdID)) rgCmds[i].cmdf = OLECMDF_ENABLED; } ILFree(pidl); } break; } default: break; } }
return S_OK; } return CToolBand::QueryStatus(pguidCmdGroup, cCmds, rgCmds, pcmdtext); }
HRESULT CNSCBand::_InvokeCommandOnItem(LPCTSTR pszVerb) { HRESULT hr; IContextMenu *pcm; hr = _QueryContextMenuSelection(&pcm); if (SUCCEEDED(hr)) { CMINVOKECOMMANDINFOEX ici = { SIZEOF(CMINVOKECOMMANDINFOEX), 0L, _hwnd, NULL, NULL, NULL, SW_NORMAL, }; #ifdef UNICODE
CHAR szVerbAnsi[MAX_PATH]; SHUnicodeToAnsi(pszVerb, szVerbAnsi, ARRAYSIZE(szVerbAnsi)); ici.lpVerb = szVerbAnsi; ici.lpVerbW = pszVerb; ici.fMask |= CMIC_MASK_UNICODE; #else
ici.lpVerb = pszVerb; #endif
hr = pcm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici); pcm->Release(); } return hr; }
HRESULT CNSCBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut) { if (pguidCmdGroup == NULL) { switch (nCmdID) { case OLECMDID_REFRESH: if (_pns) _pns->Refresh(); return S_OK; }
} else if (pguidCmdGroup && IsEqualGUID(CGID_Explorer, *pguidCmdGroup)) { HRESULT hr = S_OK; switch (nCmdID) { case SBCMDID_SELECTHISTPIDL: if (IsEqualCLSID(*_poi->pclsid, CLSID_HistBand) && _hwnd && _fVisible) { // If you're not visible do nothing. On becoming visible
// use Exec to proxy to get last pidlSelect that you would
// have shown, had you been visible
LPITEMIDLIST pidlSelect = VariantToIDList(pvarargIn); if (pidlSelect) { _pns->SetSelectedItem(pidlSelect, TRUE, FALSE, 0); ILFree(pidlSelect); } } break;
case SBCMDID_INITFILECTXMENU: if (_hwnd && _fVisible) { if (pvarargOut) { VariantClearLazy(pvarargOut);
HRESULT hres = _QueryContextMenuSelection((IContextMenu **)&(pvarargOut->punkVal)); if (SUCCEEDED(hres)) { pvarargOut->vt = VT_UNKNOWN; } } } break;
case SBCMDID_FILERENAME: { IShellNameSpace *psfns; hr = _pns->QueryInterface(IID_PPV_ARG(IShellNameSpace, &psfns)); if (SUCCEEDED(hr)) { hr = psfns->InvokeContextMenuCommand(L"rename"); psfns->Release(); } break; } case SBCMDID_FILEDELETE: hr = _InvokeCommandOnItem(TEXT("delete")); break; case SBCMDID_FILEPROPERTIES: hr = _InvokeCommandOnItem(TEXT("properties")); break;
default: hr = E_FAIL; break; } if (SUCCEEDED(hr)) return hr; }
return CToolBand::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut); }
HRESULT CNSCBand::_QueryContextMenuSelection(IContextMenu ** ppcm) { HRESULT hr = E_FAIL; LPITEMIDLIST pidlSelected;
*ppcm = NULL; hr = _pns->GetSelectedItem(&pidlSelected, 0); if (SUCCEEDED(hr)) { LPCITEMIDLIST pidlRelative; IShellFolder * psf;
hr = IEBindToParentFolder(pidlSelected, &psf, &pidlRelative); if (SUCCEEDED(hr)) { hr = psf->GetUIObjectOf(NULL, 1, &pidlRelative, IID_PPV_ARG_NULL(IContextMenu, ppcm)); } ILFree(pidlSelected); } return hr; }
HRESULT CNSCBand::Select(LPCITEMIDLIST pidl) { _pns->SetSelectedItem(pidl, TRUE, FALSE, 0); return S_OK; }
// *** IInputObject Methods ***
HRESULT CNSCBand::TranslateAcceleratorIO(LPMSG lpMsg) { HWND hwndFocus = GetFocus(); if (_pns->InLabelEdit()) return EditBox_TranslateAcceleratorST(lpMsg); else if ( lpMsg && lpMsg->hwnd && SendMessage(lpMsg->hwnd, TVM_TRANSLATEACCELERATOR, 0, (LPARAM)lpMsg)) return S_OK; else if (hwndFocus == _hwnd && TranslateAcceleratorWrap(_hwnd, _haccTree, lpMsg)) return S_OK;
return S_FALSE; }
void CNSCBand::_EnsureImageListsLoaded() { if (_himlNormal == NULL) _himlNormal = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_HISTORYANDFAVBANDSDEF), 18, 3, RGB(255, 0, 255), IMAGE_BITMAP, LR_CREATEDIBSECTION);
if (_himlHot == NULL) _himlHot = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_HISTORYANDFAVBANDSHOT), 18, 3, RGB(255, 0, 255), IMAGE_BITMAP, LR_CREATEDIBSECTION); }
HRESULT CNSCBand::_TranslatePidl(LPCITEMIDLIST pidl, LPITEMIDLIST *ppidlTarget, ULONG *pulAttrib) { IShellFolder *psf; LPCITEMIDLIST pidlLast; HRESULT hr = SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast); if (SUCCEEDED(hr)) { hr = SHGetNavigateTarget(psf, pidlLast, ppidlTarget, pulAttrib); psf->Release(); }
return hr; }
// favorites, history and Explorer band should override this (they need not worry about channel band)
BOOL CNSCBand::_ShouldNavigateToPidl(LPCITEMIDLIST pidl, ULONG ulAttrib) { BOOL bReturn = (ulAttrib & SFGAO_FOLDER); if (bReturn) { IShellFolder *psf; LPCITEMIDLIST pidlLast; HRESULT hr = SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast); if (SUCCEEDED(hr)) { bReturn = IsExpandableChannelFolder(psf, pidlLast); psf->Release(); } }
return !bReturn; }
HRESULT CNSCBand::GetNavigateTarget(LPCITEMIDLIST pidl, LPITEMIDLIST *ppidlTarget, ULONG *pulAttrib) { HRESULT hr = _TranslatePidl(pidl, ppidlTarget, pulAttrib); if (SUCCEEDED(hr)) { hr = _ShouldNavigateToPidl(pidl, *pulAttrib) ? S_OK : S_FALSE; if (hr == S_FALSE) { ILFree(*ppidlTarget); *ppidlTarget = NULL; } } return hr; }
HRESULT CNSCBand::OnSelectionChanged(LPCITEMIDLIST pidl) { return S_OK; }
HRESULT CNSCBand::Invoke(LPCITEMIDLIST pidl) { HRESULT hr = E_INVALIDARG;
if (pidl) { IShellBrowser *psb; hr = IUnknown_QueryService(_punkSite, SID_SProxyBrowser, IID_PPV_ARG(IShellBrowser, &psb)); if (SUCCEEDED(hr)) { hr = _NavigateRightPane(psb, pidl); if (FAILED(hr)) { IShellFolder *psf; LPCITEMIDLIST pidlChild; if (SUCCEEDED(SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild))) { DWORD dwAttributes = SFGAO_FOLDER; psf->GetAttributesOf(1, &pidlChild, &dwAttributes); if (!(dwAttributes & SFGAO_FOLDER)) { hr = SHInvokeDefaultCommand(_hwnd, psf, pidlChild); } psf->Release(); } } psb->Release(); } } return hr; }
HRESULT CNSCBand::_NavigateRightPane(IShellBrowser *psb, LPCITEMIDLIST pidl) { HRESULT hr = psb->BrowseObject(pidl, SBSP_SAMEBROWSER); if (SUCCEEDED(hr)) UEMFireEvent(&UEMIID_BROWSER, UEME_INSTRBROWSER, UEMF_INSTRUMENT, UIBW_NAVIGATE, UIBL_NAVOTHER); return hr; }
|