Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1487 lines
44 KiB

// Implements Folder Shortcut.
#include "shellprv.h"
#include "clsobj.h"
// implemented in filefldr.cpp
extern LPTSTR PathFindCLSIDExtension(LPCTSTR pszFile, CLSID *pclsid);
BOOL CreateFolderDesktopIni(LPCTSTR pszName)
{
SHFOLDERCUSTOMSETTINGS fcs = {0};
fcs.dwSize = sizeof(fcs);
fcs.dwMask = FCSM_CLSID | FCSM_FLAGS;
fcs.pclsid = (GUID*)&CLSID_FolderShortcut;
fcs.dwFlags = FCS_FLAG_DRAGDROP;
return SUCCEEDED(SHGetSetFolderCustomSettings(&fcs, pszName, FCS_FORCEWRITE));
}
EXTERN_C BOOL IsFolderShortcut(LPCTSTR pszName)
{
SHFOLDERCUSTOMSETTINGS fcs = {0};
CLSID clsid = {0};
fcs.dwSize = sizeof(fcs);
fcs.dwMask = FCSM_CLSID;
fcs.pclsid = &clsid;
if (SUCCEEDED(SHGetSetFolderCustomSettings(&fcs, pszName, FCS_READ)))
{
return IsEqualGUID(clsid, CLSID_FolderShortcut);
}
return FALSE;
}
// exported from fsnotify.c
STDAPI_(void) SHChangeNotifyRegisterAlias(LPCITEMIDLIST pidlReal, LPCITEMIDLIST pidlAlias);
class CFolderShortcut : public IShellFolder2,
public IPersistFolder3,
public IShellLinkA,
public IShellLinkW,
public IPersistFile,
public IExtractIcon,
public IQueryInfo,
public IFolderShortcutConvert,
public IPersistStreamInit,
public IPersistPropertyBag,
public IBrowserFrameOptions
{
public:
// IUnknown
STDMETHODIMP QueryInterface(REFIID, void **);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// IShellFolder
STDMETHODIMP ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR pszDisplayName,
ULONG *pchEaten, LPITEMIDLIST *ppidl, ULONG *pdwAttributes);
STDMETHODIMP EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList ** ppenumIDList);
STDMETHODIMP BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv);
STDMETHODIMP BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv);
STDMETHODIMP CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
STDMETHODIMP CreateViewObject (HWND hwnd, REFIID riid, void **ppv);
STDMETHODIMP GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl, ULONG *rgfInOut);
STDMETHODIMP GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST * apidl,
REFIID riid, UINT * prgfInOut, void **ppv);
STDMETHODIMP GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName);
STDMETHODIMP SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR pszName, DWORD uFlags,
LPITEMIDLIST *ppidlOut);
// IShellFolder2
STDMETHODIMP GetDefaultSearchGUID(GUID *pGuid);
STDMETHODIMP EnumSearches(IEnumExtraSearch **ppenum);
STDMETHODIMP GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay);
STDMETHODIMP GetDefaultColumnState(UINT iColumn, DWORD *pbState);
STDMETHODIMP GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv);
STDMETHODIMP GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pDetails);
STDMETHODIMP MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid);
// IPersist
STDMETHODIMP GetClassID(CLSID *pClassID);
// IPersistFolder
STDMETHODIMP Initialize(LPCITEMIDLIST pidl);
// IPersistFolder2
STDMETHODIMP GetCurFolder(LPITEMIDLIST *ppidl);
// IPersistFolder3
STDMETHODIMP InitializeEx(IBindCtx *pbc, LPCITEMIDLIST pidlRoot, const PERSIST_FOLDER_TARGET_INFO *pfti);
STDMETHODIMP GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO *pfti);
// IPersistStream
STDMETHODIMP Load(IStream *pStm);
STDMETHODIMP Save(IStream *pStm,int fClearDirty);
STDMETHODIMP GetSizeMax(ULARGE_INTEGER * pcbSize);
// IPersistPropertyBag
STDMETHODIMP Save(IPropertyBag* pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties);
STDMETHODIMP Load(IPropertyBag* pPropBag, IErrorLog* pErrorLog);
// IPersistPropertyBag/IPersistStreamInit
STDMETHODIMP InitNew(void);
// IPersistFile
STDMETHODIMP Load(LPCOLESTR pszFileName, DWORD dwMode);
STDMETHODIMP Save(LPCOLESTR pszFileName, BOOL fRemember);
STDMETHODIMP IsDirty() { return E_NOTIMPL; };
STDMETHODIMP SaveCompleted(LPCOLESTR pszFileName) { return E_NOTIMPL; };
STDMETHODIMP GetCurFile(LPOLESTR *ppszFileName);
// IShellLinkW
STDMETHODIMP GetPath(LPWSTR pszFile, int cchMaxPath, WIN32_FIND_DATAW *pfd, DWORD flags);
STDMETHODIMP SetPath(LPCWSTR pszFile);
STDMETHODIMP GetIDList(LPITEMIDLIST *ppidl);
STDMETHODIMP SetIDList(LPCITEMIDLIST pidl);
STDMETHODIMP GetDescription(LPWSTR pszName, int cchMaxName);
STDMETHODIMP SetDescription(LPCWSTR pszName);
STDMETHODIMP GetWorkingDirectory(LPWSTR pszDir, int cchMaxPath);
STDMETHODIMP SetWorkingDirectory(LPCWSTR pszDir);
STDMETHODIMP GetArguments(LPWSTR pszArgs, int cchMaxPath);
STDMETHODIMP SetArguments(LPCWSTR pszArgs);
STDMETHODIMP GetHotkey(WORD *pwHotkey);
STDMETHODIMP SetHotkey(WORD wHotkey);
STDMETHODIMP GetShowCmd(int *piShowCmd);
STDMETHODIMP SetShowCmd(int iShowCmd);
STDMETHODIMP GetIconLocation(LPWSTR pszIconPath, int cchIconPath, int *piIcon);
STDMETHODIMP SetIconLocation(LPCWSTR pszIconPath, int iIcon);
STDMETHODIMP Resolve(HWND hwnd, DWORD fFlags);
STDMETHODIMP SetRelativePath(LPCWSTR pszPathRel, DWORD dwReserved);
// IShellLinkA
STDMETHODIMP GetPath(LPSTR pszFile, int cchMaxPath, WIN32_FIND_DATAA *pfd, DWORD flags);
STDMETHODIMP SetPath(LPCSTR pszFile);
STDMETHODIMP GetDescription(LPSTR pszName, int cchMaxName);
STDMETHODIMP SetDescription(LPCSTR pszName);
STDMETHODIMP GetWorkingDirectory(LPSTR pszDir, int cchMaxPath);
STDMETHODIMP SetWorkingDirectory(LPCSTR pszDir);
STDMETHODIMP GetArguments(LPSTR pszArgs, int cchMaxPath);
STDMETHODIMP SetArguments(LPCSTR pszArgs);
STDMETHODIMP GetIconLocation(LPSTR pszIconPath, int cchIconPath, int *piIcon);
STDMETHODIMP SetIconLocation(LPCSTR pszIconPath, int iIcon);
STDMETHODIMP SetRelativePath(LPCSTR pszPathRel, DWORD dwReserved);
// IFolderShortcutConvert
STDMETHODIMP ConvertToLink(LPCOLESTR pszPathLNK, DWORD fFlags);
STDMETHODIMP ConvertToFolderShortcut(LPCOLESTR pszPathLNK, DWORD fFlags);
// IExtractIcon
STDMETHODIMP GetIconLocation(UINT uFlags, LPTSTR pszIconFile, UINT ucchMax, INT *pniIcon, UINT *puFlags);
STDMETHODIMP Extract(LPCTSTR pcszFile, UINT uIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT ucIconSize);
// IQueryInfo
STDMETHODIMP GetInfoTip(DWORD dwFlags, WCHAR** ppwszTip);
STDMETHODIMP GetInfoFlags(DWORD *pdwFlags);
// IBrowserFrameOptions
STDMETHODIMP GetFrameOptions(IN BROWSERFRAMEOPTIONS dwMask, IN BROWSERFRAMEOPTIONS * pdwOptions);
CFolderShortcut();
protected:
~CFolderShortcut();
void _ClearState();
void _ClearTargetFolder();
private:
HRESULT _LoadShortcut();
HRESULT _GetTargetIDList(BOOL fResolve);
HRESULT _BindFolder(BOOL fResolve);
HRESULT _GetFolder(BOOL fForceResolve);
HRESULT _GetFolder2();
HRESULT _GetLink();
HRESULT _GetLinkA();
HRESULT _GetLinkQI(REFIID riid, void **ppv);
HRESULT _PreBindCtxHelper(IBindCtx **ppbc);
LONG _cRef;
LPITEMIDLIST _pidlRoot;
LPITEMIDLIST _pidlTarget;
LPITEMIDLIST _pidlTargetFldrFromInit;
IShellFolder* _psfTarget;
IShellFolder2* _psf2Target;
IShellLinkW* _pslTarget;
IShellLinkA* _pslTargetA;
LPTSTR _pszLastSave;
BOOL _fHaveResolved;
DWORD _dwAttributesTarget;
TCHAR _szFolderPath[MAX_PATH];
};
//constructor/destructor and related functions
CFolderShortcut::CFolderShortcut() : _cRef(1), _dwAttributesTarget(FILE_ATTRIBUTE_DIRECTORY)
{
ASSERT(_pidlRoot == NULL);
ASSERT(_pidlTarget == NULL);
ASSERT(_psfTarget == NULL);
ASSERT(_psf2Target == NULL);
ASSERT(_szFolderPath[0] == 0);
ASSERT(_pidlTargetFldrFromInit == NULL);
DllAddRef();
}
CFolderShortcut::~CFolderShortcut()
{
_ClearState();
DllRelease();
}
void CFolderShortcut::_ClearTargetFolder()
{
ATOMICRELEASE(_psfTarget);
ATOMICRELEASE(_psf2Target);
}
void CFolderShortcut::_ClearState()
{
_fHaveResolved = FALSE;
Pidl_Set(&_pidlRoot, NULL);
Pidl_Set(&_pidlTarget, NULL);
Pidl_Set(&_pidlTargetFldrFromInit, NULL);
Str_SetPtr(&_pszLastSave, NULL);
_ClearTargetFolder();
ATOMICRELEASE(_pslTarget);
ATOMICRELEASE(_pslTargetA);
}
STDAPI CFolderShortcut_CreateInstance(IUnknown* pUnkOuter, REFIID riid, void **ppv)
{
HRESULT hr = E_OUTOFMEMORY;
*ppv = NULL;
// aggregation checking is handled in class factory
CFolderShortcut* pfolder = new CFolderShortcut();
if (pfolder)
{
hr = pfolder->QueryInterface(riid, ppv);
pfolder->Release();
}
return hr;
}
// ensure that _pslTarget has been created and loaded
HRESULT CFolderShortcut::_LoadShortcut()
{
HRESULT hr;
if (_pslTarget)
{
hr = S_OK;
}
else if (_szFolderPath[0])
{
TCHAR szPath[MAX_PATH];
// leave this shortcut visible so down level clients see it and can
// navigate through it.
if (PathCombine(szPath, _szFolderPath, TEXT("target.lnk")))
{
hr = LoadFromFile(CLSID_ShellLink, szPath, IID_PPV_ARG(IShellLinkW, &_pslTarget));
if (SUCCEEDED(hr))
{
LPITEMIDLIST pidlTarget;
// Prevalidate to prevent recusion
// If GetIDList fails, that's okay; I guess it doesn't point to us after all
if (_pslTarget->GetIDList(&pidlTarget) == S_OK)
{
SHGetPathFromIDList(pidlTarget, szPath);
// Does this point to itself?
if (StrCmpI(szPath, _szFolderPath) == 0)
{
_pslTarget->Release();
_pslTarget = NULL;
hr = E_FAIL;
}
ILFree(pidlTarget);
}
}
}
else
{
hr = E_FAIL;
}
}
else
{
hr = E_FAIL;
}
return hr;
}
// ensure that _pidlTarget is inited (requres _pslTarget)
HRESULT CFolderShortcut::_GetTargetIDList(BOOL bResolve)
{
HRESULT hr = _LoadShortcut();
if (SUCCEEDED(hr))
{
if (_pidlTarget)
{
hr = S_OK;
}
else
{
if (bResolve)
_pslTarget->Resolve(NULL, SLR_UPDATE | SLR_NO_UI);
hr = _pslTarget->GetIDList(&_pidlTarget);
if (hr == S_FALSE)
hr = E_FAIL; // convert empty to failure
if (SUCCEEDED(hr))
{
// make sure we dont have another shortcut here
IShellLink *psl;
if (SUCCEEDED(SHBindToObject(NULL, IID_IShellLink, _pidlTarget, (void**)&psl)))
{
ILFree(_pidlTarget);
hr = psl->GetIDList(&_pidlTarget);
if (SUCCEEDED(hr))
{
hr = _pslTarget->SetIDList(_pidlTarget);
}
psl->Release();
}
}
if (FAILED(hr) && _pidlTarget)
{
ILFree(_pidlTarget);
_pidlTarget = NULL;
}
}
}
return hr;
}
// create _psfTarget (requires _pidlTarget)
HRESULT CFolderShortcut::_BindFolder(BOOL bResolve)
{
ASSERT(_psfTarget == NULL);
HRESULT hr = _GetTargetIDList(bResolve);
if (SUCCEEDED(hr))
{
IBindCtx *pbc = NULL; // in/out param below
hr = _PreBindCtxHelper(&pbc); // avoid loops in the name space
if (SUCCEEDED(hr))
{
if (SUCCEEDED(hr))
{
IShellFolder *psfDesktop;
hr = SHGetDesktopFolder(&psfDesktop);
if (SUCCEEDED(hr))
{
// Are we trying to bind to the desktop folder?
if (ILIsEmpty(_pidlTarget))
{
// Yes; Clone the desktop shell folder.
_psfTarget = psfDesktop;
_psfTarget->AddRef();
hr = S_OK;
}
else
{
// No. Bind to it.
hr = psfDesktop->BindToObject(_pidlTarget, pbc, IID_PPV_ARG(IShellFolder, &_psfTarget));
}
if (SUCCEEDED(hr))
{
// optionally re-target the folder (if he is a file system folder)
// to separate the location in the name space (_pidlRoot)
// and the folder being viewed (pfsfi.szFolderPath).
IPersistFolder3 *ppf;
if (SUCCEEDED(_psfTarget->QueryInterface(IID_PPV_ARG(IPersistFolder3, &ppf))))
{
PERSIST_FOLDER_TARGET_INFO pfti = { 0 };
pfti.pidlTargetFolder = _pidlTarget;
pfti.dwAttributes = _dwAttributesTarget;
pfti.csidl = -1;
hr = ppf->InitializeEx(pbc, _pidlRoot, &pfti);
ppf->Release();
}
}
psfDesktop->Release();
}
}
pbc->Release();
}
}
return hr;
}
// ensure that _psfTarget is inited
HRESULT CFolderShortcut::_GetFolder(BOOL fForceResolve)
{
HRESULT hr;
if (fForceResolve)
{
if (_fHaveResolved)
{
hr = _psfTarget ? S_OK : E_FAIL;
}
else
{
_fHaveResolved = TRUE; // don't do this again
_ClearTargetFolder();
Pidl_Set(&_pidlTarget, NULL);
hr = _BindFolder(fForceResolve);
}
}
else if (_psfTarget)
{
hr = S_OK;
}
else
{
hr = _BindFolder(fForceResolve);
}
return hr;
}
// ensure that _psf2Target is inited
HRESULT CFolderShortcut::_GetFolder2()
{
if (_psf2Target)
return S_OK;
HRESULT hr = _GetFolder(FALSE);
if (SUCCEEDED(hr))
hr = _psfTarget->QueryInterface(IID_PPV_ARG(IShellFolder2, &_psf2Target));
return hr;
}
STDMETHODIMP CFolderShortcut::QueryInterface(REFIID riid, void **ppvObj)
{
static const QITAB qit[] = {
QITABENTMULTI(CFolderShortcut, IShellFolder, IShellFolder2),
QITABENT(CFolderShortcut, IShellFolder2),
QITABENTMULTI(CFolderShortcut, IPersist, IPersistFolder3),
QITABENTMULTI(CFolderShortcut, IPersistFolder, IPersistFolder3),
QITABENTMULTI(CFolderShortcut, IPersistFolder2, IPersistFolder3),
QITABENT(CFolderShortcut, IPersistFolder3),
QITABENT(CFolderShortcut, IPersistStreamInit),
QITABENTMULTI(CFolderShortcut, IPersistStream, IPersistStreamInit),
QITABENT(CFolderShortcut, IShellLinkA),
QITABENT(CFolderShortcut, IShellLinkW),
QITABENT(CFolderShortcut, IPersistFile),
QITABENT(CFolderShortcut, IFolderShortcutConvert),
QITABENT(CFolderShortcut, IExtractIcon),
QITABENT(CFolderShortcut, IQueryInfo),
QITABENT(CFolderShortcut, IPersistPropertyBag),
QITABENT(CFolderShortcut, IBrowserFrameOptions),
{ 0 },
};
return QISearch(this, qit, riid, ppvObj);
}
STDMETHODIMP_(ULONG) CFolderShortcut::AddRef()
{
return InterlockedIncrement(&_cRef);
}
STDMETHODIMP_(ULONG) CFolderShortcut::Release()
{
ASSERT( 0 != _cRef );
ULONG cRef = InterlockedDecrement(&_cRef);
if ( 0 == cRef )
{
delete this;
}
return cRef;
}
// either create or init the passed bind ctx with the params to avoid loops in the name space
HRESULT CFolderShortcut::_PreBindCtxHelper(IBindCtx **ppbc)
{
HRESULT hr;
if (*ppbc)
{
(*ppbc)->AddRef();
hr = S_OK;
}
else
{
hr = BindCtx_CreateWithMode(STGM_READ | STGM_SHARE_DENY_WRITE, ppbc);
}
if (SUCCEEDED(hr))
(*ppbc)->RegisterObjectParam(STR_SKIP_BINDING_CLSID, SAFECAST(this, IShellFolder2 *));
return hr;
}
// IShellFolder methods
HRESULT CFolderShortcut::ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR pwszDisplayName,
ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes)
{
if (!ppidl)
return E_INVALIDARG;
*ppidl = NULL;
if (!pwszDisplayName)
return E_INVALIDARG;
HRESULT hr = _GetFolder(FALSE);
if (SUCCEEDED(hr))
{
hr = _PreBindCtxHelper(&pbc);
if (SUCCEEDED(hr))
{
hr = _psfTarget->ParseDisplayName(hwnd, pbc, pwszDisplayName,
pchEaten, ppidl, pdwAttributes);
pbc->Release();
}
}
return hr;
}
HRESULT CFolderShortcut::EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList)
{
HRESULT hr = _GetFolder(TRUE);
if (SUCCEEDED(hr))
hr = _psfTarget->EnumObjects(hwnd, grfFlags, ppenumIDList);
if (SUCCEEDED(hr))
SHChangeNotifyRegisterAlias(_pidlTarget, _pidlRoot);
return hr;
}
HRESULT CFolderShortcut::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
{
HRESULT hr = _GetFolder(TRUE);
if (SUCCEEDED(hr))
{
hr = _PreBindCtxHelper(&pbc);
if (SUCCEEDED(hr))
{
hr = _psfTarget->BindToObject(pidl, pbc, riid, ppv);
pbc->Release();
if (SUCCEEDED(hr))
SHChangeNotifyRegisterAlias(_pidlTarget, _pidlRoot);
}
}
return hr;
}
HRESULT CFolderShortcut::BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
{
return BindToObject(pidl, pbc, riid, ppv);
}
HRESULT CFolderShortcut::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
{
HRESULT hr = _GetFolder(FALSE);
if (SUCCEEDED(hr))
hr = _psfTarget->CompareIDs(lParam, pidl1, pidl2);
return hr;
}
HRESULT CFolderShortcut::CreateViewObject(HWND hwnd, REFIID riid, void **ppv)
{
HRESULT hr = _GetFolder(TRUE);
if ( SUCCEEDED(hr) )
hr = _psfTarget->CreateViewObject(hwnd, riid, ppv);
if ( SUCCEEDED(hr) && (IsEqualIID(riid, IID_IShellView) || IsEqualIID(riid, IID_IShellView2)) )
SHChangeNotifyRegisterAlias(_pidlTarget, _pidlRoot);
return hr;
}
HRESULT CFolderShortcut::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, ULONG *rgfInOut)
{
if (IsSelf (cidl, apidl))
{
// since our folder is marked "CallForAttributes" we get to report
// our attributes at runtime instead of the normal way via the registry
if (SHGetAppCompatFlags (ACF_STRIPFOLDERBIT) & ACF_STRIPFOLDERBIT)
{
*rgfInOut = SFGAO_LINK | SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM;
}
else
{
*rgfInOut = SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_STORAGE |
SFGAO_LINK | SFGAO_DROPTARGET | SFGAO_CANRENAME | SFGAO_CANDELETE |
SFGAO_CANLINK | SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_HASSUBFOLDER;
}
return S_OK;
}
HRESULT hr = _GetFolder(FALSE);
if (SUCCEEDED(hr))
hr = _psfTarget->GetAttributesOf(cidl, apidl, rgfInOut);
return hr;
}
HRESULT CFolderShortcut::GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST *apidl,
REFIID riid, UINT *prgfInOut, void **ppv)
{
HRESULT hr = _GetFolder(FALSE);
if (SUCCEEDED(hr))
hr = _psfTarget->GetUIObjectOf(hwnd, cidl, apidl, riid, prgfInOut, ppv);
return hr;
}
HRESULT CFolderShortcut::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, STRRET *pName)
{
HRESULT hr = _GetFolder(FALSE);
if (SUCCEEDED(hr))
hr = _psfTarget->GetDisplayNameOf(pidl, uFlags, pName);
return hr;
}
HRESULT CFolderShortcut::SetNameOf(HWND hwnd, LPCITEMIDLIST pidl,
LPCOLESTR pszName, DWORD uFlags,
LPITEMIDLIST *ppidlOut)
{
HRESULT hr = _GetFolder(FALSE);
if (SUCCEEDED(hr))
hr = _psfTarget->SetNameOf(hwnd, pidl, pszName, uFlags, ppidlOut);
return hr;
}
STDMETHODIMP CFolderShortcut::GetDefaultSearchGUID(LPGUID lpGuid)
{
HRESULT hr = _GetFolder2();
if (SUCCEEDED(hr))
hr = _psf2Target->GetDefaultSearchGUID(lpGuid);
return hr;
}
STDMETHODIMP CFolderShortcut::EnumSearches(LPENUMEXTRASEARCH *ppenum)
{
HRESULT hr = _GetFolder2();
if (SUCCEEDED(hr))
hr = _psf2Target->EnumSearches(ppenum);
return hr;
}
STDMETHODIMP CFolderShortcut::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
{
HRESULT hr = _GetFolder2();
if (SUCCEEDED(hr))
hr = _psf2Target->GetDefaultColumn(dwRes, pSort, pDisplay);
return hr;
}
STDMETHODIMP CFolderShortcut::GetDefaultColumnState(UINT iColumn, DWORD *pbState)
{
HRESULT hr = _GetFolder2();
if (SUCCEEDED(hr))
hr = _psf2Target->GetDefaultColumnState(iColumn, pbState);
return hr;
}
STDMETHODIMP CFolderShortcut::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
{
HRESULT hr = _GetFolder2();
if (SUCCEEDED(hr))
hr = _psf2Target->GetDetailsEx(pidl, pscid, pv);
return hr;
}
STDMETHODIMP CFolderShortcut::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, LPSHELLDETAILS pDetail)
{
HRESULT hr = _GetFolder2();
if (SUCCEEDED(hr))
hr = _psf2Target->GetDetailsOf(pidl, iColumn, pDetail);
return hr;
}
STDMETHODIMP CFolderShortcut::MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid)
{
HRESULT hr = _GetFolder2();
if (SUCCEEDED(hr))
hr = _psf2Target->MapColumnToSCID(iColumn, pscid);
return hr;
}
// IPersist
HRESULT CFolderShortcut::GetClassID(CLSID *pCLSID)
{
*pCLSID = CLSID_FolderShortcut;
return S_OK;
}
// IPersistFolder
HRESULT CFolderShortcut::Initialize(LPCITEMIDLIST pidl)
{
HRESULT hr;
// is the link loaded (could have been loaded through IPersistStream::Load)?
if (_pslTarget)
{
// Yes, it's loaded so re-initialize
// note, _szFolderPath will be empty since we are not loaded from the file system
hr = Pidl_Set(&_pidlRoot, pidl) ? S_OK : E_OUTOFMEMORY;
}
else
{
// we explictly require initialization through
// IPersistFolder3::InitializeEx, if we don't do these we can
// not defent against loops in the name space
hr = E_FAIL;
}
return hr;
}
// IPersistFolder2
STDMETHODIMP CFolderShortcut::GetCurFolder(LPITEMIDLIST *ppidl)
{
return GetCurFolderImpl(this->_pidlRoot, ppidl);
}
// IPersistFolder3
STDMETHODIMP CFolderShortcut::InitializeEx(IBindCtx *pbc, LPCITEMIDLIST pidlRoot, const PERSIST_FOLDER_TARGET_INFO *pfti)
{
HRESULT hr = E_INVALIDARG; // assume failure
if ( NULL == pbc || (pbc && !SHSkipJunction(pbc, &CLSID_FolderShortcut)) )
{
_ClearState();
if (pidlRoot)
hr = SHILClone(pidlRoot, &_pidlRoot);
if (pfti && pfti->pidlTargetFolder)
{
if ( SUCCEEDED(hr) )
hr = SHILClone(pfti->pidlTargetFolder, &_pidlTargetFldrFromInit);
if ( SUCCEEDED(hr) && !_szFolderPath[0] )
hr = SHGetPathFromIDList(pfti->pidlTargetFolder, _szFolderPath) ? S_OK : E_FAIL;
}
else
{
if ( SUCCEEDED(hr) && !_szFolderPath[0] )
hr = SHGetPathFromIDList(_pidlRoot, _szFolderPath) ? S_OK : E_FAIL;
}
if ( SUCCEEDED(hr) )
hr = _LoadShortcut();
}
return hr;
}
HRESULT CFolderShortcut::GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO *pfti)
{
HRESULT hr = S_OK;
ZeroMemory(pfti, sizeof(*pfti));
if ( _pidlTargetFldrFromInit )
hr = SHILClone(_pidlTargetFldrFromInit, &pfti->pidlTargetFolder);
pfti->dwAttributes = -1;
pfti->csidl = -1;
return hr;
}
HRESULT CFolderShortcut::_GetLink()
{
HRESULT hr = _LoadShortcut();
if (FAILED(hr))
{
// get an empty one in case we are going to be asked to save
hr = SHCoCreateInstance(NULL, &CLSID_ShellLink, NULL, IID_PPV_ARG(IShellLinkW, &_pslTarget));
}
return hr;
}
HRESULT CFolderShortcut::_GetLinkQI(REFIID riid, void **ppv)
{
HRESULT hr = _GetLink();
if (SUCCEEDED(hr))
hr = _pslTarget->QueryInterface(riid, ppv);
return hr;
}
HRESULT CFolderShortcut::_GetLinkA()
{
return _pslTargetA ? S_OK : _GetLinkQI(IID_PPV_ARG(IShellLinkA, &_pslTargetA));
}
// IPersistFile
STDMETHODIMP CFolderShortcut::Load(LPCOLESTR pszFileName, DWORD dwMode)
{
_ClearState();
SHUnicodeToTChar(pszFileName, _szFolderPath, ARRAYSIZE(_szFolderPath));
return _LoadShortcut();
}
BOOL _IsFolder(LPCITEMIDLIST pidl)
{
ULONG rgInfo = SFGAO_FOLDER;
HRESULT hr = SHGetNameAndFlags(pidl, SHGDN_NORMAL, NULL, 0, &rgInfo);
return SUCCEEDED(hr) && (rgInfo & SFGAO_FOLDER);
}
void PathStripTrailingDots(LPTSTR szPath)
{
if (szPath[0] == TEXT('\0'))
return;
LPTSTR psz = &szPath[lstrlen(szPath) - 1];
while ((*psz == TEXT('.')) &&
(psz >= szPath))
{
*psz-- = TEXT('\0');
}
}
STDMETHODIMP CFolderShortcut::Save(LPCOLESTR pszFileName, BOOL fRemember)
{
HRESULT hr = _GetTargetIDList(FALSE);
// We need to make sure the folder shortcut can be saved keeping in mind the MAX_PATH limitation
// cchFSReserved is the number of characters to reserve for the largest file that will be created
// in the foldershortcut directory, in this case, it is the ARRAYSIZE of "\\desktop.ini"
static const int cchFSReserved = ARRAYSIZE(TEXT("\\desktop.ini"));
LPITEMIDLIST pidlInternet;
// Don't create a folder shortcut to the internet folder.
if (SUCCEEDED(hr) && SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_INTERNET, &pidlInternet)))
{
if (ILIsEqual(_pidlTarget, pidlInternet))
{
hr = E_INVALIDARG;
}
ILFree(pidlInternet);
}
if (SUCCEEDED(hr) && _IsFolder(_pidlTarget))
{
// we know the target is a folder, create a folder shortcut.
BOOL fCreatedDir;
TCHAR szName[MAX_PATH];
SHUnicodeToTChar(pszFileName, szName, ARRAYSIZE(szName));
// Remove any exisiting extension.
// We dont want "Shortcut To My Documents.lnk.{GUID}
if (PathFindCLSIDExtension(szName,NULL))
{
PathRemoveExtension(szName);
}
PathStripTrailingDots(szName);
// Can't create a fldrshcut with too long a path
if ((MAX_PATH - cchFSReserved) < lstrlen(szName))
{
hr = CO_E_PATHTOOLONG;
}
if (SUCCEEDED(hr))
{
if (PathIsDirectory(szName))
fCreatedDir = FALSE;
else
fCreatedDir = SHCreateDirectory(NULL, szName) == 0;
CreateFolderDesktopIni(szName);
// Now initialize the child link
IPersistFile *ppf;
hr = _pslTarget->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
if (SUCCEEDED(hr))
{
WCHAR wszName[MAX_PATH];
SHTCharToUnicode(szName, wszName, ARRAYSIZE(wszName));
if (PathAppendW(wszName, L"target.lnk"))
{
hr = ppf->Save(wszName, fRemember);
if (SUCCEEDED(hr))
{
if (fRemember)
Str_SetPtr(&_pszLastSave, szName);
}
}
else
{
hr = HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE);
}
ppf->Release();
}
if (FAILED(hr) && fCreatedDir)
{
RemoveDirectory(szName); // cleanup after ourselves.
}
}
}
else
{
// ensure that if we save as a file we do so with the right extension
WCHAR szFile[MAX_PATH];
hr = StringCchCopy(szFile, ARRAYSIZE(szFile), pszFileName);
if (SUCCEEDED(hr))
{
PathRenameExtension(szFile, L".lnk");
// the target is not a folder, create a normal shortcut in this case
IPersistFile *ppf;
hr = _pslTarget->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
if (SUCCEEDED(hr))
{
hr = ppf->Save(szFile, fRemember);
ppf->Release();
}
}
}
return hr;
}
STDMETHODIMP CFolderShortcut::GetCurFile(LPOLESTR *ppszFileName)
{
HRESULT hr = E_FAIL;
if (_pszLastSave)
hr = SHStrDup(_pszLastSave, ppszFileName);
else if (_pslTarget)
{
IPersistFile *ppf;
hr = _pslTarget->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
if (SUCCEEDED(hr))
{
hr = ppf->GetCurFile(ppszFileName);
ppf->Release();
}
}
return hr;
}
// IShellLinkW
STDMETHODIMP CFolderShortcut::GetPath(LPWSTR pszFile, int cchMaxPath, WIN32_FIND_DATAW *pfd, DWORD flags)
{
HRESULT hr = _GetLink();
if (SUCCEEDED(hr))
hr = _pslTarget->GetPath(pszFile, cchMaxPath, pfd, flags);
return hr;
}
STDMETHODIMP CFolderShortcut::SetPath(LPCWSTR pwszFile)
{
HRESULT hr = _GetLink();
if (SUCCEEDED(hr) && PathIsDirectoryW(pwszFile))
{
hr = _pslTarget->SetPath(pwszFile);
Pidl_Set(&_pidlTarget, NULL);
}
return hr;
}
STDMETHODIMP CFolderShortcut::GetIDList(LPITEMIDLIST *ppidl)
{
HRESULT hr = _GetLink();
if (SUCCEEDED(hr))
hr = _pslTarget->GetIDList(ppidl);
else
*ppidl = NULL;
return hr;
}
STDMETHODIMP CFolderShortcut::SetIDList(LPCITEMIDLIST pidl)
{
HRESULT hr = _GetLink();
if (SUCCEEDED(hr))
{
hr = _pslTarget->SetIDList(pidl);
Pidl_Set(&_pidlTarget, NULL);
}
return hr;
}
STDMETHODIMP CFolderShortcut::GetDescription(LPWSTR wszName, int cchMaxName)
{
HRESULT hr = _GetLink();
if (SUCCEEDED(hr))
hr = _pslTarget->GetDescription(wszName, cchMaxName);
return hr;
}
STDMETHODIMP CFolderShortcut::SetDescription(LPCWSTR wszName)
{
HRESULT hr = _GetLink();
if (SUCCEEDED(hr))
hr = _pslTarget->SetDescription(wszName);
return hr;
}
STDMETHODIMP CFolderShortcut::GetWorkingDirectory(LPWSTR wszDir, int cchMaxPath)
{
HRESULT hr = _GetLink();
if (SUCCEEDED(hr))
hr = _pslTarget->GetWorkingDirectory(wszDir, cchMaxPath);
return hr;
}
STDMETHODIMP CFolderShortcut::SetWorkingDirectory(LPCWSTR wszDir)
{
HRESULT hr = _GetLink();
if (SUCCEEDED(hr))
hr = _pslTarget->SetWorkingDirectory(wszDir);
return hr;
}
STDMETHODIMP CFolderShortcut::GetArguments(LPWSTR wszArgs, int cchMaxPath)
{
HRESULT hr = _GetLink();
if (SUCCEEDED(hr))
hr = _pslTarget->GetArguments(wszArgs, cchMaxPath);//this is probably not at all useful.
return hr;
}
STDMETHODIMP CFolderShortcut::SetArguments(LPCWSTR wszArgs)
{
HRESULT hr = _GetLink();
if (SUCCEEDED(hr))
hr = _pslTarget->SetArguments(wszArgs);//this is probably not at all useful.
return hr;
}
STDMETHODIMP CFolderShortcut::GetHotkey(WORD *pwHotkey)
{
HRESULT hr = _GetLink();
if (SUCCEEDED(hr))
hr = _pslTarget->GetHotkey(pwHotkey);
return hr;
}
STDMETHODIMP CFolderShortcut::SetHotkey(WORD wHotkey)
{
HRESULT hr = _GetLink();
if (SUCCEEDED(hr))
hr = _pslTarget->SetHotkey(wHotkey);
return hr;
}
STDMETHODIMP CFolderShortcut::GetShowCmd(int *piShowCmd)
{
HRESULT hr = _GetLink();
if (SUCCEEDED(hr))
hr = _pslTarget->GetShowCmd(piShowCmd);
return hr;
}
STDMETHODIMP CFolderShortcut::SetShowCmd(int iShowCmd)
{
HRESULT hr = _GetLink();
if (SUCCEEDED(hr))
hr = _pslTarget->SetShowCmd(iShowCmd);
return hr;
}
STDMETHODIMP CFolderShortcut::GetIconLocation(LPWSTR wszIconPath, int cchIconPath, int *piIcon)
{
HRESULT hr = _GetLink();
if (SUCCEEDED(hr))
hr = _pslTarget->GetIconLocation(wszIconPath, cchIconPath, piIcon);
return hr;
}
STDMETHODIMP CFolderShortcut::SetIconLocation(LPCWSTR wszIconPath, int iIcon)
{
HRESULT hr = _GetLink();
if (SUCCEEDED(hr))
hr = _pslTarget->SetIconLocation(wszIconPath, iIcon);
return hr;
}
STDMETHODIMP CFolderShortcut::Resolve(HWND hwnd, DWORD fFlags)
{
HRESULT hr = _GetLink();
if (SUCCEEDED(hr))
hr = _pslTarget->Resolve(hwnd, fFlags);
return hr;
}
STDMETHODIMP CFolderShortcut::SetRelativePath(LPCWSTR wszPathRel, DWORD dwReserved)
{
HRESULT hr = _GetLink();
if (SUCCEEDED(hr))
hr = _pslTarget->SetRelativePath(wszPathRel, dwReserved);
return hr;
}
// IShellLinkA
STDMETHODIMP CFolderShortcut::GetPath(LPSTR pszFile, int cchMaxPath, WIN32_FIND_DATAA *pfd, DWORD flags)
{
HRESULT hr = _GetLinkA();
if (SUCCEEDED(hr))
hr = _pslTargetA->GetPath(pszFile, cchMaxPath, pfd, flags);
return hr;
}
STDMETHODIMP CFolderShortcut::GetDescription(LPSTR pszName, int cchMaxName)
{
HRESULT hr = _GetLinkA();
if (SUCCEEDED(hr))
hr = _pslTargetA->GetDescription(pszName, cchMaxName);
return hr;
}
STDMETHODIMP CFolderShortcut::GetWorkingDirectory(LPSTR pszDir, int cchMaxPath)
{
HRESULT hr = _GetLinkA();
if (SUCCEEDED(hr))
hr = _pslTargetA->GetWorkingDirectory(pszDir, cchMaxPath);
return hr;
}
STDMETHODIMP CFolderShortcut::GetArguments(LPSTR pszArgs, int cchMaxPath)
{
HRESULT hr = _GetLinkA();
if (SUCCEEDED(hr))
hr = _pslTargetA->GetArguments(pszArgs, cchMaxPath);//this is probably not at all useful.
return hr;
}
STDMETHODIMP CFolderShortcut::GetIconLocation(LPSTR pszIconPath, int cchIconPath, int *piIcon)
{
HRESULT hr = _GetLinkA();
if (SUCCEEDED(hr))
hr = _pslTargetA->GetIconLocation(pszIconPath, cchIconPath, piIcon);
return hr;
}
STDMETHODIMP CFolderShortcut::SetPath(LPCSTR pszFile)
{
HRESULT hr = _GetLinkA();
if (SUCCEEDED(hr) && PathIsDirectoryA(pszFile))
{
hr = _pslTargetA->SetPath(pszFile);
Pidl_Set(&_pidlTarget, NULL);
}
return hr;
}
STDMETHODIMP CFolderShortcut::SetDescription(LPCSTR pszName)
{
HRESULT hr = _GetLinkA();
if (SUCCEEDED(hr))
hr = _pslTargetA->SetDescription(pszName);
return hr;
}
STDMETHODIMP CFolderShortcut::SetWorkingDirectory(LPCSTR pszDir)
{
HRESULT hr = _GetLinkA();
if (SUCCEEDED(hr))
hr = _pslTargetA->SetWorkingDirectory(pszDir);
return hr;
}
STDMETHODIMP CFolderShortcut::SetArguments(LPCSTR pszArgs)
{
HRESULT hr = _GetLinkA();
if (SUCCEEDED(hr))
hr = _pslTargetA->SetArguments(pszArgs);
return hr;
}
STDMETHODIMP CFolderShortcut::SetIconLocation(LPCSTR pszIconPath, int iIcon)
{
HRESULT hr = _GetLinkA();
if (SUCCEEDED(hr))
hr = _pslTargetA->SetIconLocation(pszIconPath, iIcon);
return hr;
}
STDMETHODIMP CFolderShortcut::SetRelativePath(LPCSTR pszPathRel, DWORD dwReserved)
{
HRESULT hr = _GetLinkA();
if (SUCCEEDED(hr))
hr = _pslTargetA->SetRelativePath(pszPathRel, dwReserved);
return hr;
}
STDMETHODIMP CFolderShortcut::GetIconLocation(UINT uFlags, LPTSTR pszIconFile, UINT ucchMax, PINT pniIcon, PUINT puFlags)
{
IExtractIcon *pxi;
HRESULT hr = _GetLinkQI(IID_PPV_ARG(IExtractIcon, &pxi));
if (SUCCEEDED(hr))
{
hr = pxi->GetIconLocation(uFlags, pszIconFile, ucchMax, pniIcon, puFlags);
pxi->Release();
}
return hr;
}
STDMETHODIMP CFolderShortcut::Extract(LPCTSTR pcszFile, UINT uIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT ucIconSize)
{
IExtractIcon *pxi;
HRESULT hr = _GetLinkQI(IID_PPV_ARG(IExtractIcon, &pxi));
if (SUCCEEDED(hr))
{
hr = pxi->Extract(pcszFile, uIconIndex, phiconLarge, phiconSmall, ucIconSize);
pxi->Release();
}
return hr;
}
HRESULT CFolderShortcut::GetInfoTip(DWORD dwFlags, WCHAR** ppwszText)
{
IQueryInfo *pqi;
HRESULT hr = _GetLinkQI(IID_PPV_ARG(IQueryInfo, &pqi));
if (SUCCEEDED(hr))
{
hr = pqi->GetInfoTip(dwFlags | QITIPF_LINKUSETARGET, ppwszText);
pqi->Release();
}
return hr;
}
HRESULT CFolderShortcut::GetInfoFlags(DWORD *pdwFlags)
{
IQueryInfo *pqi;
HRESULT hr = _GetLinkQI(IID_PPV_ARG(IQueryInfo, &pqi));
if (SUCCEEDED(hr))
{
hr = pqi->GetInfoFlags(pdwFlags);
pqi->Release();
}
return hr;
}
// IBrowserFrameOptions
HRESULT CFolderShortcut::GetFrameOptions(IN BROWSERFRAMEOPTIONS dwMask, IN BROWSERFRAMEOPTIONS * pdwOptions)
{
HRESULT hr = _GetFolder(FALSE);
*pdwOptions = BFO_NONE;
if (SUCCEEDED(hr))
{
IBrowserFrameOptions *pbfo;
hr = _psfTarget->QueryInterface(IID_PPV_ARG(IBrowserFrameOptions, &pbfo));
if (SUCCEEDED(hr))
{
hr = pbfo->GetFrameOptions(dwMask, pdwOptions);
pbfo->Release();
}
}
return hr;
}
// IPersistStream
STDMETHODIMP CFolderShortcut::Load(IStream *pStm)
{
_ClearState();
IPersistStream *pps;
HRESULT hr = SHCoCreateInstance(NULL, &CLSID_ShellLink, NULL, IID_PPV_ARG(IPersistStream, &pps));
if (SUCCEEDED(hr))
{
hr = pps->Load(pStm);
if (SUCCEEDED(hr))
pps->QueryInterface(IID_PPV_ARG(IShellLinkW, &_pslTarget)); // keep this guy
pps->Release();
}
return hr;
}
// IPersistStream
STDMETHODIMP CFolderShortcut::Save(IStream *pStm, int fClearDirty)
{
return E_NOTIMPL;
}
// IPersistStream
STDMETHODIMP CFolderShortcut::GetSizeMax(ULARGE_INTEGER * pcbSize)
{
return E_NOTIMPL;
}
//
// IFolderShortcut::ConvertToLink.
//
// destructively convert a Folder Shortcut into a Shell Link.
//
// pszFolderShortcut is the path to an existing folder shortcut
// c:\Folder Shortcut.{guid} - deleted
// c:\Folder Shortcut.lnk - created
//
STDMETHODIMP CFolderShortcut::ConvertToLink(LPCOLESTR pszFolderShortcut, DWORD fFlags)
{
HRESULT hr = E_FAIL;
TCHAR szName[MAX_PATH];
SHUnicodeToTChar(pszFolderShortcut, szName, ARRAYSIZE(szName));
if (PathIsDirectory(szName) && IsFolderShortcut(szName))
{
TCHAR szLinkName[MAX_PATH];
// c:\Folder Shortcut\target.lnk
hr = StringCchCopy(szLinkName, ARRAYSIZE(szLinkName), szName);
if (SUCCEEDED(hr))
{
hr = E_FAIL;
if (PathAppend(szLinkName, TEXT("target.lnk")))
{
PathRenameExtension(szName, TEXT(".lnk"));
// FS.{guid} -> FS.lnk
if (CopyFile(szLinkName, szName, FALSE))
{
PathRemoveExtension(szName);
if (DeleteFile(szLinkName)
&& PathAppend(szName, TEXT("desktop.ini"))
&& DeleteFile(szName)
&& PathRemoveFileSpec(szName)
&& RemoveDirectory(szName))
{
hr = S_OK;
}
}
}
}
}
return hr;
}
//
// IFolderShortcut::ConvertToFolderShortcut.
//
// destructively convert a Shell Link (.lnk) -> Folder Shortcut (Folder.{guid}).
// pszPathLNK is the path to an existing .lnk file
// c:\Folder Shortcut.lnk - deleted
// c:\Folder Shortcut.{guid} - created
//
STDMETHODIMP CFolderShortcut::ConvertToFolderShortcut(LPCOLESTR pszPathLNK, DWORD fFlags)
{
//must bind to the link, resolve it, and make sure it points to a folder.
IShellLink *psl;
HRESULT hr = SHCoCreateInstance(NULL, &CLSID_ShellLink, NULL, IID_PPV_ARG(IShellLink, &psl));
if (SUCCEEDED(hr))
{
IPersistFile *ppf;
hr = psl->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
if (SUCCEEDED(hr))
{
hr = ppf->Load(pszPathLNK, STGM_READ);
if (SUCCEEDED(hr))
{
hr = psl->Resolve(NULL, SLR_NO_UI); // make sure the link is real
if (SUCCEEDED(hr))
{
LPITEMIDLIST pidl;
hr = psl->GetIDList(&pidl);
if (hr == S_OK)
{
// this should maybe work on the pidl so that
// it doesn't have to worry about files.
if (_IsFolder(pidl))
{
TCHAR szPath[MAX_PATH], szName[MAX_PATH];
SHUnicodeToTChar(pszPathLNK, szName, ARRAYSIZE(szName));
hr = StringCchCopy(szPath, ARRAYSIZE(szPath), szName);
if (SUCCEEDED(hr))
{
hr = E_FAIL;
PathRemoveExtension(szName);
BOOL fCreatedDir = SHCreateDirectory(NULL, szName) == 0;
if (CreateFolderDesktopIni(szName) &&
PathAppend(szName, TEXT("target.lnk")))
{
//copy the link file into the new directory.
if (CopyFile(szPath, szName, FALSE))
{
if (DeleteFile(szPath)) //if all goes well, delete the old.
hr = S_OK;
}
else
{
PathRemoveFileSpec(szName);
if (fCreatedDir)
RemoveDirectory(szName);
}
}
}
}
else
hr = E_FAIL;
ILFree(pidl);
}
else
hr = E_FAIL;
}
}
ppf->Release();
}
psl->Release();
}
return hr;
}
// IPersistPropertyBag
STDMETHODIMP CFolderShortcut::Save(IPropertyBag* pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties)
{
return E_NOTIMPL;
}
// IPersistPropertyBag
STDMETHODIMP CFolderShortcut::Load(IPropertyBag* pPropBag, IErrorLog* pErrorLog)
{
_ClearState();
IPersistPropertyBag* pppb;
HRESULT hr = SHCoCreateInstance(NULL, &CLSID_ShellLink, NULL, IID_PPV_ARG(IPersistPropertyBag, &pppb));
if (SUCCEEDED(hr))
{
hr = pppb->Load(pPropBag, pErrorLog);
if (SUCCEEDED(hr))
{
hr = pppb->QueryInterface(IID_PPV_ARG(IShellLinkW, &_pslTarget));
DWORD dwFlags;
if (SUCCEEDED(SHPropertyBag_ReadDWORD(pPropBag, L"Attributes", &dwFlags)))
_dwAttributesTarget = dwFlags;
}
pppb->Release();
}
return hr;
}
STDMETHODIMP CFolderShortcut::InitNew(void)
{
_ClearState();
return S_OK;
}