static HRESULT ParseWxlControls( __in IXMLDOMElement* pElement, __in WIX_LOCALIZATION* pWixLoc ) { HRESULT hr = S_OK; IXMLDOMNode* pixn = NULL; IXMLDOMNodeList* pixnl = NULL; DWORD dwIdx = 0; hr = XmlSelectNodes(pElement, L"UI|Control", &pixnl); ExitOnLastError(hr, "Failed to get UI child nodes of Wxl File."); hr = pixnl->get_length(reinterpret_cast<long*>(&pWixLoc->cLocControls)); ExitOnLastError(hr, "Failed to get number of UI child nodes in Wxl File."); if (0 < pWixLoc->cLocControls) { pWixLoc->rgLocControls = static_cast<LOC_CONTROL*>(MemAlloc(sizeof(LOC_CONTROL) * pWixLoc->cLocControls, TRUE)); ExitOnNull(pWixLoc->rgLocControls, hr, E_OUTOFMEMORY, "Failed to allocate memory for localized controls."); while (S_OK == (hr = XmlNextElement(pixnl, &pixn, NULL))) { hr = ParseWxlControl(pixn, dwIdx, pWixLoc); ExitOnFailure(hr, "Failed to parse localized control."); ++dwIdx; ReleaseNullObject(pixn); } hr = S_OK; ExitOnFailure(hr, "Failed to enumerate all localized controls."); } LExit: if (FAILED(hr) && pWixLoc->rgLocControls) { for (DWORD idx = 0; idx < pWixLoc->cLocControls; ++idx) { ReleaseStr(pWixLoc->rgLocControls[idx].wzControl); ReleaseStr(pWixLoc->rgLocControls[idx].wzText); } ReleaseMem(pWixLoc->rgLocControls); } ReleaseObject(pixn); ReleaseObject(pixnl); return hr; }
HRESULT CpiSubscriptionsVerifyUninstall( CPI_SUBSCRIPTION_LIST* pList ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; ICatalogObject* piSubsObj = NULL; for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext) { // subscriptions that are being installed if (!WcaIsUninstalling(pItm->isInstalled, pItm->isAction)) continue; // find subscriptions with conflicting name hr = FindObjectForSubscription(pItm, 0 != *pItm->wzID, 0 == *pItm->wzID, &piSubsObj); ExitOnFailure(hr, "Failed to find collection object for subscription"); // if the subscription was found if (S_OK == hr) { // if we don't have an id, copy id from object if (!*pItm->wzID) { hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID)); ExitOnFailure(hr, "Failed to get id"); } } // if the subscription was not found else { pItm->fObjectNotFound = TRUE; pList->iUninstallCount--; // elements with the fObjectNotFound flag set will not be scheduled for uninstall } // clean up ReleaseNullObject(piSubsObj); } hr = S_OK; LExit: // clean up ReleaseObject(piSubsObj); return hr; }
static HRESULT ParsePackagesFromXml( __in BAL_INFO_PACKAGES* pPackages, __in IXMLDOMDocument* pixdManifest ) { HRESULT hr = S_OK; IXMLDOMNodeList* pNodeList = NULL; IXMLDOMNode* pNode = NULL; BAL_INFO_PACKAGE* prgPackages = NULL; DWORD cPackages = 0; LPWSTR sczType = NULL; hr = XmlSelectNodes(pixdManifest, L"/BootstrapperApplicationData/WixPackageProperties", &pNodeList); ExitOnFailure(hr, "Failed to select all packages."); hr = pNodeList->get_length(reinterpret_cast<long*>(&cPackages)); ExitOnFailure(hr, "Failed to get the package count."); prgPackages = static_cast<BAL_INFO_PACKAGE*>(MemAlloc(sizeof(BAL_INFO_PACKAGE) * cPackages, TRUE)); ExitOnNull(prgPackages, hr, E_OUTOFMEMORY, "Failed to allocate memory for packages."); DWORD iPackage = 0; while (S_OK == (hr = XmlNextElement(pNodeList, &pNode, NULL))) { hr = XmlGetAttributeEx(pNode, L"Package", &prgPackages[iPackage].sczId); ExitOnFailure(hr, "Failed to get package identifier for package."); hr = XmlGetAttributeEx(pNode, L"DisplayName", &prgPackages[iPackage].sczDisplayName); if (E_NOTFOUND != hr) { ExitOnFailure(hr, "Failed to get description for package."); } hr = XmlGetAttributeEx(pNode, L"Description", &prgPackages[iPackage].sczDescription); if (E_NOTFOUND != hr) { ExitOnFailure(hr, "Failed to get description for package."); } hr = XmlGetAttributeEx(pNode, L"PackageType", &sczType); ExitOnFailure(hr, "Failed to get description for package."); if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Exe", -1, sczType, -1)) { prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_EXE; } else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Msi", -1, sczType, -1)) { prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_MSI; } else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Msp", -1, sczType, -1)) { prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_MSP; } else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Msu", -1, sczType, -1)) { prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_MSU; } hr = XmlGetYesNoAttribute(pNode, L"Permanent", &prgPackages[iPackage].fPermanent); ExitOnFailure(hr, "Failed to get permanent setting for package."); hr = XmlGetYesNoAttribute(pNode, L"Vital", &prgPackages[iPackage].fVital); ExitOnFailure(hr, "Failed to get vital setting for package."); hr = XmlGetYesNoAttribute(pNode, L"DisplayInternalUI", &prgPackages[iPackage].fDisplayInternalUI); ExitOnFailure(hr, "Failed to get DisplayInternalUI setting for package."); ++iPackage; ReleaseNullObject(pNode); } ExitOnFailure(hr, "Failed to parse all package property elements."); if (S_FALSE == hr) { hr = S_OK; } pPackages->cPackages = cPackages; pPackages->rgPackages = prgPackages; prgPackages = NULL; LExit: ReleaseStr(sczType); ReleaseMem(prgPackages); ReleaseObject(pNode); ReleaseObject(pNodeList); return hr; }
DAPI_(HRESULT) BalConditionsParseFromXml( __in BAL_CONDITIONS* pConditions, __in IXMLDOMDocument* pixdManifest, __in_opt WIX_LOCALIZATION* pWixLoc ) { HRESULT hr = S_OK; IXMLDOMNodeList* pNodeList = NULL; IXMLDOMNode* pNode = NULL; BAL_CONDITION* prgConditions = NULL; DWORD cConditions = 0; hr = XmlSelectNodes(pixdManifest, L"/BootstrapperApplicationData/WixBalCondition", &pNodeList); ExitOnFailure(hr, "Failed to select all conditions."); hr = pNodeList->get_length(reinterpret_cast<long*>(&cConditions)); ExitOnFailure(hr, "Failed to get the condition count."); if (!cConditions) { ExitFunction(); } prgConditions = static_cast<BAL_CONDITION*>(MemAlloc(sizeof(BAL_CONDITION) * cConditions, TRUE)); ExitOnNull(prgConditions, hr, E_OUTOFMEMORY, "Failed to allocate memory for conditions."); DWORD iCondition = 0; while (S_OK == (hr = XmlNextElement(pNodeList, &pNode, NULL))) { hr = XmlGetAttributeEx(pNode, L"Condition", &prgConditions[iCondition].sczCondition); ExitOnFailure(hr, "Failed to get condition for condition."); hr = XmlGetAttributeEx(pNode, L"Message", &prgConditions[iCondition].sczMessage); ExitOnFailure(hr, "Failed to get message for condition."); if (pWixLoc && prgConditions[iCondition].sczMessage && *prgConditions[iCondition].sczMessage) { hr = LocLocalizeString(pWixLoc, &prgConditions[iCondition].sczMessage); ExitOnFailure(hr, "Failed to localize condition message."); } ++iCondition; ReleaseNullObject(pNode); } ExitOnFailure(hr, "Failed to parse all condition elements."); if (S_FALSE == hr) { hr = S_OK; } pConditions->cConditions = cConditions; pConditions->rgConditions = prgConditions; prgConditions = NULL; LExit: ReleaseMem(prgConditions); ReleaseObject(pNode); ReleaseObject(pNodeList); return hr; }
HRESULT CpiApplicationRolesVerifyInstall( CPI_APPLICATION_ROLE_LIST* pList ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; ICatalogObject* piRoleObj = NULL; for (CPI_APPLICATION_ROLE* pItm = pList->pFirst; pItm; pItm = pItm->pNext) { // referenced locaters or roles that are being installed if (!pItm->fReferencedForInstall && !(pItm->fHasComponent && WcaIsInstalling(pItm->isInstalled, pItm->isAction))) continue; // if the role is referensed and is not a locater, it must be installed if (pItm->fReferencedForInstall && pItm->fHasComponent && !CpiWillBeInstalled(pItm->isInstalled, pItm->isAction)) MessageExitOnFailure1(hr = E_FAIL, msierrComPlusApplicationRoleDependency, "An application role is used by another entity being installed, but is not installed itself, key: %S", pItm->wzKey); // role is a locater if (!pItm->fHasComponent) { // get collection object for role hr = FindObjectForApplicationRole(pItm, &piRoleObj); ExitOnFailure(hr, "Failed to find collection object for role"); // if the role was not found if (S_FALSE == hr) MessageExitOnFailure1(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), msierrComPlusApplicationRoleNotFound, "An application role required by this installation was not found, key: %S", pItm->wzKey); } // role is supposed to be created else if (!CpiIsInstalled(pItm->isInstalled)) { do { // find roles with conflicting name or id hr = FindObjectForApplicationRole(pItm, NULL); ExitOnFailure(hr, "Failed to find collection object for role"); if (S_OK == hr) { er = WcaErrorMessage(msierrComPlusApplicationRoleConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); switch (er) { case IDABORT: ExitOnFailure1(hr = E_FAIL, "An application with a conflictiong name exists, key: %S", pItm->wzKey); break; case IDRETRY: break; case IDIGNORE: default: hr = S_FALSE; // indicate that this is not a conflict } } } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts } // clean up ReleaseNullObject(piRoleObj); } hr = S_OK; LExit: // clean up ReleaseObject(piRoleObj); return hr; }
HRESULT CpiFindCollectionObject( ICatalogCollection* piColl, LPCWSTR pwzID, LPCWSTR pwzName, ICatalogObject** ppiObj ) { HRESULT hr = S_OK; IDispatch* piDisp = NULL; ICatalogObject* piObj = NULL; VARIANT vtVal; ::VariantInit(&vtVal); long lCnt; hr = piColl->get_Count(&lCnt); ExitOnFailure(hr, "Failed to get to number of items in collection"); for (long i = 0; i < lCnt; i++) { // get ICatalogObject interface hr = piColl->get_Item(i, &piDisp); ExitOnFailure(hr, "Failed to get object from collection"); hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj); ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface"); // compare id if (pwzID && *pwzID) { hr = piObj->get_Key(&vtVal); ExitOnFailure(hr, "Failed to get key"); hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR); ExitOnFailure(hr, "Failed to change variant type"); if (0 == lstrcmpiW(vtVal.bstrVal, pwzID)) { if (ppiObj) { *ppiObj = piObj; piObj = NULL; } ExitFunction1(hr = S_OK); } ::VariantClear(&vtVal); } // compare name if (pwzName && *pwzName) { hr = piObj->get_Name(&vtVal); ExitOnFailure(hr, "Failed to get name"); hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR); ExitOnFailure(hr, "Failed to change variant type"); if (0 == lstrcmpW(vtVal.bstrVal, pwzName)) { if (ppiObj) { *ppiObj = piObj; piObj = NULL; } ExitFunction1(hr = S_OK); } ::VariantClear(&vtVal); } // release interface pointers ReleaseNullObject(piDisp); ReleaseNullObject(piObj); } hr = S_FALSE; LExit: // clean up ReleaseObject(piDisp); ReleaseObject(piObj); ::VariantClear(&vtVal); return hr; }
HRESULT CpiPartitionsVerifyInstall( CPI_PARTITION_LIST* pList ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; ICatalogCollection* piPartColl = NULL; ICatalogObject* piPartObj = NULL; for (CPI_PARTITION* pItm = pList->pFirst; pItm; pItm = pItm->pNext) { // referenced locaters or partitions that are being installed if (!pItm->fReferencedForInstall && !(pItm->fHasComponent && WcaIsInstalling(pItm->isInstalled, pItm->isAction))) continue; // if the partition is referensed and is not a locater, it must be installed if (pItm->fReferencedForInstall && pItm->fHasComponent && !CpiWillBeInstalled(pItm->isInstalled, pItm->isAction)) MessageExitOnFailure(hr = E_FAIL, msierrComPlusPartitionDependency, "A partition is used by another entity being installed, but is not installed itself, key: %S", pItm->wzKey); // get partitions collection if (!piPartColl) { hr = CpiGetPartitionsCollection(&piPartColl); ExitOnFailure(hr, "Failed to get partitions collection"); } // partition is supposed to exist if (!pItm->fHasComponent || CpiIsInstalled(pItm->isInstalled)) { // get collection object for partition hr = CpiFindCollectionObject(piPartColl, pItm->wzID, *pItm->wzID ? NULL : pItm->wzName, &piPartObj); ExitOnFailure(hr, "Failed to find collection object for partition"); // if the partition was found if (S_OK == hr) { // if we don't have an id, copy id from object if (!*pItm->wzID) { hr = CpiGetKeyForObject(piPartObj, pItm->wzID, countof(pItm->wzID)); ExitOnFailure(hr, "Failed to get id"); } } // if the partition was not found else { // if the application is a locater, this is an error if (!pItm->fHasComponent) MessageExitOnFailure(hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND), msierrComPlusPartitionNotFound, "A partition required by this installation was not found, key: %S", pItm->wzKey); // create a new id if one is missing if (!*pItm->wzID) { hr = CpiCreateId(pItm->wzID, countof(pItm->wzID)); ExitOnFailure(hr, "Failed to create id"); } } } // partition is supposed to be created else { // check for conflicts do { if (*pItm->wzID) { // find partitions with conflicting id hr = CpiFindCollectionObject(piPartColl, pItm->wzID, NULL, &piPartObj); ExitOnFailure(hr, "Failed to find collection object for partition"); if (S_FALSE == hr) { // find partitions with conflicting name hr = CpiFindCollectionObject(piPartColl, NULL, pItm->wzName, &piPartObj); ExitOnFailure(hr, "Failed to find collection object for partition"); if (S_OK == hr) // "A partition with a conflictiong name exists. retry cancel" er = WcaErrorMessage(msierrComPlusPartitionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_RETRYCANCEL, 0); else break; // no conflicting entry found, break loop } else // "A partition with a conflicting id exists. abort retry ignore" er = WcaErrorMessage(msierrComPlusPartitionIdConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); } else { // find partitions with conflicting name hr = CpiFindCollectionObject(piPartColl, NULL, pItm->wzName, &piPartObj); ExitOnFailure(hr, "Failed to find collection object for partition"); if (S_OK == hr) // "A partition with a conflictiong name exists. abort retry ignore" er = WcaErrorMessage(msierrComPlusPartitionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); else break; // no conflicting entry found, break loop } switch (er) { case IDCANCEL: case IDABORT: ExitOnFailure(hr = E_FAIL, "A partition with a conflictiong name or id exists, key: %S", pItm->wzKey); break; case IDRETRY: break; case IDIGNORE: default: // if we don't have an id, copy id from object if (!*pItm->wzID) { hr = CpiGetKeyForObject(piPartObj, pItm->wzID, countof(pItm->wzID)); ExitOnFailure(hr, "Failed to get id"); } hr = S_FALSE; // indicate that this is not a conflict } } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts // create a new id if one is missing if (!*pItm->wzID) { hr = CpiCreateId(pItm->wzID, countof(pItm->wzID)); ExitOnFailure(hr, "Failed to create id"); } } // clean up ReleaseNullObject(piPartObj); } hr = S_OK; LExit: // clean up ReleaseObject(piPartColl); ReleaseObject(piPartObj); return hr; }
static HRESULT FindUserCollectionObjectIndex( ICatalogCollection* piColl, PSID pSid, int* pi ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; NTSTATUS st = 0; long i = 0; long lCollCnt = 0; LSA_OBJECT_ATTRIBUTES loaAttributes; LSA_HANDLE lsahPolicy = NULL; PLSA_UNICODE_STRING plusNames = NULL; PLSA_REFERENCED_DOMAIN_LIST plrdsDomains = NULL; PLSA_TRANSLATED_SID pltsSids = NULL; IDispatch* piDisp = NULL; ICatalogObject* piObj = NULL; VARIANT vtVal; PSID pTmpSid = NULL; PLSA_TRANSLATED_SID pltsSid; ::VariantInit(&vtVal); ::ZeroMemory(&loaAttributes, sizeof(loaAttributes)); // open policy handle st = ::LsaOpenPolicy(NULL, &loaAttributes, POLICY_ALL_ACCESS, &lsahPolicy); er = ::LsaNtStatusToWinError(st); ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to open policy handle"); // get number of elements in collection hr = piColl->get_Count(&lCollCnt); ExitOnFailure(hr, "Failed to get to number of objects in collection"); if (0 == lCollCnt) ExitFunction1(hr = S_FALSE); // not found // allocate name buffer plusNames = (PLSA_UNICODE_STRING)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LSA_UNICODE_STRING) * lCollCnt); ExitOnNull(plusNames, hr, E_OUTOFMEMORY, "Failed to allocate names buffer"); // get accounts in collection for (i = 0; i < lCollCnt; i++) { // get ICatalogObject interface hr = piColl->get_Item(i, &piDisp); ExitOnFailure(hr, "Failed to get object from collection"); hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj); ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface"); // get value hr = piObj->get_Key(&vtVal); ExitOnFailure(hr, "Failed to get key"); hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR); ExitOnFailure(hr, "Failed to change variant type"); // copy account name string hr = InitLsaUnicodeString(&plusNames[i], vtVal.bstrVal, ::SysStringLen(vtVal.bstrVal)); ExitOnFailure(hr, "Failed to initialize account name string"); // clean up ReleaseNullObject(piDisp); ReleaseNullObject(piObj); ::VariantClear(&vtVal); } // lookup names st = ::LsaLookupNames(lsahPolicy, lCollCnt, plusNames, &plrdsDomains, &pltsSids); er = ::LsaNtStatusToWinError(st); if (ERROR_NONE_MAPPED != er && ERROR_SOME_NOT_MAPPED != er) ExitOnFailure(hr = HRESULT_FROM_WIN32(er), "Failed to lookup account names"); // compare SIDs for (i = 0; i < lCollCnt; i++) { // get SID pltsSid = &pltsSids[i]; if (SidTypeDomain == pltsSid->Use || SidTypeInvalid == pltsSid->Use || SidTypeUnknown == pltsSid->Use) continue; // ignore... hr = CreateSidFromDomainRidPair(plrdsDomains->Domains[pltsSid->DomainIndex].Sid, pltsSid->RelativeId, &pTmpSid); ExitOnFailure(hr, "Failed to convert SID"); // compare SIDs if (::EqualSid(pSid, pTmpSid)) { *pi = i; ExitFunction1(hr = S_OK); } } if (ERROR_NONE_MAPPED == er && ERROR_SOME_NOT_MAPPED == er) hr = HRESULT_FROM_WIN32(er); else hr = S_FALSE; // not found LExit: // clean up ReleaseObject(piDisp); ReleaseObject(piObj); ::VariantClear(&vtVal); if (plusNames) { for (i = 0; i < lCollCnt; i++) FreeLsaUnicodeString(&plusNames[i]); ::HeapFree(::GetProcessHeap(), 0, plusNames); } if (lsahPolicy) ::LsaClose(lsahPolicy); if (plrdsDomains) ::LsaFreeMemory(plrdsDomains); if (pltsSids) ::LsaFreeMemory(pltsSids); if (pTmpSid) ::HeapFree(::GetProcessHeap(), 0, pTmpSid); return hr; }
HRESULT CpiLogCatalogErrorInfo() { HRESULT hr = S_OK; ICOMAdminCatalog* piCatalog = NULL; ICatalogCollection* piErrColl = NULL; IDispatch* piDisp = NULL; ICatalogObject* piObj = NULL; LPWSTR pwzName = NULL; LPWSTR pwzErrorCode = NULL; LPWSTR pwzMajorRef = NULL; LPWSTR pwzMinorRef = NULL; // get catalog hr = CpiGetAdminCatalog(&piCatalog); ExitOnFailure(hr, "Failed to get COM+ admin catalog"); // get error info collection hr = CpiGetCatalogCollection(L"ErrorInfo", &piErrColl); ExitOnFailure(hr, "Failed to get error info collection"); // loop objects long lCnt; hr = piErrColl->get_Count(&lCnt); ExitOnFailure(hr, "Failed to get to number of items in collection"); for (long i = 0; i < lCnt; i++) { // get ICatalogObject interface hr = piErrColl->get_Item(i, &piDisp); ExitOnFailure(hr, "Failed to get item from partitions collection"); hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj); ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface"); // get properties hr = CpiGetCollectionObjectValue(piObj, L"Name", &pwzName); ExitOnFailure(hr, "Failed to get name"); hr = CpiGetCollectionObjectValue(piObj, L"ErrorCode", &pwzErrorCode); ExitOnFailure(hr, "Failed to get error code"); hr = CpiGetCollectionObjectValue(piObj, L"MajorRef", &pwzMajorRef); ExitOnFailure(hr, "Failed to get major ref"); hr = CpiGetCollectionObjectValue(piObj, L"MinorRef", &pwzMinorRef); ExitOnFailure(hr, "Failed to get minor ref"); // write to log WcaLog(LOGMSG_STANDARD, "ErrorInfo: Name='%S', ErrorCode='%S', MajorRef='%S', MinorRef='%S'", pwzName, pwzErrorCode, pwzMajorRef, pwzMinorRef); // clean up ReleaseNullObject(piDisp); ReleaseNullObject(piObj); } hr = S_OK; LExit: // clean up ReleaseObject(piCatalog); ReleaseObject(piErrColl); ReleaseObject(piDisp); ReleaseObject(piObj); ReleaseStr(pwzName); ReleaseStr(pwzErrorCode); ReleaseStr(pwzMajorRef); ReleaseStr(pwzMinorRef); return hr; }
DAPI_(void) BalUninitialize() { ReleaseNullObject(vpEngine); }
/****************************************************************** ExecXmlConfig - entry point for XmlConfig Custom Action *******************************************************************/ extern "C" UINT __stdcall ExecXmlConfig( __in MSIHANDLE hInstall ) { //AssertSz(FALSE, "debug ExecXmlConfig"); HRESULT hr = S_OK; HRESULT hrOpenFailure = S_OK; UINT er = ERROR_SUCCESS; BOOL fIsWow64Process = FALSE; BOOL fIsFSRedirectDisabled = FALSE; BOOL fPreserveDate = FALSE; LPWSTR pwzCustomActionData = NULL; LPWSTR pwzData = NULL; LPWSTR pwzFile = NULL; LPWSTR pwzElementPath = NULL; LPWSTR pwzVerifyPath = NULL; LPWSTR pwzName = NULL; LPWSTR pwzValue = NULL; LPWSTR pwz = NULL; int cAdditionalChanges = 0; IXMLDOMDocument* pixd = NULL; IXMLDOMNode* pixn = NULL; IXMLDOMNode* pixnVerify = NULL; IXMLDOMNode* pixnNewNode = NULL; IXMLDOMNode* pixnRemovedChild = NULL; IXMLDOMDocument* pixdNew = NULL; IXMLDOMElement* pixeNew = NULL; FILETIME ft; int id = IDRETRY; eXmlAction xa; eXmlPreserveDate xd; // initialize hr = WcaInitialize(hInstall, "ExecXmlConfig"); ExitOnFailure(hr, "failed to initialize"); hr = XmlInitialize(); ExitOnFailure(hr, "failed to initialize xml utilities"); hr = WcaGetProperty( L"CustomActionData", &pwzCustomActionData); ExitOnFailure(hr, "failed to get CustomActionData"); WcaLog(LOGMSG_TRACEONLY, "CustomActionData: %ls", pwzCustomActionData); pwz = pwzCustomActionData; hr = WcaReadIntegerFromCaData(&pwz, (int*) &xa); ExitOnFailure(hr, "failed to process CustomActionData"); // Initialize the Wow64 API - store the result in fWow64APIPresent // If it fails, this doesn't warrant an error yet, because we only need the Wow64 API in some cases WcaInitializeWow64(); fIsWow64Process = WcaIsWow64Process(); if (xaOpenFile != xa && xaOpenFilex64 != xa) { ExitOnFailure(hr = E_INVALIDARG, "invalid custom action data"); } // loop through all the passed in data while (pwz && *pwz) { hr = WcaReadStringFromCaData(&pwz, &pwzFile); ExitOnFailure(hr, "failed to read file name from custom action data"); // Default to not preserve date, preserve it if any modifications require us to fPreserveDate = FALSE; // Open the file ReleaseNullObject(pixd); if (xaOpenFilex64 == xa) { if (!fIsWow64Process) { hr = E_NOTIMPL; ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but the custom action process is not running in WOW."); } hr = WcaDisableWow64FSRedirection(); ExitOnFailure(hr, "Custom action was told to act on a 64-bit component, but was unable to disable filesystem redirection through the Wow64 API."); fIsFSRedirectDisabled = TRUE; } hr = XmlLoadDocumentFromFileEx(pwzFile, XML_LOAD_PRESERVE_WHITESPACE, &pixd); if (FAILED(hr)) { // Ignore the return code for now. If they try to add something, we'll fail the install. If all they do is remove stuff then it doesn't matter. hrOpenFailure = hr; hr = S_OK; } else { hrOpenFailure = S_OK; } WcaLog(LOGMSG_VERBOSE, "Configuring Xml File: %ls", pwzFile); while (pwz && *pwz) { // If we skip past an element that has additional changes we need to strip them off the stream before // moving on to the next element. Do that now and then restart the outer loop. if (cAdditionalChanges > 0) { while (cAdditionalChanges > 0) { hr = WcaReadStringFromCaData(&pwz, &pwzName); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzValue); ExitOnFailure(hr, "failed to process CustomActionData"); cAdditionalChanges--; } continue; } hr = WcaReadIntegerFromCaData(&pwz, (int*) &xa); ExitOnFailure(hr, "failed to process CustomActionData"); // Break if we need to move on to a different file if (xaOpenFile == xa || xaOpenFilex64 == xa) { break; } hr = WcaReadIntegerFromCaData(&pwz, (int*) &xd); ExitOnFailure(hr, "failed to process CustomActionData"); if (xdPreserve == xd) { fPreserveDate = TRUE; } // Get path, name, and value to be written hr = WcaReadStringFromCaData(&pwz, &pwzElementPath); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzVerifyPath); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzName); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzValue); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadIntegerFromCaData(&pwz, &cAdditionalChanges); ExitOnFailure(hr, "failed to process CustomActionData"); // If we failed to open the file and we're adding something to the file, we've got a problem. Otherwise, just continue on since the file's already gone. if (FAILED(hrOpenFailure)) { if (xaCreateElement == xa || xaWriteValue == xa || xaWriteDocument == xa) { MessageExitOnFailure1(hr = hrOpenFailure, msierrXmlConfigFailedOpen, "failed to load XML file: %ls", pwzFile); } else { continue; } } // Select the node we're about to modify ReleaseNullObject(pixn); hr = XmlSelectSingleNode(pixd, pwzElementPath, &pixn); // If we failed to find the node that we are going to add to, we've got a problem. Otherwise, just continue since the node's already gone. if (S_FALSE == hr) { if (xaCreateElement == xa || xaWriteValue == xa || xaWriteDocument == xa) { hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND); } else { hr = S_OK; continue; } } MessageExitOnFailure2(hr, msierrXmlConfigFailedSelect, "failed to find node: %ls in XML file: %ls", pwzElementPath, pwzFile); // Make the modification switch (xa) { case xaWriteValue: if (pwzName && *pwzName) { // We're setting an attribute hr = XmlSetAttribute(pixn, pwzName, pwzValue); ExitOnFailure2(hr, "failed to set attribute: %ls to value %ls", pwzName, pwzValue); } else { // We're setting the text of the node hr = XmlSetText(pixn, pwzValue); ExitOnFailure2(hr, "failed to set text to: %ls for element %ls. Make sure that XPath points to an element.", pwzValue, pwzElementPath); } break; case xaWriteDocument: if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0]) { hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify); if (S_OK == hr) { // We found the verify path which means we have no further work to do continue; } ExitOnFailure1(hr, "failed to query verify path: %ls", pwzVerifyPath); } hr = XmlLoadDocumentEx(pwzValue, XML_LOAD_PRESERVE_WHITESPACE, &pixdNew); ExitOnFailure(hr, "Failed to load value as document."); hr = pixdNew->get_documentElement(&pixeNew); ExitOnFailure(hr, "Failed to get document element."); hr = pixn->appendChild(pixeNew, NULL); ExitOnFailure(hr, "Failed to append document element on to parent element."); ReleaseNullObject(pixeNew); ReleaseNullObject(pixdNew); break; case xaCreateElement: if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0]) { hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify); if (S_OK == hr) { // We found the verify path which means we have no further work to do continue; } ExitOnFailure1(hr, "failed to query verify path: %ls", pwzVerifyPath); } hr = XmlCreateChild(pixn, pwzName, &pixnNewNode); ExitOnFailure1(hr, "failed to create child element: %ls", pwzName); if (pwzValue && *pwzValue) { hr = XmlSetText(pixnNewNode, pwzValue); ExitOnFailure2(hr, "failed to set text to: %ls for node: %ls", pwzValue, pwzName); } while (cAdditionalChanges > 0) { hr = WcaReadStringFromCaData(&pwz, &pwzName); ExitOnFailure(hr, "failed to process CustomActionData"); hr = WcaReadStringFromCaData(&pwz, &pwzValue); ExitOnFailure(hr, "failed to process CustomActionData"); // Set the additional attribute hr = XmlSetAttribute(pixnNewNode, pwzName, pwzValue); ExitOnFailure2(hr, "failed to set attribute: %ls to value %ls", pwzName, pwzValue); cAdditionalChanges--; } ReleaseNullObject(pixnNewNode); break; case xaDeleteValue: if (pwzName && *pwzName) { // Delete the attribute hr = XmlRemoveAttribute(pixn, pwzName); ExitOnFailure1(hr, "failed to remove attribute: %ls", pwzName); } else { // Clear the text value for the node hr = XmlSetText(pixn, L""); ExitOnFailure(hr, "failed to clear text value"); } break; case xaDeleteElement: if (NULL != pwzVerifyPath && 0 != pwzVerifyPath[0]) { hr = XmlSelectSingleNode(pixn, pwzVerifyPath, &pixnVerify); if (S_OK == hr) { hr = pixn->removeChild(pixnVerify, &pixnRemovedChild); ExitOnFailure(hr, "failed to remove created child element"); ReleaseNullObject(pixnRemovedChild); } else { WcaLog(LOGMSG_VERBOSE, "Failed to select path %ls for deleting. Skipping...", pwzVerifyPath); hr = S_OK; } } else { // TODO: This requires a VerifyPath to delete an element. Should we support not having one? WcaLog(LOGMSG_VERBOSE, "No VerifyPath specified for delete element of ID: %ls", pwzElementPath); } break; default: ExitOnFailure(hr = E_UNEXPECTED, "Invalid modification specified in custom action data"); break; } } // Now that we've made all of the changes to this file, save it and move on to the next if (S_OK == hrOpenFailure) { if (fPreserveDate) { hr = FileGetTime(pwzFile, NULL, NULL, &ft); ExitOnFailure1(hr, "failed to get modified time of file : %ls", pwzFile); } int iSaveAttempt = 0; do { hr = XmlSaveDocument(pixd, pwzFile); if (FAILED(hr)) { id = WcaErrorMessage(msierrXmlConfigFailedSave, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 1, pwzFile); switch (id) { case IDABORT: ExitOnFailure1(hr, "Failed to save changes to XML file: %ls", pwzFile); case IDRETRY: hr = S_FALSE; // hit me, baby, one more time break; case IDIGNORE: hr = S_OK; // pretend everything is okay and bail break; case 0: // No UI case, MsiProcessMessage returns 0 if (STIERR_SHARING_VIOLATION == hr) { // Only in case of sharing violation do we retry 30 times, once a second. if (iSaveAttempt < 30) { hr = S_FALSE; ++iSaveAttempt; WcaLog(LOGMSG_VERBOSE, "Unable to save changes to XML file: %ls, retry attempt: %x", pwzFile, iSaveAttempt); Sleep(1000); } else { ExitOnFailure1(hr, "Failed to save changes to XML file: %ls", pwzFile); } } break; default: // Unknown error ExitOnFailure1(hr, "Failed to save changes to XML file: %ls", pwzFile); } } } while (S_FALSE == hr); if (fPreserveDate) { hr = FileSetTime(pwzFile, NULL, NULL, &ft); ExitOnFailure1(hr, "failed to set modified time of file : %ls", pwzFile); } if (fIsFSRedirectDisabled) { fIsFSRedirectDisabled = FALSE; WcaRevertWow64FSRedirection(); } } } LExit: // Make sure we revert FS Redirection if necessary before exiting if (fIsFSRedirectDisabled) { fIsFSRedirectDisabled = FALSE; WcaRevertWow64FSRedirection(); } WcaFinalizeWow64(); ReleaseStr(pwzCustomActionData); ReleaseStr(pwzData); ReleaseStr(pwzFile); ReleaseStr(pwzElementPath); ReleaseStr(pwzVerifyPath); ReleaseStr(pwzName); ReleaseStr(pwzValue); ReleaseObject(pixeNew); ReleaseObject(pixdNew); ReleaseObject(pixn); ReleaseObject(pixd); ReleaseObject(pixnNewNode); ReleaseObject(pixnRemovedChild); XmlUninitialize(); if (FAILED(hr)) { er = ERROR_INSTALL_FAILURE; } return WcaFinalize(er); }
HRESULT CpiSubscriptionsVerifyInstall( CPI_SUBSCRIPTION_LIST* pList ) { HRESULT hr = S_OK; UINT er = ERROR_SUCCESS; ICatalogObject* piSubsObj = NULL; for (CPI_SUBSCRIPTION* pItm = pList->pFirst; pItm; pItm = pItm->pNext) { // subscriptions that are being installed if (!WcaIsInstalling(pItm->isInstalled, pItm->isAction)) continue; // subscription is supposed to exist if (CpiIsInstalled(pItm->isInstalled)) { // if we don't have an id if (!*pItm->wzID) { // find subscriptions with conflicting name hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj); ExitOnFailure(hr, "Failed to find collection object for subscription"); // if the subscription was found if (S_OK == hr) { // get id from subscription object hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID)); ExitOnFailure(hr, "Failed to get id"); } // if the subscription was not found else { // create a new id hr = CpiCreateId(pItm->wzID, countof(pItm->wzID)); ExitOnFailure(hr, "Failed to create id"); } } } // subscription is supposed to be created else { // check for conflicts do { if (*pItm->wzID) { // find subscriptions with conflicting id hr = FindObjectForSubscription(pItm, TRUE, FALSE, &piSubsObj); ExitOnFailure(hr, "Failed to find collection object for subscription"); if (S_FALSE == hr) { // find subscriptions with conflicting name hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj); ExitOnFailure(hr, "Failed to find collection object for subscription"); if (S_OK == hr) // "A subscription with a conflictiong name exists. retry cancel" er = WcaErrorMessage(msierrComPlusSubscriptionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_RETRYCANCEL, 0); else break; // no conflicting entry found, break loop } else // "A subscription with a conflicting id exists. abort retry ignore" er = WcaErrorMessage(msierrComPlusSubscriptionIdConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); } else { // find subscriptions with conflicting name hr = FindObjectForSubscription(pItm, FALSE, TRUE, &piSubsObj); ExitOnFailure(hr, "Failed to find collection object for subscription"); if (S_OK == hr) // "A subscription with a conflictiong name exists. abort retry ignore" er = WcaErrorMessage(msierrComPlusSubscriptionNameConflict, hr, INSTALLMESSAGE_ERROR | MB_ABORTRETRYIGNORE, 0); else break; // no conflicting entry found, break loop } switch (er) { case IDCANCEL: case IDABORT: ExitOnFailure1(hr = E_FAIL, "A subscription with a conflictiong name or id exists, key: %S", pItm->wzKey); break; case IDRETRY: break; case IDIGNORE: default: // if we don't have an id, copy id from object if (!*pItm->wzID) { hr = CpiGetKeyForObject(piSubsObj, pItm->wzID, countof(pItm->wzID)); ExitOnFailure(hr, "Failed to get id"); } hr = S_FALSE; // indicate that this is not a conflict } } while (S_OK == hr); // hr = S_FALSE if we don't have any conflicts // create a new id if one is missing if (!*pItm->wzID) { hr = CpiCreateId(pItm->wzID, countof(pItm->wzID)); ExitOnFailure(hr, "Failed to create id"); } } // clean up ReleaseNullObject(piSubsObj); } hr = S_OK; LExit: // clean up ReleaseObject(piSubsObj); return hr; }
extern "C" HRESULT ApprovedExesParseFromXml( __in BURN_APPROVED_EXES* pApprovedExes, __in IXMLDOMNode* pixnBundle ) { HRESULT hr = S_OK; IXMLDOMNodeList* pixnNodes = NULL; IXMLDOMNode* pixnNode = NULL; DWORD cNodes = 0; LPWSTR scz = NULL; // select approved exe nodes hr = XmlSelectNodes(pixnBundle, L"ApprovedExeForElevation", &pixnNodes); ExitOnFailure(hr, "Failed to select approved exe nodes."); // get approved exe node count hr = pixnNodes->get_length((long*)&cNodes); ExitOnFailure(hr, "Failed to get approved exe node count."); if (!cNodes) { ExitFunction(); } // allocate memory for approved exes pApprovedExes->rgApprovedExes = (BURN_APPROVED_EXE*)MemAlloc(sizeof(BURN_APPROVED_EXE) * cNodes, TRUE); ExitOnNull(pApprovedExes->rgApprovedExes, hr, E_OUTOFMEMORY, "Failed to allocate memory for approved exe structs."); pApprovedExes->cApprovedExes = cNodes; // parse approved exe elements for (DWORD i = 0; i < cNodes; ++i) { BURN_APPROVED_EXE* pApprovedExe = &pApprovedExes->rgApprovedExes[i]; hr = XmlNextElement(pixnNodes, &pixnNode, NULL); ExitOnFailure(hr, "Failed to get next node."); // @Id hr = XmlGetAttributeEx(pixnNode, L"Id", &pApprovedExe->sczId); ExitOnFailure(hr, "Failed to get @Id."); // @Key hr = XmlGetAttributeEx(pixnNode, L"Key", &pApprovedExe->sczKey); ExitOnFailure(hr, "Failed to get @Key."); // @ValueName hr = XmlGetAttributeEx(pixnNode, L"ValueName", &pApprovedExe->sczValueName); if (E_NOTFOUND != hr) { ExitOnFailure(hr, "Failed to get @ValueName."); } // @Win64 hr = XmlGetYesNoAttribute(pixnNode, L"Win64", &pApprovedExe->fWin64); if (E_NOTFOUND != hr) { ExitOnFailure(hr, "Failed to get @Win64."); } // prepare next iteration ReleaseNullObject(pixnNode); ReleaseNullStr(scz); } hr = S_OK; LExit: ReleaseObject(pixnNodes); ReleaseObject(pixnNode); ReleaseStr(scz); return hr; }
extern "C" HRESULT PayloadsParseFromXml( __in BURN_PAYLOADS* pPayloads, __in_opt BURN_CONTAINERS* pContainers, __in_opt BURN_CATALOGS* pCatalogs, __in IXMLDOMNode* pixnBundle ) { HRESULT hr = S_OK; IXMLDOMNodeList* pixnNodes = NULL; IXMLDOMNode* pixnNode = NULL; DWORD cNodes = 0; LPWSTR scz = NULL; // select payload nodes hr = XmlSelectNodes(pixnBundle, L"Payload", &pixnNodes); ExitOnFailure(hr, "Failed to select payload nodes."); // get payload node count hr = pixnNodes->get_length((long*)&cNodes); ExitOnFailure(hr, "Failed to get payload node count."); if (!cNodes) { ExitFunction(); } // allocate memory for payloads pPayloads->rgPayloads = (BURN_PAYLOAD*)MemAlloc(sizeof(BURN_PAYLOAD) * cNodes, TRUE); ExitOnNull(pPayloads->rgPayloads, hr, E_OUTOFMEMORY, "Failed to allocate memory for payload structs."); pPayloads->cPayloads = cNodes; // parse search elements for (DWORD i = 0; i < cNodes; ++i) { BURN_PAYLOAD* pPayload = &pPayloads->rgPayloads[i]; hr = XmlNextElement(pixnNodes, &pixnNode, NULL); ExitOnFailure(hr, "Failed to get next node."); // @Id hr = XmlGetAttributeEx(pixnNode, L"Id", &pPayload->sczKey); ExitOnFailure(hr, "Failed to get @Id."); // @FilePath hr = XmlGetAttributeEx(pixnNode, L"FilePath", &pPayload->sczFilePath); ExitOnFailure(hr, "Failed to get @FilePath."); // @Packaging hr = XmlGetAttributeEx(pixnNode, L"Packaging", &scz); ExitOnFailure(hr, "Failed to get @Packaging."); if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"download", -1)) { pPayload->packaging = BURN_PAYLOAD_PACKAGING_DOWNLOAD; } else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"embedded", -1)) { pPayload->packaging = BURN_PAYLOAD_PACKAGING_EMBEDDED; } else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"external", -1)) { pPayload->packaging = BURN_PAYLOAD_PACKAGING_EXTERNAL; } else { hr = E_INVALIDARG; ExitOnFailure(hr, "Invalid value for @Packaging: %ls", scz); } // @Container if (pContainers) { hr = XmlGetAttributeEx(pixnNode, L"Container", &scz); if (E_NOTFOUND != hr || BURN_PAYLOAD_PACKAGING_EMBEDDED == pPayload->packaging) { ExitOnFailure(hr, "Failed to get @Container."); // find container hr = ContainerFindById(pContainers, scz, &pPayload->pContainer); ExitOnFailure(hr, "Failed to to find container: %ls", scz); } } // @LayoutOnly hr = XmlGetYesNoAttribute(pixnNode, L"LayoutOnly", &pPayload->fLayoutOnly); if (E_NOTFOUND != hr) { ExitOnFailure(hr, "Failed to get @LayoutOnly."); } // @SourcePath hr = XmlGetAttributeEx(pixnNode, L"SourcePath", &pPayload->sczSourcePath); if (E_NOTFOUND != hr || BURN_PAYLOAD_PACKAGING_DOWNLOAD != pPayload->packaging) { ExitOnFailure(hr, "Failed to get @SourcePath."); } // @DownloadUrl hr = XmlGetAttributeEx(pixnNode, L"DownloadUrl", &pPayload->downloadSource.sczUrl); if (E_NOTFOUND != hr || BURN_PAYLOAD_PACKAGING_DOWNLOAD == pPayload->packaging) { ExitOnFailure(hr, "Failed to get @DownloadUrl."); } // @FileSize hr = XmlGetAttributeEx(pixnNode, L"FileSize", &scz); if (E_NOTFOUND != hr) { ExitOnFailure(hr, "Failed to get @FileSize."); hr = StrStringToUInt64(scz, 0, &pPayload->qwFileSize); ExitOnFailure(hr, "Failed to parse @FileSize."); } // @CertificateAuthorityKeyIdentifier hr = XmlGetAttributeEx(pixnNode, L"CertificateRootPublicKeyIdentifier", &scz); if (E_NOTFOUND != hr) { ExitOnFailure(hr, "Failed to get @CertificateRootPublicKeyIdentifier."); hr = StrAllocHexDecode(scz, &pPayload->pbCertificateRootPublicKeyIdentifier, &pPayload->cbCertificateRootPublicKeyIdentifier); ExitOnFailure(hr, "Failed to hex decode @CertificateRootPublicKeyIdentifier."); } // @CertificateThumbprint hr = XmlGetAttributeEx(pixnNode, L"CertificateRootThumbprint", &scz); if (E_NOTFOUND != hr) { ExitOnFailure(hr, "Failed to get @CertificateRootThumbprint."); hr = StrAllocHexDecode(scz, &pPayload->pbCertificateRootThumbprint, &pPayload->cbCertificateRootThumbprint); ExitOnFailure(hr, "Failed to hex decode @CertificateRootThumbprint."); } // @Hash hr = XmlGetAttributeEx(pixnNode, L"Hash", &scz); ExitOnFailure(hr, "Failed to get @Hash."); hr = StrAllocHexDecode(scz, &pPayload->pbHash, &pPayload->cbHash); ExitOnFailure(hr, "Failed to hex decode the Payload/@Hash."); // @Catalog hr = XmlGetAttributeEx(pixnNode, L"Catalog", &scz); if (E_NOTFOUND != hr) { ExitOnFailure(hr, "Failed to get @Catalog."); hr = CatalogFindById(pCatalogs, scz, &pPayload->pCatalog); ExitOnFailure(hr, "Failed to find catalog."); } // prepare next iteration ReleaseNullObject(pixnNode); } hr = S_OK; LExit: ReleaseObject(pixnNodes); ReleaseObject(pixnNode); ReleaseStr(scz); return hr; }
extern "C" HRESULT ExeEngineParsePackageFromXml( __in IXMLDOMNode* pixnExePackage, __in BURN_PACKAGE* pPackage ) { HRESULT hr = S_OK; IXMLDOMNodeList* pixnNodes = NULL; IXMLDOMNode* pixnNode = NULL; DWORD cNodes = 0; LPWSTR scz = NULL; // @DetectCondition hr = XmlGetAttributeEx(pixnExePackage, L"DetectCondition", &pPackage->Exe.sczDetectCondition); ExitOnFailure(hr, "Failed to get @DetectCondition."); // @InstallArguments hr = XmlGetAttributeEx(pixnExePackage, L"InstallArguments", &pPackage->Exe.sczInstallArguments); ExitOnFailure(hr, "Failed to get @InstallArguments."); // @UninstallArguments hr = XmlGetAttributeEx(pixnExePackage, L"UninstallArguments", &pPackage->Exe.sczUninstallArguments); ExitOnFailure(hr, "Failed to get @UninstallArguments."); // @RepairArguments hr = XmlGetAttributeEx(pixnExePackage, L"RepairArguments", &pPackage->Exe.sczRepairArguments); ExitOnFailure(hr, "Failed to get @RepairArguments."); // @Repairable hr = XmlGetYesNoAttribute(pixnExePackage, L"Repairable", &pPackage->Exe.fRepairable); if (E_NOTFOUND != hr) { ExitOnFailure(hr, "Failed to get @Repairable."); } // @Protocol hr = XmlGetAttributeEx(pixnExePackage, L"Protocol", &scz); if (SUCCEEDED(hr)) { if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"burn", -1)) { pPackage->Exe.protocol = BURN_EXE_PROTOCOL_TYPE_BURN; } else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"netfx4", -1)) { pPackage->Exe.protocol = BURN_EXE_PROTOCOL_TYPE_NETFX4; } else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"none", -1)) { pPackage->Exe.protocol = BURN_EXE_PROTOCOL_TYPE_NONE; } else { hr = E_UNEXPECTED; ExitOnFailure1(hr, "Invalid protocol type: %ls", scz); } } else if (E_NOTFOUND != hr) { ExitOnFailure(hr, "Failed to get @Protocol."); } // select exit code nodes hr = XmlSelectNodes(pixnExePackage, L"ExitCode", &pixnNodes); ExitOnFailure(hr, "Failed to select exit code nodes."); // get exit code node count hr = pixnNodes->get_length((long*)&cNodes); ExitOnFailure(hr, "Failed to get exit code node count."); if (cNodes) { // allocate memory for exit codes pPackage->Exe.rgExitCodes = (BURN_EXE_EXIT_CODE*)MemAlloc(sizeof(BURN_EXE_EXIT_CODE) * cNodes, TRUE); ExitOnNull(pPackage->Exe.rgExitCodes, hr, E_OUTOFMEMORY, "Failed to allocate memory for exit code structs."); pPackage->Exe.cExitCodes = cNodes; // parse package elements for (DWORD i = 0; i < cNodes; ++i) { BURN_EXE_EXIT_CODE* pExitCode = &pPackage->Exe.rgExitCodes[i]; hr = XmlNextElement(pixnNodes, &pixnNode, NULL); ExitOnFailure(hr, "Failed to get next node."); // @Type hr = XmlGetAttributeEx(pixnNode, L"Type", &scz); ExitOnFailure(hr, "Failed to get @Type."); if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"success", -1)) { pExitCode->type = BURN_EXE_EXIT_CODE_TYPE_SUCCESS; } else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"error", -1)) { pExitCode->type = BURN_EXE_EXIT_CODE_TYPE_ERROR; } else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"scheduleReboot", -1)) { pExitCode->type = BURN_EXE_EXIT_CODE_TYPE_SCHEDULE_REBOOT; } else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"forceReboot", -1)) { pExitCode->type = BURN_EXE_EXIT_CODE_TYPE_FORCE_REBOOT; } else { hr = E_UNEXPECTED; ExitOnFailure1(hr, "Invalid exit code type: %ls", scz); } // @Code hr = XmlGetAttributeEx(pixnNode, L"Code", &scz); ExitOnFailure(hr, "Failed to get @Code."); if (L'*' == scz[0]) { pExitCode->fWildcard = TRUE; } else { hr = StrStringToUInt32(scz, 0, (UINT*)&pExitCode->dwCode); ExitOnFailure1(hr, "Failed to parse @Code value: %ls", scz); } // prepare next iteration ReleaseNullObject(pixnNode); } } hr = S_OK; LExit: ReleaseObject(pixnNodes); ReleaseObject(pixnNode); ReleaseStr(scz); return hr; }
HRESULT CpiRemoveCollectionObject( ICatalogCollection* piColl, LPCWSTR pwzID, LPCWSTR pwzName, BOOL fResetDeleteable ) { HRESULT hr = S_OK; IDispatch* piDisp = NULL; ICatalogObject* piObj = NULL; BOOL fMatch = FALSE; VARIANT vtVal; ::VariantInit(&vtVal); long lCnt; hr = piColl->get_Count(&lCnt); ExitOnFailure(hr, "Failed to get to number of items in collection"); for (long i = 0; i < lCnt; i++) { // get ICatalogObject interface hr = piColl->get_Item(i, &piDisp); ExitOnFailure(hr, "Failed to get object from collection"); hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj); ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface"); // compare id if (pwzID && *pwzID) { hr = piObj->get_Key(&vtVal); ExitOnFailure(hr, "Failed to get key"); hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR); ExitOnFailure(hr, "Failed to change variant type"); if (0 == lstrcmpiW(vtVal.bstrVal, pwzID)) fMatch = TRUE; ::VariantClear(&vtVal); } // compare name if (pwzName && *pwzName) { hr = piObj->get_Name(&vtVal); ExitOnFailure(hr, "Failed to get name"); hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_BSTR); ExitOnFailure(hr, "Failed to change variant type"); if (0 == lstrcmpW(vtVal.bstrVal, pwzName)) fMatch = TRUE; ::VariantClear(&vtVal); } // if it's a match, remove it if (fMatch) { if (fResetDeleteable) { // reset deleteable property, if set hr = CpiResetObjectProperty(piColl, piObj, L"Deleteable"); ExitOnFailure(hr, "Failed to reset deleteable property"); } hr = piColl->Remove(i); ExitOnFailure(hr, "Failed to remove item from collection"); break; } // release interface pointers ReleaseNullObject(piDisp); ReleaseNullObject(piObj); } hr = S_OK; LExit: // clean up ReleaseObject(piDisp); ReleaseObject(piObj); ::VariantClear(&vtVal); return hr; }
extern "C" HRESULT DependencyParseProvidersFromXml( __in BURN_PACKAGE* pPackage, __in IXMLDOMNode* pixnPackage ) { HRESULT hr = S_OK; IXMLDOMNodeList* pixnNodes = NULL; DWORD cNodes = 0; IXMLDOMNode* pixnNode = NULL; // Select dependency provider nodes. hr = XmlSelectNodes(pixnPackage, L"Provides", &pixnNodes); ExitOnFailure(hr, "Failed to select dependency provider nodes."); // Get dependency provider node count. hr = pixnNodes->get_length((long*)&cNodes); ExitOnFailure(hr, "Failed to get the dependency provider node count."); if (!cNodes) { ExitFunction1(hr = S_OK); } // Allocate memory for dependency provider pointers. pPackage->rgDependencyProviders = (BURN_DEPENDENCY_PROVIDER*)MemAlloc(sizeof(BURN_DEPENDENCY_PROVIDER) * cNodes, TRUE); ExitOnNull(pPackage->rgDependencyProviders, hr, E_OUTOFMEMORY, "Failed to allocate memory for dependency providers."); pPackage->cDependencyProviders = cNodes; // Parse dependency provider elements. for (DWORD i = 0; i < cNodes; i++) { BURN_DEPENDENCY_PROVIDER* pDependencyProvider = &pPackage->rgDependencyProviders[i]; hr = XmlNextElement(pixnNodes, &pixnNode, NULL); ExitOnFailure(hr, "Failed to get the next dependency provider node."); // @Key hr = XmlGetAttributeEx(pixnNode, L"Key", &pDependencyProvider->sczKey); ExitOnFailure(hr, "Failed to get the Key attribute."); // @Version hr = XmlGetAttributeEx(pixnNode, L"Version", &pDependencyProvider->sczVersion); if (E_NOTFOUND != hr) { ExitOnFailure(hr, "Failed to get the Version attribute."); } // @DisplayName hr = XmlGetAttributeEx(pixnNode, L"DisplayName", &pDependencyProvider->sczDisplayName); if (E_NOTFOUND != hr) { ExitOnFailure(hr, "Failed to get the DisplayName attribute."); } // @Imported hr = XmlGetYesNoAttribute(pixnNode, L"Imported", &pDependencyProvider->fImported); if (E_NOTFOUND != hr) { ExitOnFailure(hr, "Failed to get the Imported attribute."); } else { pDependencyProvider->fImported = FALSE; hr = S_OK; } // Prepare next iteration. ReleaseNullObject(pixnNode); } hr = S_OK; LExit: ReleaseObject(pixnNode); ReleaseObject(pixnNodes); return hr; }
HRESULT CpiFindCollectionObjectByIntegerKey( ICatalogCollection* piColl, long lKey, ICatalogObject** ppiObj ) { HRESULT hr = S_OK; IDispatch* piDisp = NULL; ICatalogObject* piObj = NULL; VARIANT vtVal; ::VariantInit(&vtVal); long lCnt; hr = piColl->get_Count(&lCnt); ExitOnFailure(hr, "Failed to get to number of items in collection"); for (long i = 0; i < lCnt; i++) { // get ICatalogObject interface hr = piColl->get_Item(i, &piDisp); ExitOnFailure(hr, "Failed to get object from collection"); hr = piDisp->QueryInterface(IID_ICatalogObject, (void**)&piObj); ExitOnFailure(hr, "Failed to get IID_ICatalogObject interface"); // compare key hr = piObj->get_Key(&vtVal); ExitOnFailure(hr, "Failed to get key"); hr = ::VariantChangeType(&vtVal, &vtVal, 0, VT_I4); ExitOnFailure(hr, "Failed to change variant type"); if (vtVal.lVal == lKey) { if (ppiObj) { *ppiObj = piObj; piObj = NULL; } ExitFunction1(hr = S_OK); } // clean up ReleaseNullObject(piDisp); ReleaseNullObject(piObj); ::VariantClear(&vtVal); } hr = S_FALSE; LExit: // clean up ReleaseObject(piDisp); ReleaseObject(piObj); ::VariantClear(&vtVal); return hr; }
/******************************************************************** SqlGetErrorInfo - gets error information from the last SQL function call NOTE: pbstrErrorSource and pbstrErrorDescription are optional ********************************************************************/ extern "C" HRESULT DAPI SqlGetErrorInfo( __in IUnknown* pObjectWithError, __in REFIID IID_InterfaceWithError, __in DWORD dwLocaleId, __out_opt BSTR* pbstrErrorSource, __out_opt BSTR* pbstrErrorDescription ) { HRESULT hr = S_OK; Assert(pObjectWithError); // interfaces needed to extract error information out ISupportErrorInfo* pISupportErrorInfo = NULL; IErrorInfo* pIErrorInfoAll = NULL; IErrorRecords* pIErrorRecords = NULL; IErrorInfo* pIErrorInfoRecord = NULL; // only ask for error information if the interface supports it. hr = pObjectWithError->QueryInterface(IID_ISupportErrorInfo,(void**)&pISupportErrorInfo); ExitOnFailure(hr, "No error information was found for object."); hr = pISupportErrorInfo->InterfaceSupportsErrorInfo(IID_InterfaceWithError); ExitOnFailure(hr, "InterfaceWithError is not supported for object with error"); // ignore the return of GetErrorInfo it can succeed and return a NULL pointer in pIErrorInfoAll anyway hr = ::GetErrorInfo(0, &pIErrorInfoAll); ExitOnFailure(hr, "failed to get error info"); if (S_OK == hr && pIErrorInfoAll) { // see if it's a valid OLE DB IErrorInfo interface that exposes a list of records hr = pIErrorInfoAll->QueryInterface(IID_IErrorRecords, (void**)&pIErrorRecords); if (SUCCEEDED(hr)) { ULONG cErrors = 0; pIErrorRecords->GetRecordCount(&cErrors); // get the error information for each record for (ULONG i = 0; i < cErrors; ++i) { hr = pIErrorRecords->GetErrorInfo(i, dwLocaleId, &pIErrorInfoRecord); if (SUCCEEDED(hr)) { if (pbstrErrorSource) { pIErrorInfoRecord->GetSource(pbstrErrorSource); } if (pbstrErrorDescription) { pIErrorInfoRecord->GetDescription(pbstrErrorDescription); } ReleaseNullObject(pIErrorInfoRecord); break; // TODO: return more than one error in the future! } } ReleaseNullObject(pIErrorRecords); } else // we have a simple error record { if (pbstrErrorSource) { pIErrorInfoAll->GetSource(pbstrErrorSource); } if (pbstrErrorDescription) { pIErrorInfoAll->GetDescription(pbstrErrorDescription); } } } else { hr = E_NOMOREITEMS; } LExit: ReleaseObject(pIErrorInfoRecord); ReleaseObject(pIErrorRecords); ReleaseObject(pIErrorInfoAll); ReleaseObject(pISupportErrorInfo); return hr; }
HRESULT ScaWebSearch7( __in SCA_WEB7* psw, __deref_out_z_opt LPWSTR* pswWeb, __out_opt BOOL* pfFound ) { HRESULT hr = S_OK; BOOL fInitializedCom = FALSE; BSTR bstrSites = NULL; BSTR bstrAppHostRoot = NULL; IAppHostAdminManager *pAdminMgr = NULL; IAppHostElement *pSites = NULL; IAppHostElementCollection *pCollection = NULL; IAppHostElement *pSite = NULL; if (NULL != pswWeb) { ReleaseNullStr(*pswWeb); } if (NULL != pfFound) { *pfFound = FALSE; } hr = ::CoInitialize(NULL); ExitOnFailure(hr, "Failed to initialize COM"); fInitializedCom = TRUE; hr = CoCreateInstance(__uuidof(AppHostAdminManager), NULL, CLSCTX_INPROC_SERVER, __uuidof(IAppHostAdminManager), reinterpret_cast<void**> (&pAdminMgr)); if (REGDB_E_CLASSNOTREG == hr) { WcaLog(LOGMSG_VERBOSE, "AppHostAdminManager was not registered, cannot find site."); hr = S_OK; ExitFunction(); } ExitOnFailure(hr, "Failed to CoCreate IAppHostAdminManager"); bstrSites = ::SysAllocString(IIS_CONFIG_SITES_SECTION); ExitOnNull(bstrSites, hr, E_OUTOFMEMORY, "Failed to allocate sites string."); bstrAppHostRoot = ::SysAllocString(IIS_CONFIG_APPHOST_ROOT); ExitOnNull(bstrAppHostRoot, hr, E_OUTOFMEMORY, "Failed to allocate host root string."); hr = pAdminMgr->GetAdminSection(bstrSites, bstrAppHostRoot, &pSites); ExitOnFailure(hr, "Failed get sites section"); ExitOnNull(pSites, hr, ERROR_FILE_NOT_FOUND, "Failed get sites section object"); hr = pSites->get_Collection(&pCollection); ExitOnFailure(hr, "Failed get sites collection"); // not explicitly doing a Description search if (-1 != psw->iSiteId) { if (MSI_NULL_INTEGER == psw->iSiteId) { // Enumerate sites & determine if the binding matches hr = Iis7EnumAppHostElements(pCollection, EnumSiteCompareBinding, psw, &pSite, NULL); ExitOnFailure(hr, "Failed locate site by ID"); } else { // Find a site with ID matches hr = Iis7FindAppHostElementInteger(pCollection, IIS_CONFIG_SITE, IIS_CONFIG_ID, psw->iSiteId, &pSite, NULL); ExitOnFailure(hr, "Failed locate site by ID"); } } if (NULL == pSite) { // Find a site with Name that matches hr = Iis7FindAppHostElementString(pCollection, IIS_CONFIG_SITE, IIS_CONFIG_NAME, psw->wzDescription, &pSite, NULL); ExitOnFailure(hr, "Failed locate site by ID"); } if (NULL != pSite) { if (NULL != pfFound) { *pfFound = TRUE; } if (NULL != pswWeb) { // We found a site, return its description hr = Iis7GetPropertyString(pSite, IIS_CONFIG_NAME, pswWeb); ExitOnFailure(hr, "Failed get site name"); } } LExit: ReleaseNullObject(pAdminMgr); ReleaseNullObject(pSites); ReleaseNullObject(pCollection); ReleaseNullObject(pSite); ReleaseBSTR(bstrAppHostRoot); ReleaseBSTR(bstrSites); if (fInitializedCom) { ::CoUninitialize(); } return hr; }