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.

2536 lines
82 KiB

  1. #include "shellprv.h"
  2. #include "deskfldr.h"
  3. #include "fstreex.h"
  4. #include "datautil.h"
  5. #include "views.h"
  6. #include "ids.h"
  7. #include "caggunk.h"
  8. #include "shitemid.h"
  9. #include "basefvcb.h"
  10. #include "filefldr.h"
  11. #include "drives.h"
  12. #include "infotip.h"
  13. #include "prop.h"
  14. #include <idhidden.h>
  15. #include "cowsite.h"
  16. #include "unicpp\deskhtm.h"
  17. #include "sfstorage.h"
  18. #include <cfgmgr32.h> // MAX_GUID_STRING_LEN
  19. #include "defcm.h"
  20. #define EXCLUDE_COMPPROPSHEET
  21. #include "unicpp\dcomp.h"
  22. #undef EXCLUDE_COMPPROPSHEET
  23. // TODO - maybe we should add rooted folders to the AnyAlias's - ZekeL - 27-JAN-2000
  24. class CDesktopRootedStub : public IShellFolder2, public IContextMenuCB
  25. {
  26. public:
  27. // IUnknown
  28. STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { return E_UNEXPECTED;}
  29. STDMETHODIMP_(ULONG) AddRef(void) { return 3; }
  30. STDMETHODIMP_(ULONG) Release(void) { return 2; }
  31. // IShellFolder
  32. STDMETHODIMP ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR lpszDisplayName,
  33. ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes);
  34. STDMETHODIMP EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList)
  35. {return E_NOTIMPL;}
  36. STDMETHODIMP BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  37. {return ILRootedBindToObject(pidl, riid, ppv);}
  38. STDMETHODIMP BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  39. {
  40. LPCITEMIDLIST pidlChild;
  41. IShellFolder *psf;
  42. HRESULT hr = ILRootedBindToParentFolder(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild);
  43. if (SUCCEEDED(hr))
  44. {
  45. hr = psf->BindToStorage(pidlChild, pbc, riid, ppv);
  46. psf->Release();
  47. }
  48. return hr;
  49. }
  50. STDMETHODIMP CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  51. {
  52. if (ILIsEqualRoot(pidl1, pidl2))
  53. {
  54. return ILCompareRelIDs(SAFECAST(this, IShellFolder *), pidl1, pidl2, lParam);
  55. }
  56. else
  57. {
  58. UINT cb1 = ILGetSize(pidl1);
  59. UINT cb2 = ILGetSize(pidl2);
  60. short i = (short) memcmp(pidl1, pidl2, min(cb1, cb2));
  61. if (i == 0)
  62. i = cb1 - cb2;
  63. return ResultFromShort(i);
  64. }
  65. return ResultFromShort(-1);
  66. }
  67. STDMETHODIMP CreateViewObject (HWND hwnd, REFIID riid, void **ppv)
  68. {return E_NOTIMPL;}
  69. STDMETHODIMP GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl, ULONG *rgfInOut)
  70. {
  71. HRESULT hr = E_INVALIDARG;
  72. if (cidl == 1)
  73. {
  74. LPCITEMIDLIST pidlChild;
  75. IShellFolder *psf;
  76. hr = ILRootedBindToParentFolder(apidl[0], IID_PPV_ARG(IShellFolder, &psf), &pidlChild);
  77. if (SUCCEEDED(hr))
  78. {
  79. hr = psf->GetAttributesOf(1, &pidlChild, rgfInOut);
  80. psf->Release();
  81. }
  82. }
  83. return hr;
  84. }
  85. STDMETHODIMP GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST * apidl,
  86. REFIID riid, UINT * prgfInOut, void **ppv);
  87. STDMETHODIMP GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName)
  88. {
  89. LPCITEMIDLIST pidlChild;
  90. IShellFolder *psf;
  91. HRESULT hr = ILRootedBindToParentFolder(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild);
  92. if (SUCCEEDED(hr))
  93. {
  94. hr = psf->GetDisplayNameOf(pidlChild, uFlags, lpName);
  95. psf->Release();
  96. }
  97. return hr;
  98. }
  99. STDMETHODIMP SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD uFlags,
  100. LPITEMIDLIST * ppidlOut)
  101. {return E_NOTIMPL;}
  102. // IShellFolder2 methods
  103. STDMETHODIMP GetDefaultSearchGUID(LPGUID lpGuid)
  104. {return E_NOTIMPL;}
  105. STDMETHODIMP EnumSearches(LPENUMEXTRASEARCH *ppenum)
  106. {return E_NOTIMPL;}
  107. STDMETHODIMP GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
  108. {return E_NOTIMPL;}
  109. STDMETHODIMP GetDefaultColumnState(UINT iColumn, DWORD *pbState)
  110. {return E_NOTIMPL;}
  111. STDMETHODIMP GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
  112. {
  113. LPCITEMIDLIST pidlChild;
  114. IShellFolder2 *psf;
  115. HRESULT hr = ILRootedBindToParentFolder(pidl, IID_PPV_ARG(IShellFolder2, &psf), &pidlChild);
  116. if (SUCCEEDED(hr))
  117. {
  118. hr = psf->GetDetailsEx(pidlChild, pscid, pv);
  119. psf->Release();
  120. }
  121. return hr;
  122. }
  123. STDMETHODIMP GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pDetails)
  124. {
  125. LPCITEMIDLIST pidlChild;
  126. IShellFolder2 *psf;
  127. HRESULT hr = ILRootedBindToParentFolder(pidl, IID_PPV_ARG(IShellFolder2, &psf), &pidlChild);
  128. if (SUCCEEDED(hr))
  129. {
  130. hr = psf->GetDetailsOf(pidlChild, iColumn, pDetails);
  131. psf->Release();
  132. }
  133. return hr;
  134. }
  135. STDMETHODIMP MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid)
  136. {return E_NOTIMPL;}
  137. // IContextMenuCB
  138. STDMETHODIMP CallBack(IShellFolder *psf, HWND hwnd, IDataObject *pdtobj,
  139. UINT uMsg, WPARAM wParam, LPARAM lParam)
  140. {return (uMsg == DFM_MERGECONTEXTMENU) ? S_OK : E_NOTIMPL;}
  141. };
  142. class CShellUrlStub : public IShellFolder
  143. {
  144. public:
  145. // IUnknown
  146. STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { return E_UNEXPECTED;}
  147. STDMETHODIMP_(ULONG) AddRef(void) { return 3; }
  148. STDMETHODIMP_(ULONG) Release(void) { return 2; }
  149. // IShellFolder
  150. STDMETHODIMP ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR lpszDisplayName,
  151. ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes);
  152. STDMETHODIMP EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList)
  153. {return E_NOTIMPL;}
  154. STDMETHODIMP BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  155. {return E_NOTIMPL;}
  156. STDMETHODIMP BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  157. {return E_NOTIMPL;}
  158. STDMETHODIMP CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  159. {return E_NOTIMPL;}
  160. STDMETHODIMP CreateViewObject (HWND hwnd, REFIID riid, void **ppv)
  161. {return E_NOTIMPL;}
  162. STDMETHODIMP GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl, ULONG *rgfInOut)
  163. {return E_NOTIMPL;}
  164. STDMETHODIMP GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST * apidl,
  165. REFIID riid, UINT * prgfInOut, void **ppv)
  166. {return E_NOTIMPL;}
  167. STDMETHODIMP GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName)
  168. {return E_NOTIMPL;}
  169. STDMETHODIMP SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD uFlags,
  170. LPITEMIDLIST * ppidlOut)
  171. {return E_NOTIMPL;}
  172. };
  173. class CIDListUrlStub : public IShellFolder
  174. {
  175. public:
  176. // IUnknown
  177. STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { return E_UNEXPECTED;}
  178. STDMETHODIMP_(ULONG) AddRef(void) { return 3; }
  179. STDMETHODIMP_(ULONG) Release(void) { return 2; }
  180. // IShellFolder
  181. STDMETHODIMP ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR lpszDisplayName,
  182. ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes);
  183. STDMETHODIMP EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList)
  184. {return E_NOTIMPL;}
  185. STDMETHODIMP BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  186. {return E_NOTIMPL;}
  187. STDMETHODIMP BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  188. {return E_NOTIMPL;}
  189. STDMETHODIMP CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  190. {return E_NOTIMPL;}
  191. STDMETHODIMP CreateViewObject (HWND hwnd, REFIID riid, void **ppv)
  192. {return E_NOTIMPL;}
  193. STDMETHODIMP GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl, ULONG *rgfInOut)
  194. {return E_NOTIMPL;}
  195. STDMETHODIMP GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST * apidl,
  196. REFIID riid, UINT * prgfInOut, void **ppv)
  197. {return E_NOTIMPL;}
  198. STDMETHODIMP GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName)
  199. {return E_NOTIMPL;}
  200. STDMETHODIMP SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD uFlags,
  201. LPITEMIDLIST * ppidlOut)
  202. {return E_NOTIMPL;}
  203. };
  204. class CFileUrlStub : public IShellFolder
  205. {
  206. public:
  207. // IUnknown
  208. STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { return E_UNEXPECTED;}
  209. STDMETHODIMP_(ULONG) AddRef(void) { return 3; }
  210. STDMETHODIMP_(ULONG) Release(void) { return 2; }
  211. // IShellFolder
  212. STDMETHODIMP ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR lpszDisplayName,
  213. ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes);
  214. STDMETHODIMP EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList)
  215. {return E_NOTIMPL;}
  216. STDMETHODIMP BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  217. {return E_NOTIMPL;}
  218. STDMETHODIMP BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  219. {return E_NOTIMPL;}
  220. STDMETHODIMP CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  221. {return E_NOTIMPL;}
  222. STDMETHODIMP CreateViewObject (HWND hwnd, REFIID riid, void **ppv)
  223. {return E_NOTIMPL;}
  224. STDMETHODIMP GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl, ULONG *rgfInOut)
  225. {return E_NOTIMPL;}
  226. STDMETHODIMP GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST * apidl,
  227. REFIID riid, UINT * prgfInOut, void **ppv)
  228. {return E_NOTIMPL;}
  229. STDMETHODIMP GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName)
  230. {return E_NOTIMPL;}
  231. STDMETHODIMP SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD uFlags,
  232. LPITEMIDLIST * ppidlOut)
  233. {return E_NOTIMPL;}
  234. };
  235. class CHttpUrlStub : public IShellFolder
  236. {
  237. public:
  238. // IUnknown
  239. STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { return E_UNEXPECTED;}
  240. STDMETHODIMP_(ULONG) AddRef(void) { return 3; }
  241. STDMETHODIMP_(ULONG) Release(void) { return 2; }
  242. // IShellFolder
  243. STDMETHODIMP ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR lpszDisplayName,
  244. ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes);
  245. STDMETHODIMP EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList)
  246. {return E_NOTIMPL;}
  247. STDMETHODIMP BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  248. {return E_NOTIMPL;}
  249. STDMETHODIMP BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  250. {return E_NOTIMPL;}
  251. STDMETHODIMP CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  252. {return E_NOTIMPL;}
  253. STDMETHODIMP CreateViewObject (HWND hwnd, REFIID riid, void **ppv)
  254. {return E_NOTIMPL;}
  255. STDMETHODIMP GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl, ULONG *rgfInOut)
  256. {return E_NOTIMPL;}
  257. STDMETHODIMP GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST * apidl,
  258. REFIID riid, UINT * prgfInOut, void **ppv)
  259. {return E_NOTIMPL;}
  260. STDMETHODIMP GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName)
  261. {return E_NOTIMPL;}
  262. STDMETHODIMP SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD uFlags,
  263. LPITEMIDLIST * ppidlOut)
  264. {return E_NOTIMPL;}
  265. };
  266. class CDesktopFolderEnum;
  267. class CDesktopViewCallBack;
  268. class CDesktopFolderDropTarget;
  269. class CDesktopFolder : CObjectWithSite
  270. , CSFStorage
  271. , public IPersistFolder2
  272. , public IShellIcon
  273. , public IShellIconOverlay
  274. , public IContextMenuCB
  275. , public ITranslateShellChangeNotify
  276. , public IItemNameLimits
  277. , public IOleCommandTarget
  278. {
  279. public:
  280. // IUnknown
  281. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  282. STDMETHODIMP_(ULONG) AddRef(void) { return 3; };
  283. STDMETHODIMP_(ULONG) Release(void) { return 2; };
  284. // IShellFolder
  285. STDMETHODIMP ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR lpszDisplayName,
  286. ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes);
  287. STDMETHODIMP EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList);
  288. STDMETHODIMP BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv);
  289. STDMETHODIMP BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv);
  290. STDMETHODIMP CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
  291. STDMETHODIMP CreateViewObject (HWND hwnd, REFIID riid, void **ppv);
  292. STDMETHODIMP GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl, ULONG *rgfInOut);
  293. STDMETHODIMP GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST * apidl,
  294. REFIID riid, UINT * prgfInOut, void **ppv);
  295. STDMETHODIMP GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName);
  296. STDMETHODIMP SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD uFlags,
  297. LPITEMIDLIST * ppidlOut);
  298. // IShellFolder2 methods
  299. STDMETHODIMP GetDefaultSearchGUID(LPGUID lpGuid);
  300. STDMETHODIMP EnumSearches(LPENUMEXTRASEARCH *ppenum);
  301. STDMETHODIMP GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay);
  302. STDMETHODIMP GetDefaultColumnState(UINT iColumn, DWORD *pbState);
  303. STDMETHODIMP GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv);
  304. STDMETHODIMP GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pDetails);
  305. STDMETHODIMP MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid);
  306. // IPersist
  307. STDMETHODIMP GetClassID(LPCLSID lpClassID);
  308. // IPersistFolder
  309. STDMETHODIMP Initialize(LPCITEMIDLIST pidl);
  310. // IPersistFolder2
  311. STDMETHODIMP GetCurFolder(LPITEMIDLIST *ppidl);
  312. // IShellIcon methods
  313. STDMETHODIMP GetIconOf(LPCITEMIDLIST pidl, UINT flags, int *piIndex);
  314. // IShellIconOverlay methods
  315. STDMETHODIMP GetOverlayIndex(LPCITEMIDLIST pidl, int * pIndex);
  316. STDMETHODIMP GetOverlayIconIndex(LPCITEMIDLIST pidl, int * pIndex);
  317. // IContextMenuCB
  318. STDMETHODIMP CallBack(IShellFolder *psf, HWND hwnd, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam);
  319. // ITranslateShellChangeNotify
  320. STDMETHODIMP TranslateIDs(LONG *plEvent,
  321. LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2,
  322. LPITEMIDLIST * ppidlOut1, LPITEMIDLIST * ppidlOut2,
  323. LONG *plEvent2, LPITEMIDLIST *ppidlOut1Event2,
  324. LPITEMIDLIST *ppidlOut2Event2);
  325. STDMETHODIMP IsChildID(LPCITEMIDLIST pidlKid, BOOL fImmediate) { return E_NOTIMPL; }
  326. STDMETHODIMP IsEqualID(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) { return E_NOTIMPL; }
  327. STDMETHODIMP Register(HWND hwnd, UINT uMsg, long lEvents) { return E_NOTIMPL; }
  328. STDMETHODIMP Unregister() { return E_NOTIMPL; }
  329. // IItemNameLimits
  330. STDMETHODIMP GetValidCharacters(LPWSTR *ppwszValidChars, LPWSTR *ppwszInvalidChars);
  331. STDMETHODIMP GetMaxLength(LPCWSTR pszName, int *piMaxNameLen);
  332. // IOleCommandTarget
  333. STDMETHODIMP QueryStatus(const GUID *pguidCmdGroup,
  334. ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext);
  335. STDMETHODIMP Exec(const GUID *pguidCmdGroup,
  336. DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut);
  337. CDesktopFolder(IUnknown *punkOuter);
  338. HRESULT _Init();
  339. HRESULT _Init2();
  340. void _Destroy();
  341. private:
  342. ~CDesktopFolder();
  343. friend CDesktopFolderEnum;
  344. friend CDesktopViewCallBack;
  345. // IStorage virtuals
  346. STDMETHOD(_DeleteItemByIDList)(LPCITEMIDLIST pidl);
  347. STDMETHOD(_StgCreate)(LPCITEMIDLIST pidl, DWORD grfMode, REFIID riid, void **ppv);
  348. HRESULT _BGCommand(HWND hwnd, WPARAM wparam, BOOL bExecute);
  349. IShellFolder2 *_GetItemFolder(LPCITEMIDLIST pidl);
  350. HRESULT _GetItemUIObject(HWND hwnd, UINT cidl, LPCITEMIDLIST *apidl, REFIID riid, UINT *prgfInOut, void **ppv);
  351. HRESULT _QueryInterfaceItem(LPCITEMIDLIST pidl, REFIID riid, void **ppv);
  352. HRESULT _ChildParseDisplayName(IShellFolder *psfRight, LPCITEMIDLIST pidlLeft, HWND hwnd, IBindCtx *pbc,
  353. LPWSTR pwzDisplayName, ULONG *pchEaten, LPITEMIDLIST *ppidl, DWORD *pdwAttributes);
  354. BOOL _TryUrlJunctions(LPCTSTR pszName, IBindCtx *pbc, IShellFolder **ppsf, LPITEMIDLIST *ppidlLeft);
  355. BOOL _GetFolderForParsing(LPCTSTR pszName, LPBC pbc, IShellFolder **ppsf, LPITEMIDLIST *ppidlLeft);
  356. HRESULT _SelfAssocCreate(REFIID riid, void **ppv);
  357. HRESULT _SelfCreateContextMenu(HWND hwnd, void **ppv);
  358. IShellFolder2 *_psfDesktop; // "Desktop" shell folder (real files live here)
  359. IShellFolder2 *_psfAltDesktop; // "Common Desktop" shell folder
  360. IUnknown *_punkReg; // regitem inner folder (agregate)
  361. CDesktopRootedStub _sfRooted; // rooted folder stub object
  362. CShellUrlStub _sfShellUrl; // handles parsing shell: Urls
  363. CIDListUrlStub _sfIDListUrl; // handles parsing ms-shell-idlist: Urls
  364. CFileUrlStub _sfFileUrl; // handles parsing file: Urls
  365. CHttpUrlStub _sfHttpUrl; // handles parsing http: and https: Urls
  366. };
  367. class CDesktopFolderEnum : public IEnumIDList
  368. {
  369. public:
  370. // IUnknown
  371. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  372. STDMETHODIMP_(ULONG) AddRef(void);
  373. STDMETHODIMP_(ULONG) Release(void);
  374. // IEnumIDList
  375. STDMETHOD(Next)(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched);
  376. STDMETHOD(Skip)(ULONG celt);
  377. STDMETHOD(Reset)();
  378. STDMETHOD(Clone)(IEnumIDList **ppenum);
  379. CDesktopFolderEnum(CDesktopFolder *pdf, HWND hwnd, DWORD grfFlags);
  380. private:
  381. ~CDesktopFolderEnum();
  382. LONG _cRef;
  383. BOOL _bUseAltEnum;
  384. IEnumIDList *_penumFolder;
  385. IEnumIDList *_penumAltFolder;
  386. };
  387. class CDesktopViewCallBack : public CBaseShellFolderViewCB, public IFolderFilter
  388. {
  389. public:
  390. // IUnknown
  391. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  392. STDMETHODIMP_(ULONG) AddRef(void) { return CBaseShellFolderViewCB::AddRef(); };
  393. STDMETHODIMP_(ULONG) Release(void) { return CBaseShellFolderViewCB::Release(); };
  394. // IFolderFilter
  395. STDMETHODIMP ShouldShow(IShellFolder* psf, LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlItem);
  396. STDMETHODIMP GetEnumFlags(IShellFolder* psf, LPCITEMIDLIST pidlFolder, HWND *phwnd, DWORD *pgrfFlags);
  397. STDMETHODIMP RealMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
  398. private:
  399. CDesktopViewCallBack(CDesktopFolder* pdf);
  400. friend HRESULT Create_CDesktopViewCallback(CDesktopFolder* pdf, IShellFolderViewCB** ppv);
  401. HRESULT OnSupportsIdentity(DWORD pv);
  402. HRESULT OnGETCCHMAX(DWORD pv, LPCITEMIDLIST pidlItem, UINT *lP);
  403. HRESULT OnGetWebViewTemplate(DWORD pv, UINT uViewMode, SFVM_WEBVIEW_TEMPLATE_DATA* pvit);
  404. HRESULT OnGetWorkingDir(DWORD pv, UINT wP, LPTSTR pszDir);
  405. HRESULT OnGetWebViewLayout(DWORD pv, UINT uViewMode, SFVM_WEBVIEW_LAYOUT_DATA* pData);
  406. CDesktopFolder* _pdf;
  407. BOOL _fCheckedIfRealDesktop;
  408. BOOL _fRealDesktop;
  409. };
  410. HRESULT Create_CDesktopViewCallback(CDesktopFolder* pdf, IShellFolderViewCB** ppv);
  411. class CDesktopFolderDropTarget : public IDropTarget, CObjectWithSite
  412. {
  413. public:
  414. // IUnknown
  415. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  416. STDMETHODIMP_(ULONG) AddRef(void);
  417. STDMETHODIMP_(ULONG) Release(void);
  418. // IDropTarget
  419. STDMETHODIMP DragEnter(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect);
  420. STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect);
  421. STDMETHODIMP Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect);
  422. STDMETHODIMP DragLeave(void);
  423. // IObjectWithSite
  424. STDMETHODIMP SetSite(IUnknown* punkSite);
  425. CDesktopFolderDropTarget(IDropTarget* pdt);
  426. private:
  427. ~CDesktopFolderDropTarget();
  428. STDMETHODIMP_(BOOL) _IsSpecialCaseDrop(IDataObject* pDataObject, DWORD grfKeyState, BOOL* pfIsPIDA, UINT* pcItems);
  429. STDMETHODIMP _ShowIEIcon();
  430. IDropTarget* _pdt;
  431. LONG _cRef;
  432. };
  433. // some fields are modified so this can't be const
  434. REQREGITEM g_asDesktopReqItems[] =
  435. {
  436. {
  437. &CLSID_MyComputer, IDS_DRIVEROOT,
  438. TEXT("explorer.exe"), 0, SORT_ORDER_DRIVES,
  439. SFGAO_HASSUBFOLDER | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR | SFGAO_DROPTARGET | SFGAO_FOLDER | SFGAO_CANRENAME | SFGAO_CANDELETE,
  440. TEXT("SYSDM.CPL")
  441. },
  442. {
  443. &CLSID_NetworkPlaces, IDS_NETWORKROOT,
  444. TEXT("shell32.dll"), -IDI_MYNETWORK, SORT_ORDER_NETWORK,
  445. SFGAO_HASSUBFOLDER | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR | SFGAO_DROPTARGET | SFGAO_FOLDER | SFGAO_CANRENAME | SFGAO_CANDELETE,
  446. TEXT("NCPA.CPL"),
  447. },
  448. {
  449. &CLSID_Internet, IDS_INETROOT,
  450. TEXT("mshtml.dll"), 0, SORT_ORDER_INETROOT,
  451. SFGAO_BROWSABLE | SFGAO_HASPROPSHEET | SFGAO_CANRENAME,
  452. TEXT("INETCPL.CPL")
  453. },
  454. };
  455. const ITEMIDLIST c_idlDesktop = { { 0, 0 } };
  456. #define DESKTOP_PIDL ((LPITEMIDLIST)&c_idlDesktop)
  457. // single global instance of this CDesktopFolder object
  458. CDesktopFolder *g_pDesktopFolder = NULL;
  459. REGITEMSINFO g_riiDesktop =
  460. {
  461. REGSTR_PATH_EXPLORER TEXT("\\Desktop\\NameSpace"),
  462. NULL,
  463. TEXT(':'),
  464. SHID_ROOT_REGITEM,
  465. 1,
  466. SFGAO_CANLINK,
  467. ARRAYSIZE(g_asDesktopReqItems),
  468. g_asDesktopReqItems,
  469. RIISA_ORIGINAL,
  470. NULL,
  471. 0,
  472. 0,
  473. };
  474. void Desktop_InitRequiredItems(void)
  475. {
  476. // "NoNetHood" restriction -> always hide the hood.
  477. // Otherwise, show the hood if either MPR says so or we have RNA.
  478. if (SHRestricted(REST_NONETHOOD))
  479. {
  480. // Don't enumerate the "Net Hood" thing.
  481. g_asDesktopReqItems[CDESKTOP_REGITEM_NETWORK].dwAttributes |= SFGAO_NONENUMERATED;
  482. }
  483. else
  484. {
  485. // Do enumerate the "My Network" thing.
  486. g_asDesktopReqItems[CDESKTOP_REGITEM_NETWORK].dwAttributes &= ~SFGAO_NONENUMERATED;
  487. }
  488. // "MyComp_NoProp" restriction -> hide Properties context menu entry on My Computer
  489. if (SHRestricted(REST_MYCOMPNOPROP))
  490. {
  491. g_asDesktopReqItems[CDESKTOP_REGITEM_DRIVES].dwAttributes &= ~SFGAO_HASPROPSHEET;
  492. }
  493. //
  494. // "NoInternetIcon" restriction or AppCompat -> hide The Internet on the desktop
  495. //
  496. // Word Perfect 7 faults when it enumerates the Internet item
  497. // in their background thread. For now App hack specific to this app
  498. // later may need to extend... Note: This app does not install on
  499. // NT so only do for W95...
  500. // it repros with Word Perfect Suite 8, too, this time on both NT and 95
  501. // so removing the #ifndef... -- reljai 11/20/97, bug#842 in ie5 db
  502. //
  503. // we used to remove the SFGAO_BROWSABLE flag for both of these cases - ZekeL - 19-Dec-2000
  504. // but ShellExec() needs SFGAO_BROWSABLE so that parsing URLs succeeds
  505. // if it turns out that we need to exclude the BROWSABLE, then we should
  506. // change regfldr to look at a value like "WantsToParseDisplayName" under
  507. // the CLSID. or we could add routing code in deskfldr (like we have for
  508. // MyComputer and NetHood) to pass it to the internet folder directly
  509. //
  510. if (SHRestricted(REST_NOINTERNETICON) || (SHGetAppCompatFlags(ACF_CORELINTERNETENUM) & ACF_CORELINTERNETENUM))
  511. {
  512. // g_asDesktopReqItems[CDESKTOP_REGITEM_INTERNET].dwAttributes &= ~(SFGAO_BROWSABLE);
  513. g_asDesktopReqItems[CDESKTOP_REGITEM_INTERNET].dwAttributes |= SFGAO_NONENUMERATED;
  514. }
  515. }
  516. CDesktopFolder::CDesktopFolder(IUnknown *punkOuter)
  517. {
  518. DllAddRef();
  519. }
  520. CDesktopFolder::~CDesktopFolder()
  521. {
  522. DllRelease();
  523. }
  524. // first phase of init (does not need to be seralized)
  525. HRESULT CDesktopFolder::_Init()
  526. {
  527. Desktop_InitRequiredItems();
  528. return CRegFolder_CreateInstance(&g_riiDesktop, SAFECAST(this, IShellFolder2 *), IID_PPV_ARG(IUnknown, &_punkReg));
  529. }
  530. // second phase of init (needs to be seralized)
  531. HRESULT CDesktopFolder::_Init2()
  532. {
  533. HRESULT hr = SHCacheTrackingFolder(DESKTOP_PIDL, CSIDL_DESKTOPDIRECTORY | CSIDL_FLAG_CREATE, &_psfDesktop);
  534. if (FAILED(hr))
  535. {
  536. DebugMsg(DM_TRACE, TEXT("Failed to create desktop IShellFolder!"));
  537. return hr;
  538. }
  539. if (!SHRestricted(REST_NOCOMMONGROUPS))
  540. {
  541. hr = SHCacheTrackingFolder(DESKTOP_PIDL, CSIDL_COMMON_DESKTOPDIRECTORY, &_psfAltDesktop);
  542. }
  543. return hr;
  544. }
  545. // CLSID_ShellDesktop constructor
  546. STDAPI CDesktop_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  547. {
  548. HRESULT hr;
  549. if (g_pDesktopFolder)
  550. {
  551. hr = g_pDesktopFolder->QueryInterface(riid, ppv);
  552. }
  553. else
  554. {
  555. *ppv = NULL;
  556. // WARNING: the order of init of the desktop folder state is very important.
  557. // the creation of the sub folders, in particular _psfAltDesktop will
  558. // recurse on this function. we protect ourself from that here. the creation
  559. // of that also requires the above members to be inited.
  560. CDesktopFolder *pdf = new CDesktopFolder(punkOuter);
  561. if (pdf)
  562. {
  563. hr = pdf->_Init();
  564. if (SUCCEEDED(hr))
  565. {
  566. // NOTE: there is a race condition here where we have stored g_pDesktopFolder but
  567. // not initialized _psfDesktop & _psfAltDesktop. the main line code deals with
  568. // this by testing for NULL on these members.
  569. if (SHInterlockedCompareExchange((void **)&g_pDesktopFolder, pdf, 0))
  570. {
  571. // Someone else beat us to creating the object.
  572. // get rid of our copy, global already set (the race case)
  573. pdf->_Destroy();
  574. }
  575. else
  576. {
  577. g_pDesktopFolder->_Init2();
  578. }
  579. hr = g_pDesktopFolder->QueryInterface(riid, ppv);
  580. }
  581. else
  582. pdf->_Destroy();
  583. }
  584. else
  585. hr = E_OUTOFMEMORY;
  586. }
  587. return hr;
  588. }
  589. STDAPI SHGetDesktopFolder(IShellFolder **ppshf)
  590. {
  591. return CDesktop_CreateInstance(NULL, IID_PPV_ARG(IShellFolder, ppshf));
  592. }
  593. IShellFolder2 *CDesktopFolder::_GetItemFolder(LPCITEMIDLIST pidl)
  594. {
  595. IShellFolder2 *psf = NULL;
  596. if (ILIsRooted(pidl))
  597. psf = SAFECAST(&_sfRooted, IShellFolder2 *);
  598. else if (_psfAltDesktop && CFSFolder_IsCommonItem(pidl))
  599. psf = _psfAltDesktop;
  600. else
  601. psf = _psfDesktop;
  602. return psf;
  603. }
  604. HRESULT CDesktopFolder::_QueryInterfaceItem(LPCITEMIDLIST pidl, REFIID riid, void **ppv)
  605. {
  606. HRESULT hr;
  607. IShellFolder2 *psf = _GetItemFolder(pidl);
  608. if (psf)
  609. hr = psf->QueryInterface(riid, ppv);
  610. else
  611. {
  612. *ppv = NULL;
  613. hr = E_NOINTERFACE;
  614. }
  615. return hr;
  616. }
  617. STDAPI_(BOOL) RegGetsFirstShot(REFIID riid)
  618. {
  619. return (IsEqualIID(riid, IID_IShellFolder) ||
  620. IsEqualIID(riid, IID_IShellFolder2) ||
  621. IsEqualIID(riid, IID_IShellIconOverlay));
  622. }
  623. HRESULT CDesktopFolder::QueryInterface(REFIID riid, void **ppv)
  624. {
  625. static const QITAB qit[] = {
  626. QITABENT(CDesktopFolder, IShellFolder2),
  627. QITABENTMULTI(CDesktopFolder, IShellFolder, IShellFolder2),
  628. QITABENT(CDesktopFolder, IShellIcon),
  629. QITABENT(CDesktopFolder, IPersistFolder2),
  630. QITABENTMULTI(CDesktopFolder, IPersistFolder, IPersistFolder2),
  631. QITABENTMULTI(CDesktopFolder, IPersist, IPersistFolder2),
  632. QITABENT(CDesktopFolder, IShellIconOverlay),
  633. QITABENT(CDesktopFolder, IStorage),
  634. QITABENT(CDesktopFolder, IContextMenuCB),
  635. QITABENT(CDesktopFolder, IObjectWithSite),
  636. QITABENT(CDesktopFolder, ITranslateShellChangeNotify),
  637. QITABENT(CDesktopFolder, IItemNameLimits),
  638. QITABENT(CDesktopFolder, IOleCommandTarget),
  639. { 0 },
  640. };
  641. if (IsEqualIID(riid, CLSID_ShellDesktop))
  642. {
  643. *ppv = this; // class pointer (unrefed!)
  644. return S_OK;
  645. }
  646. HRESULT hr;
  647. if (_punkReg && RegGetsFirstShot(riid))
  648. {
  649. hr = _punkReg->QueryInterface(riid, ppv);
  650. }
  651. else
  652. {
  653. hr = QISearch(this, qit, riid, ppv);
  654. if ((E_NOINTERFACE == hr) && _punkReg)
  655. {
  656. hr = _punkReg->QueryInterface(riid, ppv);
  657. }
  658. }
  659. return hr;
  660. }
  661. // During shell32.dll process detach, we will call here to do the final
  662. // release of the IShellFolder ptrs which used to be left around for the
  663. // life of the process. This quiets things such as OLE's debug allocator,
  664. // which detected the leak.
  665. void CDesktopFolder::_Destroy()
  666. {
  667. ATOMICRELEASE(_psfDesktop);
  668. ATOMICRELEASE(_psfAltDesktop);
  669. SHReleaseInnerInterface(SAFECAST(this, IShellFolder *), &_punkReg);
  670. delete this;
  671. }
  672. LPITEMIDLIST CreateMyComputerIDList()
  673. {
  674. return ILCreateFromPath(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}")); // CLSID_MyComputer
  675. }
  676. LPITEMIDLIST CreateWebFoldersIDList()
  677. {
  678. return ILCreateFromPath(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{BDEADF00-C265-11D0-BCED-00A0C90AB50F}")); // CLSID_MyComputer\CLSID_WebFolders
  679. }
  680. LPITEMIDLIST CreateMyNetPlacesIDList()
  681. {
  682. return ILCreateFromPath(TEXT("::{208D2C60-3AEA-1069-A2D7-08002B30309D}")); // CLSID_NetworkPlaces
  683. }
  684. HRESULT CDesktopFolder::_ChildParseDisplayName(IShellFolder *psfRight, LPCITEMIDLIST pidlLeft, HWND hwnd, IBindCtx *pbc,
  685. LPWSTR pwzDisplayName, ULONG *pchEaten, LPITEMIDLIST *ppidl, DWORD *pdwAttributes)
  686. {
  687. LPITEMIDLIST pidlRight;
  688. HRESULT hr = psfRight->ParseDisplayName(hwnd, pbc,
  689. pwzDisplayName, pchEaten, &pidlRight, pdwAttributes);
  690. if (SUCCEEDED(hr))
  691. {
  692. if (pidlLeft)
  693. {
  694. hr = SHILCombine(pidlLeft, pidlRight, ppidl);
  695. ILFree(pidlRight);
  696. }
  697. else
  698. *ppidl = pidlRight;
  699. }
  700. return hr;
  701. }
  702. STDMETHODIMP CDesktopRootedStub::GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST * apidl,
  703. REFIID riid, UINT *prgfInOut, void **ppv)
  704. {
  705. HRESULT hr = E_INVALIDARG;
  706. if (cidl == 1)
  707. {
  708. if (IsEqualIID(riid, IID_IDataObject))
  709. {
  710. hr = CIDLData_CreateFromIDArray(&c_idlDesktop, cidl, apidl, (IDataObject **)ppv);
  711. }
  712. else if (IsEqualIID(riid, IID_IContextMenu))
  713. {
  714. IQueryAssociations *pqa;
  715. if (SUCCEEDED(SHGetAssociations(apidl[0], (void **)&pqa)))
  716. {
  717. HKEY keys[5];
  718. DWORD cKeys = SHGetAssocKeys(pqa, keys, ARRAYSIZE(keys));
  719. hr = CDefFolderMenu_Create2Ex(&c_idlDesktop, hwnd,
  720. cidl, apidl, this, this,
  721. cKeys, keys, (IContextMenu **)ppv);
  722. SHRegCloseKeys(keys, cKeys);
  723. }
  724. }
  725. else
  726. {
  727. LPCITEMIDLIST pidlChild;
  728. IShellFolder *psf;
  729. hr = ILRootedBindToParentFolder(apidl[0], IID_PPV_ARG(IShellFolder, &psf), &pidlChild);
  730. if (SUCCEEDED(hr))
  731. {
  732. hr = psf->GetUIObjectOf(hwnd, 1, &pidlChild, riid, prgfInOut, ppv);
  733. psf->Release();
  734. }
  735. }
  736. }
  737. return hr;
  738. }
  739. // Check the registry for a shell root under this CLSID.
  740. BOOL GetRootFromRootClass(CLSID *pclsid, LPWSTR pszPath, int cchPath)
  741. {
  742. WCHAR szClsid[GUIDSTR_MAX];
  743. WCHAR szClass[MAX_PATH];
  744. SHStringFromGUIDW(*pclsid, szClsid, ARRAYSIZE(szClsid));
  745. wnsprintfW(szClass, ARRAYSIZE(szClass), L"CLSID\\%s\\ShellExplorerRoot", szClsid);
  746. DWORD cbPath = cchPath * sizeof(WCHAR);
  747. return SHGetValueGoodBootW(HKEY_CLASSES_ROOT, szClass, NULL, NULL, (BYTE *)pszPath, &cbPath) == ERROR_SUCCESS;
  748. }
  749. //
  750. // General form for Rooted URLs:
  751. // ms-shell-root:{clsid}?URL
  752. // {CLSID} is not required, defaults to CLSID_ShellDesktop
  753. // URL is also not required. if there is a CLSID defaults to
  754. // what is specified under "CLSID\{CLSID}\ShellExplorerRoot
  755. // or default to CSIDL_DESKTOP
  756. // but one of them at least must be specified
  757. // rooted:{clsid}?idlist
  758. //
  759. STDMETHODIMP CDesktopRootedStub::ParseDisplayName(HWND hwnd,
  760. LPBC pbc, WCHAR *pwzDisplayName, ULONG *pchEaten,
  761. LPITEMIDLIST *ppidl, ULONG *pdwAttributes)
  762. {
  763. // Need to keep the internet SF from getting a chance to parse
  764. HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
  765. PARSEDURLW pu = {0};
  766. pu.cbSize = sizeof(pu);
  767. ParseURLW(pwzDisplayName, &pu);
  768. ASSERT(pu.nScheme == URL_SCHEME_MSSHELLROOTED);
  769. LPCWSTR pszUrl = StrChrW(pu.pszSuffix, L':');
  770. if (pszUrl++)
  771. {
  772. WCHAR szField[MAX_PATH];
  773. CLSID clsid;
  774. CLSID *pclsidRoot = GUIDFromStringW(pu.pszSuffix, &clsid) ? &clsid : NULL;
  775. // path might come from the registry
  776. // if nothing was passed in.
  777. if (!*pszUrl && GetRootFromRootClass(pclsidRoot, szField, ARRAYSIZE(szField)))
  778. {
  779. pszUrl = szField;
  780. }
  781. if (pclsidRoot || *pszUrl)
  782. {
  783. LPITEMIDLIST pidlRoot = ILCreateFromPathW(pszUrl);
  784. // fix up bad cmd line "explorer.exe /root," case
  785. if (!pidlRoot)
  786. SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidlRoot);
  787. if (pidlRoot)
  788. {
  789. *ppidl = ILRootedCreateIDList(pclsidRoot, pidlRoot);
  790. if (*ppidl)
  791. hr = S_OK;
  792. ILFree(pidlRoot);
  793. }
  794. }
  795. }
  796. return hr;
  797. }
  798. STDMETHODIMP CIDListUrlStub::ParseDisplayName(HWND hwnd, LPBC pbc, WCHAR *pwzDisplayName,
  799. ULONG *pchEaten, LPITEMIDLIST *ppidl, ULONG *pdwAttributes)
  800. {
  801. // Need to keep the internet SF from getting a chance to parse
  802. HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
  803. PARSEDURLW pu = {0};
  804. pu.cbSize = sizeof(pu);
  805. ParseURLW(pwzDisplayName, &pu);
  806. ASSERT(pu.nScheme == URL_SCHEME_MSSHELLIDLIST);
  807. LPCWSTR psz = pu.pszSuffix;
  808. if (psz)
  809. {
  810. HANDLE hMem = LongToHandle(StrToIntW(psz));
  811. psz = StrChrW(psz, TEXT(':'));
  812. if (psz++)
  813. {
  814. DWORD dwProcId = (DWORD)StrToIntW(psz);
  815. LPITEMIDLIST pidlGlobal = (LPITEMIDLIST) SHLockShared(hMem, dwProcId);
  816. if (pidlGlobal)
  817. {
  818. if (!IsBadReadPtr(pidlGlobal, 1))
  819. hr = SHILClone(pidlGlobal, ppidl);
  820. SHUnlockShared(pidlGlobal);
  821. SHFreeShared(hMem, dwProcId);
  822. }
  823. }
  824. }
  825. return hr;
  826. }
  827. STDMETHODIMP CFileUrlStub::ParseDisplayName(HWND hwnd, LPBC pbc, WCHAR *pwzDisplayName,
  828. ULONG *pchEaten, LPITEMIDLIST *ppidl, ULONG *pdwAttributes)
  829. {
  830. LPCWSTR pszFragment = UrlGetLocationW(pwzDisplayName);
  831. WCHAR szPath[MAX_URL_STRING];
  832. DWORD cchPath = ARRAYSIZE(szPath);
  833. WCHAR szQuery[MAX_URL_STRING];
  834. DWORD cchQuery = ARRAYSIZE(szQuery) - 1;
  835. // We want to remove QUERY and FRAGMENT sections of
  836. // FILE URLs because they need to be added in "Hidden" pidls.
  837. // Also, URLs need to be escaped all the time except for paths
  838. // to facility parsing and because we already removed all other
  839. // parts of the URL (Query and Fragment).
  840. ASSERT(UrlIsW(pwzDisplayName, URLIS_FILEURL));
  841. if (SUCCEEDED(UrlGetPartW(pwzDisplayName, szQuery+1, &cchQuery, URL_PART_QUERY, 0)) && cchQuery)
  842. szQuery[0] = TEXT('?');
  843. else
  844. szQuery[0] = 0;
  845. if (SUCCEEDED(PathCreateFromUrlW(pwzDisplayName, szPath, &cchPath, 0)))
  846. {
  847. // WARNING - we skip supporting simple ids here
  848. ILCreateFromPathEx(szPath, NULL, ILCFP_FLAG_NORMAL, ppidl, pdwAttributes);
  849. if (*ppidl && pszFragment)
  850. {
  851. *ppidl = ILAppendHiddenStringW(*ppidl, IDLHID_URLFRAGMENT, pszFragment);
  852. }
  853. if (*ppidl && szQuery[0] == TEXT('?'))
  854. {
  855. *ppidl = ILAppendHiddenStringW(*ppidl, IDLHID_URLQUERY, szQuery);
  856. }
  857. E_OUTOFMEMORY;
  858. }
  859. // Need to keep the internet SF from getting a chance to parse
  860. return *ppidl ? S_OK : HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
  861. }
  862. STDAPI_(int) SHGetSpecialFolderID(LPCWSTR pszName);
  863. //
  864. // Given a string of the form
  865. //
  866. // programs\My Pictures\Vacation
  867. //
  868. //
  869. // return CSIDL_PROGRAMS and set ppwszUnparsed to "My Pictures\Vacation".
  870. //
  871. // If there is no backslash, then ppwszUnparsed = NULL.
  872. //
  873. // This function is broken out of CShellUrlStub::ParseDisplayName() to conserve stack space,
  874. // since ParseDisplayName is used by 16-bit ShellExecute.
  875. STDAPI_(int) _ParseSpecialFolder(LPCWSTR pszName, LPWSTR *ppwszUnparsed, ULONG *pcchEaten)
  876. {
  877. LPCWSTR pwszKey;
  878. WCHAR wszKey[MAX_PATH];
  879. LPWSTR pwszBS = StrChrW(pszName, L'\\');
  880. if (pwszBS)
  881. {
  882. *ppwszUnparsed = pwszBS + 1;
  883. *pcchEaten = (ULONG)(pwszBS + 1 - pszName);
  884. StrCpyNW(wszKey, pszName, min(*pcchEaten, MAX_PATH));
  885. pwszKey = wszKey;
  886. }
  887. else
  888. {
  889. *ppwszUnparsed = NULL;
  890. pwszKey = pszName;
  891. *pcchEaten = lstrlenW(pwszKey);
  892. }
  893. return SHGetSpecialFolderID(pwszKey);
  894. }
  895. STDMETHODIMP CShellUrlStub::ParseDisplayName(HWND hwnd,
  896. LPBC pbc, WCHAR *pwzDisplayName, ULONG *pchEaten,
  897. LPITEMIDLIST *ppidl, ULONG *pdwAttributes)
  898. {
  899. PARSEDURLW pu = {0};
  900. pu.cbSize = sizeof(pu);
  901. EVAL(SUCCEEDED(ParseURLW(pwzDisplayName, &pu)));
  902. // Need to keep the internet SF from getting a chance to parse
  903. // the shell: URLs even if we fail to parse it
  904. HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
  905. ASSERT(pu.nScheme == URL_SCHEME_SHELL);
  906. // shell:::{guid}
  907. if (pu.pszSuffix[0] == L':' && pu.pszSuffix[1] == L':')
  908. {
  909. IShellFolder *psfDesktop;
  910. hr = SHGetDesktopFolder(&psfDesktop);
  911. if (SUCCEEDED(hr))
  912. {
  913. IBindCtx *pbcCreate=NULL;
  914. hr = CreateBindCtx(0, &pbcCreate);
  915. if (SUCCEEDED(hr))
  916. {
  917. BIND_OPTS bo = {sizeof(bo)}; // Requires size filled in.
  918. bo.grfMode = STGM_CREATE;
  919. pbcCreate->SetBindOptions(&bo);
  920. hr = psfDesktop->ParseDisplayName(hwnd, pbcCreate, (LPWSTR)pu.pszSuffix, pchEaten, ppidl, pdwAttributes);
  921. pbcCreate->Release();
  922. }
  923. psfDesktop->Release();
  924. }
  925. }
  926. else
  927. { // shell:personal\My Pictures
  928. LPWSTR pwszUnparsed = NULL;
  929. ULONG cchEaten;
  930. int csidl = _ParseSpecialFolder(pu.pszSuffix, &pwszUnparsed, &cchEaten);
  931. if (-1 != csidl)
  932. {
  933. LPITEMIDLIST pidlCSIDL;
  934. hr = SHGetFolderLocation(hwnd, csidl | CSIDL_FLAG_CREATE, NULL, 0, &pidlCSIDL);
  935. if (SUCCEEDED(hr))
  936. {
  937. if (pwszUnparsed && *pwszUnparsed)
  938. {
  939. IShellFolder *psf;
  940. hr = SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder, pidlCSIDL, &psf));
  941. if (SUCCEEDED(hr))
  942. {
  943. LPITEMIDLIST pidlChild;
  944. hr = psf->ParseDisplayName(hwnd, pbc, pwszUnparsed, pchEaten,
  945. &pidlChild, pdwAttributes);
  946. if (SUCCEEDED(hr))
  947. {
  948. hr = SHILCombine(pidlCSIDL, pidlChild, ppidl);
  949. ILFree(pidlChild);
  950. if (pchEaten) *pchEaten += cchEaten;
  951. }
  952. psf->Release();
  953. }
  954. ILFree(pidlCSIDL);
  955. }
  956. else
  957. {
  958. if (pdwAttributes && *pdwAttributes)
  959. {
  960. hr = SHGetNameAndFlags(pidlCSIDL, 0, NULL, 0, pdwAttributes);
  961. }
  962. if (SUCCEEDED(hr))
  963. {
  964. if (pchEaten) *pchEaten = cchEaten;
  965. *ppidl = pidlCSIDL;
  966. }
  967. else
  968. ILFree(pidlCSIDL);
  969. }
  970. }
  971. }
  972. }
  973. return hr;
  974. }
  975. // key for the DAVRDR so that we can read the localised provider name.
  976. #define DAVRDR_KEY TEXT("SYSTEM\\CurrentControlSet\\Services\\WebClient\\NetworkProvider")
  977. STDMETHODIMP CHttpUrlStub::ParseDisplayName(HWND hwnd,
  978. LPBC pbc, WCHAR *pwzDisplayName, ULONG *pchEaten,
  979. LPITEMIDLIST *ppidl, ULONG *pdwAttributes)
  980. {
  981. HRESULT hr = E_INVALIDARG;
  982. PARSEDURLW pu = {0};
  983. pu.cbSize = sizeof(pu);
  984. ParseURLW(pwzDisplayName, &pu);
  985. // we cant handle anything but simple URLs here, and only HTTP (not HTTPS).
  986. if (!UrlGetLocationW(pwzDisplayName)
  987. && !StrChrW(pu.pszSuffix, L'?')
  988. && (lstrlen(pu.pszSuffix) < MAX_PATH)
  989. && (pu.nScheme == URL_SCHEME_HTTP))
  990. {
  991. // convert from wacky http: to something that the RDR will pick up as a UNC,
  992. // given that this is being forwarded directly to the DAV RDR.
  993. //
  994. // http://server/share -> \\server\share
  995. WCHAR sz[MAX_PATH];
  996. StrCpyN(sz, pu.pszSuffix, ARRAYSIZE(sz));
  997. for (LPWSTR psz = sz; *psz; psz++)
  998. {
  999. if (*psz == L'/')
  1000. {
  1001. *psz = L'\\';
  1002. }
  1003. }
  1004. // this forces the use of the DavRedir as the provider
  1005. // thus avoiding any confusion...
  1006. IPropertyBag *ppb;
  1007. hr = SHCreatePropertyBagOnMemory(STGM_READWRITE, IID_PPV_ARG(IPropertyBag, &ppb));
  1008. if (SUCCEEDED(hr))
  1009. {
  1010. TCHAR szProvider[MAX_PATH];
  1011. DWORD cbProvider = sizeof (szProvider);
  1012. if (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, DAVRDR_KEY, TEXT("Name"), NULL, szProvider, &cbProvider))
  1013. {
  1014. hr = SHPropertyBag_WriteStr(ppb, STR_PARSE_NETFOLDER_PROVIDERNAME, szProvider);
  1015. if (SUCCEEDED(hr))
  1016. {
  1017. hr = pbc->RegisterObjectParam(STR_PARSE_NETFOLDER_INFO, ppb);
  1018. if (SUCCEEDED(hr))
  1019. {
  1020. // add a UI bindctx if necessary
  1021. IBindCtx *pbcRelease = NULL;
  1022. if (hwnd && !BindCtx_GetUIWindow(pbc))
  1023. {
  1024. // returns a reference to our pbc in pbcRelease
  1025. BindCtx_RegisterUIWindow(pbc, hwnd, &pbcRelease);
  1026. }
  1027. hr = SHParseDisplayName(sz, pbc, ppidl, pdwAttributes ? *pdwAttributes : 0, pdwAttributes);
  1028. if (pbcRelease)
  1029. pbc->Release();
  1030. }
  1031. }
  1032. }
  1033. else
  1034. {
  1035. hr = E_FAIL;
  1036. }
  1037. ppb->Release();
  1038. }
  1039. }
  1040. if (FAILED(hr) && !BindCtx_ContainsObject(pbc, L"BUT NOT WEBFOLDERS"))
  1041. {
  1042. // fall back to webfolders
  1043. LPITEMIDLIST pidlParent = CreateWebFoldersIDList();
  1044. if (pidlParent)
  1045. {
  1046. IShellFolder *psf;
  1047. hr = SHBindToObjectEx(NULL, pidlParent, NULL, IID_PPV_ARG(IShellFolder, &psf));
  1048. if (SUCCEEDED(hr))
  1049. {
  1050. LPITEMIDLIST pidlRight;
  1051. // always pass NULL for the HWND. webfolders shows really bad UI
  1052. hr = psf->ParseDisplayName(NULL, pbc, pwzDisplayName, pchEaten, &pidlRight, pdwAttributes);
  1053. if (SUCCEEDED(hr))
  1054. {
  1055. hr = SHILCombine(pidlParent, pidlRight, ppidl);
  1056. ILFree(pidlRight);
  1057. }
  1058. psf->Release();
  1059. }
  1060. ILFree(pidlParent);
  1061. }
  1062. }
  1063. return hr;
  1064. }
  1065. HKEY _RegOpenSchemeJunctionKey(LPCTSTR pszScheme)
  1066. {
  1067. HKEY hk = NULL;
  1068. TCHAR sz[MAX_PATH];
  1069. wnsprintf(sz, ARRAYSIZE(sz), TEXT("%s\\ShellEx\\Junction"), pszScheme);
  1070. RegOpenKeyEx(HKEY_CLASSES_ROOT, sz, 0, KEY_READ, &hk);
  1071. return hk;
  1072. }
  1073. BOOL _TryRegisteredUrlJunction(LPCTSTR pszName, DWORD cchName, IShellFolder **ppsf, LPITEMIDLIST *ppidlLeft)
  1074. {
  1075. TCHAR sz[MAX_PATH];
  1076. StrCpyN(sz, pszName, (int)min(ARRAYSIZE(sz), cchName + 1));
  1077. HKEY hk = _RegOpenSchemeJunctionKey(sz);
  1078. if (hk)
  1079. {
  1080. DWORD cbSize;
  1081. // try for IDList
  1082. if (S_OK == SHGetValue(hk, NULL, TEXT("IDList"), NULL, NULL, &cbSize))
  1083. {
  1084. LPITEMIDLIST pidl= (LPITEMIDLIST) SHAlloc(cbSize);
  1085. if (pidl)
  1086. {
  1087. if (S_OK == SHGetValue(hk, NULL, TEXT("IDList"), NULL, pidl, &cbSize))
  1088. {
  1089. *ppidlLeft = pidl;
  1090. }
  1091. else
  1092. SHFree(pidl);
  1093. }
  1094. }
  1095. else
  1096. {
  1097. cbSize = sizeof(sz);
  1098. if (S_OK == SHGetValue(hk, NULL, TEXT("Path"), NULL, sz, &cbSize))
  1099. {
  1100. // maybe we should ILCFP_FLAG_SKIPJUNCTIONS?
  1101. ILCreateFromPathEx(sz, NULL, ILCFP_FLAG_NORMAL, ppidlLeft, NULL);
  1102. }
  1103. else
  1104. {
  1105. CLSID clsid;
  1106. cbSize = sizeof(sz);
  1107. if (S_OK == SHGetValue(hk, NULL, TEXT("CLSID"), NULL, sz, &cbSize)
  1108. && GUIDFromString(sz, &clsid))
  1109. {
  1110. SHCoCreateInstance(NULL, &clsid, NULL, IID_PPV_ARG(IShellFolder, ppsf));
  1111. }
  1112. }
  1113. }
  1114. RegCloseKey(hk);
  1115. return (*ppsf || *ppidlLeft);
  1116. }
  1117. return FALSE;
  1118. }
  1119. BOOL CDesktopFolder::_TryUrlJunctions(LPCTSTR pszName, IBindCtx *pbc, IShellFolder **ppsf, LPITEMIDLIST *ppidlLeft)
  1120. {
  1121. PARSEDURL pu = {0};
  1122. pu.cbSize = sizeof(pu);
  1123. EVAL(SUCCEEDED(ParseURL(pszName, &pu)));
  1124. ASSERT(!*ppsf);
  1125. ASSERT(!*ppidlLeft);
  1126. switch (pu.nScheme)
  1127. {
  1128. case URL_SCHEME_SHELL:
  1129. *ppsf = SAFECAST(&_sfShellUrl, IShellFolder *);
  1130. break;
  1131. case URL_SCHEME_FILE:
  1132. *ppsf = SAFECAST(&_sfFileUrl, IShellFolder *);
  1133. break;
  1134. case URL_SCHEME_MSSHELLROOTED:
  1135. *ppsf = SAFECAST(&_sfRooted, IShellFolder *);
  1136. break;
  1137. case URL_SCHEME_MSSHELLIDLIST:
  1138. *ppsf = SAFECAST(&_sfIDListUrl, IShellFolder *);
  1139. break;
  1140. case URL_SCHEME_HTTP:
  1141. case URL_SCHEME_HTTPS:
  1142. if (BindCtx_ContainsObject(pbc, STR_PARSE_PREFER_FOLDER_BROWSING))
  1143. *ppsf = SAFECAST(&_sfHttpUrl, IShellFolder *);
  1144. break;
  1145. default:
  1146. // _TryRegisteredUrlJunction(pu.pszProtocol, pu.cchProtocol, ppsf, ppidlLeft)
  1147. break;
  1148. }
  1149. return (*ppsf || *ppidlLeft);
  1150. }
  1151. BOOL _FailForceReturn(HRESULT hr);
  1152. BOOL CDesktopFolder::_GetFolderForParsing(LPCTSTR pszName, LPBC pbc, IShellFolder **ppsf, LPITEMIDLIST *ppidlLeft)
  1153. {
  1154. ASSERT(!*ppidlLeft);
  1155. ASSERT(!*ppsf);
  1156. if ((InRange(pszName[0], TEXT('A'), TEXT('Z')) ||
  1157. InRange(pszName[0], TEXT('a'), TEXT('z'))) &&
  1158. pszName[1] == TEXT(':'))
  1159. {
  1160. // The string contains a path, let "My Computer" figire it out.
  1161. *ppidlLeft = CreateMyComputerIDList();
  1162. }
  1163. else if (PathIsUNC(pszName))
  1164. {
  1165. // The path is UNC, let "World" figure it out.
  1166. *ppidlLeft = CreateMyNetPlacesIDList();
  1167. }
  1168. else if (UrlIs(pszName, URLIS_URL) && !SHSkipJunctionBinding(pbc, NULL))
  1169. {
  1170. _TryUrlJunctions(pszName, pbc, ppsf, ppidlLeft);
  1171. }
  1172. if (!*ppsf && *ppidlLeft)
  1173. SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder, *ppidlLeft, ppsf));
  1174. return (*ppsf != NULL);
  1175. }
  1176. STDMETHODIMP CDesktopFolder::ParseDisplayName(HWND hwnd,
  1177. LPBC pbc, WCHAR *pwzDisplayName, ULONG *pchEaten,
  1178. LPITEMIDLIST *ppidl, ULONG *pdwAttributes)
  1179. {
  1180. HRESULT hr = E_INVALIDARG;
  1181. if (ppidl)
  1182. {
  1183. *ppidl = NULL; // assume error
  1184. if (pwzDisplayName && *pwzDisplayName)
  1185. {
  1186. LPITEMIDLIST pidlLeft = NULL;
  1187. IShellFolder *psfRight = NULL;
  1188. ASSERT(hr == E_INVALIDARG);
  1189. if (_GetFolderForParsing(pwzDisplayName, pbc, &psfRight, &pidlLeft))
  1190. {
  1191. if (pchEaten)
  1192. *pchEaten = 0;
  1193. hr = _ChildParseDisplayName(psfRight, pidlLeft, hwnd, pbc, pwzDisplayName, pchEaten, ppidl, pdwAttributes);
  1194. ILFree(pidlLeft);
  1195. psfRight->Release();
  1196. }
  1197. if (SUCCEEDED(hr))
  1198. {
  1199. // translate aliases here for goodness sake
  1200. if (BindCtx_ContainsObject(pbc, STR_PARSE_TRANSLATE_ALIASES))
  1201. {
  1202. LPITEMIDLIST pidlAlias;
  1203. if (SUCCEEDED(SHILAliasTranslate(*ppidl, &pidlAlias, XLATEALIAS_ALL)))
  1204. {
  1205. ILFree(*ppidl);
  1206. *ppidl = pidlAlias;
  1207. }
  1208. }
  1209. }
  1210. else if (FAILED(hr) && !_FailForceReturn(hr))
  1211. {
  1212. //
  1213. // MIL 131297 - desktop did not support relative simple parses - ZekeL - 3-FEB-2000
  1214. // it was only the roots (drives/net) that would create simple IDs
  1215. // so for some apps we need to still not do it.
  1216. //
  1217. if (BindCtx_ContainsObject(pbc, STR_DONT_PARSE_RELATIVE))
  1218. {
  1219. // we're told not to parse relative paths and _GetFolderForParsing failed
  1220. // so act like we don't think the path exists.
  1221. hr = E_INVALIDARG;
  1222. }
  1223. else if (S_OK != SHIsFileSysBindCtx(pbc, NULL))
  1224. {
  1225. // when we request that something be created, we need to
  1226. // check both folders and make sure that it doesnt exist in
  1227. // either one. and then try and create it in the user folder
  1228. BIND_OPTS bo = {sizeof(bo)};
  1229. BOOL fCreate = FALSE;
  1230. if (pbc && SUCCEEDED(pbc->GetBindOptions(&bo)) &&
  1231. (bo.grfMode & STGM_CREATE))
  1232. {
  1233. fCreate = TRUE;
  1234. bo.grfMode &= ~STGM_CREATE;
  1235. pbc->SetBindOptions(&bo);
  1236. }
  1237. // give the users desktop first shot.
  1238. // This must be a desktop item, _psfDesktop may not be inited in
  1239. // the case where we are called from ILCreateFromPath()
  1240. if (_psfDesktop)
  1241. hr = _psfDesktop->ParseDisplayName(hwnd, pbc, pwzDisplayName, pchEaten, ppidl, pdwAttributes);
  1242. // if the normal desktop folder didnt pick it off,
  1243. // it could be in the allusers folder. give psfAlt a chance.
  1244. if (FAILED(hr) && _psfAltDesktop)
  1245. {
  1246. hr = _psfAltDesktop->ParseDisplayName(hwnd, pbc, pwzDisplayName, pchEaten, ppidl, pdwAttributes);
  1247. }
  1248. // neither of the folders can identify an existing item
  1249. // so we should pass the create flag to the real desktop
  1250. if (FAILED(hr) && fCreate && _psfDesktop)
  1251. {
  1252. bo.grfMode |= STGM_CREATE;
  1253. pbc->SetBindOptions(&bo);
  1254. hr = _psfDesktop->ParseDisplayName(hwnd, pbc, pwzDisplayName, pchEaten, ppidl, pdwAttributes);
  1255. // when this succeeds, we know we got a magical ghost pidl...
  1256. }
  1257. }
  1258. }
  1259. }
  1260. else if (pwzDisplayName)
  1261. {
  1262. // we used to return this pidl when passed an empty string
  1263. // some apps (such as Wright Design) depend on this behavior
  1264. hr = SHILClone((LPCITEMIDLIST)&c_idlDrives, ppidl);
  1265. }
  1266. }
  1267. return hr;
  1268. }
  1269. STDAPI_(void) UltRoot_Term()
  1270. {
  1271. if (g_pDesktopFolder)
  1272. {
  1273. g_pDesktopFolder->_Destroy();
  1274. g_pDesktopFolder = NULL;
  1275. }
  1276. }
  1277. HRESULT CDesktopFolder::EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenum)
  1278. {
  1279. *ppenum = new CDesktopFolderEnum(this, hwnd, grfFlags);
  1280. return *ppenum ? S_OK : E_OUTOFMEMORY;
  1281. }
  1282. STDMETHODIMP CDesktopFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  1283. {
  1284. // note: using IsSelf() here will cause a problem with WinZip. they expect
  1285. // failure when they pass an empty pidl. SHBindToOjbect() has the special
  1286. // case for the desktop, so it is not needed here.
  1287. IShellFolder2 *psf = _GetItemFolder(pidl);
  1288. if (psf)
  1289. return psf->BindToObject(pidl, pbc, riid, ppv);
  1290. return E_UNEXPECTED;
  1291. }
  1292. STDMETHODIMP CDesktopFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  1293. {
  1294. return BindToObject(pidl, pbc, riid, ppv);
  1295. }
  1296. STDMETHODIMP CDesktopFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  1297. {
  1298. if (pidl1 == NULL || pidl2 == NULL)
  1299. return E_INVALIDARG;
  1300. if (pidl1->mkid.cb == 0 && pidl2->mkid.cb == 0)
  1301. return ResultFromShort(0); // 2 empty IDLists, they are the same
  1302. if (ILIsRooted(pidl1) || ILIsRooted(pidl2))
  1303. {
  1304. return _sfRooted.CompareIDs(lParam, pidl1, pidl2);
  1305. }
  1306. // If both objects aren't from the same directory, they won't match.
  1307. else if (_psfAltDesktop)
  1308. {
  1309. if (CFSFolder_IsCommonItem(pidl1))
  1310. {
  1311. if (CFSFolder_IsCommonItem(pidl2))
  1312. return _psfAltDesktop->CompareIDs(lParam, pidl1, pidl2);
  1313. else
  1314. return ResultFromShort(-1);
  1315. }
  1316. else
  1317. {
  1318. if (CFSFolder_IsCommonItem(pidl2))
  1319. return ResultFromShort(1);
  1320. else if (_psfDesktop)
  1321. return _psfDesktop->CompareIDs(lParam, pidl1, pidl2);
  1322. }
  1323. }
  1324. else if (_psfDesktop)
  1325. {
  1326. return _psfDesktop->CompareIDs(lParam, pidl1, pidl2);
  1327. }
  1328. // If we have no _psfDesktop, we get here...
  1329. return ResultFromShort(-1);
  1330. }
  1331. HRESULT CDesktopFolder::_BGCommand(HWND hwnd, WPARAM wparam, BOOL bExecute)
  1332. {
  1333. HRESULT hr = S_OK;
  1334. switch (wparam)
  1335. {
  1336. case DFM_CMD_PROPERTIES:
  1337. case FSIDM_PROPERTIESBG:
  1338. if (bExecute)
  1339. {
  1340. // run the default applet in desk.cpl
  1341. if (SHRunControlPanel( TEXT("desk.cpl"), hwnd ))
  1342. hr = S_OK;
  1343. else
  1344. hr = E_OUTOFMEMORY;
  1345. }
  1346. break;
  1347. case DFM_CMD_MOVE:
  1348. case DFM_CMD_COPY:
  1349. hr = E_FAIL;
  1350. break;
  1351. default:
  1352. // This is common menu items, use the default code.
  1353. hr = S_FALSE;
  1354. break;
  1355. }
  1356. return hr;
  1357. }
  1358. // IContextMenuCB::CallBack for the background context menu
  1359. //
  1360. // Returns:
  1361. // S_OK, if successfully processed.
  1362. // S_FALSE, if default code should be used.
  1363. STDMETHODIMP CDesktopFolder::CallBack(IShellFolder *psf, HWND hwnd, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1364. {
  1365. HRESULT hr = S_OK;
  1366. switch (uMsg)
  1367. {
  1368. case DFM_MERGECONTEXTMENU_BOTTOM:
  1369. if (!(wParam & (CMF_VERBSONLY | CMF_DVFILE)))
  1370. {
  1371. // Only add the desktop background Properties iff we're the real desktop browser
  1372. // (i.e., we don't want it when in explorer)
  1373. //
  1374. if (IsDesktopBrowser(_punkSite))
  1375. {
  1376. LPQCMINFO pqcm = (LPQCMINFO)lParam;
  1377. UINT idCmdFirst = pqcm->idCmdFirst;
  1378. CDefFolderMenu_MergeMenu(HINST_THISDLL, POPUP_PROPERTIES_BG, 0, pqcm);
  1379. }
  1380. }
  1381. break;
  1382. case DFM_GETHELPTEXT:
  1383. LoadStringA(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPSTR)lParam, HIWORD(wParam));;
  1384. break;
  1385. case DFM_GETHELPTEXTW:
  1386. LoadStringW(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPWSTR)lParam, HIWORD(wParam));;
  1387. break;
  1388. case DFM_INVOKECOMMAND:
  1389. case DFM_VALIDATECMD:
  1390. hr = _BGCommand(hwnd, wParam, uMsg == DFM_INVOKECOMMAND);
  1391. break;
  1392. default:
  1393. hr = E_NOTIMPL;
  1394. break;
  1395. }
  1396. return hr;
  1397. }
  1398. // IItemNameLimits
  1399. STDMETHODIMP CDesktopFolder::GetValidCharacters(LPWSTR *ppwszValidChars, LPWSTR *ppwszInvalidChars)
  1400. {
  1401. IItemNameLimits *pinl;
  1402. HRESULT hr = _QueryInterfaceItem(NULL, IID_PPV_ARG(IItemNameLimits, &pinl));
  1403. if (SUCCEEDED(hr))
  1404. {
  1405. hr = pinl->GetValidCharacters(ppwszValidChars, ppwszInvalidChars);
  1406. pinl->Release();
  1407. }
  1408. return hr;
  1409. }
  1410. STDMETHODIMP CDesktopFolder::GetMaxLength(LPCWSTR pszName, int *piMaxNameLen)
  1411. {
  1412. // delegate to per user or common based on which name space
  1413. // pszName is from (we have to search for that)
  1414. IItemNameLimits *pinl;
  1415. HRESULT hr = _QueryInterfaceItem(NULL, IID_PPV_ARG(IItemNameLimits, &pinl));
  1416. if (SUCCEEDED(hr))
  1417. {
  1418. hr = pinl->GetMaxLength(pszName, piMaxNameLen);
  1419. pinl->Release();
  1420. }
  1421. return hr;
  1422. }
  1423. // IOleCommandTarget stuff
  1424. STDMETHODIMP CDesktopFolder::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
  1425. {
  1426. return IUnknown_QueryStatus(_psfDesktop, pguidCmdGroup, cCmds, rgCmds, pcmdtext);
  1427. }
  1428. STDMETHODIMP CDesktopFolder::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
  1429. {
  1430. // invalidate our cache
  1431. // which we dont really have right now.
  1432. // but CFSFolder does
  1433. IUnknown_Exec(_psfAltDesktop, pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
  1434. return IUnknown_Exec(_psfDesktop, pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
  1435. }
  1436. STDMETHODIMP CDesktopFolder::CreateViewObject(HWND hwnd, REFIID riid, void **ppv)
  1437. {
  1438. HRESULT hr = E_NOINTERFACE;
  1439. *ppv = NULL;
  1440. if (IsEqualIID(riid, IID_IShellView))
  1441. {
  1442. IShellFolderViewCB* psfvcb;
  1443. if (SUCCEEDED(Create_CDesktopViewCallback(this, &psfvcb)))
  1444. {
  1445. SFV_CREATE sfvc = {0};
  1446. sfvc.cbSize = sizeof(sfvc);
  1447. sfvc.psfvcb = psfvcb;
  1448. hr = QueryInterface(IID_PPV_ARG(IShellFolder, &sfvc.pshf)); // in case we are agregated
  1449. if (SUCCEEDED(hr))
  1450. {
  1451. hr = SHCreateShellFolderView(&sfvc, (IShellView**)ppv);
  1452. sfvc.pshf->Release();
  1453. }
  1454. psfvcb->Release();
  1455. }
  1456. }
  1457. else if (IsEqualIID(riid, IID_IDropTarget) && _psfDesktop)
  1458. {
  1459. IDropTarget* pdt;
  1460. if (SUCCEEDED(_psfDesktop->CreateViewObject(hwnd, riid, (void**)&pdt)))
  1461. {
  1462. CDesktopFolderDropTarget* pdfdt = new CDesktopFolderDropTarget(pdt);
  1463. if (pdfdt)
  1464. {
  1465. hr = pdfdt->QueryInterface(IID_PPV_ARG(IDropTarget, (IDropTarget**)ppv));
  1466. pdfdt->Release();
  1467. }
  1468. pdt->Release();
  1469. }
  1470. }
  1471. else if (IsEqualIID(riid, IID_IContextMenu))
  1472. {
  1473. IShellFolder *psfTemp;
  1474. hr = QueryInterface(IID_PPV_ARG(IShellFolder, &psfTemp));
  1475. if (SUCCEEDED(hr))
  1476. {
  1477. HKEY hkNoFiles = NULL;
  1478. RegOpenKey(HKEY_CLASSES_ROOT, TEXT("Directory\\Background"), &hkNoFiles);
  1479. hr = CDefFolderMenu_Create2Ex(&c_idlDesktop, hwnd, 0, NULL,
  1480. psfTemp, this, 1, &hkNoFiles, (IContextMenu **)ppv);
  1481. psfTemp->Release();
  1482. RegCloseKey(hkNoFiles);
  1483. }
  1484. }
  1485. return hr;
  1486. }
  1487. STDMETHODIMP CDesktopFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, ULONG *rgfOut)
  1488. {
  1489. if (IsSelf(cidl, apidl))
  1490. {
  1491. *rgfOut &= SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR | SFGAO_STORAGEANCESTOR | SFGAO_STORAGE;
  1492. return S_OK;
  1493. }
  1494. IShellFolder2 *psf = _GetItemFolder(apidl[0]);
  1495. if (psf)
  1496. return psf->GetAttributesOf(cidl, apidl, rgfOut);
  1497. return E_UNEXPECTED;
  1498. }
  1499. HRESULT CDesktopFolder::_SelfAssocCreate(REFIID riid, void **ppv)
  1500. {
  1501. *ppv = NULL;
  1502. IQueryAssociations *pqa;
  1503. HRESULT hr = AssocCreate(CLSID_QueryAssociations, IID_PPV_ARG(IQueryAssociations, &pqa));
  1504. if (SUCCEEDED(hr))
  1505. {
  1506. hr = pqa->Init(ASSOCF_INIT_DEFAULTTOFOLDER, L"{00021400-0000-0000-C000-000000000046}", // CLSID_ShellDesktop
  1507. NULL, NULL);
  1508. if (SUCCEEDED(hr))
  1509. {
  1510. hr = pqa->QueryInterface(riid, ppv);
  1511. }
  1512. pqa->Release();
  1513. }
  1514. return hr;
  1515. }
  1516. STDAPI _DeskContextMenuCB(IShellFolder *psf, HWND hwnd, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1517. {
  1518. // The "safe" thing to return is usually E_NOTIMPL, but some messages
  1519. // have special return values.
  1520. HRESULT hr;
  1521. switch (uMsg)
  1522. {
  1523. case DFM_VALIDATECMD:
  1524. hr = S_FALSE;
  1525. break;
  1526. case DFM_INVOKECOMMAND:
  1527. if (wParam == DFM_CMD_PROPERTIES)
  1528. {
  1529. // Properties should act like Properties on the background
  1530. SHRunControlPanel(TEXT("desk.cpl"), hwnd);
  1531. hr = S_OK;
  1532. }
  1533. else
  1534. hr = S_FALSE;
  1535. break;
  1536. case DFM_MERGECONTEXTMENU:
  1537. hr = S_OK;
  1538. break;
  1539. default:
  1540. hr = E_NOTIMPL;
  1541. break;
  1542. }
  1543. return hr;
  1544. }
  1545. HRESULT CDesktopFolder::_SelfCreateContextMenu(HWND hwnd, void **ppv)
  1546. {
  1547. *ppv = NULL;
  1548. IQueryAssociations *pqa;
  1549. HRESULT hr = _SelfAssocCreate(IID_PPV_ARG(IQueryAssociations, &pqa));
  1550. if (SUCCEEDED(hr))
  1551. {
  1552. HKEY ahkeys[2] = { NULL, NULL };
  1553. DWORD cKeys = SHGetAssocKeys(pqa, ahkeys, ARRAYSIZE(ahkeys));
  1554. pqa->Release();
  1555. // We must pass cidl=1 apidl=&pidlDesktop to ensure that an
  1556. // IDataObject is created,
  1557. // or Symantec Internet FastFind ALERTEX.DLL will fault.
  1558. LPCITEMIDLIST pidlDesktop = DESKTOP_PIDL;
  1559. hr = CDefFolderMenu_Create2(&c_idlDesktop, hwnd, 1, &pidlDesktop, this, _DeskContextMenuCB,
  1560. ARRAYSIZE(ahkeys), ahkeys, (IContextMenu **)ppv);
  1561. SHRegCloseKeys(ahkeys, ARRAYSIZE(ahkeys));
  1562. }
  1563. return hr;
  1564. }
  1565. HRESULT CDesktopFolder::_GetItemUIObject(HWND hwnd, UINT cidl, LPCITEMIDLIST *apidl,
  1566. REFIID riid, UINT *prgfInOut, void **ppv)
  1567. {
  1568. IShellFolder2 *psf = _GetItemFolder(apidl[0]);
  1569. if (psf)
  1570. return psf->GetUIObjectOf(hwnd, cidl, apidl, riid, prgfInOut, ppv);
  1571. return E_UNEXPECTED;
  1572. }
  1573. STDMETHODIMP CDesktopFolder::GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST *apidl,
  1574. REFIID riid, UINT *prgfInOut, void **ppv)
  1575. {
  1576. HRESULT hr = E_NOINTERFACE;
  1577. *ppv = NULL;
  1578. if (IsSelf(cidl, apidl))
  1579. {
  1580. // for the desktop itself
  1581. if (IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW))
  1582. {
  1583. hr = SHCreateDefExtIcon(NULL, II_DESKTOP, II_DESKTOP, GIL_PERCLASS, II_DESKTOP, riid, ppv);
  1584. }
  1585. else if (IsEqualIID(riid, IID_IQueryInfo))
  1586. {
  1587. hr = CreateInfoTipFromText(MAKEINTRESOURCE(IDS_FOLDER_DESKTOP_TT), riid, ppv);
  1588. }
  1589. else if (IsEqualIID(riid, IID_IContextMenu))
  1590. {
  1591. hr = _SelfCreateContextMenu(hwnd, ppv);
  1592. }
  1593. else if (IsEqualIID(riid, IID_IDropTarget))
  1594. {
  1595. hr = _psfDesktop->CreateViewObject(hwnd, riid, ppv);
  1596. }
  1597. else if (IsEqualIID(riid, IID_IDataObject))
  1598. {
  1599. // Must create with 1 pidl inside that maps to the desktop.
  1600. // Otherwise, CShellExecMenu::InvokeCommand will punt.
  1601. LPCITEMIDLIST pidlDesktop = DESKTOP_PIDL;
  1602. hr = SHCreateFileDataObject(&c_idlDesktop, 1, &pidlDesktop, NULL, (IDataObject **)ppv);
  1603. }
  1604. // Nobody seems to mind if we don't provide this
  1605. // so don't give one out because AssocCreate is slow.
  1606. // else if (IsEqualIID(riid, IID_IQueryAssociations))
  1607. // {
  1608. // hr = _SelfAssocCreate(riid, ppv);
  1609. // }
  1610. }
  1611. else
  1612. {
  1613. hr = _GetItemUIObject(hwnd, cidl, apidl, riid, prgfInOut, ppv);
  1614. }
  1615. return hr;
  1616. }
  1617. STDMETHODIMP CDesktopFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, STRRET *pStrRet)
  1618. {
  1619. HRESULT hr;
  1620. if (IsSelf(1, &pidl))
  1621. {
  1622. if ((dwFlags & (SHGDN_FORPARSING | SHGDN_INFOLDER | SHGDN_FORADDRESSBAR)) == SHGDN_FORPARSING)
  1623. {
  1624. // note some ISV apps puke if we return a full name here but the
  1625. // rest of the shell depends on this...
  1626. TCHAR szPath[MAX_PATH];
  1627. SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, szPath);
  1628. hr = StringToStrRet(szPath, pStrRet);
  1629. }
  1630. else
  1631. hr = ResToStrRet(IDS_DESKTOP, pStrRet); // display name, "Desktop"
  1632. }
  1633. else
  1634. {
  1635. IShellFolder2 *psf = _GetItemFolder(pidl);
  1636. if (psf)
  1637. hr = psf->GetDisplayNameOf(pidl, dwFlags, pStrRet);
  1638. else
  1639. hr = E_UNEXPECTED;
  1640. }
  1641. return hr;
  1642. }
  1643. STDMETHODIMP CDesktopFolder::SetNameOf(HWND hwnd, LPCITEMIDLIST pidl,
  1644. LPCOLESTR pszName, DWORD dwRes, LPITEMIDLIST *ppidlOut)
  1645. {
  1646. IShellFolder2 *psf = _GetItemFolder(pidl);
  1647. if (psf)
  1648. return psf->SetNameOf(hwnd, pidl, pszName, dwRes, ppidlOut);
  1649. return E_UNEXPECTED;
  1650. }
  1651. STDMETHODIMP CDesktopFolder::GetDefaultSearchGUID(GUID *pGuid)
  1652. {
  1653. return E_NOTIMPL;
  1654. }
  1655. STDMETHODIMP CDesktopFolder::EnumSearches(LPENUMEXTRASEARCH *ppenum)
  1656. {
  1657. *ppenum = NULL;
  1658. return E_NOTIMPL;
  1659. }
  1660. STDMETHODIMP CDesktopFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
  1661. {
  1662. if (_psfDesktop)
  1663. return _psfDesktop->GetDefaultColumn(dwRes, pSort, pDisplay);
  1664. return E_UNEXPECTED;
  1665. }
  1666. STDMETHODIMP CDesktopFolder::GetDefaultColumnState(UINT iColumn, DWORD *pdwState)
  1667. {
  1668. if (_psfDesktop)
  1669. return _psfDesktop->GetDefaultColumnState(iColumn, pdwState);
  1670. return E_UNEXPECTED;
  1671. }
  1672. STDMETHODIMP CDesktopFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
  1673. {
  1674. HRESULT hr = E_UNEXPECTED;
  1675. if (IsSelf(1, &pidl))
  1676. {
  1677. if (IsEqualSCID(*pscid, SCID_NAME))
  1678. {
  1679. STRRET strRet;
  1680. hr = GetDisplayNameOf(pidl, SHGDN_NORMAL, &strRet);
  1681. if (SUCCEEDED(hr))
  1682. {
  1683. hr = InitVariantFromStrRet(&strRet, pidl, pv);
  1684. }
  1685. }
  1686. }
  1687. else
  1688. {
  1689. IShellFolder2 *psf = _GetItemFolder(pidl);
  1690. if (psf)
  1691. {
  1692. hr = psf->GetDetailsEx(pidl, pscid, pv);
  1693. }
  1694. }
  1695. return hr;
  1696. }
  1697. STDMETHODIMP CDesktopFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pDetails)
  1698. {
  1699. IShellFolder2 *psf = _GetItemFolder(pidl);
  1700. if (psf)
  1701. return psf->GetDetailsOf(pidl, iColumn, pDetails);
  1702. return E_UNEXPECTED;
  1703. }
  1704. STDMETHODIMP CDesktopFolder::MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid)
  1705. {
  1706. if (_psfDesktop)
  1707. return _psfDesktop->MapColumnToSCID(iColumn, pscid);
  1708. return E_UNEXPECTED;
  1709. }
  1710. STDMETHODIMP CDesktopFolder::GetClassID(CLSID *pCLSID)
  1711. {
  1712. *pCLSID = CLSID_ShellDesktop;
  1713. return S_OK;
  1714. }
  1715. STDMETHODIMP CDesktopFolder::Initialize(LPCITEMIDLIST pidl)
  1716. {
  1717. return ILIsEmpty(pidl) ? S_OK : E_INVALIDARG;
  1718. }
  1719. STDMETHODIMP CDesktopFolder::GetCurFolder(LPITEMIDLIST *ppidl)
  1720. {
  1721. return GetCurFolderImpl(&c_idlDesktop, ppidl);
  1722. }
  1723. STDMETHODIMP CDesktopFolder::TranslateIDs(LONG *plEvent,
  1724. LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2,
  1725. LPITEMIDLIST * ppidlOut1, LPITEMIDLIST * ppidlOut2,
  1726. LONG *plEvent2, LPITEMIDLIST *ppidlOut1Event2,
  1727. LPITEMIDLIST *ppidlOut2Event2)
  1728. {
  1729. *ppidlOut1 = NULL;
  1730. *ppidlOut2 = NULL;
  1731. *plEvent2 = -1;
  1732. *ppidlOut1Event2 = NULL;
  1733. *ppidlOut2Event2 = NULL;
  1734. if (pidl1)
  1735. SHILAliasTranslate(pidl1, ppidlOut1, XLATEALIAS_DESKTOP);
  1736. if (pidl2)
  1737. SHILAliasTranslate(pidl2, ppidlOut2, XLATEALIAS_DESKTOP);
  1738. if (*ppidlOut1 || *ppidlOut2)
  1739. {
  1740. if (!*ppidlOut1)
  1741. *ppidlOut1 = ILClone(pidl1);
  1742. if (!*ppidlOut2)
  1743. *ppidlOut2 = ILClone(pidl2);
  1744. if (*ppidlOut1 || *ppidlOut2)
  1745. {
  1746. return S_OK;
  1747. }
  1748. ILFree(*ppidlOut1);
  1749. ILFree(*ppidlOut2);
  1750. *ppidlOut1 = NULL;
  1751. *ppidlOut2 = NULL;
  1752. }
  1753. return E_FAIL;
  1754. }
  1755. STDMETHODIMP CDesktopFolder::GetIconOf(LPCITEMIDLIST pidl, UINT flags, int *piIndex)
  1756. {
  1757. IShellIcon *psi;
  1758. HRESULT hr = _QueryInterfaceItem(pidl, IID_PPV_ARG(IShellIcon, &psi));
  1759. if (SUCCEEDED(hr))
  1760. {
  1761. hr = psi->GetIconOf(pidl, flags, piIndex);
  1762. psi->Release();
  1763. }
  1764. return hr;
  1765. }
  1766. STDMETHODIMP CDesktopFolder::GetOverlayIndex(LPCITEMIDLIST pidl, int *pIndex)
  1767. {
  1768. IShellIconOverlay *psio;
  1769. HRESULT hr = _QueryInterfaceItem(pidl, IID_PPV_ARG(IShellIconOverlay, &psio));
  1770. if (SUCCEEDED(hr))
  1771. {
  1772. hr = psio->GetOverlayIndex(pidl, pIndex);
  1773. psio->Release();
  1774. }
  1775. return hr;
  1776. }
  1777. STDMETHODIMP CDesktopFolder::GetOverlayIconIndex(LPCITEMIDLIST pidl, int *pIconIndex)
  1778. {
  1779. IShellIconOverlay *psio;
  1780. HRESULT hr = _QueryInterfaceItem(pidl, IID_PPV_ARG(IShellIconOverlay, &psio));
  1781. if (SUCCEEDED(hr))
  1782. {
  1783. hr = psio->GetOverlayIconIndex(pidl, pIconIndex);
  1784. psio->Release();
  1785. }
  1786. return hr;
  1787. }
  1788. // IStorage
  1789. STDMETHODIMP CDesktopFolder::_DeleteItemByIDList(LPCITEMIDLIST pidl)
  1790. {
  1791. IStorage *pstg;
  1792. HRESULT hr = _QueryInterfaceItem(pidl, IID_PPV_ARG(IStorage, &pstg));
  1793. if (SUCCEEDED(hr))
  1794. {
  1795. TCHAR szName[MAX_PATH];
  1796. hr = DisplayNameOf(this, pidl, SHGDN_FORPARSING | SHGDN_INFOLDER, szName, ARRAYSIZE(szName));
  1797. if (SUCCEEDED(hr))
  1798. {
  1799. hr = pstg->DestroyElement(szName);
  1800. }
  1801. pstg->Release();
  1802. }
  1803. return hr;
  1804. }
  1805. STDMETHODIMP CDesktopFolder::_StgCreate(LPCITEMIDLIST pidl, DWORD grfMode, REFIID riid, void **ppv)
  1806. {
  1807. IStorage *pstg;
  1808. HRESULT hr = _QueryInterfaceItem(pidl, IID_PPV_ARG(IStorage, &pstg));
  1809. if (SUCCEEDED(hr))
  1810. {
  1811. TCHAR szName[MAX_PATH];
  1812. hr = DisplayNameOf(this, pidl, SHGDN_FORPARSING | SHGDN_INFOLDER, szName, ARRAYSIZE(szName));
  1813. if (SUCCEEDED(hr))
  1814. {
  1815. if (IsEqualIID(riid, IID_IStorage))
  1816. {
  1817. hr = pstg->CreateStorage(szName, grfMode, 0, 0, (IStorage **) ppv);
  1818. }
  1819. else if (IsEqualIID(riid, IID_IStream))
  1820. {
  1821. hr = pstg->CreateStream(szName, grfMode, 0, 0, (IStream **) ppv);
  1822. }
  1823. else
  1824. {
  1825. hr = E_INVALIDARG;
  1826. }
  1827. }
  1828. pstg->Release();
  1829. }
  1830. return hr;
  1831. }
  1832. #define DESKTOP_EVENTS \
  1833. SHCNE_DISKEVENTS | \
  1834. SHCNE_ASSOCCHANGED | \
  1835. SHCNE_NETSHARE | \
  1836. SHCNE_NETUNSHARE
  1837. HRESULT CDesktopViewCallBack::QueryInterface(REFIID riid, void **ppv)
  1838. {
  1839. HRESULT hr = CBaseShellFolderViewCB::QueryInterface(riid, ppv);
  1840. if (FAILED(hr))
  1841. {
  1842. static const QITAB qit[] = {
  1843. QITABENT(CDesktopViewCallBack, IFolderFilter),
  1844. { 0 },
  1845. };
  1846. hr = QISearch(this, qit, riid, ppv);
  1847. }
  1848. return hr;
  1849. }
  1850. //
  1851. // Copied to shell\applets\cleanup\fldrclnr\cleanupwiz.cpp :CCleanupWiz::_ShouldShow
  1852. // If you modify this, modify that as well
  1853. //
  1854. STDMETHODIMP CDesktopViewCallBack::ShouldShow(IShellFolder* psf, LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlItem)
  1855. {
  1856. HRESULT hr = S_OK; //Assume that this item should be shown!
  1857. if (!_fCheckedIfRealDesktop) //Have we done this check before?
  1858. {
  1859. _fRealDesktop = IsDesktopBrowser(_punkSite);
  1860. _fCheckedIfRealDesktop = TRUE; //Remember this fact!
  1861. }
  1862. if (!_fRealDesktop)
  1863. return S_OK; //Not a real desktop! So, let's show everything!
  1864. IShellFolder2 *psf2;
  1865. if (SUCCEEDED(psf->QueryInterface(IID_PPV_ARG(IShellFolder2, &psf2))))
  1866. {
  1867. // Get the GUID in the pidl, which requires IShellFolder2.
  1868. CLSID guidItem;
  1869. if (SUCCEEDED(GetItemCLSID(psf2, pidlItem, &guidItem)))
  1870. {
  1871. SHELLSTATE ss = {0};
  1872. SHGetSetSettings(&ss, SSF_STARTPANELON, FALSE); //See if the StartPanel is on!
  1873. TCHAR szRegPath[MAX_PATH];
  1874. //Get the proper registry path based on if StartPanel is ON/OFF
  1875. wsprintf(szRegPath, REGSTR_PATH_HIDDEN_DESKTOP_ICONS, (ss.fStartPanelOn ? REGSTR_VALUE_STARTPANEL : REGSTR_VALUE_CLASSICMENU));
  1876. //Convert the guid to a string
  1877. TCHAR szGuidValue[MAX_GUID_STRING_LEN];
  1878. SHStringFromGUID(guidItem, szGuidValue, ARRAYSIZE(szGuidValue));
  1879. //See if this item is turned off in the registry.
  1880. if (SHRegGetBoolUSValue(szRegPath, szGuidValue, FALSE, /* default */FALSE))
  1881. hr = S_FALSE; //They want to hide it; So, return S_FALSE.
  1882. }
  1883. psf2->Release();
  1884. }
  1885. return hr;
  1886. }
  1887. STDMETHODIMP CDesktopViewCallBack::GetEnumFlags(IShellFolder* psf, LPCITEMIDLIST pidlFolder, HWND *phwnd, DWORD *pgrfFlags)
  1888. {
  1889. return E_NOTIMPL;
  1890. }
  1891. CDesktopViewCallBack::CDesktopViewCallBack(CDesktopFolder* pdf) :
  1892. CBaseShellFolderViewCB((LPCITEMIDLIST)&c_idlDesktop, DESKTOP_EVENTS),
  1893. _pdf(pdf)
  1894. {
  1895. ASSERT(_fCheckedIfRealDesktop == FALSE);
  1896. ASSERT(_fRealDesktop == FALSE);
  1897. }
  1898. HRESULT Create_CDesktopViewCallback(CDesktopFolder* pdf, IShellFolderViewCB** ppv)
  1899. {
  1900. HRESULT hr;
  1901. CDesktopViewCallBack* p = new CDesktopViewCallBack(pdf);
  1902. if (p)
  1903. {
  1904. *ppv = SAFECAST(p, IShellFolderViewCB*);
  1905. hr = S_OK;
  1906. }
  1907. else
  1908. {
  1909. *ppv = NULL;
  1910. hr = E_OUTOFMEMORY;
  1911. }
  1912. return hr;
  1913. }
  1914. HRESULT CDesktopViewCallBack::OnGETCCHMAX(DWORD pv, LPCITEMIDLIST pidlItem, UINT *pcch)
  1915. {
  1916. HRESULT hr = S_OK;
  1917. if (SIL_GetType(pidlItem) == SHID_ROOT_REGITEM)
  1918. {
  1919. // evil, we should not have to know this
  1920. // make regfldr implement IItemNameLimits and this code won't be needed
  1921. *pcch = MAX_REGITEMCCH;
  1922. }
  1923. else
  1924. {
  1925. TCHAR szName[MAX_PATH];
  1926. if (SUCCEEDED(DisplayNameOf(_pdf, pidlItem, SHGDN_FORPARSING | SHGDN_INFOLDER, szName, ARRAYSIZE(szName))))
  1927. {
  1928. hr = _pdf->GetMaxLength(szName, (int *)pcch);
  1929. }
  1930. }
  1931. return hr;
  1932. }
  1933. HRESULT CDesktopViewCallBack::OnGetWorkingDir(DWORD pv, UINT wP, LPTSTR pszDir)
  1934. {
  1935. return SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, pszDir);
  1936. }
  1937. HRESULT CDesktopViewCallBack::OnGetWebViewTemplate(DWORD pv, UINT uViewMode, SFVM_WEBVIEW_TEMPLATE_DATA* pvi)
  1938. {
  1939. HRESULT hr = E_FAIL;
  1940. if (IsDesktopBrowser(_punkSite))
  1941. {
  1942. // It's the actual desktop, use desstop.htt (from the desktop CLSID)
  1943. //
  1944. hr = DefaultGetWebViewTemplateFromClsid(CLSID_ShellDesktop, pvi);
  1945. }
  1946. return hr;
  1947. }
  1948. HRESULT CDesktopViewCallBack::OnGetWebViewLayout(DWORD pv, UINT uViewMode, SFVM_WEBVIEW_LAYOUT_DATA* pData)
  1949. {
  1950. ZeroMemory(pData, sizeof(*pData));
  1951. pData->dwLayout = SFVMWVL_NORMAL | SFVMWVL_FILES;
  1952. return S_OK;
  1953. }
  1954. STDMETHODIMP CDesktopViewCallBack::RealMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
  1955. {
  1956. switch (uMsg)
  1957. {
  1958. HANDLE_MSG(0, SFVM_GETCCHMAX, OnGETCCHMAX);
  1959. HANDLE_MSG(0, SFVM_GETWEBVIEW_TEMPLATE, OnGetWebViewTemplate);
  1960. HANDLE_MSG(0, SFVM_GETWORKINGDIR, OnGetWorkingDir);
  1961. HANDLE_MSG(0, SFVM_GETWEBVIEWLAYOUT, OnGetWebViewLayout);
  1962. default:
  1963. return E_FAIL;
  1964. }
  1965. return S_OK;
  1966. }
  1967. CDesktopFolderDropTarget::CDesktopFolderDropTarget(IDropTarget* pdt) : _cRef(1)
  1968. {
  1969. pdt->QueryInterface(IID_PPV_ARG(IDropTarget, &_pdt));
  1970. }
  1971. CDesktopFolderDropTarget::~CDesktopFolderDropTarget()
  1972. {
  1973. _pdt->Release();
  1974. }
  1975. STDMETHODIMP CDesktopFolderDropTarget::QueryInterface(REFIID riid, void **ppv)
  1976. {
  1977. static const QITAB qit[] = {
  1978. QITABENT(CDesktopFolderDropTarget, IDropTarget),
  1979. QITABENT(CDesktopFolderDropTarget, IObjectWithSite),
  1980. { 0 },
  1981. };
  1982. return QISearch(this, qit, riid, ppv);
  1983. }
  1984. STDMETHODIMP_(ULONG) CDesktopFolderDropTarget::AddRef()
  1985. {
  1986. return InterlockedIncrement(&_cRef);
  1987. }
  1988. STDMETHODIMP_(ULONG) CDesktopFolderDropTarget::Release()
  1989. {
  1990. if (InterlockedDecrement(&_cRef))
  1991. return _cRef;
  1992. delete this;
  1993. return 0;
  1994. }
  1995. // IDropTarget
  1996. HRESULT CDesktopFolderDropTarget::DragEnter(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
  1997. {
  1998. return _pdt->DragEnter(pDataObject, grfKeyState, pt, pdwEffect);
  1999. }
  2000. HRESULT CDesktopFolderDropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
  2001. {
  2002. return _pdt->DragOver(grfKeyState, pt, pdwEffect);
  2003. }
  2004. HRESULT CDesktopFolderDropTarget::DragLeave(void)
  2005. {
  2006. return _pdt->DragLeave();
  2007. }
  2008. HRESULT CDesktopFolderDropTarget::SetSite(IN IUnknown * punkSite)
  2009. {
  2010. IUnknown_SetSite(_pdt, punkSite);
  2011. return S_OK;
  2012. }
  2013. BOOL CDesktopFolderDropTarget::_IsSpecialCaseDrop(IDataObject* pDataObject, DWORD dwEffect, BOOL* pfIsPIDA, UINT* pcItems)
  2014. {
  2015. BOOL fIEDropped = FALSE;
  2016. *pfIsPIDA = FALSE;
  2017. // when we drag a fake IE item (filename.CLSID_Internet) back to the desktop, we delete it and unhide the real IE icon
  2018. STGMEDIUM medium = {0};
  2019. LPIDA pida = DataObj_GetHIDA(pDataObject, &medium);
  2020. if (pida)
  2021. {
  2022. for (UINT i = 0; (i < pida->cidl); i++)
  2023. {
  2024. LPITEMIDLIST pidlFull = HIDA_ILClone(pida, i);
  2025. if (pidlFull)
  2026. {
  2027. LPCITEMIDLIST pidlRelative;
  2028. IShellFolder2* psf2;
  2029. if (SUCCEEDED(SHBindToParent(pidlFull, IID_PPV_ARG(IShellFolder2, &psf2), &pidlRelative)))
  2030. {
  2031. CLSID guidItem;
  2032. if (SUCCEEDED(GetItemCLSID(psf2, pidlRelative, &guidItem)) &&
  2033. IsEqualCLSID(CLSID_Internet, guidItem))
  2034. {
  2035. fIEDropped = TRUE;
  2036. TCHAR szFakeIEItem[MAX_PATH];
  2037. if (SHGetPathFromIDList(pidlFull, szFakeIEItem))
  2038. {
  2039. TCHAR szFakeIEItemDesktop[MAX_PATH];
  2040. if (SHGetSpecialFolderPath(NULL, szFakeIEItemDesktop, CSIDL_DESKTOP, 0))
  2041. {
  2042. // delete the original if this is a move or if we're on the same volume and we're neither explicitly copying nor linking
  2043. if (((dwEffect & DROPEFFECT_MOVE) == DROPEFFECT_MOVE) ||
  2044. (((dwEffect & DROPEFFECT_COPY) != DROPEFFECT_COPY) &&
  2045. ((dwEffect & DROPEFFECT_LINK) != DROPEFFECT_LINK) &&
  2046. (PathIsSameRoot(szFakeIEItemDesktop, szFakeIEItem))))
  2047. {
  2048. DeleteFile(szFakeIEItem);
  2049. }
  2050. }
  2051. }
  2052. pida->cidl--;
  2053. pida->aoffset[i] = pida->aoffset[pida->cidl];
  2054. i--; // stall the for loop
  2055. }
  2056. psf2->Release();
  2057. }
  2058. ILFree(pidlFull);
  2059. }
  2060. }
  2061. *pfIsPIDA = TRUE;
  2062. *pcItems = pida->cidl;
  2063. HIDA_ReleaseStgMedium(pida, &medium);
  2064. }
  2065. return fIEDropped;
  2066. }
  2067. HRESULT CDesktopFolderDropTarget::_ShowIEIcon()
  2068. {
  2069. // reset desktop cleanup wizard's legacy location of "don't show IE" information
  2070. HKEY hkey;
  2071. if(SUCCEEDED(SHRegGetCLSIDKey(CLSID_Internet, TEXT("ShellFolder"), FALSE, TRUE, &hkey)))
  2072. {
  2073. DWORD dwAttr, dwType = 0;
  2074. DWORD cbSize = sizeof(dwAttr);
  2075. if (ERROR_SUCCESS == RegQueryValueEx(hkey, TEXT("Attributes"), NULL, &dwType, (BYTE *) &dwAttr, &cbSize))
  2076. {
  2077. dwAttr &= ~SFGAO_NONENUMERATED;
  2078. RegSetValueEx(hkey, TEXT("Attributes"), NULL, dwType, (BYTE *) &dwAttr, cbSize);
  2079. }
  2080. RegCloseKey(hkey);
  2081. }
  2082. // reset start menu's location of "don't show IE" information
  2083. DWORD dwData = 0;
  2084. TCHAR szCLSID[MAX_GUID_STRING_LEN];
  2085. TCHAR szBuffer[MAX_PATH];
  2086. if (SUCCEEDED(SHStringFromGUID(CLSID_Internet, szCLSID, ARRAYSIZE(szCLSID))))
  2087. {
  2088. for (int i = 0; i < 2; i ++)
  2089. {
  2090. wsprintf(szBuffer, REGSTR_PATH_HIDDEN_DESKTOP_ICONS, (i == 0) ? REGSTR_VALUE_STARTPANEL : REGSTR_VALUE_CLASSICMENU);
  2091. SHRegSetUSValue(szBuffer, szCLSID, REG_DWORD, &dwData, sizeof(DWORD), SHREGSET_FORCE_HKCU);
  2092. }
  2093. }
  2094. SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, DESKTOP_PIDL, NULL);
  2095. return S_OK;
  2096. }
  2097. HRESULT CDesktopFolderDropTarget::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
  2098. {
  2099. BOOL fIsPIDA;
  2100. UINT cidl;
  2101. if (_IsSpecialCaseDrop(pDataObject, *pdwEffect, &fIsPIDA, &cidl))
  2102. {
  2103. _ShowIEIcon();
  2104. }
  2105. HRESULT hr;
  2106. if (fIsPIDA && 0 == cidl)
  2107. {
  2108. hr = _pdt->DragLeave();
  2109. }
  2110. else
  2111. {
  2112. hr = _pdt->Drop(pDataObject, grfKeyState, pt, pdwEffect);
  2113. }
  2114. return hr;
  2115. }
  2116. CDesktopFolderEnum::CDesktopFolderEnum(CDesktopFolder *pdf, HWND hwnd, DWORD grfFlags) :
  2117. _cRef(1), _bUseAltEnum(FALSE)
  2118. {
  2119. if (pdf->_psfDesktop)
  2120. pdf->_psfDesktop->EnumObjects(hwnd, grfFlags, &_penumFolder);
  2121. if (pdf->_psfAltDesktop)
  2122. pdf->_psfAltDesktop->EnumObjects(NULL, grfFlags, &_penumAltFolder);
  2123. }
  2124. CDesktopFolderEnum::~CDesktopFolderEnum()
  2125. {
  2126. if (_penumFolder)
  2127. _penumFolder->Release();
  2128. if (_penumAltFolder)
  2129. _penumAltFolder->Release();
  2130. }
  2131. STDMETHODIMP CDesktopFolderEnum::QueryInterface(REFIID riid, void **ppv)
  2132. {
  2133. static const QITAB qit[] = {
  2134. QITABENT(CDesktopFolderEnum, IEnumIDList), // IID_IEnumIDList
  2135. { 0 },
  2136. };
  2137. return QISearch(this, qit, riid, ppv);
  2138. }
  2139. STDMETHODIMP_(ULONG) CDesktopFolderEnum::AddRef()
  2140. {
  2141. return InterlockedIncrement(&_cRef);
  2142. }
  2143. STDMETHODIMP_(ULONG) CDesktopFolderEnum::Release()
  2144. {
  2145. if (InterlockedDecrement(&_cRef))
  2146. return _cRef;
  2147. delete this;
  2148. return 0;
  2149. }
  2150. STDMETHODIMP CDesktopFolderEnum::Next(ULONG celt, LPITEMIDLIST *ppidl, ULONG *pceltFetched)
  2151. {
  2152. HRESULT hr;
  2153. if (_bUseAltEnum)
  2154. {
  2155. if (_penumAltFolder)
  2156. {
  2157. hr = _penumAltFolder->Next(celt, ppidl, pceltFetched);
  2158. }
  2159. else
  2160. hr = S_FALSE;
  2161. }
  2162. else if (_penumFolder)
  2163. {
  2164. hr = _penumFolder->Next(celt, ppidl, pceltFetched);
  2165. if (S_OK != hr)
  2166. {
  2167. _bUseAltEnum = TRUE;
  2168. hr = Next(celt, ppidl, pceltFetched); // recurse
  2169. }
  2170. }
  2171. else
  2172. {
  2173. hr = S_FALSE;
  2174. }
  2175. if (hr == S_FALSE)
  2176. {
  2177. *ppidl = NULL;
  2178. if (pceltFetched)
  2179. *pceltFetched = 0;
  2180. }
  2181. return hr;
  2182. }
  2183. STDMETHODIMP CDesktopFolderEnum::Skip(ULONG celt)
  2184. {
  2185. return E_NOTIMPL;
  2186. }
  2187. STDMETHODIMP CDesktopFolderEnum::Reset()
  2188. {
  2189. if (_penumFolder)
  2190. _penumFolder->Reset();
  2191. if (_penumAltFolder)
  2192. _penumAltFolder->Reset();
  2193. _bUseAltEnum = FALSE;
  2194. return S_OK;
  2195. }
  2196. STDMETHODIMP CDesktopFolderEnum::Clone(IEnumIDList **ppenum)
  2197. {
  2198. *ppenum = NULL;
  2199. return E_NOTIMPL;
  2200. }