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

#include <fusenetincludes.h>
#include <msxml2.h>
#include <manifestemit.h>
#include <manifestimport.h>
#include "macros.h"
CRITICAL_SECTION CAssemblyManifestEmit::g_cs;
// CLSID_XML DOM Document 3.0
class __declspec(uuid("f6d90f11-9c73-11d3-b32e-00c04f990bb4")) private_MSXML_DOMDocument30;
// Publics
// ---------------------------------------------------------------------------
// CreateAssemblyManifestEmit
// ---------------------------------------------------------------------------
STDAPI CreateAssemblyManifestEmit(LPASSEMBLY_MANIFEST_EMIT* ppEmit,
LPCOLESTR pwzManifestFilePath, MANIFEST_TYPE eType)
{
HRESULT hr = S_OK;
MAKE_ERROR_MACROS_STATIC(hr);
CAssemblyManifestEmit* pEmit = NULL;
IF_NULL_EXIT(ppEmit, E_INVALIDARG);
*ppEmit = NULL;
// only support emitting desktop manifest now
IF_FALSE_EXIT(eType == MANIFEST_TYPE_DESKTOP, HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED));
pEmit = new(CAssemblyManifestEmit);
IF_ALLOC_FAILED_EXIT(pEmit);
IF_FAILED_EXIT(pEmit->Init(pwzManifestFilePath));
*ppEmit = (IAssemblyManifestEmit*) pEmit;
pEmit->AddRef();
exit:
SAFERELEASE(pEmit);
return hr;
}
// ---------------------------------------------------------------------------
// ctor
// ---------------------------------------------------------------------------
CAssemblyManifestEmit::CAssemblyManifestEmit()
: _dwSig('TMEM'), _cRef(1), _hr(S_OK), _pXMLDoc(NULL),
_pAssemblyNode(NULL), _pDependencyNode(NULL),
_pApplicationNode(NULL),_bstrManifestFilePath(NULL)
{
}
// ---------------------------------------------------------------------------
// dtor
// ---------------------------------------------------------------------------
CAssemblyManifestEmit::~CAssemblyManifestEmit()
{
SAFERELEASE(_pAssemblyNode);
SAFERELEASE(_pDependencyNode);
SAFERELEASE(_pApplicationNode);
SAFERELEASE(_pXMLDoc);
if (_bstrManifestFilePath)
::SysFreeString(_bstrManifestFilePath);
}
// IUnknown Boilerplate
// ---------------------------------------------------------------------------
// CAssemblyManifestEmit::QI
// ---------------------------------------------------------------------------
STDMETHODIMP
CAssemblyManifestEmit::QueryInterface(REFIID riid, void** ppvObj)
{
if ( IsEqualIID(riid, IID_IUnknown)
|| IsEqualIID(riid, IID_IAssemblyManifestEmit))
{
*ppvObj = static_cast<IAssemblyManifestEmit*> (this);
AddRef();
return S_OK;
}
else
{
*ppvObj = NULL;
return E_NOINTERFACE;
}
}
// ---------------------------------------------------------------------------
// CAssemblyManifestEmit::AddRef
// ---------------------------------------------------------------------------
STDMETHODIMP_(ULONG)
CAssemblyManifestEmit::AddRef()
{
return InterlockedIncrement ((LONG*) &_cRef);
}
// ---------------------------------------------------------------------------
// CAssemblyManifestEmit::Release
// ---------------------------------------------------------------------------
STDMETHODIMP_(ULONG)
CAssemblyManifestEmit::Release()
{
ULONG lRet = InterlockedDecrement ((LONG*) &_cRef);
if (!lRet)
delete this;
return lRet;
}
// Privates
// ---------------------------------------------------------------------------
// Init
// ---------------------------------------------------------------------------
HRESULT CAssemblyManifestEmit::Init(LPCOLESTR pwzManifestFilePath)
{
IF_NULL_EXIT(pwzManifestFilePath, E_INVALIDARG);
// Alloc manifest file path.
_bstrManifestFilePath = ::SysAllocString((LPWSTR) pwzManifestFilePath);
IF_ALLOC_FAILED_EXIT(_bstrManifestFilePath);
// note: DOM Doc is delayed initialized in ImportAssemblyNode() to enable sharing of BSTRs
_hr = S_OK;
exit:
return _hr;
}
// ---------------------------------------------------------------------------
// InitGlobalCritSect
// ---------------------------------------------------------------------------
HRESULT CAssemblyManifestEmit::InitGlobalCritSect()
{
HRESULT hr = S_OK;
__try {
InitializeCriticalSection(&g_cs);
}
__except (GetExceptionCode() == STATUS_NO_MEMORY ?
EXCEPTION_EXECUTE_HANDLER :
EXCEPTION_CONTINUE_SEARCH )
{
hr = E_OUTOFMEMORY;
}
return hr;
}
// ---------------------------------------------------------------------------
// DelGlobalCritSect
// ---------------------------------------------------------------------------
void CAssemblyManifestEmit::DelGlobalCritSect()
{
DeleteCriticalSection(&g_cs);
}
// ---------------------------------------------------------------------------
// ImportManifestInfo
// ---------------------------------------------------------------------------
HRESULT CAssemblyManifestEmit::ImportManifestInfo(LPASSEMBLY_MANIFEST_IMPORT pManImport)
{
DWORD dwType = MANIFEST_TYPE_UNKNOWN;
IXMLDOMDocument2 *pXMLDocSrc = NULL;
IXMLDOMNode *pIDOMNode = NULL;
IXMLDOMNode *pIDOMNodeClone = NULL;
IXMLDOMElement *pIXMLDOMElement = NULL;
VARIANT varVersionWildcard;
VARIANT varTypeDesktop;
VARIANT varRefNode;
IF_NULL_EXIT(pManImport, E_INVALIDARG);
IF_FAILED_EXIT(pManImport->ReportManifestType(&dwType));
IF_FALSE_EXIT(dwType == MANIFEST_TYPE_APPLICATION, HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED));
IF_TRUE_EXIT(_pApplicationNode != NULL, S_FALSE);
if (_pAssemblyNode == NULL)
IF_FAILED_EXIT(ImportAssemblyNode(pManImport));
// application manifest: clone and insert 'assemblyIdentity' node (change 'version', 'type' attribute)
// and 'application' node
pXMLDocSrc = ((CAssemblyManifestImport*)pManImport)->_pXMLDoc;
// BUGBUG: this only pick the 1st instance of 'application'
IF_FAILED_EXIT(pXMLDocSrc->selectSingleNode(
CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::ApplicationNode].bstr, &pIDOMNode));
IF_FALSE_EXIT(_hr == S_OK, E_FAIL);
// clone all children
IF_FAILED_EXIT(pIDOMNode->cloneNode(VARIANT_TRUE, &pIDOMNodeClone));
VariantInit(&varRefNode);
varRefNode.vt = VT_UNKNOWN;
V_UNKNOWN(&varRefNode) = _pDependencyNode;
// insert before 'dependency', if present
IF_FAILED_EXIT(_pAssemblyNode->insertBefore(pIDOMNodeClone, varRefNode, &_pApplicationNode));
SAFERELEASE(pIDOMNodeClone);
SAFERELEASE(pIDOMNode);
// BUGBUG: this only pick the 1st instance of 'assemblyIdentity'
IF_FAILED_EXIT(pXMLDocSrc->selectSingleNode(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::AssemblyId].bstr, &pIDOMNode));
IF_FALSE_EXIT(_hr == S_OK, E_FAIL);
// clone all children
IF_FAILED_EXIT(pIDOMNode->cloneNode(VARIANT_TRUE, &pIDOMNodeClone));
SAFERELEASE(pIDOMNode);
VariantInit(&varRefNode);
varRefNode.vt = VT_UNKNOWN;
V_UNKNOWN(&varRefNode) = _pApplicationNode;
// insert before 'application'
IF_FAILED_EXIT(_pAssemblyNode->insertBefore(pIDOMNodeClone, varRefNode, &pIDOMNode));
// change 'version' = '*', 'type' = 'desktop'
IF_FAILED_EXIT(pIDOMNode->QueryInterface(IID_IXMLDOMElement, (void**) &pIXMLDOMElement));
VariantInit(&varVersionWildcard);
varVersionWildcard.vt = VT_BSTR;
V_BSTR(&varVersionWildcard) = CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::VersionWildcard].bstr;
IF_FAILED_EXIT(pIXMLDOMElement->setAttribute(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::Version].bstr, varVersionWildcard));
VariantInit(&varTypeDesktop);
varTypeDesktop.vt = VT_BSTR;
V_BSTR(&varTypeDesktop) = CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::Desktop].bstr;
_hr = pIXMLDOMElement->setAttribute(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::Type].bstr, varTypeDesktop);
exit:
SAFERELEASE(pIXMLDOMElement);
SAFERELEASE(pIDOMNodeClone);
SAFERELEASE(pIDOMNode);
if (FAILED(_hr))
SAFERELEASE(_pApplicationNode);
return _hr;
}
// ---------------------------------------------------------------------------
// SetDependencySubscription
// ---------------------------------------------------------------------------
HRESULT CAssemblyManifestEmit::SetDependencySubscription(LPASSEMBLY_MANIFEST_IMPORT pManImport, LPWSTR pwzManifestUrl)
{
DWORD dwType = MANIFEST_TYPE_UNKNOWN;
IXMLDOMDocument2 *pXMLDocSrc = NULL;
IXMLDOMNode *pIDOMNode = NULL;
IXMLDOMNode *pIDOMNodeClone = NULL;
IXMLDOMElement *pIDOMElement = NULL;
IXMLDOMNode *pDependentAssemblyNode = NULL;
VARIANT varVersionWildcard;
VARIANT varCodebase;
BSTR bstrManifestUrl = NULL;
VariantInit(&varCodebase);
IF_FALSE_EXIT(pManImport && pwzManifestUrl, E_INVALIDARG);
IF_FAILED_EXIT(pManImport->ReportManifestType(&dwType));
IF_FALSE_EXIT(dwType == MANIFEST_TYPE_SUBSCRIPTION || dwType == MANIFEST_TYPE_APPLICATION, HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED));
IF_TRUE_EXIT(_pDependencyNode != NULL, S_FALSE);
if (_pAssemblyNode == NULL)
IF_FAILED_EXIT(ImportAssemblyNode(pManImport));
// setup manifest subscription data: create dependency/dependentAssembly
// then add a clone of the asm Id node from pManImport and an 'install' node with the given URL
IF_FAILED_EXIT(_pXMLDoc->createElement(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::Dependency].bstr, &pIDOMElement));
// insert at the end
IF_FAILED_EXIT(_pAssemblyNode->appendChild(pIDOMElement, &_pDependencyNode));
SAFERELEASE(pIDOMElement);
IF_FAILED_EXIT(_pXMLDoc->createElement(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::DependentAssembly].bstr, &pIDOMElement));
IF_FAILED_EXIT(_pDependencyNode->appendChild(pIDOMElement, &pDependentAssemblyNode));
SAFERELEASE(pIDOMElement);
pXMLDocSrc = ((CAssemblyManifestImport*)pManImport)->_pXMLDoc;
// BUGBUG: this only pick the 1st instance of 'assemblyIdentity'
IF_FAILED_EXIT(pXMLDocSrc->selectSingleNode(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::AssemblyId].bstr, &pIDOMNode));
IF_FALSE_EXIT(_hr == S_OK, E_FAIL);
// clone all children
IF_FAILED_EXIT(pIDOMNode->cloneNode(VARIANT_TRUE, &pIDOMNodeClone));
// change 'version' = '*'
IF_FAILED_EXIT(pIDOMNodeClone->QueryInterface(IID_IXMLDOMElement, (void**) &pIDOMElement));
VariantInit(&varVersionWildcard);
varVersionWildcard.vt = VT_BSTR;
V_BSTR(&varVersionWildcard) = CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::VersionWildcard].bstr;
IF_FAILED_EXIT(pIDOMElement->setAttribute(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::Version].bstr, varVersionWildcard));
SAFERELEASE(pIDOMElement);
IF_FAILED_EXIT(pDependentAssemblyNode->appendChild(pIDOMNodeClone, NULL));
IF_FAILED_EXIT(_pXMLDoc->createElement(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::Install].bstr, &pIDOMElement));
bstrManifestUrl = ::SysAllocString(pwzManifestUrl);
IF_ALLOC_FAILED_EXIT(bstrManifestUrl);
// bstrManifestUrl to be freed by VariantClear()
varCodebase.vt = VT_BSTR;
V_BSTR(&varCodebase) = bstrManifestUrl;
IF_FAILED_EXIT(pIDOMElement->setAttribute(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::Codebase].bstr, varCodebase));
IF_FAILED_EXIT(pDependentAssemblyNode->appendChild(pIDOMElement, NULL));
exit:
VariantClear(&varCodebase);
SAFERELEASE(pDependentAssemblyNode);
SAFERELEASE(pIDOMElement);
SAFERELEASE(pIDOMNode);
SAFERELEASE(pIDOMNodeClone);
if (FAILED(_hr))
SAFERELEASE(_pDependencyNode);
return _hr;
}
// ---------------------------------------------------------------------------
// ImportAssemblyNode
// ---------------------------------------------------------------------------
HRESULT CAssemblyManifestEmit::ImportAssemblyNode(LPASSEMBLY_MANIFEST_IMPORT pManImport)
{
VARIANT varNameSpaces;
VARIANT varXPath;
IXMLDOMDocument2 *pXMLDocSrc = NULL;
IXMLDOMNode *pIDOMNode = NULL;
IXMLDOMNode *pIDOMNodeClone = NULL;
// note: _pXMLDoc, _pAssemblyNode must be NULL
// and this must be called _only and exactly once_
// Create the DOM Doc interface
IF_FAILED_EXIT(CoCreateInstance(__uuidof(private_MSXML_DOMDocument30),
NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument2, (void**)&_pXMLDoc));
// Load synchronously
IF_FAILED_EXIT(_pXMLDoc->put_async(VARIANT_FALSE));
// Setup namespace filter
VariantInit(&varNameSpaces);
varNameSpaces.vt = VT_BSTR;
V_BSTR(&varNameSpaces) = CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::NameSpace].bstr;
IF_FAILED_EXIT(_pXMLDoc->setProperty(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::SelNameSpaces].bstr, varNameSpaces));
// Setup query type
VariantInit(&varXPath);
varXPath.vt = VT_BSTR;
V_BSTR(&varXPath) = CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::XPath].bstr;
IF_FAILED_EXIT(_pXMLDoc->setProperty(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::SelLanguage].bstr, varXPath));
// initialize manifest file: clone and insert 'assembly' node
// by doing this, manifestVersion and other attributes are maintained
pXMLDocSrc = ((CAssemblyManifestImport*)pManImport)->_pXMLDoc;
// BUGBUG: this only pick the 1st instance of 'assembly'
IF_FAILED_EXIT(pXMLDocSrc->selectSingleNode(CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::AssemblyNode].bstr, &pIDOMNode));
IF_FALSE_EXIT(_hr == S_OK, E_FAIL);
// clone no child
IF_FAILED_EXIT(pIDOMNode->cloneNode(VARIANT_FALSE, &pIDOMNodeClone));
_hr = _pXMLDoc->appendChild(pIDOMNodeClone, &_pAssemblyNode);
exit:
if (FAILED(_hr))
SAFERELEASE(_pXMLDoc);
SAFERELEASE(pIDOMNodeClone);
SAFERELEASE(pIDOMNode);
return _hr;
}
// ---------------------------------------------------------------------------
// Commit
// ---------------------------------------------------------------------------
HRESULT CAssemblyManifestEmit::Commit()
{
// considered safe to be called multiple times
VARIANT varFileName;
if (_pXMLDoc)
{
// ignore any error occured before, do save anyway
// it's caller's responsibility to track a incomplete xml manifest file/XMLDoc state
VariantInit(&varFileName);
varFileName.vt = VT_BSTR;
V_BSTR(&varFileName) = _bstrManifestFilePath;
_hr = _pXMLDoc->save(varFileName);
}
else
{
// not initialized
_hr = HRESULT_FROM_WIN32(ERROR_CAN_NOT_COMPLETE);
}
return _hr;
}