aboutsummaryrefslogtreecommitdiff
path: root/src/burn/engine/registration.cpp
diff options
context:
space:
mode:
authorBob Arnson <bob@firegiant.com>2026-02-04 20:47:04 -0500
committerBob Arnson <bob@firegiant.com>2026-02-04 20:47:04 -0500
commitedccb203c421d2bd820062024088c6698424d9ee (patch)
tree6b47c3eb5ca53bd9f79f3d032dc1a596d411bf38 /src/burn/engine/registration.cpp
parenta3d3963f806117ce123d95e8b77e73e1c1545b25 (diff)
downloadwix-bob/ConfigurableScopeBundles.tar.gz
wix-bob/ConfigurableScopeBundles.tar.bz2
wix-bob/ConfigurableScopeBundles.zip
Support dual-purpose packages in Burn.bob/ConfigurableScopeBundles
Fixes https://github.com/wixtoolset/issues/issues/8958
Diffstat (limited to 'src/burn/engine/registration.cpp')
-rw-r--r--src/burn/engine/registration.cpp287
1 files changed, 181 insertions, 106 deletions
diff --git a/src/burn/engine/registration.cpp b/src/burn/engine/registration.cpp
index 9733e92c..fa1b024a 100644
--- a/src/burn/engine/registration.cpp
+++ b/src/burn/engine/registration.cpp
@@ -39,10 +39,6 @@ static HRESULT ParseSoftwareTagsFromXml(
39 __out BURN_SOFTWARE_TAG** prgSoftwareTags, 39 __out BURN_SOFTWARE_TAG** prgSoftwareTags,
40 __out DWORD* pcSoftwareTags 40 __out DWORD* pcSoftwareTags
41 ); 41 );
42static HRESULT SetPaths(
43 __in BURN_REGISTRATION* pRegistration,
44 __in BURN_CACHE* pCache
45 );
46static HRESULT GetBundleManufacturer( 42static HRESULT GetBundleManufacturer(
47 __in BURN_REGISTRATION* pRegistration, 43 __in BURN_REGISTRATION* pRegistration,
48 __in BURN_VARIABLES* pVariables, 44 __in BURN_VARIABLES* pVariables,
@@ -108,6 +104,15 @@ static HRESULT UpdateEstimatedSize(
108 ); 104 );
109static BOOL IsWuRebootPending(); 105static BOOL IsWuRebootPending();
110static BOOL IsRegistryRebootPending(); 106static BOOL IsRegistryRebootPending();
107static HRESULT RegistrationDetectResumeTypeByHive(
108 __in HKEY hkRegistrationRoot,
109 __in BURN_REGISTRATION* pRegistration,
110 __out BOOTSTRAPPER_RESUME_TYPE* pResumeType
111);
112static HRESULT DetectInstalled(
113 __in BURN_REGISTRATION* pRegistration,
114 __in HKEY hkRoot
115);
111 116
112// function definitions 117// function definitions
113 118
@@ -163,9 +168,9 @@ extern "C" HRESULT RegistrationParseFromXml(
163 hr = XmlGetAttributeEx(pixnRegistrationNode, L"ExecutableName", &pRegistration->sczExecutableName); 168 hr = XmlGetAttributeEx(pixnRegistrationNode, L"ExecutableName", &pRegistration->sczExecutableName);
164 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @ExecutableName."); 169 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @ExecutableName.");
165 170
166 // @PerMachine 171 // @Scope
167 hr = XmlGetYesNoAttribute(pixnRegistrationNode, L"PerMachine", &pRegistration->fPerMachine); 172 hr = PackageParseScopeFromXml(pixnRegistrationNode, &pRegistration->scope);
168 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @PerMachine."); 173 ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Scope.");
169 174
170 // select ARP node 175 // select ARP node
171 hr = XmlSelectSingleNode(pixnRegistrationNode, L"Arp", &pixnArpNode); 176 hr = XmlSelectSingleNode(pixnRegistrationNode, L"Arp", &pixnArpNode);
@@ -285,8 +290,18 @@ extern "C" HRESULT RegistrationParseFromXml(
285 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Classification."); 290 ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Classification.");
286 } 291 }
287 292
288 hr = SetPaths(pRegistration, pCache); 293 // Handle the easy case of build-time bundle scope early.
289 ExitOnFailure(hr, "Failed to set registration paths."); 294 if (BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE == pRegistration->scope || BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER == pRegistration->scope)
295 {
296 pRegistration->fPerMachine = BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE == pRegistration->scope;
297
298 hr = RegistrationSetPaths(pRegistration, pCache);
299 ExitOnFailure(hr, "Failed to set registration paths for fixed scope.");
300 }
301 else
302 {
303 pRegistration->hkRoot = reinterpret_cast<HKEY>(0ull);
304 }
290 305
291LExit: 306LExit:
292 ReleaseObject(pixnRegistrationNode); 307 ReleaseObject(pixnRegistrationNode);
@@ -452,31 +467,28 @@ LExit:
452 467
453extern "C" HRESULT RegistrationDetectInstalled( 468extern "C" HRESULT RegistrationDetectInstalled(
454 __in BURN_REGISTRATION* pRegistration 469 __in BURN_REGISTRATION* pRegistration
455 ) 470)
456{ 471{
457 HRESULT hr = S_OK; 472 HRESULT hr = S_OK;
458 HKEY hkRegistration = NULL;
459 DWORD dwInstalled = 0;
460 473
461 pRegistration->fCached = FileExistsEx(pRegistration->sczCacheExecutablePath, NULL); 474 if (pRegistration->hkRoot)
462 pRegistration->detectedRegistrationType = BOOTSTRAPPER_REGISTRATION_TYPE_NONE;
463
464 // open registration key
465 hr = RegOpen(pRegistration->hkRoot, pRegistration->sczRegistrationKey, KEY_QUERY_VALUE, &hkRegistration);
466 if (SUCCEEDED(hr))
467 { 475 {
468 hr = RegReadNumber(hkRegistration, REGISTRY_BUNDLE_INSTALLED, &dwInstalled); 476 hr = DetectInstalled(pRegistration, pRegistration->hkRoot);
469
470 pRegistration->detectedRegistrationType = (1 == dwInstalled) ? BOOTSTRAPPER_REGISTRATION_TYPE_FULL : BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS;
471 } 477 }
472 478 else
473 // Not finding the key or value is okay.
474 if (E_FILENOTFOUND == hr || E_PATHNOTFOUND == hr)
475 { 479 {
476 hr = S_OK; 480 // For PUOM/PMOU bundles, check per-machine then fall back to per-user.
481 hr = DetectInstalled(pRegistration, HKEY_LOCAL_MACHINE);
482 ExitOnFailure(hr, "Failed to detect HKEY_LOCAL_MACHINE bundle registration install state.");
483
484 if (BOOTSTRAPPER_REGISTRATION_TYPE_NONE == pRegistration->detectedRegistrationType)
485 {
486 hr = DetectInstalled(pRegistration, HKEY_CURRENT_USER);
487 ExitOnFailure(hr, "Failed to detect HKEY_CURRENT_USER bundle registration install state.");
488 }
477 } 489 }
478 490
479 ReleaseRegKey(hkRegistration); 491LExit:
480 return hr; 492 return hr;
481} 493}
482 494
@@ -488,63 +500,26 @@ extern "C" HRESULT RegistrationDetectInstalled(
488extern "C" HRESULT RegistrationDetectResumeType( 500extern "C" HRESULT RegistrationDetectResumeType(
489 __in BURN_REGISTRATION* pRegistration, 501 __in BURN_REGISTRATION* pRegistration,
490 __out BOOTSTRAPPER_RESUME_TYPE* pResumeType 502 __out BOOTSTRAPPER_RESUME_TYPE* pResumeType
491 ) 503)
492{ 504{
493 HRESULT hr = S_OK; 505 HRESULT hr = S_OK;
494 HKEY hkRegistration = NULL;
495 BOOL fExists = FALSE;
496 DWORD dwResume = 0;
497 506
498 // open registration key 507 if (pRegistration->hkRoot)
499 hr = RegOpen(pRegistration->hkRoot, pRegistration->sczRegistrationKey, KEY_QUERY_VALUE, &hkRegistration);
500 ExitOnPathFailure(hr, fExists, "Failed to open registration key.");
501
502 if (!fExists)
503 { 508 {
504 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_NONE; 509 hr = RegistrationDetectResumeTypeByHive(pRegistration->hkRoot, pRegistration, pResumeType);
505 ExitFunction();
506 } 510 }
507 511 else
508 // read Resume value
509 hr = RegReadNumber(hkRegistration, L"Resume", &dwResume);
510 ExitOnPathFailure(hr, fExists, "Failed to read Resume value.");
511
512 if (!fExists)
513 {
514 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_INVALID;
515 ExitFunction();
516 }
517
518 switch (dwResume)
519 { 512 {
520 case BURN_RESUME_MODE_ACTIVE: 513 hr = RegistrationDetectResumeTypeByHive(HKEY_LOCAL_MACHINE, pRegistration, pResumeType);
521 // a previous run was interrupted
522 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_INTERRUPTED;
523 break;
524
525 case BURN_RESUME_MODE_SUSPEND:
526 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_SUSPEND;
527 break;
528
529 case BURN_RESUME_MODE_ARP:
530 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_ARP;
531 break;
532
533 case BURN_RESUME_MODE_REBOOT_PENDING:
534 // The volatile pending registry doesn't exist (checked above) which means
535 // the system was successfully restarted.
536 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_REBOOT;
537 break;
538 514
539 default: 515 if (BOOTSTRAPPER_RESUME_TYPE_NONE == *pResumeType)
540 // the value stored in the registry is not valid 516 {
541 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_INVALID; 517 hr = RegistrationDetectResumeTypeByHive(HKEY_CURRENT_USER, pRegistration, pResumeType);
542 break; 518 }
543 } 519 }
520 ExitOnFailure(hr, "Failed to find bundle registration: %ls", pRegistration->sczRegistrationKey);
544 521
545LExit: 522LExit:
546 ReleaseRegKey(hkRegistration);
547
548 return hr; 523 return hr;
549} 524}
550 525
@@ -889,7 +864,7 @@ extern "C" HRESULT RegistrationSessionEnd(
889 864
890 // Open registration key. 865 // Open registration key.
891 hr = RegOpen(pRegistration->hkRoot, pRegistration->sczRegistrationKey, KEY_WRITE, &hkRegistration); 866 hr = RegOpen(pRegistration->hkRoot, pRegistration->sczRegistrationKey, KEY_WRITE, &hkRegistration);
892 ExitOnFailure(hr, "Failed to open registration key."); 867 ExitOnFailure(hr, "Failed to open registration key for ending session.");
893 868
894 // update display name 869 // update display name
895 hr = UpdateBundleNameRegistration(pRegistration, pVariables, hkRegistration, BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS == registrationType); 870 hr = UpdateBundleNameRegistration(pRegistration, pVariables, hkRegistration, BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS == registrationType);
@@ -1068,6 +1043,39 @@ extern "C" HRESULT RegistrationGetResumeCommandLine(
1068 return hr; 1043 return hr;
1069} 1044}
1070 1045
1046extern "C" HRESULT RegistrationSetPaths(
1047 __in BURN_REGISTRATION* pRegistration,
1048 __in BURN_CACHE* pCache
1049 )
1050{
1051 HRESULT hr = S_OK;
1052 LPWSTR sczCacheDirectory = NULL;
1053
1054 // save registration key root
1055 pRegistration->hkRoot = pRegistration->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1056
1057 // build uninstall registry key path
1058 hr = StrAllocFormatted(&pRegistration->sczRegistrationKey, L"%ls\\%ls", BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY, pRegistration->sczCode);
1059 ExitOnFailure(hr, "Failed to build uninstall registry key path.");
1060
1061 // build cache directory
1062 hr = CacheGetCompletedPath(pCache, pRegistration->fPerMachine, pRegistration->sczCode, &sczCacheDirectory);
1063 ExitOnFailure(hr, "Failed to build cache directory.");
1064
1065 // build cached executable path
1066 hr = PathConcatRelativeToFullyQualifiedBase(sczCacheDirectory, pRegistration->sczExecutableName, &pRegistration->sczCacheExecutablePath);
1067 ExitOnFailure(hr, "Failed to build cached executable path.");
1068
1069 // build state file path
1070 hr = StrAllocFormatted(&pRegistration->sczStateFile, L"%ls\\state.rsm", sczCacheDirectory);
1071 ExitOnFailure(hr, "Failed to build state file path.");
1072
1073LExit:
1074 ReleaseStr(sczCacheDirectory);
1075
1076 return hr;
1077}
1078
1071 1079
1072// internal helper functions 1080// internal helper functions
1073 1081
@@ -1141,38 +1149,6 @@ LExit:
1141 return hr; 1149 return hr;
1142} 1150}
1143 1151
1144static HRESULT SetPaths(
1145 __in BURN_REGISTRATION* pRegistration,
1146 __in BURN_CACHE* pCache
1147 )
1148{
1149 HRESULT hr = S_OK;
1150 LPWSTR sczCacheDirectory = NULL;
1151
1152 // save registration key root
1153 pRegistration->hkRoot = pRegistration->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1154
1155 // build uninstall registry key path
1156 hr = StrAllocFormatted(&pRegistration->sczRegistrationKey, L"%ls\\%ls", BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY, pRegistration->sczCode);
1157 ExitOnFailure(hr, "Failed to build uninstall registry key path.");
1158
1159 // build cache directory
1160 hr = CacheGetCompletedPath(pCache, pRegistration->fPerMachine, pRegistration->sczCode, &sczCacheDirectory);
1161 ExitOnFailure(hr, "Failed to build cache directory.");
1162
1163 // build cached executable path
1164 hr = PathConcatRelativeToFullyQualifiedBase(sczCacheDirectory, pRegistration->sczExecutableName, &pRegistration->sczCacheExecutablePath);
1165 ExitOnFailure(hr, "Failed to build cached executable path.");
1166
1167 // build state file path
1168 hr = StrAllocFormatted(&pRegistration->sczStateFile, L"%ls\\state.rsm", sczCacheDirectory);
1169 ExitOnFailure(hr, "Failed to build state file path.");
1170
1171LExit:
1172 ReleaseStr(sczCacheDirectory);
1173 return hr;
1174}
1175
1176static HRESULT GetBundleManufacturer( 1152static HRESULT GetBundleManufacturer(
1177 __in BURN_REGISTRATION* pRegistration, 1153 __in BURN_REGISTRATION* pRegistration,
1178 __in BURN_VARIABLES* pVariables, 1154 __in BURN_VARIABLES* pVariables,
@@ -1703,3 +1679,102 @@ static BOOL IsRegistryRebootPending()
1703 1679
1704 return fRebootPending; 1680 return fRebootPending;
1705} 1681}
1682
1683static HRESULT RegistrationDetectResumeTypeByHive(
1684 __in HKEY hkRegistrationRoot,
1685 __in BURN_REGISTRATION* pRegistration,
1686 __out BOOTSTRAPPER_RESUME_TYPE* pResumeType
1687)
1688{
1689 HRESULT hr = S_OK;
1690 HKEY hkRegistration = NULL;
1691 BOOL fExists = FALSE;
1692 DWORD dwResume = 0;
1693
1694 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_NONE;
1695
1696 // open registration key
1697 hr = RegOpen(hkRegistrationRoot, pRegistration->sczRegistrationKey, KEY_QUERY_VALUE, &hkRegistration);
1698 ExitOnPathFailure(hr, fExists, "Failed to open registration key.");
1699
1700 if (!fExists)
1701 {
1702 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_NONE;
1703 ExitFunction();
1704 }
1705
1706 // read Resume value
1707 hr = RegReadNumber(hkRegistration, L"Resume", &dwResume);
1708 ExitOnPathFailure(hr, fExists, "Failed to read Resume value.");
1709
1710 if (!fExists)
1711 {
1712 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_INVALID;
1713 ExitFunction();
1714 }
1715
1716 switch (dwResume)
1717 {
1718 case BURN_RESUME_MODE_ACTIVE:
1719 // a previous run was interrupted
1720 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_INTERRUPTED;
1721 break;
1722
1723 case BURN_RESUME_MODE_SUSPEND:
1724 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_SUSPEND;
1725 break;
1726
1727 case BURN_RESUME_MODE_ARP:
1728 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_ARP;
1729 break;
1730
1731 case BURN_RESUME_MODE_REBOOT_PENDING:
1732 // The volatile pending registry doesn't exist (checked above) which means
1733 // the system was successfully restarted.
1734 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_REBOOT;
1735 break;
1736
1737 default:
1738 // the value stored in the registry is not valid
1739 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_INVALID;
1740 break;
1741 }
1742
1743LExit:
1744 ReleaseRegKey(hkRegistration);
1745
1746 return hr;
1747}
1748
1749static HRESULT DetectInstalled(
1750 __in BURN_REGISTRATION* pRegistration,
1751 __in HKEY hkRoot
1752)
1753{
1754 HRESULT hr = S_OK;
1755 HKEY hkRegistration = NULL;
1756 DWORD dwInstalled = 0;
1757
1758 pRegistration->fCached = pRegistration->sczCacheExecutablePath && FileExistsEx(pRegistration->sczCacheExecutablePath, NULL);
1759 pRegistration->detectedRegistrationType = BOOTSTRAPPER_REGISTRATION_TYPE_NONE;
1760
1761 // open registration key
1762 hr = RegOpen(hkRoot, pRegistration->sczRegistrationKey, KEY_QUERY_VALUE, &hkRegistration);
1763 if (SUCCEEDED(hr))
1764 {
1765 hr = RegReadNumber(hkRegistration, REGISTRY_BUNDLE_INSTALLED, &dwInstalled);
1766
1767 pRegistration->detectedRegistrationType = (1 == dwInstalled) ? BOOTSTRAPPER_REGISTRATION_TYPE_FULL : BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS;
1768 }
1769
1770 // Not finding the key or value is okay.
1771 if (E_FILENOTFOUND == hr || E_PATHNOTFOUND == hr)
1772 {
1773 hr = S_OK;
1774 }
1775
1776 ReleaseRegKey(hkRegistration);
1777
1778 return hr;
1779}
1780