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.

485 lines
12 KiB

  1. #include "stdinc.h"
  2. #include <string>
  3. #include <assert.h>
  4. #include <string.h>
  5. #include <set>
  6. #include "ihost.h"
  7. #include "ithunk.h"
  8. #include "idsource.h"
  9. #include "iuiview.h"
  10. #include "SxApwHandle.h"
  11. #include "SxApwCreate.h"
  12. #include "SxApwContext.h"
  13. #include "SxApwComPtr.h"
  14. #include "SxApwDLoad.h"
  15. #include "create.h"
  16. typedef HRESULT (STDMETHODCALLTYPE* PFN_DLL_GET_CLASS_OBJECT)(REFCLSID rclsid, REFIID riid, LPVOID* ppv);
  17. BOOL
  18. SxApwIsErrorResourceNotFound(
  19. DWORD dwError
  20. )
  21. {
  22. if (
  23. dwError == ERROR_RESOURCE_DATA_NOT_FOUND
  24. || dwError == ERROR_RESOURCE_TYPE_NOT_FOUND
  25. || dwError == ERROR_RESOURCE_NAME_NOT_FOUND
  26. || dwError == ERROR_RESOURCE_LANG_NOT_FOUND
  27. )
  28. {
  29. return TRUE;
  30. }
  31. return FALSE;
  32. }
  33. HRESULT
  34. SxApwWrapComObject(
  35. CSxApwActCtxHandle& actctx,
  36. REFIID riid,
  37. IUnknown* punk,
  38. void** ppv
  39. );
  40. template <typename T, typename U>
  41. inline HRESULT
  42. SxApwWrapComObject(
  43. CSxApwActCtxHandle& actctx,
  44. T t,
  45. U u
  46. )
  47. {
  48. assert(__uuidof(T) == __uuidof(U));
  49. return SxApwWrapComObject(actctx, __uuidof(T), t, u);
  50. }
  51. class CSxApwActCtxScope : public CFusionActCtxScope
  52. {
  53. private:
  54. typedef CFusionActCtxScope Base;
  55. public:
  56. ~CSxApwActCtxScope() { }
  57. CSxApwActCtxScope() { }
  58. CSxApwActCtxScope(const CSxApwActCtxHandle& handle) { Init(handle); }
  59. CSxApwActCtxScope(HANDLE handle) { Init(handle); }
  60. void Init(HANDLE handle)
  61. {
  62. if (!Base::Win32Activate(handle))
  63. OutputDebugStringA("Error ignored in " __FUNCTION__ "\n");
  64. }
  65. };
  66. STDMETHODIMP
  67. CSxApwHostThunk::InformSchema(
  68. const SxApwColumnInfo rgColumnInfo[],
  69. int nColumns
  70. )
  71. {
  72. CSxApwActCtxScope actctxScope(m_actctxHandle);
  73. return m_underlying->InformSchema(rgColumnInfo, nColumns);
  74. }
  75. STDMETHODIMP
  76. CSxApwHostThunk::OnQueryDone(
  77. )
  78. {
  79. CSxApwActCtxScope actctxScope(m_actctxHandle);
  80. return m_underlying->OnQueryDone();
  81. }
  82. STDMETHODIMP
  83. CSxApwHostThunk::OnRowCountEstimateAvailable(
  84. int nRows
  85. )
  86. {
  87. CSxApwActCtxScope actctxScope(m_actctxHandle);
  88. return m_underlying->OnRowCountEstimateAvailable(nRows);
  89. }
  90. STDMETHODIMP
  91. CSxApwHostThunk::OnNextRow(
  92. int nColumns,
  93. const LPCWSTR rgpszColumns[]
  94. )
  95. {
  96. CSxApwActCtxScope actctxScope(m_actctxHandle);
  97. return m_underlying->OnNextRow(nColumns, rgpszColumns);
  98. }
  99. STDMETHODIMP CSxApwHostThunk::DestroyView(
  100. LPCWSTR x
  101. )
  102. {
  103. CSxApwActCtxScope actctxScope(m_actctxHandle);
  104. return m_underlying->DestroyView(x);
  105. }
  106. STDMETHODIMP CSxApwHostThunk::CreateView(
  107. LPCWSTR x
  108. )
  109. {
  110. CSxApwActCtxScope actctxScope(m_actctxHandle);
  111. return m_underlying->CreateView(x);
  112. }
  113. STDMETHODIMP
  114. CSxApwHostThunk::RunQuery(
  115. LPCWSTR query
  116. )
  117. {
  118. CSxApwActCtxScope actctxScope(m_actctxHandle);
  119. return m_underlying->RunQuery(query);
  120. }
  121. STDMETHODIMP
  122. CSxApwHostThunk::SetDataSource(
  123. LPCWSTR datasource
  124. )
  125. {
  126. CSxApwActCtxScope actctxScope(m_actctxHandle);
  127. return m_underlying->SetDataSource(datasource);
  128. }
  129. STDMETHODIMP
  130. CSxApwDataSourceThunk::SetSite(
  131. ISxApwHost* host
  132. )
  133. {
  134. HRESULT hr = S_OK;
  135. CSxApwComPtr<ISxApwHost> hostThunk;
  136. CSxApwActCtxHandle actctxHandleNull(NULL);
  137. if (FAILED(hr = SxApwWrapComObject(actctxHandleNull, host, &hostThunk)))
  138. return hr;
  139. CSxApwActCtxScope actctxScope(m_actctxHandle);
  140. hr = m_underlying->SetSite(hostThunk);
  141. return hr;
  142. }
  143. STDMETHODIMP
  144. CSxApwDataSourceThunk::RunQuery(
  145. LPCWSTR query
  146. )
  147. {
  148. CSxApwActCtxScope actctxScope(m_actctxHandle);
  149. return m_underlying->RunQuery(query);
  150. }
  151. STDMETHODIMP
  152. CSxApwDataSourceThunk::StopQuery(
  153. )
  154. {
  155. CSxApwActCtxScope actctxScope(m_actctxHandle);
  156. return m_underlying->StopQuery();
  157. }
  158. STDMETHODIMP
  159. CSxApwUiViewThunk::InformSchema(
  160. const SxApwColumnInfo rgColumnInfo[],
  161. int nColumns
  162. )
  163. {
  164. CSxApwActCtxScope actctxScope(m_actctxHandle);
  165. return m_underlying->InformSchema(rgColumnInfo, nColumns);
  166. }
  167. STDMETHODIMP
  168. CSxApwUiViewThunk::SetSite(
  169. ISxApwHost* host
  170. )
  171. {
  172. HRESULT hr = S_OK;
  173. CSxApwComPtr<ISxApwHost> hostThunk;
  174. CSxApwActCtxHandle actctxHandleNull(NULL);
  175. if (FAILED(hr = SxApwWrapComObject(actctxHandleNull, host, &hostThunk)))
  176. return hr;
  177. CSxApwActCtxScope actctxScope(m_actctxHandle);
  178. hr = m_underlying->SetSite(hostThunk);
  179. return hr;
  180. }
  181. STDMETHODIMP
  182. CSxApwUiViewThunk::CreateWindow(
  183. HWND hWnd
  184. )
  185. {
  186. CSxApwActCtxScope actctxScope(m_actctxHandle);
  187. return m_underlying->CreateWindow(hWnd);
  188. }
  189. STDMETHODIMP
  190. CSxApwUiViewThunk::OnNextRow(
  191. int nColumns,
  192. const LPCWSTR* prgszColumns
  193. )
  194. {
  195. CSxApwActCtxScope actctxScope(m_actctxHandle);
  196. return m_underlying->OnNextRow(nColumns, prgszColumns);
  197. }
  198. STDMETHODIMP
  199. CSxApwUiViewThunk::OnRowCountEstimateAvailable(
  200. int nRowCountEstimate
  201. )
  202. {
  203. CSxApwActCtxScope actctxScope(m_actctxHandle);
  204. return m_underlying->OnRowCountEstimateAvailable(nRowCountEstimate);
  205. }
  206. STDMETHODIMP
  207. CSxApwUiViewThunk::OnQueryStart(
  208. )
  209. {
  210. CSxApwActCtxScope actctxScope(m_actctxHandle);
  211. return m_underlying->OnQueryStart();
  212. }
  213. STDMETHODIMP
  214. CSxApwUiViewThunk::OnQueryDone(
  215. )
  216. {
  217. CSxApwActCtxScope actctxScope(m_actctxHandle);
  218. return m_underlying->OnQueryDone();
  219. }
  220. class CInterfaceClassPair
  221. {
  222. public:
  223. const IID* piid;
  224. const CLSID* pclsid;
  225. };
  226. const static CInterfaceClassPair g_interfaceClassPairs[] =
  227. {
  228. #define X(x) { &__uuidof(x::ThunkedInterface), &__uuidof(x) },
  229. X(CSxApwDataSourceThunk)
  230. X(CSxApwUiViewThunk)
  231. X(CSxApwHostThunk)
  232. #undef X
  233. };
  234. HRESULT
  235. SxApwWrapComObject(
  236. CSxApwActCtxHandle& actctx,
  237. REFIID riid,
  238. IUnknown* punk,
  239. void** ppv
  240. )
  241. {
  242. HRESULT hr = S_OK;
  243. ULONG i;
  244. ATL::CComQIPtr<ISxApwThunk> isAlreadyThunked(punk);
  245. ATL::CComQIPtr<ISxApwThunk> thunk;
  246. if (isAlreadyThunked != NULL)
  247. {
  248. hr = punk->QueryInterface(riid, ppv);
  249. goto Exit;
  250. }
  251. if (static_cast<HANDLE>(actctx) == NULL)
  252. {
  253. WCHAR path[MAX_PATH];
  254. HMODULE hModule = NULL;
  255. if (FAILED(hr = SxApwHmoduleFromObject(punk, &hModule)))
  256. goto Exit;
  257. IFFALSE_WIN32TOHR_EXIT(hr, GetModuleFileNameW(hModule, path, NUMBER_OF(path)));
  258. if (FAILED(hr = actctx.HrCreate(path)))
  259. goto Exit;
  260. }
  261. for (i = 0 ; i != NUMBER_OF(g_interfaceClassPairs) ; ++i)
  262. {
  263. if (*g_interfaceClassPairs[i].piid == riid)
  264. {
  265. if (FAILED(hr = SxApwHostCreateObject(*g_interfaceClassPairs[i].pclsid, SXAPW_CREATEOBJECT_NOWRAP, &thunk)))
  266. goto Exit;
  267. if (FAILED(hr = thunk->InitThunk(punk, actctx)))
  268. goto Exit;
  269. actctx.Detach();
  270. hr = thunk->QueryInterface(riid, ppv); // extra addref cycle, trying to avoid 0
  271. goto Exit;
  272. }
  273. }
  274. OutputDebugStringA("object not wrapped\n");
  275. hr = S_OK;
  276. Exit:
  277. return hr;
  278. }
  279. HRESULT
  280. SxApwHostCreateObject(
  281. PCWSTR psz,
  282. REFIID riid,
  283. DWORD dwFlags,
  284. void** ppv
  285. )
  286. {
  287. HRESULT hr;
  288. CLSID clsid;
  289. PCWSTR dot;
  290. if ((dot = wcsrchr(psz, '.')) != NULL
  291. && _wcsicmp(dot, L".dll") == 0
  292. )
  293. {
  294. //
  295. // category bind, pass NULL clsid, DllGetClassObject tries the first
  296. // entry in the map
  297. //
  298. const PCWSTR dllPath = psz;
  299. CDynamicLinkLibrary dll;
  300. CSxApwComPtr<IClassFactory> classFactory;
  301. CSxApwComPtr<IUnknown> unk;
  302. CSxApwActCtxHandle actctxHandle;
  303. CSxApwActCtxScope actctxScope;
  304. PFN_DLL_GET_CLASS_OBJECT pfnDllGetClassObject;
  305. if (dwFlags & SXAPW_CREATEOBJECT_WRAP)
  306. {
  307. if (FAILED(hr = actctxHandle.HrCreate(dllPath)))
  308. goto Exit;
  309. actctxScope.Init(actctxHandle);
  310. }
  311. IFFALSE_WIN32TOHR_EXIT(hr, dll.Win32Create(dllPath));
  312. IFFALSE_WIN32TOHR_EXIT(hr, dll.GetProcAddress("DllGetClassObject", &pfnDllGetClassObject));
  313. if (FAILED(hr = pfnDllGetClassObject(GUID_NULL, __uuidof(classFactory), &classFactory)))
  314. goto Exit;
  315. if (FAILED(hr = classFactory->CreateInstance(NULL, riid, &unk)))
  316. goto Exit;
  317. if (dwFlags & SXAPW_CREATEOBJECT_WRAP)
  318. {
  319. if (FAILED(hr = SxApwWrapComObject(actctxHandle, riid, unk, ppv)))
  320. goto Exit;
  321. }
  322. else
  323. {
  324. *ppv = unk.Detach();
  325. }
  326. dll.Detach(); // leak the dll
  327. hr = S_OK;
  328. goto Exit;
  329. }
  330. else
  331. {
  332. if (FAILED(hr = CLSIDFromString(const_cast<PWSTR>(psz), &clsid)))
  333. goto Exit;
  334. if (FAILED(hr = SxApwHostCreateObject(clsid, riid, dwFlags, ppv)))
  335. goto Exit;
  336. }
  337. hr = S_OK;
  338. Exit:
  339. return hr;
  340. }
  341. HRESULT
  342. SxApwHostCreateObject(
  343. REFCLSID rclsid,
  344. REFIID riid,
  345. DWORD dwFlags,
  346. void** ppv
  347. )
  348. /*
  349. Strategy:
  350. Enumerate .dlls in the same directory as the .exe, calling DllGetClassObject on each, etc..
  351. This is subject to change.
  352. This code is presently shared both by the host and the managers...maybe this is wrong.
  353. */
  354. {
  355. HRESULT hr = E_FAIL;
  356. CFindFile findFile;
  357. WCHAR exePath[MAX_PATH];
  358. WCHAR dllPath[MAX_PATH];
  359. HMODULE exeHandle;
  360. WIN32_FIND_DATAW findData;
  361. PWSTR filePart;
  362. IFFALSE_WIN32TOHR_EXIT(hr, exeHandle = GetModuleHandleW(NULL));
  363. IFFALSE_WIN32TOHR_EXIT(hr, GetModuleFileNameW(exeHandle, exePath, RTL_NUMBER_OF(exePath)));
  364. wcscpy(dllPath, exePath);
  365. filePart = 1 + wcsrchr(dllPath, '\\');
  366. wcscpy(filePart, L"sxapw*.dll");
  367. //
  368. // enumerate .dlls in the .exe's directory and try any that export DllGetClassObject
  369. //
  370. if (findFile.Win32Create(dllPath, &findData))
  371. {
  372. bool fCheckedExe = false;
  373. bool fCheckExe = false;
  374. do
  375. {
  376. CDynamicLinkLibrary dll;
  377. CSxApwComPtr<IClassFactory> classFactory;
  378. CSxApwActCtxHandle actctxHandle;
  379. CSxApwActCtxScope actctxScope;
  380. PFN_DLL_GET_CLASS_OBJECT pfnDllGetClassObject;
  381. CSxApwComPtr<IUnknown> unk;
  382. //
  383. // we ought to check the exe first instead of last, and independent of if
  384. // if there are any .dlls..
  385. //
  386. if (fCheckExe)
  387. {
  388. fCheckedExe = true;
  389. wcscpy(dllPath, exePath);
  390. }
  391. else
  392. {
  393. wcscpy(filePart, findData.cFileName);
  394. }
  395. if (dwFlags & SXAPW_CREATEOBJECT_WRAP)
  396. {
  397. if (FAILED(hr = actctxHandle.HrCreate(dllPath)))
  398. goto Exit;
  399. actctxScope.Init(actctxHandle);
  400. }
  401. IFFALSE_WIN32TOHR_EXIT(hr, dll.Win32Create(dllPath));
  402. if (dll.GetProcAddress("DllGetClassObject", &pfnDllGetClassObject))
  403. {
  404. if (FAILED(hr = pfnDllGetClassObject(rclsid, __uuidof(classFactory), &classFactory)))
  405. continue;
  406. }
  407. else
  408. {
  409. const DWORD LastError = ::GetLastError();
  410. if (LastError != ERROR_PROC_NOT_FOUND)
  411. {
  412. TRACE_WIN32_FAILURE(GetProcAddress);
  413. hr = HRESULT_FROM_WIN32(LastError);
  414. goto Exit;
  415. }
  416. if (dll != GetModule()->GetModuleInstance())
  417. {
  418. continue;
  419. }
  420. if (FAILED(hr = GetModule()->GetClassObject(rclsid, __uuidof(classFactory), &classFactory)))
  421. continue;
  422. }
  423. if (FAILED(hr = classFactory->CreateInstance(NULL, riid, &unk)))
  424. continue;
  425. if (dwFlags & SXAPW_CREATEOBJECT_WRAP)
  426. {
  427. if (FAILED(hr = SxApwWrapComObject(actctxHandle, riid, unk, ppv)))
  428. goto Exit;
  429. }
  430. else
  431. {
  432. *ppv = unk.Detach();
  433. }
  434. dll.Detach(); // leak the .dll
  435. hr = S_OK;
  436. goto Exit;
  437. } while (FindNextFileW(findFile, &findData) || (!fCheckedExe && (fCheckExe = true)));
  438. }
  439. hr = REGDB_E_CLASSNOTREG;
  440. Exit:
  441. return hr;
  442. }