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.

367 lines
10 KiB

  1. /*
  2. * urlexec.cpp - IUnknown implementation for Intshcut class.
  3. */
  4. #include "project.hpp"
  5. #include "urlshell.h"
  6. #include "clsfact.h"
  7. #include "resource.h"
  8. #include <mluisupp.h>
  9. // URL Exec Hook
  10. class CURLExec : public IShellExecuteHookA, public IShellExecuteHookW
  11. {
  12. private:
  13. ULONG m_cRef;
  14. ~CURLExec(void); // Prevent this class from being allocated on the stack or it will fault.
  15. public:
  16. CURLExec(void);
  17. // IShellExecuteHook methods
  18. // Ansi
  19. STDMETHODIMP Execute(LPSHELLEXECUTEINFOA pei);
  20. // Unicode
  21. STDMETHODIMP Execute(LPSHELLEXECUTEINFOW pei);
  22. // IUnknown methods
  23. STDMETHODIMP QueryInterface(REFIID riid, PVOID *ppvObj);
  24. STDMETHODIMP_(ULONG) AddRef(void);
  25. STDMETHODIMP_(ULONG) Release(void);
  26. #ifdef DEBUG
  27. friend BOOL IsValidPCURLExec(const CURLExec * pue);
  28. #endif
  29. };
  30. #ifdef DEBUG
  31. BOOL IsValidPCURLExec(CURLExec * pue)
  32. {
  33. return (IS_VALID_READ_PTR(pue, CURLExec));
  34. }
  35. #endif
  36. CURLExec::CURLExec(void) : m_cRef(1)
  37. {
  38. // CURLExec objects should always be allocated
  39. ASSERT(IS_VALID_STRUCT_PTR(this, CURLExec));
  40. DLLAddRef();
  41. }
  42. CURLExec::~CURLExec(void)
  43. {
  44. ASSERT(IS_VALID_STRUCT_PTR(this, CURLExec));
  45. DLLRelease();
  46. }
  47. /*----------------------------------------------------------
  48. Purpose: IUnknown::QueryInterface handler for CURLExec
  49. */
  50. STDMETHODIMP CURLExec::QueryInterface(REFIID riid, PVOID *ppvObj)
  51. {
  52. if (IsEqualIID(riid, IID_IUnknown) ||
  53. IsEqualIID(riid, IID_IShellExecuteHookA))
  54. {
  55. *ppvObj = SAFECAST(this, IShellExecuteHookA *);
  56. }
  57. else if (IsEqualIID(riid, IID_IShellExecuteHookW))
  58. {
  59. *ppvObj = SAFECAST(this, IShellExecuteHookW *);
  60. }
  61. else
  62. {
  63. *ppvObj = NULL;
  64. return E_NOINTERFACE;
  65. }
  66. AddRef();
  67. return NOERROR;
  68. }
  69. STDMETHODIMP_(ULONG) CURLExec::AddRef()
  70. {
  71. return ++m_cRef;
  72. }
  73. STDMETHODIMP_(ULONG) CURLExec::Release()
  74. {
  75. m_cRef--;
  76. if (m_cRef > 0)
  77. return m_cRef;
  78. delete this;
  79. return 0;
  80. }
  81. // from shlexec.c
  82. #define SEE_MASK_CLASS (SEE_MASK_CLASSNAME|SEE_MASK_CLASSKEY)
  83. /*----------------------------------------------------------
  84. Purpose: IShellExecuteHook::Execute handler for CURLExec
  85. */
  86. STDMETHODIMP CURLExec::Execute(LPSHELLEXECUTEINFOA pei)
  87. {
  88. HRESULT hres;
  89. ASSERT(IS_VALID_STRUCT_PTR(this, CURLExec));
  90. ASSERT(IS_VALID_READ_PTR(pei, SHELLEXECUTEINFO));
  91. if (! pei->lpVerb ||
  92. ! lstrcmpi(pei->lpVerb, TEXT("open")))
  93. {
  94. if (pei->lpFile)
  95. {
  96. LPTSTR pszURL;
  97. // This should succeed only for real URLs. We should fail
  98. // for file paths and let the shell handle those.
  99. hres = TranslateURL(pei->lpFile,
  100. TRANSLATEURL_FL_GUESS_PROTOCOL | TRANSLATEURL_FL_CANONICALIZE,
  101. &pszURL);
  102. if (SUCCEEDED(hres))
  103. {
  104. LPCTSTR pszURLToUse;
  105. pszURLToUse = (hres == S_OK) ? pszURL : pei->lpFile;
  106. hres = ValidateURL(pszURLToUse);
  107. if (SUCCEEDED(hres))
  108. {
  109. IUniformResourceLocator * purl;
  110. hres = SHCoCreateInstance(NULL, &CLSID_InternetShortcut, NULL, IID_IUniformResourceLocator, (void **)&purl);
  111. if (SUCCEEDED(hres))
  112. {
  113. hres = purl->SetURL(pszURLToUse, 0);
  114. if (hres == S_OK)
  115. {
  116. IShellLink * psl;
  117. hres = purl->QueryInterface(IID_IShellLink, (void **)&psl);
  118. if (SUCCEEDED(hres))
  119. {
  120. URLINVOKECOMMANDINFO urlici;
  121. EVAL(psl->SetShowCmd(pei->nShow) == S_OK);
  122. urlici.dwcbSize = SIZEOF(urlici);
  123. urlici.hwndParent = pei->hwnd;
  124. urlici.pcszVerb = NULL;
  125. urlici.dwFlags = IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB;
  126. if (IsFlagClear(pei->fMask, SEE_MASK_FLAG_NO_UI))
  127. SetFlag(urlici.dwFlags, IURL_INVOKECOMMAND_FL_ALLOW_UI);
  128. hres = purl->InvokeCommand(&urlici);
  129. if (hres != S_OK)
  130. SetFlag(pei->fMask, SEE_MASK_FLAG_NO_UI);
  131. psl->Release();
  132. }
  133. }
  134. purl->Release();
  135. }
  136. }
  137. if (pszURL)
  138. LocalFree(pszURL);
  139. }
  140. }
  141. else
  142. // (scotth): This hook only handles execution of file string, not IDList.
  143. hres = S_FALSE;
  144. }
  145. else
  146. // Unrecognized verb.
  147. hres = S_FALSE;
  148. if (hres == S_OK)
  149. pei->hInstApp = (HINSTANCE)42; // huh??
  150. else if (FAILED(hres))
  151. {
  152. switch (hres)
  153. {
  154. case URL_E_INVALID_SYNTAX:
  155. case URL_E_UNREGISTERED_PROTOCOL:
  156. hres = S_FALSE;
  157. break;
  158. case E_OUTOFMEMORY:
  159. pei->hInstApp = (HINSTANCE)SE_ERR_OOM;
  160. hres = E_FAIL;
  161. break;
  162. case IS_E_EXEC_FAILED:
  163. // Translate execution failure into "file not found".
  164. pei->hInstApp = (HINSTANCE)SE_ERR_FNF;
  165. hres = E_FAIL;
  166. break;
  167. default:
  168. // pei->lpFile is bogus. Treat as file not found.
  169. ASSERT(hres == E_POINTER);
  170. pei->hInstApp = (HINSTANCE)SE_ERR_FNF;
  171. hres = E_FAIL;
  172. break;
  173. }
  174. }
  175. else
  176. ASSERT(hres == S_FALSE);
  177. ASSERT(hres == S_OK ||
  178. hres == S_FALSE ||
  179. hres == E_FAIL);
  180. return hres;
  181. }
  182. STDMETHODIMP CURLExec::Execute(LPSHELLEXECUTEINFOW pei)
  183. {
  184. // thunk stuff copied from shlexec.c InvokeShellExecuteHook
  185. SHELLEXECUTEINFOA seia;
  186. UINT cchVerb = 0;
  187. UINT cchFile = 0;
  188. UINT cchParameters = 0;
  189. UINT cchDirectory = 0;
  190. UINT cchClass = 0;
  191. LPSTR lpszBuffer;
  192. HRESULT hres = E_FAIL;
  193. seia = *(SHELLEXECUTEINFOA*)pei; // Copy all of the binary data
  194. if (pei->lpVerb)
  195. {
  196. cchVerb = WideCharToMultiByte(CP_ACP,0,
  197. pei->lpVerb, -1,
  198. NULL, 0,
  199. NULL, NULL)+1;
  200. }
  201. if (pei->lpFile)
  202. cchFile = WideCharToMultiByte(CP_ACP,0,
  203. pei->lpFile, -1,
  204. NULL, 0,
  205. NULL, NULL)+1;
  206. if (pei->lpParameters)
  207. cchParameters = WideCharToMultiByte(CP_ACP,0,
  208. pei->lpParameters, -1,
  209. NULL, 0,
  210. NULL, NULL)+1;
  211. if (pei->lpDirectory)
  212. cchDirectory = WideCharToMultiByte(CP_ACP,0,
  213. pei->lpDirectory, -1,
  214. NULL, 0,
  215. NULL, NULL)+1;
  216. if (((pei->fMask & SEE_MASK_CLASS) == SEE_MASK_CLASSNAME) && pei->lpClass)
  217. cchClass = WideCharToMultiByte(CP_ACP,0,
  218. pei->lpClass, -1,
  219. NULL, 0,
  220. NULL, NULL)+1;
  221. // what is this (alloca)? InvokeShellExecuteHook is not freeing lpszBuffer
  222. //lpszBuffer = alloca(cchVerb+cchFile+cchParameters+cchDirectory+cchClass);
  223. lpszBuffer = (LPSTR)LocalAlloc(LPTR, cchVerb+cchFile+cchParameters+cchDirectory+cchClass);
  224. if (lpszBuffer)
  225. {
  226. LPSTR lpsz = lpszBuffer;
  227. seia.lpVerb = NULL;
  228. seia.lpFile = NULL;
  229. seia.lpParameters = NULL;
  230. seia.lpDirectory = NULL;
  231. seia.lpClass = NULL;
  232. //
  233. // Convert all of the strings to ANSI
  234. //
  235. if (pei->lpVerb)
  236. {
  237. WideCharToMultiByte(CP_ACP, 0, pei->lpVerb, -1,
  238. lpszBuffer, cchVerb, NULL, NULL);
  239. seia.lpVerb = lpszBuffer;
  240. lpszBuffer += cchVerb;
  241. }
  242. if (pei->lpFile)
  243. {
  244. WideCharToMultiByte(CP_ACP, 0, pei->lpFile, -1,
  245. lpszBuffer, cchFile, NULL, NULL);
  246. seia.lpFile = lpszBuffer;
  247. lpszBuffer += cchFile;
  248. }
  249. if (pei->lpParameters)
  250. {
  251. WideCharToMultiByte(CP_ACP, 0,
  252. pei->lpParameters, -1,
  253. lpszBuffer, cchParameters, NULL, NULL);
  254. seia.lpParameters = lpszBuffer;
  255. lpszBuffer += cchParameters;
  256. }
  257. if (pei->lpDirectory)
  258. {
  259. WideCharToMultiByte(CP_ACP, 0,
  260. pei->lpDirectory, -1,
  261. lpszBuffer, cchDirectory, NULL, NULL);
  262. seia.lpDirectory = lpszBuffer;
  263. lpszBuffer += cchDirectory;
  264. }
  265. if (((pei->fMask & SEE_MASK_CLASS) == SEE_MASK_CLASSNAME) && pei->lpClass)
  266. {
  267. WideCharToMultiByte(CP_ACP, 0,
  268. pei->lpClass, -1,
  269. lpszBuffer, cchClass, NULL, NULL);
  270. seia.lpClass = lpszBuffer;
  271. }
  272. hres = Execute(&seia);
  273. // now thunk the possible new stuff back
  274. pei->hInstApp = seia.hInstApp;
  275. if (pei->fMask & SEE_MASK_NOCLOSEPROCESS)
  276. pei->hProcess = seia.hProcess;
  277. LocalFree(lpsz);
  278. }
  279. return hres;
  280. }
  281. STDAPI CreateInstance_URLExec(LPUNKNOWN punkOuter, REFIID riid, void **ppvOut)
  282. {
  283. *ppvOut = NULL;
  284. if (punkOuter)
  285. return CLASS_E_NOAGGREGATION;
  286. CURLExec *pue = new(CURLExec);
  287. if (!pue)
  288. return E_OUTOFMEMORY;
  289. HRESULT hres = pue->QueryInterface(riid, ppvOut);
  290. pue->Release();
  291. return hres;
  292. }