740 lines
23 KiB
C++
740 lines
23 KiB
C++
#include "priv.h"
|
|
#include "sccls.h"
|
|
#include "nscband.h"
|
|
#include "resource.h"
|
|
#include "uemapp.h" // KMTF: Included for instrumentation
|
|
#include "shlguid.h"
|
|
#include <dpa.h>
|
|
#include <mluisupp.h>
|
|
#include "varutil.h"
|
|
#include "apithk.h"
|
|
|
|
#define TF_EXPLORERBAND 0
|
|
|
|
typedef struct
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
IShellFolder *psf;
|
|
} SFCITEM;
|
|
|
|
class CExplorerBand : public CNSCBand,
|
|
public IDispatch
|
|
{
|
|
public:
|
|
|
|
// *** IUnknown ***
|
|
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
|
|
STDMETHODIMP_(ULONG) AddRef(void) { return CNSCBand::AddRef(); };
|
|
STDMETHODIMP_(ULONG) Release(void) { return CNSCBand::Release(); };
|
|
|
|
// *** IOleCommandTarget methods ***
|
|
STDMETHODIMP QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext);
|
|
STDMETHODIMP Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut);
|
|
|
|
// *** IDockingWindow methods ***
|
|
STDMETHODIMP CloseDW(DWORD dw);
|
|
STDMETHODIMP ShowDW(BOOL fShow);
|
|
|
|
// *** IObjectWithSite methods ***
|
|
STDMETHODIMP SetSite(IUnknown* punkSite);
|
|
|
|
// *** INamespaceProxy methods ***
|
|
STDMETHODIMP Invoke(LPCITEMIDLIST pidl);
|
|
STDMETHODIMP OnSelectionChanged(LPCITEMIDLIST pidl);
|
|
STDMETHODIMP CacheItem(LPCITEMIDLIST pidl) {_MaybeAddToLegacySFC(pidl); return S_OK;}
|
|
|
|
// *** IDispatch methods ***
|
|
STDMETHODIMP GetTypeInfoCount(UINT *pctinfo) {return E_NOTIMPL;}
|
|
STDMETHODIMP GetTypeInfo(UINT itinfo,LCID lcid,ITypeInfo **pptinfo) {return E_NOTIMPL;}
|
|
STDMETHODIMP GetIDsOfNames(REFIID riid,OLECHAR **rgszNames,UINT cNames, LCID lcid, DISPID * rgdispid) {return E_NOTIMPL;}
|
|
STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
|
|
DISPPARAMS *pdispparams, VARIANT *pvarResult, EXCEPINFO *pexcepinfo, UINT *puArgErr);
|
|
|
|
protected:
|
|
CExplorerBand() : _fCanSelect(TRUE), _fIgnoreSelection(TRUE)
|
|
{}
|
|
virtual ~CExplorerBand();
|
|
|
|
virtual HRESULT _TranslatePidl(LPCITEMIDLIST pidl, LPITEMIDLIST *ppidlTarget, ULONG *pulAttrib);
|
|
virtual BOOL _ShouldNavigateToPidl(LPCITEMIDLIST pidl, ULONG ulAttrib);
|
|
virtual HRESULT _InitializeNsc();
|
|
virtual DWORD _GetTVStyle();
|
|
virtual DWORD _GetTVExStyle();
|
|
virtual DWORD _GetEnumFlags();
|
|
void _MaybeAddToLegacySFC(LPCITEMIDLIST pidl);
|
|
void _AddToLegacySFC(LPCITEMIDLIST pidl, IShellFolder *psf);
|
|
BOOL _IsInSFC(LPCITEMIDLIST pidl);
|
|
BOOL _IsFloppy(LPCITEMIDLIST pidl);
|
|
void _OnNavigate();
|
|
HRESULT _ConnectToBrowser(BOOL fConnect);
|
|
friend HRESULT CExplorerBand_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi);
|
|
|
|
static void s_DVEnumReadyCallback(void *pvData);
|
|
|
|
CDSA<SFCITEM> *_pdsaLegacySFC;
|
|
DWORD _dwcpCookie;
|
|
LPITEMIDLIST _pidlView; //pidl view is navigated to
|
|
BOOL _fCanSelect;
|
|
BOOL _fIgnoreSelection; //so we don't navigate away from the web page when user opens explorer pane
|
|
BOOL _fFloppyRefresh;
|
|
};
|
|
|
|
HRESULT _UnwrapRootedPidl(LPCITEMIDLIST pidlRooted, BOOL bOnlyIfRooted, LPITEMIDLIST *ppidl)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
if (ILIsRooted(pidlRooted))
|
|
{
|
|
hr = SHILCombine(ILRootedFindIDList(pidlRooted), _ILNext(pidlRooted), ppidl);
|
|
}
|
|
else if (!bOnlyIfRooted)
|
|
{
|
|
hr = SHILClone(pidlRooted, ppidl);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
BOOL IsFTPPidl(LPCITEMIDLIST pidl)
|
|
{
|
|
BOOL fIsFTP = FALSE;
|
|
IShellFolder * psf;
|
|
|
|
if (pidl && SUCCEEDED(IEBindToObject(pidl, &psf)))
|
|
{
|
|
fIsFTP = IsFTPFolder(psf);
|
|
psf->Release();
|
|
}
|
|
|
|
return fIsFTP;
|
|
}
|
|
|
|
|
|
void CExplorerBand::_OnNavigate()
|
|
{
|
|
IBrowserService* pbs;
|
|
HRESULT hr = IUnknown_QueryService(_punkSite, SID_STopLevelBrowser, IID_PPV_ARG(IBrowserService, &pbs));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
hr = pbs->GetPidl(&pidl);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPITEMIDLIST pidlNew;
|
|
hr = _UnwrapRootedPidl(pidl, FALSE, &pidlNew);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// We must go in this code path if the pidl is an FTP pidl. FTP pidls can contain
|
|
// passwords so it needs to replace any existing pidl. Whistler #252206.
|
|
if (!_pidlView || !ILIsEqual(pidlNew, _pidlView) || IsFTPPidl(pidlNew))
|
|
{
|
|
DWORD dwAttributes = SFGAO_FOLDER;
|
|
// only let folders go through (to filter out Web pages)
|
|
hr = IEGetAttributesOf(pidlNew, &dwAttributes);
|
|
if (SUCCEEDED(hr) && (dwAttributes & SFGAO_FOLDER))
|
|
{
|
|
BOOL fExpand = (_pidlView == NULL); //the very first time we expand the folder the view is navigated to
|
|
Pidl_Set(&_pidlView, pidlNew);
|
|
_fIgnoreSelection = FALSE; //in the web page case we don't come here because the page does not have folder attribute
|
|
|
|
if (_fCanSelect)
|
|
{
|
|
if (fExpand)
|
|
{
|
|
VARIANT var;
|
|
hr = InitVariantFromIDList(&var, _pidlView);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IShellNameSpace *psns;
|
|
hr = _pns->QueryInterface(IID_PPV_ARG(IShellNameSpace, &psns));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
psns->Expand(var, 1);
|
|
psns->Release();
|
|
}
|
|
VariantClear(&var);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_pns->SetSelectedItem(_pidlView, TRUE, FALSE, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// view navigation is asynchronous so we don't know if it failed in OnSelectionChanged
|
|
// but the view is getting navigated to the old pidl and _fCanSelect is false (which happens after we try
|
|
// to navigate the view) so it is safe to assume that navigation failed.
|
|
// we need to update the selection to match the view
|
|
else if (ILIsEqual(pidlNew, _pidlView) && !_fCanSelect)
|
|
{
|
|
_pns->SetSelectedItem(_pidlView, TRUE, FALSE, 0);
|
|
}
|
|
|
|
_fCanSelect = TRUE;
|
|
ILFree(pidlNew);
|
|
}
|
|
ILFree(pidl);
|
|
}
|
|
pbs->Release();
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
Pidl_Set(&_pidlView, NULL);
|
|
}
|
|
}
|
|
|
|
HRESULT CExplorerBand::Invoke(DISPID dispidMember, REFIID riid,LCID lcid, WORD wFlags,
|
|
DISPPARAMS *pdispparams, VARIANT *pvarResult,
|
|
EXCEPINFO *pexcepinfo, UINT *puArgErr)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!pdispparams)
|
|
return E_INVALIDARG;
|
|
|
|
switch(dispidMember)
|
|
{
|
|
case DISPID_NAVIGATECOMPLETE2:
|
|
case DISPID_DOCUMENTCOMPLETE:
|
|
{
|
|
BOOL fCallNavigateFinished = TRUE;
|
|
IDVGetEnum *pdvge;
|
|
if (SUCCEEDED(IUnknown_QueryService(_punkSite, SID_SFolderView, IID_PPV_ARG(IDVGetEnum, &pdvge))))
|
|
{
|
|
// callback will call it
|
|
fCallNavigateFinished = FALSE;
|
|
if (dispidMember == DISPID_NAVIGATECOMPLETE2)
|
|
pdvge->SetEnumReadyCallback(s_DVEnumReadyCallback, this);
|
|
|
|
pdvge->Release();
|
|
}
|
|
_OnNavigate();
|
|
if (fCallNavigateFinished && DISPID_DOCUMENTCOMPLETE == dispidMember)
|
|
{
|
|
// need to let nsc know the navigation finished in case we navigated to a 3rd party namespace extension (w/ its own view impl)
|
|
// because it does not implement IDVGetEnum, hence s_DVEnumReadyCallback will not get called
|
|
LPITEMIDLIST pidlClone = ILClone(_pidlView);
|
|
// should we unwrap this pidl if rooted?
|
|
if (pidlClone)
|
|
_pns->RightPaneNavigationFinished(pidlClone); // takes ownership
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
void CExplorerBand::s_DVEnumReadyCallback(void *pvData)
|
|
{
|
|
CExplorerBand *peb = (CExplorerBand *) pvData;
|
|
IBrowserService* pbs;
|
|
if (SUCCEEDED(IUnknown_QueryService(peb->_punkSite, SID_STopLevelBrowser, IID_PPV_ARG(IBrowserService, &pbs))))
|
|
{
|
|
LPITEMIDLIST pidlTemp;
|
|
if (SUCCEEDED(pbs->GetPidl(&pidlTemp)))
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
if (SUCCEEDED(_UnwrapRootedPidl(pidlTemp, FALSE, &pidl)))
|
|
{
|
|
peb->_pns->RightPaneNavigationFinished(pidl); // takes ownership
|
|
}
|
|
ILFree(pidlTemp);
|
|
}
|
|
pbs->Release();
|
|
}
|
|
}
|
|
|
|
const TCHAR c_szLink[] = TEXT("link");
|
|
const TCHAR c_szRename[] = TEXT("rename");
|
|
const TCHAR c_szMove[] = TEXT("cut");
|
|
const TCHAR c_szPaste[] = TEXT("paste");
|
|
const TCHAR c_szCopy[] = TEXT("copy");
|
|
const TCHAR c_szDelete[] = TEXT("delete");
|
|
const TCHAR c_szProperties[] = TEXT("properties");
|
|
|
|
// IOleCommandTarget
|
|
HRESULT CExplorerBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
|
|
{
|
|
if (pguidCmdGroup == NULL)
|
|
{
|
|
IContextMenu *pcm = NULL;
|
|
HRESULT hr = _QueryContextMenuSelection(&pcm);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
HMENU hmenu = CreatePopupMenu();
|
|
if (hmenu)
|
|
{
|
|
hr = pcm->QueryContextMenu(hmenu, 0, 0, 255, 0);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
UINT ilast = GetMenuItemCount(hmenu);
|
|
for (UINT ipos=0; ipos < ilast; ipos++)
|
|
{
|
|
MENUITEMINFO mii = {0};
|
|
TCHAR szVerb[40];
|
|
UINT idCmd;
|
|
|
|
mii.cbSize = SIZEOF(MENUITEMINFO);
|
|
mii.fMask = MIIM_ID|MIIM_STATE;
|
|
|
|
if (!GetMenuItemInfoWrap(hmenu, ipos, TRUE, &mii)) continue;
|
|
if (0 != (mii.fState & (MF_GRAYED|MF_DISABLED))) continue;
|
|
idCmd = mii.wID;
|
|
|
|
hr = ContextMenu_GetCommandStringVerb(pcm, idCmd, szVerb, ARRAYSIZE(szVerb));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPCTSTR szCmd = NULL;
|
|
|
|
for (ULONG cItem = 0; cItem < cCmds; cItem++)
|
|
{
|
|
switch (rgCmds[cItem].cmdID)
|
|
{
|
|
case OLECMDID_CUT:
|
|
szCmd = c_szMove;
|
|
break;
|
|
case OLECMDID_COPY:
|
|
szCmd = c_szCopy;
|
|
break;
|
|
case OLECMDID_PASTE:
|
|
szCmd = c_szPaste;
|
|
break;
|
|
case OLECMDID_DELETE:
|
|
szCmd = c_szDelete;
|
|
break;
|
|
case OLECMDID_PROPERTIES:
|
|
szCmd = c_szProperties;
|
|
break;
|
|
}
|
|
|
|
if (StrCmpI(szVerb, szCmd)==0)
|
|
{
|
|
rgCmds[cItem].cmdf = OLECMDF_ENABLED;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
DestroyMenu(hmenu);
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
pcm->Release();
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
return hr;
|
|
}
|
|
|
|
return CNSCBand::QueryStatus(pguidCmdGroup, cCmds, rgCmds, pcmdtext);
|
|
}
|
|
|
|
HRESULT CExplorerBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
|
|
{
|
|
if (pguidCmdGroup == NULL)
|
|
{
|
|
HRESULT hr;
|
|
|
|
switch(nCmdID)
|
|
{
|
|
case OLECMDID_CUT:
|
|
hr = _InvokeCommandOnItem(c_szMove);
|
|
break;
|
|
case OLECMDID_COPY:
|
|
hr = _InvokeCommandOnItem(c_szCopy);
|
|
break;
|
|
case OLECMDID_PASTE:
|
|
hr = _InvokeCommandOnItem(c_szPaste);
|
|
break;
|
|
case OLECMDID_DELETE:
|
|
hr = _InvokeCommandOnItem(c_szDelete);
|
|
break;
|
|
case OLECMDID_PROPERTIES:
|
|
hr = _InvokeCommandOnItem(c_szProperties);
|
|
break;
|
|
default:
|
|
hr = E_FAIL;
|
|
break;
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
return hr;
|
|
}
|
|
|
|
return CNSCBand::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
|
|
}
|
|
|
|
// IDockingWindow
|
|
HRESULT CExplorerBand::CloseDW(DWORD dw)
|
|
{
|
|
_ConnectToBrowser(FALSE);
|
|
return CNSCBand::CloseDW(dw);
|
|
}
|
|
|
|
HRESULT CExplorerBand::ShowDW(BOOL fShow)
|
|
{
|
|
return CNSCBand::ShowDW(fShow);
|
|
}
|
|
|
|
// IObjectWithSite
|
|
HRESULT CExplorerBand::SetSite(IUnknown* punkSite)
|
|
{
|
|
HRESULT hr = CNSCBand::SetSite(punkSite);
|
|
|
|
if (punkSite)
|
|
_ConnectToBrowser(TRUE);
|
|
|
|
return hr;
|
|
}
|
|
|
|
int _SFCDestroyCB(SFCITEM *psfcItem, void *pv)
|
|
{
|
|
psfcItem->psf->Release();
|
|
ILFree(psfcItem->pidl);
|
|
return 1;
|
|
}
|
|
|
|
CExplorerBand::~CExplorerBand()
|
|
{
|
|
ILFree(_pidlView);
|
|
if (_pdsaLegacySFC)
|
|
{
|
|
_pdsaLegacySFC->DestroyCallback(_SFCDestroyCB, NULL);
|
|
delete _pdsaLegacySFC;
|
|
}
|
|
}
|
|
|
|
HRESULT CExplorerBand::QueryInterface(REFIID riid, void **ppvObj)
|
|
{
|
|
static const QITAB qit[] = {
|
|
QITABENT(CExplorerBand, IDispatch),
|
|
{ 0 },
|
|
};
|
|
|
|
HRESULT hr = QISearch(this, qit, riid, ppvObj);
|
|
if (FAILED(hr))
|
|
hr = CNSCBand::QueryInterface(riid, ppvObj);
|
|
return hr;
|
|
}
|
|
|
|
DWORD CExplorerBand::_GetEnumFlags()
|
|
{
|
|
DWORD dwFlags = SHCONTF_FOLDERS;
|
|
SHELLSTATE ss = {0};
|
|
|
|
SHGetSetSettings(&ss, SSF_SHOWALLOBJECTS, FALSE);
|
|
if (ss.fShowAllObjects)
|
|
dwFlags |= SHCONTF_INCLUDEHIDDEN;
|
|
|
|
return dwFlags;
|
|
}
|
|
|
|
DWORD CExplorerBand::_GetTVExStyle()
|
|
{
|
|
DWORD dwExStyle = 0;
|
|
|
|
if (IsOS(OS_WHISTLERORGREATER) &&
|
|
SHRegGetBoolUSValue(TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"),
|
|
TEXT("FriendlyTree"), FALSE, TRUE))
|
|
{
|
|
dwExStyle |= TVS_EX_NOSINGLECOLLAPSE;
|
|
}
|
|
|
|
return dwExStyle;
|
|
}
|
|
|
|
DWORD CExplorerBand::_GetTVStyle()
|
|
{
|
|
DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP | WS_HSCROLL | TVS_EDITLABELS | TVS_SHOWSELALWAYS;
|
|
|
|
if (SHRegGetBoolUSValue(TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"), TEXT("FriendlyTree"), FALSE, TRUE))
|
|
{
|
|
dwStyle |= TVS_HASBUTTONS | TVS_SINGLEEXPAND | TVS_TRACKSELECT;
|
|
}
|
|
else
|
|
{
|
|
dwStyle |= TVS_HASBUTTONS | TVS_HASLINES;
|
|
}
|
|
|
|
// If the parent window is mirrored then the treeview window will inheret the mirroring flag
|
|
// And we need the reading order to be Left to right, which is the right to left in the mirrored mode.
|
|
if (_hwndParent && IS_WINDOW_RTL_MIRRORED(_hwndParent))
|
|
{
|
|
// This means left to right reading order because this window will be mirrored.
|
|
_dwStyle |= TVS_RTLREADING;
|
|
}
|
|
|
|
return dwStyle;
|
|
}
|
|
|
|
HRESULT CExplorerBand_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
|
|
{
|
|
// aggregation checking is handled in class factory
|
|
CExplorerBand * peb = new CExplorerBand();
|
|
if (!peb)
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (SUCCEEDED(peb->_Init((LPCITEMIDLIST)CSIDL_DESKTOP)))
|
|
{
|
|
peb->_pns = CNscTree_CreateInstance();
|
|
if (peb->_pns)
|
|
{
|
|
ASSERT(poi);
|
|
peb->_poi = poi;
|
|
// if you change this cast, fix up CFavBand_CreateInstance
|
|
*ppunk = SAFECAST(peb, IDeskBand *);
|
|
|
|
IUnknown_SetSite(peb->_pns, *ppunk);
|
|
peb->_SetNscMode(MODE_NORMAL);
|
|
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
peb->Release();
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT CExplorerBand::_ConnectToBrowser(BOOL fConnect)
|
|
{
|
|
IBrowserService* pbs;
|
|
HRESULT hr = IUnknown_QueryService(_punkSite, SID_STopLevelBrowser, IID_PPV_ARG(IBrowserService, &pbs));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (fConnect)
|
|
{
|
|
LPITEMIDLIST pidlTemp = NULL;
|
|
// try to get the pidl the browser is navigated to
|
|
// this usually fails if user just opened Explorer window because navigation is asynchronous
|
|
// so we're not initialized yet
|
|
if (FAILED(pbs->GetPidl(&pidlTemp)))
|
|
{
|
|
IBrowserService2 *pbs2;
|
|
if (SUCCEEDED(pbs->QueryInterface(IID_PPV_ARG(IBrowserService2, &pbs2))))
|
|
{
|
|
LPCBASEBROWSERDATA pbbd;
|
|
// our last hope is the pidl browser is navigating to...
|
|
if (SUCCEEDED(pbs2->GetBaseBrowserData(&pbbd)) && pbbd->_pidlPending)
|
|
{
|
|
pidlTemp = ILClone(pbbd->_pidlPending);
|
|
}
|
|
pbs2->Release();
|
|
}
|
|
}
|
|
|
|
if (pidlTemp)
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
// see if we're dealing with a rooted namespace
|
|
if (SUCCEEDED(_UnwrapRootedPidl(pidlTemp, TRUE, &pidl)))
|
|
{
|
|
_Init(pidl); //if so, reinitialize ourself with the rooted pidl
|
|
ILFree(pidl);
|
|
}
|
|
ILFree(pidlTemp);
|
|
}
|
|
}
|
|
|
|
IConnectionPointContainer* pcpc;
|
|
hr = IUnknown_QueryService(pbs, SID_SWebBrowserApp, IID_PPV_ARG(IConnectionPointContainer, &pcpc));
|
|
// Let's now have the Browser Window give us notification when something happens.
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = ConnectToConnectionPoint(SAFECAST(this, IDispatch*), DIID_DWebBrowserEvents2, fConnect,
|
|
pcpc, &_dwcpCookie, NULL);
|
|
pcpc->Release();
|
|
}
|
|
|
|
pbs->Release();
|
|
}
|
|
|
|
ASSERT(SUCCEEDED(hr));
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CExplorerBand::_InitializeNsc()
|
|
{
|
|
HRESULT hr = _pns->Initialize(_pidl, _GetEnumFlags(), NSS_DROPTARGET | NSS_BROWSERSELECT);
|
|
if (SUCCEEDED(hr))
|
|
_OnNavigate();
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CExplorerBand::_TranslatePidl(LPCITEMIDLIST pidl, LPITEMIDLIST *ppidlTarget, ULONG *pulAttrib)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (pidl && ppidlTarget && pulAttrib)
|
|
{
|
|
hr = IEGetAttributesOf(pidl, pulAttrib);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = SHILClone(pidl, ppidlTarget);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
BOOL CExplorerBand::_ShouldNavigateToPidl(LPCITEMIDLIST pidl, ULONG ulAttrib)
|
|
{
|
|
return ulAttrib & SFGAO_FOLDER;
|
|
}
|
|
|
|
BOOL CExplorerBand::_IsFloppy(LPCITEMIDLIST pidl)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
|
|
WCHAR szPath[MAX_PATH];
|
|
if (SUCCEEDED(SHGetNameAndFlags(pidl, SHGDN_FORPARSING, szPath, ARRAYSIZE(szPath), NULL)))
|
|
{
|
|
if (DRIVE_REMOVABLE == GetDriveType(szPath))
|
|
{
|
|
fRet = (L'A' == szPath[0] || L'B' == szPath[0] || L'a' == szPath[0] || L'b' == szPath[0]);
|
|
}
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
HRESULT CExplorerBand::Invoke(LPCITEMIDLIST pidl)
|
|
{
|
|
HRESULT hr;
|
|
|
|
// allow user to navigate to an already selected item if they opened Explorer band in Web browser
|
|
// (because we put selection on the root node but don't navigate away from the web page, if they click
|
|
// on the root we don't navigate there, because selection never changed)
|
|
|
|
if (!_pidlView)
|
|
{
|
|
_fIgnoreSelection = FALSE;
|
|
hr = OnSelectionChanged(pidl);
|
|
}
|
|
else if (ILIsEqual(pidl, _pidlView) && _IsFloppy(pidl))
|
|
{
|
|
// If the drive is a floppy and the user reselects the drive refresh the contents. This enables
|
|
// a user to refresh when a floppy is replaced.
|
|
_fFloppyRefresh = TRUE;
|
|
hr = OnSelectionChanged(pidl);
|
|
_fFloppyRefresh = FALSE;
|
|
}
|
|
else
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CExplorerBand::OnSelectionChanged(LPCITEMIDLIST pidl)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (!_fIgnoreSelection)
|
|
{
|
|
if (pidl)
|
|
{
|
|
ULONG ulAttrib = SFGAO_FOLDER;
|
|
LPITEMIDLIST pidlTarget;
|
|
|
|
hr = GetNavigateTarget(pidl, &pidlTarget, &ulAttrib);
|
|
if (hr == S_OK)
|
|
{
|
|
if (!_pidlView || _fFloppyRefresh || !ILIsEqual(pidlTarget, _pidlView))
|
|
{
|
|
hr = CNSCBand::Invoke(pidlTarget);
|
|
if (SUCCEEDED(hr))
|
|
_fCanSelect = FALSE;
|
|
_pns->RightPaneNavigationStarted(pidlTarget);
|
|
pidlTarget = NULL; // ownership passed
|
|
}
|
|
ILFree(pidlTarget);
|
|
}
|
|
#ifdef DEBUG
|
|
else if (hr == S_FALSE)
|
|
{
|
|
ASSERT(pidlTarget == NULL);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_fIgnoreSelection = FALSE; //we ignore only first selection
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
void CExplorerBand::_MaybeAddToLegacySFC(LPCITEMIDLIST pidl)
|
|
{
|
|
IShellFolder *psf = NULL;
|
|
if (pidl && SUCCEEDED(SHBindToObjectEx(NULL, pidl, NULL, IID_PPV_ARG(IShellFolder, &psf))))
|
|
{
|
|
//
|
|
// APPCOMPAT LEGACY - Compatibility. needs the Shell folder cache, - ZekeL - 4-MAY-99
|
|
// some apps, specifically WS_FTP and AECO Zip Pro,
|
|
// rely on having a shellfolder existing in order for them to work.
|
|
// we pulled the SFC because it wasnt any perf win.
|
|
//
|
|
if (OBJCOMPATF_OTNEEDSSFCACHE & SHGetObjectCompatFlags(psf, NULL))
|
|
_AddToLegacySFC(pidl, psf);
|
|
psf->Release();
|
|
}
|
|
}
|
|
|
|
BOOL CExplorerBand::_IsInSFC(LPCITEMIDLIST pidl)
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
|
|
ASSERT(_pdsaLegacySFC);
|
|
for (int i=0; i<_pdsaLegacySFC->GetItemCount(); i++)
|
|
{
|
|
SFCITEM *psfcItem = _pdsaLegacySFC->GetItemPtr(i);
|
|
if (ILIsEqual(psfcItem->pidl, pidl))
|
|
{
|
|
bReturn = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
void CExplorerBand::_AddToLegacySFC(LPCITEMIDLIST pidl, IShellFolder *psf)
|
|
{
|
|
if (!_pdsaLegacySFC)
|
|
{
|
|
_pdsaLegacySFC = new CDSA<SFCITEM>;
|
|
if (_pdsaLegacySFC && !_pdsaLegacySFC->Create(4))
|
|
{
|
|
delete _pdsaLegacySFC;
|
|
_pdsaLegacySFC = NULL;
|
|
}
|
|
}
|
|
|
|
if (_pdsaLegacySFC)
|
|
{
|
|
LPITEMIDLIST pidlCache;
|
|
if (!_IsInSFC(pidl) && SUCCEEDED(SHILClone(pidl, &pidlCache)))
|
|
{
|
|
SFCITEM sfc = {pidlCache, psf};
|
|
if (-1 != _pdsaLegacySFC->InsertItem(0, &sfc))
|
|
psf->AddRef();
|
|
else
|
|
ILFree(pidlCache);
|
|
}
|
|
}
|
|
}
|