#include #include #include #include #include #define PATCH_DIRECTORY L"__patch__\\" // --------------------------------------------------------------------------- // CreatePatchingUtil // --------------------------------------------------------------------------- STDAPI CreatePatchingUtil(IXMLDOMNode *pPatchNode, LPPATCHING_INTERFACE* ppPatchingInfo) { HRESULT hr = S_OK; MAKE_ERROR_MACROS_STATIC(hr); CPatchingUtil *pPatchingInfo = NULL; IF_ALLOC_FAILED_EXIT(pPatchingInfo = new(CPatchingUtil)); IF_FAILED_EXIT(pPatchingInfo->Init(pPatchNode)); *ppPatchingInfo = static_cast (pPatchingInfo); pPatchingInfo = NULL; exit: SAFERELEASE(pPatchingInfo); return hr; } // --------------------------------------------------------------------------- // ctor // --------------------------------------------------------------------------- CPatchingUtil::CPatchingUtil() : _dwSig('UATP'), _cRef(1), _hr(S_OK), _pXMLPatchNode(NULL) { } // --------------------------------------------------------------------------- // dtor // --------------------------------------------------------------------------- CPatchingUtil::~CPatchingUtil() { SAFERELEASE(_pXMLPatchNode); } // --------------------------------------------------------------------------- // Init // --------------------------------------------------------------------------- HRESULT CPatchingUtil::Init(IXMLDOMNode *pPatchNode) { _hr = S_OK; _pXMLPatchNode = pPatchNode; _pXMLPatchNode->AddRef(); return _hr; } // --------------------------------------------------------------------------- // MatchTarget // --------------------------------------------------------------------------- HRESULT CPatchingUtil::MatchTarget(LPWSTR pwzTarget, IManifestInfo **ppPatchInfo) { LPWSTR pwzBuf; DWORD ccBuf; CString sQueryString; BSTR bstrtQueryString; IXMLDOMNode *pNode=NULL; IXMLDOMNodeList *pNodeList = NULL; LONG nNodes; IManifestInfo *pPatchInfo = NULL; CString sSourceName, sPatchName, sTargetName; IF_FAILED_EXIT(sTargetName.Assign(pwzTarget)); // set up serach string IF_FAILED_EXIT(sQueryString.Assign(L"PatchInfo[@file=\"")); IF_FAILED_EXIT(sQueryString.Append(pwzTarget)); IF_FAILED_EXIT(sQueryString.Append(L"\"] | PatchInfo[@target=\"")); IF_FAILED_EXIT(sQueryString.Append(pwzTarget)); IF_FAILED_EXIT(sQueryString.Append(L"\"]")); IF_ALLOC_FAILED_EXIT(bstrtQueryString = ::SysAllocString(sQueryString._pwz)); IF_FAILED_EXIT(_pXMLPatchNode->selectNodes(bstrtQueryString, &pNodeList)); IF_FAILED_EXIT(_hr = pNodeList->get_length(&nNodes)); IF_FALSE_EXIT(nNodes <= 1, HRESULT_FROM_WIN32(ERROR_BAD_FORMAT)); IF_TRUE_EXIT(nNodes == 0, S_FALSE); IF_FALSE_EXIT(pNodeList->get_item(0, &pNode) == S_OK, E_FAIL); IF_FAILED_EXIT(CreateManifestInfo(MAN_INFO_PATCH_INFO, &pPatchInfo)); IF_FAILED_EXIT(pPatchInfo->Set(MAN_INFO_PATCH_INFO_TARGET, sTargetName._pwz, sTargetName.ByteCount(), MAN_INFO_FLAG_LPWSTR)); IF_FAILED_EXIT(CAssemblyManifestImport::ParseAttribute(pNode, CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::File].bstr, &pwzBuf, &ccBuf)); if(_hr == S_OK) { IF_FAILED_EXIT(sSourceName.TakeOwnership(pwzBuf, ccBuf)); } else if (_hr == S_FALSE) { IF_FAILED_EXIT(CAssemblyManifestImport::ParseAttribute(pNode, CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::Source].bstr, &pwzBuf, &ccBuf)); IF_FALSE_EXIT(_hr == S_OK, HRESULT_FROM_WIN32(ERROR_BAD_FORMAT)); IF_FAILED_EXIT(sSourceName.TakeOwnership(pwzBuf, ccBuf)); } IF_FAILED_EXIT(pPatchInfo->Set(MAN_INFO_PATCH_INFO_SOURCE, sSourceName._pwz, sSourceName.ByteCount(), MAN_INFO_FLAG_LPWSTR)); IF_FAILED_EXIT(CAssemblyManifestImport::ParseAttribute(pNode, CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::PatchFile].bstr, &pwzBuf, &ccBuf)); IF_TRUE_EXIT(_hr == S_FALSE, S_OK); IF_FAILED_EXIT(sPatchName.TakeOwnership(pwzBuf, ccBuf)); IF_FAILED_EXIT(pPatchInfo->Set(MAN_INFO_PATCH_INFO_PATCH, sPatchName._pwz, sPatchName.ByteCount(), MAN_INFO_FLAG_LPWSTR)); *ppPatchInfo = pPatchInfo; pPatchInfo = NULL; exit: if (bstrtQueryString) ::SysFreeString(bstrtQueryString); SAFERELEASE(pNode); SAFERELEASE(pNodeList); SAFERELEASE(pPatchInfo); return _hr; } // --------------------------------------------------------------------------- // MatchPatch // --------------------------------------------------------------------------- HRESULT CPatchingUtil::MatchPatch(LPWSTR pwzPatch, IManifestInfo **ppPatchInfo) { LPWSTR pwzBuf; DWORD ccBuf; CString sQueryString; BSTR bstrtQueryString; IXMLDOMNode *pNode=NULL; IXMLDOMNodeList *pNodeList = NULL; LONG nNodes; IManifestInfo *pPatchInfo = NULL; CString sSourceName, sTargetName, sFileName, sPatchName; IF_FAILED_EXIT(sPatchName.Assign (pwzPatch)); // set up serach string IF_FAILED_EXIT(sQueryString.Assign(L"PatchInfo[@patchfile=\"")); IF_FAILED_EXIT(sQueryString.Append(pwzPatch)); IF_FAILED_EXIT(sQueryString.Append(L"\"]")); IF_ALLOC_FAILED_EXIT(bstrtQueryString = ::SysAllocString(sQueryString._pwz)); if ((_hr = _pXMLPatchNode->selectNodes(bstrtQueryString, &pNodeList)) != S_OK) goto exit; _hr = pNodeList->get_length(&nNodes); IF_FALSE_EXIT(nNodes <= 1, HRESULT_FROM_WIN32(ERROR_BAD_FORMAT)); IF_FALSE_EXIT(pNodeList->get_item(0, &pNode) == S_OK, E_FAIL); IF_FAILED_EXIT(CreateManifestInfo(MAN_INFO_PATCH_INFO, &pPatchInfo)); IF_FAILED_EXIT(pPatchInfo->Set(MAN_INFO_PATCH_INFO_PATCH, sPatchName._pwz, sPatchName.ByteCount(), MAN_INFO_FLAG_LPWSTR)); IF_FAILED_EXIT(CAssemblyManifestImport::ParseAttribute(pNode, CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::File].bstr, &pwzBuf, &ccBuf)); if(_hr == S_OK) { IF_FAILED_EXIT(sSourceName.TakeOwnership(pwzBuf, ccBuf)); IF_FAILED_EXIT(sTargetName.Assign(pwzBuf)); } else if (_hr == S_FALSE) { IF_FALSE_EXIT(CAssemblyManifestImport::ParseAttribute(pNode, CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::Source].bstr, &pwzBuf, &ccBuf) == S_OK, HRESULT_FROM_WIN32(ERROR_BAD_FORMAT)); IF_FAILED_EXIT(sSourceName.TakeOwnership(pwzBuf, ccBuf)); IF_FALSE_EXIT(CAssemblyManifestImport::ParseAttribute(pNode, CAssemblyManifestImport::g_StringTable[CAssemblyManifestImport::Target].bstr, &pwzBuf, &ccBuf) == S_OK, HRESULT_FROM_WIN32(ERROR_BAD_FORMAT)); IF_FAILED_EXIT(sTargetName.TakeOwnership(pwzBuf, ccBuf)); } IF_FAILED_EXIT(pPatchInfo->Set(MAN_INFO_PATCH_INFO_SOURCE, sSourceName._pwz, sSourceName.ByteCount(), MAN_INFO_FLAG_LPWSTR)); IF_FAILED_EXIT(pPatchInfo->Set(MAN_INFO_PATCH_INFO_TARGET, sTargetName._pwz, sTargetName.ByteCount(), MAN_INFO_FLAG_LPWSTR)); *ppPatchInfo = pPatchInfo; pPatchInfo = NULL; _hr = S_OK; exit: if (bstrtQueryString) ::SysFreeString(bstrtQueryString); SAFERELEASE(pNode); SAFERELEASE(pNodeList); SAFERELEASE(pPatchInfo); return _hr; } // IUnknown Boilerplate // --------------------------------------------------------------------------- // CPatchingUtil::QI // --------------------------------------------------------------------------- STDMETHODIMP CPatchingUtil::QueryInterface(REFIID riid, void** ppvObj) { if ( IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IPatchingUtil) ) { *ppvObj = static_cast (this); AddRef(); return S_OK; } else { *ppvObj = NULL; return E_NOINTERFACE; } } // --------------------------------------------------------------------------- // CPatchingUtil::AddRef // --------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CPatchingUtil::AddRef() { return InterlockedIncrement ((LONG*) &_cRef); } // --------------------------------------------------------------------------- // CPatchingUtil::Release // --------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CPatchingUtil::Release() { ULONG lRet = InterlockedDecrement ((LONG*) &_cRef); if (!lRet) delete this; return lRet; } // --------------------------------------------------------------------------- // CreatePatchingInfo // --------------------------------------------------------------------------- HRESULT CPatchingUtil::CreatePatchingInfo(IXMLDOMDocument2 *pXMLDOMDocument, IAssemblyCacheImport *pCacheImport, IManifestInfo **ppPatchingInfo) { HRESULT hr = S_OK; MAKE_ERROR_MACROS_STATIC(hr); LPWSTR pwzBuf; DWORD cbBuf, ccBuf; CString sManifestDirectory, sSourceManifestDirectory, sTempDirectoryPath; CString sSourceAssemblyDisplayName; CString sQueryString; BSTR bstrtQueryString = NULL; IXMLDOMNodeList *pXMLMatchingNodeList = NULL; IXMLDOMNode *pXMLNode = NULL; IXMLDOMNode *pXMLASMNode = NULL; IAssemblyCacheImport *pSourceASMImport = NULL; IAssemblyIdentity *pAssemblyId = NULL, *pSourceASMId =NULL; IAssemblyManifestImport *pManifestImport = NULL; IManifestInfo *pPatchingInfo = NULL; IPatchingUtil *pPatchingUtil = NULL; *ppPatchingInfo = NULL; //Get the manifest import from the pCacheImport so we can grab the AssemblyId IF_FAILED_EXIT(pCacheImport->GetManifestImport(&pManifestImport)); //Get the assemblyID IF_FAILED_EXIT(pManifestImport->GetAssemblyIdentity(&pAssemblyId)); SAFERELEASE(pManifestImport); IF_FAILED_EXIT(sQueryString.Assign(L"/assembly/Patch/SourceAssembly")); IF_ALLOC_FAILED_EXIT(bstrtQueryString = ::SysAllocString(sQueryString._pwz)); if ((hr = pXMLDOMDocument->selectNodes(bstrtQueryString, &pXMLMatchingNodeList)) != S_OK) goto exit; pXMLMatchingNodeList->reset(); //enumerate through the Source Assemblies while ((hr = pXMLMatchingNodeList->nextNode(&pXMLNode)) == S_OK) { //Get the first child under the SourceAssemly (this is the ASM Id) if ((hr = pXMLNode->get_firstChild (&pXMLASMNode)) != S_OK) goto exit; //Convert the XML node to an actuall ASM Id if ((hr = CAssemblyManifestImport::XMLtoAssemblyIdentity(pXMLASMNode, &pSourceASMId)) != S_OK) goto exit; //Check to see if the SourceAssembly exists in cache // or if is the same as the Assembly we are currently downloading IF_FAILED_EXIT(CreateAssemblyCacheImport(&pSourceASMImport, pSourceASMId, CACHEIMP_CREATE_RETRIEVE)); if (hr == S_FALSE) { IF_FAILED_EXIT(pSourceASMId->IsEqual(pAssemblyId)); if (hr == S_OK) { pSourceASMImport = pCacheImport; pSourceASMImport->AddRef(); } } //Found a suitable SourceAssembly if (hr == S_OK) { //Create a manifestInfo property bag IF_FAILED_EXIT(CreateManifestInfo(MAN_INFO_SOURCE_ASM, &pPatchingInfo)); //Set the source ASMId in the property bag IF_FAILED_EXIT(pPatchingInfo->Set(MAN_INFO_SOURCE_ASM_ID, &pSourceASMId, sizeof(LPVOID), MAN_INFO_FLAG_IUNKNOWN_PTR)); // grab the manifest directory IF_FAILED_EXIT(pCacheImport->GetManifestFileDir(&pwzBuf, &ccBuf)); IF_FAILED_EXIT(sManifestDirectory.TakeOwnership(pwzBuf, ccBuf)); //Set manifest Directory in patchingInfo property bag IF_FAILED_EXIT(pPatchingInfo->Set(MAN_INFO_SOURCE_ASM_INSTALL_DIR, sManifestDirectory._pwz, sManifestDirectory.ByteCount(), MAN_INFO_FLAG_LPWSTR)); //grab directory of SourceAssembly IF_FAILED_EXIT(pSourceASMImport->GetManifestFileDir(&pwzBuf, &ccBuf)); IF_FAILED_EXIT(sSourceManifestDirectory.TakeOwnership(pwzBuf, ccBuf)); //Set SourceAssembly Directory in patchingInfo property bag IF_FAILED_EXIT(pPatchingInfo->Set(MAN_INFO_SOURCE_ASM_DIR, sSourceManifestDirectory._pwz, sSourceManifestDirectory.ByteCount(), MAN_INFO_FLAG_LPWSTR)); //get display name of patch assembly identity IF_FAILED_EXIT(pSourceASMId->GetDisplayName(ASMID_DISPLAYNAME_NOMANGLING, &pwzBuf, &ccBuf)); IF_FAILED_EXIT(sSourceAssemblyDisplayName.TakeOwnership (pwzBuf, ccBuf)); //setup the path of the temporary directory IF_FAILED_EXIT(sTempDirectoryPath.Assign(sManifestDirectory)); IF_FAILED_EXIT(DoPathCombine(sTempDirectoryPath, PATCH_DIRECTORY)); IF_FAILED_EXIT(DoPathCombine(sTempDirectoryPath, sSourceAssemblyDisplayName._pwz)); IF_FAILED_EXIT(sTempDirectoryPath.Append(L"\\")); //Set Temporary Directory in patchingInfo property bag IF_FAILED_EXIT(pPatchingInfo->Set(MAN_INFO_SOURCE_ASM_TEMP_DIR, sTempDirectoryPath._pwz, sTempDirectoryPath.ByteCount(), MAN_INFO_FLAG_LPWSTR)); // Create patching info interface and insert into manifestInfo propertybag IF_FAILED_EXIT(CreatePatchingUtil(pXMLNode, &pPatchingUtil)); IF_FAILED_EXIT(pPatchingInfo->Set(MAN_INFO_SOURCE_ASM_PATCH_UTIL, &pPatchingUtil, sizeof(LPVOID), MAN_INFO_FLAG_IUNKNOWN_PTR)); } SAFERELEASE(pXMLNode); SAFERELEASE(pXMLASMNode); SAFERELEASE(pSourceASMId); SAFERELEASE(pSourceASMImport); if (pPatchingInfo) { *ppPatchingInfo = pPatchingInfo; pPatchingInfo = NULL; hr = S_OK; // this is the successful case. goto exit; } } IF_FAILED_EXIT(hr); // BUGBUG: what the hell is this? hr = S_FALSE; exit: if (bstrtQueryString) ::SysFreeString(bstrtQueryString); SAFERELEASE(pManifestImport); SAFERELEASE(pXMLNode); SAFERELEASE(pXMLASMNode); SAFERELEASE(pSourceASMId); SAFERELEASE(pSourceASMImport); SAFERELEASE(pXMLMatchingNodeList); SAFERELEASE(pPatchingUtil); SAFERELEASE(pPatchingInfo); SAFERELEASE(pAssemblyId); return hr; }