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

2478 lines
83 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. {
  586. hr = E_OUTOFMEMORY;
  587. }
  588. }
  589. return hr;
  590. }
  591. STDAPI SHGetDesktopFolder(IShellFolder **ppshf)
  592. {
  593. return CDesktop_CreateInstance(NULL, IID_PPV_ARG(IShellFolder, ppshf));
  594. }
  595. IShellFolder2 *CDesktopFolder::_GetItemFolder(LPCITEMIDLIST pidl)
  596. {
  597. IShellFolder2 *psf = NULL;
  598. if (ILIsRooted(pidl))
  599. psf = SAFECAST(&_sfRooted, IShellFolder2 *);
  600. else if (_psfAltDesktop && CFSFolder_IsCommonItem(pidl))
  601. psf = _psfAltDesktop;
  602. else
  603. psf = _psfDesktop;
  604. return psf;
  605. }
  606. HRESULT CDesktopFolder::_QueryInterfaceItem(LPCITEMIDLIST pidl, REFIID riid, void **ppv)
  607. {
  608. HRESULT hr;
  609. IShellFolder2 *psf = _GetItemFolder(pidl);
  610. if (psf)
  611. hr = psf->QueryInterface(riid, ppv);
  612. else
  613. {
  614. *ppv = NULL;
  615. hr = E_NOINTERFACE;
  616. }
  617. return hr;
  618. }
  619. STDAPI_(BOOL) RegGetsFirstShot(REFIID riid)
  620. {
  621. return (IsEqualIID(riid, IID_IShellFolder) ||
  622. IsEqualIID(riid, IID_IShellFolder2) ||
  623. IsEqualIID(riid, IID_IShellIconOverlay));
  624. }
  625. HRESULT CDesktopFolder::QueryInterface(REFIID riid, void **ppv)
  626. {
  627. static const QITAB qit[] = {
  628. QITABENT(CDesktopFolder, IShellFolder2),
  629. QITABENTMULTI(CDesktopFolder, IShellFolder, IShellFolder2),
  630. QITABENT(CDesktopFolder, IShellIcon),
  631. QITABENT(CDesktopFolder, IPersistFolder2),
  632. QITABENTMULTI(CDesktopFolder, IPersistFolder, IPersistFolder2),
  633. QITABENTMULTI(CDesktopFolder, IPersist, IPersistFolder2),
  634. QITABENT(CDesktopFolder, IShellIconOverlay),
  635. QITABENT(CDesktopFolder, IStorage),
  636. QITABENT(CDesktopFolder, IContextMenuCB),
  637. QITABENT(CDesktopFolder, IObjectWithSite),
  638. QITABENT(CDesktopFolder, ITranslateShellChangeNotify),
  639. QITABENT(CDesktopFolder, IItemNameLimits),
  640. QITABENT(CDesktopFolder, IOleCommandTarget),
  641. { 0 },
  642. };
  643. if (IsEqualIID(riid, CLSID_ShellDesktop))
  644. {
  645. *ppv = this; // class pointer (unrefed!)
  646. return S_OK;
  647. }
  648. HRESULT hr;
  649. if (_punkReg && RegGetsFirstShot(riid))
  650. {
  651. hr = _punkReg->QueryInterface(riid, ppv);
  652. }
  653. else
  654. {
  655. hr = QISearch(this, qit, riid, ppv);
  656. if ((E_NOINTERFACE == hr) && _punkReg)
  657. {
  658. hr = _punkReg->QueryInterface(riid, ppv);
  659. }
  660. }
  661. return hr;
  662. }
  663. // During shell32.dll process detach, we will call here to do the final
  664. // release of the IShellFolder ptrs which used to be left around for the
  665. // life of the process. This quiets things such as OLE's debug allocator,
  666. // which detected the leak.
  667. void CDesktopFolder::_Destroy()
  668. {
  669. ATOMICRELEASE(_psfDesktop);
  670. ATOMICRELEASE(_psfAltDesktop);
  671. SHReleaseInnerInterface(SAFECAST(this, IShellFolder *), &_punkReg);
  672. delete this;
  673. }
  674. LPITEMIDLIST CreateMyComputerIDList()
  675. {
  676. return ILCreateFromPath(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}")); // CLSID_MyComputer
  677. }
  678. LPITEMIDLIST CreateWebFoldersIDList()
  679. {
  680. return ILCreateFromPath(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{BDEADF00-C265-11D0-BCED-00A0C90AB50F}")); // CLSID_MyComputer\CLSID_WebFolders
  681. }
  682. LPITEMIDLIST CreateMyNetPlacesIDList()
  683. {
  684. return ILCreateFromPath(TEXT("::{208D2C60-3AEA-1069-A2D7-08002B30309D}")); // CLSID_NetworkPlaces
  685. }
  686. HRESULT CDesktopFolder::_ChildParseDisplayName(IShellFolder *psfRight, LPCITEMIDLIST pidlLeft, HWND hwnd, IBindCtx *pbc,
  687. LPWSTR pwzDisplayName, ULONG *pchEaten, LPITEMIDLIST *ppidl, DWORD *pdwAttributes)
  688. {
  689. LPITEMIDLIST pidlRight;
  690. HRESULT hr = psfRight->ParseDisplayName(hwnd, pbc, pwzDisplayName, pchEaten, &pidlRight, pdwAttributes);
  691. if (SUCCEEDED(hr))
  692. {
  693. if (pidlLeft)
  694. {
  695. hr = SHILCombine(pidlLeft, pidlRight, ppidl);
  696. ILFree(pidlRight);
  697. }
  698. else
  699. {
  700. *ppidl = pidlRight;
  701. }
  702. }
  703. return hr;
  704. }
  705. STDMETHODIMP CDesktopRootedStub::GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST * apidl,
  706. REFIID riid, UINT *prgfInOut, void **ppv)
  707. {
  708. HRESULT hr = E_INVALIDARG;
  709. if (cidl == 1)
  710. {
  711. if (IsEqualIID(riid, IID_IDataObject))
  712. {
  713. hr = CIDLData_CreateFromIDArray(&c_idlDesktop, cidl, apidl, (IDataObject **)ppv);
  714. }
  715. else if (IsEqualIID(riid, IID_IContextMenu))
  716. {
  717. IQueryAssociations *pqa;
  718. if (SUCCEEDED(SHGetAssociations(apidl[0], (void **)&pqa)))
  719. {
  720. HKEY keys[5];
  721. DWORD cKeys = SHGetAssocKeys(pqa, keys, ARRAYSIZE(keys));
  722. hr = CDefFolderMenu_Create2Ex(&c_idlDesktop, hwnd,
  723. cidl, apidl, this, this,
  724. cKeys, keys, (IContextMenu **)ppv);
  725. SHRegCloseKeys(keys, cKeys);
  726. }
  727. }
  728. else
  729. {
  730. LPCITEMIDLIST pidlChild;
  731. IShellFolder *psf;
  732. hr = ILRootedBindToParentFolder(apidl[0], IID_PPV_ARG(IShellFolder, &psf), &pidlChild);
  733. if (SUCCEEDED(hr))
  734. {
  735. hr = psf->GetUIObjectOf(hwnd, 1, &pidlChild, riid, prgfInOut, ppv);
  736. psf->Release();
  737. }
  738. }
  739. }
  740. return hr;
  741. }
  742. // Check the registry for a shell root under this CLSID.
  743. BOOL GetRootFromRootClass(CLSID *pclsid, LPWSTR pszPath, int cchPath)
  744. {
  745. WCHAR szClsid[GUIDSTR_MAX];
  746. WCHAR szClass[MAX_PATH];
  747. SHStringFromGUIDW(*pclsid, szClsid, ARRAYSIZE(szClsid));
  748. wnsprintfW(szClass, ARRAYSIZE(szClass), L"CLSID\\%s\\ShellExplorerRoot", szClsid);
  749. DWORD cbPath = cchPath * sizeof(WCHAR);
  750. return SHGetValueGoodBootW(HKEY_CLASSES_ROOT, szClass, NULL, NULL, (BYTE *)pszPath, &cbPath) == ERROR_SUCCESS;
  751. }
  752. //
  753. // General form for Rooted URLs:
  754. // ms-shell-root:{clsid}?URL
  755. // {CLSID} is not required, defaults to CLSID_ShellDesktop
  756. // URL is also not required. if there is a CLSID defaults to
  757. // what is specified under "CLSID\{CLSID}\ShellExplorerRoot
  758. // or default to CSIDL_DESKTOP
  759. // but one of them at least must be specified
  760. // rooted:{clsid}?idlist
  761. //
  762. STDMETHODIMP CDesktopRootedStub::ParseDisplayName(HWND hwnd,
  763. LPBC pbc, WCHAR *pwzDisplayName, ULONG *pchEaten,
  764. LPITEMIDLIST *ppidl, ULONG *pdwAttributes)
  765. {
  766. // Need to keep the internet SF from getting a chance to parse
  767. HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
  768. PARSEDURLW pu = {0};
  769. pu.cbSize = sizeof(pu);
  770. ParseURLW(pwzDisplayName, &pu);
  771. ASSERT(pu.nScheme == URL_SCHEME_MSSHELLROOTED);
  772. LPCWSTR pszUrl = StrChrW(pu.pszSuffix, L':');
  773. if (pszUrl++)
  774. {
  775. WCHAR szField[MAX_PATH];
  776. CLSID clsid;
  777. CLSID *pclsidRoot = GUIDFromStringW(pu.pszSuffix, &clsid) ? &clsid : NULL;
  778. // path might come from the registry
  779. // if nothing was passed in.
  780. if (!*pszUrl && GetRootFromRootClass(pclsidRoot, szField, ARRAYSIZE(szField)))
  781. {
  782. pszUrl = szField;
  783. }
  784. if (pclsidRoot || *pszUrl)
  785. {
  786. LPITEMIDLIST pidlRoot = ILCreateFromPathW(pszUrl);
  787. // fix up bad cmd line "explorer.exe /root," case
  788. if (!pidlRoot)
  789. SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidlRoot);
  790. if (pidlRoot)
  791. {
  792. *ppidl = ILRootedCreateIDList(pclsidRoot, pidlRoot);
  793. if (*ppidl)
  794. {
  795. hr = S_OK;
  796. }
  797. ILFree(pidlRoot);
  798. }
  799. }
  800. }
  801. return hr;
  802. }
  803. STDMETHODIMP CIDListUrlStub::ParseDisplayName(HWND hwnd, LPBC pbc, WCHAR *pwzDisplayName,
  804. ULONG *pchEaten, LPITEMIDLIST *ppidl, ULONG *pdwAttributes)
  805. {
  806. // Need to keep the internet SF from getting a chance to parse
  807. HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
  808. PARSEDURLW pu = {0};
  809. pu.cbSize = sizeof(pu);
  810. ParseURLW(pwzDisplayName, &pu);
  811. ASSERT(pu.nScheme == URL_SCHEME_MSSHELLIDLIST);
  812. LPCWSTR psz = pu.pszSuffix;
  813. if (psz)
  814. {
  815. HANDLE hMem = LongToHandle(StrToIntW(psz));
  816. psz = StrChrW(psz, TEXT(':'));
  817. if (psz++)
  818. {
  819. DWORD dwProcId = (DWORD)StrToIntW(psz);
  820. LPITEMIDLIST pidlGlobal = (LPITEMIDLIST)SHLockShared(hMem, dwProcId);
  821. if (pidlGlobal)
  822. {
  823. hr = SHILClone(pidlGlobal, ppidl);
  824. SHUnlockShared(pidlGlobal);
  825. SHFreeShared(hMem, dwProcId);
  826. }
  827. }
  828. }
  829. return hr;
  830. }
  831. STDMETHODIMP CFileUrlStub::ParseDisplayName(HWND hwnd, LPBC pbc, WCHAR *pwzDisplayName,
  832. ULONG *pchEaten, LPITEMIDLIST *ppidl, ULONG *pdwAttributes)
  833. {
  834. LPCWSTR pszFragment = UrlGetLocationW(pwzDisplayName);
  835. WCHAR szPath[MAX_URL_STRING];
  836. DWORD cchPath = ARRAYSIZE(szPath);
  837. WCHAR szQuery[MAX_URL_STRING];
  838. DWORD cchQuery = ARRAYSIZE(szQuery) - 1;
  839. // We want to remove QUERY and FRAGMENT sections of
  840. // FILE URLs because they need to be added in "Hidden" pidls.
  841. // Also, URLs need to be escaped all the time except for paths
  842. // to facility parsing and because we already removed all other
  843. // parts of the URL (Query and Fragment).
  844. ASSERT(UrlIsW(pwzDisplayName, URLIS_FILEURL));
  845. if (SUCCEEDED(UrlGetPartW(pwzDisplayName, szQuery+1, &cchQuery, URL_PART_QUERY, 0)) && cchQuery)
  846. szQuery[0] = TEXT('?');
  847. else
  848. szQuery[0] = 0;
  849. if (SUCCEEDED(PathCreateFromUrlW(pwzDisplayName, szPath, &cchPath, 0)))
  850. {
  851. // WARNING - we skip supporting simple ids here
  852. ILCreateFromPathEx(szPath, NULL, ILCFP_FLAG_NORMAL, ppidl, pdwAttributes);
  853. if (*ppidl && pszFragment)
  854. {
  855. *ppidl = ILAppendHiddenStringW(*ppidl, IDLHID_URLFRAGMENT, pszFragment);
  856. }
  857. if (*ppidl && szQuery[0] == TEXT('?'))
  858. {
  859. *ppidl = ILAppendHiddenStringW(*ppidl, IDLHID_URLQUERY, szQuery);
  860. }
  861. E_OUTOFMEMORY;
  862. }
  863. // Need to keep the internet SF from getting a chance to parse
  864. return *ppidl ? S_OK : HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
  865. }
  866. STDAPI_(int) SHGetSpecialFolderID(LPCWSTR pszName);
  867. //
  868. // Given a string of the form
  869. //
  870. // programs\My Pictures\Vacation
  871. //
  872. //
  873. // return CSIDL_PROGRAMS and set ppwszUnparsed to "My Pictures\Vacation".
  874. //
  875. // If there is no backslash, then ppwszUnparsed = NULL.
  876. //
  877. // This function is broken out of CShellUrlStub::ParseDisplayName() to conserve stack space,
  878. // since ParseDisplayName is used by 16-bit ShellExecute.
  879. STDAPI_(int) _ParseSpecialFolder(LPCWSTR pszName, LPWSTR *ppwszUnparsed, ULONG *pcchEaten)
  880. {
  881. LPCWSTR pwszKey;
  882. WCHAR wszKey[MAX_PATH];
  883. LPWSTR pwszBS = StrChrW(pszName, L'\\');
  884. if (pwszBS)
  885. {
  886. *ppwszUnparsed = pwszBS + 1;
  887. *pcchEaten = (ULONG)(pwszBS + 1 - pszName);
  888. StrCpyNW(wszKey, pszName, min(*pcchEaten, MAX_PATH));
  889. pwszKey = wszKey;
  890. }
  891. else
  892. {
  893. *ppwszUnparsed = NULL;
  894. pwszKey = pszName;
  895. *pcchEaten = lstrlenW(pwszKey);
  896. }
  897. return SHGetSpecialFolderID(pwszKey);
  898. }
  899. STDMETHODIMP CShellUrlStub::ParseDisplayName(HWND hwnd,
  900. LPBC pbc, WCHAR *pwzDisplayName, ULONG *pchEaten,
  901. LPITEMIDLIST *ppidl, ULONG *pdwAttributes)
  902. {
  903. PARSEDURLW pu = {0};
  904. pu.cbSize = sizeof(pu);
  905. EVAL(SUCCEEDED(ParseURLW(pwzDisplayName, &pu)));
  906. // Need to keep the internet SF from getting a chance to parse
  907. // the shell: URLs even if we fail to parse it
  908. HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
  909. ASSERT(pu.nScheme == URL_SCHEME_SHELL);
  910. // shell:::{guid}
  911. if (pu.pszSuffix[0] == L':' && pu.pszSuffix[1] == L':')
  912. {
  913. IShellFolder *psfDesktop;
  914. hr = SHGetDesktopFolder(&psfDesktop);
  915. if (SUCCEEDED(hr))
  916. {
  917. IBindCtx *pbcCreate = NULL;
  918. hr = CreateBindCtx(0, &pbcCreate);
  919. if (SUCCEEDED(hr))
  920. {
  921. BIND_OPTS bo = {sizeof(bo)}; // Requires size filled in.
  922. bo.grfMode = STGM_CREATE;
  923. pbcCreate->SetBindOptions(&bo);
  924. hr = psfDesktop->ParseDisplayName(hwnd, pbcCreate, (LPWSTR)pu.pszSuffix, pchEaten, ppidl, pdwAttributes);
  925. pbcCreate->Release();
  926. }
  927. psfDesktop->Release();
  928. }
  929. }
  930. else
  931. { // shell:personal\My Pictures
  932. LPWSTR pwszUnparsed = NULL;
  933. ULONG cchEaten;
  934. int csidl = _ParseSpecialFolder(pu.pszSuffix, &pwszUnparsed, &cchEaten);
  935. if (-1 != csidl)
  936. {
  937. LPITEMIDLIST pidlCSIDL;
  938. hr = SHGetFolderLocation(hwnd, csidl | CSIDL_FLAG_CREATE, NULL, 0, &pidlCSIDL);
  939. if (SUCCEEDED(hr))
  940. {
  941. if (pwszUnparsed && *pwszUnparsed)
  942. {
  943. IShellFolder *psf;
  944. hr = SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder, pidlCSIDL, &psf));
  945. if (SUCCEEDED(hr))
  946. {
  947. LPITEMIDLIST pidlChild;
  948. hr = psf->ParseDisplayName(hwnd, pbc, pwszUnparsed, pchEaten, &pidlChild, pdwAttributes);
  949. if (SUCCEEDED(hr))
  950. {
  951. hr = SHILCombine(pidlCSIDL, pidlChild, ppidl);
  952. ILFree(pidlChild);
  953. if (pchEaten)
  954. {
  955. *pchEaten += cchEaten;
  956. }
  957. }
  958. psf->Release();
  959. }
  960. ILFree(pidlCSIDL);
  961. }
  962. else
  963. {
  964. if (pdwAttributes && *pdwAttributes)
  965. {
  966. hr = SHGetNameAndFlags(pidlCSIDL, 0, NULL, 0, pdwAttributes);
  967. }
  968. if (SUCCEEDED(hr))
  969. {
  970. if (pchEaten) *pchEaten = cchEaten;
  971. *ppidl = pidlCSIDL;
  972. }
  973. else
  974. {
  975. ILFree(pidlCSIDL);
  976. }
  977. }
  978. }
  979. }
  980. }
  981. return hr;
  982. }
  983. // key for the DAVRDR so that we can read the localised provider name.
  984. #define DAVRDR_KEY TEXT("SYSTEM\\CurrentControlSet\\Services\\WebClient\\NetworkProvider")
  985. STDMETHODIMP CHttpUrlStub::ParseDisplayName(HWND hwnd,
  986. LPBC pbc, WCHAR *pwzDisplayName, ULONG *pchEaten,
  987. LPITEMIDLIST *ppidl, ULONG *pdwAttributes)
  988. {
  989. HRESULT hr = E_INVALIDARG;
  990. PARSEDURLW pu = {0};
  991. pu.cbSize = sizeof(pu);
  992. ParseURLW(pwzDisplayName, &pu);
  993. // we cant handle anything but simple URLs here, and only HTTP (not HTTPS).
  994. if (!UrlGetLocationW(pwzDisplayName)
  995. && !StrChrW(pu.pszSuffix, L'?')
  996. && (lstrlen(pu.pszSuffix) < MAX_PATH)
  997. && (pu.nScheme == URL_SCHEME_HTTP))
  998. {
  999. // convert from wacky http: to something that the RDR will pick up as a UNC,
  1000. // given that this is being forwarded directly to the DAV RDR.
  1001. //
  1002. // http://server/share -> \\server\share
  1003. WCHAR sz[MAX_PATH];
  1004. StrCpyN(sz, pu.pszSuffix, ARRAYSIZE(sz));
  1005. for (LPWSTR psz = sz; *psz; psz++)
  1006. {
  1007. if (*psz == L'/')
  1008. {
  1009. *psz = L'\\';
  1010. }
  1011. }
  1012. // this forces the use of the DavRedir as the provider
  1013. // thus avoiding any confusion...
  1014. IPropertyBag *ppb;
  1015. hr = SHCreatePropertyBagOnMemory(STGM_READWRITE, IID_PPV_ARG(IPropertyBag, &ppb));
  1016. if (SUCCEEDED(hr))
  1017. {
  1018. TCHAR szProvider[MAX_PATH];
  1019. DWORD cbProvider = sizeof (szProvider);
  1020. if (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, DAVRDR_KEY, TEXT("Name"), NULL, szProvider, &cbProvider))
  1021. {
  1022. hr = SHPropertyBag_WriteStr(ppb, STR_PARSE_NETFOLDER_PROVIDERNAME, szProvider);
  1023. if (SUCCEEDED(hr))
  1024. {
  1025. hr = pbc->RegisterObjectParam(STR_PARSE_NETFOLDER_INFO, ppb);
  1026. if (SUCCEEDED(hr))
  1027. {
  1028. // add a UI bindctx if necessary
  1029. IBindCtx *pbcRelease = NULL;
  1030. if (hwnd && !BindCtx_GetUIWindow(pbc))
  1031. {
  1032. // returns a reference to our pbc in pbcRelease
  1033. BindCtx_RegisterUIWindow(pbc, hwnd, &pbcRelease);
  1034. }
  1035. hr = SHParseDisplayName(sz, pbc, ppidl, pdwAttributes ? *pdwAttributes : 0, pdwAttributes);
  1036. if (pbcRelease)
  1037. pbc->Release();
  1038. }
  1039. }
  1040. }
  1041. else
  1042. {
  1043. hr = E_FAIL;
  1044. }
  1045. ppb->Release();
  1046. }
  1047. }
  1048. if (FAILED(hr) && !BindCtx_ContainsObject(pbc, L"BUT NOT WEBFOLDERS"))
  1049. {
  1050. // fall back to webfolders
  1051. LPITEMIDLIST pidlParent = CreateWebFoldersIDList();
  1052. if (pidlParent)
  1053. {
  1054. IShellFolder *psf;
  1055. hr = SHBindToObjectEx(NULL, pidlParent, NULL, IID_PPV_ARG(IShellFolder, &psf));
  1056. if (SUCCEEDED(hr))
  1057. {
  1058. // always pass NULL for the HWND. webfolders shows really bad UI
  1059. LPITEMIDLIST pidlRight;
  1060. hr = psf->ParseDisplayName(NULL, pbc, pwzDisplayName, pchEaten, &pidlRight, pdwAttributes);
  1061. if (SUCCEEDED(hr))
  1062. {
  1063. hr = SHILCombine(pidlParent, pidlRight, ppidl);
  1064. ILFree(pidlRight);
  1065. }
  1066. psf->Release();
  1067. }
  1068. ILFree(pidlParent);
  1069. }
  1070. }
  1071. return hr;
  1072. }
  1073. BOOL CDesktopFolder::_TryUrlJunctions(LPCTSTR pszName, IBindCtx *pbc, IShellFolder **ppsf, LPITEMIDLIST *ppidlLeft)
  1074. {
  1075. PARSEDURL pu = {0};
  1076. pu.cbSize = sizeof(pu);
  1077. EVAL(SUCCEEDED(ParseURL(pszName, &pu)));
  1078. ASSERT(!*ppsf);
  1079. ASSERT(!*ppidlLeft);
  1080. switch (pu.nScheme)
  1081. {
  1082. case URL_SCHEME_SHELL:
  1083. *ppsf = SAFECAST(&_sfShellUrl, IShellFolder *);
  1084. break;
  1085. case URL_SCHEME_FILE:
  1086. *ppsf = SAFECAST(&_sfFileUrl, IShellFolder *);
  1087. break;
  1088. case URL_SCHEME_MSSHELLROOTED:
  1089. *ppsf = SAFECAST(&_sfRooted, IShellFolder *);
  1090. break;
  1091. case URL_SCHEME_MSSHELLIDLIST:
  1092. *ppsf = SAFECAST(&_sfIDListUrl, IShellFolder *);
  1093. break;
  1094. case URL_SCHEME_HTTP:
  1095. case URL_SCHEME_HTTPS:
  1096. if (BindCtx_ContainsObject(pbc, STR_PARSE_PREFER_FOLDER_BROWSING))
  1097. *ppsf = SAFECAST(&_sfHttpUrl, IShellFolder *);
  1098. break;
  1099. default:
  1100. // _TryRegisteredUrlJunction(pu.pszProtocol, pu.cchProtocol, ppsf, ppidlLeft)
  1101. break;
  1102. }
  1103. return (*ppsf || *ppidlLeft);
  1104. }
  1105. BOOL _FailForceReturn(HRESULT hr);
  1106. BOOL CDesktopFolder::_GetFolderForParsing(LPCTSTR pszName, LPBC pbc, IShellFolder **ppsf, LPITEMIDLIST *ppidlLeft)
  1107. {
  1108. ASSERT(!*ppidlLeft);
  1109. ASSERT(!*ppsf);
  1110. if ((InRange(pszName[0], TEXT('A'), TEXT('Z')) ||
  1111. InRange(pszName[0], TEXT('a'), TEXT('z'))) &&
  1112. pszName[1] == TEXT(':'))
  1113. {
  1114. // The string contains a path, let "My Computer" figire it out.
  1115. *ppidlLeft = CreateMyComputerIDList();
  1116. }
  1117. else if (PathIsUNC(pszName))
  1118. {
  1119. // The path is UNC, let "World" figure it out.
  1120. *ppidlLeft = CreateMyNetPlacesIDList();
  1121. }
  1122. else if (UrlIs(pszName, URLIS_URL) && !SHSkipJunctionBinding(pbc, NULL))
  1123. {
  1124. _TryUrlJunctions(pszName, pbc, ppsf, ppidlLeft);
  1125. }
  1126. if (!*ppsf && *ppidlLeft)
  1127. SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder, *ppidlLeft, ppsf));
  1128. return (*ppsf != NULL);
  1129. }
  1130. STDMETHODIMP CDesktopFolder::ParseDisplayName(HWND hwnd,
  1131. LPBC pbc, WCHAR *pwzDisplayName, ULONG *pchEaten,
  1132. LPITEMIDLIST *ppidl, ULONG *pdwAttributes)
  1133. {
  1134. HRESULT hr = E_INVALIDARG;
  1135. if (ppidl)
  1136. {
  1137. *ppidl = NULL; // assume error
  1138. if (pwzDisplayName && *pwzDisplayName)
  1139. {
  1140. LPITEMIDLIST pidlLeft = NULL;
  1141. IShellFolder *psfRight = NULL;
  1142. ASSERT(hr == E_INVALIDARG);
  1143. if (_GetFolderForParsing(pwzDisplayName, pbc, &psfRight, &pidlLeft))
  1144. {
  1145. if (pchEaten)
  1146. *pchEaten = 0;
  1147. hr = _ChildParseDisplayName(psfRight, pidlLeft, hwnd, pbc, pwzDisplayName, pchEaten, ppidl, pdwAttributes);
  1148. ILFree(pidlLeft);
  1149. psfRight->Release();
  1150. }
  1151. if (SUCCEEDED(hr))
  1152. {
  1153. // translate aliases here for goodness sake
  1154. if (BindCtx_ContainsObject(pbc, STR_PARSE_TRANSLATE_ALIASES))
  1155. {
  1156. LPITEMIDLIST pidlAlias;
  1157. if (SUCCEEDED(SHILAliasTranslate(*ppidl, &pidlAlias, XLATEALIAS_ALL)))
  1158. {
  1159. ILFree(*ppidl);
  1160. *ppidl = pidlAlias;
  1161. }
  1162. }
  1163. }
  1164. else if (FAILED(hr) && !_FailForceReturn(hr))
  1165. {
  1166. //
  1167. // MIL 131297 - desktop did not support relative simple parses - ZekeL - 3-FEB-2000
  1168. // it was only the roots (drives/net) that would create simple IDs
  1169. // so for some apps we need to still not do it.
  1170. //
  1171. if (BindCtx_ContainsObject(pbc, STR_DONT_PARSE_RELATIVE))
  1172. {
  1173. // we're told not to parse relative paths and _GetFolderForParsing failed
  1174. // so act like we don't think the path exists.
  1175. hr = E_INVALIDARG;
  1176. }
  1177. else if (S_OK != SHIsFileSysBindCtx(pbc, NULL))
  1178. {
  1179. // when we request that something be created, we need to
  1180. // check both folders and make sure that it doesnt exist in
  1181. // either one. and then try and create it in the user folder
  1182. BIND_OPTS bo = {sizeof(bo)};
  1183. BOOL fCreate = FALSE;
  1184. if (pbc && SUCCEEDED(pbc->GetBindOptions(&bo)) &&
  1185. (bo.grfMode & STGM_CREATE))
  1186. {
  1187. fCreate = TRUE;
  1188. bo.grfMode &= ~STGM_CREATE;
  1189. pbc->SetBindOptions(&bo);
  1190. }
  1191. // give the users desktop first shot.
  1192. // This must be a desktop item, _psfDesktop may not be inited in
  1193. // the case where we are called from ILCreateFromPath()
  1194. if (_psfDesktop)
  1195. hr = _psfDesktop->ParseDisplayName(hwnd, pbc, pwzDisplayName, pchEaten, ppidl, pdwAttributes);
  1196. // if the normal desktop folder didnt pick it off,
  1197. // it could be in the allusers folder. give psfAlt a chance.
  1198. if (FAILED(hr) && _psfAltDesktop)
  1199. {
  1200. hr = _psfAltDesktop->ParseDisplayName(hwnd, pbc, pwzDisplayName, pchEaten, ppidl, pdwAttributes);
  1201. }
  1202. // neither of the folders can identify an existing item
  1203. // so we should pass the create flag to the real desktop
  1204. if (FAILED(hr) && fCreate && _psfDesktop)
  1205. {
  1206. bo.grfMode |= STGM_CREATE;
  1207. pbc->SetBindOptions(&bo);
  1208. hr = _psfDesktop->ParseDisplayName(hwnd, pbc, pwzDisplayName, pchEaten, ppidl, pdwAttributes);
  1209. // when this succeeds, we know we got a magical ghost pidl...
  1210. }
  1211. }
  1212. }
  1213. }
  1214. else if (pwzDisplayName)
  1215. {
  1216. // we used to return this pidl when passed an empty string
  1217. // some apps (such as Wright Design) depend on this behavior
  1218. hr = SHILClone((LPCITEMIDLIST)&c_idlDrives, ppidl);
  1219. }
  1220. }
  1221. return hr;
  1222. }
  1223. STDAPI_(void) UltRoot_Term()
  1224. {
  1225. if (g_pDesktopFolder)
  1226. {
  1227. g_pDesktopFolder->_Destroy();
  1228. g_pDesktopFolder = NULL;
  1229. }
  1230. }
  1231. HRESULT CDesktopFolder::EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenum)
  1232. {
  1233. *ppenum = new CDesktopFolderEnum(this, hwnd, grfFlags);
  1234. return *ppenum ? S_OK : E_OUTOFMEMORY;
  1235. }
  1236. STDMETHODIMP CDesktopFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  1237. {
  1238. // note: using IsSelf() here will cause a problem with WinZip. they expect
  1239. // failure when they pass an empty pidl. SHBindToOjbect() has the special
  1240. // case for the desktop, so it is not needed here.
  1241. IShellFolder2 *psf = _GetItemFolder(pidl);
  1242. if (psf)
  1243. return psf->BindToObject(pidl, pbc, riid, ppv);
  1244. return E_UNEXPECTED;
  1245. }
  1246. STDMETHODIMP CDesktopFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  1247. {
  1248. return BindToObject(pidl, pbc, riid, ppv);
  1249. }
  1250. STDMETHODIMP CDesktopFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  1251. {
  1252. if (pidl1 == NULL || pidl2 == NULL)
  1253. return E_INVALIDARG;
  1254. if (pidl1->mkid.cb == 0 && pidl2->mkid.cb == 0)
  1255. return ResultFromShort(0); // 2 empty IDLists, they are the same
  1256. if (ILIsRooted(pidl1) || ILIsRooted(pidl2))
  1257. {
  1258. return _sfRooted.CompareIDs(lParam, pidl1, pidl2);
  1259. }
  1260. // If both objects aren't from the same directory, they won't match.
  1261. else if (_psfAltDesktop)
  1262. {
  1263. if (CFSFolder_IsCommonItem(pidl1))
  1264. {
  1265. if (CFSFolder_IsCommonItem(pidl2))
  1266. return _psfAltDesktop->CompareIDs(lParam, pidl1, pidl2);
  1267. else
  1268. return ResultFromShort(-1);
  1269. }
  1270. else
  1271. {
  1272. if (CFSFolder_IsCommonItem(pidl2))
  1273. return ResultFromShort(1);
  1274. else if (_psfDesktop)
  1275. return _psfDesktop->CompareIDs(lParam, pidl1, pidl2);
  1276. }
  1277. }
  1278. else if (_psfDesktop)
  1279. {
  1280. return _psfDesktop->CompareIDs(lParam, pidl1, pidl2);
  1281. }
  1282. // If we have no _psfDesktop, we get here...
  1283. return ResultFromShort(-1);
  1284. }
  1285. HRESULT CDesktopFolder::_BGCommand(HWND hwnd, WPARAM wparam, BOOL bExecute)
  1286. {
  1287. HRESULT hr = S_OK;
  1288. switch (wparam)
  1289. {
  1290. case DFM_CMD_PROPERTIES:
  1291. case FSIDM_PROPERTIESBG:
  1292. if (bExecute)
  1293. {
  1294. // run the default applet in desk.cpl
  1295. if (SHRunControlPanel( TEXT("desk.cpl"), hwnd ))
  1296. hr = S_OK;
  1297. else
  1298. hr = E_OUTOFMEMORY;
  1299. }
  1300. break;
  1301. case DFM_CMD_MOVE:
  1302. case DFM_CMD_COPY:
  1303. hr = E_FAIL;
  1304. break;
  1305. default:
  1306. // This is common menu items, use the default code.
  1307. hr = S_FALSE;
  1308. break;
  1309. }
  1310. return hr;
  1311. }
  1312. // IContextMenuCB::CallBack for the background context menu
  1313. //
  1314. // Returns:
  1315. // S_OK, if successfully processed.
  1316. // S_FALSE, if default code should be used.
  1317. STDMETHODIMP CDesktopFolder::CallBack(IShellFolder *psf, HWND hwnd, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1318. {
  1319. HRESULT hr = S_OK;
  1320. switch (uMsg)
  1321. {
  1322. case DFM_MERGECONTEXTMENU_BOTTOM:
  1323. if (!(wParam & (CMF_VERBSONLY | CMF_DVFILE)))
  1324. {
  1325. // Only add the desktop background Properties iff we're the real desktop browser
  1326. // (i.e., we don't want it when in explorer)
  1327. //
  1328. if (IsDesktopBrowser(_punkSite))
  1329. {
  1330. LPQCMINFO pqcm = (LPQCMINFO)lParam;
  1331. UINT idCmdFirst = pqcm->idCmdFirst;
  1332. CDefFolderMenu_MergeMenu(HINST_THISDLL, POPUP_PROPERTIES_BG, 0, pqcm);
  1333. }
  1334. }
  1335. break;
  1336. case DFM_GETHELPTEXT:
  1337. LoadStringA(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPSTR)lParam, HIWORD(wParam));;
  1338. break;
  1339. case DFM_GETHELPTEXTW:
  1340. LoadStringW(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPWSTR)lParam, HIWORD(wParam));;
  1341. break;
  1342. case DFM_INVOKECOMMAND:
  1343. case DFM_VALIDATECMD:
  1344. hr = _BGCommand(hwnd, wParam, uMsg == DFM_INVOKECOMMAND);
  1345. break;
  1346. default:
  1347. hr = E_NOTIMPL;
  1348. break;
  1349. }
  1350. return hr;
  1351. }
  1352. // IItemNameLimits
  1353. STDMETHODIMP CDesktopFolder::GetValidCharacters(LPWSTR *ppwszValidChars, LPWSTR *ppwszInvalidChars)
  1354. {
  1355. IItemNameLimits *pinl;
  1356. HRESULT hr = _QueryInterfaceItem(NULL, IID_PPV_ARG(IItemNameLimits, &pinl));
  1357. if (SUCCEEDED(hr))
  1358. {
  1359. hr = pinl->GetValidCharacters(ppwszValidChars, ppwszInvalidChars);
  1360. pinl->Release();
  1361. }
  1362. return hr;
  1363. }
  1364. STDMETHODIMP CDesktopFolder::GetMaxLength(LPCWSTR pszName, int *piMaxNameLen)
  1365. {
  1366. // delegate to per user or common based on which name space
  1367. // pszName is from (we have to search for that)
  1368. IItemNameLimits *pinl;
  1369. HRESULT hr = _QueryInterfaceItem(NULL, IID_PPV_ARG(IItemNameLimits, &pinl));
  1370. if (SUCCEEDED(hr))
  1371. {
  1372. hr = pinl->GetMaxLength(pszName, piMaxNameLen);
  1373. pinl->Release();
  1374. }
  1375. return hr;
  1376. }
  1377. // IOleCommandTarget stuff
  1378. STDMETHODIMP CDesktopFolder::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
  1379. {
  1380. return IUnknown_QueryStatus(_psfDesktop, pguidCmdGroup, cCmds, rgCmds, pcmdtext);
  1381. }
  1382. STDMETHODIMP CDesktopFolder::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
  1383. {
  1384. // invalidate our cache
  1385. // which we dont really have right now.
  1386. // but CFSFolder does
  1387. IUnknown_Exec(_psfAltDesktop, pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
  1388. return IUnknown_Exec(_psfDesktop, pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
  1389. }
  1390. STDMETHODIMP CDesktopFolder::CreateViewObject(HWND hwnd, REFIID riid, void **ppv)
  1391. {
  1392. HRESULT hr = E_NOINTERFACE;
  1393. *ppv = NULL;
  1394. if (IsEqualIID(riid, IID_IShellView))
  1395. {
  1396. IShellFolderViewCB* psfvcb;
  1397. if (SUCCEEDED(Create_CDesktopViewCallback(this, &psfvcb)))
  1398. {
  1399. SFV_CREATE sfvc = {0};
  1400. sfvc.cbSize = sizeof(sfvc);
  1401. sfvc.psfvcb = psfvcb;
  1402. hr = QueryInterface(IID_PPV_ARG(IShellFolder, &sfvc.pshf)); // in case we are agregated
  1403. if (SUCCEEDED(hr))
  1404. {
  1405. hr = SHCreateShellFolderView(&sfvc, (IShellView**)ppv);
  1406. sfvc.pshf->Release();
  1407. }
  1408. psfvcb->Release();
  1409. }
  1410. }
  1411. else if (IsEqualIID(riid, IID_IDropTarget) && _psfDesktop)
  1412. {
  1413. IDropTarget* pdt;
  1414. if (SUCCEEDED(_psfDesktop->CreateViewObject(hwnd, riid, (void**)&pdt)))
  1415. {
  1416. CDesktopFolderDropTarget* pdfdt = new CDesktopFolderDropTarget(pdt);
  1417. if (pdfdt)
  1418. {
  1419. hr = pdfdt->QueryInterface(IID_PPV_ARG(IDropTarget, (IDropTarget**)ppv));
  1420. pdfdt->Release();
  1421. }
  1422. pdt->Release();
  1423. }
  1424. }
  1425. else if (IsEqualIID(riid, IID_IContextMenu))
  1426. {
  1427. IShellFolder *psfTemp;
  1428. hr = QueryInterface(IID_PPV_ARG(IShellFolder, &psfTemp));
  1429. if (SUCCEEDED(hr))
  1430. {
  1431. HKEY hkNoFiles = NULL;
  1432. RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("Directory\\Background"), 0, KEY_READ, &hkNoFiles);
  1433. hr = CDefFolderMenu_Create2Ex(&c_idlDesktop, hwnd, 0, NULL,
  1434. psfTemp, this, 1, &hkNoFiles, (IContextMenu **)ppv);
  1435. psfTemp->Release();
  1436. RegCloseKey(hkNoFiles);
  1437. }
  1438. }
  1439. return hr;
  1440. }
  1441. STDMETHODIMP CDesktopFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, ULONG *rgfOut)
  1442. {
  1443. if (IsSelf(cidl, apidl))
  1444. {
  1445. *rgfOut &= SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR | SFGAO_STORAGEANCESTOR | SFGAO_STORAGE;
  1446. return S_OK;
  1447. }
  1448. IShellFolder2 *psf = _GetItemFolder(apidl[0]);
  1449. if (psf)
  1450. return psf->GetAttributesOf(cidl, apidl, rgfOut);
  1451. return E_UNEXPECTED;
  1452. }
  1453. HRESULT CDesktopFolder::_SelfAssocCreate(REFIID riid, void **ppv)
  1454. {
  1455. *ppv = NULL;
  1456. IQueryAssociations *pqa;
  1457. HRESULT hr = AssocCreate(CLSID_QueryAssociations, IID_PPV_ARG(IQueryAssociations, &pqa));
  1458. if (SUCCEEDED(hr))
  1459. {
  1460. hr = pqa->Init(ASSOCF_INIT_DEFAULTTOFOLDER, L"{00021400-0000-0000-C000-000000000046}", // CLSID_ShellDesktop
  1461. NULL, NULL);
  1462. if (SUCCEEDED(hr))
  1463. {
  1464. hr = pqa->QueryInterface(riid, ppv);
  1465. }
  1466. pqa->Release();
  1467. }
  1468. return hr;
  1469. }
  1470. STDAPI _DeskContextMenuCB(IShellFolder *psf, HWND hwnd, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1471. {
  1472. // The "safe" thing to return is usually E_NOTIMPL, but some messages
  1473. // have special return values.
  1474. HRESULT hr;
  1475. switch (uMsg)
  1476. {
  1477. case DFM_VALIDATECMD:
  1478. hr = S_FALSE;
  1479. break;
  1480. case DFM_INVOKECOMMAND:
  1481. if (wParam == DFM_CMD_PROPERTIES)
  1482. {
  1483. // Properties should act like Properties on the background
  1484. SHRunControlPanel(TEXT("desk.cpl"), hwnd);
  1485. hr = S_OK;
  1486. }
  1487. else
  1488. hr = S_FALSE;
  1489. break;
  1490. case DFM_MERGECONTEXTMENU:
  1491. hr = S_OK;
  1492. break;
  1493. default:
  1494. hr = E_NOTIMPL;
  1495. break;
  1496. }
  1497. return hr;
  1498. }
  1499. HRESULT CDesktopFolder::_SelfCreateContextMenu(HWND hwnd, void **ppv)
  1500. {
  1501. *ppv = NULL;
  1502. IQueryAssociations *pqa;
  1503. HRESULT hr = _SelfAssocCreate(IID_PPV_ARG(IQueryAssociations, &pqa));
  1504. if (SUCCEEDED(hr))
  1505. {
  1506. HKEY ahkeys[2] = { NULL, NULL };
  1507. DWORD cKeys = SHGetAssocKeys(pqa, ahkeys, ARRAYSIZE(ahkeys));
  1508. pqa->Release();
  1509. // We must pass cidl=1 apidl=&pidlDesktop to ensure that an
  1510. // IDataObject is created,
  1511. // or Symantec Internet FastFind ALERTEX.DLL will fault.
  1512. LPCITEMIDLIST pidlDesktop = DESKTOP_PIDL;
  1513. hr = CDefFolderMenu_Create2(&c_idlDesktop, hwnd, 1, &pidlDesktop, this, _DeskContextMenuCB,
  1514. ARRAYSIZE(ahkeys), ahkeys, (IContextMenu **)ppv);
  1515. SHRegCloseKeys(ahkeys, ARRAYSIZE(ahkeys));
  1516. }
  1517. return hr;
  1518. }
  1519. HRESULT CDesktopFolder::_GetItemUIObject(HWND hwnd, UINT cidl, LPCITEMIDLIST *apidl,
  1520. REFIID riid, UINT *prgfInOut, void **ppv)
  1521. {
  1522. IShellFolder2 *psf = _GetItemFolder(apidl[0]);
  1523. if (psf)
  1524. return psf->GetUIObjectOf(hwnd, cidl, apidl, riid, prgfInOut, ppv);
  1525. return E_UNEXPECTED;
  1526. }
  1527. STDMETHODIMP CDesktopFolder::GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST *apidl,
  1528. REFIID riid, UINT *prgfInOut, void **ppv)
  1529. {
  1530. HRESULT hr = E_NOINTERFACE;
  1531. *ppv = NULL;
  1532. if (IsSelf(cidl, apidl))
  1533. {
  1534. // for the desktop itself
  1535. if (IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW))
  1536. {
  1537. hr = SHCreateDefExtIcon(NULL, II_DESKTOP, II_DESKTOP, GIL_PERCLASS, II_DESKTOP, riid, ppv);
  1538. }
  1539. else if (IsEqualIID(riid, IID_IQueryInfo))
  1540. {
  1541. hr = CreateInfoTipFromText(MAKEINTRESOURCE(IDS_FOLDER_DESKTOP_TT), riid, ppv);
  1542. }
  1543. else if (IsEqualIID(riid, IID_IContextMenu))
  1544. {
  1545. hr = _SelfCreateContextMenu(hwnd, ppv);
  1546. }
  1547. else if (IsEqualIID(riid, IID_IDropTarget))
  1548. {
  1549. hr = _psfDesktop->CreateViewObject(hwnd, riid, ppv);
  1550. }
  1551. else if (IsEqualIID(riid, IID_IDataObject))
  1552. {
  1553. // Must create with 1 pidl inside that maps to the desktop.
  1554. // Otherwise, CShellExecMenu::InvokeCommand will punt.
  1555. LPCITEMIDLIST pidlDesktop = DESKTOP_PIDL;
  1556. hr = SHCreateFileDataObject(&c_idlDesktop, 1, &pidlDesktop, NULL, (IDataObject **)ppv);
  1557. }
  1558. // Nobody seems to mind if we don't provide this
  1559. // so don't give one out because AssocCreate is slow.
  1560. // else if (IsEqualIID(riid, IID_IQueryAssociations))
  1561. // {
  1562. // hr = _SelfAssocCreate(riid, ppv);
  1563. // }
  1564. }
  1565. else
  1566. {
  1567. hr = _GetItemUIObject(hwnd, cidl, apidl, riid, prgfInOut, ppv);
  1568. }
  1569. return hr;
  1570. }
  1571. STDMETHODIMP CDesktopFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, STRRET *pStrRet)
  1572. {
  1573. HRESULT hr;
  1574. if (IsSelf(1, &pidl))
  1575. {
  1576. if ((dwFlags & (SHGDN_FORPARSING | SHGDN_INFOLDER | SHGDN_FORADDRESSBAR)) == SHGDN_FORPARSING)
  1577. {
  1578. // note some ISV apps puke if we return a full name here but the
  1579. // rest of the shell depends on this...
  1580. TCHAR szPath[MAX_PATH];
  1581. SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, szPath);
  1582. hr = StringToStrRet(szPath, pStrRet);
  1583. }
  1584. else
  1585. hr = ResToStrRet(IDS_DESKTOP, pStrRet); // display name, "Desktop"
  1586. }
  1587. else
  1588. {
  1589. IShellFolder2 *psf = _GetItemFolder(pidl);
  1590. if (psf)
  1591. hr = psf->GetDisplayNameOf(pidl, dwFlags, pStrRet);
  1592. else
  1593. hr = E_UNEXPECTED;
  1594. }
  1595. return hr;
  1596. }
  1597. STDMETHODIMP CDesktopFolder::SetNameOf(HWND hwnd, LPCITEMIDLIST pidl,
  1598. LPCOLESTR pszName, DWORD dwRes, LPITEMIDLIST *ppidlOut)
  1599. {
  1600. IShellFolder2 *psf = _GetItemFolder(pidl);
  1601. if (psf)
  1602. return psf->SetNameOf(hwnd, pidl, pszName, dwRes, ppidlOut);
  1603. return E_UNEXPECTED;
  1604. }
  1605. STDMETHODIMP CDesktopFolder::GetDefaultSearchGUID(GUID *pGuid)
  1606. {
  1607. return E_NOTIMPL;
  1608. }
  1609. STDMETHODIMP CDesktopFolder::EnumSearches(LPENUMEXTRASEARCH *ppenum)
  1610. {
  1611. *ppenum = NULL;
  1612. return E_NOTIMPL;
  1613. }
  1614. STDMETHODIMP CDesktopFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
  1615. {
  1616. if (_psfDesktop)
  1617. return _psfDesktop->GetDefaultColumn(dwRes, pSort, pDisplay);
  1618. return E_UNEXPECTED;
  1619. }
  1620. STDMETHODIMP CDesktopFolder::GetDefaultColumnState(UINT iColumn, DWORD *pdwState)
  1621. {
  1622. if (_psfDesktop)
  1623. return _psfDesktop->GetDefaultColumnState(iColumn, pdwState);
  1624. return E_UNEXPECTED;
  1625. }
  1626. STDMETHODIMP CDesktopFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
  1627. {
  1628. HRESULT hr = E_UNEXPECTED;
  1629. if (IsSelf(1, &pidl))
  1630. {
  1631. if (IsEqualSCID(*pscid, SCID_NAME))
  1632. {
  1633. STRRET strRet;
  1634. hr = GetDisplayNameOf(pidl, SHGDN_NORMAL, &strRet);
  1635. if (SUCCEEDED(hr))
  1636. {
  1637. hr = InitVariantFromStrRet(&strRet, pidl, pv);
  1638. }
  1639. }
  1640. }
  1641. else
  1642. {
  1643. IShellFolder2 *psf = _GetItemFolder(pidl);
  1644. if (psf)
  1645. {
  1646. hr = psf->GetDetailsEx(pidl, pscid, pv);
  1647. }
  1648. }
  1649. return hr;
  1650. }
  1651. STDMETHODIMP CDesktopFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pDetails)
  1652. {
  1653. IShellFolder2 *psf = _GetItemFolder(pidl);
  1654. if (psf)
  1655. return psf->GetDetailsOf(pidl, iColumn, pDetails);
  1656. return E_UNEXPECTED;
  1657. }
  1658. STDMETHODIMP CDesktopFolder::MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid)
  1659. {
  1660. if (_psfDesktop)
  1661. return _psfDesktop->MapColumnToSCID(iColumn, pscid);
  1662. return E_UNEXPECTED;
  1663. }
  1664. STDMETHODIMP CDesktopFolder::GetClassID(CLSID *pCLSID)
  1665. {
  1666. *pCLSID = CLSID_ShellDesktop;
  1667. return S_OK;
  1668. }
  1669. STDMETHODIMP CDesktopFolder::Initialize(LPCITEMIDLIST pidl)
  1670. {
  1671. return ILIsEmpty(pidl) ? S_OK : E_INVALIDARG;
  1672. }
  1673. STDMETHODIMP CDesktopFolder::GetCurFolder(LPITEMIDLIST *ppidl)
  1674. {
  1675. return GetCurFolderImpl(&c_idlDesktop, ppidl);
  1676. }
  1677. STDMETHODIMP CDesktopFolder::TranslateIDs(LONG *plEvent,
  1678. LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2,
  1679. LPITEMIDLIST * ppidlOut1, LPITEMIDLIST * ppidlOut2,
  1680. LONG *plEvent2, LPITEMIDLIST *ppidlOut1Event2,
  1681. LPITEMIDLIST *ppidlOut2Event2)
  1682. {
  1683. *ppidlOut1 = NULL;
  1684. *ppidlOut2 = NULL;
  1685. *plEvent2 = -1;
  1686. *ppidlOut1Event2 = NULL;
  1687. *ppidlOut2Event2 = NULL;
  1688. if (pidl1)
  1689. SHILAliasTranslate(pidl1, ppidlOut1, XLATEALIAS_DESKTOP);
  1690. if (pidl2)
  1691. SHILAliasTranslate(pidl2, ppidlOut2, XLATEALIAS_DESKTOP);
  1692. if (*ppidlOut1 || *ppidlOut2)
  1693. {
  1694. if (!*ppidlOut1)
  1695. *ppidlOut1 = ILClone(pidl1);
  1696. if (!*ppidlOut2)
  1697. *ppidlOut2 = ILClone(pidl2);
  1698. if (*ppidlOut1 || *ppidlOut2)
  1699. {
  1700. return S_OK;
  1701. }
  1702. ILFree(*ppidlOut1);
  1703. ILFree(*ppidlOut2);
  1704. *ppidlOut1 = NULL;
  1705. *ppidlOut2 = NULL;
  1706. }
  1707. return E_FAIL;
  1708. }
  1709. STDMETHODIMP CDesktopFolder::GetIconOf(LPCITEMIDLIST pidl, UINT flags, int *piIndex)
  1710. {
  1711. IShellIcon *psi;
  1712. HRESULT hr = _QueryInterfaceItem(pidl, IID_PPV_ARG(IShellIcon, &psi));
  1713. if (SUCCEEDED(hr))
  1714. {
  1715. hr = psi->GetIconOf(pidl, flags, piIndex);
  1716. psi->Release();
  1717. }
  1718. return hr;
  1719. }
  1720. STDMETHODIMP CDesktopFolder::GetOverlayIndex(LPCITEMIDLIST pidl, int *pIndex)
  1721. {
  1722. IShellIconOverlay *psio;
  1723. HRESULT hr = _QueryInterfaceItem(pidl, IID_PPV_ARG(IShellIconOverlay, &psio));
  1724. if (SUCCEEDED(hr))
  1725. {
  1726. hr = psio->GetOverlayIndex(pidl, pIndex);
  1727. psio->Release();
  1728. }
  1729. return hr;
  1730. }
  1731. STDMETHODIMP CDesktopFolder::GetOverlayIconIndex(LPCITEMIDLIST pidl, int *pIconIndex)
  1732. {
  1733. IShellIconOverlay *psio;
  1734. HRESULT hr = _QueryInterfaceItem(pidl, IID_PPV_ARG(IShellIconOverlay, &psio));
  1735. if (SUCCEEDED(hr))
  1736. {
  1737. hr = psio->GetOverlayIconIndex(pidl, pIconIndex);
  1738. psio->Release();
  1739. }
  1740. return hr;
  1741. }
  1742. // IStorage
  1743. STDMETHODIMP CDesktopFolder::_DeleteItemByIDList(LPCITEMIDLIST pidl)
  1744. {
  1745. IStorage *pstg;
  1746. HRESULT hr = _QueryInterfaceItem(pidl, IID_PPV_ARG(IStorage, &pstg));
  1747. if (SUCCEEDED(hr))
  1748. {
  1749. TCHAR szName[MAX_PATH];
  1750. hr = DisplayNameOf(this, pidl, SHGDN_FORPARSING | SHGDN_INFOLDER, szName, ARRAYSIZE(szName));
  1751. if (SUCCEEDED(hr))
  1752. {
  1753. hr = pstg->DestroyElement(szName);
  1754. }
  1755. pstg->Release();
  1756. }
  1757. return hr;
  1758. }
  1759. STDMETHODIMP CDesktopFolder::_StgCreate(LPCITEMIDLIST pidl, DWORD grfMode, REFIID riid, void **ppv)
  1760. {
  1761. IStorage *pstg;
  1762. HRESULT hr = _QueryInterfaceItem(pidl, IID_PPV_ARG(IStorage, &pstg));
  1763. if (SUCCEEDED(hr))
  1764. {
  1765. TCHAR szName[MAX_PATH];
  1766. hr = DisplayNameOf(this, pidl, SHGDN_FORPARSING | SHGDN_INFOLDER, szName, ARRAYSIZE(szName));
  1767. if (SUCCEEDED(hr))
  1768. {
  1769. if (IsEqualIID(riid, IID_IStorage))
  1770. {
  1771. hr = pstg->CreateStorage(szName, grfMode, 0, 0, (IStorage **) ppv);
  1772. }
  1773. else if (IsEqualIID(riid, IID_IStream))
  1774. {
  1775. hr = pstg->CreateStream(szName, grfMode, 0, 0, (IStream **) ppv);
  1776. }
  1777. else
  1778. {
  1779. hr = E_INVALIDARG;
  1780. }
  1781. }
  1782. pstg->Release();
  1783. }
  1784. return hr;
  1785. }
  1786. #define DESKTOP_EVENTS \
  1787. SHCNE_DISKEVENTS | \
  1788. SHCNE_ASSOCCHANGED | \
  1789. SHCNE_NETSHARE | \
  1790. SHCNE_NETUNSHARE
  1791. HRESULT CDesktopViewCallBack::QueryInterface(REFIID riid, void **ppv)
  1792. {
  1793. HRESULT hr = CBaseShellFolderViewCB::QueryInterface(riid, ppv);
  1794. if (FAILED(hr))
  1795. {
  1796. static const QITAB qit[] = {
  1797. QITABENT(CDesktopViewCallBack, IFolderFilter),
  1798. { 0 },
  1799. };
  1800. hr = QISearch(this, qit, riid, ppv);
  1801. }
  1802. return hr;
  1803. }
  1804. //
  1805. // Copied to shell\applets\cleanup\fldrclnr\cleanupwiz.cpp :CCleanupWiz::_ShouldShow
  1806. // If you modify this, modify that as well
  1807. //
  1808. STDMETHODIMP CDesktopViewCallBack::ShouldShow(IShellFolder* psf, LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlItem)
  1809. {
  1810. HRESULT hr = S_OK; //Assume that this item should be shown!
  1811. if (!_fCheckedIfRealDesktop) //Have we done this check before?
  1812. {
  1813. _fRealDesktop = IsDesktopBrowser(_punkSite);
  1814. _fCheckedIfRealDesktop = TRUE; //Remember this fact!
  1815. }
  1816. if (!_fRealDesktop)
  1817. return S_OK; //Not a real desktop! So, let's show everything!
  1818. IShellFolder2 *psf2;
  1819. if (SUCCEEDED(psf->QueryInterface(IID_PPV_ARG(IShellFolder2, &psf2))))
  1820. {
  1821. // Get the GUID in the pidl, which requires IShellFolder2.
  1822. CLSID guidItem;
  1823. if (SUCCEEDED(GetItemCLSID(psf2, pidlItem, &guidItem)))
  1824. {
  1825. SHELLSTATE ss = {0};
  1826. SHGetSetSettings(&ss, SSF_STARTPANELON, FALSE); //See if the StartPanel is on!
  1827. //Get the proper registry path based on if StartPanel is ON/OFF
  1828. TCHAR szRegPath[MAX_PATH];
  1829. wnsprintf(szRegPath, ARRAYSIZE(szRegPath), REGSTR_PATH_HIDDEN_DESKTOP_ICONS, (ss.fStartPanelOn ? REGSTR_VALUE_STARTPANEL : REGSTR_VALUE_CLASSICMENU));
  1830. //Convert the guid to a string
  1831. TCHAR szGuidValue[MAX_GUID_STRING_LEN];
  1832. SHStringFromGUID(guidItem, szGuidValue, ARRAYSIZE(szGuidValue));
  1833. //See if this item is turned off in the registry.
  1834. if (SHRegGetBoolUSValue(szRegPath, szGuidValue, FALSE, /* default */FALSE))
  1835. hr = S_FALSE; //They want to hide it; So, return S_FALSE.
  1836. }
  1837. psf2->Release();
  1838. }
  1839. return hr;
  1840. }
  1841. STDMETHODIMP CDesktopViewCallBack::GetEnumFlags(IShellFolder* psf, LPCITEMIDLIST pidlFolder, HWND *phwnd, DWORD *pgrfFlags)
  1842. {
  1843. return E_NOTIMPL;
  1844. }
  1845. CDesktopViewCallBack::CDesktopViewCallBack(CDesktopFolder* pdf) :
  1846. CBaseShellFolderViewCB((LPCITEMIDLIST)&c_idlDesktop, DESKTOP_EVENTS),
  1847. _pdf(pdf)
  1848. {
  1849. ASSERT(_fCheckedIfRealDesktop == FALSE);
  1850. ASSERT(_fRealDesktop == FALSE);
  1851. }
  1852. HRESULT Create_CDesktopViewCallback(CDesktopFolder* pdf, IShellFolderViewCB** ppv)
  1853. {
  1854. HRESULT hr;
  1855. CDesktopViewCallBack* p = new CDesktopViewCallBack(pdf);
  1856. if (p)
  1857. {
  1858. *ppv = SAFECAST(p, IShellFolderViewCB*);
  1859. hr = S_OK;
  1860. }
  1861. else
  1862. {
  1863. *ppv = NULL;
  1864. hr = E_OUTOFMEMORY;
  1865. }
  1866. return hr;
  1867. }
  1868. HRESULT CDesktopViewCallBack::OnGETCCHMAX(DWORD pv, LPCITEMIDLIST pidlItem, UINT *pcch)
  1869. {
  1870. HRESULT hr = S_OK;
  1871. if (SIL_GetType(pidlItem) == SHID_ROOT_REGITEM)
  1872. {
  1873. // evil, we should not have to know this
  1874. // make regfldr implement IItemNameLimits and this code won't be needed
  1875. *pcch = MAX_REGITEMCCH;
  1876. }
  1877. else
  1878. {
  1879. TCHAR szName[MAX_PATH];
  1880. if (SUCCEEDED(DisplayNameOf(_pdf, pidlItem, SHGDN_FORPARSING | SHGDN_INFOLDER, szName, ARRAYSIZE(szName))))
  1881. {
  1882. hr = _pdf->GetMaxLength(szName, (int *)pcch);
  1883. }
  1884. }
  1885. return hr;
  1886. }
  1887. HRESULT CDesktopViewCallBack::OnGetWorkingDir(DWORD pv, UINT wP, LPTSTR pszDir)
  1888. {
  1889. return SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, pszDir);
  1890. }
  1891. HRESULT CDesktopViewCallBack::OnGetWebViewTemplate(DWORD pv, UINT uViewMode, SFVM_WEBVIEW_TEMPLATE_DATA* pvi)
  1892. {
  1893. HRESULT hr = E_FAIL;
  1894. if (IsDesktopBrowser(_punkSite))
  1895. {
  1896. // It's the actual desktop, use desstop.htt (from the desktop CLSID)
  1897. //
  1898. hr = DefaultGetWebViewTemplateFromClsid(CLSID_ShellDesktop, pvi);
  1899. }
  1900. return hr;
  1901. }
  1902. HRESULT CDesktopViewCallBack::OnGetWebViewLayout(DWORD pv, UINT uViewMode, SFVM_WEBVIEW_LAYOUT_DATA* pData)
  1903. {
  1904. ZeroMemory(pData, sizeof(*pData));
  1905. pData->dwLayout = SFVMWVL_NORMAL | SFVMWVL_FILES;
  1906. return S_OK;
  1907. }
  1908. STDMETHODIMP CDesktopViewCallBack::RealMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
  1909. {
  1910. switch (uMsg)
  1911. {
  1912. HANDLE_MSG(0, SFVM_GETCCHMAX, OnGETCCHMAX);
  1913. HANDLE_MSG(0, SFVM_GETWEBVIEW_TEMPLATE, OnGetWebViewTemplate);
  1914. HANDLE_MSG(0, SFVM_GETWORKINGDIR, OnGetWorkingDir);
  1915. HANDLE_MSG(0, SFVM_GETWEBVIEWLAYOUT, OnGetWebViewLayout);
  1916. default:
  1917. return E_FAIL;
  1918. }
  1919. return S_OK;
  1920. }
  1921. CDesktopFolderDropTarget::CDesktopFolderDropTarget(IDropTarget* pdt) : _cRef(1)
  1922. {
  1923. pdt->QueryInterface(IID_PPV_ARG(IDropTarget, &_pdt));
  1924. }
  1925. CDesktopFolderDropTarget::~CDesktopFolderDropTarget()
  1926. {
  1927. _pdt->Release();
  1928. }
  1929. STDMETHODIMP CDesktopFolderDropTarget::QueryInterface(REFIID riid, void **ppv)
  1930. {
  1931. static const QITAB qit[] = {
  1932. QITABENT(CDesktopFolderDropTarget, IDropTarget),
  1933. QITABENT(CDesktopFolderDropTarget, IObjectWithSite),
  1934. { 0 },
  1935. };
  1936. return QISearch(this, qit, riid, ppv);
  1937. }
  1938. STDMETHODIMP_(ULONG) CDesktopFolderDropTarget::AddRef()
  1939. {
  1940. return InterlockedIncrement(&_cRef);
  1941. }
  1942. STDMETHODIMP_(ULONG) CDesktopFolderDropTarget::Release()
  1943. {
  1944. ASSERT( 0 != _cRef );
  1945. ULONG cRef = InterlockedDecrement(&_cRef);
  1946. if ( 0 == cRef )
  1947. {
  1948. delete this;
  1949. }
  1950. return cRef;
  1951. }
  1952. // IDropTarget
  1953. HRESULT CDesktopFolderDropTarget::DragEnter(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
  1954. {
  1955. return _pdt->DragEnter(pDataObject, grfKeyState, pt, pdwEffect);
  1956. }
  1957. HRESULT CDesktopFolderDropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
  1958. {
  1959. return _pdt->DragOver(grfKeyState, pt, pdwEffect);
  1960. }
  1961. HRESULT CDesktopFolderDropTarget::DragLeave(void)
  1962. {
  1963. return _pdt->DragLeave();
  1964. }
  1965. HRESULT CDesktopFolderDropTarget::SetSite(IN IUnknown * punkSite)
  1966. {
  1967. IUnknown_SetSite(_pdt, punkSite);
  1968. return S_OK;
  1969. }
  1970. BOOL CDesktopFolderDropTarget::_IsSpecialCaseDrop(IDataObject* pDataObject, DWORD dwEffect, BOOL* pfIsPIDA, UINT* pcItems)
  1971. {
  1972. BOOL fIEDropped = FALSE;
  1973. *pfIsPIDA = FALSE;
  1974. // when we drag a fake IE item (filename.CLSID_Internet) back to the desktop, we delete it and unhide the real IE icon
  1975. STGMEDIUM medium = {0};
  1976. LPIDA pida = DataObj_GetHIDA(pDataObject, &medium);
  1977. if (pida)
  1978. {
  1979. for (UINT i = 0; (i < pida->cidl); i++)
  1980. {
  1981. LPITEMIDLIST pidlFull = HIDA_ILClone(pida, i);
  1982. if (pidlFull)
  1983. {
  1984. LPCITEMIDLIST pidlRelative;
  1985. IShellFolder2* psf2;
  1986. if (SUCCEEDED(SHBindToParent(pidlFull, IID_PPV_ARG(IShellFolder2, &psf2), &pidlRelative)))
  1987. {
  1988. CLSID guidItem;
  1989. if (SUCCEEDED(GetItemCLSID(psf2, pidlRelative, &guidItem)) &&
  1990. IsEqualCLSID(CLSID_Internet, guidItem))
  1991. {
  1992. fIEDropped = TRUE;
  1993. TCHAR szFakeIEItem[MAX_PATH];
  1994. if (SHGetPathFromIDList(pidlFull, szFakeIEItem))
  1995. {
  1996. TCHAR szFakeIEItemDesktop[MAX_PATH];
  1997. if (SHGetSpecialFolderPath(NULL, szFakeIEItemDesktop, CSIDL_DESKTOP, 0))
  1998. {
  1999. // delete the original if this is a move or if we're on the same volume and we're neither explicitly copying nor linking
  2000. if (((dwEffect & DROPEFFECT_MOVE) == DROPEFFECT_MOVE) ||
  2001. (((dwEffect & DROPEFFECT_COPY) != DROPEFFECT_COPY) &&
  2002. ((dwEffect & DROPEFFECT_LINK) != DROPEFFECT_LINK) &&
  2003. (PathIsSameRoot(szFakeIEItemDesktop, szFakeIEItem))))
  2004. {
  2005. DeleteFile(szFakeIEItem);
  2006. }
  2007. }
  2008. }
  2009. pida->cidl--;
  2010. pida->aoffset[i] = pida->aoffset[pida->cidl];
  2011. i--; // stall the for loop
  2012. }
  2013. psf2->Release();
  2014. }
  2015. ILFree(pidlFull);
  2016. }
  2017. }
  2018. *pfIsPIDA = TRUE;
  2019. *pcItems = pida->cidl;
  2020. HIDA_ReleaseStgMedium(pida, &medium);
  2021. }
  2022. return fIEDropped;
  2023. }
  2024. HRESULT CDesktopFolderDropTarget::_ShowIEIcon()
  2025. {
  2026. // reset desktop cleanup wizard's legacy location of "don't show IE" information
  2027. HKEY hkey;
  2028. if(SUCCEEDED(SHRegGetCLSIDKey(CLSID_Internet, TEXT("ShellFolder"), FALSE, TRUE, &hkey)))
  2029. {
  2030. DWORD dwAttr, dwType = 0;
  2031. DWORD cbSize = sizeof(dwAttr);
  2032. if (ERROR_SUCCESS == RegQueryValueEx(hkey, TEXT("Attributes"), NULL, &dwType, (BYTE *) &dwAttr, &cbSize) && (dwType == REG_DWORD))
  2033. {
  2034. dwAttr &= ~SFGAO_NONENUMERATED;
  2035. RegSetValueEx(hkey, TEXT("Attributes"), NULL, dwType, (BYTE *) &dwAttr, cbSize);
  2036. }
  2037. RegCloseKey(hkey);
  2038. }
  2039. // reset start menu's location of "don't show IE" information
  2040. DWORD dwData = 0;
  2041. TCHAR szCLSID[MAX_GUID_STRING_LEN];
  2042. TCHAR szBuffer[MAX_PATH];
  2043. if (SUCCEEDED(SHStringFromGUID(CLSID_Internet, szCLSID, ARRAYSIZE(szCLSID))))
  2044. {
  2045. for (int i = 0; i < 2; i ++)
  2046. {
  2047. wnsprintf(szBuffer, ARRAYSIZE(szBuffer), REGSTR_PATH_HIDDEN_DESKTOP_ICONS, (i == 0) ? REGSTR_VALUE_STARTPANEL : REGSTR_VALUE_CLASSICMENU);
  2048. SHRegSetUSValue(szBuffer, szCLSID, REG_DWORD, &dwData, sizeof(DWORD), SHREGSET_FORCE_HKCU);
  2049. }
  2050. }
  2051. SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, DESKTOP_PIDL, NULL);
  2052. return S_OK;
  2053. }
  2054. HRESULT CDesktopFolderDropTarget::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect)
  2055. {
  2056. BOOL fIsPIDA;
  2057. UINT cidl;
  2058. if (_IsSpecialCaseDrop(pDataObject, *pdwEffect, &fIsPIDA, &cidl))
  2059. {
  2060. _ShowIEIcon();
  2061. }
  2062. HRESULT hr;
  2063. if (fIsPIDA && 0 == cidl)
  2064. {
  2065. hr = _pdt->DragLeave();
  2066. }
  2067. else
  2068. {
  2069. hr = _pdt->Drop(pDataObject, grfKeyState, pt, pdwEffect);
  2070. }
  2071. return hr;
  2072. }
  2073. CDesktopFolderEnum::CDesktopFolderEnum(CDesktopFolder *pdf, HWND hwnd, DWORD grfFlags) :
  2074. _cRef(1), _bUseAltEnum(FALSE)
  2075. {
  2076. if (pdf->_psfDesktop)
  2077. pdf->_psfDesktop->EnumObjects(hwnd, grfFlags, &_penumFolder);
  2078. if (pdf->_psfAltDesktop)
  2079. pdf->_psfAltDesktop->EnumObjects(NULL, grfFlags, &_penumAltFolder);
  2080. }
  2081. CDesktopFolderEnum::~CDesktopFolderEnum()
  2082. {
  2083. if (_penumFolder)
  2084. _penumFolder->Release();
  2085. if (_penumAltFolder)
  2086. _penumAltFolder->Release();
  2087. }
  2088. STDMETHODIMP CDesktopFolderEnum::QueryInterface(REFIID riid, void **ppv)
  2089. {
  2090. static const QITAB qit[] = {
  2091. QITABENT(CDesktopFolderEnum, IEnumIDList), // IID_IEnumIDList
  2092. { 0 },
  2093. };
  2094. return QISearch(this, qit, riid, ppv);
  2095. }
  2096. STDMETHODIMP_(ULONG) CDesktopFolderEnum::AddRef()
  2097. {
  2098. return InterlockedIncrement(&_cRef);
  2099. }
  2100. STDMETHODIMP_(ULONG) CDesktopFolderEnum::Release()
  2101. {
  2102. ASSERT( 0 != _cRef );
  2103. ULONG cRef = InterlockedDecrement(&_cRef);
  2104. if ( 0 == cRef )
  2105. {
  2106. delete this;
  2107. }
  2108. return cRef;
  2109. }
  2110. STDMETHODIMP CDesktopFolderEnum::Next(ULONG celt, LPITEMIDLIST *ppidl, ULONG *pceltFetched)
  2111. {
  2112. HRESULT hr;
  2113. if (_bUseAltEnum)
  2114. {
  2115. if (_penumAltFolder)
  2116. {
  2117. hr = _penumAltFolder->Next(celt, ppidl, pceltFetched);
  2118. }
  2119. else
  2120. hr = S_FALSE;
  2121. }
  2122. else if (_penumFolder)
  2123. {
  2124. hr = _penumFolder->Next(celt, ppidl, pceltFetched);
  2125. if (S_OK != hr)
  2126. {
  2127. _bUseAltEnum = TRUE;
  2128. hr = Next(celt, ppidl, pceltFetched); // recurse
  2129. }
  2130. }
  2131. else
  2132. {
  2133. hr = S_FALSE;
  2134. }
  2135. if (hr == S_FALSE)
  2136. {
  2137. *ppidl = NULL;
  2138. if (pceltFetched)
  2139. *pceltFetched = 0;
  2140. }
  2141. return hr;
  2142. }
  2143. STDMETHODIMP CDesktopFolderEnum::Skip(ULONG celt)
  2144. {
  2145. return E_NOTIMPL;
  2146. }
  2147. STDMETHODIMP CDesktopFolderEnum::Reset()
  2148. {
  2149. if (_penumFolder)
  2150. _penumFolder->Reset();
  2151. if (_penumAltFolder)
  2152. _penumAltFolder->Reset();
  2153. _bUseAltEnum = FALSE;
  2154. return S_OK;
  2155. }
  2156. STDMETHODIMP CDesktopFolderEnum::Clone(IEnumIDList **ppenum)
  2157. {
  2158. *ppenum = NULL;
  2159. return E_NOTIMPL;
  2160. }