aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob Arnson <bob@firegiant.com>2022-01-15 21:40:54 -0500
committerBob Arnson <github@bobs.org>2022-01-16 10:28:44 -0500
commit47bca2dc51525fcad86f325278b14953ac5b137e (patch)
tree80a153833efbe0794be7153c64e712a5799649c4
parent6d1c4cc83214b65032251c67239b02da59a3e635 (diff)
downloadwix-47bca2dc51525fcad86f325278b14953ac5b137e.tar.gz
wix-47bca2dc51525fcad86f325278b14953ac5b137e.tar.bz2
wix-47bca2dc51525fcad86f325278b14953ac5b137e.zip
Fix 32/64-bit bitness handling in Burn and BUtil.
- Take advantage of RegOpenEx. - Always look for related bundles in both 32 and 64 hives. - BundleEnumRelatedBundle requires caller to specify bitness.
-rw-r--r--src/burn/engine/elevation.cpp8
-rw-r--r--src/burn/engine/relatedbundle.cpp24
-rw-r--r--src/burn/engine/search.cpp16
-rw-r--r--src/burn/engine/variable.cpp2
-rw-r--r--src/burn/test/BurnUnitTest/RegistrationTest.cpp2
-rw-r--r--src/libs/dutil/WixToolset.DUtil/butil.cpp232
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/butil.h7
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/regutil.h9
-rw-r--r--src/libs/dutil/WixToolset.DUtil/monutil.cpp13
-rw-r--r--src/libs/dutil/WixToolset.DUtil/precomp.h2
-rw-r--r--src/libs/dutil/WixToolset.DUtil/regutil.cpp19
-rw-r--r--src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv1x64/BundleAv1x64.wixproj16
-rw-r--r--src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv1x64/BundleAv1x64.wxs10
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/UpgradeRelatedBundleTests.cs17
14 files changed, 180 insertions, 197 deletions
diff --git a/src/burn/engine/elevation.cpp b/src/burn/engine/elevation.cpp
index 355b4a34..221d8b6d 100644
--- a/src/burn/engine/elevation.cpp
+++ b/src/burn/engine/elevation.cpp
@@ -3299,7 +3299,6 @@ static HRESULT OnLaunchApprovedExe(
3299 SIZE_T iData = 0; 3299 SIZE_T iData = 0;
3300 BURN_LAUNCH_APPROVED_EXE* pLaunchApprovedExe = NULL; 3300 BURN_LAUNCH_APPROVED_EXE* pLaunchApprovedExe = NULL;
3301 BURN_APPROVED_EXE* pApprovedExe = NULL; 3301 BURN_APPROVED_EXE* pApprovedExe = NULL;
3302 REGSAM samDesired = KEY_QUERY_VALUE;
3303 HKEY hKey = NULL; 3302 HKEY hKey = NULL;
3304 DWORD dwProcessId = 0; 3303 DWORD dwProcessId = 0;
3305 BYTE* pbSendData = NULL; 3304 BYTE* pbSendData = NULL;
@@ -3323,12 +3322,7 @@ static HRESULT OnLaunchApprovedExe(
3323 3322
3324 LogId(REPORT_STANDARD, MSG_LAUNCH_APPROVED_EXE_SEARCH, pApprovedExe->sczKey, pApprovedExe->sczValueName ? pApprovedExe->sczValueName : L"", pApprovedExe->fWin64 ? L"yes" : L"no"); 3323 LogId(REPORT_STANDARD, MSG_LAUNCH_APPROVED_EXE_SEARCH, pApprovedExe->sczKey, pApprovedExe->sczValueName ? pApprovedExe->sczValueName : L"", pApprovedExe->fWin64 ? L"yes" : L"no");
3325 3324
3326 if (pApprovedExe->fWin64) 3325 hr = RegOpenEx(HKEY_LOCAL_MACHINE, pApprovedExe->sczKey, KEY_QUERY_VALUE, pApprovedExe->fWin64 ? REG_KEY_64BIT : REG_KEY_32BIT, &hKey);
3327 {
3328 samDesired |= KEY_WOW64_64KEY;
3329 }
3330
3331 hr = RegOpen(HKEY_LOCAL_MACHINE, pApprovedExe->sczKey, samDesired, &hKey);
3332 ExitOnFailure(hr, "Failed to open the registry key for the approved exe path."); 3326 ExitOnFailure(hr, "Failed to open the registry key for the approved exe path.");
3333 3327
3334 hr = RegReadString(hKey, pApprovedExe->sczValueName, &pLaunchApprovedExe->sczExecutablePath); 3328 hr = RegReadString(hKey, pApprovedExe->sczValueName, &pLaunchApprovedExe->sczExecutablePath);
diff --git a/src/burn/engine/relatedbundle.cpp b/src/burn/engine/relatedbundle.cpp
index 99ed8553..619fa8dd 100644
--- a/src/burn/engine/relatedbundle.cpp
+++ b/src/burn/engine/relatedbundle.cpp
@@ -11,13 +11,13 @@ static __callback int __cdecl CompareRelatedBundles(
11); 11);
12static HRESULT InitializeForScopeAndBitness( 12static HRESULT InitializeForScopeAndBitness(
13 __in BOOL fPerMachine, 13 __in BOOL fPerMachine,
14 __in BOOL fWow6432, 14 __in REG_KEY_BITNESS regBitness,
15 __in BURN_REGISTRATION* pRegistration, 15 __in BURN_REGISTRATION* pRegistration,
16 __in BURN_RELATED_BUNDLES* pRelatedBundles 16 __in BURN_RELATED_BUNDLES* pRelatedBundles
17 ); 17 );
18static HRESULT LoadIfRelatedBundle( 18static HRESULT LoadIfRelatedBundle(
19 __in BOOL fPerMachine, 19 __in BOOL fPerMachine,
20 __in BOOL fWow6432, 20 __in REG_KEY_BITNESS regBitness,
21 __in HKEY hkUninstallKey, 21 __in HKEY hkUninstallKey,
22 __in_z LPCWSTR sczRelatedBundleId, 22 __in_z LPCWSTR sczRelatedBundleId,
23 __in BURN_REGISTRATION* pRegistration, 23 __in BURN_REGISTRATION* pRegistration,
@@ -47,13 +47,11 @@ extern "C" HRESULT RelatedBundlesInitializeForScope(
47{ 47{
48 HRESULT hr = S_OK; 48 HRESULT hr = S_OK;
49 49
50 hr = InitializeForScopeAndBitness(fPerMachine, /*fWow6432*/FALSE, pRegistration, pRelatedBundles); 50 hr = InitializeForScopeAndBitness(fPerMachine, REG_KEY_32BIT, pRegistration, pRelatedBundles);
51 ExitOnFailure(hr, "Failed to open platform-native uninstall registry key.");
52
53#if defined(_WIN64)
54 hr = InitializeForScopeAndBitness(fPerMachine, /*fWow6432*/TRUE, pRegistration, pRelatedBundles);
55 ExitOnFailure(hr, "Failed to open 32-bit uninstall registry key."); 51 ExitOnFailure(hr, "Failed to open 32-bit uninstall registry key.");
56#endif 52
53 hr = InitializeForScopeAndBitness(fPerMachine, REG_KEY_64BIT, pRegistration, pRelatedBundles);
54 ExitOnFailure(hr, "Failed to open 64-bit uninstall registry key.");
57 55
58LExit: 56LExit:
59 return hr; 57 return hr;
@@ -170,7 +168,7 @@ static __callback int __cdecl CompareRelatedBundles(
170 168
171static HRESULT InitializeForScopeAndBitness( 169static HRESULT InitializeForScopeAndBitness(
172 __in BOOL fPerMachine, 170 __in BOOL fPerMachine,
173 __in BOOL fWow6432, 171 __in REG_KEY_BITNESS regBitness,
174 __in BURN_REGISTRATION * pRegistration, 172 __in BURN_REGISTRATION * pRegistration,
175 __in BURN_RELATED_BUNDLES * pRelatedBundles 173 __in BURN_RELATED_BUNDLES * pRelatedBundles
176) 174)
@@ -180,7 +178,7 @@ static HRESULT InitializeForScopeAndBitness(
180 HKEY hkUninstallKey = NULL; 178 HKEY hkUninstallKey = NULL;
181 LPWSTR sczRelatedBundleId = NULL; 179 LPWSTR sczRelatedBundleId = NULL;
182 180
183 hr = RegOpen(hkRoot, BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY, KEY_READ | (fWow6432 ? KEY_WOW64_32KEY : 0), &hkUninstallKey); 181 hr = RegOpenEx(hkRoot, BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY, KEY_READ, regBitness, &hkUninstallKey);
184 if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) 182 if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
185 { 183 {
186 ExitFunction1(hr = S_OK); 184 ExitFunction1(hr = S_OK);
@@ -202,7 +200,7 @@ static HRESULT InitializeForScopeAndBitness(
202 { 200 {
203 // Ignore failures here since we'll often find products that aren't actually 201 // Ignore failures here since we'll often find products that aren't actually
204 // related bundles (or even bundles at all). 202 // related bundles (or even bundles at all).
205 HRESULT hrRelatedBundle = LoadIfRelatedBundle(fPerMachine, fWow6432, hkUninstallKey, sczRelatedBundleId, pRegistration, pRelatedBundles); 203 HRESULT hrRelatedBundle = LoadIfRelatedBundle(fPerMachine, regBitness, hkUninstallKey, sczRelatedBundleId, pRegistration, pRelatedBundles);
206 UNREFERENCED_PARAMETER(hrRelatedBundle); 204 UNREFERENCED_PARAMETER(hrRelatedBundle);
207 } 205 }
208 } 206 }
@@ -216,7 +214,7 @@ LExit:
216 214
217static HRESULT LoadIfRelatedBundle( 215static HRESULT LoadIfRelatedBundle(
218 __in BOOL fPerMachine, 216 __in BOOL fPerMachine,
219 __in BOOL fWow6432, 217 __in REG_KEY_BITNESS regBitness,
220 __in HKEY hkUninstallKey, 218 __in HKEY hkUninstallKey,
221 __in_z LPCWSTR sczRelatedBundleId, 219 __in_z LPCWSTR sczRelatedBundleId,
222 __in BURN_REGISTRATION* pRegistration, 220 __in BURN_REGISTRATION* pRegistration,
@@ -227,7 +225,7 @@ static HRESULT LoadIfRelatedBundle(
227 HKEY hkBundleId = NULL; 225 HKEY hkBundleId = NULL;
228 BOOTSTRAPPER_RELATION_TYPE relationType = BOOTSTRAPPER_RELATION_NONE; 226 BOOTSTRAPPER_RELATION_TYPE relationType = BOOTSTRAPPER_RELATION_NONE;
229 227
230 hr = RegOpen(hkUninstallKey, sczRelatedBundleId, KEY_READ | (fWow6432 ? KEY_WOW64_32KEY : 0), &hkBundleId); 228 hr = RegOpenEx(hkUninstallKey, sczRelatedBundleId, KEY_READ, regBitness, &hkBundleId);
231 ExitOnFailure(hr, "Failed to open uninstall key for potential related bundle: %ls", sczRelatedBundleId); 229 ExitOnFailure(hr, "Failed to open uninstall key for potential related bundle: %ls", sczRelatedBundleId);
232 230
233 hr = DetermineRelationType(hkBundleId, pRegistration, &relationType); 231 hr = DetermineRelationType(hkBundleId, pRegistration, &relationType);
diff --git a/src/burn/engine/search.cpp b/src/burn/engine/search.cpp
index 6d5f8d49..4505e1a2 100644
--- a/src/burn/engine/search.cpp
+++ b/src/burn/engine/search.cpp
@@ -836,19 +836,13 @@ static HRESULT RegistrySearchExists(
836 HKEY hKey = NULL; 836 HKEY hKey = NULL;
837 DWORD dwType = 0; 837 DWORD dwType = 0;
838 BOOL fExists = FALSE; 838 BOOL fExists = FALSE;
839 REGSAM samDesired = KEY_QUERY_VALUE;
840
841 if (pSearch->RegistrySearch.fWin64)
842 {
843 samDesired = samDesired | KEY_WOW64_64KEY;
844 }
845 839
846 // format key string 840 // format key string
847 hr = VariableFormatString(pVariables, pSearch->RegistrySearch.sczKey, &sczKey, NULL); 841 hr = VariableFormatString(pVariables, pSearch->RegistrySearch.sczKey, &sczKey, NULL);
848 ExitOnFailure(hr, "Failed to format key string."); 842 ExitOnFailure(hr, "Failed to format key string.");
849 843
850 // open key 844 // open key
851 hr = RegOpen(pSearch->RegistrySearch.hRoot, sczKey, samDesired, &hKey); 845 hr = RegOpenEx(pSearch->RegistrySearch.hRoot, sczKey, KEY_QUERY_VALUE, pSearch->RegistrySearch.fWin64 ? REG_KEY_64BIT : REG_KEY_32BIT, &hKey);
852 if (SUCCEEDED(hr)) 846 if (SUCCEEDED(hr))
853 { 847 {
854 fExists = TRUE; 848 fExists = TRUE;
@@ -922,12 +916,6 @@ static HRESULT RegistrySearchValue(
922 LPBYTE pData = NULL; 916 LPBYTE pData = NULL;
923 DWORD cch = 0; 917 DWORD cch = 0;
924 BURN_VARIANT value = { }; 918 BURN_VARIANT value = { };
925 REGSAM samDesired = KEY_QUERY_VALUE;
926
927 if (pSearch->RegistrySearch.fWin64)
928 {
929 samDesired = samDesired | KEY_WOW64_64KEY;
930 }
931 919
932 // format key string 920 // format key string
933 hr = VariableFormatString(pVariables, pSearch->RegistrySearch.sczKey, &sczKey, NULL); 921 hr = VariableFormatString(pVariables, pSearch->RegistrySearch.sczKey, &sczKey, NULL);
@@ -941,7 +929,7 @@ static HRESULT RegistrySearchValue(
941 } 929 }
942 930
943 // open key 931 // open key
944 hr = RegOpen(pSearch->RegistrySearch.hRoot, sczKey, samDesired, &hKey); 932 hr = RegOpenEx(pSearch->RegistrySearch.hRoot, sczKey, KEY_QUERY_VALUE, pSearch->RegistrySearch.fWin64 ? REG_KEY_64BIT : REG_KEY_32BIT, &hKey);
945 if (E_FILENOTFOUND == hr) 933 if (E_FILENOTFOUND == hr)
946 { 934 {
947 // What if there is a hidden variable in sczKey? 935 // What if there is a hidden variable in sczKey?
diff --git a/src/burn/engine/variable.cpp b/src/burn/engine/variable.cpp
index fa6190dd..b3dcdb7d 100644
--- a/src/burn/engine/variable.cpp
+++ b/src/burn/engine/variable.cpp
@@ -2361,7 +2361,7 @@ static HRESULT Get64bitFolderFromRegistry(
2361 AssertSz(CSIDL_PROGRAM_FILES == nFolder || CSIDL_PROGRAM_FILES_COMMON == nFolder, "Unknown folder CSIDL."); 2361 AssertSz(CSIDL_PROGRAM_FILES == nFolder || CSIDL_PROGRAM_FILES_COMMON == nFolder, "Unknown folder CSIDL.");
2362 LPCWSTR wzFolderValue = CSIDL_PROGRAM_FILES_COMMON == nFolder ? L"CommonFilesDir" : L"ProgramFilesDir"; 2362 LPCWSTR wzFolderValue = CSIDL_PROGRAM_FILES_COMMON == nFolder ? L"CommonFilesDir" : L"ProgramFilesDir";
2363 2363
2364 hr = RegOpen(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion", KEY_READ | KEY_WOW64_64KEY, &hkFolders); 2364 hr = RegOpenEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion", KEY_READ, REG_KEY_64BIT, &hkFolders);
2365 ExitOnFailure(hr, "Failed to open Windows folder key."); 2365 ExitOnFailure(hr, "Failed to open Windows folder key.");
2366 2366
2367 hr = RegReadString(hkFolders, wzFolderValue, psczPath); 2367 hr = RegReadString(hkFolders, wzFolderValue, psczPath);
diff --git a/src/burn/test/BurnUnitTest/RegistrationTest.cpp b/src/burn/test/BurnUnitTest/RegistrationTest.cpp
index dbcd2613..d2ec0a82 100644
--- a/src/burn/test/BurnUnitTest/RegistrationTest.cpp
+++ b/src/burn/test/BurnUnitTest/RegistrationTest.cpp
@@ -645,7 +645,7 @@ namespace Bootstrapper
645 NativeAssert::Succeeded(hr, "Failed to allocate buffer for related bundle id."); 645 NativeAssert::Succeeded(hr, "Failed to allocate buffer for related bundle id.");
646 646
647 // Verify we can find ourself via the UpgradeCode 647 // Verify we can find ourself via the UpgradeCode
648 hr = BundleEnumRelatedBundleFixed(TEST_BUNDLE_UPGRADE_CODE, BUNDLE_INSTALL_CONTEXT_USER, &dwRelatedBundleIndex, sczRelatedBundleId); 648 hr = BundleEnumRelatedBundleFixed(TEST_BUNDLE_UPGRADE_CODE, BUNDLE_INSTALL_CONTEXT_USER, REG_KEY_DEFAULT, &dwRelatedBundleIndex, sczRelatedBundleId);
649 TestThrowOnFailure(hr, L"Failed to enumerate related bundle."); 649 TestThrowOnFailure(hr, L"Failed to enumerate related bundle.");
650 650
651 NativeAssert::StringEqual(TEST_BUNDLE_ID, sczRelatedBundleId); 651 NativeAssert::StringEqual(TEST_BUNDLE_ID, sczRelatedBundleId);
diff --git a/src/libs/dutil/WixToolset.DUtil/butil.cpp b/src/libs/dutil/WixToolset.DUtil/butil.cpp
index 4262d573..2f45da56 100644
--- a/src/libs/dutil/WixToolset.DUtil/butil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/butil.cpp
@@ -63,13 +63,6 @@ static HRESULT CopyStringToBuffer(
63 __in_z_opt LPWSTR wzBuffer, 63 __in_z_opt LPWSTR wzBuffer,
64 __inout SIZE_T* pcchBuffer 64 __inout SIZE_T* pcchBuffer
65 ); 65 );
66static HRESULT DoBundleEnumRelatedBundle(
67 __in HKEY hkRoot,
68 __in REG_KEY_BITNESS kbKeyBitness,
69 __in_z LPCWSTR wzUpgradeCode,
70 __inout PDWORD pdwStartIndex,
71 __deref_out_z LPWSTR* psczBundleId
72 );
73 66
74 67
75DAPI_(HRESULT) BundleGetBundleInfo( 68DAPI_(HRESULT) BundleGetBundleInfo(
@@ -156,11 +149,21 @@ LExit:
156DAPI_(HRESULT) BundleEnumRelatedBundle( 149DAPI_(HRESULT) BundleEnumRelatedBundle(
157 __in_z LPCWSTR wzUpgradeCode, 150 __in_z LPCWSTR wzUpgradeCode,
158 __in BUNDLE_INSTALL_CONTEXT context, 151 __in BUNDLE_INSTALL_CONTEXT context,
152 __in REG_KEY_BITNESS kbKeyBitness,
159 __inout PDWORD pdwStartIndex, 153 __inout PDWORD pdwStartIndex,
160 __deref_out_z LPWSTR* psczBundleId 154 __deref_out_z LPWSTR* psczBundleId
161 ) 155 )
162{ 156{
163 HRESULT hr = S_OK; 157 HRESULT hr = S_OK;
158 BOOL fUpgradeCodeFound = FALSE;
159 HKEY hkUninstall = NULL;
160 HKEY hkBundle = NULL;
161 LPWSTR sczUninstallSubKey = NULL;
162 LPWSTR sczUninstallSubKeyPath = NULL;
163 LPWSTR sczValue = NULL;
164 DWORD dwType = 0;
165 LPWSTR* rgsczBundleUpgradeCodes = NULL;
166 DWORD cBundleUpgradeCodes = 0;
164 HKEY hkRoot = BUNDLE_INSTALL_CONTEXT_USER == context ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; 167 HKEY hkRoot = BUNDLE_INSTALL_CONTEXT_USER == context ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
165 168
166 if (!wzUpgradeCode || !pdwStartIndex) 169 if (!wzUpgradeCode || !pdwStartIndex)
@@ -168,27 +171,105 @@ DAPI_(HRESULT) BundleEnumRelatedBundle(
168 ButilExitOnFailure(hr = E_INVALIDARG, "An invalid parameter was passed to the function."); 171 ButilExitOnFailure(hr = E_INVALIDARG, "An invalid parameter was passed to the function.");
169 } 172 }
170 173
171 hr = DoBundleEnumRelatedBundle(hkRoot, REG_KEY_DEFAULT, wzUpgradeCode, pdwStartIndex, psczBundleId); 174 hr = RegOpenEx(hkRoot, BUNDLE_REGISTRATION_REGISTRY_UNINSTALL_KEY, KEY_READ, kbKeyBitness, &hkUninstall);
172 ButilExitOnFailure(hr, "Failed to enumerate default-bitness bundles."); 175 ButilExitOnFailure(hr, "Failed to open bundle uninstall key path.");
173 if (S_FALSE == hr) 176
177 for (DWORD dwIndex = *pdwStartIndex; !fUpgradeCodeFound; dwIndex++)
174 { 178 {
175#if defined(_WIN64) 179 hr = RegKeyEnum(hkUninstall, dwIndex, &sczUninstallSubKey);
176 hr = DoBundleEnumRelatedBundle(hkRoot, REG_KEY_32BIT, wzUpgradeCode, pdwStartIndex, psczBundleId); 180 ButilExitOnFailure(hr, "Failed to enumerate bundle uninstall key path.");
177 ButilExitOnFailure(hr, "Failed to enumerate 32-bit bundles."); 181
178#else 182 hr = StrAllocFormatted(&sczUninstallSubKeyPath, L"%ls\\%ls", BUNDLE_REGISTRATION_REGISTRY_UNINSTALL_KEY, sczUninstallSubKey);
179 hr = DoBundleEnumRelatedBundle(hkRoot, REG_KEY_64BIT, wzUpgradeCode, pdwStartIndex, psczBundleId); 183 ButilExitOnFailure(hr, "Failed to allocate bundle uninstall key path.");
180 ButilExitOnFailure(hr, "Failed to enumerate 64-bit bundles."); 184
181#endif 185 hr = RegOpenEx(hkRoot, sczUninstallSubKeyPath, KEY_READ, kbKeyBitness, &hkBundle);
186 ButilExitOnFailure(hr, "Failed to open uninstall key path.");
187
188 // If it's a bundle, it should have a BundleUpgradeCode value of type REG_SZ (old) or REG_MULTI_SZ
189 hr = RegGetType(hkBundle, BUNDLE_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE, &dwType);
190 if (FAILED(hr))
191 {
192 ReleaseRegKey(hkBundle);
193 ReleaseNullStr(sczUninstallSubKey);
194 ReleaseNullStr(sczUninstallSubKeyPath);
195 // Not a bundle
196 continue;
197 }
198
199 switch (dwType)
200 {
201 case REG_SZ:
202 hr = RegReadString(hkBundle, BUNDLE_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE, &sczValue);
203 ButilExitOnFailure(hr, "Failed to read BundleUpgradeCode string property.");
204
205 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, sczValue, -1, wzUpgradeCode, -1))
206 {
207 *pdwStartIndex = dwIndex;
208 fUpgradeCodeFound = TRUE;
209 break;
210 }
211
212 ReleaseNullStr(sczValue);
213
214 break;
215 case REG_MULTI_SZ:
216 hr = RegReadStringArray(hkBundle, BUNDLE_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE, &rgsczBundleUpgradeCodes, &cBundleUpgradeCodes);
217 ButilExitOnFailure(hr, "Failed to read BundleUpgradeCode multi-string property.");
218
219 for (DWORD i = 0; i < cBundleUpgradeCodes; i++)
220 {
221 LPWSTR wzBundleUpgradeCode = rgsczBundleUpgradeCodes[i];
222 if (wzBundleUpgradeCode && *wzBundleUpgradeCode)
223 {
224 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, wzBundleUpgradeCode, -1, wzUpgradeCode, -1))
225 {
226 *pdwStartIndex = dwIndex;
227 fUpgradeCodeFound = TRUE;
228 break;
229 }
230 }
231 }
232 ReleaseNullStrArray(rgsczBundleUpgradeCodes, cBundleUpgradeCodes);
233
234 break;
235
236 default:
237 ButilExitWithRootFailure(hr, E_NOTIMPL, "BundleUpgradeCode of type 0x%x not implemented.", dwType);
238 }
239
240 if (fUpgradeCodeFound)
241 {
242 if (psczBundleId)
243 {
244 *psczBundleId = sczUninstallSubKey;
245 sczUninstallSubKey = NULL;
246 }
247
248 break;
249 }
250
251 // Cleanup before next iteration
252 ReleaseRegKey(hkBundle);
253 ReleaseNullStr(sczUninstallSubKey);
254 ReleaseNullStr(sczUninstallSubKeyPath);
182 } 255 }
183 256
184LExit: 257LExit:
185 return hr; 258 ReleaseStr(sczValue);
259 ReleaseStr(sczUninstallSubKey);
260 ReleaseStr(sczUninstallSubKeyPath);
261 ReleaseRegKey(hkBundle);
262 ReleaseRegKey(hkUninstall);
263 ReleaseStrArray(rgsczBundleUpgradeCodes, cBundleUpgradeCodes);
264
265 return FAILED(hr) ? hr : fUpgradeCodeFound ? S_OK : S_FALSE;
186} 266}
187 267
188 268
189DAPI_(HRESULT) BundleEnumRelatedBundleFixed( 269DAPI_(HRESULT) BundleEnumRelatedBundleFixed(
190 __in_z LPCWSTR wzUpgradeCode, 270 __in_z LPCWSTR wzUpgradeCode,
191 __in BUNDLE_INSTALL_CONTEXT context, 271 __in BUNDLE_INSTALL_CONTEXT context,
272 __in REG_KEY_BITNESS kbKeyBitness,
192 __inout PDWORD pdwStartIndex, 273 __inout PDWORD pdwStartIndex,
193 __out_ecount(MAX_GUID_CHARS+1) LPWSTR wzBundleId 274 __out_ecount(MAX_GUID_CHARS+1) LPWSTR wzBundleId
194 ) 275 )
@@ -197,7 +278,7 @@ DAPI_(HRESULT) BundleEnumRelatedBundleFixed(
197 LPWSTR sczValue = NULL; 278 LPWSTR sczValue = NULL;
198 size_t cchValue = 0; 279 size_t cchValue = 0;
199 280
200 hr = BundleEnumRelatedBundle(wzUpgradeCode, context, pdwStartIndex, &sczValue); 281 hr = BundleEnumRelatedBundle(wzUpgradeCode, context, kbKeyBitness, pdwStartIndex, &sczValue);
201 if (S_OK == hr && wzBundleId) 282 if (S_OK == hr && wzBundleId)
202 { 283 {
203 hr = ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchValue); 284 hr = ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchValue);
@@ -396,116 +477,3 @@ static HRESULT CopyStringToBuffer(
396 477
397 return hr; 478 return hr;
398} 479}
399
400static HRESULT DoBundleEnumRelatedBundle(
401 __in HKEY hkRoot,
402 __in REG_KEY_BITNESS kbKeyBitness,
403 __in_z LPCWSTR wzUpgradeCode,
404 __inout PDWORD pdwStartIndex,
405 __deref_out_z LPWSTR* psczBundleId
406)
407{
408 HRESULT hr = S_OK;
409 BOOL fUpgradeCodeFound = FALSE;
410 HKEY hkUninstall = NULL;
411 HKEY hkBundle = NULL;
412 LPWSTR sczUninstallSubKey = NULL;
413 LPWSTR sczUninstallSubKeyPath = NULL;
414 LPWSTR sczValue = NULL;
415 DWORD dwType = 0;
416 LPWSTR* rgsczBundleUpgradeCodes = NULL;
417 DWORD cBundleUpgradeCodes = 0;
418
419 hr = RegOpenEx(hkRoot, BUNDLE_REGISTRATION_REGISTRY_UNINSTALL_KEY, KEY_READ, kbKeyBitness, &hkUninstall);
420 ButilExitOnFailure(hr, "Failed to open bundle uninstall key path.");
421
422 for (DWORD dwIndex = *pdwStartIndex; !fUpgradeCodeFound; dwIndex++)
423 {
424 hr = RegKeyEnum(hkUninstall, dwIndex, &sczUninstallSubKey);
425 ButilExitOnFailure(hr, "Failed to enumerate bundle uninstall key path.");
426
427 hr = StrAllocFormatted(&sczUninstallSubKeyPath, L"%ls\\%ls", BUNDLE_REGISTRATION_REGISTRY_UNINSTALL_KEY, sczUninstallSubKey);
428 ButilExitOnFailure(hr, "Failed to allocate bundle uninstall key path.");
429
430 hr = RegOpenEx(hkRoot, sczUninstallSubKeyPath, KEY_READ, kbKeyBitness, &hkBundle);
431 ButilExitOnFailure(hr, "Failed to open uninstall key path.");
432
433 // If it's a bundle, it should have a BundleUpgradeCode value of type REG_SZ (old) or REG_MULTI_SZ
434 hr = RegGetType(hkBundle, BUNDLE_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE, &dwType);
435 if (FAILED(hr))
436 {
437 ReleaseRegKey(hkBundle);
438 ReleaseNullStr(sczUninstallSubKey);
439 ReleaseNullStr(sczUninstallSubKeyPath);
440 // Not a bundle
441 continue;
442 }
443
444 switch (dwType)
445 {
446 case REG_SZ:
447 hr = RegReadString(hkBundle, BUNDLE_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE, &sczValue);
448 ButilExitOnFailure(hr, "Failed to read BundleUpgradeCode string property.");
449
450 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, sczValue, -1, wzUpgradeCode, -1))
451 {
452 *pdwStartIndex = dwIndex;
453 fUpgradeCodeFound = TRUE;
454 break;
455 }
456
457 ReleaseNullStr(sczValue);
458
459 break;
460 case REG_MULTI_SZ:
461 hr = RegReadStringArray(hkBundle, BUNDLE_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE, &rgsczBundleUpgradeCodes, &cBundleUpgradeCodes);
462 ButilExitOnFailure(hr, "Failed to read BundleUpgradeCode multi-string property.");
463
464 for (DWORD i = 0; i < cBundleUpgradeCodes; i++)
465 {
466 LPWSTR wzBundleUpgradeCode = rgsczBundleUpgradeCodes[i];
467 if (wzBundleUpgradeCode && *wzBundleUpgradeCode)
468 {
469 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, wzBundleUpgradeCode, -1, wzUpgradeCode, -1))
470 {
471 *pdwStartIndex = dwIndex;
472 fUpgradeCodeFound = TRUE;
473 break;
474 }
475 }
476 }
477 ReleaseNullStrArray(rgsczBundleUpgradeCodes, cBundleUpgradeCodes);
478
479 break;
480
481 default:
482 ButilExitWithRootFailure(hr, E_NOTIMPL, "BundleUpgradeCode of type 0x%x not implemented.", dwType);
483 }
484
485 if (fUpgradeCodeFound)
486 {
487 if (psczBundleId)
488 {
489 *psczBundleId = sczUninstallSubKey;
490 sczUninstallSubKey = NULL;
491 }
492
493 break;
494 }
495
496 // Cleanup before next iteration
497 ReleaseRegKey(hkBundle);
498 ReleaseNullStr(sczUninstallSubKey);
499 ReleaseNullStr(sczUninstallSubKeyPath);
500 }
501
502LExit:
503 ReleaseStr(sczValue);
504 ReleaseStr(sczUninstallSubKey);
505 ReleaseStr(sczUninstallSubKeyPath);
506 ReleaseRegKey(hkBundle);
507 ReleaseRegKey(hkUninstall);
508 ReleaseStrArray(rgsczBundleUpgradeCodes, cBundleUpgradeCodes);
509
510 return FAILED(hr) ? hr : fUpgradeCodeFound ? S_OK : S_FALSE;
511}
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/butil.h b/src/libs/dutil/WixToolset.DUtil/inc/butil.h
index 3b316e66..9c2010ee 100644
--- a/src/libs/dutil/WixToolset.DUtil/inc/butil.h
+++ b/src/libs/dutil/WixToolset.DUtil/inc/butil.h
@@ -60,7 +60,9 @@ HRESULT DAPI BundleGetBundleInfoFixed(
60 ); 60 );
61 61
62/******************************************************************** 62/********************************************************************
63BundleEnumRelatedBundle - Queries the bundle installation metadata for installs with the given upgrade code 63BundleEnumRelatedBundle - Queries the bundle installation metadata for installs with the given upgrade code.
64Enumerate 32-bit and 64-bit in two passes.
65
64RETURNS: 66RETURNS:
65 E_INVALIDARG 67 E_INVALIDARG
66 An invalid parameter was passed to the function. 68 An invalid parameter was passed to the function.
@@ -74,12 +76,14 @@ RETURNS:
74HRESULT DAPI BundleEnumRelatedBundle( 76HRESULT DAPI BundleEnumRelatedBundle(
75 __in_z LPCWSTR wzUpgradeCode, 77 __in_z LPCWSTR wzUpgradeCode,
76 __in BUNDLE_INSTALL_CONTEXT context, 78 __in BUNDLE_INSTALL_CONTEXT context,
79 __in REG_KEY_BITNESS kbKeyBitness,
77 __inout PDWORD pdwStartIndex, 80 __inout PDWORD pdwStartIndex,
78 __deref_out_z LPWSTR* psczBundleId 81 __deref_out_z LPWSTR* psczBundleId
79 ); 82 );
80 83
81/******************************************************************** 84/********************************************************************
82BundleEnumRelatedBundleFixed - Queries the bundle installation metadata for installs with the given upgrade code 85BundleEnumRelatedBundleFixed - Queries the bundle installation metadata for installs with the given upgrade code
86Enumerate 32-bit and 64-bit in two passes.
83 87
84NOTE: lpBundleIdBuff is a buffer to receive the bundle GUID. This buffer must be 39 characters long. 88NOTE: lpBundleIdBuff is a buffer to receive the bundle GUID. This buffer must be 39 characters long.
85 The first 38 characters are for the GUID, and the last character is for the terminating null character. 89 The first 38 characters are for the GUID, and the last character is for the terminating null character.
@@ -96,6 +100,7 @@ RETURNS:
96HRESULT DAPI BundleEnumRelatedBundleFixed( 100HRESULT DAPI BundleEnumRelatedBundleFixed(
97 __in_z LPCWSTR wzUpgradeCode, 101 __in_z LPCWSTR wzUpgradeCode,
98 __in BUNDLE_INSTALL_CONTEXT context, 102 __in BUNDLE_INSTALL_CONTEXT context,
103 __in REG_KEY_BITNESS kbKeyBitness,
99 __inout PDWORD pdwStartIndex, 104 __inout PDWORD pdwStartIndex,
100 __out_ecount(MAX_GUID_CHARS+1) LPWSTR wzBundleId 105 __out_ecount(MAX_GUID_CHARS+1) LPWSTR wzBundleId
101 ); 106 );
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/regutil.h b/src/libs/dutil/WixToolset.DUtil/inc/regutil.h
index db8e0c5c..3cbb53b0 100644
--- a/src/libs/dutil/WixToolset.DUtil/inc/regutil.h
+++ b/src/libs/dutil/WixToolset.DUtil/inc/regutil.h
@@ -408,6 +408,15 @@ BOOL DAPI RegValueExists(
408 __in REG_KEY_BITNESS kbKeyBitness 408 __in REG_KEY_BITNESS kbKeyBitness
409 ); 409 );
410 410
411/********************************************************************
412RegTranslateKeyBitness - Converts from REG_KEY_BITNESS values to
413REGSAM-compatible values.
414
415*********************************************************************/
416REGSAM DAPI RegTranslateKeyBitness(
417 __in REG_KEY_BITNESS kbKeyBitness
418 );
419
411#ifdef __cplusplus 420#ifdef __cplusplus
412} 421}
413#endif 422#endif
diff --git a/src/libs/dutil/WixToolset.DUtil/monutil.cpp b/src/libs/dutil/WixToolset.DUtil/monutil.cpp
index 6a7f0596..6ad75b56 100644
--- a/src/libs/dutil/WixToolset.DUtil/monutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/monutil.cpp
@@ -1677,18 +1677,7 @@ static REGSAM GetRegKeyBitness(
1677 __in MON_REQUEST *pRequest 1677 __in MON_REQUEST *pRequest
1678 ) 1678 )
1679{ 1679{
1680 if (REG_KEY_32BIT == pRequest->regkey.kbKeyBitness) 1680 return RegTranslateKeyBitness(pRequest->regkey.kbKeyBitness);
1681 {
1682 return KEY_WOW64_32KEY;
1683 }
1684 else if (REG_KEY_64BIT == pRequest->regkey.kbKeyBitness)
1685 {
1686 return KEY_WOW64_64KEY;
1687 }
1688 else
1689 {
1690 return 0;
1691 }
1692} 1681}
1693 1682
1694static HRESULT DuplicateRemoveMessage( 1683static HRESULT DuplicateRemoveMessage(
diff --git a/src/libs/dutil/WixToolset.DUtil/precomp.h b/src/libs/dutil/WixToolset.DUtil/precomp.h
index 093c16a2..902fe3e3 100644
--- a/src/libs/dutil/WixToolset.DUtil/precomp.h
+++ b/src/libs/dutil/WixToolset.DUtil/precomp.h
@@ -48,7 +48,6 @@
48#include "apputil.h" 48#include "apputil.h"
49#include "atomutil.h" 49#include "atomutil.h"
50#include "buffutil.h" 50#include "buffutil.h"
51#include "butil.h"
52#include "cabcutil.h" 51#include "cabcutil.h"
53#include "cabutil.h" 52#include "cabutil.h"
54#include "conutil.h" 53#include "conutil.h"
@@ -76,6 +75,7 @@
76#include "polcutil.h" 75#include "polcutil.h"
77#include "procutil.h" 76#include "procutil.h"
78#include "regutil.h" 77#include "regutil.h"
78#include "butil.h" // NOTE: Butil must come after Regutil.
79#include "resrutil.h" 79#include "resrutil.h"
80#include "reswutil.h" 80#include "reswutil.h"
81#include "rmutil.h" 81#include "rmutil.h"
diff --git a/src/libs/dutil/WixToolset.DUtil/regutil.cpp b/src/libs/dutil/WixToolset.DUtil/regutil.cpp
index f4719466..219a6c11 100644
--- a/src/libs/dutil/WixToolset.DUtil/regutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/regutil.cpp
@@ -32,9 +32,6 @@ static PFN_REGDELETEVALUEW vpfnRegDeleteValueW = ::RegDeleteValueW;
32static HMODULE vhAdvApi32Dll = NULL; 32static HMODULE vhAdvApi32Dll = NULL;
33static BOOL vfRegInitialized = FALSE; 33static BOOL vfRegInitialized = FALSE;
34 34
35static REGSAM TranslateKeyBitness(
36 __in REG_KEY_BITNESS kbKeyBitness
37);
38static HRESULT WriteStringToRegistry( 35static HRESULT WriteStringToRegistry(
39 __in HKEY hk, 36 __in HKEY hk,
40 __in_z_opt LPCWSTR wzName, 37 __in_z_opt LPCWSTR wzName,
@@ -135,7 +132,7 @@ DAPI_(HRESULT) RegCreateEx(
135 DWORD er = ERROR_SUCCESS; 132 DWORD er = ERROR_SUCCESS;
136 DWORD dwDisposition; 133 DWORD dwDisposition;
137 134
138 REGSAM samDesired = TranslateKeyBitness(kbKeyBitness); 135 REGSAM samDesired = RegTranslateKeyBitness(kbKeyBitness);
139 er = vpfnRegCreateKeyExW(hkRoot, wzSubKey, 0, NULL, fVolatile ? REG_OPTION_VOLATILE : REG_OPTION_NON_VOLATILE, dwAccess | samDesired, pSecurityAttributes, phk, &dwDisposition); 136 er = vpfnRegCreateKeyExW(hkRoot, wzSubKey, 0, NULL, fVolatile ? REG_OPTION_VOLATILE : REG_OPTION_NON_VOLATILE, dwAccess | samDesired, pSecurityAttributes, phk, &dwDisposition);
140 RegExitOnWin32Error(er, hr, "Failed to create registry key."); 137 RegExitOnWin32Error(er, hr, "Failed to create registry key.");
141 138
@@ -171,7 +168,7 @@ DAPI_(HRESULT) RegOpenEx(
171 HRESULT hr = S_OK; 168 HRESULT hr = S_OK;
172 DWORD er = ERROR_SUCCESS; 169 DWORD er = ERROR_SUCCESS;
173 170
174 REGSAM samDesired = TranslateKeyBitness(kbKeyBitness); 171 REGSAM samDesired = RegTranslateKeyBitness(kbKeyBitness);
175 er = vpfnRegOpenKeyExW(hkRoot, wzSubKey, 0, dwAccess | samDesired, phk); 172 er = vpfnRegOpenKeyExW(hkRoot, wzSubKey, 0, dwAccess | samDesired, phk);
176 if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er)) 173 if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er))
177 { 174 {
@@ -229,7 +226,7 @@ DAPI_(HRESULT) RegDelete(
229 226
230 if (NULL != vpfnRegDeleteKeyExW) 227 if (NULL != vpfnRegDeleteKeyExW)
231 { 228 {
232 REGSAM samDesired = TranslateKeyBitness(kbKeyBitness); 229 REGSAM samDesired = RegTranslateKeyBitness(kbKeyBitness);
233 er = vpfnRegDeleteKeyExW(hkRoot, wzSubKey, samDesired, 0); 230 er = vpfnRegDeleteKeyExW(hkRoot, wzSubKey, samDesired, 0);
234 if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er)) 231 if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er))
235 { 232 {
@@ -912,11 +909,6 @@ LExit:
912 return hr; 909 return hr;
913} 910}
914 911
915/********************************************************************
916RegValueExists - determines whether a named value exists in a
917specified subkey.
918
919*********************************************************************/
920DAPI_(BOOL) RegValueExists( 912DAPI_(BOOL) RegValueExists(
921 __in HKEY hk, 913 __in HKEY hk,
922 __in_z LPCWSTR wzSubKey, 914 __in_z LPCWSTR wzSubKey,
@@ -940,7 +932,7 @@ LExit:
940 return SUCCEEDED(hr); 932 return SUCCEEDED(hr);
941} 933}
942 934
943static REGSAM TranslateKeyBitness( 935DAPI_(REGSAM) RegTranslateKeyBitness(
944 __in REG_KEY_BITNESS kbKeyBitness 936 __in REG_KEY_BITNESS kbKeyBitness
945 ) 937 )
946{ 938{
@@ -948,14 +940,11 @@ static REGSAM TranslateKeyBitness(
948 { 940 {
949 case REG_KEY_32BIT: 941 case REG_KEY_32BIT:
950 return KEY_WOW64_32KEY; 942 return KEY_WOW64_32KEY;
951 break;
952 case REG_KEY_64BIT: 943 case REG_KEY_64BIT:
953 return KEY_WOW64_64KEY; 944 return KEY_WOW64_64KEY;
954 break;
955 case REG_KEY_DEFAULT: 945 case REG_KEY_DEFAULT:
956 default: 946 default:
957 return 0; 947 return 0;
958 break;
959 } 948 }
960} 949}
961 950
diff --git a/src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv1x64/BundleAv1x64.wixproj b/src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv1x64/BundleAv1x64.wixproj
new file mode 100644
index 00000000..44bf9772
--- /dev/null
+++ b/src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv1x64/BundleAv1x64.wixproj
@@ -0,0 +1,16 @@
1<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
2<Project Sdk="WixToolset.Sdk">
3 <Import Project="..\BundleAv1\BundleA.props" />
4 <PropertyGroup>
5 <BA>TestBA_x64</BA>
6 <InstallerPlatform>X64</InstallerPlatform>
7 </PropertyGroup>
8 <ItemGroup>
9 <ProjectReference Include="..\PackageAv1\PackageAv1.wixproj" />
10 <ProjectReference Include="..\..\TestBA\TestBAWixlib_x64\testbawixlib_x64.wixproj" />
11 </ItemGroup>
12 <ItemGroup>
13 <PackageReference Include="WixToolset.Bal.wixext" />
14 <PackageReference Include="WixToolset.NetFx.wixext" />
15 </ItemGroup>
16</Project> \ No newline at end of file
diff --git a/src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv1x64/BundleAv1x64.wxs b/src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv1x64/BundleAv1x64.wxs
new file mode 100644
index 00000000..7bf16212
--- /dev/null
+++ b/src/test/burn/TestData/UpgradeRelatedBundleTests/BundleAv1x64/BundleAv1x64.wxs
@@ -0,0 +1,10 @@
1<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
2
3
4<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 <Fragment>
6 <PackageGroup Id="BundlePackages">
7 <MsiPackage Id="PackageA" SourceFile="$(var.PackageAv1.TargetPath)" />
8 </PackageGroup>
9 </Fragment>
10</Wix>
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/UpgradeRelatedBundleTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/UpgradeRelatedBundleTests.cs
index a515ed69..6d81252e 100644
--- a/src/test/burn/WixToolsetTest.BurnE2E/UpgradeRelatedBundleTests.cs
+++ b/src/test/burn/WixToolsetTest.BurnE2E/UpgradeRelatedBundleTests.cs
@@ -49,5 +49,22 @@ namespace WixToolsetTest.BurnE2E
49 49
50 bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache(); 50 bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
51 } 51 }
52
53 [Fact]
54 public void Bundle32UpgradesBundle64()
55 {
56 var packageAv1 = this.CreatePackageInstaller("PackageAv1");
57 var packageAv2 = this.CreatePackageInstaller("PackageAv2");
58 var bundleAv1x64 = this.CreateBundleInstaller("BundleAv1x64");
59 var bundleAv2 = this.CreateBundleInstaller("BundleAv2");
60
61 bundleAv1x64.Install();
62 bundleAv1x64.VerifyRegisteredAndInPackageCache();
63
64 bundleAv2.Install();
65 bundleAv2.VerifyRegisteredAndInPackageCache();
66
67 bundleAv1x64.VerifyUnregisteredAndRemovedFromPackageCache();
68 }
52 } 69 }
53} 70}