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.

282 lines
7.9 KiB

  1. #include "precomp.h" // pch file
  2. #include "sendto.h"
  3. #pragma hdrstop
  4. // class that implements the send to desktop (as shortcut)
  5. const GUID CLSID_DesktopShortcut = { 0x9E56BE61L, 0xC50F, 0x11CF, 0x9A, 0x2C, 0x00, 0xA0, 0xC9, 0x0A, 0x90, 0xCE };
  6. class CDesktopShortcut : public CSendTo
  7. {
  8. private:
  9. LPIDA _GetHIDA(IDataObject *pdtobj, STGMEDIUM *pmedium);
  10. LPCITEMIDLIST _GetIDListPtr(LPIDA pida, UINT i);
  11. void _ReleaseStgMedium(void *pv, STGMEDIUM *pmedium);
  12. HRESULT _BindToObject(IShellFolder *psf, REFIID riid, LPCITEMIDLIST pidl, void **ppvOut);
  13. HRESULT _InvokeVerbOnItems(HWND hwnd, LPCTSTR pszVerb, UINT uFlags, IShellFolder *psf, UINT cidl, LPCITEMIDLIST *apidl, LPCTSTR pszDirectory);
  14. HRESULT _InvokeVerbOnDataObj(HWND hwnd, LPCTSTR pszVerb, UINT uFlags, IDataObject *pdtobj, LPCTSTR pszDirectory);
  15. protected:
  16. HRESULT v_DropHandler(IDataObject *pdtobj, DWORD grfKeyState, DWORD dwEffect);
  17. public:
  18. CDesktopShortcut();
  19. };
  20. // construct the sendto object with the appropriate CLSID.
  21. CDesktopShortcut::CDesktopShortcut() :
  22. CSendTo(CLSID_DesktopShortcut)
  23. {
  24. }
  25. // helper methods
  26. LPIDA CDesktopShortcut::_GetHIDA(IDataObject *pdtobj, STGMEDIUM *pmedium)
  27. {
  28. FORMATETC fmte = {g_cfHIDA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  29. if (pmedium)
  30. {
  31. pmedium->pUnkForRelease = NULL;
  32. pmedium->hGlobal = NULL;
  33. }
  34. if (!pmedium)
  35. {
  36. if (SUCCEEDED(pdtobj->QueryGetData(&fmte)))
  37. return (LPIDA)TRUE;
  38. else
  39. return (LPIDA)FALSE;
  40. }
  41. else if (SUCCEEDED(pdtobj->GetData(&fmte, pmedium)))
  42. {
  43. return (LPIDA)GlobalLock(pmedium->hGlobal);
  44. }
  45. return NULL;
  46. }
  47. LPCITEMIDLIST CDesktopShortcut::_GetIDListPtr(LPIDA pida, UINT i)
  48. {
  49. if (NULL == pida)
  50. {
  51. return NULL;
  52. }
  53. if (i == (UINT)-1 || i < pida->cidl)
  54. {
  55. return (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[i+1]);
  56. }
  57. return NULL;
  58. }
  59. // release a storage medium (doing a Global unlock as required).
  60. void CDesktopShortcut::_ReleaseStgMedium(void *pv, STGMEDIUM *pmedium)
  61. {
  62. if (pmedium->hGlobal && (pmedium->tymed == TYMED_HGLOBAL))
  63. {
  64. GlobalUnlock(pmedium->hGlobal);
  65. }
  66. ReleaseStgMedium(pmedium);
  67. }
  68. // dupe of shell\lib SHBindToObject() to avoid link dependancies... (OLEAUT32 gets pulled in by
  69. // stuff that does VARIANT goo in that lib)
  70. HRESULT CDesktopShortcut::_BindToObject(IShellFolder *psf, REFIID riid, LPCITEMIDLIST pidl, void **ppvOut)
  71. {
  72. HRESULT hr;
  73. IShellFolder *psfRelease;
  74. *ppvOut = NULL;
  75. if (!psf)
  76. {
  77. hr = SHGetDesktopFolder(&psf);
  78. psfRelease = psf;
  79. }
  80. else
  81. {
  82. psfRelease = NULL;
  83. hr = S_OK;
  84. }
  85. if (FAILED(hr))
  86. {
  87. // leave error code in hr
  88. }
  89. else if (!pidl || ILIsEmpty(pidl))
  90. {
  91. hr = psf->QueryInterface(riid, ppvOut);
  92. }
  93. else
  94. {
  95. hr = psf->BindToObject(pidl, NULL, riid, ppvOut);
  96. }
  97. if (psfRelease)
  98. psfRelease->Release();
  99. if (SUCCEEDED(hr) && (*ppvOut == NULL))
  100. {
  101. hr = E_FAIL;
  102. }
  103. return hr;
  104. }
  105. // invoke a verb on an array of items in the folder.
  106. HRESULT CDesktopShortcut::_InvokeVerbOnItems(HWND hwnd, LPCTSTR pszVerb, UINT uFlags, IShellFolder *psf, UINT cidl, LPCITEMIDLIST *apidl, LPCTSTR pszDirectory)
  107. {
  108. IContextMenu *pcm;
  109. HRESULT hr = psf->GetUIObjectOf(hwnd, cidl, apidl, IID_IContextMenu, NULL, (void **)&pcm);
  110. if (SUCCEEDED(hr))
  111. {
  112. CHAR szVerbA[128];
  113. WCHAR szVerbW[128];
  114. CHAR szDirA[MAX_PATH];
  115. WCHAR szDirW[MAX_PATH];
  116. CMINVOKECOMMANDINFOEX ici =
  117. {
  118. SIZEOF(CMINVOKECOMMANDINFOEX),
  119. uFlags | CMIC_MASK_UNICODE | CMIC_MASK_FLAG_NO_UI,
  120. hwnd,
  121. NULL,
  122. NULL,
  123. NULL,
  124. SW_NORMAL,
  125. };
  126. SHTCharToAnsi(pszVerb, szVerbA, ARRAYSIZE(szVerbA));
  127. SHTCharToUnicode(pszVerb, szVerbW, ARRAYSIZE(szVerbW));
  128. if (pszDirectory)
  129. {
  130. SHTCharToAnsi(pszDirectory, szDirA, ARRAYSIZE(szDirA));
  131. SHTCharToUnicode(pszDirectory, szDirW, ARRAYSIZE(szDirW));
  132. ici.lpDirectory = szDirA;
  133. ici.lpDirectoryW = szDirW;
  134. }
  135. ici.lpVerb = szVerbA;
  136. ici.lpVerbW = szVerbW;
  137. hr = pcm->InvokeCommand((CMINVOKECOMMANDINFO*)&ici);
  138. pcm->Release();
  139. }
  140. return hr;
  141. }
  142. // invoke a verb on the data object item
  143. HRESULT CDesktopShortcut::_InvokeVerbOnDataObj(HWND hwnd, LPCTSTR pszVerb, UINT uFlags, IDataObject *pdtobj, LPCTSTR pszDirectory)
  144. {
  145. HRESULT hr;
  146. STGMEDIUM medium;
  147. LPIDA pida = _GetHIDA(pdtobj, &medium);
  148. if (pida)
  149. {
  150. LPCITEMIDLIST pidlParent = _GetIDListPtr(pida, (UINT)-1);
  151. IShellFolder *psf;
  152. hr = _BindToObject(NULL, IID_IShellFolder, pidlParent, (void **)&psf);
  153. if (SUCCEEDED(hr))
  154. {
  155. LPCITEMIDLIST *ppidl = (LPCITEMIDLIST *)LocalAlloc(LPTR, pida->cidl * sizeof(LPCITEMIDLIST));
  156. if (ppidl)
  157. {
  158. UINT i;
  159. for (i = 0; i < pida->cidl; i++)
  160. {
  161. ppidl[i] = _GetIDListPtr(pida, i);
  162. }
  163. hr = _InvokeVerbOnItems(hwnd, pszVerb, uFlags, psf, pida->cidl, ppidl, pszDirectory);
  164. LocalFree((LPVOID)ppidl);
  165. }
  166. psf->Release();
  167. }
  168. _ReleaseStgMedium(pida, &medium);
  169. }
  170. else
  171. hr = E_FAIL;
  172. return hr;
  173. }
  174. // handle the drop on the object, so for each item in the HIDA invoke the create
  175. // link verb on them.
  176. HRESULT CDesktopShortcut::v_DropHandler(IDataObject *pdtobj, DWORD grfKeyState, DWORD dwEffect)
  177. {
  178. TCHAR szDesktop[MAX_PATH];
  179. if (SHGetSpecialFolderPath(NULL, szDesktop, CSIDL_DESKTOPDIRECTORY, FALSE))
  180. {
  181. if (g_cfHIDA == 0)
  182. {
  183. g_cfHIDA = (CLIPFORMAT) RegisterClipboardFormat(CFSTR_SHELLIDLIST);
  184. }
  185. return _InvokeVerbOnDataObj (NULL, TEXT("link"), 0, pdtobj, szDesktop);
  186. }
  187. return E_OUTOFMEMORY;
  188. }
  189. // create an instance of desktop link object
  190. STDAPI DesktopShortcut_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
  191. {
  192. *ppunk = NULL; // assume failure
  193. if ( punkOuter )
  194. return CLASS_E_NOAGGREGATION;
  195. CDesktopShortcut *pds = new CDesktopShortcut;
  196. if ( !pds )
  197. return E_OUTOFMEMORY;
  198. HRESULT hr = pds->QueryInterface(IID_PPV_ARG(IUnknown, ppunk));
  199. pds->Release();
  200. return hr;
  201. }
  202. // handler registration of the desktop link verb
  203. #define DESKLINK_EXTENSION TEXT("DeskLink")
  204. STDAPI DesktopShortcut_RegUnReg(BOOL bReg, HKEY hkCLSID, LPCTSTR pszCLSID, LPCTSTR pszModule)
  205. {
  206. TCHAR szFile[MAX_PATH];
  207. if (bReg)
  208. {
  209. HKEY hk;
  210. // get rid of old name "Desktop as Shortcut" link from IE4
  211. if (SUCCEEDED(GetDropTargetPath(szFile, ARRAYSIZE(szFile), IDS_DESKTOPLINK_FILENAME, DESKLINK_EXTENSION)))
  212. DeleteFile(szFile);
  213. if (RegCreateKeyEx(hkCLSID, DEFAULTICON, 0, NULL, 0, KEY_SET_VALUE, NULL, &hk, NULL) == ERROR_SUCCESS)
  214. {
  215. TCHAR szExplorer[MAX_PATH];
  216. TCHAR szIcon[MAX_PATH+10];
  217. GetWindowsDirectory(szExplorer, ARRAYSIZE(szExplorer));
  218. StringCchPrintf(szIcon, ARRAYSIZE(szIcon), TEXT("%s\\explorer.exe,-103"), szExplorer); // ICO_DESKTOP res ID
  219. RegSetValueEx(hk, NULL, 0, REG_SZ, (LPBYTE)szIcon, (lstrlen(szIcon) + 1) * SIZEOF(TCHAR));
  220. RegCloseKey(hk);
  221. }
  222. CommonRegister(hkCLSID, pszCLSID, DESKLINK_EXTENSION, IDS_DESKTOPLINK_FILENAME_NEW);
  223. }
  224. else
  225. {
  226. if (SUCCEEDED(GetDropTargetPath(szFile, ARRAYSIZE(szFile), IDS_DESKTOPLINK_FILENAME, DESKLINK_EXTENSION)))
  227. {
  228. DeleteFile(szFile);
  229. }
  230. }
  231. return S_OK;
  232. }