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.

367 lines
11 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #include "ids.h"
  4. #include "defview.h"
  5. #include "datautil.h"
  6. #include <cowsite.h> // base class for IObjectWithSite
  7. #include "idlcomm.h"
  8. // shlexec.c
  9. STDAPI_(BOOL) DoesAppWantUrl(LPCTSTR pszFullPathToApp);
  10. // drop target impl for .exe files
  11. class CExeDropTarget : public IDropTarget, IPersistFile, CObjectWithSite
  12. {
  13. public:
  14. // IUnknown
  15. STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
  16. STDMETHOD_(ULONG, AddRef)();
  17. STDMETHOD_(ULONG, Release)();
  18. // IDropTarget
  19. STDMETHODIMP DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
  20. STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
  21. STDMETHODIMP DragLeave();
  22. STDMETHODIMP Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
  23. // IPersist
  24. STDMETHOD(GetClassID)(CLSID *pClassID);
  25. // IPersistFile
  26. STDMETHOD(IsDirty)(void);
  27. STDMETHOD(Load)(LPCOLESTR pszFileName, DWORD dwMode);
  28. STDMETHOD(Save)(LPCOLESTR pszFileName, BOOL fRemember);
  29. STDMETHOD(SaveCompleted)(LPCOLESTR pszFileName);
  30. STDMETHOD(GetCurFile)(LPOLESTR *ppszFileName);
  31. // IObjectWithSite
  32. // STDMETHOD(SetSite)(IUnknown *punkSite);
  33. // STDMETHOD(GetSite)(REFIID riid, void **ppvSite);
  34. CExeDropTarget();
  35. private:
  36. ~CExeDropTarget();
  37. void _FillSEIFromLinkSite(SHELLEXECUTEINFO *pei);
  38. void _CleanupSEIFromLinkSite(SHELLEXECUTEINFO *pei);
  39. LONG _cRef;
  40. DWORD _dwEffectLast;
  41. DWORD _grfKeyStateLast;
  42. TCHAR _szFile[MAX_PATH];
  43. };
  44. CExeDropTarget::CExeDropTarget() : _cRef(1)
  45. {
  46. }
  47. CExeDropTarget::~CExeDropTarget()
  48. {
  49. }
  50. STDMETHODIMP CExeDropTarget::QueryInterface(REFIID riid, void **ppv)
  51. {
  52. static const QITAB qit[] = {
  53. QITABENT(CExeDropTarget, IDropTarget),
  54. QITABENT(CExeDropTarget, IPersistFile),
  55. QITABENTMULTI(CExeDropTarget, IPersist, IPersistFile),
  56. QITABENT(CExeDropTarget, IObjectWithSite), // IID_IObjectWithSite
  57. { 0 },
  58. };
  59. return QISearch(this, qit, riid, ppv);
  60. }
  61. STDMETHODIMP_(ULONG) CExeDropTarget::AddRef()
  62. {
  63. return InterlockedIncrement(&_cRef);
  64. }
  65. STDMETHODIMP_(ULONG) CExeDropTarget::Release()
  66. {
  67. ASSERT( 0 != _cRef );
  68. ULONG cRef = InterlockedDecrement(&_cRef);
  69. if ( 0 == cRef )
  70. {
  71. delete this;
  72. }
  73. return cRef;
  74. }
  75. STDMETHODIMP CExeDropTarget::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  76. {
  77. FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  78. if ((S_OK == pdtobj->QueryGetData(&fmte)) ||
  79. (S_OK == DataObj_GetShellURL(pdtobj, NULL, NULL)))
  80. {
  81. *pdwEffect &= (DROPEFFECT_COPY | DROPEFFECT_LINK);
  82. }
  83. else
  84. *pdwEffect = 0;
  85. _dwEffectLast = *pdwEffect;
  86. _grfKeyStateLast = grfKeyState;
  87. return S_OK;
  88. }
  89. STDMETHODIMP CExeDropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  90. {
  91. *pdwEffect = _dwEffectLast;
  92. _grfKeyStateLast = grfKeyState;
  93. return S_OK;
  94. }
  95. STDMETHODIMP CExeDropTarget::DragLeave()
  96. {
  97. return S_OK;
  98. }
  99. //
  100. // See if we were created from a shortcut. If so, then pull the exec
  101. // parameters from the shortcut.
  102. //
  103. void CExeDropTarget::_FillSEIFromLinkSite(SHELLEXECUTEINFO *pei)
  104. {
  105. ASSERT(pei->lpParameters == NULL);
  106. ASSERT(pei->lpDirectory == NULL);
  107. IShellLink *psl;
  108. if (SUCCEEDED(IUnknown_QueryService(_punkSite, SID_LinkSite, IID_PPV_ARG(IShellLink, &psl))))
  109. {
  110. TCHAR szBuf[MAX_PATH];
  111. psl->GetShowCmd(&pei->nShow);
  112. // Hotkeys are annoying because IShellLink::GetHotkey uses a
  113. // WORD as the hotkey, but SHELLEXECUTEINFO uses a DWORD.
  114. WORD wHotkey;
  115. if (SUCCEEDED(psl->GetHotkey(&wHotkey)))
  116. {
  117. pei->dwHotKey = wHotkey;
  118. pei->fMask |= SEE_MASK_HOTKEY;
  119. }
  120. if (SUCCEEDED(psl->GetWorkingDirectory(szBuf, ARRAYSIZE(szBuf))) &&
  121. szBuf[0])
  122. {
  123. Str_SetPtr(const_cast<LPTSTR *>(&pei->lpDirectory), szBuf);
  124. }
  125. if (SUCCEEDED(psl->GetArguments(szBuf, ARRAYSIZE(szBuf))) &&
  126. szBuf[0])
  127. {
  128. Str_SetPtr(const_cast<LPTSTR *>(&pei->lpParameters), szBuf);
  129. }
  130. psl->Release();
  131. }
  132. }
  133. void CExeDropTarget::_CleanupSEIFromLinkSite(SHELLEXECUTEINFO *pei)
  134. {
  135. Str_SetPtr(const_cast<LPTSTR *>(&pei->lpDirectory), NULL);
  136. Str_SetPtr(const_cast<LPTSTR *>(&pei->lpParameters), NULL);
  137. }
  138. BOOL GetAppDropTarget(LPCTSTR pszPath, CLSID *pclsid)
  139. {
  140. TCHAR sz[MAX_PATH];
  141. // NOTE this assumes that this is a path to the exe
  142. // and not a command line
  143. PathToAppPathKey(pszPath, sz, ARRAYSIZE(sz));
  144. TCHAR szClsid[64];
  145. DWORD cb = sizeof(szClsid);
  146. return (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, sz, TEXT("DropTarget"), NULL, szClsid, &cb)) &&
  147. GUIDFromString(szClsid, pclsid);
  148. }
  149. STDMETHODIMP CExeDropTarget::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  150. {
  151. DWORD dwEffectPerformed = 0;
  152. if (!(_grfKeyStateLast & MK_LBUTTON))
  153. {
  154. HMENU hmenu = SHLoadPopupMenu(HINST_THISDLL, POPUP_DROPONEXE);
  155. if (hmenu)
  156. {
  157. HWND hwnd;
  158. IUnknown_GetWindow(_punkSite, &hwnd);
  159. UINT idCmd = SHTrackPopupMenu(hmenu, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
  160. pt.x, pt.y, 0, hwnd, NULL);
  161. DestroyMenu(hmenu);
  162. if (idCmd != DDIDM_COPY)
  163. {
  164. *pdwEffect = 0; // canceled
  165. }
  166. }
  167. }
  168. if (*pdwEffect)
  169. {
  170. CLSID clsidDropTarget;
  171. if (GetAppDropTarget(_szFile, &clsidDropTarget))
  172. {
  173. if (SUCCEEDED(SHSimulateDropOnClsid(clsidDropTarget, _punkSite, pdtobj)))
  174. {
  175. dwEffectPerformed = DROPEFFECT_COPY; // what we did
  176. }
  177. }
  178. else
  179. {
  180. SHELLEXECUTEINFO ei = {
  181. sizeof(ei),
  182. 0, NULL, NULL, _szFile, NULL, NULL, SW_SHOWNORMAL, NULL
  183. };
  184. _FillSEIFromLinkSite(&ei);
  185. LPCTSTR pszLinkParams = ei.lpParameters;
  186. FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  187. STGMEDIUM medium;
  188. HRESULT hr = pdtobj->GetData(&fmte, &medium);
  189. if (SUCCEEDED(hr))
  190. {
  191. TCHAR szPath[MAX_PATH];
  192. int cchParam = ei.lpParameters ? lstrlen(ei.lpParameters) + 1 : 0;
  193. BOOL fLFNAware = App_IsLFNAware(_szFile);
  194. for (UINT i = 0; DragQueryFile((HDROP)medium.hGlobal, i, szPath, ARRAYSIZE(szPath)); i++)
  195. {
  196. if (fLFNAware)
  197. PathQuoteSpaces(szPath);
  198. else
  199. GetShortPathName(szPath, szPath, ARRAYSIZE(szPath));
  200. cchParam += lstrlen(szPath) + 2; // space and NULL
  201. }
  202. if (cchParam)
  203. {
  204. LPTSTR pszParam = (LPTSTR)LocalAlloc(LPTR, cchParam * sizeof(*pszParam));
  205. if (pszParam)
  206. {
  207. // If the link had parameters, then put our filenames after
  208. // the parameters (with an intervening space)
  209. if (ei.lpParameters)
  210. {
  211. StrCpyN(pszParam, ei.lpParameters, cchParam);
  212. StrCatBuff(pszParam, c_szSpace, cchParam);
  213. }
  214. for (i = 0; DragQueryFile((HDROP)medium.hGlobal, i, szPath, ARRAYSIZE(szPath)); i++)
  215. {
  216. if (fLFNAware)
  217. PathQuoteSpaces(szPath);
  218. else
  219. GetShortPathName(szPath, szPath, ARRAYSIZE(szPath));
  220. if (i > 0)
  221. StrCatBuff(pszParam, c_szSpace, cchParam);
  222. StrCatBuff(pszParam, szPath, cchParam);
  223. }
  224. ei.lpParameters = pszParam;
  225. // all shellexec info comes from stuff thats in the dataobject or already on disk --
  226. // no getting around it, and the args are quoted properly or put into short path names.
  227. ShellExecuteEx(&ei);
  228. LocalFree((HLOCAL)pszParam);
  229. dwEffectPerformed = DROPEFFECT_COPY; // what we did
  230. }
  231. }
  232. ReleaseStgMedium(&medium);
  233. }
  234. else
  235. {
  236. LPCSTR pszURL;
  237. if (SUCCEEDED(DataObj_GetShellURL(pdtobj, &medium, &pszURL)))
  238. {
  239. if (DoesAppWantUrl(_szFile))
  240. {
  241. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  242. SHAnsiToTChar(pszURL, szURL, ARRAYSIZE(szURL));
  243. ei.lpParameters = szURL;
  244. // all shellexec info comes from stuff thats in the dataobject or already on disk
  245. ShellExecuteEx(&ei);
  246. dwEffectPerformed = DROPEFFECT_LINK; // what we did
  247. }
  248. ReleaseStgMediumHGLOBAL(NULL, &medium);
  249. }
  250. }
  251. // The process of building the ShellExecuteEx parameters may have
  252. // messed up the ei.lpParameters, so put the original back so the
  253. // cleanup function won't get confused.
  254. ei.lpParameters = pszLinkParams;
  255. _CleanupSEIFromLinkSite(&ei);
  256. }
  257. *pdwEffect = dwEffectPerformed;
  258. }
  259. return S_OK;
  260. }
  261. STDMETHODIMP CExeDropTarget::GetClassID(CLSID *pClassID)
  262. {
  263. *pClassID = CLSID_ExeDropTarget;
  264. return S_OK;
  265. }
  266. STDMETHODIMP CExeDropTarget::IsDirty(void)
  267. {
  268. return S_OK; // no
  269. }
  270. STDMETHODIMP CExeDropTarget::Load(LPCOLESTR pszFileName, DWORD dwMode)
  271. {
  272. SHUnicodeToTChar(pszFileName, _szFile, ARRAYSIZE(_szFile));
  273. return S_OK;
  274. }
  275. STDMETHODIMP CExeDropTarget::Save(LPCOLESTR pszFileName, BOOL fRemember)
  276. {
  277. return S_OK;
  278. }
  279. STDMETHODIMP CExeDropTarget::SaveCompleted(LPCOLESTR pszFileName)
  280. {
  281. return S_OK;
  282. }
  283. STDMETHODIMP CExeDropTarget::GetCurFile(LPOLESTR *ppszFileName)
  284. {
  285. *ppszFileName = NULL;
  286. return E_NOTIMPL;
  287. }
  288. STDAPI CExeDropTarget_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  289. {
  290. HRESULT hr;
  291. CExeDropTarget* pdt = new CExeDropTarget();
  292. if (pdt)
  293. {
  294. hr = pdt->QueryInterface(riid, ppv);
  295. pdt->Release();
  296. }
  297. else
  298. {
  299. *ppv = NULL;
  300. hr = E_OUTOFMEMORY;
  301. }
  302. return hr;
  303. }