WindowsXP-SP1/shell/shdocvw/explband.cpp

748 lines
24 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);
HRESULT _BrowserExec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut);
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 CExplorerBand::_BrowserExec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
{
return IUnknown_QueryServiceExec(_punkSite, SID_STopLevelBrowser, pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
}
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 (IsOS(OS_WHISTLERORGREATER) &&
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);
}
}
}