aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob Arnson <bob@firegiant.com>2021-03-28 22:17:56 -0400
committerBob Arnson <bob@firegiant.com>2021-03-28 22:32:10 -0400
commit65b905667b8567cd9b40c220eb18bd729276e7a6 (patch)
tree6176c85ff7d2f89a7cb6f3533eda3e25be2cb119
parentb7582318f6cb6e166f5ca22128caea2a97551a1f (diff)
downloadwix-65b905667b8567cd9b40c220eb18bd729276e7a6.tar.gz
wix-65b905667b8567cd9b40c220eb18bd729276e7a6.tar.bz2
wix-65b905667b8567cd9b40c220eb18bd729276e7a6.zip
Include bundle reboot-pending in RebootPending variable.
Fixes https://github.com/wixtoolset/issues/issues/5332
-rw-r--r--src/engine/core.h1
-rw-r--r--src/engine/registration.cpp63
-rw-r--r--src/engine/variable.cpp43
-rw-r--r--src/test/BurnUnitTest/RegistrationTest.cpp110
4 files changed, 163 insertions, 54 deletions
diff --git a/src/engine/core.h b/src/engine/core.h
index 75a61614..b4e0e0d3 100644
--- a/src/engine/core.h
+++ b/src/engine/core.h
@@ -46,6 +46,7 @@ const LPCWSTR BURN_BUNDLE_SOURCE_PROCESS_FOLDER = L"WixBundleSourceProcessFolder
46const LPCWSTR BURN_BUNDLE_TAG = L"WixBundleTag"; 46const LPCWSTR BURN_BUNDLE_TAG = L"WixBundleTag";
47const LPCWSTR BURN_BUNDLE_UILEVEL = L"WixBundleUILevel"; 47const LPCWSTR BURN_BUNDLE_UILEVEL = L"WixBundleUILevel";
48const LPCWSTR BURN_BUNDLE_VERSION = L"WixBundleVersion"; 48const LPCWSTR BURN_BUNDLE_VERSION = L"WixBundleVersion";
49const LPCWSTR BURN_REBOOT_PENDING = L"RebootPending";
49 50
50// The following constants must stay in sync with src\wix\Binder.cs 51// The following constants must stay in sync with src\wix\Binder.cs
51const LPCWSTR BURN_BUNDLE_NAME = L"WixBundleName"; 52const LPCWSTR BURN_BUNDLE_NAME = L"WixBundleName";
diff --git a/src/engine/registration.cpp b/src/engine/registration.cpp
index dc4b88bf..fc5ae627 100644
--- a/src/engine/registration.cpp
+++ b/src/engine/registration.cpp
@@ -92,6 +92,10 @@ static HRESULT UpdateBundleNameRegistration(
92 __in BURN_VARIABLES* pVariables, 92 __in BURN_VARIABLES* pVariables,
93 __in HKEY hkRegistration 93 __in HKEY hkRegistration
94 ); 94 );
95static BOOL IsWuRebootPending();
96static BOOL IsBundleRebootPending(
97 __in BURN_REGISTRATION* pRegistration
98);
95 99
96// function definitions 100// function definitions
97 101
@@ -443,7 +447,10 @@ extern "C" HRESULT RegistrationSetVariables(
443 ExitOnFailure(hr, "Failed to overwrite the bundle tag built-in variable."); 447 ExitOnFailure(hr, "Failed to overwrite the bundle tag built-in variable.");
444 448
445 hr = VariableSetVersion(pVariables, BURN_BUNDLE_VERSION, pRegistration->pVersion, TRUE); 449 hr = VariableSetVersion(pVariables, BURN_BUNDLE_VERSION, pRegistration->pVersion, TRUE);
446 ExitOnFailure(hr, "Failed to overwrite the bundle tag built-in variable."); 450 ExitOnFailure(hr, "Failed to overwrite the bundle version built-in variable.");
451
452 hr = VariableSetNumeric(pVariables, BURN_REBOOT_PENDING, IsBundleRebootPending(pRegistration) || IsWuRebootPending(), TRUE);
453 ExitOnFailure(hr, "Failed to overwrite the bundle reboot-pending built-in variable.");
447 454
448LExit: 455LExit:
449 ReleaseStr(sczBundleManufacturer); 456 ReleaseStr(sczBundleManufacturer);
@@ -491,17 +498,10 @@ extern "C" HRESULT RegistrationDetectResumeType(
491 ) 498 )
492{ 499{
493 HRESULT hr = S_OK; 500 HRESULT hr = S_OK;
494 LPWSTR sczRebootRequiredKey = NULL;
495 HKEY hkRebootRequired = NULL;
496 HKEY hkRegistration = NULL; 501 HKEY hkRegistration = NULL;
497 DWORD dwResume = 0; 502 DWORD dwResume = 0;
498 503
499 // Check to see if a restart is pending for this bundle. 504 if (IsBundleRebootPending(pRegistration))
500 hr = StrAllocFormatted(&sczRebootRequiredKey, REGISTRY_REBOOT_PENDING_FORMAT, pRegistration->sczRegistrationKey);
501 ExitOnFailure(hr, "Failed to format pending restart registry key to read.");
502
503 hr = RegOpen(pRegistration->hkRoot, sczRebootRequiredKey, KEY_QUERY_VALUE, &hkRebootRequired);
504 if (SUCCEEDED(hr))
505 { 505 {
506 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_REBOOT_PENDING; 506 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_REBOOT_PENDING;
507 ExitFunction1(hr = S_OK); 507 ExitFunction1(hr = S_OK);
@@ -554,8 +554,6 @@ extern "C" HRESULT RegistrationDetectResumeType(
554 554
555LExit: 555LExit:
556 ReleaseRegKey(hkRegistration); 556 ReleaseRegKey(hkRegistration);
557 ReleaseRegKey(hkRebootRequired);
558 ReleaseStr(sczRebootRequiredKey);
559 557
560 return hr; 558 return hr;
561} 559}
@@ -1591,3 +1589,46 @@ LExit:
1591 1589
1592 return hr; 1590 return hr;
1593} 1591}
1592
1593static BOOL IsWuRebootPending()
1594{
1595 HRESULT hr = S_OK;
1596 BOOL fRebootPending = FALSE;
1597
1598 // Do a best effort to ask WU if a reboot is required. If anything goes
1599 // wrong then let's pretend a reboot is not required.
1600 hr = ::CoInitialize(NULL);
1601 if (SUCCEEDED(hr) || RPC_E_CHANGED_MODE == hr)
1602 {
1603 hr = WuaRestartRequired(&fRebootPending);
1604 if (FAILED(hr))
1605 {
1606 fRebootPending = FALSE;
1607 }
1608
1609 ::CoUninitialize();
1610 }
1611
1612 return fRebootPending;
1613}
1614
1615static BOOL IsBundleRebootPending(BURN_REGISTRATION* pRegistration)
1616{
1617 HRESULT hr = S_OK;
1618 LPWSTR sczRebootRequiredKey = NULL;
1619 HKEY hkRebootRequired = NULL;
1620 BOOL fBundleRebootPending = FALSE;
1621
1622 // Check to see if a restart is pending for this bundle.
1623 hr = StrAllocFormatted(&sczRebootRequiredKey, REGISTRY_REBOOT_PENDING_FORMAT, pRegistration->sczRegistrationKey);
1624 ExitOnFailure(hr, "Failed to format pending restart registry key to read.");
1625
1626 hr = RegOpen(pRegistration->hkRoot, sczRebootRequiredKey, KEY_QUERY_VALUE, &hkRebootRequired);
1627 fBundleRebootPending = SUCCEEDED(hr);
1628
1629LExit:
1630 ReleaseStr(sczRebootRequiredKey);
1631 ReleaseRegKey(hkRebootRequired);
1632
1633 return fBundleRebootPending;
1634}
diff --git a/src/engine/variable.cpp b/src/engine/variable.cpp
index fed23151..d0c67504 100644
--- a/src/engine/variable.cpp
+++ b/src/engine/variable.cpp
@@ -133,10 +133,6 @@ static HRESULT InitializeVariablePrivileged(
133 __in DWORD_PTR dwpData, 133 __in DWORD_PTR dwpData,
134 __inout BURN_VARIANT* pValue 134 __inout BURN_VARIANT* pValue
135 ); 135 );
136static HRESULT InitializeVariableRebootPending(
137 __in DWORD_PTR dwpData,
138 __inout BURN_VARIANT* pValue
139 );
140static HRESULT InitializeSystemLanguageID( 136static HRESULT InitializeSystemLanguageID(
141 __in DWORD_PTR dwpData, 137 __in DWORD_PTR dwpData,
142 __inout BURN_VARIANT* pValue 138 __inout BURN_VARIANT* pValue
@@ -247,7 +243,6 @@ extern "C" HRESULT VariableInitialize(
247#endif 243#endif
248 {L"ProgramFiles6432Folder", InitializeVariable6432Folder, CSIDL_PROGRAM_FILES}, 244 {L"ProgramFiles6432Folder", InitializeVariable6432Folder, CSIDL_PROGRAM_FILES},
249 {L"ProgramMenuFolder", InitializeVariableCsidlFolder, CSIDL_PROGRAMS}, 245 {L"ProgramMenuFolder", InitializeVariableCsidlFolder, CSIDL_PROGRAMS},
250 {L"RebootPending", InitializeVariableRebootPending, 0},
251 {L"SendToFolder", InitializeVariableCsidlFolder, CSIDL_SENDTO}, 246 {L"SendToFolder", InitializeVariableCsidlFolder, CSIDL_SENDTO},
252 {L"ServicePackLevel", InitializeVariableVersionNT, OS_INFO_VARIABLE_ServicePackLevel}, 247 {L"ServicePackLevel", InitializeVariableVersionNT, OS_INFO_VARIABLE_ServicePackLevel},
253 {L"StartMenuFolder", InitializeVariableCsidlFolder, CSIDL_STARTMENU}, 248 {L"StartMenuFolder", InitializeVariableCsidlFolder, CSIDL_STARTMENU},
@@ -2031,44 +2026,6 @@ LExit:
2031 return hr; 2026 return hr;
2032} 2027}
2033 2028
2034static HRESULT InitializeVariableRebootPending(
2035 __in DWORD_PTR dwpData,
2036 __inout BURN_VARIANT* pValue
2037 )
2038{
2039 UNREFERENCED_PARAMETER(dwpData);
2040
2041 HRESULT hr = S_OK;
2042 BOOL fRebootPending = FALSE;
2043 BOOL fComInitialized = FALSE;
2044
2045 // Do a best effort to ask WU if a reboot is required. If anything goes
2046 // wrong then let's pretend a reboot is not required.
2047 hr = ::CoInitialize(NULL);
2048 if (SUCCEEDED(hr) || RPC_E_CHANGED_MODE == hr)
2049 {
2050 fComInitialized = TRUE;
2051
2052 hr = WuaRestartRequired(&fRebootPending);
2053 if (FAILED(hr))
2054 {
2055 fRebootPending = FALSE;
2056 hr = S_OK;
2057 }
2058 }
2059
2060 hr = BVariantSetNumeric(pValue, fRebootPending);
2061 ExitOnFailure(hr, "Failed to set reboot pending variant value.");
2062
2063LExit:
2064 if (fComInitialized)
2065 {
2066 ::CoUninitialize();
2067 }
2068
2069 return hr;
2070}
2071
2072static HRESULT InitializeSystemLanguageID( 2029static HRESULT InitializeSystemLanguageID(
2073 __in DWORD_PTR dwpData, 2030 __in DWORD_PTR dwpData,
2074 __inout BURN_VARIANT* pValue 2031 __inout BURN_VARIANT* pValue
diff --git a/src/test/BurnUnitTest/RegistrationTest.cpp b/src/test/BurnUnitTest/RegistrationTest.cpp
index 1687385b..883a1258 100644
--- a/src/test/BurnUnitTest/RegistrationTest.cpp
+++ b/src/test/BurnUnitTest/RegistrationTest.cpp
@@ -73,6 +73,7 @@ namespace Bootstrapper
73 BURN_LOGGING logging = { }; 73 BURN_LOGGING logging = { };
74 BURN_PACKAGES packages = { }; 74 BURN_PACKAGES packages = { };
75 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}")); 75 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"));
76
76 try 77 try
77 { 78 {
78 // set mock API's 79 // set mock API's
@@ -261,6 +262,115 @@ namespace Bootstrapper
261 } 262 }
262 263
263 [Fact] 264 [Fact]
265 void RegisterVariablesTest()
266 {
267 HRESULT hr = S_OK;
268 IXMLDOMElement* pixeBundle = NULL;
269 LPWSTR sczCurrentProcess = NULL;
270 BURN_VARIABLES variables = { };
271 BURN_USER_EXPERIENCE userExperience = { };
272 BOOTSTRAPPER_COMMAND command = { };
273 BURN_REGISTRATION registration = { };
274 BURN_LOGGING logging = { };
275 BURN_PACKAGES packages = { };
276 String^ cacheDirectory = Path::Combine(Path::Combine(Environment::GetFolderPath(Environment::SpecialFolder::LocalApplicationData), gcnew String(L"Package Cache")), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"));
277 try
278 {
279 // set mock API's
280 RegFunctionOverride(RegistrationTest_RegCreateKeyExW, RegistrationTest_RegOpenKeyExW, RegistrationTest_RegDeleteKeyExW, NULL, NULL, NULL, NULL, NULL, NULL);
281
282 Registry::CurrentUser->CreateSubKey(gcnew String(HKCU_PATH));
283
284 logging.sczPath = L"BurnUnitTest.txt";
285
286 LPCWSTR wzDocument =
287 L"<Bundle>"
288 L" <UX>"
289 L" <Payload Id='ux.dll' FilePath='ux.dll' Packaging='embedded' SourcePath='ux.dll' Hash='000000000000' />"
290 L" </UX>"
291 L" <Registration Id='{D54F896D-1952-43e6-9C67-B5652240618C}' UpgradeCode='{D54F896D-1952-43e6-9C67-B5652240618C}' Tag='foo' ProviderKey='bar' Version='1.0.0.0' ExecutableName='setup.exe' PerMachine='no'>"
292 L" <Arp Register='yes' Publisher='WiX Toolset' DisplayName='Product1' DisplayVersion='1.0.0.0' />"
293 L" </Registration>"
294 L"</Bundle>";
295
296 // load XML document
297 LoadBundleXmlHelper(wzDocument, &pixeBundle);
298
299 hr = VariableInitialize(&variables);
300 TestThrowOnFailure(hr, L"Failed to initialize variables.");
301
302 hr = UserExperienceParseFromXml(&userExperience, pixeBundle);
303 TestThrowOnFailure(hr, L"Failed to parse UX from XML.");
304
305 hr = RegistrationParseFromXml(&registration, pixeBundle);
306 TestThrowOnFailure(hr, L"Failed to parse registration from XML.");
307
308 hr = PlanSetResumeCommand(&registration, BOOTSTRAPPER_ACTION_INSTALL, &command, &logging);
309 TestThrowOnFailure(hr, L"Failed to set registration resume command.");
310
311 hr = PathForCurrentProcess(&sczCurrentProcess, NULL);
312 TestThrowOnFailure(hr, L"Failed to get current process path.");
313
314 //
315 // install
316 //
317
318 // write registration
319 hr = RegistrationSessionBegin(sczCurrentProcess, &registration, &variables, &userExperience, BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER, 0);
320 TestThrowOnFailure(hr, L"Failed to register bundle.");
321
322 // verify that registration was created
323 Assert::Equal(Int32(BURN_RESUME_MODE_ACTIVE), (Int32)Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
324 Assert::Equal<String^>(String::Concat(L"\"", Path::Combine(cacheDirectory, gcnew String(L"setup.exe")), L"\" /burn.runonce"), (String^)Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
325
326 // complete registration
327 hr = RegistrationSessionEnd(&registration, &packages, BURN_RESUME_MODE_ARP, BOOTSTRAPPER_APPLY_RESTART_REQUIRED, BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER);
328 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
329
330 // verify that registration variables were updated
331 registration.fInstalled = TRUE;
332
333 hr = RegistrationSetVariables(&registration, &variables);
334 TestThrowOnFailure(hr, L"Failed to set registration variables.");
335
336 Assert::Equal(1ll, VariableGetNumericHelper(&variables, BURN_BUNDLE_INSTALLED));
337 Assert::Equal(1ll, VariableGetNumericHelper(&variables, BURN_REBOOT_PENDING));
338 Assert::Equal<String^>(gcnew String(L"foo"), VariableGetStringHelper(&variables, BURN_BUNDLE_TAG));
339 Assert::Equal<String^>(gcnew String(L"bar"), VariableGetStringHelper(&variables, BURN_BUNDLE_PROVIDER_KEY));
340 Assert::Equal<String^>(gcnew String(L"1.0.0.0"), VariableGetVersionHelper(&variables, BURN_BUNDLE_VERSION));
341
342 //
343 // uninstall
344 //
345
346 // delete registration
347 hr = RegistrationSessionEnd(&registration, &packages, BURN_RESUME_MODE_NONE, BOOTSTRAPPER_APPLY_RESTART_NONE, BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER);
348 TestThrowOnFailure(hr, L"Failed to unregister bundle.");
349
350 // verify that registration was removed
351 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Resume"), nullptr));
352 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_UNINSTALL_KEY), gcnew String(L"Installed"), nullptr));
353 Assert::Equal((Object^)nullptr, Registry::GetValue(gcnew String(TEST_RUN_KEY), gcnew String(L"{D54F896D-1952-43e6-9C67-B5652240618C}"), nullptr));
354 }
355 finally
356 {
357 ReleaseStr(sczCurrentProcess);
358 ReleaseObject(pixeBundle);
359 UserExperienceUninitialize(&userExperience);
360 RegistrationUninitialize(&registration);
361 VariablesUninitialize(&variables);
362
363 Registry::CurrentUser->DeleteSubKeyTree(gcnew String(ROOT_PATH));
364 if (Directory::Exists(cacheDirectory))
365 {
366 Directory::Delete(cacheDirectory, true);
367 }
368
369 RegFunctionOverride(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
370 }
371 }
372
373 [Fact]
264 void RegisterArpFullTest() 374 void RegisterArpFullTest()
265 { 375 {
266 HRESULT hr = S_OK; 376 HRESULT hr = S_OK;