aboutsummaryrefslogtreecommitdiff
path: root/src/burn/engine/registration.cpp
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-04-22 17:06:54 -0700
committerRob Mensching <rob@firegiant.com>2021-04-29 16:36:06 -0700
commitaf10c45d7b3a44af0b461a557847fe03263dcc10 (patch)
tree6a5c1532304782c36ffe4200b38f3afb76789a43 /src/burn/engine/registration.cpp
parent9c2aed97299fb96aeee3f1471ce40225437aaecf (diff)
downloadwix-af10c45d7b3a44af0b461a557847fe03263dcc10.tar.gz
wix-af10c45d7b3a44af0b461a557847fe03263dcc10.tar.bz2
wix-af10c45d7b3a44af0b461a557847fe03263dcc10.zip
Move burn into burn
Diffstat (limited to 'src/burn/engine/registration.cpp')
-rw-r--r--src/burn/engine/registration.cpp1702
1 files changed, 1702 insertions, 0 deletions
diff --git a/src/burn/engine/registration.cpp b/src/burn/engine/registration.cpp
new file mode 100644
index 00000000..19da543c
--- /dev/null
+++ b/src/burn/engine/registration.cpp
@@ -0,0 +1,1702 @@
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#include "precomp.h"
4
5
6// constants
7
8const LPCWSTR REGISTRY_RUN_KEY = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
9const LPCWSTR REGISTRY_RUN_ONCE_KEY = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce";
10const LPCWSTR REGISTRY_REBOOT_PENDING_FORMAT = L"%ls.RebootRequired";
11const LPCWSTR REGISTRY_BUNDLE_INSTALLED = L"Installed";
12const LPCWSTR REGISTRY_BUNDLE_DISPLAY_ICON = L"DisplayIcon";
13const LPCWSTR REGISTRY_BUNDLE_DISPLAY_VERSION = L"DisplayVersion";
14const LPCWSTR REGISTRY_BUNDLE_ESTIMATED_SIZE = L"EstimatedSize";
15const LPCWSTR REGISTRY_BUNDLE_PUBLISHER = L"Publisher";
16const LPCWSTR REGISTRY_BUNDLE_HELP_LINK = L"HelpLink";
17const LPCWSTR REGISTRY_BUNDLE_HELP_TELEPHONE = L"HelpTelephone";
18const LPCWSTR REGISTRY_BUNDLE_URL_INFO_ABOUT = L"URLInfoAbout";
19const LPCWSTR REGISTRY_BUNDLE_URL_UPDATE_INFO = L"URLUpdateInfo";
20const LPCWSTR REGISTRY_BUNDLE_PARENT_DISPLAY_NAME = L"ParentDisplayName";
21const LPCWSTR REGISTRY_BUNDLE_PARENT_KEY_NAME = L"ParentKeyName";
22const LPCWSTR REGISTRY_BUNDLE_COMMENTS = L"Comments";
23const LPCWSTR REGISTRY_BUNDLE_CONTACT = L"Contact";
24const LPCWSTR REGISTRY_BUNDLE_NO_MODIFY = L"NoModify";
25const LPCWSTR REGISTRY_BUNDLE_MODIFY_PATH = L"ModifyPath";
26const LPCWSTR REGISTRY_BUNDLE_NO_ELEVATE_ON_MODIFY = L"NoElevateOnModify";
27const LPCWSTR REGISTRY_BUNDLE_NO_REMOVE = L"NoRemove";
28const LPCWSTR REGISTRY_BUNDLE_SYSTEM_COMPONENT = L"SystemComponent";
29const LPCWSTR REGISTRY_BUNDLE_QUIET_UNINSTALL_STRING = L"QuietUninstallString";
30const LPCWSTR REGISTRY_BUNDLE_UNINSTALL_STRING = L"UninstallString";
31const LPCWSTR REGISTRY_BUNDLE_RESUME_COMMAND_LINE = L"BundleResumeCommandLine";
32const LPCWSTR REGISTRY_BUNDLE_VERSION_MAJOR = L"VersionMajor";
33const LPCWSTR REGISTRY_BUNDLE_VERSION_MINOR = L"VersionMinor";
34const LPCWSTR SWIDTAG_FOLDER = L"swidtag";
35
36// internal function declarations
37
38static HRESULT ParseSoftwareTagsFromXml(
39 __in IXMLDOMNode* pixnRegistrationNode,
40 __out BURN_SOFTWARE_TAG** prgSoftwareTags,
41 __out DWORD* pcSoftwareTags
42 );
43static HRESULT SetPaths(
44 __in BURN_REGISTRATION* pRegistration
45 );
46static HRESULT GetBundleManufacturer(
47 __in BURN_REGISTRATION* pRegistration,
48 __in BURN_VARIABLES* pVariables,
49 __out LPWSTR* psczBundleManufacturer
50 );
51static HRESULT GetBundleName(
52 __in BURN_REGISTRATION* pRegistration,
53 __in BURN_VARIABLES* pVariables,
54 __out LPWSTR* psczBundleName
55 );
56static HRESULT UpdateResumeMode(
57 __in BURN_REGISTRATION* pRegistration,
58 __in HKEY hkRegistration,
59 __in BURN_RESUME_MODE resumeMode,
60 __in BOOL fRestartInitiated
61 );
62static HRESULT ParseRelatedCodes(
63 __in BURN_REGISTRATION* pRegistration,
64 __in IXMLDOMNode* pixnBundle
65 );
66static HRESULT FormatUpdateRegistrationKey(
67 __in BURN_REGISTRATION* pRegistration,
68 __out_z LPWSTR* psczKey
69 );
70static HRESULT WriteSoftwareTags(
71 __in BURN_VARIABLES* pVariables,
72 __in BURN_SOFTWARE_TAGS* pSoftwareTags
73 );
74static HRESULT RemoveSoftwareTags(
75 __in BURN_VARIABLES* pVariables,
76 __in BURN_SOFTWARE_TAGS* pSoftwareTags
77 );
78static HRESULT WriteUpdateRegistration(
79 __in BURN_REGISTRATION* pRegistration,
80 __in BURN_VARIABLES* pVariables
81 );
82static HRESULT RemoveUpdateRegistration(
83 __in BURN_REGISTRATION* pRegistration
84 );
85static HRESULT RegWriteStringVariable(
86 __in HKEY hkKey,
87 __in BURN_VARIABLES* pVariables,
88 __in LPCWSTR wzVariable,
89 __in LPCWSTR wzName
90 );
91static HRESULT UpdateBundleNameRegistration(
92 __in BURN_REGISTRATION* pRegistration,
93 __in BURN_VARIABLES* pVariables,
94 __in HKEY hkRegistration
95 );
96static BOOL IsWuRebootPending();
97static BOOL IsBundleRebootPending(
98 __in BURN_REGISTRATION* pRegistration
99);
100static BOOL IsRegistryRebootPending();
101
102// function definitions
103
104/*******************************************************************
105 RegistrationParseFromXml - Parses registration information from manifest.
106
107*******************************************************************/
108extern "C" HRESULT RegistrationParseFromXml(
109 __in BURN_REGISTRATION* pRegistration,
110 __in IXMLDOMNode* pixnBundle
111 )
112{
113 HRESULT hr = S_OK;
114 IXMLDOMNode* pixnRegistrationNode = NULL;
115 IXMLDOMNode* pixnArpNode = NULL;
116 IXMLDOMNode* pixnUpdateNode = NULL;
117 LPWSTR scz = NULL;
118
119 // select registration node
120 hr = XmlSelectSingleNode(pixnBundle, L"Registration", &pixnRegistrationNode);
121 if (S_FALSE == hr)
122 {
123 hr = E_NOTFOUND;
124 }
125 ExitOnFailure(hr, "Failed to select registration node.");
126
127 // @Id
128 hr = XmlGetAttributeEx(pixnRegistrationNode, L"Id", &pRegistration->sczId);
129 ExitOnFailure(hr, "Failed to get @Id.");
130
131 // @Tag
132 hr = XmlGetAttributeEx(pixnRegistrationNode, L"Tag", &pRegistration->sczTag);
133 ExitOnFailure(hr, "Failed to get @Tag.");
134
135 hr = ParseRelatedCodes(pRegistration, pixnBundle);
136 ExitOnFailure(hr, "Failed to parse related bundles");
137
138 // @Version
139 hr = XmlGetAttributeEx(pixnRegistrationNode, L"Version", &scz);
140 ExitOnFailure(hr, "Failed to get @Version.");
141
142 hr = VerParseVersion(scz, 0, FALSE, &pRegistration->pVersion);
143 ExitOnFailure(hr, "Failed to parse @Version: %ls", scz);
144
145 if (pRegistration->pVersion->fInvalid)
146 {
147 LogId(REPORT_WARNING, MSG_MANIFEST_INVALID_VERSION, scz);
148 }
149
150 // @ProviderKey
151 hr = XmlGetAttributeEx(pixnRegistrationNode, L"ProviderKey", &pRegistration->sczProviderKey);
152 ExitOnFailure(hr, "Failed to get @ProviderKey.");
153
154 // @ExecutableName
155 hr = XmlGetAttributeEx(pixnRegistrationNode, L"ExecutableName", &pRegistration->sczExecutableName);
156 ExitOnFailure(hr, "Failed to get @ExecutableName.");
157
158 // @PerMachine
159 hr = XmlGetYesNoAttribute(pixnRegistrationNode, L"PerMachine", &pRegistration->fPerMachine);
160 ExitOnFailure(hr, "Failed to get @PerMachine.");
161
162 // select ARP node
163 hr = XmlSelectSingleNode(pixnRegistrationNode, L"Arp", &pixnArpNode);
164 if (S_FALSE != hr)
165 {
166 ExitOnFailure(hr, "Failed to select ARP node.");
167
168 // @Register
169 hr = XmlGetYesNoAttribute(pixnArpNode, L"Register", &pRegistration->fRegisterArp);
170 ExitOnFailure(hr, "Failed to get @Register.");
171
172 // @DisplayName
173 hr = XmlGetAttributeEx(pixnArpNode, L"DisplayName", &pRegistration->sczDisplayName);
174 if (E_NOTFOUND != hr)
175 {
176 ExitOnFailure(hr, "Failed to get @DisplayName.");
177 }
178
179 // @DisplayVersion
180 hr = XmlGetAttributeEx(pixnArpNode, L"DisplayVersion", &pRegistration->sczDisplayVersion);
181 if (E_NOTFOUND != hr)
182 {
183 ExitOnFailure(hr, "Failed to get @DisplayVersion.");
184 }
185
186 // @Publisher
187 hr = XmlGetAttributeEx(pixnArpNode, L"Publisher", &pRegistration->sczPublisher);
188 if (E_NOTFOUND != hr)
189 {
190 ExitOnFailure(hr, "Failed to get @Publisher.");
191 }
192
193 // @HelpLink
194 hr = XmlGetAttributeEx(pixnArpNode, L"HelpLink", &pRegistration->sczHelpLink);
195 if (E_NOTFOUND != hr)
196 {
197 ExitOnFailure(hr, "Failed to get @HelpLink.");
198 }
199
200 // @HelpTelephone
201 hr = XmlGetAttributeEx(pixnArpNode, L"HelpTelephone", &pRegistration->sczHelpTelephone);
202 if (E_NOTFOUND != hr)
203 {
204 ExitOnFailure(hr, "Failed to get @HelpTelephone.");
205 }
206
207 // @AboutUrl
208 hr = XmlGetAttributeEx(pixnArpNode, L"AboutUrl", &pRegistration->sczAboutUrl);
209 if (E_NOTFOUND != hr)
210 {
211 ExitOnFailure(hr, "Failed to get @AboutUrl.");
212 }
213
214 // @UpdateUrl
215 hr = XmlGetAttributeEx(pixnArpNode, L"UpdateUrl", &pRegistration->sczUpdateUrl);
216 if (E_NOTFOUND != hr)
217 {
218 ExitOnFailure(hr, "Failed to get @UpdateUrl.");
219 }
220
221 // @ParentDisplayName
222 hr = XmlGetAttributeEx(pixnArpNode, L"ParentDisplayName", &pRegistration->sczParentDisplayName);
223 if (E_NOTFOUND != hr)
224 {
225 ExitOnFailure(hr, "Failed to get @ParentDisplayName.");
226 }
227
228 // @Comments
229 hr = XmlGetAttributeEx(pixnArpNode, L"Comments", &pRegistration->sczComments);
230 if (E_NOTFOUND != hr)
231 {
232 ExitOnFailure(hr, "Failed to get @Comments.");
233 }
234
235 // @Contact
236 hr = XmlGetAttributeEx(pixnArpNode, L"Contact", &pRegistration->sczContact);
237 if (E_NOTFOUND != hr)
238 {
239 ExitOnFailure(hr, "Failed to get @Contact.");
240 }
241
242 // @DisableModify
243 hr = XmlGetAttributeEx(pixnArpNode, L"DisableModify", &scz);
244 if (SUCCEEDED(hr))
245 {
246 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"button", -1))
247 {
248 pRegistration->modify = BURN_REGISTRATION_MODIFY_DISABLE_BUTTON;
249 }
250 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"yes", -1))
251 {
252 pRegistration->modify = BURN_REGISTRATION_MODIFY_DISABLE;
253 }
254 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"no", -1))
255 {
256 pRegistration->modify = BURN_REGISTRATION_MODIFY_ENABLED;
257 }
258 else
259 {
260 hr = E_UNEXPECTED;
261 ExitOnRootFailure(hr, "Invalid modify disabled type: %ls", scz);
262 }
263 }
264 else if (E_NOTFOUND == hr)
265 {
266 pRegistration->modify = BURN_REGISTRATION_MODIFY_ENABLED;
267 hr = S_OK;
268 }
269 ExitOnFailure(hr, "Failed to get @DisableModify.");
270
271 // @DisableRemove
272 hr = XmlGetYesNoAttribute(pixnArpNode, L"DisableRemove", &pRegistration->fNoRemove);
273 if (E_NOTFOUND != hr)
274 {
275 ExitOnFailure(hr, "Failed to get @DisableRemove.");
276 pRegistration->fNoRemoveDefined = TRUE;
277 }
278 }
279
280 hr = ParseSoftwareTagsFromXml(pixnRegistrationNode, &pRegistration->softwareTags.rgSoftwareTags, &pRegistration->softwareTags.cSoftwareTags);
281 ExitOnFailure(hr, "Failed to parse software tag.");
282
283 // select Update node
284 hr = XmlSelectSingleNode(pixnRegistrationNode, L"Update", &pixnUpdateNode);
285 if (S_FALSE != hr)
286 {
287 ExitOnFailure(hr, "Failed to select Update node.");
288
289 pRegistration->update.fRegisterUpdate = TRUE;
290
291 // @Manufacturer
292 hr = XmlGetAttributeEx(pixnUpdateNode, L"Manufacturer", &pRegistration->update.sczManufacturer);
293 ExitOnFailure(hr, "Failed to get @Manufacturer.");
294
295 // @Department
296 hr = XmlGetAttributeEx(pixnUpdateNode, L"Department", &pRegistration->update.sczDepartment);
297 if (E_NOTFOUND != hr)
298 {
299 ExitOnFailure(hr, "Failed to get @Department.");
300 }
301
302 // @ProductFamily
303 hr = XmlGetAttributeEx(pixnUpdateNode, L"ProductFamily", &pRegistration->update.sczProductFamily);
304 if (E_NOTFOUND != hr)
305 {
306 ExitOnFailure(hr, "Failed to get @ProductFamily.");
307 }
308
309 // @Name
310 hr = XmlGetAttributeEx(pixnUpdateNode, L"Name", &pRegistration->update.sczName);
311 ExitOnFailure(hr, "Failed to get @Name.");
312
313 // @Classification
314 hr = XmlGetAttributeEx(pixnUpdateNode, L"Classification", &pRegistration->update.sczClassification);
315 ExitOnFailure(hr, "Failed to get @Classification.");
316 }
317
318 hr = SetPaths(pRegistration);
319 ExitOnFailure(hr, "Failed to set registration paths.");
320
321LExit:
322 ReleaseObject(pixnRegistrationNode);
323 ReleaseObject(pixnArpNode);
324 ReleaseObject(pixnUpdateNode);
325 ReleaseStr(scz);
326
327 return hr;
328}
329
330/*******************************************************************
331 RegistrationUninitialize -
332
333*******************************************************************/
334extern "C" void RegistrationUninitialize(
335 __in BURN_REGISTRATION* pRegistration
336 )
337{
338 ReleaseStr(pRegistration->sczId);
339 ReleaseStr(pRegistration->sczTag);
340
341 for (DWORD i = 0; i < pRegistration->cDetectCodes; ++i)
342 {
343 ReleaseStr(pRegistration->rgsczDetectCodes[i]);
344 }
345 ReleaseMem(pRegistration->rgsczDetectCodes);
346
347 for (DWORD i = 0; i < pRegistration->cUpgradeCodes; ++i)
348 {
349 ReleaseStr(pRegistration->rgsczUpgradeCodes[i]);
350 }
351 ReleaseMem(pRegistration->rgsczUpgradeCodes);
352
353 for (DWORD i = 0; i < pRegistration->cAddonCodes; ++i)
354 {
355 ReleaseStr(pRegistration->rgsczAddonCodes[i]);
356 }
357 ReleaseMem(pRegistration->rgsczAddonCodes);
358
359 for (DWORD i = 0; i < pRegistration->cPatchCodes; ++i)
360 {
361 ReleaseStr(pRegistration->rgsczPatchCodes[i]);
362 }
363 ReleaseMem(pRegistration->rgsczPatchCodes);
364
365 ReleaseStr(pRegistration->sczProviderKey);
366 ReleaseStr(pRegistration->sczActiveParent);
367 ReleaseStr(pRegistration->sczExecutableName);
368
369 ReleaseStr(pRegistration->sczRegistrationKey);
370 ReleaseStr(pRegistration->sczCacheExecutablePath);
371 ReleaseStr(pRegistration->sczResumeCommandLine);
372 ReleaseStr(pRegistration->sczStateFile);
373
374 ReleaseStr(pRegistration->sczDisplayName);
375 ReleaseStr(pRegistration->sczDisplayVersion);
376 ReleaseStr(pRegistration->sczPublisher);
377 ReleaseStr(pRegistration->sczHelpLink);
378 ReleaseStr(pRegistration->sczHelpTelephone);
379 ReleaseStr(pRegistration->sczAboutUrl);
380 ReleaseStr(pRegistration->sczUpdateUrl);
381 ReleaseStr(pRegistration->sczParentDisplayName);
382 ReleaseStr(pRegistration->sczComments);
383 ReleaseStr(pRegistration->sczContact);
384
385 ReleaseStr(pRegistration->update.sczManufacturer);
386 ReleaseStr(pRegistration->update.sczDepartment);
387 ReleaseStr(pRegistration->update.sczProductFamily);
388 ReleaseStr(pRegistration->update.sczName);
389 ReleaseStr(pRegistration->update.sczClassification);
390
391 if (pRegistration->softwareTags.rgSoftwareTags)
392 {
393 for (DWORD i = 0; i < pRegistration->softwareTags.cSoftwareTags; ++i)
394 {
395 ReleaseStr(pRegistration->softwareTags.rgSoftwareTags[i].sczFilename);
396 ReleaseStr(pRegistration->softwareTags.rgSoftwareTags[i].sczRegid);
397 ReleaseStr(pRegistration->softwareTags.rgSoftwareTags[i].sczPath);
398 ReleaseStr(pRegistration->softwareTags.rgSoftwareTags[i].sczTag);
399 }
400
401 MemFree(pRegistration->softwareTags.rgSoftwareTags);
402 }
403
404 ReleaseStr(pRegistration->sczDetectedProviderKeyBundleId);
405 ReleaseStr(pRegistration->sczAncestors);
406 ReleaseStr(pRegistration->sczBundlePackageAncestors);
407 RelatedBundlesUninitialize(&pRegistration->relatedBundles);
408
409 // clear struct
410 memset(pRegistration, 0, sizeof(BURN_REGISTRATION));
411}
412
413/*******************************************************************
414 RegistrationSetVariables - Initializes bundle variables that map to
415 registration entities.
416
417*******************************************************************/
418extern "C" HRESULT RegistrationSetVariables(
419 __in BURN_REGISTRATION* pRegistration,
420 __in BURN_VARIABLES* pVariables
421 )
422{
423 HRESULT hr = S_OK;
424 LPWSTR sczBundleManufacturer = NULL;
425 LPWSTR sczBundleName = NULL;
426
427 if (pRegistration->fInstalled)
428 {
429 hr = VariableSetNumeric(pVariables, BURN_BUNDLE_INSTALLED, 1, TRUE);
430 ExitOnFailure(hr, "Failed to set the bundle installed built-in variable.");
431 }
432
433 // Ensure the registration bundle name is updated.
434 hr = GetBundleName(pRegistration, pVariables, &sczBundleName);
435 ExitOnFailure(hr, "Failed to initialize bundle name.");
436
437 hr = GetBundleManufacturer(pRegistration, pVariables, &sczBundleName);
438 ExitOnFailure(hr, "Failed to initialize bundle manufacturer.");
439
440 if (pRegistration->sczActiveParent && *pRegistration->sczActiveParent)
441 {
442 hr = VariableSetString(pVariables, BURN_BUNDLE_ACTIVE_PARENT, pRegistration->sczActiveParent, TRUE, FALSE);
443 ExitOnFailure(hr, "Failed to overwrite the bundle active parent built-in variable.");
444 }
445
446 hr = VariableSetString(pVariables, BURN_BUNDLE_PROVIDER_KEY, pRegistration->sczProviderKey, TRUE, FALSE);
447 ExitOnFailure(hr, "Failed to overwrite the bundle provider key built-in variable.");
448
449 hr = VariableSetString(pVariables, BURN_BUNDLE_TAG, pRegistration->sczTag, TRUE, FALSE);
450 ExitOnFailure(hr, "Failed to overwrite the bundle tag built-in variable.");
451
452 hr = VariableSetVersion(pVariables, BURN_BUNDLE_VERSION, pRegistration->pVersion, TRUE);
453 ExitOnFailure(hr, "Failed to overwrite the bundle version built-in variable.");
454
455 hr = VariableSetNumeric(pVariables, BURN_REBOOT_PENDING, IsBundleRebootPending(pRegistration) || IsWuRebootPending() || IsRegistryRebootPending(), TRUE);
456 ExitOnFailure(hr, "Failed to overwrite the bundle reboot-pending built-in variable.");
457
458LExit:
459 ReleaseStr(sczBundleManufacturer);
460 ReleaseStr(sczBundleName);
461
462 return hr;
463}
464
465extern "C" HRESULT RegistrationDetectInstalled(
466 __in BURN_REGISTRATION* pRegistration
467 )
468{
469 HRESULT hr = S_OK;
470 HKEY hkRegistration = NULL;
471 DWORD dwInstalled = 0;
472
473 pRegistration->fCached = FileExistsEx(pRegistration->sczCacheExecutablePath, NULL);
474
475 // open registration key
476 hr = RegOpen(pRegistration->hkRoot, pRegistration->sczRegistrationKey, KEY_QUERY_VALUE, &hkRegistration);
477 if (SUCCEEDED(hr))
478 {
479 hr = RegReadNumber(hkRegistration, REGISTRY_BUNDLE_INSTALLED, &dwInstalled);
480 }
481
482 // Not finding the key or value is okay.
483 if (E_FILENOTFOUND == hr || E_PATHNOTFOUND == hr)
484 {
485 hr = S_OK;
486 }
487
488 pRegistration->fInstalled = (1 == dwInstalled);
489
490 ReleaseRegKey(hkRegistration);
491 return hr;
492}
493
494/*******************************************************************
495 RegistrationDetectResumeMode - Detects registration information on the system
496 to determine if a resume is taking place.
497
498*******************************************************************/
499extern "C" HRESULT RegistrationDetectResumeType(
500 __in BURN_REGISTRATION* pRegistration,
501 __out BOOTSTRAPPER_RESUME_TYPE* pResumeType
502 )
503{
504 HRESULT hr = S_OK;
505 HKEY hkRegistration = NULL;
506 DWORD dwResume = 0;
507
508 if (IsBundleRebootPending(pRegistration))
509 {
510 LogId(REPORT_STANDARD, MSG_PENDING_REBOOT_DETECTED, pRegistration->sczRegistrationKey);
511
512 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_REBOOT_PENDING;
513 ExitFunction1(hr = S_OK);
514 }
515
516 // open registration key
517 hr = RegOpen(pRegistration->hkRoot, pRegistration->sczRegistrationKey, KEY_QUERY_VALUE, &hkRegistration);
518 if (E_FILENOTFOUND == hr || E_PATHNOTFOUND == hr)
519 {
520 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_NONE;
521 ExitFunction1(hr = S_OK);
522 }
523 ExitOnFailure(hr, "Failed to open registration key.");
524
525 // read Resume value
526 hr = RegReadNumber(hkRegistration, L"Resume", &dwResume);
527 if (E_FILENOTFOUND == hr)
528 {
529 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_INVALID;
530 ExitFunction1(hr = S_OK);
531 }
532 ExitOnFailure(hr, "Failed to read Resume value.");
533
534 switch (dwResume)
535 {
536 case BURN_RESUME_MODE_ACTIVE:
537 // a previous run was interrupted
538 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_INTERRUPTED;
539 break;
540
541 case BURN_RESUME_MODE_SUSPEND:
542 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_SUSPEND;
543 break;
544
545 case BURN_RESUME_MODE_ARP:
546 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_ARP;
547 break;
548
549 case BURN_RESUME_MODE_REBOOT_PENDING:
550 // The volatile pending registry doesn't exist (checked above) which means
551 // the system was successfully restarted.
552 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_REBOOT;
553 break;
554
555 default:
556 // the value stored in the registry is not valid
557 *pResumeType = BOOTSTRAPPER_RESUME_TYPE_INVALID;
558 break;
559 }
560
561LExit:
562 ReleaseRegKey(hkRegistration);
563
564 return hr;
565}
566
567/*******************************************************************
568 RegistrationDetectRelatedBundles - finds the bundles with same
569 upgrade/detect/addon/patch codes.
570
571*******************************************************************/
572extern "C" HRESULT RegistrationDetectRelatedBundles(
573 __in BURN_REGISTRATION* pRegistration
574 )
575{
576 HRESULT hr = S_OK;
577
578 hr = RelatedBundlesInitializeForScope(TRUE, pRegistration, &pRegistration->relatedBundles);
579 ExitOnFailure(hr, "Failed to initialize per-machine related bundles.");
580
581 hr = RelatedBundlesInitializeForScope(FALSE, pRegistration, &pRegistration->relatedBundles);
582 ExitOnFailure(hr, "Failed to initialize per-user related bundles.");
583
584LExit:
585 return hr;
586}
587
588/*******************************************************************
589 RegistrationSessionBegin - Registers a run session on the system.
590
591*******************************************************************/
592extern "C" HRESULT RegistrationSessionBegin(
593 __in_z LPCWSTR wzEngineWorkingPath,
594 __in BURN_REGISTRATION* pRegistration,
595 __in BURN_VARIABLES* pVariables,
596 __in DWORD dwRegistrationOptions,
597 __in BURN_DEPENDENCY_REGISTRATION_ACTION dependencyRegistrationAction,
598 __in DWORD64 qwEstimatedSize
599 )
600{
601 HRESULT hr = S_OK;
602 DWORD dwSize = 0;
603 HKEY hkRegistration = NULL;
604 LPWSTR sczPublisher = NULL;
605
606 LogId(REPORT_VERBOSE, MSG_SESSION_BEGIN, pRegistration->sczRegistrationKey, dwRegistrationOptions, LoggingBoolToString(pRegistration->fDisableResume));
607
608 // Cache bundle executable.
609 if (dwRegistrationOptions & BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE)
610 {
611 hr = CacheCompleteBundle(pRegistration->fPerMachine, pRegistration->sczExecutableName, pRegistration->sczId, wzEngineWorkingPath
612#ifdef DEBUG
613 , pRegistration->sczCacheExecutablePath
614#endif
615 );
616 ExitOnFailure(hr, "Failed to cache bundle from path: %ls", wzEngineWorkingPath);
617 }
618
619 // create registration key
620 hr = RegCreate(pRegistration->hkRoot, pRegistration->sczRegistrationKey, KEY_WRITE, &hkRegistration);
621 ExitOnFailure(hr, "Failed to create registration key.");
622
623 // Write any ARP values and software tags.
624 if (dwRegistrationOptions & BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_REGISTRATION)
625 {
626 // Upgrade information
627 hr = RegWriteString(hkRegistration, BURN_REGISTRATION_REGISTRY_BUNDLE_CACHE_PATH, pRegistration->sczCacheExecutablePath);
628 ExitOnFailure(hr, "Failed to write %ls value.", BURN_REGISTRATION_REGISTRY_BUNDLE_CACHE_PATH);
629
630 hr = RegWriteStringArray(hkRegistration, BURN_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE, pRegistration->rgsczUpgradeCodes, pRegistration->cUpgradeCodes);
631 ExitOnFailure(hr, "Failed to write %ls value.", BURN_REGISTRATION_REGISTRY_BUNDLE_UPGRADE_CODE);
632
633 hr = RegWriteStringArray(hkRegistration, BURN_REGISTRATION_REGISTRY_BUNDLE_ADDON_CODE, pRegistration->rgsczAddonCodes, pRegistration->cAddonCodes);
634 ExitOnFailure(hr, "Failed to write %ls value.", BURN_REGISTRATION_REGISTRY_BUNDLE_ADDON_CODE);
635
636 hr = RegWriteStringArray(hkRegistration, BURN_REGISTRATION_REGISTRY_BUNDLE_DETECT_CODE, pRegistration->rgsczDetectCodes, pRegistration->cDetectCodes);
637 ExitOnFailure(hr, "Failed to write %ls value.", BURN_REGISTRATION_REGISTRY_BUNDLE_DETECT_CODE);
638
639 hr = RegWriteStringArray(hkRegistration, BURN_REGISTRATION_REGISTRY_BUNDLE_PATCH_CODE, pRegistration->rgsczPatchCodes, pRegistration->cPatchCodes);
640 ExitOnFailure(hr, "Failed to write %ls value.", BURN_REGISTRATION_REGISTRY_BUNDLE_PATCH_CODE);
641
642 hr = RegWriteString(hkRegistration, BURN_REGISTRATION_REGISTRY_BUNDLE_VERSION, pRegistration->pVersion->sczVersion);
643 ExitOnFailure(hr, "Failed to write %ls value.", BURN_REGISTRATION_REGISTRY_BUNDLE_VERSION);
644
645 hr = RegWriteNumber(hkRegistration, REGISTRY_BUNDLE_VERSION_MAJOR, pRegistration->pVersion->dwMajor);
646 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_VERSION_MAJOR);
647
648 hr = RegWriteNumber(hkRegistration, REGISTRY_BUNDLE_VERSION_MINOR, pRegistration->pVersion->dwMinor);
649 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_VERSION_MINOR);
650
651 if (pRegistration->sczProviderKey)
652 {
653 hr = RegWriteString(hkRegistration, BURN_REGISTRATION_REGISTRY_BUNDLE_PROVIDER_KEY, pRegistration->sczProviderKey);
654 ExitOnFailure(hr, "Failed to write %ls value.", BURN_REGISTRATION_REGISTRY_BUNDLE_PROVIDER_KEY);
655 }
656
657 if (pRegistration->sczTag)
658 {
659 hr = RegWriteString(hkRegistration, BURN_REGISTRATION_REGISTRY_BUNDLE_TAG, pRegistration->sczTag);
660 ExitOnFailure(hr, "Failed to write %ls value.", BURN_REGISTRATION_REGISTRY_BUNDLE_TAG);
661 }
662
663 hr = RegWriteStringFormatted(hkRegistration, BURN_REGISTRATION_REGISTRY_ENGINE_VERSION, L"%hs", szVerMajorMinorBuild);
664 ExitOnFailure(hr, "Failed to write %ls value.", BURN_REGISTRATION_REGISTRY_ENGINE_VERSION);
665
666 // DisplayIcon: [path to exe] and ",0" to refer to the first icon in the executable.
667 hr = RegWriteStringFormatted(hkRegistration, REGISTRY_BUNDLE_DISPLAY_ICON, L"%s,0", pRegistration->sczCacheExecutablePath);
668 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_DISPLAY_ICON);
669
670 // update display name
671 hr = UpdateBundleNameRegistration(pRegistration, pVariables, hkRegistration);
672 ExitOnFailure(hr, "Failed to update name and publisher.");
673
674 // DisplayVersion: provided by UI
675 if (pRegistration->sczDisplayVersion)
676 {
677 hr = RegWriteString(hkRegistration, REGISTRY_BUNDLE_DISPLAY_VERSION, pRegistration->sczDisplayVersion);
678 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_DISPLAY_VERSION);
679 }
680
681 // Publisher: provided by UI
682 hr = GetBundleManufacturer(pRegistration, pVariables, &sczPublisher);
683 hr = RegWriteString(hkRegistration, REGISTRY_BUNDLE_PUBLISHER, SUCCEEDED(hr) ? sczPublisher : pRegistration->sczPublisher);
684 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_PUBLISHER);
685
686 // HelpLink: provided by UI
687 if (pRegistration->sczHelpLink)
688 {
689 hr = RegWriteString(hkRegistration, REGISTRY_BUNDLE_HELP_LINK, pRegistration->sczHelpLink);
690 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_HELP_LINK);
691 }
692
693 // HelpTelephone: provided by UI
694 if (pRegistration->sczHelpTelephone)
695 {
696 hr = RegWriteString(hkRegistration, REGISTRY_BUNDLE_HELP_TELEPHONE, pRegistration->sczHelpTelephone);
697 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_HELP_TELEPHONE);
698 }
699
700 // URLInfoAbout, provided by UI
701 if (pRegistration->sczAboutUrl)
702 {
703 hr = RegWriteString(hkRegistration, REGISTRY_BUNDLE_URL_INFO_ABOUT, pRegistration->sczAboutUrl);
704 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_URL_INFO_ABOUT);
705 }
706
707 // URLUpdateInfo, provided by UI
708 if (pRegistration->sczUpdateUrl)
709 {
710 hr = RegWriteString(hkRegistration, REGISTRY_BUNDLE_URL_UPDATE_INFO, pRegistration->sczUpdateUrl);
711 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_URL_UPDATE_INFO);
712 }
713
714 // ParentDisplayName
715 if (pRegistration->sczParentDisplayName)
716 {
717 hr = RegWriteString(hkRegistration, REGISTRY_BUNDLE_PARENT_DISPLAY_NAME, pRegistration->sczParentDisplayName);
718 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_PARENT_DISPLAY_NAME);
719
720 // Need to write the ParentKeyName but can be set to anything.
721 hr = RegWriteString(hkRegistration, REGISTRY_BUNDLE_PARENT_KEY_NAME, pRegistration->sczParentDisplayName);
722 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_PARENT_KEY_NAME);
723 }
724
725 // Comments, provided by UI
726 if (pRegistration->sczComments)
727 {
728 hr = RegWriteString(hkRegistration, REGISTRY_BUNDLE_COMMENTS, pRegistration->sczComments);
729 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_COMMENTS);
730 }
731
732 // Contact, provided by UI
733 if (pRegistration->sczContact)
734 {
735 hr = RegWriteString(hkRegistration, REGISTRY_BUNDLE_CONTACT, pRegistration->sczContact);
736 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_CONTACT);
737 }
738
739 // InstallLocation: provided by UI
740 // TODO: need to figure out what "InstallLocation" means in a chainer. <smile/>
741
742 // NoModify
743 if (BURN_REGISTRATION_MODIFY_DISABLE == pRegistration->modify)
744 {
745 hr = RegWriteNumber(hkRegistration, REGISTRY_BUNDLE_NO_MODIFY, 1);
746 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_NO_MODIFY);
747 }
748 else if (BURN_REGISTRATION_MODIFY_DISABLE_BUTTON != pRegistration->modify) // if support modify (aka: did not disable anything)
749 {
750 // ModifyPath: [path to exe] /modify
751 hr = RegWriteStringFormatted(hkRegistration, REGISTRY_BUNDLE_MODIFY_PATH, L"\"%ls\" /modify", pRegistration->sczCacheExecutablePath);
752 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_MODIFY_PATH);
753
754 // NoElevateOnModify: 1
755 hr = RegWriteNumber(hkRegistration, REGISTRY_BUNDLE_NO_ELEVATE_ON_MODIFY, 1);
756 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_NO_ELEVATE_ON_MODIFY);
757 }
758
759 // NoRemove: should this be allowed?
760 if (pRegistration->fNoRemoveDefined)
761 {
762 hr = RegWriteNumber(hkRegistration, REGISTRY_BUNDLE_NO_REMOVE, (DWORD)pRegistration->fNoRemove);
763 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_NO_REMOVE);
764 }
765
766 // Conditionally hide the ARP entry.
767 if (!pRegistration->fRegisterArp)
768 {
769 hr = RegWriteNumber(hkRegistration, REGISTRY_BUNDLE_SYSTEM_COMPONENT, 1);
770 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_SYSTEM_COMPONENT);
771 }
772
773 // QuietUninstallString: [path to exe] /uninstall /quiet
774 hr = RegWriteStringFormatted(hkRegistration, REGISTRY_BUNDLE_QUIET_UNINSTALL_STRING, L"\"%ls\" /uninstall /quiet", pRegistration->sczCacheExecutablePath);
775 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_QUIET_UNINSTALL_STRING);
776
777 // UninstallString, [path to exe]
778 // If the modify button is to be disabled, we'll add "/modify" to the uninstall string because the button is "Uninstall/Change". Otherwise,
779 // it's just the "Uninstall" button so we add "/uninstall" to make the program just go away.
780 LPCWSTR wzUninstallParameters = (BURN_REGISTRATION_MODIFY_DISABLE_BUTTON == pRegistration->modify) ? L"/modify" : L" /uninstall";
781 hr = RegWriteStringFormatted(hkRegistration, REGISTRY_BUNDLE_UNINSTALL_STRING, L"\"%ls\" %ls", pRegistration->sczCacheExecutablePath, wzUninstallParameters);
782 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_UNINSTALL_STRING);
783
784 if (pRegistration->softwareTags.cSoftwareTags)
785 {
786 hr = WriteSoftwareTags(pVariables, &pRegistration->softwareTags);
787 ExitOnFailure(hr, "Failed to write software tags.");
788 }
789
790 // Update registration.
791 if (pRegistration->update.fRegisterUpdate)
792 {
793 hr = WriteUpdateRegistration(pRegistration, pVariables);
794 ExitOnFailure(hr, "Failed to write update registration.");
795 }
796 }
797
798 // Update estimated size.
799 if (dwRegistrationOptions & BURN_REGISTRATION_ACTION_OPERATIONS_UPDATE_SIZE)
800 {
801 qwEstimatedSize /= 1024; // Convert bytes to KB
802 if (0 < qwEstimatedSize)
803 {
804 if (DWORD_MAX < qwEstimatedSize)
805 {
806 // ARP doesn't support QWORDs here
807 dwSize = DWORD_MAX;
808 }
809 else
810 {
811 dwSize = static_cast<DWORD>(qwEstimatedSize);
812 }
813
814 hr = RegWriteNumber(hkRegistration, REGISTRY_BUNDLE_ESTIMATED_SIZE, dwSize);
815 ExitOnFailure(hr, "Failed to write %ls value.", REGISTRY_BUNDLE_ESTIMATED_SIZE);
816 }
817 }
818
819 // Register the bundle dependency key.
820 if (BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER == dependencyRegistrationAction)
821 {
822 hr = DependencyRegisterBundle(pRegistration);
823 ExitOnFailure(hr, "Failed to register the bundle dependency key.");
824 }
825
826 // update resume mode
827 hr = UpdateResumeMode(pRegistration, hkRegistration, BURN_RESUME_MODE_ACTIVE, FALSE);
828 ExitOnFailure(hr, "Failed to update resume mode.");
829
830LExit:
831 ReleaseStr(sczPublisher);
832 ReleaseRegKey(hkRegistration);
833
834 return hr;
835}
836
837
838/*******************************************************************
839 RegistrationSessionResume - Resumes a previous run session.
840
841*******************************************************************/
842extern "C" HRESULT RegistrationSessionResume(
843 __in BURN_REGISTRATION* pRegistration,
844 __in BURN_VARIABLES* pVariables
845 )
846{
847 HRESULT hr = S_OK;
848 HKEY hkRegistration = NULL;
849
850 // open registration key
851 hr = RegOpen(pRegistration->hkRoot, pRegistration->sczRegistrationKey, KEY_WRITE, &hkRegistration);
852 ExitOnFailure(hr, "Failed to open registration key.");
853
854 // update resume mode
855 hr = UpdateResumeMode(pRegistration, hkRegistration, BURN_RESUME_MODE_ACTIVE, FALSE);
856 ExitOnFailure(hr, "Failed to update resume mode.");
857
858 // update display name
859 hr = UpdateBundleNameRegistration(pRegistration, pVariables, hkRegistration);
860 ExitOnFailure(hr, "Failed to update name and publisher.");
861
862LExit:
863 ReleaseRegKey(hkRegistration);
864
865 return hr;
866}
867
868
869/*******************************************************************
870 RegistrationSessionEnd - Unregisters a run session from the system.
871
872 *******************************************************************/
873extern "C" HRESULT RegistrationSessionEnd(
874 __in BURN_REGISTRATION* pRegistration,
875 __in BURN_VARIABLES* pVariables,
876 __in BURN_PACKAGES* pPackages,
877 __in BURN_RESUME_MODE resumeMode,
878 __in BOOTSTRAPPER_APPLY_RESTART restart,
879 __in BURN_DEPENDENCY_REGISTRATION_ACTION dependencyRegistrationAction
880 )
881{
882 HRESULT hr = S_OK;
883 LPWSTR sczRebootRequiredKey = NULL;
884 HKEY hkRebootRequired = NULL;
885 HKEY hkRegistration = NULL;
886
887 LogId(REPORT_STANDARD, MSG_SESSION_END, pRegistration->sczRegistrationKey, LoggingResumeModeToString(resumeMode), LoggingRestartToString(restart), LoggingBoolToString(pRegistration->fDisableResume));
888
889 // If a restart is required for any reason, write a volatile registry key to track of
890 // of that fact until the reboot has taken place.
891 if (BOOTSTRAPPER_APPLY_RESTART_NONE != restart)
892 {
893 // We'll write the volatile registry key right next to the bundle ARP registry key
894 // because that's easy. This is all best effort since the worst case just means in
895 // the rare case the user launches the same install again before taking the restart
896 // the BA won't know a restart was still required.
897 hr = StrAllocFormatted(&sczRebootRequiredKey, REGISTRY_REBOOT_PENDING_FORMAT, pRegistration->sczRegistrationKey);
898 if (SUCCEEDED(hr))
899 {
900 hr = RegCreateEx(pRegistration->hkRoot, sczRebootRequiredKey, KEY_WRITE, TRUE, NULL, &hkRebootRequired, NULL);
901 }
902
903 if (FAILED(hr))
904 {
905 ExitTraceSource(DUTIL_SOURCE_DEFAULT, hr, "Failed to write volatile reboot required registry key.");
906 hr = S_OK;
907 }
908 }
909
910 // If no resume mode, then remove the bundle registration.
911 if (BURN_RESUME_MODE_NONE == resumeMode)
912 {
913 // If we just registered the bundle dependency but something went wrong and caused us to not
914 // keep the bundle registration (like rollback) or we are supposed to unregister the bundle
915 // dependency when unregistering the bundle, do so.
916 if (BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER == dependencyRegistrationAction ||
917 BURN_DEPENDENCY_REGISTRATION_ACTION_UNREGISTER == dependencyRegistrationAction)
918 {
919 // Remove the bundle dependency key.
920 DependencyUnregisterBundle(pRegistration, pPackages);
921 }
922
923 // Delete update registration key.
924 if (pRegistration->update.fRegisterUpdate)
925 {
926 RemoveUpdateRegistration(pRegistration);
927 }
928
929 RemoveSoftwareTags(pVariables, &pRegistration->softwareTags);
930
931 // Delete registration key.
932 hr = RegDelete(pRegistration->hkRoot, pRegistration->sczRegistrationKey, REG_KEY_DEFAULT, FALSE);
933 if (E_FILENOTFOUND != hr)
934 {
935 ExitOnFailure(hr, "Failed to delete registration key: %ls", pRegistration->sczRegistrationKey);
936 }
937
938 CacheRemoveBundle(pRegistration->fPerMachine, pRegistration->sczId);
939 }
940 else // the mode needs to be updated so open the registration key.
941 {
942 // Open registration key.
943 hr = RegOpen(pRegistration->hkRoot, pRegistration->sczRegistrationKey, KEY_WRITE, &hkRegistration);
944 ExitOnFailure(hr, "Failed to open registration key.");
945 }
946
947 // Update resume mode.
948 hr = UpdateResumeMode(pRegistration, hkRegistration, resumeMode, BOOTSTRAPPER_APPLY_RESTART_INITIATED == restart);
949 ExitOnFailure(hr, "Failed to update resume mode.");
950
951LExit:
952 ReleaseRegKey(hkRegistration);
953 ReleaseRegKey(hkRebootRequired);
954 ReleaseStr(sczRebootRequiredKey);
955
956 return hr;
957}
958
959/*******************************************************************
960 RegistrationSaveState - Saves an engine state BLOB for retreval after a resume.
961
962*******************************************************************/
963extern "C" HRESULT RegistrationSaveState(
964 __in BURN_REGISTRATION* pRegistration,
965 __in_bcount(cbBuffer) BYTE* pbBuffer,
966 __in SIZE_T cbBuffer
967 )
968{
969 HRESULT hr = S_OK;
970
971 // write data to file
972 hr = FileWrite(pRegistration->sczStateFile, FILE_ATTRIBUTE_NORMAL, pbBuffer, cbBuffer, NULL);
973 if (E_PATHNOTFOUND == hr)
974 {
975 // TODO: should we log that the bundle's cache folder was not present so the state file wasn't created either?
976 hr = S_OK;
977 }
978 ExitOnFailure(hr, "Failed to write state to file: %ls", pRegistration->sczStateFile);
979
980LExit:
981 return hr;
982}
983
984/*******************************************************************
985 RegistrationLoadState - Loads a previously stored engine state BLOB.
986
987*******************************************************************/
988extern "C" HRESULT RegistrationLoadState(
989 __in BURN_REGISTRATION* pRegistration,
990 __out_bcount(*pcbBuffer) BYTE** ppbBuffer,
991 __out SIZE_T* pcbBuffer
992 )
993{
994 // read data from file
995 HRESULT hr = FileRead(ppbBuffer, pcbBuffer, pRegistration->sczStateFile);
996 return hr;
997}
998
999/*******************************************************************
1000RegistrationGetResumeCommandLine - Gets the resume command line from the registry
1001
1002*******************************************************************/
1003extern "C" HRESULT RegistrationGetResumeCommandLine(
1004 __in const BURN_REGISTRATION* pRegistration,
1005 __deref_out_z LPWSTR* psczResumeCommandLine
1006 )
1007{
1008 HRESULT hr = S_OK;
1009 HKEY hkRegistration = NULL;
1010
1011 // open registration key
1012 hr = RegOpen(pRegistration->hkRoot, pRegistration->sczRegistrationKey, KEY_QUERY_VALUE, &hkRegistration);
1013 if (SUCCEEDED(hr))
1014 {
1015 hr = RegReadString(hkRegistration, REGISTRY_BUNDLE_RESUME_COMMAND_LINE, psczResumeCommandLine);
1016 }
1017
1018 // Not finding the key or value is okay.
1019 if (E_FILENOTFOUND == hr || E_PATHNOTFOUND == hr)
1020 {
1021 hr = S_OK;
1022 }
1023
1024 ReleaseRegKey(hkRegistration);
1025
1026 return hr;
1027}
1028
1029
1030// internal helper functions
1031
1032static HRESULT ParseSoftwareTagsFromXml(
1033 __in IXMLDOMNode* pixnRegistrationNode,
1034 __out BURN_SOFTWARE_TAG** prgSoftwareTags,
1035 __out DWORD* pcSoftwareTags
1036 )
1037{
1038 HRESULT hr = S_OK;
1039 IXMLDOMNodeList* pixnNodes = NULL;
1040 IXMLDOMNode* pixnNode = NULL;
1041 DWORD cNodes = 0;
1042
1043 BURN_SOFTWARE_TAG* pSoftwareTags = NULL;
1044 BSTR bstrTagXml = NULL;
1045
1046 // select tag nodes
1047 hr = XmlSelectNodes(pixnRegistrationNode, L"SoftwareTag", &pixnNodes);
1048 ExitOnFailure(hr, "Failed to select software tag nodes.");
1049
1050 // get tag node count
1051 hr = pixnNodes->get_length((long*)&cNodes);
1052 ExitOnFailure(hr, "Failed to get software tag count.");
1053
1054 if (cNodes)
1055 {
1056 pSoftwareTags = (BURN_SOFTWARE_TAG*)MemAlloc(sizeof(BURN_SOFTWARE_TAG) * cNodes, TRUE);
1057 ExitOnNull(pSoftwareTags, hr, E_OUTOFMEMORY, "Failed to allocate memory for software tag structs.");
1058
1059 for (DWORD i = 0; i < cNodes; ++i)
1060 {
1061 BURN_SOFTWARE_TAG* pSoftwareTag = &pSoftwareTags[i];
1062
1063 hr = XmlNextElement(pixnNodes, &pixnNode, NULL);
1064 ExitOnFailure(hr, "Failed to get next node.");
1065
1066 hr = XmlGetAttributeEx(pixnNode, L"Filename", &pSoftwareTag->sczFilename);
1067 ExitOnFailure(hr, "Failed to get @Filename.");
1068
1069 hr = XmlGetAttributeEx(pixnNode, L"Regid", &pSoftwareTag->sczRegid);
1070 ExitOnFailure(hr, "Failed to get @Regid.");
1071
1072 hr = XmlGetAttributeEx(pixnNode, L"Path", &pSoftwareTag->sczPath);
1073 ExitOnFailure(hr, "Failed to get @Path.");
1074
1075 hr = XmlGetText(pixnNode, &bstrTagXml);
1076 ExitOnFailure(hr, "Failed to get SoftwareTag text.");
1077
1078 hr = StrAnsiAllocString(&pSoftwareTag->sczTag, bstrTagXml, 0, CP_UTF8);
1079 ExitOnFailure(hr, "Failed to convert SoftwareTag text to UTF-8");
1080
1081 // prepare next iteration
1082 ReleaseNullBSTR(bstrTagXml);
1083 ReleaseNullObject(pixnNode);
1084 }
1085 }
1086
1087 *pcSoftwareTags = cNodes;
1088 *prgSoftwareTags = pSoftwareTags;
1089 pSoftwareTags = NULL;
1090
1091 hr = S_OK;
1092
1093LExit:
1094 ReleaseBSTR(bstrTagXml);
1095 ReleaseObject(pixnNode);
1096 ReleaseObject(pixnNodes);
1097 ReleaseMem(pSoftwareTags);
1098
1099 return hr;
1100}
1101
1102static HRESULT SetPaths(
1103 __in BURN_REGISTRATION* pRegistration
1104 )
1105{
1106 HRESULT hr = S_OK;
1107 LPWSTR sczCacheDirectory = NULL;
1108
1109 // save registration key root
1110 pRegistration->hkRoot = pRegistration->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1111
1112 // build uninstall registry key path
1113 hr = StrAllocFormatted(&pRegistration->sczRegistrationKey, L"%s\\%s", BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY, pRegistration->sczId);
1114 ExitOnFailure(hr, "Failed to build uninstall registry key path.");
1115
1116 // build cache directory
1117 hr = CacheGetCompletedPath(pRegistration->fPerMachine, pRegistration->sczId, &sczCacheDirectory);
1118 ExitOnFailure(hr, "Failed to build cache directory.");
1119
1120 // build cached executable path
1121 hr = PathConcat(sczCacheDirectory, pRegistration->sczExecutableName, &pRegistration->sczCacheExecutablePath);
1122 ExitOnFailure(hr, "Failed to build cached executable path.");
1123
1124 // build state file path
1125 hr = StrAllocFormatted(&pRegistration->sczStateFile, L"%s\\state.rsm", sczCacheDirectory);
1126 ExitOnFailure(hr, "Failed to build state file path.");
1127
1128LExit:
1129 ReleaseStr(sczCacheDirectory);
1130 return hr;
1131}
1132
1133static HRESULT GetBundleManufacturer(
1134 __in BURN_REGISTRATION* pRegistration,
1135 __in BURN_VARIABLES* pVariables,
1136 __out LPWSTR* psczBundleManufacturer
1137 )
1138{
1139 HRESULT hr = S_OK;
1140
1141 hr = VariableGetString(pVariables, BURN_BUNDLE_MANUFACTURER, psczBundleManufacturer);
1142 if (E_NOTFOUND == hr)
1143 {
1144 hr = VariableSetString(pVariables, BURN_BUNDLE_MANUFACTURER, pRegistration->sczPublisher, FALSE, FALSE);
1145 ExitOnFailure(hr, "Failed to set bundle manufacturer.");
1146
1147 hr = StrAllocString(psczBundleManufacturer, pRegistration->sczPublisher, 0);
1148 }
1149 ExitOnFailure(hr, "Failed to get bundle manufacturer.");
1150
1151LExit:
1152 return hr;
1153}
1154
1155static HRESULT GetBundleName(
1156 __in BURN_REGISTRATION* pRegistration,
1157 __in BURN_VARIABLES* pVariables,
1158 __out LPWSTR* psczBundleName
1159 )
1160{
1161 HRESULT hr = S_OK;
1162
1163 hr = VariableGetString(pVariables, BURN_BUNDLE_NAME, psczBundleName);
1164 if (E_NOTFOUND == hr)
1165 {
1166 hr = VariableSetString(pVariables, BURN_BUNDLE_NAME, pRegistration->sczDisplayName, FALSE, FALSE);
1167 ExitOnFailure(hr, "Failed to set bundle name.");
1168
1169 hr = StrAllocString(psczBundleName, pRegistration->sczDisplayName, 0);
1170 }
1171 ExitOnFailure(hr, "Failed to get bundle name.");
1172
1173LExit:
1174 return hr;
1175}
1176
1177static HRESULT UpdateResumeMode(
1178 __in BURN_REGISTRATION* pRegistration,
1179 __in HKEY hkRegistration,
1180 __in BURN_RESUME_MODE resumeMode,
1181 __in BOOL fRestartInitiated
1182 )
1183{
1184 HRESULT hr = S_OK;
1185 DWORD er = ERROR_SUCCESS;
1186 HKEY hkRebootRequired = NULL;
1187 HKEY hkRun = NULL;
1188 LPWSTR sczResumeCommandLine = NULL;
1189 LPCWSTR sczResumeKey = REGISTRY_RUN_ONCE_KEY;
1190
1191 LogId(REPORT_STANDARD, MSG_SESSION_UPDATE, pRegistration->sczRegistrationKey, LoggingResumeModeToString(resumeMode), LoggingBoolToString(fRestartInitiated), LoggingBoolToString(pRegistration->fDisableResume));
1192
1193 // write resume information
1194 if (hkRegistration)
1195 {
1196 // write Resume value
1197 hr = RegWriteNumber(hkRegistration, L"Resume", (DWORD)resumeMode);
1198 ExitOnFailure(hr, "Failed to write Resume value.");
1199
1200 // Write the Installed value *only* when the mode is ARP. This will tell us
1201 // that the bundle considers itself "installed" on the machine. Note that we
1202 // never change the value to "0" after that. The bundle will be considered
1203 // "uninstalled" when all of the registration is removed.
1204 if (BURN_RESUME_MODE_ARP == resumeMode)
1205 {
1206 // Write Installed value.
1207 hr = RegWriteNumber(hkRegistration, REGISTRY_BUNDLE_INSTALLED, 1);
1208 ExitOnFailure(hr, "Failed to write Installed value.");
1209 }
1210 }
1211
1212 // If the engine is active write the run key so we resume if there is an unexpected
1213 // power loss. Also, if a restart was initiated in the middle of the chain then
1214 // ensure the run key exists (it should since going active would have written it).
1215 // Do not write the run key when embedded since the containing bundle
1216 // is expected to detect for and restart the embedded bundle.
1217 if ((BURN_RESUME_MODE_ACTIVE == resumeMode || fRestartInitiated) && !pRegistration->fDisableResume)
1218 {
1219 // append RunOnce switch
1220 hr = StrAllocFormatted(&sczResumeCommandLine, L"\"%ls\" /%ls", pRegistration->sczCacheExecutablePath, BURN_COMMANDLINE_SWITCH_RUNONCE);
1221 ExitOnFailure(hr, "Failed to format resume command line for RunOnce.");
1222
1223 // write run key
1224 hr = RegCreate(pRegistration->hkRoot, sczResumeKey, KEY_WRITE, &hkRun);
1225 ExitOnFailure(hr, "Failed to create run key.");
1226
1227 hr = RegWriteString(hkRun, pRegistration->sczId, sczResumeCommandLine);
1228 ExitOnFailure(hr, "Failed to write run key value.");
1229
1230 hr = RegWriteString(hkRegistration, REGISTRY_BUNDLE_RESUME_COMMAND_LINE, pRegistration->sczResumeCommandLine);
1231 ExitOnFailure(hr, "Failed to write resume command line value.");
1232 }
1233 else // delete run key value
1234 {
1235 hr = RegOpen(pRegistration->hkRoot, sczResumeKey, KEY_WRITE, &hkRun);
1236 if (E_FILENOTFOUND == hr || E_PATHNOTFOUND == hr)
1237 {
1238 hr = S_OK;
1239 }
1240 else
1241 {
1242 ExitOnWin32Error(er, hr, "Failed to open run key.");
1243
1244 er = ::RegDeleteValueW(hkRun, pRegistration->sczId);
1245 if (ERROR_FILE_NOT_FOUND == er)
1246 {
1247 er = ERROR_SUCCESS;
1248 }
1249 ExitOnWin32Error(er, hr, "Failed to delete run key value.");
1250 }
1251
1252 if (hkRegistration)
1253 {
1254 er = ::RegDeleteValueW(hkRegistration, REGISTRY_BUNDLE_RESUME_COMMAND_LINE);
1255 if (ERROR_FILE_NOT_FOUND == er)
1256 {
1257 er = ERROR_SUCCESS;
1258 }
1259 ExitOnWin32Error(er, hr, "Failed to delete resume command line value.");
1260 }
1261 }
1262
1263LExit:
1264 ReleaseStr(sczResumeCommandLine);
1265 ReleaseRegKey(hkRebootRequired);
1266 ReleaseRegKey(hkRun);
1267
1268 return hr;
1269}
1270
1271static HRESULT ParseRelatedCodes(
1272 __in BURN_REGISTRATION* pRegistration,
1273 __in IXMLDOMNode* pixnBundle
1274 )
1275{
1276 HRESULT hr = S_OK;
1277 IXMLDOMNodeList* pixnNodes = NULL;
1278 IXMLDOMNode* pixnElement = NULL;
1279 LPWSTR sczAction = NULL;
1280 LPWSTR sczId = NULL;
1281 DWORD cElements = 0;
1282
1283 hr = XmlSelectNodes(pixnBundle, L"RelatedBundle", &pixnNodes);
1284 ExitOnFailure(hr, "Failed to get RelatedBundle nodes");
1285
1286 hr = pixnNodes->get_length((long*)&cElements);
1287 ExitOnFailure(hr, "Failed to get RelatedBundle element count.");
1288
1289 for (DWORD i = 0; i < cElements; ++i)
1290 {
1291 hr = XmlNextElement(pixnNodes, &pixnElement, NULL);
1292 ExitOnFailure(hr, "Failed to get next RelatedBundle element.");
1293
1294 hr = XmlGetAttributeEx(pixnElement, L"Action", &sczAction);
1295 ExitOnFailure(hr, "Failed to get @Action.");
1296
1297 hr = XmlGetAttributeEx(pixnElement, L"Id", &sczId);
1298 ExitOnFailure(hr, "Failed to get @Id.");
1299
1300 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Detect", -1))
1301 {
1302 hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pRegistration->rgsczDetectCodes), pRegistration->cDetectCodes + 1, sizeof(LPWSTR), 5);
1303 ExitOnFailure(hr, "Failed to resize Detect code array in registration");
1304
1305 pRegistration->rgsczDetectCodes[pRegistration->cDetectCodes] = sczId;
1306 sczId = NULL;
1307 ++pRegistration->cDetectCodes;
1308 }
1309 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Upgrade", -1))
1310 {
1311 hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pRegistration->rgsczUpgradeCodes), pRegistration->cUpgradeCodes + 1, sizeof(LPWSTR), 5);
1312 ExitOnFailure(hr, "Failed to resize Upgrade code array in registration");
1313
1314 pRegistration->rgsczUpgradeCodes[pRegistration->cUpgradeCodes] = sczId;
1315 sczId = NULL;
1316 ++pRegistration->cUpgradeCodes;
1317 }
1318 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Addon", -1))
1319 {
1320 hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pRegistration->rgsczAddonCodes), pRegistration->cAddonCodes + 1, sizeof(LPWSTR), 5);
1321 ExitOnFailure(hr, "Failed to resize Addon code array in registration");
1322
1323 pRegistration->rgsczAddonCodes[pRegistration->cAddonCodes] = sczId;
1324 sczId = NULL;
1325 ++pRegistration->cAddonCodes;
1326 }
1327 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Patch", -1))
1328 {
1329 hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pRegistration->rgsczPatchCodes), pRegistration->cPatchCodes + 1, sizeof(LPWSTR), 5);
1330 ExitOnFailure(hr, "Failed to resize Patch code array in registration");
1331
1332 pRegistration->rgsczPatchCodes[pRegistration->cPatchCodes] = sczId;
1333 sczId = NULL;
1334 ++pRegistration->cPatchCodes;
1335 }
1336 else
1337 {
1338 hr = E_INVALIDARG;
1339 ExitOnFailure(hr, "Invalid value for @Action: %ls", sczAction);
1340 }
1341 }
1342
1343LExit:
1344 ReleaseObject(pixnNodes);
1345 ReleaseObject(pixnElement);
1346 ReleaseStr(sczAction);
1347 ReleaseStr(sczId);
1348
1349 return hr;
1350}
1351
1352static HRESULT FormatUpdateRegistrationKey(
1353 __in BURN_REGISTRATION* pRegistration,
1354 __out_z LPWSTR* psczKey
1355 )
1356{
1357 HRESULT hr = S_OK;
1358 LPWSTR sczKey = NULL;
1359
1360 hr = StrAllocFormatted(&sczKey, L"SOFTWARE\\%ls\\Updates\\", pRegistration->update.sczManufacturer);
1361 ExitOnFailure(hr, "Failed to format the key path for update registration.");
1362
1363 if (pRegistration->update.sczProductFamily)
1364 {
1365 hr = StrAllocFormatted(&sczKey, L"%ls%ls\\", sczKey, pRegistration->update.sczProductFamily);
1366 ExitOnFailure(hr, "Failed to format the key path for update registration.");
1367 }
1368
1369 hr = StrAllocConcat(&sczKey, pRegistration->update.sczName, 0);
1370 ExitOnFailure(hr, "Failed to format the key path for update registration.");
1371
1372 *psczKey = sczKey;
1373 sczKey = NULL;
1374
1375LExit:
1376 ReleaseStr(sczKey);
1377
1378 return hr;
1379}
1380
1381static HRESULT WriteSoftwareTags(
1382 __in BURN_VARIABLES* pVariables,
1383 __in BURN_SOFTWARE_TAGS* pSoftwareTags
1384 )
1385{
1386 HRESULT hr = S_OK;
1387 LPWSTR sczRootFolder = NULL;
1388 LPWSTR sczTagFolder = NULL;
1389 LPWSTR sczPath = NULL;
1390
1391 for (DWORD iTag = 0; iTag < pSoftwareTags->cSoftwareTags; ++iTag)
1392 {
1393 BURN_SOFTWARE_TAG* pSoftwareTag = pSoftwareTags->rgSoftwareTags + iTag;
1394
1395 hr = VariableFormatString(pVariables, pSoftwareTag->sczPath, &sczRootFolder, NULL);
1396 ExitOnFailure(hr, "Failed to format tag folder path.");
1397
1398 hr = PathConcat(sczRootFolder, SWIDTAG_FOLDER, &sczTagFolder);
1399 ExitOnFailure(hr, "Failed to allocate regid folder path.");
1400
1401 hr = PathConcat(sczTagFolder, pSoftwareTag->sczFilename, &sczPath);
1402 ExitOnFailure(hr, "Failed to allocate regid file path.");
1403
1404 hr = DirEnsureExists(sczTagFolder, NULL);
1405 ExitOnFailure(hr, "Failed to create regid folder: %ls", sczTagFolder);
1406
1407 hr = FileWrite(sczPath, FILE_ATTRIBUTE_NORMAL, reinterpret_cast<LPBYTE>(pSoftwareTag->sczTag), lstrlenA(pSoftwareTag->sczTag), NULL);
1408 ExitOnFailure(hr, "Failed to write tag xml to file: %ls", sczPath);
1409 }
1410
1411LExit:
1412 ReleaseStr(sczPath);
1413 ReleaseStr(sczTagFolder);
1414 ReleaseStr(sczRootFolder);
1415
1416 return hr;
1417}
1418
1419static HRESULT RemoveSoftwareTags(
1420 __in BURN_VARIABLES* pVariables,
1421 __in BURN_SOFTWARE_TAGS* pSoftwareTags
1422 )
1423{
1424 HRESULT hr = S_OK;
1425 LPWSTR sczRootFolder = NULL;
1426 LPWSTR sczTagFolder = NULL;
1427 LPWSTR sczPath = NULL;
1428
1429 for (DWORD iTag = 0; iTag < pSoftwareTags->cSoftwareTags; ++iTag)
1430 {
1431 BURN_SOFTWARE_TAG* pSoftwareTag = pSoftwareTags->rgSoftwareTags + iTag;
1432
1433 hr = VariableFormatString(pVariables, pSoftwareTag->sczPath, &sczRootFolder, NULL);
1434 ExitOnFailure(hr, "Failed to format tag folder path.");
1435
1436 hr = PathConcat(sczRootFolder, SWIDTAG_FOLDER, &sczTagFolder);
1437 ExitOnFailure(hr, "Failed to allocate regid folder path.");
1438
1439 hr = PathConcat(sczTagFolder, pSoftwareTag->sczFilename, &sczPath);
1440 ExitOnFailure(hr, "Failed to allocate regid file path.");
1441
1442 // Best effort to delete the software tag file and the regid folder.
1443 FileEnsureDelete(sczPath);
1444
1445 DirDeleteEmptyDirectoriesToRoot(sczTagFolder, 0);
1446 }
1447
1448LExit:
1449 ReleaseStr(sczPath);
1450 ReleaseStr(sczTagFolder);
1451 ReleaseStr(sczRootFolder);
1452
1453 return hr;
1454}
1455
1456static HRESULT WriteUpdateRegistration(
1457 __in BURN_REGISTRATION* pRegistration,
1458 __in BURN_VARIABLES* pVariables
1459 )
1460{
1461 HRESULT hr = S_OK;
1462 LPWSTR sczKey = NULL;
1463 HKEY hkKey = NULL;
1464
1465 hr = FormatUpdateRegistrationKey(pRegistration, &sczKey);
1466 ExitOnFailure(hr, "Failed to get the formatted key path for update registration.");
1467
1468 hr = RegCreate(pRegistration->hkRoot, sczKey, KEY_WRITE, &hkKey);
1469 ExitOnFailure(hr, "Failed to create the key for update registration.");
1470
1471 hr = RegWriteString(hkKey, L"ThisVersionInstalled", L"Y");
1472 ExitOnFailure(hr, "Failed to write %ls value.", L"ThisVersionInstalled");
1473
1474 hr = RegWriteString(hkKey, L"PackageName", pRegistration->sczDisplayName);
1475 ExitOnFailure(hr, "Failed to write %ls value.", L"PackageName");
1476
1477 hr = RegWriteString(hkKey, L"PackageVersion", pRegistration->sczDisplayVersion);
1478 ExitOnFailure(hr, "Failed to write %ls value.", L"PackageVersion");
1479
1480 hr = RegWriteString(hkKey, L"Publisher", pRegistration->sczPublisher);
1481 ExitOnFailure(hr, "Failed to write %ls value.", L"Publisher");
1482
1483 if (pRegistration->update.sczDepartment)
1484 {
1485 hr = RegWriteString(hkKey, L"PublishingGroup", pRegistration->update.sczDepartment);
1486 ExitOnFailure(hr, "Failed to write %ls value.", L"PublishingGroup");
1487 }
1488
1489 hr = RegWriteString(hkKey, L"ReleaseType", pRegistration->update.sczClassification);
1490 ExitOnFailure(hr, "Failed to write %ls value.", L"ReleaseType");
1491
1492 hr = RegWriteStringVariable(hkKey, pVariables, VARIABLE_LOGONUSER, L"InstalledBy");
1493 ExitOnFailure(hr, "Failed to write %ls value.", L"InstalledBy");
1494
1495 hr = RegWriteStringVariable(hkKey, pVariables, VARIABLE_DATE, L"InstalledDate");
1496 ExitOnFailure(hr, "Failed to write %ls value.", L"InstalledDate");
1497
1498 hr = RegWriteStringVariable(hkKey, pVariables, VARIABLE_INSTALLERNAME, L"InstallerName");
1499 ExitOnFailure(hr, "Failed to write %ls value.", L"InstallerName");
1500
1501 hr = RegWriteStringVariable(hkKey, pVariables, VARIABLE_INSTALLERVERSION, L"InstallerVersion");
1502 ExitOnFailure(hr, "Failed to write %ls value.", L"InstallerVersion");
1503
1504LExit:
1505 ReleaseRegKey(hkKey);
1506 ReleaseStr(sczKey);
1507
1508 return hr;
1509}
1510
1511static HRESULT RemoveUpdateRegistration(
1512 __in BURN_REGISTRATION* pRegistration
1513 )
1514{
1515 HRESULT hr = S_OK;
1516 LPWSTR sczKey = NULL;
1517 LPWSTR sczPackageVersion = NULL;
1518 HKEY hkKey = NULL;
1519 BOOL fDeleteRegKey = TRUE;
1520
1521 hr = FormatUpdateRegistrationKey(pRegistration, &sczKey);
1522 ExitOnFailure(hr, "Failed to format key for update registration.");
1523
1524 // Only delete if the uninstalling bundle's PackageVersion is the same as the
1525 // PackageVersion in the update registration key.
1526 // This is to support build to build upgrades
1527 hr = RegOpen(pRegistration->hkRoot, sczKey, KEY_QUERY_VALUE, &hkKey);
1528 if (SUCCEEDED(hr))
1529 {
1530 hr = RegReadString(hkKey, L"PackageVersion", &sczPackageVersion);
1531 if (SUCCEEDED(hr))
1532 {
1533 if (CSTR_EQUAL != ::CompareStringW(LOCALE_INVARIANT, 0, sczPackageVersion, -1, pRegistration->sczDisplayVersion, -1))
1534 {
1535 fDeleteRegKey = FALSE;
1536 }
1537 }
1538 ReleaseRegKey(hkKey);
1539 }
1540
1541 // Unable to open the key or read the value is okay.
1542 hr = S_OK;
1543
1544 if (fDeleteRegKey)
1545 {
1546 hr = RegDelete(pRegistration->hkRoot, sczKey, REG_KEY_DEFAULT, FALSE);
1547 if (E_FILENOTFOUND != hr)
1548 {
1549 ExitOnFailure(hr, "Failed to remove update registration key: %ls", sczKey);
1550 }
1551 }
1552
1553LExit:
1554 ReleaseStr(sczPackageVersion);
1555 ReleaseStr(sczKey);
1556
1557 return hr;
1558}
1559
1560static HRESULT RegWriteStringVariable(
1561 __in HKEY hk,
1562 __in BURN_VARIABLES* pVariables,
1563 __in LPCWSTR wzVariable,
1564 __in LPCWSTR wzName
1565 )
1566{
1567 HRESULT hr = S_OK;
1568 LPWSTR sczValue = NULL;
1569
1570 hr = VariableGetString(pVariables, wzVariable, &sczValue);
1571 ExitOnFailure(hr, "Failed to get the %ls variable.", wzVariable);
1572
1573 hr = RegWriteString(hk, wzName, sczValue);
1574 ExitOnFailure(hr, "Failed to write %ls value.", wzName);
1575
1576LExit:
1577 StrSecureZeroFreeString(sczValue);
1578
1579 return hr;
1580}
1581
1582static HRESULT UpdateBundleNameRegistration(
1583 __in BURN_REGISTRATION* pRegistration,
1584 __in BURN_VARIABLES* pVariables,
1585 __in HKEY hkRegistration
1586 )
1587{
1588 HRESULT hr = S_OK;
1589 LPWSTR sczDisplayName = NULL;
1590
1591 // DisplayName: provided by UI
1592 hr = GetBundleName(pRegistration, pVariables, &sczDisplayName);
1593 hr = RegWriteString(hkRegistration, BURN_REGISTRATION_REGISTRY_BUNDLE_DISPLAY_NAME, SUCCEEDED(hr) ? sczDisplayName : pRegistration->sczDisplayName);
1594 ExitOnFailure(hr, "Failed to write %ls value.", BURN_REGISTRATION_REGISTRY_BUNDLE_DISPLAY_NAME);
1595
1596LExit:
1597 ReleaseStr(sczDisplayName);
1598
1599 return hr;
1600}
1601
1602static BOOL IsWuRebootPending()
1603{
1604 HRESULT hr = S_OK;
1605 BOOL fRebootPending = FALSE;
1606
1607 // Do a best effort to ask WU if a reboot is required. If anything goes
1608 // wrong then let's pretend a reboot is not required.
1609 hr = ::CoInitialize(NULL);
1610 if (SUCCEEDED(hr) || RPC_E_CHANGED_MODE == hr)
1611 {
1612 hr = WuaRestartRequired(&fRebootPending);
1613 if (FAILED(hr))
1614 {
1615 fRebootPending = FALSE;
1616 }
1617
1618 ::CoUninitialize();
1619 }
1620
1621 return fRebootPending;
1622}
1623
1624static BOOL IsBundleRebootPending(BURN_REGISTRATION* pRegistration)
1625{
1626 HRESULT hr = S_OK;
1627 LPWSTR sczRebootRequiredKey = NULL;
1628 HKEY hkRebootRequired = NULL;
1629 BOOL fBundleRebootPending = FALSE;
1630
1631 // Check to see if a restart is pending for this bundle.
1632 hr = StrAllocFormatted(&sczRebootRequiredKey, REGISTRY_REBOOT_PENDING_FORMAT, pRegistration->sczRegistrationKey);
1633 ExitOnFailure(hr, "Failed to format pending restart registry key to read.");
1634
1635 hr = RegOpen(pRegistration->hkRoot, sczRebootRequiredKey, KEY_QUERY_VALUE, &hkRebootRequired);
1636 fBundleRebootPending = SUCCEEDED(hr);
1637
1638LExit:
1639 ReleaseStr(sczRebootRequiredKey);
1640 ReleaseRegKey(hkRebootRequired);
1641
1642 return fBundleRebootPending;
1643}
1644
1645static BOOL IsRegistryRebootPending()
1646{
1647 HRESULT hr = S_OK;
1648 DWORD dwValue;
1649 HKEY hk = NULL;
1650 BOOL fRebootPending = FALSE;
1651
1652 hr = RegKeyReadNumber(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\ServerManager", L"CurrentRebootAttempts", TRUE, &dwValue);
1653 fRebootPending = SUCCEEDED(hr) && 0 < dwValue;
1654
1655 if (!fRebootPending)
1656 {
1657 hr = RegKeyReadNumber(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Updates", L"UpdateExeVolatile", TRUE, &dwValue);
1658 fRebootPending = SUCCEEDED(hr) && 0 < dwValue;
1659
1660 if (!fRebootPending)
1661 {
1662 fRebootPending = RegValueExists(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\RebootPending", NULL, TRUE);
1663
1664 if (!fRebootPending)
1665 {
1666 fRebootPending = RegValueExists(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Component Based Servicing\\RebootInProgress", NULL, TRUE);
1667
1668 if (!fRebootPending)
1669 {
1670 hr = RegKeyReadNumber(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\Auto Update", L"AUState", TRUE, &dwValue);
1671 fRebootPending = SUCCEEDED(hr) && 8 == dwValue;
1672
1673 if (!fRebootPending)
1674 {
1675 fRebootPending = RegValueExists(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Session Manager", L"PendingFileRenameOperations", TRUE);
1676
1677 if (!fRebootPending)
1678 {
1679 fRebootPending = RegValueExists(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Session Manager", L"PendingFileRenameOperations2", TRUE);
1680
1681 if (!fRebootPending)
1682 {
1683 hr = RegOpen(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\FileRenameOperations", KEY_READ | KEY_WOW64_64KEY, &hk);
1684 if (SUCCEEDED(hr))
1685 {
1686 DWORD cSubKeys = 0;
1687 DWORD cValues = 0;
1688 hr = RegQueryKey(hk, &cSubKeys, &cValues);
1689 fRebootPending = SUCCEEDED(hr) && (0 < cSubKeys || 0 < cValues);
1690 }
1691 }
1692 }
1693 }
1694 }
1695 }
1696 }
1697 }
1698
1699 ReleaseRegKey(hk);
1700
1701 return fRebootPending;
1702}