Source code of Windows XP (NT5)
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.

1457 lines
42 KiB

  1. // Implements Folder Shortcut.
  2. #include "shellprv.h"
  3. #include "clsobj.h"
  4. // implemented in filefldr.cpp
  5. extern LPTSTR PathFindCLSIDExtension(LPCTSTR pszFile, CLSID *pclsid);
  6. BOOL CreateFolderDesktopIni(LPCTSTR pszName)
  7. {
  8. SHFOLDERCUSTOMSETTINGS fcs = {0};
  9. fcs.dwSize = sizeof(fcs);
  10. fcs.dwMask = FCSM_CLSID | FCSM_FLAGS;
  11. fcs.pclsid = (GUID*)&CLSID_FolderShortcut;
  12. fcs.dwFlags = FCS_FLAG_DRAGDROP;
  13. return SUCCEEDED(SHGetSetFolderCustomSettings(&fcs, pszName, FCS_FORCEWRITE));
  14. }
  15. EXTERN_C BOOL IsFolderShortcut(LPCTSTR pszName)
  16. {
  17. SHFOLDERCUSTOMSETTINGS fcs = {0};
  18. CLSID clsid = {0};
  19. fcs.dwSize = sizeof(fcs);
  20. fcs.dwMask = FCSM_CLSID;
  21. fcs.pclsid = &clsid;
  22. if (SUCCEEDED(SHGetSetFolderCustomSettings(&fcs, pszName, FCS_READ)))
  23. {
  24. return IsEqualGUID(clsid, CLSID_FolderShortcut);
  25. }
  26. return FALSE;
  27. }
  28. // exported from fsnotify.c
  29. STDAPI_(void) SHChangeNotifyRegisterAlias(LPCITEMIDLIST pidlReal, LPCITEMIDLIST pidlAlias);
  30. class CFolderShortcut : public IShellFolder2,
  31. public IPersistFolder3,
  32. public IShellLinkA,
  33. public IShellLinkW,
  34. public IPersistFile,
  35. public IExtractIcon,
  36. public IQueryInfo,
  37. public IFolderShortcutConvert,
  38. public IPersistStreamInit,
  39. public IPersistPropertyBag,
  40. public IBrowserFrameOptions
  41. {
  42. public:
  43. // IUnknown
  44. STDMETHODIMP QueryInterface(REFIID, void **);
  45. STDMETHODIMP_(ULONG) AddRef(void);
  46. STDMETHODIMP_(ULONG) Release(void);
  47. // IShellFolder
  48. STDMETHODIMP ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR pszDisplayName,
  49. ULONG *pchEaten, LPITEMIDLIST *ppidl, ULONG *pdwAttributes);
  50. STDMETHODIMP EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList ** ppenumIDList);
  51. STDMETHODIMP BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv);
  52. STDMETHODIMP BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv);
  53. STDMETHODIMP CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
  54. STDMETHODIMP CreateViewObject (HWND hwnd, REFIID riid, void **ppv);
  55. STDMETHODIMP GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl, ULONG *rgfInOut);
  56. STDMETHODIMP GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST * apidl,
  57. REFIID riid, UINT * prgfInOut, void **ppv);
  58. STDMETHODIMP GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName);
  59. STDMETHODIMP SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR pszName, DWORD uFlags,
  60. LPITEMIDLIST *ppidlOut);
  61. // IShellFolder2
  62. STDMETHODIMP GetDefaultSearchGUID(GUID *pGuid);
  63. STDMETHODIMP EnumSearches(IEnumExtraSearch **ppenum);
  64. STDMETHODIMP GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay);
  65. STDMETHODIMP GetDefaultColumnState(UINT iColumn, DWORD *pbState);
  66. STDMETHODIMP GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv);
  67. STDMETHODIMP GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pDetails);
  68. STDMETHODIMP MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid);
  69. // IPersist
  70. STDMETHODIMP GetClassID(CLSID *pClassID);
  71. // IPersistFolder
  72. STDMETHODIMP Initialize(LPCITEMIDLIST pidl);
  73. // IPersistFolder2
  74. STDMETHODIMP GetCurFolder(LPITEMIDLIST *ppidl);
  75. // IPersistFolder3
  76. STDMETHODIMP InitializeEx(IBindCtx *pbc, LPCITEMIDLIST pidlRoot, const PERSIST_FOLDER_TARGET_INFO *pfti);
  77. STDMETHODIMP GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO *pfti);
  78. // IPersistStream
  79. STDMETHODIMP Load(IStream *pStm);
  80. STDMETHODIMP Save(IStream *pStm,int fClearDirty);
  81. STDMETHODIMP GetSizeMax(ULARGE_INTEGER * pcbSize);
  82. // IPersistPropertyBag
  83. STDMETHODIMP Save(IPropertyBag* pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties);
  84. STDMETHODIMP Load(IPropertyBag* pPropBag, IErrorLog* pErrorLog);
  85. // IPersistPropertyBag/IPersistStreamInit
  86. STDMETHODIMP InitNew(void);
  87. // IPersistFile
  88. STDMETHODIMP Load(LPCOLESTR pszFileName, DWORD dwMode);
  89. STDMETHODIMP Save(LPCOLESTR pszFileName, BOOL fRemember);
  90. STDMETHODIMP IsDirty() { return E_NOTIMPL; };
  91. STDMETHODIMP SaveCompleted(LPCOLESTR pszFileName) { return E_NOTIMPL; };
  92. STDMETHODIMP GetCurFile(LPOLESTR *ppszFileName);
  93. // IShellLinkW
  94. STDMETHODIMP GetPath(LPWSTR pszFile, int cchMaxPath, WIN32_FIND_DATAW *pfd, DWORD flags);
  95. STDMETHODIMP SetPath(LPCWSTR pszFile);
  96. STDMETHODIMP GetIDList(LPITEMIDLIST *ppidl);
  97. STDMETHODIMP SetIDList(LPCITEMIDLIST pidl);
  98. STDMETHODIMP GetDescription(LPWSTR pszName, int cchMaxName);
  99. STDMETHODIMP SetDescription(LPCWSTR pszName);
  100. STDMETHODIMP GetWorkingDirectory(LPWSTR pszDir, int cchMaxPath);
  101. STDMETHODIMP SetWorkingDirectory(LPCWSTR pszDir);
  102. STDMETHODIMP GetArguments(LPWSTR pszArgs, int cchMaxPath);
  103. STDMETHODIMP SetArguments(LPCWSTR pszArgs);
  104. STDMETHODIMP GetHotkey(WORD *pwHotkey);
  105. STDMETHODIMP SetHotkey(WORD wHotkey);
  106. STDMETHODIMP GetShowCmd(int *piShowCmd);
  107. STDMETHODIMP SetShowCmd(int iShowCmd);
  108. STDMETHODIMP GetIconLocation(LPWSTR pszIconPath, int cchIconPath, int *piIcon);
  109. STDMETHODIMP SetIconLocation(LPCWSTR pszIconPath, int iIcon);
  110. STDMETHODIMP Resolve(HWND hwnd, DWORD fFlags);
  111. STDMETHODIMP SetRelativePath(LPCWSTR pszPathRel, DWORD dwReserved);
  112. // IShellLinkA
  113. STDMETHODIMP GetPath(LPSTR pszFile, int cchMaxPath, WIN32_FIND_DATAA *pfd, DWORD flags);
  114. STDMETHODIMP SetPath(LPCSTR pszFile);
  115. STDMETHODIMP GetDescription(LPSTR pszName, int cchMaxName);
  116. STDMETHODIMP SetDescription(LPCSTR pszName);
  117. STDMETHODIMP GetWorkingDirectory(LPSTR pszDir, int cchMaxPath);
  118. STDMETHODIMP SetWorkingDirectory(LPCSTR pszDir);
  119. STDMETHODIMP GetArguments(LPSTR pszArgs, int cchMaxPath);
  120. STDMETHODIMP SetArguments(LPCSTR pszArgs);
  121. STDMETHODIMP GetIconLocation(LPSTR pszIconPath, int cchIconPath, int *piIcon);
  122. STDMETHODIMP SetIconLocation(LPCSTR pszIconPath, int iIcon);
  123. STDMETHODIMP SetRelativePath(LPCSTR pszPathRel, DWORD dwReserved);
  124. // IFolderShortcutConvert
  125. STDMETHODIMP ConvertToLink(LPCOLESTR pszPathLNK, DWORD fFlags);
  126. STDMETHODIMP ConvertToFolderShortcut(LPCOLESTR pszPathLNK, DWORD fFlags);
  127. // IExtractIcon
  128. STDMETHODIMP GetIconLocation(UINT uFlags, LPTSTR pszIconFile, UINT ucchMax, INT *pniIcon, UINT *puFlags);
  129. STDMETHODIMP Extract(LPCTSTR pcszFile, UINT uIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT ucIconSize);
  130. // IQueryInfo
  131. STDMETHODIMP GetInfoTip(DWORD dwFlags, WCHAR** ppwszTip);
  132. STDMETHODIMP GetInfoFlags(DWORD *pdwFlags);
  133. // IBrowserFrameOptions
  134. STDMETHODIMP GetFrameOptions(IN BROWSERFRAMEOPTIONS dwMask, IN BROWSERFRAMEOPTIONS * pdwOptions);
  135. CFolderShortcut();
  136. protected:
  137. ~CFolderShortcut();
  138. void _ClearState();
  139. void _ClearTargetFolder();
  140. private:
  141. HRESULT _LoadShortcut();
  142. HRESULT _GetTargetIDList(BOOL fResolve);
  143. HRESULT _BindFolder(BOOL fResolve);
  144. HRESULT _GetFolder(BOOL fForceResolve);
  145. HRESULT _GetFolder2();
  146. HRESULT _GetLink();
  147. HRESULT _GetLinkA();
  148. HRESULT _GetLinkQI(REFIID riid, void **ppv);
  149. HRESULT _PreBindCtxHelper(IBindCtx **ppbc);
  150. LONG _cRef;
  151. LPITEMIDLIST _pidlRoot;
  152. LPITEMIDLIST _pidlTarget;
  153. LPITEMIDLIST _pidlTargetFldrFromInit;
  154. IShellFolder* _psfTarget;
  155. IShellFolder2* _psf2Target;
  156. IShellLinkW* _pslTarget;
  157. IShellLinkA* _pslTargetA;
  158. LPTSTR _pszLastSave;
  159. BOOL _fHaveResolved;
  160. DWORD _dwAttributesTarget;
  161. TCHAR _szFolderPath[MAX_PATH];
  162. };
  163. //constructor/destructor and related functions
  164. CFolderShortcut::CFolderShortcut() : _cRef(1), _dwAttributesTarget(FILE_ATTRIBUTE_DIRECTORY)
  165. {
  166. ASSERT(_pidlRoot == NULL);
  167. ASSERT(_pidlTarget == NULL);
  168. ASSERT(_psfTarget == NULL);
  169. ASSERT(_psf2Target == NULL);
  170. ASSERT(_szFolderPath[0] == 0);
  171. ASSERT(_pidlTargetFldrFromInit == NULL);
  172. DllAddRef();
  173. }
  174. CFolderShortcut::~CFolderShortcut()
  175. {
  176. _ClearState();
  177. DllRelease();
  178. }
  179. void CFolderShortcut::_ClearTargetFolder()
  180. {
  181. ATOMICRELEASE(_psfTarget);
  182. ATOMICRELEASE(_psf2Target);
  183. }
  184. void CFolderShortcut::_ClearState()
  185. {
  186. _fHaveResolved = FALSE;
  187. Pidl_Set(&_pidlRoot, NULL);
  188. Pidl_Set(&_pidlTarget, NULL);
  189. Pidl_Set(&_pidlTargetFldrFromInit, NULL);
  190. Str_SetPtr(&_pszLastSave, NULL);
  191. _ClearTargetFolder();
  192. ATOMICRELEASE(_pslTarget);
  193. ATOMICRELEASE(_pslTargetA);
  194. }
  195. STDAPI CFolderShortcut_CreateInstance(IUnknown* pUnkOuter, REFIID riid, void **ppv)
  196. {
  197. HRESULT hr = E_OUTOFMEMORY;
  198. *ppv = NULL;
  199. // aggregation checking is handled in class factory
  200. CFolderShortcut* pfolder = new CFolderShortcut();
  201. if (pfolder)
  202. {
  203. hr = pfolder->QueryInterface(riid, ppv);
  204. pfolder->Release();
  205. }
  206. return hr;
  207. }
  208. // ensure that _pslTarget has been created and loaded
  209. HRESULT CFolderShortcut::_LoadShortcut()
  210. {
  211. HRESULT hr;
  212. if (_pslTarget)
  213. {
  214. hr = S_OK;
  215. }
  216. else if (_szFolderPath[0])
  217. {
  218. TCHAR szPath[MAX_PATH];
  219. // leave this shortcut visible so down level clients see it and can
  220. // navigate through it.
  221. PathCombine(szPath, _szFolderPath, TEXT("target.lnk"));
  222. hr = LoadFromFile(CLSID_ShellLink, szPath, IID_PPV_ARG(IShellLinkW, &_pslTarget));
  223. if (SUCCEEDED(hr))
  224. {
  225. LPITEMIDLIST pidlTarget;
  226. // Prevalidate to prevent recusion
  227. // If GetIDList fails, that's okay; I guess it doesn't point to us after all
  228. if (_pslTarget->GetIDList(&pidlTarget) == S_OK)
  229. {
  230. SHGetPathFromIDList(pidlTarget, szPath);
  231. // Does this point to itself?
  232. if (StrCmpI(szPath, _szFolderPath) == 0)
  233. {
  234. _pslTarget->Release();
  235. _pslTarget = NULL;
  236. hr = E_FAIL;
  237. }
  238. ILFree(pidlTarget);
  239. }
  240. }
  241. }
  242. else
  243. {
  244. hr = E_FAIL;
  245. }
  246. return hr;
  247. }
  248. // ensure that _pidlTarget is inited (requres _pslTarget)
  249. HRESULT CFolderShortcut::_GetTargetIDList(BOOL bResolve)
  250. {
  251. HRESULT hr = _LoadShortcut();
  252. if (SUCCEEDED(hr))
  253. {
  254. if (_pidlTarget)
  255. {
  256. hr = S_OK;
  257. }
  258. else
  259. {
  260. if (bResolve)
  261. _pslTarget->Resolve(NULL, SLR_UPDATE | SLR_NO_UI);
  262. hr = _pslTarget->GetIDList(&_pidlTarget);
  263. if (hr == S_FALSE)
  264. hr = E_FAIL; // convert empty to failure
  265. if (SUCCEEDED(hr))
  266. {
  267. // make sure we dont have another shortcut here
  268. IShellLink *psl;
  269. if (SUCCEEDED(SHBindToObject(NULL, IID_IShellLink, _pidlTarget, (void**)&psl)))
  270. {
  271. ILFree(_pidlTarget);
  272. hr = psl->GetIDList(&_pidlTarget);
  273. if (SUCCEEDED(hr))
  274. {
  275. hr = _pslTarget->SetIDList(_pidlTarget);
  276. }
  277. psl->Release();
  278. }
  279. }
  280. if (FAILED(hr) && _pidlTarget)
  281. {
  282. ILFree(_pidlTarget);
  283. _pidlTarget = NULL;
  284. }
  285. }
  286. }
  287. return hr;
  288. }
  289. // create _psfTarget (requires _pidlTarget)
  290. HRESULT CFolderShortcut::_BindFolder(BOOL bResolve)
  291. {
  292. ASSERT(_psfTarget == NULL);
  293. HRESULT hr = _GetTargetIDList(bResolve);
  294. if (SUCCEEDED(hr))
  295. {
  296. IBindCtx *pbc = NULL; // in/out param below
  297. hr = _PreBindCtxHelper(&pbc); // avoid loops in the name space
  298. if (SUCCEEDED(hr))
  299. {
  300. if (SUCCEEDED(hr))
  301. {
  302. IShellFolder *psfDesktop;
  303. hr = SHGetDesktopFolder(&psfDesktop);
  304. if (SUCCEEDED(hr))
  305. {
  306. // Are we trying to bind to the desktop folder?
  307. if (ILIsEmpty(_pidlTarget))
  308. {
  309. // Yes; Clone the desktop shell folder.
  310. _psfTarget = psfDesktop;
  311. _psfTarget->AddRef();
  312. hr = S_OK;
  313. }
  314. else
  315. {
  316. // No. Bind to it.
  317. hr = psfDesktop->BindToObject(_pidlTarget, pbc, IID_PPV_ARG(IShellFolder, &_psfTarget));
  318. }
  319. if (SUCCEEDED(hr))
  320. {
  321. // optionally re-target the folder (if he is a file system folder)
  322. // to separate the location in the name space (_pidlRoot)
  323. // and the folder being viewed (pfsfi.szFolderPath).
  324. IPersistFolder3 *ppf;
  325. if (SUCCEEDED(_psfTarget->QueryInterface(IID_PPV_ARG(IPersistFolder3, &ppf))))
  326. {
  327. PERSIST_FOLDER_TARGET_INFO pfti = { 0 };
  328. pfti.pidlTargetFolder = _pidlTarget;
  329. pfti.dwAttributes = _dwAttributesTarget;
  330. pfti.csidl = -1;
  331. hr = ppf->InitializeEx(pbc, _pidlRoot, &pfti);
  332. ppf->Release();
  333. }
  334. }
  335. psfDesktop->Release();
  336. }
  337. }
  338. pbc->Release();
  339. }
  340. }
  341. return hr;
  342. }
  343. // ensure that _psfTarget is inited
  344. HRESULT CFolderShortcut::_GetFolder(BOOL fForceResolve)
  345. {
  346. HRESULT hr;
  347. if (fForceResolve)
  348. {
  349. if (_fHaveResolved)
  350. {
  351. hr = _psfTarget ? S_OK : E_FAIL;
  352. }
  353. else
  354. {
  355. _fHaveResolved = TRUE; // don't do this again
  356. _ClearTargetFolder();
  357. Pidl_Set(&_pidlTarget, NULL);
  358. hr = _BindFolder(fForceResolve);
  359. }
  360. }
  361. else if (_psfTarget)
  362. {
  363. hr = S_OK;
  364. }
  365. else
  366. {
  367. hr = _BindFolder(fForceResolve);
  368. }
  369. return hr;
  370. }
  371. // ensure that _psf2Target is inited
  372. HRESULT CFolderShortcut::_GetFolder2()
  373. {
  374. if (_psf2Target)
  375. return S_OK;
  376. HRESULT hr = _GetFolder(FALSE);
  377. if (SUCCEEDED(hr))
  378. hr = _psfTarget->QueryInterface(IID_PPV_ARG(IShellFolder2, &_psf2Target));
  379. return hr;
  380. }
  381. STDMETHODIMP CFolderShortcut::QueryInterface(REFIID riid, void **ppvObj)
  382. {
  383. static const QITAB qit[] = {
  384. QITABENTMULTI(CFolderShortcut, IShellFolder, IShellFolder2),
  385. QITABENT(CFolderShortcut, IShellFolder2),
  386. QITABENTMULTI(CFolderShortcut, IPersist, IPersistFolder3),
  387. QITABENTMULTI(CFolderShortcut, IPersistFolder, IPersistFolder3),
  388. QITABENTMULTI(CFolderShortcut, IPersistFolder2, IPersistFolder3),
  389. QITABENT(CFolderShortcut, IPersistFolder3),
  390. QITABENT(CFolderShortcut, IPersistStreamInit),
  391. QITABENTMULTI(CFolderShortcut, IPersistStream, IPersistStreamInit),
  392. QITABENT(CFolderShortcut, IShellLinkA),
  393. QITABENT(CFolderShortcut, IShellLinkW),
  394. QITABENT(CFolderShortcut, IPersistFile),
  395. QITABENT(CFolderShortcut, IFolderShortcutConvert),
  396. QITABENT(CFolderShortcut, IExtractIcon),
  397. QITABENT(CFolderShortcut, IQueryInfo),
  398. QITABENT(CFolderShortcut, IPersistPropertyBag),
  399. QITABENT(CFolderShortcut, IBrowserFrameOptions),
  400. { 0 },
  401. };
  402. return QISearch(this, qit, riid, ppvObj);
  403. }
  404. STDMETHODIMP_(ULONG) CFolderShortcut::AddRef()
  405. {
  406. return InterlockedIncrement(&_cRef);
  407. }
  408. STDMETHODIMP_(ULONG) CFolderShortcut::Release()
  409. {
  410. if (InterlockedDecrement(&_cRef))
  411. return _cRef;
  412. delete this;
  413. return 0;
  414. }
  415. // either create or init the passed bind ctx with the params to avoid loops in the name space
  416. HRESULT CFolderShortcut::_PreBindCtxHelper(IBindCtx **ppbc)
  417. {
  418. HRESULT hr;
  419. if (*ppbc)
  420. {
  421. (*ppbc)->AddRef();
  422. hr = S_OK;
  423. }
  424. else
  425. {
  426. hr = BindCtx_CreateWithMode(STGM_READ | STGM_SHARE_DENY_WRITE, ppbc);
  427. }
  428. if (SUCCEEDED(hr))
  429. (*ppbc)->RegisterObjectParam(STR_SKIP_BINDING_CLSID, SAFECAST(this, IShellFolder2 *));
  430. return hr;
  431. }
  432. // IShellFolder methods
  433. HRESULT CFolderShortcut::ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR pwszDisplayName,
  434. ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes)
  435. {
  436. if (!ppidl)
  437. return E_INVALIDARG;
  438. *ppidl = NULL;
  439. if (!pwszDisplayName)
  440. return E_INVALIDARG;
  441. HRESULT hr = _GetFolder(FALSE);
  442. if (SUCCEEDED(hr))
  443. {
  444. hr = _PreBindCtxHelper(&pbc);
  445. if (SUCCEEDED(hr))
  446. {
  447. hr = _psfTarget->ParseDisplayName(hwnd, pbc, pwszDisplayName,
  448. pchEaten, ppidl, pdwAttributes);
  449. pbc->Release();
  450. }
  451. }
  452. return hr;
  453. }
  454. HRESULT CFolderShortcut::EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList)
  455. {
  456. HRESULT hr = _GetFolder(TRUE);
  457. if (SUCCEEDED(hr))
  458. hr = _psfTarget->EnumObjects(hwnd, grfFlags, ppenumIDList);
  459. if (SUCCEEDED(hr))
  460. SHChangeNotifyRegisterAlias(_pidlTarget, _pidlRoot);
  461. return hr;
  462. }
  463. HRESULT CFolderShortcut::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  464. {
  465. HRESULT hr = _GetFolder(TRUE);
  466. if (SUCCEEDED(hr))
  467. {
  468. hr = _PreBindCtxHelper(&pbc);
  469. if (SUCCEEDED(hr))
  470. {
  471. hr = _psfTarget->BindToObject(pidl, pbc, riid, ppv);
  472. pbc->Release();
  473. if (SUCCEEDED(hr))
  474. SHChangeNotifyRegisterAlias(_pidlTarget, _pidlRoot);
  475. }
  476. }
  477. return hr;
  478. }
  479. HRESULT CFolderShortcut::BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  480. {
  481. return BindToObject(pidl, pbc, riid, ppv);
  482. }
  483. HRESULT CFolderShortcut::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  484. {
  485. HRESULT hr = _GetFolder(FALSE);
  486. if (SUCCEEDED(hr))
  487. hr = _psfTarget->CompareIDs(lParam, pidl1, pidl2);
  488. return hr;
  489. }
  490. HRESULT CFolderShortcut::CreateViewObject(HWND hwnd, REFIID riid, void **ppv)
  491. {
  492. HRESULT hr = _GetFolder(TRUE);
  493. if ( SUCCEEDED(hr) )
  494. hr = _psfTarget->CreateViewObject(hwnd, riid, ppv);
  495. if ( SUCCEEDED(hr) && (IsEqualIID(riid, IID_IShellView) || IsEqualIID(riid, IID_IShellView2)) )
  496. SHChangeNotifyRegisterAlias(_pidlTarget, _pidlRoot);
  497. return hr;
  498. }
  499. HRESULT CFolderShortcut::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, ULONG *rgfInOut)
  500. {
  501. if (IsSelf (cidl, apidl))
  502. {
  503. // since our folder is marked "CallForAttributes" we get to report
  504. // our attributes at runtime instead of the normal way via the registry
  505. if (SHGetAppCompatFlags (ACF_STRIPFOLDERBIT) & ACF_STRIPFOLDERBIT)
  506. {
  507. *rgfInOut = SFGAO_LINK | SFGAO_CAPABILITYMASK | SFGAO_FILESYSTEM;
  508. }
  509. else
  510. {
  511. *rgfInOut = SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_STORAGE |
  512. SFGAO_LINK | SFGAO_DROPTARGET | SFGAO_CANRENAME | SFGAO_CANDELETE |
  513. SFGAO_CANLINK | SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_HASSUBFOLDER;
  514. }
  515. return S_OK;
  516. }
  517. HRESULT hr = _GetFolder(FALSE);
  518. if (SUCCEEDED(hr))
  519. hr = _psfTarget->GetAttributesOf(cidl, apidl, rgfInOut);
  520. return hr;
  521. }
  522. HRESULT CFolderShortcut::GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST *apidl,
  523. REFIID riid, UINT *prgfInOut, void **ppv)
  524. {
  525. HRESULT hr = _GetFolder(FALSE);
  526. if (SUCCEEDED(hr))
  527. hr = _psfTarget->GetUIObjectOf(hwnd, cidl, apidl, riid, prgfInOut, ppv);
  528. return hr;
  529. }
  530. HRESULT CFolderShortcut::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, STRRET *pName)
  531. {
  532. HRESULT hr = _GetFolder(FALSE);
  533. if (SUCCEEDED(hr))
  534. hr = _psfTarget->GetDisplayNameOf(pidl, uFlags, pName);
  535. return hr;
  536. }
  537. HRESULT CFolderShortcut::SetNameOf(HWND hwnd, LPCITEMIDLIST pidl,
  538. LPCOLESTR pszName, DWORD uFlags,
  539. LPITEMIDLIST *ppidlOut)
  540. {
  541. HRESULT hr = _GetFolder(FALSE);
  542. if (SUCCEEDED(hr))
  543. hr = _psfTarget->SetNameOf(hwnd, pidl, pszName, uFlags, ppidlOut);
  544. return hr;
  545. }
  546. STDMETHODIMP CFolderShortcut::GetDefaultSearchGUID(LPGUID lpGuid)
  547. {
  548. HRESULT hr = _GetFolder2();
  549. if (SUCCEEDED(hr))
  550. hr = _psf2Target->GetDefaultSearchGUID(lpGuid);
  551. return hr;
  552. }
  553. STDMETHODIMP CFolderShortcut::EnumSearches(LPENUMEXTRASEARCH *ppenum)
  554. {
  555. HRESULT hr = _GetFolder2();
  556. if (SUCCEEDED(hr))
  557. hr = _psf2Target->EnumSearches(ppenum);
  558. return hr;
  559. }
  560. STDMETHODIMP CFolderShortcut::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
  561. {
  562. HRESULT hr = _GetFolder2();
  563. if (SUCCEEDED(hr))
  564. hr = _psf2Target->GetDefaultColumn(dwRes, pSort, pDisplay);
  565. return hr;
  566. }
  567. STDMETHODIMP CFolderShortcut::GetDefaultColumnState(UINT iColumn, DWORD *pbState)
  568. {
  569. HRESULT hr = _GetFolder2();
  570. if (SUCCEEDED(hr))
  571. hr = _psf2Target->GetDefaultColumnState(iColumn, pbState);
  572. return hr;
  573. }
  574. STDMETHODIMP CFolderShortcut::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
  575. {
  576. HRESULT hr = _GetFolder2();
  577. if (SUCCEEDED(hr))
  578. hr = _psf2Target->GetDetailsEx(pidl, pscid, pv);
  579. return hr;
  580. }
  581. STDMETHODIMP CFolderShortcut::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, LPSHELLDETAILS pDetail)
  582. {
  583. HRESULT hr = _GetFolder2();
  584. if (SUCCEEDED(hr))
  585. hr = _psf2Target->GetDetailsOf(pidl, iColumn, pDetail);
  586. return hr;
  587. }
  588. STDMETHODIMP CFolderShortcut::MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid)
  589. {
  590. HRESULT hr = _GetFolder2();
  591. if (SUCCEEDED(hr))
  592. hr = _psf2Target->MapColumnToSCID(iColumn, pscid);
  593. return hr;
  594. }
  595. // IPersist
  596. HRESULT CFolderShortcut::GetClassID(CLSID *pCLSID)
  597. {
  598. *pCLSID = CLSID_FolderShortcut;
  599. return S_OK;
  600. }
  601. // IPersistFolder
  602. HRESULT CFolderShortcut::Initialize(LPCITEMIDLIST pidl)
  603. {
  604. HRESULT hr;
  605. // is the link loaded (could have been loaded through IPersistStream::Load)?
  606. if (_pslTarget)
  607. {
  608. // Yes, it's loaded so re-initialize
  609. // note, _szFolderPath will be empty since we are not loaded from the file system
  610. hr = Pidl_Set(&_pidlRoot, pidl) ? S_OK : E_OUTOFMEMORY;
  611. }
  612. else
  613. {
  614. // we explictly require initialization through
  615. // IPersistFolder3::InitializeEx, if we don't do these we can
  616. // not defent against loops in the name space
  617. hr = E_FAIL;
  618. }
  619. return hr;
  620. }
  621. // IPersistFolder2
  622. STDMETHODIMP CFolderShortcut::GetCurFolder(LPITEMIDLIST *ppidl)
  623. {
  624. return GetCurFolderImpl(this->_pidlRoot, ppidl);
  625. }
  626. // IPersistFolder3
  627. STDMETHODIMP CFolderShortcut::InitializeEx(IBindCtx *pbc, LPCITEMIDLIST pidlRoot, const PERSIST_FOLDER_TARGET_INFO *pfti)
  628. {
  629. HRESULT hr = E_INVALIDARG; // assume failure
  630. if ( NULL == pbc || (pbc && !SHSkipJunction(pbc, &CLSID_FolderShortcut)) )
  631. {
  632. _ClearState();
  633. if (pidlRoot)
  634. hr = SHILClone(pidlRoot, &_pidlRoot);
  635. if (pfti && pfti->pidlTargetFolder)
  636. {
  637. if ( SUCCEEDED(hr) )
  638. hr = SHILClone(pfti->pidlTargetFolder, &_pidlTargetFldrFromInit);
  639. if ( SUCCEEDED(hr) && !_szFolderPath[0] )
  640. hr = SHGetPathFromIDList(pfti->pidlTargetFolder, _szFolderPath) ? S_OK : E_FAIL;
  641. }
  642. else
  643. {
  644. if ( SUCCEEDED(hr) && !_szFolderPath[0] )
  645. hr = SHGetPathFromIDList(_pidlRoot, _szFolderPath) ? S_OK : E_FAIL;
  646. }
  647. if ( SUCCEEDED(hr) )
  648. hr = _LoadShortcut();
  649. }
  650. return hr;
  651. }
  652. HRESULT CFolderShortcut::GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO *pfti)
  653. {
  654. HRESULT hr = S_OK;
  655. ZeroMemory(pfti, sizeof(*pfti));
  656. if ( _pidlTargetFldrFromInit )
  657. hr = SHILClone(_pidlTargetFldrFromInit, &pfti->pidlTargetFolder);
  658. pfti->dwAttributes = -1;
  659. pfti->csidl = -1;
  660. return hr;
  661. }
  662. HRESULT CFolderShortcut::_GetLink()
  663. {
  664. HRESULT hr = _LoadShortcut();
  665. if (FAILED(hr))
  666. {
  667. // get an empty one in case we are going to be asked to save
  668. hr = SHCoCreateInstance(NULL, &CLSID_ShellLink, NULL, IID_PPV_ARG(IShellLinkW, &_pslTarget));
  669. }
  670. return hr;
  671. }
  672. HRESULT CFolderShortcut::_GetLinkQI(REFIID riid, void **ppv)
  673. {
  674. HRESULT hr = _GetLink();
  675. if (SUCCEEDED(hr))
  676. hr = _pslTarget->QueryInterface(riid, ppv);
  677. return hr;
  678. }
  679. HRESULT CFolderShortcut::_GetLinkA()
  680. {
  681. return _pslTargetA ? S_OK : _GetLinkQI(IID_PPV_ARG(IShellLinkA, &_pslTargetA));
  682. }
  683. // IPersistFile
  684. STDMETHODIMP CFolderShortcut::Load(LPCOLESTR pszFileName, DWORD dwMode)
  685. {
  686. _ClearState();
  687. SHUnicodeToTChar(pszFileName, _szFolderPath, ARRAYSIZE(_szFolderPath));
  688. return _LoadShortcut();
  689. }
  690. BOOL _IsFolder(LPCITEMIDLIST pidl)
  691. {
  692. ULONG rgInfo = SFGAO_FOLDER;
  693. HRESULT hr = SHGetNameAndFlags(pidl, SHGDN_NORMAL, NULL, 0, &rgInfo);
  694. return SUCCEEDED(hr) && (rgInfo & SFGAO_FOLDER);
  695. }
  696. void PathStripTrailingDots(LPTSTR szPath)
  697. {
  698. if (szPath[0] == TEXT('\0'))
  699. return;
  700. LPTSTR psz = &szPath[lstrlen(szPath) - 1];
  701. while ((*psz == TEXT('.')) &&
  702. (psz >= szPath))
  703. {
  704. *psz-- = TEXT('\0');
  705. }
  706. }
  707. STDMETHODIMP CFolderShortcut::Save(LPCOLESTR pszFileName, BOOL fRemember)
  708. {
  709. HRESULT hr = _GetTargetIDList(FALSE);
  710. // We need to make sure the folder shortcut can be saved keeping in mind the MAX_PATH limitation
  711. // cchFSReserved is the number of characters to reserve for the largest file that will be created
  712. // in the foldershortcut directory, in this case, it is the ARRAYSIZE of "\\desktop.ini"
  713. static const int cchFSReserved = ARRAYSIZE(TEXT("\\desktop.ini"));
  714. LPITEMIDLIST pidlInternet;
  715. // Don't create a folder shortcut to the internet folder.
  716. if (SUCCEEDED(hr) && SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_INTERNET, &pidlInternet)))
  717. {
  718. if (ILIsEqual(_pidlTarget, pidlInternet))
  719. {
  720. hr = E_INVALIDARG;
  721. }
  722. ILFree(pidlInternet);
  723. }
  724. if (SUCCEEDED(hr) && _IsFolder(_pidlTarget))
  725. {
  726. // we know the target is a folder, create a folder shortcut.
  727. BOOL fCreatedDir;
  728. TCHAR szName[MAX_PATH];
  729. SHUnicodeToTChar(pszFileName, szName, ARRAYSIZE(szName));
  730. // Remove any exisiting extension.
  731. // We dont want "Shortcut To My Documents.lnk.{GUID}
  732. if (PathFindCLSIDExtension(szName,NULL))
  733. {
  734. PathRemoveExtension(szName);
  735. }
  736. PathStripTrailingDots(szName);
  737. // Can't create a fldrshcut with too long a path
  738. if ((MAX_PATH - cchFSReserved) < lstrlen(szName))
  739. {
  740. hr = CO_E_PATHTOOLONG;
  741. }
  742. if (SUCCEEDED(hr))
  743. {
  744. if (PathIsDirectory(szName))
  745. fCreatedDir = FALSE;
  746. else
  747. fCreatedDir = SHCreateDirectory(NULL, szName) == 0;
  748. CreateFolderDesktopIni(szName);
  749. // Now initialize the child link
  750. IPersistFile *ppf;
  751. hr = _pslTarget->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
  752. if (SUCCEEDED(hr))
  753. {
  754. WCHAR wszName[MAX_PATH];
  755. SHTCharToUnicode(szName, wszName, ARRAYSIZE(wszName));
  756. PathAppendW(wszName, L"target.lnk");
  757. hr = ppf->Save(wszName, fRemember);
  758. if (SUCCEEDED(hr))
  759. {
  760. if (fRemember)
  761. Str_SetPtr(&_pszLastSave, szName);
  762. }
  763. ppf->Release();
  764. }
  765. if (FAILED(hr) && fCreatedDir)
  766. {
  767. RemoveDirectory(szName); // cleanup after ourselves.
  768. }
  769. }
  770. }
  771. else
  772. {
  773. // ensure that if we save as a file we do so with the right extension
  774. WCHAR szFile[MAX_PATH];
  775. StrCpy(szFile, pszFileName);
  776. PathRenameExtension(szFile, L".lnk");
  777. // the target is not a folder, create a normal shortcut in this case
  778. IPersistFile *ppf;
  779. hr = _pslTarget->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
  780. if (SUCCEEDED(hr))
  781. {
  782. hr = ppf->Save(szFile, fRemember);
  783. ppf->Release();
  784. }
  785. }
  786. return hr;
  787. }
  788. STDMETHODIMP CFolderShortcut::GetCurFile(LPOLESTR *ppszFileName)
  789. {
  790. HRESULT hr = E_FAIL;
  791. if (_pszLastSave)
  792. hr = SHStrDup(_pszLastSave, ppszFileName);
  793. else if (_pslTarget)
  794. {
  795. IPersistFile *ppf;
  796. hr = _pslTarget->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
  797. if (SUCCEEDED(hr))
  798. {
  799. hr = ppf->GetCurFile(ppszFileName);
  800. ppf->Release();
  801. }
  802. }
  803. return hr;
  804. }
  805. // IShellLinkW
  806. STDMETHODIMP CFolderShortcut::GetPath(LPWSTR pszFile, int cchMaxPath, WIN32_FIND_DATAW *pfd, DWORD flags)
  807. {
  808. HRESULT hr = _GetLink();
  809. if (SUCCEEDED(hr))
  810. hr = _pslTarget->GetPath(pszFile, cchMaxPath, pfd, flags);
  811. return hr;
  812. }
  813. STDMETHODIMP CFolderShortcut::SetPath(LPCWSTR pwszFile)
  814. {
  815. HRESULT hr = _GetLink();
  816. if (SUCCEEDED(hr) && PathIsDirectoryW(pwszFile))
  817. {
  818. hr = _pslTarget->SetPath(pwszFile);
  819. Pidl_Set(&_pidlTarget, NULL);
  820. }
  821. return hr;
  822. }
  823. STDMETHODIMP CFolderShortcut::GetIDList(LPITEMIDLIST *ppidl)
  824. {
  825. HRESULT hr = _GetLink();
  826. if (SUCCEEDED(hr))
  827. hr = _pslTarget->GetIDList(ppidl);
  828. else
  829. *ppidl = NULL;
  830. return hr;
  831. }
  832. STDMETHODIMP CFolderShortcut::SetIDList(LPCITEMIDLIST pidl)
  833. {
  834. HRESULT hr = _GetLink();
  835. if (SUCCEEDED(hr))
  836. {
  837. hr = _pslTarget->SetIDList(pidl);
  838. Pidl_Set(&_pidlTarget, NULL);
  839. }
  840. return hr;
  841. }
  842. STDMETHODIMP CFolderShortcut::GetDescription(LPWSTR wszName, int cchMaxName)
  843. {
  844. HRESULT hr = _GetLink();
  845. if (SUCCEEDED(hr))
  846. hr = _pslTarget->GetDescription(wszName, cchMaxName);
  847. return hr;
  848. }
  849. STDMETHODIMP CFolderShortcut::SetDescription(LPCWSTR wszName)
  850. {
  851. HRESULT hr = _GetLink();
  852. if (SUCCEEDED(hr))
  853. hr = _pslTarget->SetDescription(wszName);
  854. return hr;
  855. }
  856. STDMETHODIMP CFolderShortcut::GetWorkingDirectory(LPWSTR wszDir, int cchMaxPath)
  857. {
  858. HRESULT hr = _GetLink();
  859. if (SUCCEEDED(hr))
  860. hr = _pslTarget->GetWorkingDirectory(wszDir, cchMaxPath);
  861. return hr;
  862. }
  863. STDMETHODIMP CFolderShortcut::SetWorkingDirectory(LPCWSTR wszDir)
  864. {
  865. HRESULT hr = _GetLink();
  866. if (SUCCEEDED(hr))
  867. hr = _pslTarget->SetWorkingDirectory(wszDir);
  868. return hr;
  869. }
  870. STDMETHODIMP CFolderShortcut::GetArguments(LPWSTR wszArgs, int cchMaxPath)
  871. {
  872. HRESULT hr = _GetLink();
  873. if (SUCCEEDED(hr))
  874. hr = _pslTarget->GetArguments(wszArgs, cchMaxPath);//this is probably not at all useful.
  875. return hr;
  876. }
  877. STDMETHODIMP CFolderShortcut::SetArguments(LPCWSTR wszArgs)
  878. {
  879. HRESULT hr = _GetLink();
  880. if (SUCCEEDED(hr))
  881. hr = _pslTarget->SetArguments(wszArgs);//this is probably not at all useful.
  882. return hr;
  883. }
  884. STDMETHODIMP CFolderShortcut::GetHotkey(WORD *pwHotkey)
  885. {
  886. HRESULT hr = _GetLink();
  887. if (SUCCEEDED(hr))
  888. hr = _pslTarget->GetHotkey(pwHotkey);
  889. return hr;
  890. }
  891. STDMETHODIMP CFolderShortcut::SetHotkey(WORD wHotkey)
  892. {
  893. HRESULT hr = _GetLink();
  894. if (SUCCEEDED(hr))
  895. hr = _pslTarget->SetHotkey(wHotkey);
  896. return hr;
  897. }
  898. STDMETHODIMP CFolderShortcut::GetShowCmd(int *piShowCmd)
  899. {
  900. HRESULT hr = _GetLink();
  901. if (SUCCEEDED(hr))
  902. hr = _pslTarget->GetShowCmd(piShowCmd);
  903. return hr;
  904. }
  905. STDMETHODIMP CFolderShortcut::SetShowCmd(int iShowCmd)
  906. {
  907. HRESULT hr = _GetLink();
  908. if (SUCCEEDED(hr))
  909. hr = _pslTarget->SetShowCmd(iShowCmd);
  910. return hr;
  911. }
  912. STDMETHODIMP CFolderShortcut::GetIconLocation(LPWSTR wszIconPath, int cchIconPath, int *piIcon)
  913. {
  914. HRESULT hr = _GetLink();
  915. if (SUCCEEDED(hr))
  916. hr = _pslTarget->GetIconLocation(wszIconPath, cchIconPath, piIcon);
  917. return hr;
  918. }
  919. STDMETHODIMP CFolderShortcut::SetIconLocation(LPCWSTR wszIconPath, int iIcon)
  920. {
  921. HRESULT hr = _GetLink();
  922. if (SUCCEEDED(hr))
  923. hr = _pslTarget->SetIconLocation(wszIconPath, iIcon);
  924. return hr;
  925. }
  926. STDMETHODIMP CFolderShortcut::Resolve(HWND hwnd, DWORD fFlags)
  927. {
  928. HRESULT hr = _GetLink();
  929. if (SUCCEEDED(hr))
  930. hr = _pslTarget->Resolve(hwnd, fFlags);
  931. return hr;
  932. }
  933. STDMETHODIMP CFolderShortcut::SetRelativePath(LPCWSTR wszPathRel, DWORD dwReserved)
  934. {
  935. HRESULT hr = _GetLink();
  936. if (SUCCEEDED(hr))
  937. hr = _pslTarget->SetRelativePath(wszPathRel, dwReserved);
  938. return hr;
  939. }
  940. // IShellLinkA
  941. STDMETHODIMP CFolderShortcut::GetPath(LPSTR pszFile, int cchMaxPath, WIN32_FIND_DATAA *pfd, DWORD flags)
  942. {
  943. HRESULT hr = _GetLinkA();
  944. if (SUCCEEDED(hr))
  945. hr = _pslTargetA->GetPath(pszFile, cchMaxPath, pfd, flags);
  946. return hr;
  947. }
  948. STDMETHODIMP CFolderShortcut::GetDescription(LPSTR pszName, int cchMaxName)
  949. {
  950. HRESULT hr = _GetLinkA();
  951. if (SUCCEEDED(hr))
  952. hr = _pslTargetA->GetDescription(pszName, cchMaxName);
  953. return hr;
  954. }
  955. STDMETHODIMP CFolderShortcut::GetWorkingDirectory(LPSTR pszDir, int cchMaxPath)
  956. {
  957. HRESULT hr = _GetLinkA();
  958. if (SUCCEEDED(hr))
  959. hr = _pslTargetA->GetWorkingDirectory(pszDir, cchMaxPath);
  960. return hr;
  961. }
  962. STDMETHODIMP CFolderShortcut::GetArguments(LPSTR pszArgs, int cchMaxPath)
  963. {
  964. HRESULT hr = _GetLinkA();
  965. if (SUCCEEDED(hr))
  966. hr = _pslTargetA->GetArguments(pszArgs, cchMaxPath);//this is probably not at all useful.
  967. return hr;
  968. }
  969. STDMETHODIMP CFolderShortcut::GetIconLocation(LPSTR pszIconPath, int cchIconPath, int *piIcon)
  970. {
  971. HRESULT hr = _GetLinkA();
  972. if (SUCCEEDED(hr))
  973. hr = _pslTargetA->GetIconLocation(pszIconPath, cchIconPath, piIcon);
  974. return hr;
  975. }
  976. STDMETHODIMP CFolderShortcut::SetPath(LPCSTR pszFile)
  977. {
  978. HRESULT hr = _GetLinkA();
  979. if (SUCCEEDED(hr) && PathIsDirectoryA(pszFile))
  980. {
  981. hr = _pslTargetA->SetPath(pszFile);
  982. Pidl_Set(&_pidlTarget, NULL);
  983. }
  984. return hr;
  985. }
  986. STDMETHODIMP CFolderShortcut::SetDescription(LPCSTR pszName)
  987. {
  988. HRESULT hr = _GetLinkA();
  989. if (SUCCEEDED(hr))
  990. hr = _pslTargetA->SetDescription(pszName);
  991. return hr;
  992. }
  993. STDMETHODIMP CFolderShortcut::SetWorkingDirectory(LPCSTR pszDir)
  994. {
  995. HRESULT hr = _GetLinkA();
  996. if (SUCCEEDED(hr))
  997. hr = _pslTargetA->SetWorkingDirectory(pszDir);
  998. return hr;
  999. }
  1000. STDMETHODIMP CFolderShortcut::SetArguments(LPCSTR pszArgs)
  1001. {
  1002. HRESULT hr = _GetLinkA();
  1003. if (SUCCEEDED(hr))
  1004. hr = _pslTargetA->SetArguments(pszArgs);
  1005. return hr;
  1006. }
  1007. STDMETHODIMP CFolderShortcut::SetIconLocation(LPCSTR pszIconPath, int iIcon)
  1008. {
  1009. HRESULT hr = _GetLinkA();
  1010. if (SUCCEEDED(hr))
  1011. hr = _pslTargetA->SetIconLocation(pszIconPath, iIcon);
  1012. return hr;
  1013. }
  1014. STDMETHODIMP CFolderShortcut::SetRelativePath(LPCSTR pszPathRel, DWORD dwReserved)
  1015. {
  1016. HRESULT hr = _GetLinkA();
  1017. if (SUCCEEDED(hr))
  1018. hr = _pslTargetA->SetRelativePath(pszPathRel, dwReserved);
  1019. return hr;
  1020. }
  1021. STDMETHODIMP CFolderShortcut::GetIconLocation(UINT uFlags, LPTSTR pszIconFile, UINT ucchMax, PINT pniIcon, PUINT puFlags)
  1022. {
  1023. IExtractIcon *pxi;
  1024. HRESULT hr = _GetLinkQI(IID_PPV_ARG(IExtractIcon, &pxi));
  1025. if (SUCCEEDED(hr))
  1026. {
  1027. hr = pxi->GetIconLocation(uFlags, pszIconFile, ucchMax, pniIcon, puFlags);
  1028. pxi->Release();
  1029. }
  1030. return hr;
  1031. }
  1032. STDMETHODIMP CFolderShortcut::Extract(LPCTSTR pcszFile, UINT uIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT ucIconSize)
  1033. {
  1034. IExtractIcon *pxi;
  1035. HRESULT hr = _GetLinkQI(IID_PPV_ARG(IExtractIcon, &pxi));
  1036. if (SUCCEEDED(hr))
  1037. {
  1038. hr = pxi->Extract(pcszFile, uIconIndex, phiconLarge, phiconSmall, ucIconSize);
  1039. pxi->Release();
  1040. }
  1041. return hr;
  1042. }
  1043. HRESULT CFolderShortcut::GetInfoTip(DWORD dwFlags, WCHAR** ppwszText)
  1044. {
  1045. IQueryInfo *pqi;
  1046. HRESULT hr = _GetLinkQI(IID_PPV_ARG(IQueryInfo, &pqi));
  1047. if (SUCCEEDED(hr))
  1048. {
  1049. hr = pqi->GetInfoTip(dwFlags | QITIPF_LINKUSETARGET, ppwszText);
  1050. pqi->Release();
  1051. }
  1052. return hr;
  1053. }
  1054. HRESULT CFolderShortcut::GetInfoFlags(DWORD *pdwFlags)
  1055. {
  1056. IQueryInfo *pqi;
  1057. HRESULT hr = _GetLinkQI(IID_PPV_ARG(IQueryInfo, &pqi));
  1058. if (SUCCEEDED(hr))
  1059. {
  1060. hr = pqi->GetInfoFlags(pdwFlags);
  1061. pqi->Release();
  1062. }
  1063. return hr;
  1064. }
  1065. // IBrowserFrameOptions
  1066. HRESULT CFolderShortcut::GetFrameOptions(IN BROWSERFRAMEOPTIONS dwMask, IN BROWSERFRAMEOPTIONS * pdwOptions)
  1067. {
  1068. HRESULT hr = _GetFolder(FALSE);
  1069. *pdwOptions = BFO_NONE;
  1070. if (SUCCEEDED(hr))
  1071. {
  1072. IBrowserFrameOptions *pbfo;
  1073. hr = _psfTarget->QueryInterface(IID_PPV_ARG(IBrowserFrameOptions, &pbfo));
  1074. if (SUCCEEDED(hr))
  1075. {
  1076. hr = pbfo->GetFrameOptions(dwMask, pdwOptions);
  1077. pbfo->Release();
  1078. }
  1079. }
  1080. return hr;
  1081. }
  1082. // IPersistStream
  1083. STDMETHODIMP CFolderShortcut::Load(IStream *pStm)
  1084. {
  1085. _ClearState();
  1086. IPersistStream *pps;
  1087. HRESULT hr = SHCoCreateInstance(NULL, &CLSID_ShellLink, NULL, IID_PPV_ARG(IPersistStream, &pps));
  1088. if (SUCCEEDED(hr))
  1089. {
  1090. hr = pps->Load(pStm);
  1091. if (SUCCEEDED(hr))
  1092. pps->QueryInterface(IID_PPV_ARG(IShellLinkW, &_pslTarget)); // keep this guy
  1093. pps->Release();
  1094. }
  1095. return hr;
  1096. }
  1097. // IPersistStream
  1098. STDMETHODIMP CFolderShortcut::Save(IStream *pStm, int fClearDirty)
  1099. {
  1100. return E_NOTIMPL;
  1101. }
  1102. // IPersistStream
  1103. STDMETHODIMP CFolderShortcut::GetSizeMax(ULARGE_INTEGER * pcbSize)
  1104. {
  1105. return E_NOTIMPL;
  1106. }
  1107. //
  1108. // IFolderShortcut::ConvertToLink.
  1109. //
  1110. // destructively convert a Folder Shortcut into a Shell Link.
  1111. //
  1112. // pszFolderShortcut is the path to an existing folder shortcut
  1113. // c:\Folder Shortcut.{guid} - deleted
  1114. // c:\Folder Shortcut.lnk - created
  1115. //
  1116. STDMETHODIMP CFolderShortcut::ConvertToLink(LPCOLESTR pszFolderShortcut, DWORD fFlags)
  1117. {
  1118. HRESULT hr = E_FAIL;
  1119. TCHAR szName[MAX_PATH];
  1120. SHUnicodeToTChar(pszFolderShortcut, szName, ARRAYSIZE(szName));
  1121. if (PathIsDirectory(szName) && IsFolderShortcut(szName))
  1122. {
  1123. TCHAR szLinkName[MAX_PATH];
  1124. // c:\Folder Shortcut\target.lnk
  1125. StrCpyN(szLinkName, szName, ARRAYSIZE(szLinkName));
  1126. PathAppend(szLinkName, TEXT("target.lnk"));
  1127. PathRenameExtension(szName, TEXT(".lnk"));
  1128. // FS.lnk -> FS.{guid}
  1129. CopyFile(szLinkName, szName, FALSE);
  1130. PathRemoveExtension(szName);
  1131. if (DeleteFile(szLinkName) &&
  1132. PathAppend(szName, TEXT("desktop.ini")) && DeleteFile(szName) &&
  1133. PathRemoveFileSpec(szName) && RemoveDirectory(szName))
  1134. {
  1135. hr = S_OK;
  1136. }
  1137. }
  1138. return hr;
  1139. }
  1140. //
  1141. // IFolderShortcut::ConvertToFolderShortcut.
  1142. //
  1143. // destructively convert a Shell Link (.lnk) -> Folder Shortcut (Folder.{guid}).
  1144. // pszPathLNK is the path to an existing .lnk file
  1145. // c:\Folder Shortcut.lnk - deleted
  1146. // c:\Folder Shortcut.{guid} - created
  1147. //
  1148. STDMETHODIMP CFolderShortcut::ConvertToFolderShortcut(LPCOLESTR pszPathLNK, DWORD fFlags)
  1149. {
  1150. //must bind to the link, resolve it, and make sure it points to a folder.
  1151. IShellLink *psl;
  1152. HRESULT hr = SHCoCreateInstance(NULL, &CLSID_ShellLink, NULL, IID_PPV_ARG(IShellLink, &psl));
  1153. if (SUCCEEDED(hr))
  1154. {
  1155. IPersistFile *ppf;
  1156. hr = psl->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
  1157. if (SUCCEEDED(hr))
  1158. {
  1159. hr = ppf->Load(pszPathLNK, STGM_READ);
  1160. if (SUCCEEDED(hr))
  1161. {
  1162. hr = psl->Resolve(NULL, SLR_NO_UI); // make sure the link is real
  1163. if (SUCCEEDED(hr))
  1164. {
  1165. LPITEMIDLIST pidl;
  1166. hr = psl->GetIDList(&pidl);
  1167. if (hr == S_OK)
  1168. {
  1169. // this should maybe work on the pidl so that
  1170. // it doesn't have to worry about files.
  1171. if (_IsFolder(pidl))
  1172. {
  1173. hr = E_FAIL;
  1174. TCHAR szPath[MAX_PATH], szName[MAX_PATH];
  1175. SHUnicodeToTChar(pszPathLNK, szName, ARRAYSIZE(szName));
  1176. StrCpyN(szPath, szName, ARRAYSIZE(szPath));
  1177. PathRemoveExtension(szName);
  1178. BOOL fCreatedDir = SHCreateDirectory(NULL, szName) == 0;
  1179. if (CreateFolderDesktopIni(szName) &&
  1180. PathAppend(szName, TEXT("target.lnk")))
  1181. {
  1182. //copy the link file into the new directory.
  1183. if (CopyFile(szPath, szName, FALSE))
  1184. {
  1185. if (DeleteFile(szPath)) //if all goes well, delete the old.
  1186. hr = S_OK;
  1187. }
  1188. else
  1189. {
  1190. PathRemoveFileSpec(szName);
  1191. if (fCreatedDir)
  1192. RemoveDirectory(szName);
  1193. }
  1194. }
  1195. }
  1196. else
  1197. hr = E_FAIL;
  1198. ILFree(pidl);
  1199. }
  1200. else
  1201. hr = E_FAIL;
  1202. }
  1203. }
  1204. ppf->Release();
  1205. }
  1206. psl->Release();
  1207. }
  1208. return hr;
  1209. }
  1210. // IPersistPropertyBag
  1211. STDMETHODIMP CFolderShortcut::Save(IPropertyBag* pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties)
  1212. {
  1213. return E_NOTIMPL;
  1214. }
  1215. // IPersistPropertyBag
  1216. STDMETHODIMP CFolderShortcut::Load(IPropertyBag* pPropBag, IErrorLog* pErrorLog)
  1217. {
  1218. _ClearState();
  1219. IPersistPropertyBag* pppb;
  1220. HRESULT hr = SHCoCreateInstance(NULL, &CLSID_ShellLink, NULL, IID_PPV_ARG(IPersistPropertyBag, &pppb));
  1221. if (SUCCEEDED(hr))
  1222. {
  1223. hr = pppb->Load(pPropBag, pErrorLog);
  1224. if (SUCCEEDED(hr))
  1225. {
  1226. hr = pppb->QueryInterface(IID_PPV_ARG(IShellLinkW, &_pslTarget));
  1227. DWORD dwFlags;
  1228. if (SUCCEEDED(SHPropertyBag_ReadDWORD(pPropBag, L"Attributes", &dwFlags)))
  1229. _dwAttributesTarget = dwFlags;
  1230. }
  1231. pppb->Release();
  1232. }
  1233. return hr;
  1234. }
  1235. STDMETHODIMP CFolderShortcut::InitNew(void)
  1236. {
  1237. _ClearState();
  1238. return S_OK;
  1239. }