extern "C" HRESULT MspEngineDetectInitialize( __in BURN_PACKAGES* pPackages ) { AssertSz(pPackages->cPatchInfo, "MspEngineDetectInitialize() should only be called if there are MSP packages."); HRESULT hr = S_OK; POSSIBLE_TARGETPRODUCT* rgPossibleTargetProducts = NULL; DWORD cPossibleTargetProducts = 0; #ifdef DEBUG // All patch info should be initialized to zero. for (DWORD i = 0; i < pPackages->cPatchInfo; ++i) { BURN_PACKAGE* pPackage = pPackages->rgPatchInfoToPackage[i]; Assert(!pPackage->Msp.cTargetProductCodes); Assert(!pPackage->Msp.rgTargetProducts); } #endif // Figure out which product codes to target on the machine. In the worst case all products on the machine // will be returned. hr = GetPossibleTargetProductCodes(pPackages, &rgPossibleTargetProducts, &cPossibleTargetProducts); ExitOnFailure(hr, "Failed to get possible target product codes."); // Loop through possible target products, testing the collective patch applicability against each product in // the appropriate context. Store the result with the appropriate patch package. for (DWORD iSearch = 0; iSearch < cPossibleTargetProducts; ++iSearch) { const POSSIBLE_TARGETPRODUCT* pPossibleTargetProduct = rgPossibleTargetProducts + iSearch; LogId(REPORT_STANDARD, MSG_DETECT_CALCULATE_PATCH_APPLICABILITY, pPossibleTargetProduct->wzProductCode, LoggingMsiInstallContext(pPossibleTargetProduct->context)); if (pPossibleTargetProduct->pszLocalPackage) { // Ignores current machine state to determine just patch applicability. // Superseded and obsolesced patches will be planned separately. hr = WiuDetermineApplicablePatches(pPossibleTargetProduct->pszLocalPackage, pPackages->rgPatchInfo, pPackages->cPatchInfo); } else { hr = WiuDeterminePatchSequence(pPossibleTargetProduct->wzProductCode, NULL, pPossibleTargetProduct->context, pPackages->rgPatchInfo, pPackages->cPatchInfo); } if (SUCCEEDED(hr)) { for (DWORD iPatchInfo = 0; iPatchInfo < pPackages->cPatchInfo; ++iPatchInfo) { if (ERROR_SUCCESS == pPackages->rgPatchInfo[iPatchInfo].uStatus) { BURN_PACKAGE* pMspPackage = pPackages->rgPatchInfoToPackage[iPatchInfo]; Assert(BURN_PACKAGE_TYPE_MSP == pMspPackage->type); // Note that we do add superseded and obsolete MSP packages. Package Detect and Plan will sort them out later. hr = AddDetectedTargetProduct(pPackages, pMspPackage, pPackages->rgPatchInfo[iPatchInfo].dwOrder, pPossibleTargetProduct->wzProductCode, pPossibleTargetProduct->context); ExitOnFailure(hr, "Failed to add target product code to package: %ls", pMspPackage->sczId); } // TODO: should we log something for this error case? } } else { LogId(REPORT_STANDARD, MSG_DETECT_FAILED_CALCULATE_PATCH_APPLICABILITY, pPossibleTargetProduct->wzProductCode, LoggingMsiInstallContext(pPossibleTargetProduct->context), hr); } hr = S_OK; // always reset so we test all possible target products. } LExit: if (rgPossibleTargetProducts) { for (DWORD i = 0; i < cPossibleTargetProducts; ++i) { ReleaseStr(rgPossibleTargetProducts[i].pszLocalPackage); } MemFree(rgPossibleTargetProducts); } return hr; }
extern "C" HRESULT MspEngineDetectInitialize( __in BURN_PACKAGES* pPackages ) { AssertSz(pPackages->cPatchInfo, "MspEngineDetectInitialize() should only be called if there are MSP packages."); static MSIINSTALLCONTEXT rgContexts[] = { MSIINSTALLCONTEXT_USERUNMANAGED, MSIINSTALLCONTEXT_USERMANAGED, MSIINSTALLCONTEXT_MACHINE }; HRESULT hr = S_OK; DWORD iProduct = 0; WCHAR wzProductCode[MAX_GUID_CHARS + 1]; #ifdef DEBUG // All patch info should be initialized to zero. for (DWORD i = 0; i < pPackages->cPatchInfo; ++i) { BURN_PACKAGE* pPackage = pPackages->rgPatchInfoToPackage[i]; Assert(!pPackage->Msp.cTargetProductCodes); Assert(!pPackage->Msp.rgTargetProducts); } #endif // Loop through all products on the machine, testing the collective patch applicability // against each product in all contexts. Store the result with the appropriate patch package. do { hr = WiuEnumProducts(iProduct, wzProductCode); if (SUCCEEDED(hr)) { for (DWORD i = 0; i < countof(rgContexts); ++i) { hr = WiuDeterminePatchSequence(wzProductCode, NULL, rgContexts[i], pPackages->rgPatchInfo, pPackages->cPatchInfo); if (SUCCEEDED(hr)) { for (DWORD iPatchInfo = 0; iPatchInfo < pPackages->cPatchInfo; ++iPatchInfo) { if (ERROR_SUCCESS == pPackages->rgPatchInfo[iPatchInfo].uStatus) { BURN_PACKAGE* pMspPackage = pPackages->rgPatchInfoToPackage[iPatchInfo]; Assert(BURN_PACKAGE_TYPE_MSP == pMspPackage->type); // Note that we do add superseded and obsolete MSP packages. Package Detect and Plan will sort them out later. hr = AddDetectedTargetProduct(pPackages, pMspPackage, rgContexts[i], pPackages->rgPatchInfo[iPatchInfo].dwOrder, wzProductCode); ExitOnFailure1(hr, "Failed to add target product code to package: %ls", pMspPackage->sczId); } // TODO: should we log something for this error case? } } // TODO: should we log something for this error case? } hr = S_OK; // always reset so we test all possible target products. } else if (E_BADCONFIGURATION == hr) { // Skip this product and continue. LogId(REPORT_STANDARD, MSG_DETECT_BAD_PRODUCT_CONFIGURATION, wzProductCode); hr = S_OK; } ++iProduct; } while (SUCCEEDED(hr)); if (E_NOMOREITEMS == hr) { hr = S_OK; } ExitOnFailure(hr, "Failed to test patches applicability against all products on the machine."); LExit: return hr; }