static HRESULT GetPossibleTargetProductCodes( __in BURN_PACKAGES* pPackages, __deref_inout_ecount_opt(*pcPossibleTargetProducts) POSSIBLE_TARGETPRODUCT** prgPossibleTargetProducts, __inout DWORD* pcPossibleTargetProducts ) { HRESULT hr = S_OK; STRINGDICT_HANDLE sdUniquePossibleTargetProductCodes = NULL; BOOL fCheckAll = FALSE; WCHAR wzPossibleTargetProductCode[MAX_GUID_CHARS + 1]; // Use a dictionary to ensure we capture unique product codes. Otherwise, we could end up // doing patch applicability for the same product code multiple times and that would confuse // everything down stream. hr = DictCreateStringList(&sdUniquePossibleTargetProductCodes, 5, DICT_FLAG_NONE); ExitOnFailure(hr, "Failed to create unique target product codes."); // If the patches target a specific set of product/upgrade codes, search only those. This // should be much faster than searching all packages on the machine. if (pPackages->rgPatchTargetCodes) { for (DWORD i = 0; i < pPackages->cPatchTargetCodes; ++i) { BURN_PATCH_TARGETCODE* pTargetCode = pPackages->rgPatchTargetCodes + i; // If targeting a product, add the unique product code to the list. if (BURN_PATCH_TARGETCODE_TYPE_PRODUCT == pTargetCode->type) { hr = AddPossibleTargetProduct(sdUniquePossibleTargetProductCodes, pTargetCode->sczTargetCode, MSIINSTALLCONTEXT_NONE, prgPossibleTargetProducts, pcPossibleTargetProducts); ExitOnFailure(hr, "Failed to add product code to possible target product codes.");
SplitIgnoreDependencies - Splits a semicolon-delimited string into a list of unique dependencies to ignore. *********************************************************************/ static HRESULT SplitIgnoreDependencies( __in_z LPCWSTR wzIgnoreDependencies, __deref_inout_ecount_opt(*pcDependencies) DEPENDENCY** prgDependencies, __inout LPUINT pcDependencies ) { HRESULT hr = S_OK; LPWSTR wzContext = NULL; STRINGDICT_HANDLE sdIgnoreDependencies = NULL; // Create a dictionary to hold unique dependencies. hr = DictCreateStringList(&sdIgnoreDependencies, INITIAL_STRINGDICT_SIZE, DICT_FLAG_CASEINSENSITIVE); ExitOnFailure(hr, "Failed to create the string dictionary."); // Parse through the semicolon-delimited tokens and add to the array. for (LPCWSTR wzToken = ::wcstok_s(const_cast<LPWSTR>(wzIgnoreDependencies), vcszIgnoreDependenciesDelim, &wzContext); wzToken; wzToken = ::wcstok_s(NULL, vcszIgnoreDependenciesDelim, &wzContext)) { hr = DictKeyExists(sdIgnoreDependencies, wzToken); if (E_NOTFOUND != hr) { ExitOnFailure(hr, "Failed to check the dictionary of unique dependencies."); } else { hr = DepDependencyArrayAlloc(prgDependencies, pcDependencies, wzToken, NULL); ExitOnFailure1(hr, "Failed to add \"%ls\" to the list of dependencies to ignore.", wzToken);
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; }