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.

623 lines
16 KiB

  1. // CActCtx.cpp : Implementation of CActCtx
  2. #include "stdinc.h"
  3. #include "sxsoa.h"
  4. #include "actctx.h"
  5. #define NUMBER_OF(x) RTL_NUMBER_OF(x)
  6. class CActivation
  7. {
  8. public:
  9. CActivation(CActCtx &rActCtx, HANDLE hActCtx) : m_rActCtx(rActCtx), m_hActCtx(hActCtx), m_ulpCookie(0) { }
  10. CActivation(CActCtx &rActCtx) : m_rActCtx(rActCtx), m_hActCtx(NULL), m_ulpCookie(0) { }
  11. ~CActivation() { if (m_ulpCookie != 0) { (*m_rActCtx.ms_pDeactivateActCtx)(0, m_ulpCookie); } }
  12. void Attach(HANDLE hActCtx) { _ASSERTE(m_ulpCookie == 0); m_hActCtx = hActCtx; }
  13. HRESULT Activate()
  14. {
  15. if (m_ulpCookie != 0)
  16. return E_UNEXPECTED;
  17. if (!(*m_rActCtx.ms_pActivateActCtx)(m_hActCtx, &m_ulpCookie))
  18. return HRESULT_FROM_WIN32(::GetLastError());
  19. return NOERROR;
  20. }
  21. HRESULT Deactivate()
  22. {
  23. ULONG_PTR ulpCookie = m_ulpCookie; // capture
  24. m_ulpCookie = 0;
  25. if (ulpCookie == 0)
  26. return E_UNEXPECTED;
  27. if (!(*m_rActCtx.ms_pDeactivateActCtx)(0, ulpCookie))
  28. return HRESULT_FROM_WIN32(::GetLastError());
  29. return NOERROR;
  30. }
  31. protected:
  32. CActCtx &m_rActCtx;
  33. HANDLE m_hActCtx;
  34. ULONG_PTR m_ulpCookie;
  35. };
  36. /////////////////////////////////////////////////////////////////////////////
  37. // CActCtx
  38. HINSTANCE CActCtx::ms_hKERNEL32 = NULL;
  39. CActCtx::PFNCreateActCtxW CActCtx::ms_pCreateActCtxW = NULL;
  40. CActCtx::PFNAddRefActCtx CActCtx::ms_pAddRefActCtx = NULL;
  41. CActCtx::PFNReleaseActCtx CActCtx::ms_pReleaseActCtx = NULL;
  42. CActCtx::PFNActivateActCtx CActCtx::ms_pActivateActCtx = NULL;
  43. CActCtx::PFNDeactivateActCtx CActCtx::ms_pDeactivateActCtx = NULL;
  44. HRESULT CActCtx::FetchManifestInfo(ACTCTX_MANIFEST_INFO_TYPE infotype, BSTR *pVal)
  45. {
  46. HRESULT hr = E_FAIL;
  47. BSTR bstrResult = NULL;
  48. if (pVal != NULL)
  49. *pVal = NULL;
  50. if (pVal == NULL)
  51. {
  52. hr = E_INVALIDARG;
  53. goto Exit;
  54. }
  55. if (infotype == ACTCTX_MANIFEST_FILE)
  56. {
  57. bstrResult = ::SysAllocString((m_bstrManifest.m_str == NULL) ? L"" : m_bstrManifest);
  58. }
  59. else if (infotype == ACTCTX_MANIFEST_TEXT)
  60. {
  61. bstrResult = ::SysAllocString((m_bstrManifestText.m_str == NULL) ? L"" : m_bstrManifestText);
  62. }
  63. else if (infotype == ACTCTX_MANIFEST_URL)
  64. {
  65. bstrResult = ::SysAllocString((m_bstrManifestURL.m_str == NULL) ? L"" : m_bstrManifestURL);
  66. }
  67. else
  68. {
  69. hr = E_INVALIDARG;
  70. goto Exit;
  71. }
  72. if (bstrResult == NULL)
  73. {
  74. hr = E_OUTOFMEMORY;
  75. goto Exit;
  76. }
  77. *pVal = bstrResult;
  78. bstrResult = NULL;
  79. hr = NOERROR;
  80. Exit:
  81. if (bstrResult != NULL)
  82. ::SysFreeString(bstrResult);
  83. return hr;
  84. }
  85. HRESULT MakeTemporaryFileName(CComBSTR & str)
  86. {
  87. // generate a temporary filename
  88. HRESULT hr = E_FAIL;
  89. BSTR bstrTempFileName = NULL;
  90. WCHAR TempPath[MAX_PATH];
  91. WCHAR TempFileName[MAX_PATH];
  92. if ( 0 == GetTempPathW(MAX_PATH, TempPath))
  93. goto SetHrErrorAndExit;
  94. if ( 0 == GetTempFileNameW(TempPath, L"sxs", 0, TempFileName))
  95. goto SetHrErrorAndExit;
  96. bstrTempFileName = SysAllocString(TempFileName);
  97. if (bstrTempFileName == NULL)
  98. {
  99. hr = E_OUTOFMEMORY;
  100. goto Exit;
  101. }
  102. str.Attach(bstrTempFileName);
  103. bstrTempFileName = NULL;
  104. hr = S_OK;
  105. goto Exit;
  106. SetHrErrorAndExit:
  107. hr = HRESULT_FROM_WIN32(::GetLastError());
  108. Exit:
  109. if (bstrTempFileName != NULL)
  110. SysFreeString(bstrTempFileName);
  111. return hr;
  112. }
  113. HRESULT CActCtx::SetManifestInfo(ACTCTX_MANIFEST_INFO_TYPE infotype, BSTR newVal)
  114. {
  115. HRESULT hr = E_FAIL;
  116. HANDLE hActCtx = INVALID_HANDLE_VALUE;
  117. ACTCTXW acw = { sizeof(acw) };
  118. CComBSTR bstrTemp;
  119. CComBSTR bstrManifestFile;
  120. HANDLE hTempFile = INVALID_HANDLE_VALUE;
  121. if (newVal == NULL)
  122. {
  123. hr = E_INVALIDARG;
  124. goto Exit;
  125. }
  126. if (infotype == ACTCTX_MANIFEST_FILE)
  127. {
  128. bstrManifestFile.Attach(newVal);
  129. }
  130. else if (infotype == ACTCTX_MANIFEST_TEXT)
  131. {
  132. DWORD NumberOfBytesWritten;
  133. hr = MakeTemporaryFileName(bstrManifestFile);
  134. if (FAILED(hr))
  135. goto Exit;
  136. hTempFile = CreateFileW((LPWSTR)bstrManifestFile,
  137. GENERIC_READ | GENERIC_WRITE,
  138. 0, // do not share
  139. NULL, // no security
  140. CREATE_ALWAYS, // overwrite existing file
  141. FILE_ATTRIBUTE_NORMAL, // normal file
  142. NULL); // no attr. template
  143. if (hTempFile == INVALID_HANDLE_VALUE)
  144. goto SetHrErrorAndExit;
  145. // "TODO:" or "DO WE NEED TODO?":
  146. // check the encoding of the manifest, if it is encoded as "UTF-8", we have to transfer the
  147. // textual manifest into byte before writing into a file.
  148. // be sure that your manifest is UCS-2
  149. ULONG XML_UCS2_BOM=0xFEFF;
  150. if ( FALSE == WriteFile(hTempFile, (LPCVOID)&XML_UCS2_BOM, 2, &NumberOfBytesWritten, NULL))
  151. goto SetHrErrorAndExit;
  152. if ( FALSE == WriteFile(hTempFile, (LPCVOID)((LPWSTR)newVal), SysStringByteLen(newVal), &NumberOfBytesWritten, NULL))
  153. goto SetHrErrorAndExit;
  154. if ( FALSE == CloseHandle(hTempFile))
  155. goto SetHrErrorAndExit;
  156. hTempFile = INVALID_HANDLE_VALUE;
  157. }
  158. else if (infotype == ACTCTX_MANIFEST_URL)
  159. {
  160. hr = MakeTemporaryFileName(bstrManifestFile);
  161. if (FAILED(hr))
  162. {
  163. goto Exit;
  164. }
  165. if (FAILED(hr = URLDownloadToFileW(NULL, (LPWSTR)newVal, (LPWSTR)bstrManifestFile, 0, NULL)))
  166. goto Exit;
  167. }
  168. else
  169. {
  170. hr = E_INVALIDARG;
  171. goto Exit;
  172. }
  173. if (FAILED(hr = this->EnsureInitialized()))
  174. goto Exit;
  175. acw.lpSource = bstrManifestFile;
  176. hActCtx = (*ms_pCreateActCtxW)(&acw);
  177. if (hActCtx == INVALID_HANDLE_VALUE)
  178. {
  179. hr = HRESULT_FROM_WIN32(::GetLastError());
  180. goto Exit;
  181. }
  182. bstrTemp.Attach(::SysAllocString(newVal));
  183. if (bstrTemp == static_cast<BSTR>(NULL))
  184. {
  185. hr = E_OUTOFMEMORY;
  186. goto Exit;
  187. }
  188. m_cs.Lock();
  189. if (m_hActCtx != NULL)
  190. (*ms_pReleaseActCtx)(m_hActCtx);
  191. m_hActCtx = hActCtx;
  192. hActCtx = NULL;
  193. m_bstrManifest.Empty();
  194. m_bstrManifestURL.Empty();
  195. m_bstrManifestText.Empty();
  196. switch (infotype)
  197. {
  198. case ACTCTX_MANIFEST_FILE:
  199. m_bstrManifest.Attach(bstrTemp.Detach());
  200. break;
  201. case ACTCTX_MANIFEST_TEXT:
  202. m_bstrManifestText.Attach(bstrTemp.Detach());
  203. break;
  204. case ACTCTX_MANIFEST_URL:
  205. m_bstrManifestURL.Attach(bstrTemp.Detach());
  206. break;
  207. default: // impossible path because infotype has been checked at the beginning of the function
  208. hr = E_INVALIDARG;
  209. goto Exit;
  210. }
  211. m_cs.Unlock();
  212. hr = NOERROR;
  213. goto Exit;
  214. SetHrErrorAndExit:
  215. hr = HRESULT_FROM_WIN32(::GetLastError());
  216. Exit:
  217. if (hTempFile != INVALID_HANDLE_VALUE)
  218. CloseHandle(hTempFile);
  219. if (infotype == ACTCTX_MANIFEST_FILE)
  220. bstrManifestFile.Detach();
  221. if (hActCtx != NULL && hActCtx != INVALID_HANDLE_VALUE)
  222. (*ms_pReleaseActCtx)(hActCtx);
  223. return hr;
  224. }
  225. STDMETHODIMP CActCtx::CreateObject(BSTR bstrObjectReference, VARIANT *pvarLocation, IDispatch **ppObject)
  226. {
  227. HRESULT hr = E_FAIL;
  228. CLSID clsid;
  229. COSERVERINFO csi = { 0 };
  230. MULTI_QI rgmqi[1];
  231. ULONG cmqi = 0, imqiIDispatch, i;
  232. HANDLE hActCtx = INVALID_HANDLE_VALUE;
  233. CActivation act(*this);
  234. BSTR bstrLocation = NULL;
  235. if (ppObject != NULL)
  236. *ppObject = NULL;
  237. if (ppObject == NULL)
  238. {
  239. hr = E_INVALIDARG;
  240. goto Exit;
  241. }
  242. if ((pvarLocation != NULL) &&
  243. (pvarLocation->vt != VT_ERROR))
  244. {
  245. if (pvarLocation->vt != VT_BSTR)
  246. {
  247. hr = E_INVALIDARG;
  248. goto Exit;
  249. }
  250. bstrLocation = pvarLocation->bstrVal;
  251. }
  252. if (FAILED(hr = this->EnsureInitialized()))
  253. goto Exit;
  254. m_cs.Lock();
  255. hActCtx = m_hActCtx;
  256. (*ms_pAddRefActCtx)(hActCtx);
  257. m_cs.Unlock();
  258. act.Attach(hActCtx);
  259. act.Activate();
  260. if (FAILED(hr = ::CLSIDFromProgID(bstrObjectReference, &clsid)))
  261. goto Exit;
  262. if (bstrLocation != NULL)
  263. csi.pwszName = bstrLocation;
  264. cmqi = 0;
  265. _ASSERTE(cmqi < NUMBER_OF(rgmqi));
  266. rgmqi[cmqi].hr = NOERROR;
  267. rgmqi[cmqi].pIID = &IID_IDispatch;
  268. rgmqi[cmqi].pItf = NULL;
  269. imqiIDispatch = cmqi;
  270. cmqi++;
  271. if (FAILED(hr = ::CoCreateInstanceEx(
  272. clsid,
  273. NULL,
  274. CLSCTX_SERVER,
  275. &csi,
  276. cmqi,
  277. rgmqi)))
  278. goto Exit;
  279. // See if any of the QIs failed...
  280. for (i=0; i<cmqi; i++)
  281. {
  282. if (FAILED(hr = rgmqi[i].hr))
  283. goto Exit;
  284. }
  285. act.Deactivate();
  286. *ppObject = static_cast<IDispatch *>(rgmqi[imqiIDispatch].pItf);
  287. rgmqi[imqiIDispatch].pItf = NULL;
  288. hr = NOERROR;
  289. Exit:
  290. for (i=0; i<cmqi; i++)
  291. {
  292. if (rgmqi[i].pItf != NULL)
  293. rgmqi[i].pItf->Release();
  294. }
  295. if ((hActCtx != NULL) &&
  296. (hActCtx != INVALID_HANDLE_VALUE))
  297. (*ms_pReleaseActCtx)(hActCtx);
  298. return hr;
  299. }
  300. STDMETHODIMP CActCtx::GetObject(VARIANT *pvarMoniker, VARIANT *pvarProgID, IDispatch **ppIDispatch)
  301. {
  302. HRESULT hr = E_FAIL;
  303. CComPtr<IDispatch> srpIDispatch;
  304. CComPtr<IBindCtx> srpIBindCtx;
  305. CComPtr<IMoniker> srpIMoniker;
  306. CComVariant svarProgId;
  307. HANDLE hActCtx = INVALID_HANDLE_VALUE;
  308. CActivation act(*this);
  309. BSTR bstrMoniker = NULL;
  310. if (ppIDispatch != NULL)
  311. *ppIDispatch = NULL;
  312. if (ppIDispatch == NULL)
  313. {
  314. hr = E_INVALIDARG;
  315. goto Exit;
  316. }
  317. if (FAILED(hr = this->EnsureInitialized()))
  318. goto Exit;
  319. if (pvarMoniker != NULL)
  320. {
  321. if (pvarMoniker->vt != VT_ERROR)
  322. {
  323. if (pvarMoniker->vt != VT_BSTR)
  324. {
  325. hr = DISP_E_TYPEMISMATCH;
  326. goto Exit;
  327. }
  328. bstrMoniker = pvarMoniker->bstrVal;
  329. }
  330. }
  331. if ((bstrMoniker != NULL) && (bstrMoniker[0] == L'\0'))
  332. bstrMoniker = NULL;
  333. m_cs.Lock();
  334. hActCtx = m_hActCtx;
  335. (*ms_pAddRefActCtx)(hActCtx);
  336. m_cs.Unlock();
  337. act.Attach(hActCtx);
  338. act.Activate();
  339. if ((pvarProgID != NULL) && (pvarProgID->vt != VT_ERROR))
  340. {
  341. hr = svarProgId.ChangeType(VT_BSTR, pvarProgID);
  342. if (FAILED(hr))
  343. goto Exit;
  344. hr = this->CreateObject(svarProgId.bstrVal, NULL, &srpIDispatch);
  345. if (FAILED(hr))
  346. goto Exit;
  347. if (bstrMoniker != NULL)
  348. {
  349. CComPtr<IPersistFile> srpIPersistFile;
  350. hr = srpIDispatch.QueryInterface(&srpIPersistFile);
  351. if (FAILED(hr))
  352. goto Exit;
  353. hr = srpIPersistFile->Load(bstrMoniker, STGM_READWRITE);
  354. if (FAILED(hr))
  355. goto Exit;
  356. }
  357. }
  358. else
  359. {
  360. PCWSTR pszColon = NULL;
  361. ULONG cchEaten;
  362. if (bstrMoniker == NULL)
  363. {
  364. hr = E_INVALIDARG;
  365. goto Exit;
  366. }
  367. hr = ::CreateBindCtx(0, &srpIBindCtx);
  368. if (FAILED(hr))
  369. goto Exit;
  370. pszColon = wcschr(bstrMoniker, L':');
  371. if ((pszColon == NULL) || ((pszColon - bstrMoniker) == 1))
  372. {
  373. WCHAR rgwchFullPath[MAX_PATH];
  374. DWORD dwRet;
  375. PWSTR pszFilePart;
  376. dwRet = ::GetFullPathNameW(bstrMoniker, NUMBER_OF(rgwchFullPath), rgwchFullPath, &pszFilePart);
  377. if (dwRet == 0)
  378. {
  379. hr = HRESULT_FROM_WIN32(::GetLastError());
  380. goto Exit;
  381. }
  382. hr = ::MkParseDisplayName(srpIBindCtx, bstrMoniker, &cchEaten, &srpIMoniker);
  383. if (FAILED(hr))
  384. goto Exit;
  385. }
  386. else
  387. {
  388. hr = ::CreateURLMoniker(NULL, bstrMoniker, &srpIMoniker);
  389. if (FAILED(hr))
  390. goto Exit;
  391. }
  392. hr = srpIMoniker->BindToObject(srpIBindCtx, NULL, IID_IDispatch, (PVOID *) &srpIDispatch);
  393. if (hr == 0x800C0005)
  394. hr = MK_E_CANTOPENFILE;
  395. if (FAILED(hr))
  396. goto Exit;
  397. }
  398. *ppIDispatch = srpIDispatch.Detach();
  399. act.Deactivate();
  400. hr = NOERROR;
  401. Exit:
  402. return hr;
  403. }
  404. template <typename T> static HRESULT LocalGetProcAddress(HINSTANCE hInstance, PCSTR pszFunction, T &rpfn, T pfnDefault)
  405. {
  406. HRESULT hr = E_FAIL;
  407. if (rpfn == NULL)
  408. {
  409. T pfn = reinterpret_cast<T>(::GetProcAddress(hInstance, pszFunction));
  410. if (pfn == NULL)
  411. {
  412. const DWORD dwLastError = ::GetLastError();
  413. if (dwLastError != ERROR_PROC_NOT_FOUND)
  414. {
  415. hr = HRESULT_FROM_WIN32(dwLastError);
  416. goto Exit;
  417. }
  418. pfn = pfnDefault;
  419. }
  420. #if defined(_X86_)
  421. ::InterlockedCompareExchange((LONG *) &rpfn, (LONG) pfn, 0);
  422. #else
  423. ::InterlockedCompareExchangePointer((PVOID *) &rpfn, pfn, NULL);
  424. #endif
  425. }
  426. hr = NOERROR;
  427. Exit:
  428. return hr;
  429. }
  430. HRESULT CActCtx::EnsureInitialized()
  431. {
  432. HRESULT hr = E_FAIL;
  433. // Check last initialized pointer first for early exit
  434. if (ms_pDeactivateActCtx != NULL)
  435. {
  436. hr = NOERROR;
  437. goto Exit;
  438. }
  439. if (ms_hKERNEL32 == NULL)
  440. {
  441. HINSTANCE hKERNEL32 = ::GetModuleHandleA("KERNEL32.DLL");
  442. if (hKERNEL32 == NULL)
  443. {
  444. hr = HRESULT_FROM_WIN32(::GetLastError());
  445. goto Exit;
  446. }
  447. #if defined(_X86_)
  448. if (::InterlockedExchange(reinterpret_cast<LONG *>(&ms_hKERNEL32), reinterpret_cast<LONG>(hKERNEL32)) != 0)
  449. #else
  450. if (::InterlockedExchangePointer(reinterpret_cast<PVOID *>(&ms_hKERNEL32), hKERNEL32) != NULL)
  451. #endif
  452. ::FreeLibrary(hKERNEL32);
  453. }
  454. if (FAILED(hr = ::LocalGetProcAddress(ms_hKERNEL32, "CreateActCtxW", ms_pCreateActCtxW, &CActCtx::fakeCreateActCtxW)))
  455. goto Exit;
  456. if (FAILED(hr = ::LocalGetProcAddress(ms_hKERNEL32, "AddRefActCtx", ms_pAddRefActCtx, &CActCtx::fakeAddRefActCtx)))
  457. goto Exit;
  458. if (FAILED(hr = ::LocalGetProcAddress(ms_hKERNEL32, "ReleaseActCtx", ms_pReleaseActCtx, &CActCtx::fakeReleaseActCtx)))
  459. goto Exit;
  460. if (FAILED(hr = ::LocalGetProcAddress(ms_hKERNEL32, "ActivateActCtx", ms_pActivateActCtx, &CActCtx::fakeActivateActCtx)))
  461. goto Exit;
  462. if (FAILED(hr = ::LocalGetProcAddress(ms_hKERNEL32, "DeactivateActCtx", ms_pDeactivateActCtx, &CActCtx::fakeDeactivateActCtx)))
  463. goto Exit;
  464. hr = NOERROR;
  465. Exit:
  466. return hr;
  467. }
  468. STDMETHODIMP CActCtx::put_ManifestText(BSTR bstrManifestText)
  469. {
  470. return SetManifestInfo(ACTCTX_MANIFEST_TEXT, bstrManifestText);
  471. }
  472. STDMETHODIMP CActCtx::put_ManifestURL(BSTR bstrManifestURL)
  473. {
  474. return SetManifestInfo(ACTCTX_MANIFEST_URL, bstrManifestURL);
  475. }
  476. STDMETHODIMP CActCtx::put_Manifest(BSTR bstrManifestURL)
  477. {
  478. return SetManifestInfo(ACTCTX_MANIFEST_FILE, bstrManifestURL);
  479. }
  480. STDMETHODIMP CActCtx::get_Manifest(BSTR *pVal)
  481. {
  482. return FetchManifestInfo(ACTCTX_MANIFEST_FILE, pVal);
  483. }
  484. STDMETHODIMP CActCtx::get_ManifestText(BSTR *pVal)
  485. {
  486. return FetchManifestInfo(ACTCTX_MANIFEST_TEXT, pVal);
  487. }
  488. STDMETHODIMP CActCtx::get_ManifestURL(BSTR *pVal)
  489. {
  490. return FetchManifestInfo(ACTCTX_MANIFEST_URL, pVal);
  491. }