diff options
| author | Bob Arnson <bob@firegiant.com> | 2026-02-04 20:47:04 -0500 |
|---|---|---|
| committer | Bob Arnson <bob@firegiant.com> | 2026-02-04 20:47:04 -0500 |
| commit | edccb203c421d2bd820062024088c6698424d9ee (patch) | |
| tree | 6b47c3eb5ca53bd9f79f3d032dc1a596d411bf38 /src/burn/engine/registration.cpp | |
| parent | a3d3963f806117ce123d95e8b77e73e1c1545b25 (diff) | |
| download | wix-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.cpp | 287 |
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 | ); |
| 42 | static HRESULT SetPaths( | ||
| 43 | __in BURN_REGISTRATION* pRegistration, | ||
| 44 | __in BURN_CACHE* pCache | ||
| 45 | ); | ||
| 46 | static HRESULT GetBundleManufacturer( | 42 | static 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 | ); |
| 109 | static BOOL IsWuRebootPending(); | 105 | static BOOL IsWuRebootPending(); |
| 110 | static BOOL IsRegistryRebootPending(); | 106 | static BOOL IsRegistryRebootPending(); |
| 107 | static HRESULT RegistrationDetectResumeTypeByHive( | ||
| 108 | __in HKEY hkRegistrationRoot, | ||
| 109 | __in BURN_REGISTRATION* pRegistration, | ||
| 110 | __out BOOTSTRAPPER_RESUME_TYPE* pResumeType | ||
| 111 | ); | ||
| 112 | static 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 | ||
| 291 | LExit: | 306 | LExit: |
| 292 | ReleaseObject(pixnRegistrationNode); | 307 | ReleaseObject(pixnRegistrationNode); |
| @@ -452,31 +467,28 @@ LExit: | |||
| 452 | 467 | ||
| 453 | extern "C" HRESULT RegistrationDetectInstalled( | 468 | extern "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); | 491 | LExit: |
| 480 | return hr; | 492 | return hr; |
| 481 | } | 493 | } |
| 482 | 494 | ||
| @@ -488,63 +500,26 @@ extern "C" HRESULT RegistrationDetectInstalled( | |||
| 488 | extern "C" HRESULT RegistrationDetectResumeType( | 500 | extern "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 | ||
| 545 | LExit: | 522 | LExit: |
| 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 | ||
| 1046 | extern "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 | |||
| 1073 | LExit: | ||
| 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 | ||
| 1144 | static 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 | |||
| 1171 | LExit: | ||
| 1172 | ReleaseStr(sczCacheDirectory); | ||
| 1173 | return hr; | ||
| 1174 | } | ||
| 1175 | |||
| 1176 | static HRESULT GetBundleManufacturer( | 1152 | static 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 | |||
| 1683 | static 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 | |||
| 1743 | LExit: | ||
| 1744 | ReleaseRegKey(hkRegistration); | ||
| 1745 | |||
| 1746 | return hr; | ||
| 1747 | } | ||
| 1748 | |||
| 1749 | static 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 | |||
