static HRESULT AddDetectedTargetProduct( __in BURN_PACKAGES* pPackages, __in BURN_PACKAGE* pPackage, __in MSIINSTALLCONTEXT context, __in DWORD dwOrder, __in_z LPCWSTR wzProductCode ) { HRESULT hr = S_OK; hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pPackage->Msp.rgTargetProducts), pPackage->Msp.cTargetProductCodes + 1, sizeof(BURN_MSPTARGETPRODUCT), 5); ExitOnFailure(hr, "Failed to ensure enough target product codes were allocated."); hr = ::StringCchCopyW(pPackage->Msp.rgTargetProducts[pPackage->Msp.cTargetProductCodes].wzTargetProductCode, countof(pPackage->Msp.rgTargetProducts[pPackage->Msp.cTargetProductCodes].wzTargetProductCode), wzProductCode); ExitOnFailure(hr, "Failed to copy target product code."); DeterminePatchChainedTarget(pPackages, pPackage, wzProductCode, &pPackage->Msp.rgTargetProducts[pPackage->Msp.cTargetProductCodes].pChainedTargetPackage, &pPackage->Msp.rgTargetProducts[pPackage->Msp.cTargetProductCodes].fSlipstream); pPackage->Msp.rgTargetProducts[pPackage->Msp.cTargetProductCodes].context = context; pPackage->Msp.rgTargetProducts[pPackage->Msp.cTargetProductCodes].dwOrder = dwOrder; ++pPackage->Msp.cTargetProductCodes; LExit: return hr; }
DAPI_(HRESULT) BalInfoAddRelatedBundleAsPackage( __in BAL_INFO_PACKAGES* pPackages, __in LPCWSTR wzId, __in BOOTSTRAPPER_RELATION_TYPE relationType, __in BOOL /*fPerMachine*/ ) { HRESULT hr = S_OK; BAL_INFO_PACKAGE_TYPE type = BAL_INFO_PACKAGE_TYPE_UNKNOWN; BAL_INFO_PACKAGE* pPackage = NULL; // Ensure we have a supported relation type. switch (relationType) { case BOOTSTRAPPER_RELATION_ADDON: type = BAL_INFO_PACKAGE_TYPE_BUNDLE_ADDON; break; case BOOTSTRAPPER_RELATION_PATCH: type = BAL_INFO_PACKAGE_TYPE_BUNDLE_PATCH; break; case BOOTSTRAPPER_RELATION_UPGRADE: type = BAL_INFO_PACKAGE_TYPE_BUNDLE_UPGRADE; break; default: ExitOnFailure1(hr = E_INVALIDARG, "Unknown related bundle type: %u", relationType); } // Check to see if the bundle is already in the list of packages. for (DWORD i = 0; i < pPackages->cPackages; ++i) { if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzId, -1, pPackages->rgPackages[i].sczId, -1)) { ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)); } } // Add the related bundle as a package. hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pPackages->rgPackages), pPackages->cPackages + 1, sizeof(BAL_INFO_PACKAGE), 2); ExitOnFailure(hr, "Failed to allocate memory for related bundle package information."); pPackage = pPackages->rgPackages + pPackages->cPackages; ++pPackages->cPackages; hr = StrAllocString(&pPackage->sczId, wzId, 0); ExitOnFailure(hr, "Failed to copy related bundle package id."); pPackage->type = type; // TODO: try to look up the DisplayName and Description in Add/Remove Programs with the wzId. LExit: return hr; }
static HRESULT EnsureTokenStack( __in JSON_WRITER* pWriter ) { HRESULT hr = S_OK; DWORD cNumAlloc = pWriter->cTokens != 0 ? pWriter->cTokens : 0; hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pWriter->rgTokenStack), cNumAlloc, sizeof(JSON_TOKEN), JSON_STACK_INCREMENT); ExitOnFailure(hr, "Failed to allocate JSON token stack."); if (0 == pWriter->cTokens) { pWriter->rgTokenStack[0] = JSON_TOKEN_NONE; ++pWriter->cTokens; } LExit: return hr; }
HRESULT UtilGrowDatabaseList( __inout BROWSE_DATABASE_LIST *pbdlDatabaseList, __out DWORD *pdwNewIndex ) { HRESULT hr = S_OK; ::EnterCriticalSection(&pbdlDatabaseList->cs); // TODO: make UI thread appropriately enter database list critical section. For now, grow this array by 10 at a time hr = MemEnsureArraySize(reinterpret_cast<void **>(&(pbdlDatabaseList->rgDatabases)), pbdlDatabaseList->cDatabases + 1, sizeof(BROWSE_DATABASE), 10); ExitOnFailure(hr, "Failed to allocate space for one more database struct"); *pdwNewIndex = pbdlDatabaseList->cDatabases; ++(pbdlDatabaseList->cDatabases); ::InitializeCriticalSection(&pbdlDatabaseList->rgDatabases[pbdlDatabaseList->cDatabases-1].cs); ::LeaveCriticalSection(&pbdlDatabaseList->cs); LExit: return hr; }
::FreeLibrary(vhModule); vhModule = NULL; } } static HRESULT RmuApplicationArrayAlloc( __deref_inout_ecount(*pcApplications) RM_UNIQUE_PROCESS **prgApplications, __inout LPUINT pcApplications, __in DWORD dwProcessId, __in FILETIME ProcessStartTime ) { HRESULT hr = S_OK; RM_UNIQUE_PROCESS *pApplication = NULL; hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(prgApplications), *pcApplications + 1, sizeof(RM_UNIQUE_PROCESS), ARRAY_GROWTH_SIZE); ExitOnFailure(hr, "Failed to allocate memory for the application array."); pApplication = static_cast<RM_UNIQUE_PROCESS*>(&(*prgApplications)[*pcApplications]); pApplication->dwProcessId = dwProcessId; pApplication->ProcessStartTime = ProcessStartTime; ++(*pcApplications); LExit: return hr; } static HRESULT RmuApplicationArrayFree( __in RM_UNIQUE_PROCESS *rgApplications )
HRESULT ProductSyncValues( __in CFGDB_STRUCT *pcdb1, __in CFGDB_STRUCT *pcdb2, __in BOOL fAllowLocalToReceiveData, __in STRINGDICT_HANDLE shDictValuesSeen, __out CONFLICT_PRODUCT **ppcpProduct ) { HRESULT hr = S_OK; LPWSTR sczName = NULL; DWORD dwInserting = 0; SCE_QUERY_HANDLE sqhHandle = NULL; SCE_QUERY_RESULTS_HANDLE sqrhResults = NULL; SCE_ROW_HANDLE sceRow = NULL; DWORD dwFoundIndex = 0; DWORD dwSubsumeIndex = 0; BOOL fSame = FALSE; BOOL fFirstIsLocal = (NULL == pcdb1->pcdbLocal); CFG_ENUMERATION * valueHistory1 = NULL; DWORD dwCfgCount1 = 0; CFG_ENUMERATION * valueHistory2 = NULL; DWORD dwCfgCount2 = 0; hr = SceBeginQuery(pcdb1->psceDb, VALUE_INDEX_TABLE, 0, &sqhHandle); ExitOnFailure(hr, "Failed to begin query into value table"); hr = SceSetQueryColumnDword(sqhHandle, pcdb1->dwAppID); ExitOnFailure(hr, "Failed to set query column dword to: %u", pcdb1->dwAppID); hr = SceRunQueryRange(&sqhHandle, &sqrhResults); if (E_NOTFOUND == hr) { ExitFunction1(hr = S_OK); } ExitOnFailure(hr, "Failed to enumerate values for product %u", pcdb1->dwAppID); hr = SceGetNextResultRow(sqrhResults, &sceRow); while (E_NOTFOUND != hr) { ExitOnFailure(hr, "Failed to get next row from query into value table"); CfgReleaseEnumeration(valueHistory1); valueHistory1 = NULL; CfgReleaseEnumeration(valueHistory2); valueHistory2 = NULL; hr = SceGetColumnString(sceRow, VALUE_COMMON_NAME, &sczName); ExitOnFailure(hr, "Failed to get value name"); if (NULL != shDictValuesSeen) { hr = DictKeyExists(shDictValuesSeen, sczName); if (E_NOTFOUND == hr) { hr = DictAddKey(shDictValuesSeen, sczName); ExitOnFailure(hr, "Failed to add to dictionary value: %ls", sczName); } else { ExitOnFailure(hr, "Failed to check if key exists: %ls", sczName); // This value was already synced; skip it! goto Skip; } } // Exclude legacy detect cache values, they should never be synced off the machine // TODO: when we support per-machine settings, migrate this to use that feature if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczName, lstrlenW(wzLegacyDetectCacheValuePrefix), wzLegacyDetectCacheValuePrefix, lstrlenW(wzLegacyDetectCacheValuePrefix))) { goto Skip; } // First check if the values are identical. Even if they were set by different folks at different times, // same value means nothing to sync. hr = ValueMatch(sczName, pcdb1, pcdb2, sceRow, &fSame); ExitOnFailure(hr, "Failed to check if values are identical"); if (fSame) { goto Skip; } // Get history of the value in db2 hr = EnumPastValues(pcdb2, sczName, &valueHistory2, &dwCfgCount2); if (E_NOTFOUND == hr) { hr = S_OK; } ExitOnFailure(hr, "Failed to enumerate previous values in db2"); // Get history of the value in db1 hr = EnumPastValues(pcdb1, sczName, &valueHistory1, &dwCfgCount1); ExitOnFailure(hr, "Found value in db1, but failed to enumerate previous values in db1 while searching for conflicts"); if (0 == dwCfgCount2) { if (fFirstIsLocal || fAllowLocalToReceiveData) { hr = ValueTransferFromHistory(pcdb2, valueHistory1, 0, pcdb1); ExitOnFailure(hr, "Failed to transfer history (due to value not present) from db 2 to db 1 for value %ls", sczName); } goto Skip; } // Don't write anything to db2 if it's local and we're told not to if (fFirstIsLocal || fAllowLocalToReceiveData) { // We first check the latest value. However, if the previous value is identical (same type & value, just different source), check for subsumation of that too. // This reduces unnecessary conflicts in rare corner case scenarios. dwSubsumeIndex = dwCfgCount2; do { --dwSubsumeIndex; // Check if the last history entry for database 2 exists in the database 1 - if it does, database 2's changes are subsumed hr = EnumFindValueInHistory(valueHistory1, dwCfgCount1, valueHistory2->valueHistory.rgcValues + dwSubsumeIndex, &dwFoundIndex); if (S_OK == hr) { // Database 2 is subsumed - pipe over all the newest history entries hr = ValueTransferFromHistory(pcdb2, valueHistory1, dwFoundIndex + 1, pcdb1); ExitOnFailure(hr, "Failed to transfer history (due to history subsumed) from db 1 to db 2 for value %ls", sczName); goto Skip; } else if (E_NOTFOUND == hr) { hr = S_OK; } else { ExitOnFailure(hr, "Failed to check if db2's value history is subsumed by db1's value history"); } if (0 < dwSubsumeIndex) { hr = ValueCompare(valueHistory2->valueHistory.rgcValues + dwSubsumeIndex, valueHistory2->valueHistory.rgcValues + dwSubsumeIndex - 1, FALSE, &fSame); ExitOnFailure(hr, "Failed to check if value and previous value in database 2 are equivalent"); } } while (0 < dwSubsumeIndex && fSame); } // Don't write anything to db1 if it's local and we're told not to if (!fFirstIsLocal || fAllowLocalToReceiveData) { // We first check the latest value. However, if the previous value is identical (same type & value, just different source), check for subsumation of that too. // This reduces unnecessary conflicts in rare corner case scenarios. dwSubsumeIndex = dwCfgCount1; do { --dwSubsumeIndex; hr = EnumFindValueInHistory(valueHistory2, dwCfgCount2, valueHistory1->valueHistory.rgcValues + dwSubsumeIndex, &dwFoundIndex); if (S_OK == hr) { // Database 1 is subsumed - pipe over all the newest history entries hr = ValueTransferFromHistory(pcdb1, valueHistory2, dwFoundIndex + 1, pcdb2); ExitOnFailure(hr, "Failed to transfer history (due to history subsumed) from db 2 to db 1 for value %ls", sczName); goto Skip; } else if (E_NOTFOUND == hr) { hr = S_OK; } else { ExitOnFailure(hr, "Failed to check if db1's value history is subsumed by db2's value history"); } if (0 < dwSubsumeIndex) { hr = ValueCompare(valueHistory1->valueHistory.rgcValues + dwSubsumeIndex, valueHistory1->valueHistory.rgcValues + dwSubsumeIndex - 1, FALSE, &fSame); ExitOnFailure(hr, "Failed to check if value and previous value in database 1 are equivalent"); } } while (0 < dwSubsumeIndex && fSame); } // OK, we have a conflict. Report it. if (NULL == *ppcpProduct) { *ppcpProduct = static_cast<CONFLICT_PRODUCT *>(MemAlloc(sizeof(CONFLICT_PRODUCT), TRUE)); ExitOnNull(*ppcpProduct, hr, E_OUTOFMEMORY, "Failed to allocate product conflict struct"); (*ppcpProduct)->cValues = 1; } else { ++(*ppcpProduct)->cValues; } hr = MemEnsureArraySize(reinterpret_cast<void **>(&(*ppcpProduct)->rgcesValueEnumLocal), (*ppcpProduct)->cValues, sizeof(CFG_ENUMERATION *), 10); ExitOnFailure(hr, "Failed to ensure product local value conflict array size"); hr = MemEnsureArraySize(reinterpret_cast<void **>(&(*ppcpProduct)->rgdwValueCountLocal), (*ppcpProduct)->cValues, sizeof(DWORD), 10); ExitOnFailure(hr, "Failed to ensure product local value conflict count array size"); hr = MemEnsureArraySize(reinterpret_cast<void **>(&(*ppcpProduct)->rgcesValueEnumRemote), (*ppcpProduct)->cValues, sizeof(CFG_ENUMERATION *), 10); ExitOnFailure(hr, "Failed to ensure product remote value conflict array size"); hr = MemEnsureArraySize(reinterpret_cast<void **>(&(*ppcpProduct)->rgdwValueCountRemote), (*ppcpProduct)->cValues, sizeof(DWORD), 10); ExitOnFailure(hr, "Failed to ensure product remote value conflict count array size"); hr = MemEnsureArraySize(reinterpret_cast<void **>(&(*ppcpProduct)->rgrcValueChoices), (*ppcpProduct)->cValues, sizeof(RESOLUTION_CHOICE), 10); ExitOnFailure(hr, "Failed to ensure product value resolution choice array size"); dwInserting = (*ppcpProduct)->cValues - 1; // Neither is subsumed by the other, so we have conflicts - report them if (fFirstIsLocal) { hr = ConflictGetList(reinterpret_cast<const CFG_ENUMERATION *>(valueHistory1), dwCfgCount1, reinterpret_cast<const CFG_ENUMERATION *>(valueHistory2), dwCfgCount2, &((*ppcpProduct)->rgcesValueEnumLocal[dwInserting]), &(*ppcpProduct)->rgdwValueCountLocal[dwInserting], &((*ppcpProduct)->rgcesValueEnumRemote[dwInserting]), &(*ppcpProduct)->rgdwValueCountRemote[dwInserting]); } else { hr = ConflictGetList(reinterpret_cast<const CFG_ENUMERATION *>(valueHistory2), dwCfgCount2, reinterpret_cast<const CFG_ENUMERATION *>(valueHistory1), dwCfgCount1, &((*ppcpProduct)->rgcesValueEnumLocal[dwInserting]), &(*ppcpProduct)->rgdwValueCountLocal[dwInserting], &((*ppcpProduct)->rgcesValueEnumRemote[dwInserting]), &(*ppcpProduct)->rgdwValueCountRemote[dwInserting]); } ExitOnFailure(hr, "Failed to get conflict list"); Skip: ReleaseNullSceRow(sceRow); hr = SceGetNextResultRow(sqrhResults, &sceRow); } hr = S_OK; LExit: ReleaseSceQuery(sqhHandle); ReleaseSceQueryResults(sqrhResults); ReleaseSceRow(sceRow); CfgReleaseEnumeration(valueHistory1); CfgReleaseEnumeration(valueHistory2); ReleaseStr(sczName); return hr; }
HRESULT LegacySyncSetProduct( __in CFGDB_STRUCT *pcdb, __inout LEGACY_SYNC_SESSION *pSyncSession, __in LPCWSTR wzName ) { HRESULT hr = S_OK; LEGACY_SYNC_PRODUCT_SESSION *pSyncProductSession = &pSyncSession->syncProductSession; LEGACY_FILE *pFile = NULL; LEGACY_FILE_SPECIAL *pFileSpecial = NULL; LEGACY_INI_FILE *pIniFile = NULL; CONFIG_VALUE cvManifestContents = { }; CONFIG_VALUE cvManifestConvertedToBlob = { }; SCE_ROW_HANDLE sceManifestValueRow = NULL; LPWSTR sczManifestValueName = NULL; BOOL fWasRegistered = FALSE; BYTE *pbManifestBuffer = NULL; SIZE_T iManifestBuffer = 0; LPWSTR sczBlobManifestAsString = NULL; if (pSyncSession->fInSceTransaction) { SceRollbackTransaction(pcdb->psceDb); pSyncSession->fInSceTransaction = FALSE; } hr = ProductGetLegacyManifestValueName(wzName, &sczManifestValueName); ExitOnFailure(hr, "Failed to get legacy manifest value name"); ManifestFreeProductStruct(&pSyncProductSession->product); ZeroMemory(&pSyncProductSession->product, sizeof(pSyncProductSession->product)); for (DWORD i = 0; i < pSyncProductSession->cIniFiles; ++i) { IniFree(pSyncProductSession->rgIniFiles + i); } ReleaseNullMem(pSyncProductSession->rgIniFiles); pSyncProductSession->cIniFiles = 0; ReleaseNullDict(pSyncProductSession->shDictValuesSeen); ReleaseNullDict(pSyncProductSession->shIniFilesByNamespace); hr = DictCreateStringList(&pSyncProductSession->shDictValuesSeen, 0, DICT_FLAG_CASEINSENSITIVE); ExitOnFailure(hr, "Failed to create dictionary of values seen"); hr = DictCreateWithEmbeddedKey(&pSyncProductSession->shIniFilesByNamespace, 0, reinterpret_cast<void **>(&pSyncProductSession->rgIniFiles), offsetof(LEGACY_INI_FILE, sczNamespace), DICT_FLAG_CASEINSENSITIVE); ExitOnFailure(hr, "Failed to create ini file dictionary"); hr = DictCreateWithEmbeddedKey(&pSyncProductSession->product.detect.shCachedDetectionPropertyValues, offsetof(LEGACY_CACHED_DETECTION_RESULT, sczPropertyName), reinterpret_cast<void **>(&pSyncProductSession->product.detect.rgCachedDetectionProperties), 0, DICT_FLAG_CASEINSENSITIVE); ExitOnFailure(hr, "Failed to create cached detection property values dictionary"); hr = ValueFindRow(pcdb, pcdb->dwCfgAppID, sczManifestValueName, &sceManifestValueRow); ExitOnFailure(hr, "Failed to find config value for legacy manifest (AppID: %u, Config Value named: %ls)", pcdb->dwCfgAppID, sczManifestValueName); hr = ValueRead(pcdb, sceManifestValueRow, &cvManifestContents); ExitOnFailure(hr, "Failed to read manifest contents"); // TODO: someday remove this temporary conversion code when we feel confident nobody has old databases with old manifests laying around if (VALUE_STRING == cvManifestContents.cvType) { LogStringLine(REPORT_STANDARD, "Converting manifest value named %ls from string to blob value", sczManifestValueName); hr = ValueSetBlob(reinterpret_cast<BYTE *>(cvManifestContents.string.sczValue), lstrlenW(cvManifestContents.string.sczValue) * sizeof(WCHAR), FALSE, NULL, pcdb->sczGuid, &cvManifestConvertedToBlob); ExitOnFailure(hr, "Failed to set converted manifest value in memory"); hr = ValueWrite(pcdb, pcdb->dwCfgAppID, sczManifestValueName, &cvManifestConvertedToBlob, TRUE, NULL); ExitOnFailure(hr, "Failed to set converted manifest blob: %ls", sczManifestValueName); ReleaseNullSceRow(sceManifestValueRow); ReleaseNullCfgValue(cvManifestContents); hr = ValueFindRow(pcdb, pcdb->dwCfgAppID, sczManifestValueName, &sceManifestValueRow); ExitOnFailure(hr, "Failed to find config value for legacy manifest after conversion (AppID: %u, Config Value named: %ls)", pcdb->dwCfgAppID, sczManifestValueName); hr = ValueRead(pcdb, sceManifestValueRow, &cvManifestContents); ExitOnFailure(hr, "Failed to read converted manifest contents"); } if (VALUE_BLOB != cvManifestContents.cvType) { hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH); ExitOnFailure(hr, "Stored manifest value was not of type blob"); } if (CFG_BLOB_DB_STREAM != cvManifestContents.blob.cbType) { hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH); ExitOnFailure(hr, "Stored manifest blob was not a database stream"); } hr = StreamRead(pcdb, cvManifestContents.blob.dbstream.dwContentID, NULL, &pbManifestBuffer, &iManifestBuffer); ExitOnFailure(hr, "Failed to get binary content of blob named: %ls, with content ID: %u", sczManifestValueName, pcdb->dwCfgAppID); hr = StrAllocString(&sczBlobManifestAsString, reinterpret_cast<LPWSTR>(pbManifestBuffer), iManifestBuffer / sizeof(WCHAR)); ExitOnFailure(hr, "Failed to add null terminator to manifest blob"); hr = ParseManifest(sczBlobManifestAsString, &pSyncProductSession->product); ExitOnFailure(hr, "Failed to parse manifest"); hr = ProductSet(pcdb, wzName, wzLegacyVersion, wzLegacyPublicKey, FALSE, NULL); ExitOnFailure(hr, "Failed to set product"); hr = ProductIsRegistered(pcdb, pcdb->sczProductName, wzLegacyVersion, wzLegacyPublicKey, &fWasRegistered); ExitOnFailure(hr, "Failed to check if product is registered"); hr = DetectProduct(pcdb, !pSyncSession->fDetect, &pSyncSession->arpProducts, &pSyncSession->exeProducts, pSyncProductSession); ExitOnFailure(hr, "Failed to detect product with AppID: %u", pcdb->dwAppID); // Don't bother writing new registration state data to the database if detect is disabled if (pSyncSession->fDetect) { hr = UpdateProductRegistrationState(pcdb, pSyncProductSession, pcdb->sczProductName, wzLegacyVersion, wzLegacyPublicKey); ExitOnFailure(hr, "Failed to update product registration state"); } hr = ProductIsRegistered(pcdb, pcdb->sczProductName, wzLegacyVersion, wzLegacyPublicKey, &pSyncProductSession->fRegistered); ExitOnFailure(hr, "Failed to check if product is registered"); pSyncProductSession->fNewlyRegistered = (!fWasRegistered && pSyncProductSession->fRegistered); for (DWORD i = 0; i < pSyncProductSession->product.cFiles; ++i) { pFile = pSyncProductSession->product.rgFiles + i; hr = UtilExpandLegacyPath(pFile->sczLocation, &pSyncProductSession->product.detect, &pFile->sczExpandedPath); if (E_NOTFOUND == hr) { hr = S_OK; } if (NULL != pFile->sczExpandedPath) { for (DWORD j = 0; j < pFile->cFileSpecials; ++j) { pFileSpecial = pFile->rgFileSpecials + j; if (0 < pFileSpecial->cIniInfo) { hr = MemEnsureArraySize(reinterpret_cast<void **>(&pSyncProductSession->rgIniFiles), pSyncProductSession->cIniFiles + 1, sizeof(LEGACY_INI_FILE), 5); ExitOnFailure(hr, "Failed to grow active IniFiles array"); pIniFile = pSyncProductSession->rgIniFiles + pSyncProductSession->cIniFiles; hr = IniFileOpen(pFile, pFileSpecial, pFileSpecial->rgIniInfo, pIniFile); ExitOnFailure(hr, "Failed to parse INI file"); hr = DictAddValue(pSyncProductSession->shIniFilesByNamespace, pIniFile); ExitOnFailure(hr, "Failed to add INI file to dict for namespace: %ls", pIniFile->sczNamespace); ++pSyncProductSession->cIniFiles; } } } } // IMPORTANT: Put all legacy database actions into a separate transaction // for each product. In the case of any kind of failure, it's OK to leave // changes written to local machine registry / file system, but not the // legacy database - they'll just appear as local machine changes on next // sync, and everything will be happy. The other way around is NOT happy, // because every sync would create another history entry, ad infinitum! hr = SceBeginTransaction(pcdb->psceDb); ExitOnFailure(hr, "Failed to begin transaction"); pSyncSession->fInSceTransaction = TRUE; LExit: ReleaseSceRow(sceManifestValueRow); ReleaseCfgValue(cvManifestContents); ReleaseCfgValue(cvManifestConvertedToBlob); ReleaseStr(sczManifestValueName); ReleaseMem(pbManifestBuffer); ReleaseStr(sczBlobManifestAsString); return hr; }
static HRESULT PlanTargetProduct( __in BOOTSTRAPPER_DISPLAY display, __in BOOL fRollback, __in BURN_PLAN* pPlan, __in BURN_LOGGING* pLog, __in BURN_VARIABLES* pVariables, __in BOOTSTRAPPER_ACTION_STATE actionState, __in BURN_PACKAGE* pPackage, __in BURN_MSPTARGETPRODUCT* pTargetProduct ) { HRESULT hr = S_OK; BURN_EXECUTE_ACTION* rgActions = fRollback ? pPlan->rgRollbackActions : pPlan->rgExecuteActions; DWORD cActions = fRollback ? pPlan->cRollbackActions : pPlan->cExecuteActions; BURN_EXECUTE_ACTION* pAction = NULL; // Try to find another MSP action with the exact same action (install or uninstall) targeting // the same product in the same machine context (per-user or per-machine). for (DWORD i = 0; i < cActions; ++i) { pAction = rgActions + i; if (BURN_EXECUTE_ACTION_TYPE_MSP_TARGET == pAction->type && pAction->mspTarget.action == actionState && pAction->mspTarget.fPerMachineTarget == (MSIINSTALLCONTEXT_MACHINE == pTargetProduct->context) && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, pAction->mspTarget.sczTargetProductCode, -1, pTargetProduct->wzTargetProductCode, -1)) { break; } pAction = NULL; } // If we didn't find an MSP target action already updating the product, create a new action. if (!pAction) { if (fRollback) { hr = PlanAppendRollbackAction(pPlan, &pAction); } else { hr = PlanAppendExecuteAction(pPlan, &pAction); } ExitOnFailure(hr, "Failed to plan action for target product."); pAction->type = BURN_EXECUTE_ACTION_TYPE_MSP_TARGET; pAction->mspTarget.action = actionState; pAction->mspTarget.pPackage = pPackage; pAction->mspTarget.fPerMachineTarget = (MSIINSTALLCONTEXT_MACHINE == pTargetProduct->context); pAction->mspTarget.uiLevel = MsiEngineCalculateInstallLevel(pPackage->Msp.fDisplayInternalUI, display); pAction->mspTarget.pChainedTargetPackage = pTargetProduct->pChainedTargetPackage; pAction->mspTarget.fSlipstream = pTargetProduct->fSlipstream; hr = StrAllocString(&pAction->mspTarget.sczTargetProductCode, pTargetProduct->wzTargetProductCode, 0); ExitOnFailure(hr, "Failed to copy target product code."); // If this is a per-machine target product, then the plan needs to be per-machine as well. if (pAction->mspTarget.fPerMachineTarget) { pPlan->fPerMachine = TRUE; } LoggingSetPackageVariable(pPackage, pAction->mspTarget.sczTargetProductCode, fRollback, pLog, pVariables, &pAction->mspTarget.sczLogPath); // ignore errors. } // Add our target product to the array and sort based on their order determined during detection. hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pAction->mspTarget.rgOrderedPatches), pAction->mspTarget.cOrderedPatches + 1, sizeof(BURN_ORDERED_PATCHES), 2); ExitOnFailure(hr, "Failed grow array of ordered patches."); pAction->mspTarget.rgOrderedPatches[pAction->mspTarget.cOrderedPatches].dwOrder = pTargetProduct->dwOrder; pAction->mspTarget.rgOrderedPatches[pAction->mspTarget.cOrderedPatches].pPackage = pPackage; ++pAction->mspTarget.cOrderedPatches; // Insertion sort to keep the patches ordered. for (DWORD i = pAction->mspTarget.cOrderedPatches - 1; i > 0; --i) { if (pAction->mspTarget.rgOrderedPatches[i].dwOrder < pAction->mspTarget.rgOrderedPatches[i - 1].dwOrder) { BURN_ORDERED_PATCHES temp = pAction->mspTarget.rgOrderedPatches[i - 1]; pAction->mspTarget.rgOrderedPatches[i - 1] = pAction->mspTarget.rgOrderedPatches[i]; pAction->mspTarget.rgOrderedPatches[i] = temp; } else // no swap necessary, we're done. { break; } } LExit: return hr; }