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.

353 lines
9.0 KiB

  1. #include "precomp.hxx"
  2. #pragma hdrstop
  3. #include <shguidp.h> // CLSID_MyDocuments, CLSID_ShellFSFolder
  4. #include <shellp.h> // SHCoCreateInstance
  5. #include <shlguidp.h> // IID_IResolveShellLink
  6. #include "util.h"
  7. #include "dll.h"
  8. #include "resource.h"
  9. #include "prop.h"
  10. HRESULT _GetUIObjectForMyDocs(REFIID riid, void **ppv)
  11. {
  12. LPITEMIDLIST pidl;
  13. HRESULT hr = SHGetFolderLocation(NULL, CSIDL_PERSONAL | CSIDL_FLAG_NO_ALIAS, NULL, 0, &pidl);
  14. if (SUCCEEDED(hr))
  15. {
  16. hr = SHGetUIObjectFromFullPIDL(pidl, NULL, riid, ppv);
  17. ILFree(pidl);
  18. }
  19. return hr;
  20. }
  21. // send to "My Documents" handler
  22. class CMyDocsSendTo : public IDropTarget, IPersistFile
  23. {
  24. public:
  25. CMyDocsSendTo();
  26. HRESULT _InitTarget();
  27. // IUnknown
  28. STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
  29. STDMETHOD_(ULONG, AddRef)();
  30. STDMETHOD_(ULONG, Release)();
  31. // IDropTarget
  32. STDMETHODIMP DragEnter(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect);
  33. STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, DWORD * pdwEffect);
  34. STDMETHODIMP DragLeave();
  35. STDMETHODIMP Drop(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect);
  36. // IPersist
  37. STDMETHOD(GetClassID)(CLSID *pClassID);
  38. // IPersistFile
  39. STDMETHOD(IsDirty)(void);
  40. STDMETHOD(Load)(LPCOLESTR pszFileName, DWORD dwMode);
  41. STDMETHOD(Save)(LPCOLESTR pszFileName, BOOL fRemember);
  42. STDMETHOD(SaveCompleted)(LPCOLESTR pszFileName);
  43. STDMETHOD(GetCurFile)(LPOLESTR *ppszFileName);
  44. private:
  45. ~CMyDocsSendTo();
  46. LONG _cRef;
  47. IDropTarget *_pdtgt;
  48. };
  49. CMyDocsSendTo::CMyDocsSendTo() : _cRef(1)
  50. {
  51. DllAddRef();
  52. }
  53. CMyDocsSendTo::~CMyDocsSendTo()
  54. {
  55. if (_pdtgt)
  56. _pdtgt->Release();
  57. DllRelease();
  58. }
  59. STDMETHODIMP CMyDocsSendTo::QueryInterface(REFIID riid, void **ppv)
  60. {
  61. static const QITAB qit[] = {
  62. QITABENT(CMyDocsSendTo, IDropTarget),
  63. QITABENT(CMyDocsSendTo, IPersistFile),
  64. QITABENTMULTI(CMyDocsSendTo, IPersist, IPersistFile),
  65. { 0 },
  66. };
  67. return QISearch(this, qit, riid, ppv);
  68. }
  69. STDMETHODIMP_(ULONG) CMyDocsSendTo::AddRef()
  70. {
  71. return InterlockedIncrement(&_cRef);
  72. }
  73. STDMETHODIMP_(ULONG) CMyDocsSendTo::Release()
  74. {
  75. if (InterlockedDecrement(&_cRef))
  76. return _cRef;
  77. delete this;
  78. return 0;
  79. }
  80. HRESULT CMyDocsSendTo::_InitTarget()
  81. {
  82. if (_pdtgt)
  83. return S_OK;
  84. return _GetUIObjectForMyDocs(IID_PPV_ARG(IDropTarget, &_pdtgt));
  85. }
  86. STDMETHODIMP CMyDocsSendTo::DragEnter(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  87. {
  88. *pdwEffect &= ~DROPEFFECT_MOVE; // don't let this be destructive
  89. HRESULT hr = _InitTarget();
  90. if (SUCCEEDED(hr))
  91. hr = _pdtgt->DragEnter(pDataObject, grfKeyState, pt, pdwEffect);
  92. return hr;
  93. }
  94. STDMETHODIMP CMyDocsSendTo::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  95. {
  96. *pdwEffect &= ~DROPEFFECT_MOVE; // don't let this be destructive
  97. HRESULT hr = _InitTarget();
  98. if (SUCCEEDED(hr))
  99. hr = _pdtgt->DragOver(grfKeyState, pt, pdwEffect);
  100. return hr;
  101. }
  102. STDMETHODIMP CMyDocsSendTo::DragLeave()
  103. {
  104. HRESULT hr = _InitTarget();
  105. if (SUCCEEDED(hr))
  106. hr = _pdtgt->DragLeave();
  107. return hr;
  108. }
  109. STDMETHODIMP CMyDocsSendTo::Drop(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  110. {
  111. *pdwEffect &= ~DROPEFFECT_MOVE; // don't let this be destructive
  112. HRESULT hr = _InitTarget();
  113. if (SUCCEEDED(hr))
  114. hr = _pdtgt->Drop(pDataObject, grfKeyState, pt, pdwEffect);
  115. return hr;
  116. }
  117. STDMETHODIMP CMyDocsSendTo::GetClassID(CLSID *pClassID)
  118. {
  119. *pClassID = CLSID_MyDocsDropTarget;
  120. return S_OK;
  121. }
  122. STDMETHODIMP CMyDocsSendTo::IsDirty(void)
  123. {
  124. return S_OK; // no
  125. }
  126. STDMETHODIMP CMyDocsSendTo::Load(LPCOLESTR pszFileName, DWORD dwMode)
  127. {
  128. if (_pdtgt)
  129. return S_OK;
  130. UpdateSendToFile(); // refresh the send to target (in case the desktop icon was renamed)
  131. return S_OK;
  132. }
  133. STDMETHODIMP CMyDocsSendTo::Save(LPCOLESTR pszFileName, BOOL fRemember)
  134. {
  135. return S_OK;
  136. }
  137. STDMETHODIMP CMyDocsSendTo::SaveCompleted(LPCOLESTR pszFileName)
  138. {
  139. return S_OK;
  140. }
  141. STDMETHODIMP CMyDocsSendTo::GetCurFile(LPOLESTR *ppszFileName)
  142. {
  143. *ppszFileName = NULL;
  144. return E_NOTIMPL;
  145. }
  146. HRESULT CMyDocsSendTo_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
  147. {
  148. CMyDocsSendTo* pdt = new CMyDocsSendTo();
  149. if (pdt)
  150. {
  151. *ppunk = SAFECAST(pdt, IDropTarget *);
  152. return S_OK;
  153. }
  154. *ppunk = NULL;
  155. return E_OUTOFMEMORY;
  156. }
  157. // properyt page and context menu shell extension
  158. class CMyDocsProp : public IShellPropSheetExt, public IShellExtInit
  159. {
  160. public:
  161. CMyDocsProp();
  162. // IUnknown
  163. STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
  164. STDMETHOD_(ULONG, AddRef)();
  165. STDMETHOD_(ULONG, Release)();
  166. // IShellExtInit
  167. STDMETHOD(Initialize)(LPCITEMIDLIST pidlFolder, IDataObject *lpdobj, HKEY hkeyProgID);
  168. // IShellPropSheetExt
  169. STDMETHOD(AddPages)(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam);
  170. STDMETHOD(ReplacePage)(UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam);
  171. private:
  172. ~CMyDocsProp();
  173. void _AddExtraPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam);
  174. LONG _cRef;
  175. };
  176. CMyDocsProp::CMyDocsProp() : _cRef(1)
  177. {
  178. DllAddRef();
  179. }
  180. CMyDocsProp::~CMyDocsProp()
  181. {
  182. DllRelease();
  183. }
  184. STDMETHODIMP CMyDocsProp::QueryInterface( REFIID riid, void **ppv)
  185. {
  186. static const QITAB qit[] = {
  187. QITABENT(CMyDocsProp, IShellPropSheetExt),
  188. QITABENT(CMyDocsProp, IShellExtInit),
  189. { 0 },
  190. };
  191. return QISearch(this, qit, riid, ppv);
  192. }
  193. STDMETHODIMP_ (ULONG) CMyDocsProp::AddRef()
  194. {
  195. return InterlockedIncrement(&_cRef);
  196. }
  197. STDMETHODIMP_ (ULONG) CMyDocsProp::Release()
  198. {
  199. if (InterlockedDecrement(&_cRef))
  200. return _cRef;
  201. delete this;
  202. return 0;
  203. }
  204. STDMETHODIMP CMyDocsProp::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdobj, HKEY hkey)
  205. {
  206. return S_OK;
  207. }
  208. // {f81e9010-6ea4-11ce-a7ff-00aa003ca9f6}
  209. const CLSID CLSID_CShare = {0xf81e9010, 0x6ea4, 0x11ce, 0xa7, 0xff, 0x00, 0xaa, 0x00, 0x3c, 0xa9, 0xf6 };
  210. // {1F2E5C40-9550-11CE-99D2-00AA006E086C}
  211. const CLSID CLSID_RShellExt = {0x1F2E5C40, 0x9550, 0x11CE, 0x99, 0xD2, 0x00, 0xAA, 0x00, 0x6E, 0x08, 0x6C };
  212. const CLSID *c_rgFilePages[] = {
  213. &CLSID_ShellFileDefExt,
  214. &CLSID_CShare,
  215. &CLSID_RShellExt,
  216. };
  217. const CLSID *c_rgDrivePages[] = {
  218. &CLSID_ShellDrvDefExt,
  219. &CLSID_CShare,
  220. &CLSID_RShellExt,
  221. };
  222. // add optional pages to Explore/Options.
  223. void CMyDocsProp::_AddExtraPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam)
  224. {
  225. IDataObject *pdtobj;
  226. if (SUCCEEDED(_GetUIObjectForMyDocs(IID_PPV_ARG(IDataObject, &pdtobj))))
  227. {
  228. TCHAR szPath[MAX_PATH];
  229. SHGetFolderPath(NULL, CSIDL_PERSONAL | CSIDL_FLAG_DONT_VERIFY, NULL, SHGFP_TYPE_CURRENT, szPath);
  230. BOOL fDriveRoot = PathIsRoot(szPath) && !PathIsUNC(szPath);
  231. const CLSID** pCLSIDs = fDriveRoot ? c_rgDrivePages : c_rgFilePages;
  232. int nCLSIDs = (int)(fDriveRoot ? ARRAYSIZE(c_rgDrivePages) : ARRAYSIZE(c_rgFilePages));
  233. for (int i = 0; i < nCLSIDs; i++)
  234. {
  235. IUnknown *punk;
  236. // We need to CoCreate for IUnknown instead of IShellPropSheetExt because the
  237. // class factory for the Win9x sharing property sheet (msshrui.dll) is buggy
  238. // and return E_NOINTERFACE ISPSE...
  239. HRESULT hr = SHCoCreateInstance(NULL, pCLSIDs[i], NULL, IID_PPV_ARG(IUnknown, &punk));
  240. if (SUCCEEDED(hr))
  241. {
  242. IShellPropSheetExt *pspse;
  243. hr = punk->QueryInterface(IID_PPV_ARG(IShellPropSheetExt, &pspse));
  244. punk->Release();
  245. if (SUCCEEDED(hr))
  246. {
  247. IShellExtInit *psei;
  248. if (SUCCEEDED(pspse->QueryInterface(IID_PPV_ARG(IShellExtInit, &psei))))
  249. {
  250. hr = psei->Initialize(NULL, pdtobj, NULL);
  251. psei->Release();
  252. }
  253. if (SUCCEEDED(hr))
  254. pspse->AddPages(pfnAddPage, lParam);
  255. pspse->Release();
  256. }
  257. }
  258. }
  259. }
  260. }
  261. STDMETHODIMP CMyDocsProp::AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam)
  262. {
  263. HRESULT hr = S_OK;
  264. PROPSHEETPAGE psp = {0};
  265. psp.dwSize = sizeof(psp);
  266. psp.dwFlags = PSP_DEFAULT;
  267. psp.hInstance = g_hInstance;
  268. psp.pszTemplate = MAKEINTRESOURCE(DLG_TARGET);
  269. psp.pfnDlgProc = TargetDlgProc;
  270. HPROPSHEETPAGE hPage = CreatePropertySheetPage( &psp );
  271. if (hPage)
  272. {
  273. pfnAddPage( hPage, lParam );
  274. _AddExtraPages(pfnAddPage, lParam);
  275. }
  276. return hr;
  277. }
  278. STDMETHODIMP CMyDocsProp::ReplacePage( UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam)
  279. {
  280. return E_NOTIMPL;
  281. }
  282. HRESULT CMyDocsProp_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
  283. {
  284. CMyDocsProp* pmp = new CMyDocsProp();
  285. if (pmp)
  286. {
  287. *ppunk = SAFECAST(pmp, IShellExtInit *);
  288. return S_OK;
  289. }
  290. *ppunk = NULL;
  291. return E_OUTOFMEMORY;
  292. }