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