diff options
Diffstat (limited to 'src/libs/dutil/WixToolset.DUtil/butil.cpp')
-rw-r--r-- | src/libs/dutil/WixToolset.DUtil/butil.cpp | 239 |
1 files changed, 138 insertions, 101 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/butil.cpp b/src/libs/dutil/WixToolset.DUtil/butil.cpp index 4c96dfc1..4262d573 100644 --- a/src/libs/dutil/WixToolset.DUtil/butil.cpp +++ b/src/libs/dutil/WixToolset.DUtil/butil.cpp | |||
@@ -55,6 +55,7 @@ static HRESULT OpenBundleKey( | |||
55 | __in_z LPCWSTR wzBundleId, | 55 | __in_z LPCWSTR wzBundleId, |
56 | __in BUNDLE_INSTALL_CONTEXT context, | 56 | __in BUNDLE_INSTALL_CONTEXT context, |
57 | __in_opt LPCWSTR wzSubKey, | 57 | __in_opt LPCWSTR wzSubKey, |
58 | __in REG_KEY_BITNESS kbKeyBitness, | ||
58 | __inout HKEY* phKey | 59 | __inout HKEY* phKey |
59 | ); | 60 | ); |
60 | static HRESULT CopyStringToBuffer( | 61 | static HRESULT CopyStringToBuffer( |
@@ -62,6 +63,14 @@ static HRESULT CopyStringToBuffer( | |||
62 | __in_z_opt LPWSTR wzBuffer, | 63 | __in_z_opt LPWSTR wzBuffer, |
63 | __inout SIZE_T* pcchBuffer | 64 | __inout SIZE_T* pcchBuffer |
64 | ); | 65 | ); |
66 | static 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 | |||
65 | 74 | ||
66 | DAPI_(HRESULT) BundleGetBundleInfo( | 75 | DAPI_(HRESULT) BundleGetBundleInfo( |
67 | __in_z LPCWSTR wzBundleId, | 76 | __in_z LPCWSTR wzBundleId, |
@@ -153,113 +162,26 @@ DAPI_(HRESULT) BundleEnumRelatedBundle( | |||
153 | { | 162 | { |
154 | HRESULT hr = S_OK; | 163 | HRESULT hr = S_OK; |
155 | HKEY hkRoot = BUNDLE_INSTALL_CONTEXT_USER == context ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; | 164 | HKEY hkRoot = BUNDLE_INSTALL_CONTEXT_USER == context ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; |
156 | HKEY hkUninstall = NULL; | ||
157 | HKEY hkBundle = NULL; | ||
158 | LPWSTR sczUninstallSubKey = NULL; | ||
159 | LPWSTR sczUninstallSubKeyPath = NULL; | ||
160 | LPWSTR sczValue = NULL; | ||
161 | DWORD dwType = 0; | ||
162 | |||
163 | LPWSTR* rgsczBundleUpgradeCodes = NULL; | ||
164 | DWORD cBundleUpgradeCodes = 0; | ||
165 | BOOL fUpgradeCodeFound = FALSE; | ||
166 | 165 | ||
167 | if (!wzUpgradeCode || !pdwStartIndex) | 166 | if (!wzUpgradeCode || !pdwStartIndex) |
168 | { | 167 | { |
169 | ButilExitOnFailure(hr = E_INVALIDARG, "An invalid parameter was passed to the function."); | 168 | ButilExitOnFailure(hr = E_INVALIDARG, "An invalid parameter was passed to the function."); |
170 | } | 169 | } |
171 | 170 | ||
172 | hr = RegOpen(hkRoot, BUNDLE_REGISTRATION_REGISTRY_UNINSTALL_KEY, KEY_READ, &hkUninstall); | 171 | hr = DoBundleEnumRelatedBundle(hkRoot, REG_KEY_DEFAULT, wzUpgradeCode, pdwStartIndex, psczBundleId); |
173 | ButilExitOnFailure(hr, "Failed to open bundle uninstall key path."); | 172 | ButilExitOnFailure(hr, "Failed to enumerate default-bitness bundles."); |
174 | 173 | if (S_FALSE == hr) | |
175 | for (DWORD dwIndex = *pdwStartIndex; !fUpgradeCodeFound; dwIndex++) | ||
176 | { | 174 | { |
177 | hr = RegKeyEnum(hkUninstall, dwIndex, &sczUninstallSubKey); | 175 | #if defined(_WIN64) |
178 | ButilExitOnFailure(hr, "Failed to enumerate bundle uninstall key path."); | 176 | hr = DoBundleEnumRelatedBundle(hkRoot, REG_KEY_32BIT, wzUpgradeCode, pdwStartIndex, psczBundleId); |
179 | 177 | ButilExitOnFailure(hr, "Failed to enumerate 32-bit bundles."); | |
180 | hr = StrAllocFormatted(&sczUninstallSubKeyPath, L"%ls\\%ls", BUNDLE_REGISTRATION_REGISTRY_UNINSTALL_KEY, sczUninstallSubKey); | 178 | #else |
181 | ButilExitOnFailure(hr, "Failed to allocate bundle uninstall key path."); | 179 | hr = DoBundleEnumRelatedBundle(hkRoot, REG_KEY_64BIT, wzUpgradeCode, pdwStartIndex, psczBundleId); |
182 | 180 | ButilExitOnFailure(hr, "Failed to enumerate 64-bit bundles."); | |
183 | hr = RegOpen(hkRoot, sczUninstallSubKeyPath, KEY_READ, &hkBundle); | 181 | #endif |
184 | ButilExitOnFailure(hr, "Failed to open uninstall key path."); | ||
185 | |||
186 | // If it's a bundle, it should have a BundleUpgradeCode value of type REG_SZ (old) or REG_MULTI_SZ | ||
187 | hr = RegGetType(hkBundle, BUNDLE_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE, &dwType); | ||
188 | if (FAILED(hr)) | ||
189 | { | ||
190 | ReleaseRegKey(hkBundle); | ||
191 | ReleaseNullStr(sczUninstallSubKey); | ||
192 | ReleaseNullStr(sczUninstallSubKeyPath); | ||
193 | // Not a bundle | ||
194 | continue; | ||
195 | } | ||
196 | |||
197 | switch (dwType) | ||
198 | { | ||
199 | case REG_SZ: | ||
200 | hr = RegReadString(hkBundle, BUNDLE_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE, &sczValue); | ||
201 | ButilExitOnFailure(hr, "Failed to read BundleUpgradeCode string property."); | ||
202 | |||
203 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, sczValue, -1, wzUpgradeCode, -1)) | ||
204 | { | ||
205 | *pdwStartIndex = dwIndex; | ||
206 | fUpgradeCodeFound = TRUE; | ||
207 | break; | ||
208 | } | ||
209 | |||
210 | ReleaseNullStr(sczValue); | ||
211 | |||
212 | break; | ||
213 | case REG_MULTI_SZ: | ||
214 | hr = RegReadStringArray(hkBundle, BUNDLE_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE, &rgsczBundleUpgradeCodes, &cBundleUpgradeCodes); | ||
215 | ButilExitOnFailure(hr, "Failed to read BundleUpgradeCode multi-string property."); | ||
216 | |||
217 | for (DWORD i = 0; i < cBundleUpgradeCodes; i++) | ||
218 | { | ||
219 | LPWSTR wzBundleUpgradeCode = rgsczBundleUpgradeCodes[i]; | ||
220 | if (wzBundleUpgradeCode && *wzBundleUpgradeCode) | ||
221 | { | ||
222 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, wzBundleUpgradeCode, -1, wzUpgradeCode, -1)) | ||
223 | { | ||
224 | *pdwStartIndex = dwIndex; | ||
225 | fUpgradeCodeFound = TRUE; | ||
226 | break; | ||
227 | } | ||
228 | } | ||
229 | } | ||
230 | ReleaseNullStrArray(rgsczBundleUpgradeCodes, cBundleUpgradeCodes); | ||
231 | |||
232 | break; | ||
233 | |||
234 | default: | ||
235 | ButilExitWithRootFailure(hr, E_NOTIMPL, "BundleUpgradeCode of type 0x%x not implemented.", dwType); | ||
236 | } | ||
237 | |||
238 | if (fUpgradeCodeFound) | ||
239 | { | ||
240 | if (psczBundleId) | ||
241 | { | ||
242 | *psczBundleId = sczUninstallSubKey; | ||
243 | sczUninstallSubKey = NULL; | ||
244 | } | ||
245 | |||
246 | break; | ||
247 | } | ||
248 | |||
249 | // Cleanup before next iteration | ||
250 | ReleaseRegKey(hkBundle); | ||
251 | ReleaseNullStr(sczUninstallSubKey); | ||
252 | ReleaseNullStr(sczUninstallSubKeyPath); | ||
253 | } | 182 | } |
254 | 183 | ||
255 | LExit: | 184 | LExit: |
256 | ReleaseStr(sczValue); | ||
257 | ReleaseStr(sczUninstallSubKey); | ||
258 | ReleaseStr(sczUninstallSubKeyPath); | ||
259 | ReleaseRegKey(hkBundle); | ||
260 | ReleaseRegKey(hkUninstall); | ||
261 | ReleaseStrArray(rgsczBundleUpgradeCodes, cBundleUpgradeCodes); | ||
262 | |||
263 | return hr; | 185 | return hr; |
264 | } | 186 | } |
265 | 187 | ||
@@ -276,7 +198,7 @@ DAPI_(HRESULT) BundleEnumRelatedBundleFixed( | |||
276 | size_t cchValue = 0; | 198 | size_t cchValue = 0; |
277 | 199 | ||
278 | hr = BundleEnumRelatedBundle(wzUpgradeCode, context, pdwStartIndex, &sczValue); | 200 | hr = BundleEnumRelatedBundle(wzUpgradeCode, context, pdwStartIndex, &sczValue); |
279 | if (SUCCEEDED(hr) && wzBundleId) | 201 | if (S_OK == hr && wzBundleId) |
280 | { | 202 | { |
281 | hr = ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchValue); | 203 | hr = ::StringCchLengthW(sczValue, STRSAFE_MAX_CCH, &cchValue); |
282 | ButilExitOnRootFailure(hr, "Failed to calculate length of string."); | 204 | ButilExitOnRootFailure(hr, "Failed to calculate length of string."); |
@@ -380,8 +302,9 @@ static HRESULT LocateAndQueryBundleValue( | |||
380 | 302 | ||
381 | *pStatus = INTERNAL_BUNDLE_STATUS_SUCCESS; | 303 | *pStatus = INTERNAL_BUNDLE_STATUS_SUCCESS; |
382 | 304 | ||
383 | if (FAILED(hr = OpenBundleKey(wzBundleId, BUNDLE_INSTALL_CONTEXT_MACHINE, wzSubKey, phKey)) && | 305 | if (FAILED(hr = OpenBundleKey(wzBundleId, BUNDLE_INSTALL_CONTEXT_MACHINE, wzSubKey, REG_KEY_32BIT, phKey)) && |
384 | FAILED(hr = OpenBundleKey(wzBundleId, BUNDLE_INSTALL_CONTEXT_USER, wzSubKey, phKey))) | 306 | FAILED(hr = OpenBundleKey(wzBundleId, BUNDLE_INSTALL_CONTEXT_MACHINE, wzSubKey, REG_KEY_64BIT, phKey)) && |
307 | FAILED(hr = OpenBundleKey(wzBundleId, BUNDLE_INSTALL_CONTEXT_USER, wzSubKey, REG_KEY_DEFAULT, phKey))) | ||
385 | { | 308 | { |
386 | if (E_FILENOTFOUND == hr) | 309 | if (E_FILENOTFOUND == hr) |
387 | { | 310 | { |
@@ -413,6 +336,7 @@ static HRESULT OpenBundleKey( | |||
413 | __in_z LPCWSTR wzBundleId, | 336 | __in_z LPCWSTR wzBundleId, |
414 | __in BUNDLE_INSTALL_CONTEXT context, | 337 | __in BUNDLE_INSTALL_CONTEXT context, |
415 | __in_opt LPCWSTR wzSubKey, | 338 | __in_opt LPCWSTR wzSubKey, |
339 | __in REG_KEY_BITNESS kbKeyBitness, | ||
416 | __inout HKEY* phKey | 340 | __inout HKEY* phKey |
417 | ) | 341 | ) |
418 | { | 342 | { |
@@ -433,7 +357,7 @@ static HRESULT OpenBundleKey( | |||
433 | } | 357 | } |
434 | ButilExitOnFailure(hr, "Failed to allocate bundle uninstall key path."); | 358 | ButilExitOnFailure(hr, "Failed to allocate bundle uninstall key path."); |
435 | 359 | ||
436 | hr = RegOpen(hkRoot, sczKeypath, KEY_READ, phKey); | 360 | hr = RegOpenEx(hkRoot, sczKeypath, KEY_READ, kbKeyBitness, phKey); |
437 | ButilExitOnFailure(hr, "Failed to open bundle uninstall key path."); | 361 | ButilExitOnFailure(hr, "Failed to open bundle uninstall key path."); |
438 | 362 | ||
439 | LExit: | 363 | LExit: |
@@ -472,3 +396,116 @@ static HRESULT CopyStringToBuffer( | |||
472 | 396 | ||
473 | return hr; | 397 | return hr; |
474 | } | 398 | } |
399 | |||
400 | static 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 | |||
502 | LExit: | ||
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 | } | ||