#include #include #include #include #include #define WZ_NAMESPACES L"xmlns:asm_namespace_v1='urn:schemas-microsoft-com:asm.v1'" #define WZ_SELECTION_NAMESPACES L"SelectionNamespaces" #define WZ_SELECTION_LANGUAGE L"SelectionLanguage" #define WZ_XPATH L"XPath" #define WZ_FILE_NODE L"/assembly/file" #define WZ_FILE_QUERYSTRING_PREFIX L"/assembly/file[@name = \"" #define WZ_FILE_QUERYSTRING_SUFFIX L"\"]" #define WZ_ASSEMBLY_ID L"/assembly/assemblyIdentity" #define WZ_DEPENDENT_ASSEMBLY_NODE L"/assembly/dependency/dependentAssembly/assemblyIdentity" #define WZ_DEPENDENT_ASSEMBLY_CODEBASE L"../install[@codebase]" #define WZ_CODEBASE L"codebase" #define WZ_SHELLSTATE L"/assembly/application/shellState" #define WZ_FILE_NAME L"name" #define WZ_FILE_HASH L"hash" #define WZ_FRIENDLYNAME L"friendlyName" #define WZ_ENTRYPOINT L"entryPoint" #define WZ_ENTRYIMAGETYPE L"entryImageType" #define WZ_ICONFILE L"iconFile" #define WZ_ICONINDEX L"iconIndex" #define WZ_SHOWCOMMAND L"showCommand" #define WZ_HOTKEY L"hotKey" #define WZ_PATCH L"/assembly/Patch/SourceAssembly" #define WZ_PATCHINFO L"/PatchInfo/" #define WZ_SOURCE L"source" #define WZ_TARGET L"target" #define WZ_PATCHFILE L"patchfile" #define WZ_ASSEMBLY_ID_TAG L"assemblyIdentity" #define WZ_COMPRESSED L"compressed" #define WZ_SUBSCRIPTION L"/assembly/dependency/dependentAssembly/subscription" #define WZ_POLLING_INTERVAL L"pollingInterval" #define WZ_FILE L"file" #define WZ_CAB L"cab" #undef NUMBER_OF #define NUMBER_OF(x) ( (sizeof(x) / sizeof(*x) ) ) #undef ENTRY #define ENTRY(x) { x, NULL, NUMBER_OF(x) - 1 }, #undef IFALLOCFAILED_EXIT #define IFALLOCFAILED_EXIT(_x) \ do {if ((_x) == NULL) {_hr = E_OUTOFMEMORY; cs.Unlock(); goto exit; } } while (0) CAssemblyManifestImport::StringTableEntry CAssemblyManifestImport::g_StringTable[] = { ENTRY(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME) ENTRY(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_VERSION) ENTRY(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_LANGUAGE) ENTRY(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_PUBLIC_KEY) ENTRY(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_PUBLIC_KEY_TOKEN) ENTRY(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_PROCESSOR_ARCHITECTURE) ENTRY(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_TYPE) ENTRY(WZ_SELECTION_NAMESPACES) ENTRY(WZ_NAMESPACES) ENTRY(WZ_SELECTION_LANGUAGE) ENTRY(WZ_XPATH) ENTRY(WZ_FILE_NODE) ENTRY(WZ_FILE_NAME) ENTRY(WZ_FILE_HASH) ENTRY(WZ_ASSEMBLY_ID) ENTRY(WZ_DEPENDENT_ASSEMBLY_NODE) ENTRY(WZ_DEPENDENT_ASSEMBLY_CODEBASE) ENTRY(WZ_CODEBASE) ENTRY(WZ_SHELLSTATE) ENTRY(WZ_FRIENDLYNAME) ENTRY(WZ_ENTRYPOINT) ENTRY(WZ_ENTRYIMAGETYPE) ENTRY(WZ_ICONFILE) ENTRY(WZ_ICONINDEX) ENTRY(WZ_SHOWCOMMAND) ENTRY(WZ_HOTKEY) ENTRY(WZ_PATCH) ENTRY(WZ_PATCHINFO) ENTRY(WZ_SOURCE) ENTRY(WZ_TARGET) ENTRY(WZ_PATCHFILE) ENTRY(WZ_ASSEMBLY_ID_TAG) ENTRY(WZ_COMPRESSED) ENTRY(WZ_SUBSCRIPTION) ENTRY(WZ_POLLING_INTERVAL) ENTRY(WZ_FILE) ENTRY(WZ_CAB) }; LONG CAssemblyManifestImport::g_nRefCount = 0; CRITICAL_SECTION CAssemblyManifestImport::g_cs; // CLSID_XML DOM Document 3.0 class __declspec(uuid("f6d90f11-9c73-11d3-b32e-00c04f990bb4")) private_MSXML_DOMDocument30; // Publics // --------------------------------------------------------------------------- // CreateAssemblyManifestImport // --------------------------------------------------------------------------- STDAPI CreateAssemblyManifestImport(IAssemblyManifestImport** ppImport, LPCOLESTR pwzManifestFilePath) { HRESULT hr = S_OK; CAssemblyManifestImport *pImport = new(CAssemblyManifestImport); if (!pImport) { hr = E_OUTOFMEMORY; goto exit; } if (FAILED(hr = pImport->Init(pwzManifestFilePath))) { SAFERELEASE(pImport); goto exit; } exit: *ppImport = (IAssemblyManifestImport*) pImport; return hr; } // --------------------------------------------------------------------------- // ctor // --------------------------------------------------------------------------- CAssemblyManifestImport::CAssemblyManifestImport() : _dwSig('TRPM'), _cRef(1), _hr(S_OK), _pAssemblyId(NULL), _pXMLDoc(NULL), _pXMLFileNodeList(NULL), _pXMLAssemblyNodeList(NULL), _nFileNodes(0), _nAssemblyNodes(0), _bstrManifestFilePath(NULL) , _pSourceAssemblyPatchNodeList(NULL), _nSourceAssemblyPatchNodes(0), _pPatchAssemblyNode(NULL) { } // --------------------------------------------------------------------------- // dtor // --------------------------------------------------------------------------- CAssemblyManifestImport::~CAssemblyManifestImport() { SAFERELEASE(_pAssemblyId); SAFERELEASE(_pXMLFileNodeList); SAFERELEASE(_pXMLAssemblyNodeList); SAFERELEASE(_pXMLDoc); SAFERELEASE(_pSourceAssemblyPatchNodeList); SAFERELEASE(_pPatchAssemblyNode); if (_bstrManifestFilePath) ::SysFreeString(_bstrManifestFilePath); if (!InterlockedDecrement(&g_nRefCount)) { for (eStringTableId i = Name; i <= MAX_STRINGS; i++) ::SysFreeString(g_StringTable[i].bstr); } } // --------------------------------------------------------------------------- // GetPollingInterval // --------------------------------------------------------------------------- HRESULT CAssemblyManifestImport::GetPollingInterval(DWORD *pollingInterval) { LPWSTR pwzBuf = NULL; DWORD ccBuf; IXMLDOMNode *pIDOMNode = NULL; IXMLDOMNodeList *pXMLMatchingFileNodeList = NULL; LONG nMatchingFileNodes = 0; if ((_hr = _pXMLDoc->selectNodes(g_StringTable[Subscription].bstr, &pXMLMatchingFileNodeList)) != S_OK) goto exit; _hr = pXMLMatchingFileNodeList->get_length(&nMatchingFileNodes); if (nMatchingFileNodes > 1) { _hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT); goto exit; } _hr = pXMLMatchingFileNodeList->reset(); if ((_hr = pXMLMatchingFileNodeList->get_item(0, &pIDOMNode)) != S_OK) { _hr = E_FAIL; goto exit; } // BugBug, should we put in a default settign incase there is no polling info? if (!(_hr = ParseAttribute(pIDOMNode, g_StringTable[PollingInterval].bstr, &pwzBuf, &ccBuf)) == S_OK) { _hr = E_FAIL; goto exit; } (*pollingInterval) = wcstol(pwzBuf, NULL, 10); exit: SAFEDELETEARRAY(pwzBuf); SAFERELEASE(pIDOMNode); SAFERELEASE(pXMLMatchingFileNodeList); return _hr; } // --------------------------------------------------------------------------- // GetNextFile // --------------------------------------------------------------------------- HRESULT CAssemblyManifestImport::GetNextFile(DWORD nIndex, IAssemblyFileInfo **ppAssemblyFile) { LPWSTR pwzBuf = NULL; DWORD ccBuf = 0; CString sFileName; CString sFileHash; IXMLDOMNode *pIDOMNode = NULL; LPASSEMBLY_FILE_INFO pAssemblyFile = NULL; // Initialize the file node list if necessary. if (!_pXMLFileNodeList) { if ((_hr = _pXMLDoc->selectNodes(g_StringTable[FileNode].bstr, &_pXMLFileNodeList)) != S_OK) goto exit; _hr = _pXMLFileNodeList->get_length(&_nFileNodes); _hr = _pXMLFileNodeList->reset(); } if (nIndex >= (DWORD) _nFileNodes) { _hr = S_FALSE; goto exit; } if ((_hr = _pXMLFileNodeList->get_item(nIndex, &pIDOMNode)) != S_OK) goto exit; CreateAssemblyFileEx (&pAssemblyFile, pIDOMNode); *ppAssemblyFile = pAssemblyFile; (*ppAssemblyFile)->AddRef(); exit: SAFERELEASE(pAssemblyFile); SAFERELEASE(pIDOMNode); return _hr; } // --------------------------------------------------------------------------- // QueryFile // return: // S_OK // S_FALSE -not exist or not match or missing attribute // E_* // --------------------------------------------------------------------------- HRESULT CAssemblyManifestImport::QueryFile(LPCOLESTR pcwzFileName, IAssemblyFileInfo **ppAssemblyFile) { CString sQueryString; BSTR bstrtQueryString = NULL; IXMLDOMNode *pIDOMNode = NULL; IXMLDOMNodeList *pXMLMatchingFileNodeList = NULL; LPASSEMBLY_FILE_INFO pAssemblyFile = NULL; LONG nMatchingFileNodes = 0; if (pcwzFileName == NULL || ppAssemblyFile == NULL) { _hr = E_INVALIDARG; goto exit; } *ppAssemblyFile = NULL; // XPath query string: "file[@name = "path\filename"]" if (FAILED(_hr=sQueryString.Assign(WZ_FILE_QUERYSTRING_PREFIX))) goto exit; if (FAILED(_hr=sQueryString.Append((LPWSTR)pcwzFileName))) goto exit; if (FAILED(_hr=sQueryString.Append(WZ_FILE_QUERYSTRING_SUFFIX))) goto exit; bstrtQueryString = ::SysAllocString(sQueryString._pwz); if (!bstrtQueryString) { _hr = E_OUTOFMEMORY; goto exit; } if ((_hr = _pXMLDoc->selectNodes(bstrtQueryString, &pXMLMatchingFileNodeList)) != S_OK) goto exit; _hr = pXMLMatchingFileNodeList->get_length(&nMatchingFileNodes); if (nMatchingFileNodes > 1) { // multiple file callouts having the exact same file name/path within a single manifest... _hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT); goto exit; } _hr = pXMLMatchingFileNodeList->reset(); if ((_hr = pXMLMatchingFileNodeList->get_item(0, &pIDOMNode)) != S_OK) { _hr = E_FAIL; goto exit; } CreateAssemblyFileEx (&pAssemblyFile, pIDOMNode); *ppAssemblyFile = pAssemblyFile; (*ppAssemblyFile)->AddRef(); exit: if (bstrtQueryString) ::SysFreeString(bstrtQueryString); SAFERELEASE(pIDOMNode); SAFERELEASE(pXMLMatchingFileNodeList); SAFERELEASE(pAssemblyFile); return _hr; } // --------------------------------------------------------------------------- // CreateAssemblyFileEx // --------------------------------------------------------------------------- HRESULT CAssemblyManifestImport::CreateAssemblyFileEx(LPASSEMBLY_FILE_INFO *ppAssemblyFile, IXMLDOMNode *pIDOMNode) { LPWSTR pwzBuf; DWORD ccBuf; BOOL compressed; CString sFileName, sFileHash; LPASSEMBLY_FILE_INFO pAssemblyFile=NULL; // Create new AssemblyFile if (FAILED(_hr = CreateAssemblyFileInfo(&pAssemblyFile))) goto exit; // Parse out relevent information from IDOMNode if (FAILED(_hr = ParseAttribute(pIDOMNode, g_StringTable[FileName].bstr, &pwzBuf, &ccBuf))) goto exit; sFileName.TakeOwnership(pwzBuf, ccBuf); if (FAILED(_hr = ParseAttribute(pIDOMNode, g_StringTable[FileHash].bstr, &pwzBuf, &ccBuf))) goto exit; sFileHash.TakeOwnership(pwzBuf, ccBuf); // Set all aboved pased info into the AssemblyFIle if (FAILED(_hr = pAssemblyFile->Set(ASM_FILE_NAME, sFileName._pwz))) goto exit; if (FAILED(_hr = pAssemblyFile->Set(ASM_FILE_HASH, sFileHash._pwz))) goto exit; *ppAssemblyFile = pAssemblyFile; (*ppAssemblyFile)->AddRef(); exit: SAFERELEASE (pAssemblyFile); return _hr; } // --------------------------------------------------------------------------- // XMLtoAssemblyIdentiy IXMLDOMDocument2 *pXMLDoc // --------------------------------------------------------------------------- HRESULT CAssemblyManifestImport::XMLtoAssemblyIdentity(IXMLDOMNode *pIDOMNode, LPASSEMBLY_IDENTITY *ppAssemblyId) { LPASSEMBLY_IDENTITY pAssemblyId = NULL; LPWSTR pwzBuf = NULL; DWORD ccBuf = 0; if (FAILED(_hr = CreateAssemblyIdentity(&pAssemblyId, 0))) goto exit; for (eStringTableId i = Name; i <= Type; i++) { CString sBuf; if (FAILED(_hr = ParseAttribute(pIDOMNode, g_StringTable[i].bstr, &pwzBuf, &ccBuf))) goto exit; if (_hr != S_FALSE) { sBuf.TakeOwnership(pwzBuf, ccBuf); _hr = pAssemblyId->SetAttribute(g_StringTable[i].pwz, sBuf._pwz, sBuf._cc); } } *ppAssemblyId = pAssemblyId; (*ppAssemblyId)->AddRef(); exit: SAFERELEASE (pAssemblyId); return _hr; } // --------------------------------------------------------------------------- // IsCABbed // --------------------------------------------------------------------------- HRESULT CAssemblyManifestImport::IsCABbed(LPWSTR *ppwzCabName) { LPWSTR pwzBuf=NULL; DWORD ccBuf; IXMLDOMNodeList *pCABFileList; LONG nCABFiles; IXMLDOMNode *pCABNode; _hr = S_FALSE; if (_pPatchAssemblyNode) { if (_hr = _pPatchAssemblyNode->selectNodes(g_StringTable[Cab].bstr, &pCABFileList)) goto exit; _hr = pCABFileList->get_length(&nCABFiles); _hr = pCABFileList->reset(); if (nCABFiles == 0) { _hr = S_FALSE; goto exit; } else if (nCABFiles > 1) { _hr = E_FAIL; goto exit; } if (FAILED(_hr = pCABFileList->get_item(0, &pCABNode))) goto exit; if (FAILED(_hr = ParseAttribute(pCABNode, g_StringTable[File].bstr, &pwzBuf, &ccBuf))) goto exit; (*ppwzCabName) = pwzBuf; } exit: return _hr; } // --------------------------------------------------------------------------- // GetNextPatchAssemblyId // --------------------------------------------------------------------------- HRESULT CAssemblyManifestImport::GetNextPatchAssemblyId (DWORD nIndex, LPASSEMBLY_IDENTITY *ppAssemblyId) { IXMLDOMNode *pIDOMSourceAssemblyNode= NULL; IXMLDOMNode *pIDOMAssemblyIdNode = NULL; LPASSEMBLY_IDENTITY pAssemblyId = NULL; CString sQueryString; if (!_pSourceAssemblyPatchNodeList) { if ((_hr = _pXMLDoc->selectNodes(g_StringTable[Patch].bstr, &_pSourceAssemblyPatchNodeList)) != S_OK) goto exit; _hr = _pSourceAssemblyPatchNodeList->get_length(&_nSourceAssemblyPatchNodes); _hr = _pSourceAssemblyPatchNodeList->reset(); } if (nIndex >= (DWORD) _nSourceAssemblyPatchNodes) { _hr = S_FALSE; goto exit; } if (FAILED(_hr = _pSourceAssemblyPatchNodeList->get_item(nIndex, &pIDOMSourceAssemblyNode))) goto exit; if ((_hr = pIDOMSourceAssemblyNode->selectSingleNode(g_StringTable[AssemblyIdTag].bstr, &pIDOMAssemblyIdNode)) != S_OK) goto exit; if (FAILED(_hr = XMLtoAssemblyIdentity(pIDOMAssemblyIdNode, &pAssemblyId))) goto exit; *ppAssemblyId = pAssemblyId; (*ppAssemblyId)->AddRef(); exit: SAFERELEASE(pIDOMSourceAssemblyNode); SAFERELEASE(pIDOMAssemblyIdNode); SAFERELEASE(pAssemblyId); return _hr; } // --------------------------------------------------------------------------- // SetPatchAssemblyNode // --------------------------------------------------------------------------- HRESULT CAssemblyManifestImport::SetPatchAssemblyNode(DWORD nIndex) { IXMLDOMNode *pIDOMSourceAssemblyNode= NULL; SAFERELEASE(_pPatchAssemblyNode); if (nIndex >= (DWORD) _nSourceAssemblyPatchNodes) { _hr = S_FALSE; goto exit; } if (FAILED(_hr = _pSourceAssemblyPatchNodeList->get_item(nIndex, &pIDOMSourceAssemblyNode))) goto exit; _pPatchAssemblyNode = pIDOMSourceAssemblyNode; _pPatchAssemblyNode->AddRef(); exit: SAFERELEASE(pIDOMSourceAssemblyNode); return _hr; } // --------------------------------------------------------------------------- // GetTargetPatchMapping // --------------------------------------------------------------------------- HRESULT CAssemblyManifestImport::GetTargetPatchMapping(LPWSTR pwzTarget, LPWSTR *ppwzSource, LPWSTR *ppwzPatchFile) { LPWSTR pwzBuf= NULL; DWORD ccBuf = 0; LPWSTR pwzPatchFile = NULL, pwzSource = NULL; CString sQueryString; BSTR bstrtQueryString; LONG nPatchFileNodes; IXMLDOMNodeList *pPatchFileNodeList = NULL; IXMLDOMNode *pPatchFileNode = NULL; // set up serach string _hr = sQueryString.Assign(L"PatchInfo[@file=\""); _hr = sQueryString.Append(pwzTarget); _hr = sQueryString.Append(L"\"] | PatchInfo[@target=\""); _hr = sQueryString.Append(pwzTarget); _hr = sQueryString.Append(L"\"]"); bstrtQueryString = ::SysAllocString(sQueryString._pwz); if (!bstrtQueryString) { _hr = E_OUTOFMEMORY; goto exit; } if ((_hr = _pPatchAssemblyNode->selectNodes(bstrtQueryString, &pPatchFileNodeList)) != S_OK) goto exit; _hr = pPatchFileNodeList->get_length(&nPatchFileNodes); if (nPatchFileNodes > 1) { // multiple file callouts having the exact same file name/path within a single source assembly _hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT); goto exit; } else if (nPatchFileNodes == 0) { _hr = S_FALSE; goto exit; } _hr = pPatchFileNodeList->reset(); if ((_hr = pPatchFileNodeList->get_item(0, &pPatchFileNode)) != S_OK) { _hr = E_FAIL; goto exit; } if ((_hr = ParseAttribute(pPatchFileNode, g_StringTable[File].bstr, &pwzBuf, &ccBuf)) == S_OK) { pwzSource = pwzBuf; pwzTarget =WSTRDupDynamic(pwzSource); } else if (_hr == S_FALSE) { if ((_hr = ParseAttribute(pPatchFileNode, g_StringTable[Source].bstr, &pwzBuf, &ccBuf) != S_OK)) goto exit; pwzSource =pwzBuf; } else goto exit; if ((_hr = ParseAttribute(pPatchFileNode, g_StringTable[PatchFile].bstr, &pwzBuf, &ccBuf) != S_OK)) goto exit; pwzPatchFile =pwzBuf; (*ppwzSource) = pwzSource; (*ppwzPatchFile) = pwzPatchFile; exit: if (bstrtQueryString) ::SysFreeString(bstrtQueryString); SAFERELEASE(pPatchFileNode); SAFERELEASE(pPatchFileNodeList); return _hr; } // --------------------------------------------------------------------------- // GetPatchFilePatchMapping // --------------------------------------------------------------------------- HRESULT CAssemblyManifestImport::GetPatchFilePatchMapping(LPWSTR pwzPatchFile, LPWSTR *ppwzSource, LPWSTR *ppwzTarget) { LPWSTR pwzBuf= NULL; DWORD ccBuf = 0; LPWSTR pwzSource = NULL, pwzTarget = NULL; CString sQueryString; BSTR bstrtQueryString; IXMLDOMNodeList *pPatchFileNodeList; LONG nPatchFileNodes; IXMLDOMNode *pPatchFileNode; // set up serach string _hr = sQueryString.Assign(L"PatchInfo[@patchfile=\""); _hr = sQueryString.Append(pwzPatchFile); _hr = sQueryString.Append(L"\"]"); bstrtQueryString = ::SysAllocString(sQueryString._pwz); if (!bstrtQueryString) { _hr = E_OUTOFMEMORY; goto exit; } if ((_hr = _pPatchAssemblyNode->selectNodes(bstrtQueryString, &pPatchFileNodeList)) != S_OK) goto exit; _hr = pPatchFileNodeList->get_length(&nPatchFileNodes); if (nPatchFileNodes > 1) { // multiple file callouts having the exact same file name/path within a single source assembly _hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT); goto exit; } _hr = pPatchFileNodeList->reset(); if ((_hr = pPatchFileNodeList->get_item(0, &pPatchFileNode)) != S_OK) { _hr = E_FAIL; goto exit; } if ((_hr = ParseAttribute(pPatchFileNode, g_StringTable[File].bstr, &pwzBuf, &ccBuf)) == S_OK) { pwzSource = pwzBuf; pwzTarget =WSTRDupDynamic(pwzSource); } else if (_hr == S_FALSE) { // Commented out code makes NULL patching possible, Must remove following call to ParseAttribute for source. /* if (FAILED(_hr = ParseAttribute(pPatchFileNode, g_StringTable[Source].bstr, &pwzBuf, &ccBuf))) goto exit; else if (_hr == S_FALSE) pwzBuf = NULL; */ if ((_hr = ParseAttribute(pPatchFileNode, g_StringTable[Source].bstr, &pwzBuf, &ccBuf) != S_OK)) goto exit; pwzSource =pwzBuf; if ((_hr = ParseAttribute(pPatchFileNode, g_StringTable[Target].bstr, &pwzBuf, &ccBuf) != S_OK)) goto exit; pwzTarget=pwzBuf; } else goto exit; (*ppwzSource) = pwzSource; (*ppwzTarget) = pwzTarget; exit: if (bstrtQueryString) ::SysFreeString(bstrtQueryString); SAFERELEASE(pPatchFileNode); SAFERELEASE(pPatchFileNodeList); return _hr; } // --------------------------------------------------------------------------- // GetNextAssembly // --------------------------------------------------------------------------- HRESULT CAssemblyManifestImport::GetNextAssembly(DWORD nIndex, LPDEPENDENT_ASSEMBLY_INFO *ppDependAsm) { CString sCodebase; IXMLDOMNode *pIDOMNode = NULL; IXMLDOMNode *pIDOMCodebaseNode = NULL; IXMLDOMNodeList *pXMLCodebaseNodeList = NULL; LPASSEMBLY_IDENTITY pAssemblyId = NULL; LPDEPENDENT_ASSEMBLY_INFO pDependAsm = NULL; LPWSTR pwzBuf = NULL; DWORD ccBuf = NULL; LONG nCodebaseNodes = 0; if (ppDependAsm == NULL) { _hr = E_INVALIDARG; goto exit; } *ppDependAsm = NULL; // Initialize the assembly node list if necessary. if (!_pXMLAssemblyNodeList) { if ((_hr = _pXMLDoc->selectNodes(g_StringTable[DependentAssemblyNode].bstr, &_pXMLAssemblyNodeList)) != S_OK) goto exit; _hr = _pXMLAssemblyNodeList->get_length(&_nAssemblyNodes); _hr = _pXMLAssemblyNodeList->reset(); } if (nIndex >= (DWORD) _nAssemblyNodes) { _hr = S_FALSE; goto exit; } if (FAILED(_hr = _pXMLAssemblyNodeList->get_item(nIndex, &pIDOMNode))) goto exit; if (FAILED(_hr = XMLtoAssemblyIdentity(pIDOMNode, &pAssemblyId))) goto exit; // note: check for multiple qualified nodes. As the use of "../install" XPath expression // can result in either preceding _or_ following siblings with node name "install", // this is to ensure codebase is not defined > 1 for this particular dependent // BUGBUG: should just take the 1st codebase and ignore all others? if ((_hr = pIDOMNode->selectNodes(g_StringTable[DependentAssemblyCodebase].bstr, &pXMLCodebaseNodeList)) != S_OK) goto exit; _hr = pXMLCodebaseNodeList->get_length(&nCodebaseNodes); if (nCodebaseNodes > 1) { // multiple codebases for a single dependent assembly identity... _hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT); goto exit; } _hr = pXMLCodebaseNodeList->reset(); if ((_hr = pXMLCodebaseNodeList->get_item(0, &pIDOMCodebaseNode)) != S_OK) { _hr = E_FAIL; goto exit; } if (FAILED(_hr = ParseAttribute(pIDOMCodebaseNode, g_StringTable[Codebase].bstr, &pwzBuf, &ccBuf))) goto exit; sCodebase.TakeOwnership(pwzBuf, ccBuf); if (FAILED(_hr = CreateDependentAssemblyInfo(&pDependAsm))) goto exit; if (FAILED(_hr = pDependAsm->Set(DEPENDENT_ASM_CODEBASE, sCodebase._pwz))) goto exit; // Handout refcounted assemblyid. pDependAsm->SetAssemblyIdentity(pAssemblyId); *ppDependAsm = pDependAsm; (*ppDependAsm)->AddRef(); exit: SAFERELEASE(pIDOMCodebaseNode); SAFERELEASE(pXMLCodebaseNodeList); SAFERELEASE(pIDOMNode); SAFERELEASE(pAssemblyId); SAFERELEASE(pDependAsm); return _hr; } // --------------------------------------------------------------------------- // GetAssemblyIdentity // --------------------------------------------------------------------------- HRESULT CAssemblyManifestImport::GetAssemblyIdentity(LPASSEMBLY_IDENTITY *ppAssemblyId) { IXMLDOMNode *pIDOMNode = NULL; LPASSEMBLY_IDENTITY pAssemblyId = NULL; LPWSTR pwzBuf = NULL; DWORD ccBuf = 0; if (_pAssemblyId) { *ppAssemblyId = _pAssemblyId; (*ppAssemblyId)->AddRef(); _hr = S_OK; goto exit; } if ((_hr = _pXMLDoc->selectSingleNode(g_StringTable[AssemblyId].bstr, &pIDOMNode)) != S_OK) goto exit; if (FAILED(_hr = XMLtoAssemblyIdentity(pIDOMNode, &pAssemblyId))) goto exit; *ppAssemblyId = pAssemblyId; (*ppAssemblyId)->AddRef(); // do not release AsmId, cache it _pAssemblyId = pAssemblyId; exit: SAFERELEASE(pIDOMNode); return _hr; } // --------------------------------------------------------------------------- // GetManifestApplicationInfo // --------------------------------------------------------------------------- HRESULT CAssemblyManifestImport::GetManifestApplicationInfo(LPMANIFEST_APPLICATION_INFO* ppAppInfo) { IXMLDOMNode *pIDOMNode = NULL; LPMANIFEST_APPLICATION_INFO pAppInfo = NULL; LPWSTR pwzBuf = NULL; DWORD ccBuf = 0; if (ppAppInfo == NULL) { _hr = E_INVALIDARG; goto exit; } *ppAppInfo = NULL; if ((_hr = _pXMLDoc->selectSingleNode(g_StringTable[ShellState].bstr, &pIDOMNode)) != S_OK) goto exit; CreateManifestApplicationInfo(&pAppInfo); for (eStringTableId i = FriendlyName; i <= HotKey; i++) { CString sBuf; if (FAILED(_hr = ParseAttribute(pIDOMNode, g_StringTable[i].bstr, &pwzBuf, &ccBuf))) goto exit; if (_hr != S_FALSE) { sBuf.TakeOwnership(pwzBuf, ccBuf); if (FAILED(_hr = pAppInfo->Set(MAN_APPLICATION_FRIENDLYNAME+i-FriendlyName, sBuf._pwz))) goto exit; } } // reset so that S_FALSE is returned only if Subscription node is not found but not its attributes _hr = S_OK; *ppAppInfo = pAppInfo; (*ppAppInfo)->AddRef(); exit: SAFERELEASE(pIDOMNode); SAFERELEASE(pAppInfo); return _hr; } // IUnknown Boilerplate // --------------------------------------------------------------------------- // CAssemblyManifestImport::QI // --------------------------------------------------------------------------- STDMETHODIMP CAssemblyManifestImport::QueryInterface(REFIID riid, void** ppvObj) { if ( IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IAssemblyManifestImport) ) { *ppvObj = static_cast (this); AddRef(); return S_OK; } else { *ppvObj = NULL; return E_NOINTERFACE; } } // --------------------------------------------------------------------------- // CAssemblyManifestImport::AddRef // --------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CAssemblyManifestImport::AddRef() { return InterlockedIncrement ((LONG*) &_cRef); } // --------------------------------------------------------------------------- // CAssemblyManifestImport::Release // --------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CAssemblyManifestImport::Release() { ULONG lRet = InterlockedDecrement ((LONG*) &_cRef); if (!lRet) delete this; return lRet; } // Privates // --------------------------------------------------------------------------- // Init // --------------------------------------------------------------------------- HRESULT CAssemblyManifestImport::Init(LPCOLESTR pwzManifestFilePath) { CCriticalSection cs(&g_cs); if (!pwzManifestFilePath) { _hr = E_INVALIDARG; goto exit; } // Alloc globals if necessary if (!g_nRefCount) { cs.Lock(); if (!g_nRefCount) { for (eStringTableId i = Name; i < MAX_STRINGS; i++) { if (!(g_StringTable[i].bstr = ::SysAllocString(g_StringTable[i].pwz))) { cs.Unlock(); _hr = E_OUTOFMEMORY; goto exit; } } } g_nRefCount++; cs.Unlock(); } else // NOTENOTE:mem barrier needed if LeaveCriticalSection is previously executed? InterlockedIncrement(&g_nRefCount); // Alloc manifest file path. _bstrManifestFilePath = ::SysAllocString((LPWSTR) pwzManifestFilePath); if (!_bstrManifestFilePath) { _hr = E_OUTOFMEMORY; goto exit; } // Load the DOM document. _hr = LoadDocumentSync(); // Release the cached AsmId SAFERELEASE(_pAssemblyId); exit: return _hr; } // --------------------------------------------------------------------------- // LoadDocumentSync // --------------------------------------------------------------------------- HRESULT CAssemblyManifestImport::LoadDocumentSync() { VARIANT varURL; VARIANT varNameSpaces; VARIANT varXPath; VARIANT_BOOL varb; IXMLDOMDocument2 *pXMLDoc = NULL; // Create the DOM Doc interface if (FAILED(_hr = CoCreateInstance(__uuidof(private_MSXML_DOMDocument30), NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument2, (void**)&_pXMLDoc))) goto exit; // Load synchronously if (FAILED(_hr = _pXMLDoc->put_async(VARIANT_FALSE))) goto exit; // Load xml document from the given URL or file path VariantInit(&varURL); varURL.vt = VT_BSTR; V_BSTR(&varURL) = _bstrManifestFilePath; if (FAILED(_hr = _pXMLDoc->load(varURL, &varb))) goto exit; if (_hr == S_FALSE) { // S_FALSE returned if the load fails _hr = E_FAIL; goto exit; } // Setup namespace filter VariantInit(&varNameSpaces); varNameSpaces.vt = VT_BSTR; V_BSTR(&varNameSpaces) = g_StringTable[NameSpace].bstr; if (FAILED(_hr = _pXMLDoc->setProperty(g_StringTable[SelNameSpaces].bstr, varNameSpaces))) goto exit; // Setup query type VariantInit(&varXPath); varXPath.vt = VT_BSTR; V_BSTR(&varXPath) = g_StringTable[XPath].bstr; if (FAILED(_hr = _pXMLDoc->setProperty(g_StringTable[SelLanguage].bstr, varXPath))) goto exit; _hr = S_OK; exit: if (FAILED(_hr)) SAFERELEASE(_pXMLDoc); return _hr; } // --------------------------------------------------------------------------- // ParseAttribute // --------------------------------------------------------------------------- HRESULT CAssemblyManifestImport::ParseAttribute(IXMLDOMNode *pIXMLDOMNode, BSTR bstrAttributeName, LPWSTR *ppwzAttributeValue, LPDWORD pccAttributeValue) { DWORD ccAttributeValue = 0; LPWSTR pwzAttributeValue = NULL; VARIANT varValue; IXMLDOMElement *pIXMLDOMElement = NULL; if (FAILED(_hr = pIXMLDOMNode->QueryInterface(IID_IXMLDOMElement, (void**) &pIXMLDOMElement))) goto exit; if ((_hr = pIXMLDOMElement->getAttribute(bstrAttributeName, &varValue)) != S_OK) goto exit; // BUGBUG - what is meaning of NULL value here? if(varValue.vt != VT_NULL) { ccAttributeValue = ::SysStringLen(varValue.bstrVal) + 1; pwzAttributeValue = new WCHAR[ccAttributeValue]; if (!pwzAttributeValue) { _hr = E_OUTOFMEMORY; goto exit; } memcpy(pwzAttributeValue, varValue.bstrVal, ccAttributeValue * sizeof(WCHAR)); *ppwzAttributeValue = pwzAttributeValue; *pccAttributeValue = ccAttributeValue; } else _hr = S_FALSE; exit: SAFERELEASE(pIXMLDOMElement); return _hr; } // --------------------------------------------------------------------------- // InitGlobalCritSect // --------------------------------------------------------------------------- void CAssemblyManifestImport::InitGlobalCritSect() { InitializeCriticalSection(&g_cs); } // --------------------------------------------------------------------------- // ReportManifestType // --------------------------------------------------------------------------- HRESULT CAssemblyManifestImport::ReportManifestType(DWORD *pdwType) { LPWSTR pwzType = NULL; DWORD dwCC = 0; if (pdwType == NULL) { _hr = E_INVALIDARG; goto exit; } *pdwType = MANIFEST_TYPE_UNKNOWN; // ensure _pAssemblyId is initialized/cached if (!_pAssemblyId) { LPASSEMBLY_IDENTITY pAssemblyId = NULL; if ((_hr = GetAssemblyIdentity(&pAssemblyId)) != S_OK) goto exit; SAFERELEASE(pAssemblyId); } if ((_hr = _pAssemblyId->GetAttribute(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_TYPE, &pwzType, &dwCC)) == S_OK) { // note: case sensitive comparison if (wcscmp(pwzType, L"desktop") == 0) *pdwType = MANIFEST_TYPE_DESKTOP; else if (wcscmp(pwzType, L"subscription") == 0) *pdwType = MANIFEST_TYPE_SUBSCRIPTION; else if (wcscmp(pwzType, L"application") == 0) *pdwType = MANIFEST_TYPE_APPLICATION; // else MANIFEST_TYPE_UNKNOWN delete pwzType; } exit: return _hr; }