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