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.

436 lines
15 KiB

  1. #include <fusenetincludes.h>
  2. #include <msxml2.h>
  3. #include <manifestemit.h>
  4. #include <manifestimport.h>
  5. #include "macros.h"
  6. CRITICAL_SECTION CAssemblyManifestEmit::g_cs;
  7. // CLSID_XML DOM Document 3.0
  8. class __declspec(uuid("f6d90f11-9c73-11d3-b32e-00c04f990bb4")) private_MSXML_DOMDocument30;
  9. // Publics
  10. // ---------------------------------------------------------------------------
  11. // CreateAssemblyManifestEmit
  12. // ---------------------------------------------------------------------------
  13. STDAPI CreateAssemblyManifestEmit(LPASSEMBLY_MANIFEST_EMIT* ppEmit,
  14. LPCOLESTR pwzManifestFilePath, MANIFEST_TYPE eType)
  15. {
  16. HRESULT hr = S_OK;
  17. MAKE_ERROR_MACROS_STATIC(hr);
  18. CAssemblyManifestEmit* pEmit = NULL;
  19. IF_NULL_EXIT(ppEmit, E_INVALIDARG);
  20. *ppEmit = NULL;
  21. // only support emitting desktop manifest now
  22. IF_FALSE_EXIT(eType == MANIFEST_TYPE_DESKTOP, HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED));
  23. pEmit = new(CAssemblyManifestEmit);
  24. IF_ALLOC_FAILED_EXIT(pEmit);
  25. IF_FAILED_EXIT(pEmit->Init(pwzManifestFilePath));
  26. *ppEmit = (IAssemblyManifestEmit*) pEmit;
  27. pEmit->AddRef();
  28. exit:
  29. SAFERELEASE(pEmit);
  30. return hr;
  31. }
  32. // ---------------------------------------------------------------------------
  33. // ctor
  34. // ---------------------------------------------------------------------------
  35. CAssemblyManifestEmit::CAssemblyManifestEmit()
  36. : _dwSig('TMEM'), _cRef(1), _hr(S_OK), _pXMLDoc(NULL),
  37. _pAssemblyNode(NULL), _pDependencyNode(NULL),
  38. _pApplicationNode(NULL),_bstrManifestFilePath(NULL)
  39. {
  40. }
  41. // ---------------------------------------------------------------------------
  42. // dtor
  43. // ---------------------------------------------------------------------------
  44. CAssemblyManifestEmit::~CAssemblyManifestEmit()
  45. {
  46. SAFERELEASE(_pAssemblyNode);
  47. SAFERELEASE(_pDependencyNode);
  48. SAFERELEASE(_pApplicationNode);
  49. SAFERELEASE(_pXMLDoc);
  50. if (_bstrManifestFilePath)
  51. ::SysFreeString(_bstrManifestFilePath);
  52. }
  53. // IUnknown Boilerplate
  54. // ---------------------------------------------------------------------------
  55. // CAssemblyManifestEmit::QI
  56. // ---------------------------------------------------------------------------
  57. STDMETHODIMP
  58. CAssemblyManifestEmit::QueryInterface(REFIID riid, void** ppvObj)
  59. {
  60. if ( IsEqualIID(riid, IID_IUnknown)
  61. || IsEqualIID(riid, IID_IAssemblyManifestEmit))
  62. {
  63. *ppvObj = static_cast<IAssemblyManifestEmit*> (this);
  64. AddRef();
  65. return S_OK;
  66. }
  67. else
  68. {
  69. *ppvObj = NULL;
  70. return E_NOINTERFACE;
  71. }
  72. }
  73. // ---------------------------------------------------------------------------
  74. // CAssemblyManifestEmit::AddRef
  75. // ---------------------------------------------------------------------------
  76. STDMETHODIMP_(ULONG)
  77. CAssemblyManifestEmit::AddRef()
  78. {
  79. return InterlockedIncrement ((LONG*) &_cRef);
  80. }
  81. // ---------------------------------------------------------------------------
  82. // CAssemblyManifestEmit::Release
  83. // ---------------------------------------------------------------------------
  84. STDMETHODIMP_(ULONG)
  85. CAssemblyManifestEmit::Release()
  86. {
  87. ULONG lRet = InterlockedDecrement ((LONG*) &_cRef);
  88. if (!lRet)
  89. delete this;
  90. return lRet;
  91. }
  92. // Privates
  93. // ---------------------------------------------------------------------------
  94. // Init
  95. // ---------------------------------------------------------------------------
  96. HRESULT CAssemblyManifestEmit::Init(LPCOLESTR pwzManifestFilePath)
  97. {
  98. IF_NULL_EXIT(pwzManifestFilePath, E_INVALIDARG);
  99. // Alloc manifest file path.
  100. _bstrManifestFilePath = ::SysAllocString((LPWSTR) pwzManifestFilePath);
  101. IF_ALLOC_FAILED_EXIT(_bstrManifestFilePath);
  102. // note: DOM Doc is delayed initialized in ImportAssemblyNode() to enable sharing of BSTRs
  103. _hr = S_OK;
  104. exit:
  105. return _hr;
  106. }
  107. // ---------------------------------------------------------------------------
  108. // InitGlobalCritSect
  109. // ---------------------------------------------------------------------------
  110. HRESULT CAssemblyManifestEmit::InitGlobalCritSect()
  111. {
  112. HRESULT hr = S_OK;
  113. __try {
  114. InitializeCriticalSection(&g_cs);
  115. }
  116. __except (GetExceptionCode() == STATUS_NO_MEMORY ?
  117. EXCEPTION_EXECUTE_HANDLER :
  118. EXCEPTION_CONTINUE_SEARCH )
  119. {
  120. hr = E_OUTOFMEMORY;
  121. }
  122. return hr;
  123. }
  124. // ---------------------------------------------------------------------------
  125. // DelGlobalCritSect
  126. // ---------------------------------------------------------------------------
  127. void CAssemblyManifestEmit::DelGlobalCritSect()
  128. {
  129. DeleteCriticalSection(&g_cs);
  130. }
  131. // ---------------------------------------------------------------------------
  132. // ImportManifestInfo
  133. // ---------------------------------------------------------------------------
  134. HRESULT CAssemblyManifestEmit::ImportManifestInfo(LPASSEMBLY_MANIFEST_IMPORT pManImport)
  135. {
  136. DWORD dwType = MANIFEST_TYPE_UNKNOWN;
  137. IXMLDOMDocument2 *pXMLDocSrc = NULL;
  138. IXMLDOMNode *pIDOMNode = NULL;
  139. IXMLDOMNode *pIDOMNodeClone = NULL;
  140. IXMLDOMElement *pIXMLDOMElement = NULL;
  141. VARIANT varVersionWildcard;
  142. VARIANT varTypeDesktop;
  143. VARIANT varRefNode;
  144. IF_NULL_EXIT(pManImport, E_INVALIDARG);
  145. IF_FAILED_EXIT(pManImport->ReportManifestType(&dwType));
  146. IF_FALSE_EXIT(dwType == MANIFEST_TYPE_APPLICATION, HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED));
  147. IF_TRUE_EXIT(_pApplicationNode != NULL, S_FALSE);
  148. if (_pAssemblyNode == NULL)
  149. IF_FAILED_EXIT(ImportAssemblyNode(pManImport));
  150. // application manifest: clone and insert 'assemblyIdentity' node (change 'version', 'type' attribute)
  151. // and 'application' node
  152. pXMLDocSrc = ((CAssemblyManifestImport*)pManImport)->_pXMLDoc;
  153. // BUGBUG: this only pick the 1st instance of 'application'
  154. IF_FAILED_EXIT(pXMLDocSrc->selectSingleNode(
  155. CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::ApplicationNode].bstr, &pIDOMNode));
  156. IF_FALSE_EXIT(_hr == S_OK, E_FAIL);
  157. // clone all children
  158. IF_FAILED_EXIT(pIDOMNode->cloneNode(VARIANT_TRUE, &pIDOMNodeClone));
  159. VariantInit(&varRefNode);
  160. varRefNode.vt = VT_UNKNOWN;
  161. V_UNKNOWN(&varRefNode) = _pDependencyNode;
  162. // insert before 'dependency', if present
  163. IF_FAILED_EXIT(_pAssemblyNode->insertBefore(pIDOMNodeClone, varRefNode, &_pApplicationNode));
  164. SAFERELEASE(pIDOMNodeClone);
  165. SAFERELEASE(pIDOMNode);
  166. // BUGBUG: this only pick the 1st instance of 'assemblyIdentity'
  167. IF_FAILED_EXIT(pXMLDocSrc->selectSingleNode(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::AssemblyId].bstr, &pIDOMNode));
  168. IF_FALSE_EXIT(_hr == S_OK, E_FAIL);
  169. // clone all children
  170. IF_FAILED_EXIT(pIDOMNode->cloneNode(VARIANT_TRUE, &pIDOMNodeClone));
  171. SAFERELEASE(pIDOMNode);
  172. VariantInit(&varRefNode);
  173. varRefNode.vt = VT_UNKNOWN;
  174. V_UNKNOWN(&varRefNode) = _pApplicationNode;
  175. // insert before 'application'
  176. IF_FAILED_EXIT(_pAssemblyNode->insertBefore(pIDOMNodeClone, varRefNode, &pIDOMNode));
  177. // change 'version' = '*', 'type' = 'desktop'
  178. IF_FAILED_EXIT(pIDOMNode->QueryInterface(IID_IXMLDOMElement, (void**) &pIXMLDOMElement));
  179. VariantInit(&varVersionWildcard);
  180. varVersionWildcard.vt = VT_BSTR;
  181. V_BSTR(&varVersionWildcard) = CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::VersionWildcard].bstr;
  182. IF_FAILED_EXIT(pIXMLDOMElement->setAttribute(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::Version].bstr, varVersionWildcard));
  183. VariantInit(&varTypeDesktop);
  184. varTypeDesktop.vt = VT_BSTR;
  185. V_BSTR(&varTypeDesktop) = CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::Desktop].bstr;
  186. _hr = pIXMLDOMElement->setAttribute(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::Type].bstr, varTypeDesktop);
  187. exit:
  188. SAFERELEASE(pIXMLDOMElement);
  189. SAFERELEASE(pIDOMNodeClone);
  190. SAFERELEASE(pIDOMNode);
  191. if (FAILED(_hr))
  192. SAFERELEASE(_pApplicationNode);
  193. return _hr;
  194. }
  195. // ---------------------------------------------------------------------------
  196. // SetDependencySubscription
  197. // ---------------------------------------------------------------------------
  198. HRESULT CAssemblyManifestEmit::SetDependencySubscription(LPASSEMBLY_MANIFEST_IMPORT pManImport, LPWSTR pwzManifestUrl)
  199. {
  200. DWORD dwType = MANIFEST_TYPE_UNKNOWN;
  201. IXMLDOMDocument2 *pXMLDocSrc = NULL;
  202. IXMLDOMNode *pIDOMNode = NULL;
  203. IXMLDOMNode *pIDOMNodeClone = NULL;
  204. IXMLDOMElement *pIDOMElement = NULL;
  205. IXMLDOMNode *pDependentAssemblyNode = NULL;
  206. VARIANT varVersionWildcard;
  207. VARIANT varCodebase;
  208. BSTR bstrManifestUrl = NULL;
  209. VariantInit(&varCodebase);
  210. IF_FALSE_EXIT(pManImport && pwzManifestUrl, E_INVALIDARG);
  211. IF_FAILED_EXIT(pManImport->ReportManifestType(&dwType));
  212. IF_FALSE_EXIT(dwType == MANIFEST_TYPE_SUBSCRIPTION || dwType == MANIFEST_TYPE_APPLICATION, HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED));
  213. IF_TRUE_EXIT(_pDependencyNode != NULL, S_FALSE);
  214. if (_pAssemblyNode == NULL)
  215. IF_FAILED_EXIT(ImportAssemblyNode(pManImport));
  216. // setup manifest subscription data: create dependency/dependentAssembly
  217. // then add a clone of the asm Id node from pManImport and an 'install' node with the given URL
  218. IF_FAILED_EXIT(_pXMLDoc->createElement(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::Dependency].bstr, &pIDOMElement));
  219. // insert at the end
  220. IF_FAILED_EXIT(_pAssemblyNode->appendChild(pIDOMElement, &_pDependencyNode));
  221. SAFERELEASE(pIDOMElement);
  222. IF_FAILED_EXIT(_pXMLDoc->createElement(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::DependentAssembly].bstr, &pIDOMElement));
  223. IF_FAILED_EXIT(_pDependencyNode->appendChild(pIDOMElement, &pDependentAssemblyNode));
  224. SAFERELEASE(pIDOMElement);
  225. pXMLDocSrc = ((CAssemblyManifestImport*)pManImport)->_pXMLDoc;
  226. // BUGBUG: this only pick the 1st instance of 'assemblyIdentity'
  227. IF_FAILED_EXIT(pXMLDocSrc->selectSingleNode(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::AssemblyId].bstr, &pIDOMNode));
  228. IF_FALSE_EXIT(_hr == S_OK, E_FAIL);
  229. // clone all children
  230. IF_FAILED_EXIT(pIDOMNode->cloneNode(VARIANT_TRUE, &pIDOMNodeClone));
  231. // change 'version' = '*'
  232. IF_FAILED_EXIT(pIDOMNodeClone->QueryInterface(IID_IXMLDOMElement, (void**) &pIDOMElement));
  233. VariantInit(&varVersionWildcard);
  234. varVersionWildcard.vt = VT_BSTR;
  235. V_BSTR(&varVersionWildcard) = CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::VersionWildcard].bstr;
  236. IF_FAILED_EXIT(pIDOMElement->setAttribute(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::Version].bstr, varVersionWildcard));
  237. SAFERELEASE(pIDOMElement);
  238. IF_FAILED_EXIT(pDependentAssemblyNode->appendChild(pIDOMNodeClone, NULL));
  239. IF_FAILED_EXIT(_pXMLDoc->createElement(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::Install].bstr, &pIDOMElement));
  240. bstrManifestUrl = ::SysAllocString(pwzManifestUrl);
  241. IF_ALLOC_FAILED_EXIT(bstrManifestUrl);
  242. // bstrManifestUrl to be freed by VariantClear()
  243. varCodebase.vt = VT_BSTR;
  244. V_BSTR(&varCodebase) = bstrManifestUrl;
  245. IF_FAILED_EXIT(pIDOMElement->setAttribute(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::Codebase].bstr, varCodebase));
  246. IF_FAILED_EXIT(pDependentAssemblyNode->appendChild(pIDOMElement, NULL));
  247. exit:
  248. VariantClear(&varCodebase);
  249. SAFERELEASE(pDependentAssemblyNode);
  250. SAFERELEASE(pIDOMElement);
  251. SAFERELEASE(pIDOMNode);
  252. SAFERELEASE(pIDOMNodeClone);
  253. if (FAILED(_hr))
  254. SAFERELEASE(_pDependencyNode);
  255. return _hr;
  256. }
  257. // ---------------------------------------------------------------------------
  258. // ImportAssemblyNode
  259. // ---------------------------------------------------------------------------
  260. HRESULT CAssemblyManifestEmit::ImportAssemblyNode(LPASSEMBLY_MANIFEST_IMPORT pManImport)
  261. {
  262. VARIANT varNameSpaces;
  263. VARIANT varXPath;
  264. IXMLDOMDocument2 *pXMLDocSrc = NULL;
  265. IXMLDOMNode *pIDOMNode = NULL;
  266. IXMLDOMNode *pIDOMNodeClone = NULL;
  267. // note: _pXMLDoc, _pAssemblyNode must be NULL
  268. // and this must be called _only and exactly once_
  269. // Create the DOM Doc interface
  270. IF_FAILED_EXIT(CoCreateInstance(__uuidof(private_MSXML_DOMDocument30),
  271. NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument2, (void**)&_pXMLDoc));
  272. // Load synchronously
  273. IF_FAILED_EXIT(_pXMLDoc->put_async(VARIANT_FALSE));
  274. // Setup namespace filter
  275. VariantInit(&varNameSpaces);
  276. varNameSpaces.vt = VT_BSTR;
  277. V_BSTR(&varNameSpaces) = CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::NameSpace].bstr;
  278. IF_FAILED_EXIT(_pXMLDoc->setProperty(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::SelNameSpaces].bstr, varNameSpaces));
  279. // Setup query type
  280. VariantInit(&varXPath);
  281. varXPath.vt = VT_BSTR;
  282. V_BSTR(&varXPath) = CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::XPath].bstr;
  283. IF_FAILED_EXIT(_pXMLDoc->setProperty(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::SelLanguage].bstr, varXPath));
  284. // initialize manifest file: clone and insert 'assembly' node
  285. // by doing this, manifestVersion and other attributes are maintained
  286. pXMLDocSrc = ((CAssemblyManifestImport*)pManImport)->_pXMLDoc;
  287. // BUGBUG: this only pick the 1st instance of 'assembly'
  288. IF_FAILED_EXIT(pXMLDocSrc->selectSingleNode(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::AssemblyNode].bstr, &pIDOMNode));
  289. IF_FALSE_EXIT(_hr == S_OK, E_FAIL);
  290. // clone no child
  291. IF_FAILED_EXIT(pIDOMNode->cloneNode(VARIANT_FALSE, &pIDOMNodeClone));
  292. _hr = _pXMLDoc->appendChild(pIDOMNodeClone, &_pAssemblyNode);
  293. exit:
  294. if (FAILED(_hr))
  295. SAFERELEASE(_pXMLDoc);
  296. SAFERELEASE(pIDOMNodeClone);
  297. SAFERELEASE(pIDOMNode);
  298. return _hr;
  299. }
  300. // ---------------------------------------------------------------------------
  301. // Commit
  302. // ---------------------------------------------------------------------------
  303. HRESULT CAssemblyManifestEmit::Commit()
  304. {
  305. // considered safe to be called multiple times
  306. VARIANT varFileName;
  307. if (_pXMLDoc)
  308. {
  309. // ignore any error occured before, do save anyway
  310. // it's caller's responsibility to track a incomplete xml manifest file/XMLDoc state
  311. VariantInit(&varFileName);
  312. varFileName.vt = VT_BSTR;
  313. V_BSTR(&varFileName) = _bstrManifestFilePath;
  314. _hr = _pXMLDoc->save(varFileName);
  315. }
  316. else
  317. {
  318. // not initialized
  319. _hr = HRESULT_FROM_WIN32(ERROR_CAN_NOT_COMPLETE);
  320. }
  321. return _hr;
  322. }