aboutsummaryrefslogtreecommitdiff
path: root/src/burn/engine/dependency.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/burn/engine/dependency.cpp')
-rw-r--r--src/burn/engine/dependency.cpp1312
1 files changed, 1312 insertions, 0 deletions
diff --git a/src/burn/engine/dependency.cpp b/src/burn/engine/dependency.cpp
new file mode 100644
index 00000000..876cd8b3
--- /dev/null
+++ b/src/burn/engine/dependency.cpp
@@ -0,0 +1,1312 @@
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// constants
6
7#define INITIAL_STRINGDICT_SIZE 48
8const LPCWSTR vcszIgnoreDependenciesDelim = L";";
9
10
11// internal function declarations
12
13static HRESULT DetectPackageDependents(
14 __in BURN_PACKAGE* pPackage,
15 __in STRINGDICT_HANDLE sdIgnoredDependents,
16 __in const BURN_REGISTRATION* pRegistration
17 );
18
19static HRESULT SplitIgnoreDependencies(
20 __in_z LPCWSTR wzIgnoreDependencies,
21 __deref_inout_ecount_opt(*pcDependencies) DEPENDENCY** prgDependencies,
22 __inout LPUINT pcDependencies,
23 __out BOOL* pfIgnoreAll
24 );
25
26static HRESULT JoinIgnoreDependencies(
27 __out_z LPWSTR* psczIgnoreDependencies,
28 __in_ecount(cDependencies) const DEPENDENCY* rgDependencies,
29 __in UINT cDependencies
30 );
31
32static HRESULT GetIgnoredDependents(
33 __in const BURN_PACKAGE* pPackage,
34 __in const BURN_PLAN* pPlan,
35 __deref_inout STRINGDICT_HANDLE* psdIgnoredDependents
36 );
37
38static BOOL GetProviderExists(
39 __in HKEY hkRoot,
40 __in_z LPCWSTR wzProviderKey
41 );
42
43static void CalculateDependencyActionStates(
44 __in const BURN_PACKAGE* pPackage,
45 __in const BOOTSTRAPPER_ACTION action,
46 __out BURN_DEPENDENCY_ACTION* pDependencyExecuteAction,
47 __out BURN_DEPENDENCY_ACTION* pDependencyRollbackAction
48 );
49
50static HRESULT AddPackageDependencyActions(
51 __in_opt DWORD *pdwInsertSequence,
52 __in const BURN_PACKAGE* pPackage,
53 __in BURN_PLAN* pPlan,
54 __in const BURN_DEPENDENCY_ACTION dependencyExecuteAction,
55 __in const BURN_DEPENDENCY_ACTION dependencyRollbackAction
56 );
57
58static HRESULT RegisterPackageProvider(
59 __in const BURN_PACKAGE* pPackage
60 );
61
62static void UnregisterPackageProvider(
63 __in const BURN_PACKAGE* pPackage
64 );
65
66static HRESULT RegisterPackageDependency(
67 __in BOOL fPerMachine,
68 __in const BURN_PACKAGE* pPackage,
69 __in_z LPCWSTR wzDependentProviderKey
70 );
71
72static void UnregisterPackageDependency(
73 __in BOOL fPerMachine,
74 __in const BURN_PACKAGE* pPackage,
75 __in_z LPCWSTR wzDependentProviderKey
76 );
77
78
79// functions
80
81extern "C" void DependencyUninitializeProvider(
82 __in BURN_DEPENDENCY_PROVIDER* pProvider
83 )
84{
85 ReleaseStr(pProvider->sczKey);
86 ReleaseStr(pProvider->sczVersion);
87 ReleaseStr(pProvider->sczDisplayName);
88 ReleaseDependencyArray(pProvider->rgDependents, pProvider->cDependents);
89
90 memset(pProvider, 0, sizeof(BURN_DEPENDENCY_PROVIDER));
91}
92
93extern "C" HRESULT DependencyParseProvidersFromXml(
94 __in BURN_PACKAGE* pPackage,
95 __in IXMLDOMNode* pixnPackage
96 )
97{
98 HRESULT hr = S_OK;
99 IXMLDOMNodeList* pixnNodes = NULL;
100 DWORD cNodes = 0;
101 IXMLDOMNode* pixnNode = NULL;
102
103 // Select dependency provider nodes.
104 hr = XmlSelectNodes(pixnPackage, L"Provides", &pixnNodes);
105 ExitOnFailure(hr, "Failed to select dependency provider nodes.");
106
107 // Get dependency provider node count.
108 hr = pixnNodes->get_length((long*)&cNodes);
109 ExitOnFailure(hr, "Failed to get the dependency provider node count.");
110
111 if (!cNodes)
112 {
113 ExitFunction1(hr = S_OK);
114 }
115
116 // Allocate memory for dependency provider pointers.
117 pPackage->rgDependencyProviders = (BURN_DEPENDENCY_PROVIDER*)MemAlloc(sizeof(BURN_DEPENDENCY_PROVIDER) * cNodes, TRUE);
118 ExitOnNull(pPackage->rgDependencyProviders, hr, E_OUTOFMEMORY, "Failed to allocate memory for dependency providers.");
119
120 pPackage->cDependencyProviders = cNodes;
121
122 // Parse dependency provider elements.
123 for (DWORD i = 0; i < cNodes; i++)
124 {
125 BURN_DEPENDENCY_PROVIDER* pDependencyProvider = &pPackage->rgDependencyProviders[i];
126
127 hr = XmlNextElement(pixnNodes, &pixnNode, NULL);
128 ExitOnFailure(hr, "Failed to get the next dependency provider node.");
129
130 // @Key
131 hr = XmlGetAttributeEx(pixnNode, L"Key", &pDependencyProvider->sczKey);
132 ExitOnFailure(hr, "Failed to get the Key attribute.");
133
134 // @Version
135 hr = XmlGetAttributeEx(pixnNode, L"Version", &pDependencyProvider->sczVersion);
136 if (E_NOTFOUND != hr)
137 {
138 ExitOnFailure(hr, "Failed to get the Version attribute.");
139 }
140
141 // @DisplayName
142 hr = XmlGetAttributeEx(pixnNode, L"DisplayName", &pDependencyProvider->sczDisplayName);
143 if (E_NOTFOUND != hr)
144 {
145 ExitOnFailure(hr, "Failed to get the DisplayName attribute.");
146 }
147
148 // @Imported
149 hr = XmlGetYesNoAttribute(pixnNode, L"Imported", &pDependencyProvider->fImported);
150 if (E_NOTFOUND != hr)
151 {
152 ExitOnFailure(hr, "Failed to get the Imported attribute.");
153 }
154 else
155 {
156 pDependencyProvider->fImported = FALSE;
157 hr = S_OK;
158 }
159
160 // Prepare next iteration.
161 ReleaseNullObject(pixnNode);
162 }
163
164 hr = S_OK;
165
166LExit:
167 ReleaseObject(pixnNode);
168 ReleaseObject(pixnNodes);
169
170 return hr;
171}
172
173extern "C" HRESULT DependencyInitialize(
174 __in BURN_REGISTRATION* pRegistration,
175 __in_z_opt LPCWSTR wzIgnoreDependencies
176 )
177{
178 HRESULT hr = S_OK;
179
180 // If no parent was specified at all, use the bundle id as the self dependent.
181 if (!pRegistration->sczActiveParent)
182 {
183 pRegistration->wzSelfDependent = pRegistration->sczId;
184 }
185 else if (*pRegistration->sczActiveParent) // if parent was specified use that as the self dependent.
186 {
187 pRegistration->wzSelfDependent = pRegistration->sczActiveParent;
188 }
189 // else parent:none was used which means we should not register a dependency on ourself.
190
191 // The current bundle provider key should always be ignored for dependency checks.
192 hr = DepDependencyArrayAlloc(&pRegistration->rgIgnoredDependencies, &pRegistration->cIgnoredDependencies, pRegistration->sczProviderKey, NULL);
193 ExitOnFailure(hr, "Failed to add the bundle provider key to the list of dependencies to ignore.");
194
195 // Add the list of dependencies to ignore.
196 if (wzIgnoreDependencies)
197 {
198 hr = SplitIgnoreDependencies(wzIgnoreDependencies, &pRegistration->rgIgnoredDependencies, &pRegistration->cIgnoredDependencies, &pRegistration->fIgnoreAllDependents);
199 ExitOnFailure(hr, "Failed to split the list of dependencies to ignore.");
200 }
201
202LExit:
203 return hr;
204}
205
206extern "C" HRESULT DependencyDetectProviderKeyBundleId(
207 __in BURN_REGISTRATION* pRegistration
208 )
209{
210 HRESULT hr = S_OK;
211
212 hr = DepGetProviderInformation(pRegistration->hkRoot, pRegistration->sczProviderKey, &pRegistration->sczDetectedProviderKeyBundleId, NULL, NULL);
213 if (E_NOTFOUND == hr)
214 {
215 ExitFunction();
216 }
217 ExitOnFailure(hr, "Failed to get provider key bundle id.");
218
219 // If a bundle id was not explicitly set, default the provider key bundle id to this bundle's provider key.
220 if (!pRegistration->sczDetectedProviderKeyBundleId || !*pRegistration->sczDetectedProviderKeyBundleId)
221 {
222 hr = StrAllocString(&pRegistration->sczDetectedProviderKeyBundleId, pRegistration->sczProviderKey, 0);
223 ExitOnFailure(hr, "Failed to initialize provider key bundle id.");
224 }
225
226LExit:
227 return hr;
228}
229
230extern "C" HRESULT DependencyDetect(
231 __in BURN_ENGINE_STATE* pEngineState
232 )
233{
234 HRESULT hr = S_OK;
235 BURN_REGISTRATION* pRegistration = &pEngineState->registration;
236 STRINGDICT_HANDLE sdIgnoredDependents = NULL;
237 BURN_PACKAGE* pPackage = NULL;
238 BOOL fSelfDependent = NULL != pRegistration->wzSelfDependent;
239 BOOL fActiveParent = NULL != pRegistration->sczActiveParent && NULL != *pRegistration->sczActiveParent;
240
241 // Always leave this empty so that all dependents get detected. Plan will ignore dependents based on its own logic.
242 hr = DictCreateStringList(&sdIgnoredDependents, INITIAL_STRINGDICT_SIZE, DICT_FLAG_CASEINSENSITIVE);
243 ExitOnFailure(hr, "Failed to create the string dictionary.");
244
245 hr = DepCheckDependents(pRegistration->hkRoot, pRegistration->sczProviderKey, 0, sdIgnoredDependents, &pRegistration->rgDependents, &pRegistration->cDependents);
246 if (E_FILENOTFOUND != hr)
247 {
248 ExitOnFailure(hr, "Failed dependents check on bundle");
249 }
250 else
251 {
252 hr = S_OK;
253 }
254
255 for (DWORD iPackage = 0; iPackage < pEngineState->packages.cPackages; ++iPackage)
256 {
257 pPackage = pEngineState->packages.rgPackages + iPackage;
258 hr = DetectPackageDependents(pPackage, sdIgnoredDependents, pRegistration);
259 ExitOnFailure(hr, "Failed to detect dependents for package '%ls'", pPackage->sczId);
260 }
261
262 for (DWORD iRelatedBundle = 0; iRelatedBundle < pEngineState->registration.relatedBundles.cRelatedBundles; ++iRelatedBundle)
263 {
264 BURN_RELATED_BUNDLE* pRelatedBundle = pEngineState->registration.relatedBundles.rgRelatedBundles + iRelatedBundle;
265 if (!pRelatedBundle->fPlannable)
266 {
267 continue;
268 }
269
270 pPackage = &pRelatedBundle->package;
271 hr = DetectPackageDependents(pPackage, sdIgnoredDependents, pRegistration);
272 ExitOnFailure(hr, "Failed to detect dependents for related bundle '%ls'", pPackage->sczId);
273 }
274
275 if (fSelfDependent || fActiveParent)
276 {
277 for (DWORD i = 0; i < pRegistration->cDependents; ++i)
278 {
279 DEPENDENCY* pDependent = pRegistration->rgDependents + i;
280
281 if (fActiveParent && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pRegistration->sczActiveParent, -1, pDependent->sczKey, -1))
282 {
283 pRegistration->fParentRegisteredAsDependent = TRUE;
284 }
285
286 if (fSelfDependent && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pRegistration->wzSelfDependent, -1, pDependent->sczKey, -1))
287 {
288 pRegistration->fSelfRegisteredAsDependent = TRUE;
289 }
290 }
291 }
292
293LExit:
294 ReleaseDict(sdIgnoredDependents);
295
296 return hr;
297}
298
299extern "C" HRESULT DependencyPlanInitialize(
300 __in const BURN_REGISTRATION* pRegistration,
301 __in BURN_PLAN* pPlan
302 )
303{
304 HRESULT hr = S_OK;
305
306 // TODO: After adding enumeration to STRINGDICT, a single STRINGDICT_HANDLE can be used everywhere.
307 for (DWORD i = 0; i < pRegistration->cIgnoredDependencies; ++i)
308 {
309 DEPENDENCY* pDependency = pRegistration->rgIgnoredDependencies + i;
310
311 hr = DepDependencyArrayAlloc(&pPlan->rgPlannedProviders, &pPlan->cPlannedProviders, pDependency->sczKey, pDependency->sczName);
312 ExitOnFailure(hr, "Failed to add the detected provider to the list of dependencies to ignore.");
313 }
314
315LExit:
316 return hr;
317}
318
319extern "C" HRESULT DependencyAllocIgnoreDependencies(
320 __in const BURN_PLAN *pPlan,
321 __out_z LPWSTR* psczIgnoreDependencies
322 )
323{
324 HRESULT hr = S_OK;
325
326 // Join the list of dependencies to ignore for each related bundle.
327 if (0 < pPlan->cPlannedProviders)
328 {
329 hr = JoinIgnoreDependencies(psczIgnoreDependencies, pPlan->rgPlannedProviders, pPlan->cPlannedProviders);
330 ExitOnFailure(hr, "Failed to join the list of dependencies to ignore.");
331 }
332
333LExit:
334 return hr;
335}
336
337extern "C" HRESULT DependencyAddIgnoreDependencies(
338 __in STRINGDICT_HANDLE sdIgnoreDependencies,
339 __in_z LPCWSTR wzAddIgnoreDependencies
340 )
341{
342 HRESULT hr = S_OK;
343 LPWSTR wzContext = NULL;
344
345 // Parse through the semicolon-delimited tokens and add to the array.
346 for (LPCWSTR wzToken = ::wcstok_s(const_cast<LPWSTR>(wzAddIgnoreDependencies), vcszIgnoreDependenciesDelim, &wzContext); wzToken; wzToken = ::wcstok_s(NULL, vcszIgnoreDependenciesDelim, &wzContext))
347 {
348 hr = DictKeyExists(sdIgnoreDependencies, wzToken);
349 if (E_NOTFOUND != hr)
350 {
351 ExitOnFailure(hr, "Failed to check the dictionary of unique dependencies.");
352 }
353 else
354 {
355 hr = DictAddKey(sdIgnoreDependencies, wzToken);
356 ExitOnFailure(hr, "Failed to add \"%ls\" to the string dictionary.", wzToken);
357 }
358 }
359
360LExit:
361 return hr;
362}
363
364extern "C" HRESULT DependencyPlanPackageBegin(
365 __in BOOL fPerMachine,
366 __in BURN_PACKAGE* pPackage,
367 __in BURN_PLAN* pPlan
368 )
369{
370 HRESULT hr = S_OK;
371 STRINGDICT_HANDLE sdIgnoredDependents = NULL;
372 BURN_DEPENDENCY_ACTION dependencyExecuteAction = BURN_DEPENDENCY_ACTION_NONE;
373 BURN_DEPENDENCY_ACTION dependencyRollbackAction = BURN_DEPENDENCY_ACTION_NONE;
374
375 pPackage->dependencyExecute = BURN_DEPENDENCY_ACTION_NONE;
376 pPackage->dependencyRollback = BURN_DEPENDENCY_ACTION_NONE;
377
378 // Make sure the package defines at least one provider.
379 if (0 == pPackage->cDependencyProviders)
380 {
381 LogId(REPORT_VERBOSE, MSG_DEPENDENCY_PACKAGE_SKIP_NOPROVIDERS, pPackage->sczId);
382 ExitFunction1(hr = S_OK);
383 }
384
385 // Make sure the package is in the same scope as the bundle.
386 if (fPerMachine != pPackage->fPerMachine)
387 {
388 LogId(REPORT_STANDARD, MSG_DEPENDENCY_PACKAGE_SKIP_WRONGSCOPE, pPackage->sczId, LoggingPerMachineToString(fPerMachine), LoggingPerMachineToString(pPackage->fPerMachine));
389 ExitFunction1(hr = S_OK);
390 }
391
392 // If we're uninstalling the package, check if any dependents are registered.
393 if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute)
394 {
395 // Build up a list of dependents to ignore, including the current bundle.
396 hr = GetIgnoredDependents(pPackage, pPlan, &sdIgnoredDependents);
397 ExitOnFailure(hr, "Failed to build the list of ignored dependents.");
398
399 // Skip the dependency check if "ALL" was authored for IGNOREDEPENDENCIES.
400 hr = DictKeyExists(sdIgnoredDependents, L"ALL");
401 if (E_NOTFOUND != hr)
402 {
403 ExitOnFailure(hr, "Failed to check if \"ALL\" was set in IGNOREDEPENDENCIES.");
404 }
405 else
406 {
407 hr = S_OK;
408
409 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
410 {
411 const BURN_DEPENDENCY_PROVIDER* pProvider = pPackage->rgDependencyProviders + i;
412
413 for (DWORD j = 0; j < pProvider->cDependents; ++j)
414 {
415 const DEPENDENCY* pDependency = pProvider->rgDependents + j;
416
417 hr = DictKeyExists(sdIgnoredDependents, pDependency->sczKey);
418 if (E_NOTFOUND == hr)
419 {
420 hr = S_OK;
421
422 if (!pPackage->fDependencyManagerWasHere)
423 {
424 pPackage->fDependencyManagerWasHere = TRUE;
425
426 LogId(REPORT_STANDARD, MSG_DEPENDENCY_PACKAGE_HASDEPENDENTS, pPackage->sczId);
427 }
428
429 LogId(REPORT_VERBOSE, MSG_DEPENDENCY_PACKAGE_DEPENDENT, pDependency->sczKey, LoggingStringOrUnknownIfNull(pDependency->sczName));
430 }
431 ExitOnFailure(hr, "Failed to check the dictionary of ignored dependents.");
432 }
433 }
434 }
435 }
436
437 // Calculate the dependency actions before the package itself is planned.
438 CalculateDependencyActionStates(pPackage, pPlan->action, &dependencyExecuteAction, &dependencyRollbackAction);
439
440 // If dependents were found, change the action to not uninstall the package.
441 if (pPackage->fDependencyManagerWasHere)
442 {
443 pPackage->execute = BOOTSTRAPPER_ACTION_STATE_NONE;
444 pPackage->rollback = BOOTSTRAPPER_ACTION_STATE_NONE;
445 }
446 else
447 {
448 // Use the calculated dependency actions as the provider actions if there
449 // are any non-imported providers that need to be registered and the package
450 // is current (not obsolete).
451 if (BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE != pPackage->currentState)
452 {
453 BOOL fAllImportedProviders = TRUE; // assume all providers were imported.
454 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
455 {
456 const BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i];
457 if (!pProvider->fImported)
458 {
459 fAllImportedProviders = FALSE;
460 break;
461 }
462 }
463
464 if (!fAllImportedProviders)
465 {
466 pPackage->providerExecute = dependencyExecuteAction;
467 pPackage->providerRollback = dependencyRollbackAction;
468 }
469 }
470
471 // If the package will be removed, add its providers to the growing list in the plan.
472 if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute)
473 {
474 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
475 {
476 const BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i];
477
478 hr = DepDependencyArrayAlloc(&pPlan->rgPlannedProviders, &pPlan->cPlannedProviders, pProvider->sczKey, NULL);
479 ExitOnFailure(hr, "Failed to add the package provider key \"%ls\" to the planned list.", pProvider->sczKey);
480 }
481 }
482 }
483
484 pPackage->dependencyExecute = dependencyExecuteAction;
485 pPackage->dependencyRollback = dependencyRollbackAction;
486
487LExit:
488 ReleaseDict(sdIgnoredDependents);
489
490 return hr;
491}
492
493extern "C" HRESULT DependencyPlanPackage(
494 __in_opt DWORD *pdwInsertSequence,
495 __in const BURN_PACKAGE* pPackage,
496 __in BURN_PLAN* pPlan
497 )
498{
499 HRESULT hr = S_OK;
500 BURN_EXECUTE_ACTION* pAction = NULL;
501
502 // If the dependency execution action is to unregister, add the dependency actions to the plan
503 // *before* the provider key is potentially removed.
504 if (BURN_DEPENDENCY_ACTION_UNREGISTER == pPackage->dependencyExecute)
505 {
506 hr = AddPackageDependencyActions(pdwInsertSequence, pPackage, pPlan, pPackage->dependencyExecute, pPackage->dependencyRollback);
507 ExitOnFailure(hr, "Failed to plan the dependency actions for package: %ls", pPackage->sczId);
508 }
509
510 // Add the provider rollback plan.
511 if (BURN_DEPENDENCY_ACTION_NONE != pPackage->providerRollback)
512 {
513 hr = PlanAppendRollbackAction(pPlan, &pAction);
514 ExitOnFailure(hr, "Failed to append provider rollback action.");
515
516 pAction->type = BURN_EXECUTE_ACTION_TYPE_PACKAGE_PROVIDER;
517 pAction->packageProvider.pPackage = const_cast<BURN_PACKAGE*>(pPackage);
518 pAction->packageProvider.action = pPackage->providerRollback;
519
520 // Put a checkpoint before the execute action so that rollback happens
521 // if execute fails.
522 hr = PlanExecuteCheckpoint(pPlan);
523 ExitOnFailure(hr, "Failed to plan provider checkpoint action.");
524 }
525
526 // Add the provider execute plan. This comes after rollback so if something goes wrong
527 // rollback will try to clean up after us.
528 if (BURN_DEPENDENCY_ACTION_NONE != pPackage->providerExecute)
529 {
530 if (NULL != pdwInsertSequence)
531 {
532 hr = PlanInsertExecuteAction(*pdwInsertSequence, pPlan, &pAction);
533 ExitOnFailure(hr, "Failed to insert provider execute action.");
534
535 // Always move the sequence after this dependency action so the provider registration
536 // stays in front of the inserted actions.
537 ++(*pdwInsertSequence);
538 }
539 else
540 {
541 hr = PlanAppendExecuteAction(pPlan, &pAction);
542 ExitOnFailure(hr, "Failed to append provider execute action.");
543 }
544
545 pAction->type = BURN_EXECUTE_ACTION_TYPE_PACKAGE_PROVIDER;
546 pAction->packageProvider.pPackage = const_cast<BURN_PACKAGE*>(pPackage);
547 pAction->packageProvider.action = pPackage->providerExecute;
548 }
549
550LExit:
551 return hr;
552}
553
554extern "C" HRESULT DependencyPlanPackageComplete(
555 __in BURN_PACKAGE* pPackage,
556 __in BURN_PLAN* pPlan
557 )
558{
559 HRESULT hr = S_OK;
560
561 // Registration of dependencies happens here, after the package is planned to be
562 // installed and all that good stuff.
563 if (BURN_DEPENDENCY_ACTION_REGISTER == pPackage->dependencyExecute)
564 {
565 // Recalculate the dependency actions in case other operations may have changed
566 // the package execution state.
567 CalculateDependencyActionStates(pPackage, pPlan->action, &pPackage->dependencyExecute, &pPackage->dependencyRollback);
568
569 // If the dependency execution action is *still* to register, add the dependency actions to the plan.
570 if (BURN_DEPENDENCY_ACTION_REGISTER == pPackage->dependencyExecute)
571 {
572 hr = AddPackageDependencyActions(NULL, pPackage, pPlan, pPackage->dependencyExecute, pPackage->dependencyRollback);
573 ExitOnFailure(hr, "Failed to plan the dependency actions for package: %ls", pPackage->sczId);
574 }
575 }
576
577LExit:
578 return hr;
579}
580
581extern "C" HRESULT DependencyExecutePackageProviderAction(
582 __in const BURN_EXECUTE_ACTION* pAction
583 )
584{
585 AssertSz(BURN_EXECUTE_ACTION_TYPE_PACKAGE_PROVIDER == pAction->type, "Execute action type not supported by this function.");
586
587 HRESULT hr = S_OK;
588 const BURN_PACKAGE* pPackage = pAction->packageProvider.pPackage;
589
590 // Register or unregister the package provider(s).
591 if (BURN_DEPENDENCY_ACTION_REGISTER == pAction->packageProvider.action)
592 {
593 hr = RegisterPackageProvider(pPackage);
594 ExitOnFailure(hr, "Failed to register the package providers.");
595 }
596 else if (BURN_DEPENDENCY_ACTION_UNREGISTER == pAction->packageProvider.action)
597 {
598 UnregisterPackageProvider(pPackage);
599 }
600
601LExit:
602 if (!pPackage->fVital)
603 {
604 hr = S_OK;
605 }
606
607 return hr;
608}
609
610extern "C" HRESULT DependencyExecutePackageDependencyAction(
611 __in BOOL fPerMachine,
612 __in const BURN_EXECUTE_ACTION* pAction
613 )
614{
615 AssertSz(BURN_EXECUTE_ACTION_TYPE_PACKAGE_DEPENDENCY == pAction->type, "Execute action type not supported by this function.");
616
617 HRESULT hr = S_OK;
618 const BURN_PACKAGE* pPackage = pAction->packageDependency.pPackage;
619
620 // Register or unregister the bundle as a dependent of each package dependency provider.
621 if (BURN_DEPENDENCY_ACTION_REGISTER == pAction->packageDependency.action)
622 {
623 hr = RegisterPackageDependency(fPerMachine, pPackage, pAction->packageDependency.sczBundleProviderKey);
624 ExitOnFailure(hr, "Failed to register the dependency on the package provider.");
625 }
626 else if (BURN_DEPENDENCY_ACTION_UNREGISTER == pAction->packageDependency.action)
627 {
628 UnregisterPackageDependency(fPerMachine, pPackage, pAction->packageDependency.sczBundleProviderKey);
629 }
630
631LExit:
632 if (!pPackage->fVital)
633 {
634 hr = S_OK;
635 }
636
637 return hr;
638}
639
640extern "C" HRESULT DependencyRegisterBundle(
641 __in const BURN_REGISTRATION* pRegistration
642 )
643{
644 HRESULT hr = S_OK;
645
646 LogId(REPORT_VERBOSE, MSG_DEPENDENCY_BUNDLE_REGISTER, pRegistration->sczProviderKey, pRegistration->pVersion->sczVersion);
647
648 // Register the bundle provider key.
649 hr = DepRegisterDependency(pRegistration->hkRoot, pRegistration->sczProviderKey, pRegistration->pVersion->sczVersion, pRegistration->sczDisplayName, pRegistration->sczId, 0);
650 ExitOnFailure(hr, "Failed to register the bundle dependency provider.");
651
652LExit:
653 return hr;
654}
655
656extern "C" HRESULT DependencyProcessDependentRegistration(
657 __in const BURN_REGISTRATION* pRegistration,
658 __in const BURN_DEPENDENT_REGISTRATION_ACTION* pAction
659 )
660{
661 HRESULT hr = S_OK;
662
663 switch (pAction->type)
664 {
665 case BURN_DEPENDENT_REGISTRATION_ACTION_TYPE_REGISTER:
666 hr = DepRegisterDependent(pRegistration->hkRoot, pRegistration->sczProviderKey, pAction->sczDependentProviderKey, NULL, NULL, 0);
667 ExitOnFailure(hr, "Failed to register dependent: %ls", pAction->sczDependentProviderKey);
668 break;
669
670 case BURN_DEPENDENT_REGISTRATION_ACTION_TYPE_UNREGISTER:
671 hr = DepUnregisterDependent(pRegistration->hkRoot, pRegistration->sczProviderKey, pAction->sczDependentProviderKey);
672 ExitOnFailure(hr, "Failed to unregister dependent: %ls", pAction->sczDependentProviderKey);
673 break;
674
675 default:
676 hr = E_INVALIDARG;
677 ExitOnRootFailure(hr, "Unrecognized registration action type: %d", pAction->type);
678 }
679
680LExit:
681 return hr;
682}
683
684extern "C" void DependencyUnregisterBundle(
685 __in const BURN_REGISTRATION* pRegistration,
686 __in const BURN_PACKAGES* pPackages
687 )
688{
689 HRESULT hr = S_OK;
690 LPCWSTR wzDependentProviderKey = pRegistration->sczId;
691
692 // Remove the bundle provider key.
693 hr = DepUnregisterDependency(pRegistration->hkRoot, pRegistration->sczProviderKey);
694 if (SUCCEEDED(hr))
695 {
696 LogId(REPORT_VERBOSE, MSG_DEPENDENCY_BUNDLE_UNREGISTERED, pRegistration->sczProviderKey);
697 }
698 else if (FAILED(hr) && E_FILENOTFOUND != hr)
699 {
700 LogId(REPORT_VERBOSE, MSG_DEPENDENCY_BUNDLE_UNREGISTERED_FAILED, pRegistration->sczProviderKey, hr);
701 }
702
703 // Best effort to make sure this bundle is not registered as a dependent for anything.
704 for (DWORD i = 0; i < pPackages->cPackages; ++i)
705 {
706 const BURN_PACKAGE* pPackage = pPackages->rgPackages + i;
707 UnregisterPackageDependency(pPackage->fPerMachine, pPackage, wzDependentProviderKey);
708 }
709
710 for (DWORD i = 0; i < pRegistration->relatedBundles.cRelatedBundles; ++i)
711 {
712 const BURN_PACKAGE* pPackage = &pRegistration->relatedBundles.rgRelatedBundles[i].package;
713 UnregisterPackageDependency(pPackage->fPerMachine, pPackage, wzDependentProviderKey);
714 }
715}
716
717// internal functions
718
719
720static HRESULT DetectPackageDependents(
721 __in BURN_PACKAGE* pPackage,
722 __in STRINGDICT_HANDLE sdIgnoredDependents,
723 __in const BURN_REGISTRATION* pRegistration
724 )
725{
726 HRESULT hr = S_OK;
727 HKEY hkHive = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
728 BOOL fCanIgnorePresence = pPackage->fCanAffectRegistration && 0 < pPackage->cDependencyProviders &&
729 (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pPackage->cacheRegistrationState || BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pPackage->installRegistrationState);
730 BOOL fBundleRegisteredAsDependent = FALSE;
731
732 // There's currently no point in getting the dependents if the scope doesn't match,
733 // because they will just get ignored.
734 if (pRegistration->fPerMachine != pPackage->fPerMachine)
735 {
736 ExitFunction();
737 }
738
739 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
740 {
741 BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i];
742
743 hr = DepCheckDependents(hkHive, pProvider->sczKey, 0, sdIgnoredDependents, &pProvider->rgDependents, &pProvider->cDependents);
744 if (E_FILENOTFOUND != hr)
745 {
746 ExitOnFailure(hr, "Failed dependents check on package provider: %ls", pProvider->sczKey);
747
748 if (!pPackage->fPackageProviderExists && (0 < pProvider->cDependents || GetProviderExists(hkHive, pProvider->sczKey)))
749 {
750 pPackage->fPackageProviderExists = TRUE;
751 }
752
753 if (fCanIgnorePresence && !fBundleRegisteredAsDependent)
754 {
755 for (DWORD iDependent = 0; iDependent < pProvider->cDependents; ++iDependent)
756 {
757 DEPENDENCY* pDependent = pProvider->rgDependents + iDependent;
758
759 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pRegistration->sczId, -1, pDependent->sczKey, -1))
760 {
761 fBundleRegisteredAsDependent = TRUE;
762 break;
763 }
764 }
765 }
766 }
767 else
768 {
769 hr = S_OK;
770
771 if (!pPackage->fPackageProviderExists && GetProviderExists(hkHive, pProvider->sczKey))
772 {
773 pPackage->fPackageProviderExists = TRUE;
774 }
775 }
776 }
777
778 // Older bundles may not have written the id so try the default.
779 if (!pPackage->fPackageProviderExists && BURN_PACKAGE_TYPE_MSI == pPackage->type && pPackage->Msi.sczProductCode && GetProviderExists(hkHive, pPackage->Msi.sczProductCode))
780 {
781 pPackage->fPackageProviderExists = TRUE;
782 }
783
784 if (fCanIgnorePresence && !fBundleRegisteredAsDependent)
785 {
786 if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pPackage->cacheRegistrationState)
787 {
788 pPackage->cacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED;
789 }
790 if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pPackage->installRegistrationState)
791 {
792 pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED;
793 }
794 if (BURN_PACKAGE_TYPE_MSP == pPackage->type)
795 {
796 for (DWORD i = 0; i < pPackage->Msp.cTargetProductCodes; ++i)
797 {
798 BURN_MSPTARGETPRODUCT* pTargetProduct = pPackage->Msp.rgTargetProducts + i;
799
800 if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pTargetProduct->registrationState)
801 {
802 pTargetProduct->registrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED;
803 }
804 }
805 }
806 }
807
808LExit:
809 return hr;
810}
811
812/********************************************************************
813 SplitIgnoreDependencies - Splits a semicolon-delimited
814 string into a list of unique dependencies to ignore.
815
816*********************************************************************/
817static HRESULT SplitIgnoreDependencies(
818 __in_z LPCWSTR wzIgnoreDependencies,
819 __deref_inout_ecount_opt(*pcDependencies) DEPENDENCY** prgDependencies,
820 __inout LPUINT pcDependencies,
821 __out BOOL* pfIgnoreAll
822 )
823{
824 HRESULT hr = S_OK;
825 LPWSTR wzContext = NULL;
826 STRINGDICT_HANDLE sdIgnoreDependencies = NULL;
827 *pfIgnoreAll = FALSE;
828
829 // Create a dictionary to hold unique dependencies.
830 hr = DictCreateStringList(&sdIgnoreDependencies, INITIAL_STRINGDICT_SIZE, DICT_FLAG_CASEINSENSITIVE);
831 ExitOnFailure(hr, "Failed to create the string dictionary.");
832
833 // Parse through the semicolon-delimited tokens and add to the array.
834 for (LPCWSTR wzToken = ::wcstok_s(const_cast<LPWSTR>(wzIgnoreDependencies), vcszIgnoreDependenciesDelim, &wzContext); wzToken; wzToken = ::wcstok_s(NULL, vcszIgnoreDependenciesDelim, &wzContext))
835 {
836 hr = DictKeyExists(sdIgnoreDependencies, wzToken);
837 if (E_NOTFOUND != hr)
838 {
839 ExitOnFailure(hr, "Failed to check the dictionary of unique dependencies.");
840 }
841 else
842 {
843 hr = DepDependencyArrayAlloc(prgDependencies, pcDependencies, wzToken, NULL);
844 ExitOnFailure(hr, "Failed to add \"%ls\" to the list of dependencies to ignore.", wzToken);
845
846 hr = DictAddKey(sdIgnoreDependencies, wzToken);
847 ExitOnFailure(hr, "Failed to add \"%ls\" to the string dictionary.", wzToken);
848
849 if (!*pfIgnoreAll && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, L"ALL", -1, wzToken, -1))
850 {
851 *pfIgnoreAll = TRUE;
852 }
853 }
854 }
855
856LExit:
857 ReleaseDict(sdIgnoreDependencies);
858
859 return hr;
860}
861
862/********************************************************************
863 JoinIgnoreDependencies - Joins a list of dependencies
864 to ignore into a semicolon-delimited string of unique values.
865
866*********************************************************************/
867static HRESULT JoinIgnoreDependencies(
868 __out_z LPWSTR* psczIgnoreDependencies,
869 __in_ecount(cDependencies) const DEPENDENCY* rgDependencies,
870 __in UINT cDependencies
871 )
872{
873 HRESULT hr = S_OK;
874 STRINGDICT_HANDLE sdIgnoreDependencies = NULL;
875
876 // Make sure we pass back an empty string if there are no dependencies.
877 if (0 == cDependencies)
878 {
879 ExitFunction1(hr = S_OK);
880 }
881
882 // Create a dictionary to hold unique dependencies.
883 hr = DictCreateStringList(&sdIgnoreDependencies, INITIAL_STRINGDICT_SIZE, DICT_FLAG_CASEINSENSITIVE);
884 ExitOnFailure(hr, "Failed to create the string dictionary.");
885
886 for (UINT i = 0; i < cDependencies; ++i)
887 {
888 const DEPENDENCY* pDependency = &rgDependencies[i];
889
890 hr = DictKeyExists(sdIgnoreDependencies, pDependency->sczKey);
891 if (E_NOTFOUND != hr)
892 {
893 ExitOnFailure(hr, "Failed to check the dictionary of unique dependencies.");
894 }
895 else
896 {
897 if (0 < i)
898 {
899 hr = StrAllocConcat(psczIgnoreDependencies, vcszIgnoreDependenciesDelim, 1);
900 ExitOnFailure(hr, "Failed to append the string delimiter.");
901 }
902
903 hr = StrAllocConcat(psczIgnoreDependencies, pDependency->sczKey, 0);
904 ExitOnFailure(hr, "Failed to append the key \"%ls\".", pDependency->sczKey);
905
906 hr = DictAddKey(sdIgnoreDependencies, pDependency->sczKey);
907 ExitOnFailure(hr, "Failed to add \"%ls\" to the string dictionary.", pDependency->sczKey);
908 }
909 }
910
911LExit:
912 ReleaseDict(sdIgnoreDependencies);
913
914 return hr;
915}
916
917/********************************************************************
918 GetIgnoredDependents - Combines the current bundle's
919 provider key, packages' provider keys that are being uninstalled,
920 and any ignored dependencies authored for packages into a string
921 list to pass to deputil.
922
923*********************************************************************/
924static HRESULT GetIgnoredDependents(
925 __in const BURN_PACKAGE* pPackage,
926 __in const BURN_PLAN* pPlan,
927 __deref_inout STRINGDICT_HANDLE* psdIgnoredDependents
928 )
929{
930 HRESULT hr = S_OK;
931 LPWSTR sczIgnoreDependencies = NULL;
932
933 // Create the dictionary and add the bundle provider key initially.
934 hr = DictCreateStringList(psdIgnoredDependents, INITIAL_STRINGDICT_SIZE, DICT_FLAG_CASEINSENSITIVE);
935 ExitOnFailure(hr, "Failed to create the string dictionary.");
936
937 hr = DictAddKey(*psdIgnoredDependents, pPlan->wzBundleProviderKey);
938 ExitOnFailure(hr, "Failed to add the bundle provider key \"%ls\" to the list of ignored dependencies.", pPlan->wzBundleProviderKey);
939
940 // Add previously planned package providers to the dictionary.
941 for (DWORD i = 0; i < pPlan->cPlannedProviders; ++i)
942 {
943 const DEPENDENCY* pDependency = &pPlan->rgPlannedProviders[i];
944
945 hr = DictAddKey(*psdIgnoredDependents, pDependency->sczKey);
946 ExitOnFailure(hr, "Failed to add the package provider key \"%ls\" to the list of ignored dependencies.", pDependency->sczKey);
947 }
948
949 // Get the IGNOREDEPENDENCIES property if defined.
950 hr = PackageGetProperty(pPackage, DEPENDENCY_IGNOREDEPENDENCIES, &sczIgnoreDependencies);
951 if (E_NOTFOUND != hr)
952 {
953 ExitOnFailure(hr, "Failed to get the package property: %ls", DEPENDENCY_IGNOREDEPENDENCIES);
954
955 hr = DependencyAddIgnoreDependencies(*psdIgnoredDependents, sczIgnoreDependencies);
956 ExitOnFailure(hr, "Failed to add the authored ignored dependencies to the cumulative list of ignored dependencies.");
957 }
958 else
959 {
960 hr = S_OK;
961 }
962
963LExit:
964 ReleaseStr(sczIgnoreDependencies);
965
966 return hr;
967}
968
969/********************************************************************
970 GetProviderExists - Gets whether the provider key is registered.
971
972*********************************************************************/
973static BOOL GetProviderExists(
974 __in HKEY hkRoot,
975 __in_z LPCWSTR wzProviderKey
976 )
977{
978 HRESULT hr = DepGetProviderInformation(hkRoot, wzProviderKey, NULL, NULL, NULL);
979 return SUCCEEDED(hr);
980}
981
982/********************************************************************
983 CalculateDependencyActionStates - Calculates the dependency execute and
984 rollback actions for a package.
985
986*********************************************************************/
987static void CalculateDependencyActionStates(
988 __in const BURN_PACKAGE* pPackage,
989 __in const BOOTSTRAPPER_ACTION action,
990 __out BURN_DEPENDENCY_ACTION* pDependencyExecuteAction,
991 __out BURN_DEPENDENCY_ACTION* pDependencyRollbackAction
992 )
993{
994 switch (action)
995 {
996 case BOOTSTRAPPER_ACTION_UNINSTALL:
997 // Always remove the dependency when uninstalling a bundle even if the package is absent.
998 *pDependencyExecuteAction = BURN_DEPENDENCY_ACTION_UNREGISTER;
999 break;
1000 case BOOTSTRAPPER_ACTION_INSTALL: __fallthrough;
1001 case BOOTSTRAPPER_ACTION_CACHE:
1002 // Always remove the dependency during rollback when installing a bundle.
1003 *pDependencyRollbackAction = BURN_DEPENDENCY_ACTION_UNREGISTER;
1004 __fallthrough;
1005 case BOOTSTRAPPER_ACTION_MODIFY: __fallthrough;
1006 case BOOTSTRAPPER_ACTION_REPAIR:
1007 switch (pPackage->execute)
1008 {
1009 case BOOTSTRAPPER_ACTION_STATE_NONE:
1010 switch (pPackage->requested)
1011 {
1012 case BOOTSTRAPPER_REQUEST_STATE_NONE:
1013 // Register if a newer, compatible package is already installed.
1014 switch (pPackage->currentState)
1015 {
1016 case BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE:
1017 if (!pPackage->fPackageProviderExists)
1018 {
1019 break;
1020 }
1021 __fallthrough;
1022 case BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED:
1023 *pDependencyExecuteAction = BURN_DEPENDENCY_ACTION_REGISTER;
1024 break;
1025 }
1026 break;
1027 case BOOTSTRAPPER_REQUEST_STATE_PRESENT: __fallthrough;
1028 case BOOTSTRAPPER_REQUEST_STATE_MEND: __fallthrough;
1029 case BOOTSTRAPPER_REQUEST_STATE_REPAIR:
1030 // Register if the package is requested but already installed.
1031 switch (pPackage->currentState)
1032 {
1033 case BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE:
1034 if (!pPackage->fPackageProviderExists)
1035 {
1036 break;
1037 }
1038 __fallthrough;
1039 case BOOTSTRAPPER_PACKAGE_STATE_PRESENT: __fallthrough;
1040 case BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED:
1041 *pDependencyExecuteAction = BURN_DEPENDENCY_ACTION_REGISTER;
1042 break;
1043 }
1044 break;
1045 }
1046 break;
1047 case BOOTSTRAPPER_ACTION_STATE_UNINSTALL:
1048 *pDependencyExecuteAction = BURN_DEPENDENCY_ACTION_UNREGISTER;
1049 break;
1050 case BOOTSTRAPPER_ACTION_STATE_INSTALL: __fallthrough;
1051 case BOOTSTRAPPER_ACTION_STATE_MODIFY: __fallthrough;
1052 case BOOTSTRAPPER_ACTION_STATE_MEND: __fallthrough;
1053 case BOOTSTRAPPER_ACTION_STATE_REPAIR: __fallthrough;
1054 case BOOTSTRAPPER_ACTION_STATE_MINOR_UPGRADE: __fallthrough;
1055 *pDependencyExecuteAction = BURN_DEPENDENCY_ACTION_REGISTER;
1056 break;
1057 }
1058 break;
1059 }
1060
1061 switch (*pDependencyExecuteAction)
1062 {
1063 case BURN_DEPENDENCY_ACTION_REGISTER:
1064 switch (pPackage->currentState)
1065 {
1066 case BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE: __fallthrough;
1067 case BOOTSTRAPPER_PACKAGE_STATE_ABSENT: __fallthrough;
1068 *pDependencyRollbackAction = BURN_DEPENDENCY_ACTION_UNREGISTER;
1069 break;
1070 }
1071 break;
1072 case BURN_DEPENDENCY_ACTION_UNREGISTER:
1073 switch (pPackage->currentState)
1074 {
1075 case BOOTSTRAPPER_PACKAGE_STATE_PRESENT: __fallthrough;
1076 case BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED:
1077 *pDependencyRollbackAction = BURN_DEPENDENCY_ACTION_REGISTER;
1078 break;
1079 }
1080 break;
1081 }
1082}
1083
1084/********************************************************************
1085 AddPackageDependencyActions - Adds the dependency execute and rollback
1086 actions to the plan.
1087
1088*********************************************************************/
1089static HRESULT AddPackageDependencyActions(
1090 __in_opt DWORD *pdwInsertSequence,
1091 __in const BURN_PACKAGE* pPackage,
1092 __in BURN_PLAN* pPlan,
1093 __in const BURN_DEPENDENCY_ACTION dependencyExecuteAction,
1094 __in const BURN_DEPENDENCY_ACTION dependencyRollbackAction
1095 )
1096{
1097 HRESULT hr = S_OK;
1098 BURN_EXECUTE_ACTION* pAction = NULL;
1099
1100 // Add the rollback plan.
1101 if (BURN_DEPENDENCY_ACTION_NONE != dependencyRollbackAction)
1102 {
1103 hr = PlanAppendRollbackAction(pPlan, &pAction);
1104 ExitOnFailure(hr, "Failed to append rollback action.");
1105
1106 pAction->type = BURN_EXECUTE_ACTION_TYPE_PACKAGE_DEPENDENCY;
1107 pAction->packageDependency.pPackage = const_cast<BURN_PACKAGE*>(pPackage);
1108 pAction->packageDependency.action = dependencyRollbackAction;
1109
1110 hr = StrAllocString(&pAction->packageDependency.sczBundleProviderKey, pPlan->wzBundleProviderKey, 0);
1111 ExitOnFailure(hr, "Failed to copy the bundle dependency provider.");
1112
1113 // Put a checkpoint before the execute action so that rollback happens
1114 // if execute fails.
1115 hr = PlanExecuteCheckpoint(pPlan);
1116 ExitOnFailure(hr, "Failed to plan dependency checkpoint action.");
1117 }
1118
1119 // Add the execute plan. This comes after rollback so if something goes wrong
1120 // rollback will try to clean up after us correctly.
1121 if (BURN_DEPENDENCY_ACTION_NONE != dependencyExecuteAction)
1122 {
1123 if (NULL != pdwInsertSequence)
1124 {
1125 hr = PlanInsertExecuteAction(*pdwInsertSequence, pPlan, &pAction);
1126 ExitOnFailure(hr, "Failed to insert execute action.");
1127
1128 // Always move the sequence after this dependency action so the dependency registration
1129 // stays in front of the inserted actions.
1130 ++(*pdwInsertSequence);
1131 }
1132 else
1133 {
1134 hr = PlanAppendExecuteAction(pPlan, &pAction);
1135 ExitOnFailure(hr, "Failed to append execute action.");
1136 }
1137
1138 pAction->type = BURN_EXECUTE_ACTION_TYPE_PACKAGE_DEPENDENCY;
1139 pAction->packageDependency.pPackage = const_cast<BURN_PACKAGE*>(pPackage);
1140 pAction->packageDependency.action = dependencyExecuteAction;
1141
1142 hr = StrAllocString(&pAction->packageDependency.sczBundleProviderKey, pPlan->wzBundleProviderKey, 0);
1143 ExitOnFailure(hr, "Failed to copy the bundle dependency provider.");
1144 }
1145
1146LExit:
1147 return hr;
1148}
1149
1150static HRESULT RegisterPackageProvider(
1151 __in const BURN_PACKAGE* pPackage
1152 )
1153{
1154 HRESULT hr = S_OK;
1155 LPWSTR wzId = NULL;
1156 HKEY hkRoot = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1157
1158 if (pPackage->rgDependencyProviders)
1159 {
1160 if (BURN_PACKAGE_TYPE_MSI == pPackage->type)
1161 {
1162 wzId = pPackage->Msi.sczProductCode;
1163 }
1164 else if (BURN_PACKAGE_TYPE_MSP == pPackage->type)
1165 {
1166 wzId = pPackage->Msp.sczPatchCode;
1167 }
1168
1169 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
1170 {
1171 const BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i];
1172
1173 if (!pProvider->fImported)
1174 {
1175 LogId(REPORT_VERBOSE, MSG_DEPENDENCY_PACKAGE_REGISTER, pProvider->sczKey, pProvider->sczVersion, pPackage->sczId);
1176
1177 hr = DepRegisterDependency(hkRoot, pProvider->sczKey, pProvider->sczVersion, pProvider->sczDisplayName, wzId, 0);
1178 ExitOnFailure(hr, "Failed to register the package dependency provider: %ls", pProvider->sczKey);
1179 }
1180 }
1181 }
1182
1183LExit:
1184 if (!pPackage->fVital)
1185 {
1186 hr = S_OK;
1187 }
1188
1189 return hr;
1190}
1191
1192/********************************************************************
1193 UnregisterPackageProvider - Removes each dependency provider
1194 for the package (if not imported from the package itself).
1195
1196 Note: Does not check for existing dependents before removing the key.
1197*********************************************************************/
1198static void UnregisterPackageProvider(
1199 __in const BURN_PACKAGE* pPackage
1200 )
1201{
1202 HRESULT hr = S_OK;
1203 HKEY hkRoot = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1204
1205 if (pPackage->rgDependencyProviders)
1206 {
1207 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
1208 {
1209 const BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i];
1210
1211 if (!pProvider->fImported)
1212 {
1213 hr = DepUnregisterDependency(hkRoot, pProvider->sczKey);
1214 if (SUCCEEDED(hr))
1215 {
1216 LogId(REPORT_VERBOSE, MSG_DEPENDENCY_PACKAGE_UNREGISTERED, pProvider->sczKey, pPackage->sczId);
1217 }
1218 else if (FAILED(hr) && E_FILENOTFOUND != hr)
1219 {
1220 LogId(REPORT_VERBOSE, MSG_DEPENDENCY_PACKAGE_UNREGISTERED_FAILED, pProvider->sczKey, pPackage->sczId, hr);
1221 }
1222 }
1223 }
1224 }
1225}
1226
1227/********************************************************************
1228 RegisterPackageDependency - Registers the provider key
1229 as a dependent of a package.
1230
1231*********************************************************************/
1232static HRESULT RegisterPackageDependency(
1233 __in BOOL fPerMachine,
1234 __in const BURN_PACKAGE* pPackage,
1235 __in_z LPCWSTR wzDependentProviderKey
1236 )
1237{
1238 HRESULT hr = S_OK;
1239 HKEY hkRoot = fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1240
1241 // Do not register a dependency on a package in a different install context.
1242 if (fPerMachine != pPackage->fPerMachine)
1243 {
1244 LogId(REPORT_STANDARD, MSG_DEPENDENCY_PACKAGE_SKIP_WRONGSCOPE, pPackage->sczId, LoggingPerMachineToString(fPerMachine), LoggingPerMachineToString(pPackage->fPerMachine));
1245 ExitFunction1(hr = S_OK);
1246 }
1247
1248 if (pPackage->rgDependencyProviders)
1249 {
1250 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
1251 {
1252 const BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i];
1253
1254 LogId(REPORT_VERBOSE, MSG_DEPENDENCY_PACKAGE_REGISTER_DEPENDENCY, wzDependentProviderKey, pProvider->sczKey, pPackage->sczId);
1255
1256 hr = DepRegisterDependent(hkRoot, pProvider->sczKey, wzDependentProviderKey, NULL, NULL, 0);
1257 if (E_FILENOTFOUND != hr || pPackage->fVital)
1258 {
1259 ExitOnFailure(hr, "Failed to register the dependency on package dependency provider: %ls", pProvider->sczKey);
1260 }
1261 else
1262 {
1263 LogId(REPORT_VERBOSE, MSG_DEPENDENCY_PACKAGE_SKIP_MISSING, pProvider->sczKey, pPackage->sczId);
1264 hr = S_OK;
1265 }
1266 }
1267 }
1268
1269LExit:
1270 return hr;
1271}
1272
1273/********************************************************************
1274 UnregisterPackageDependency - Unregisters the provider key
1275 as a dependent of a package.
1276
1277*********************************************************************/
1278static void UnregisterPackageDependency(
1279 __in BOOL fPerMachine,
1280 __in const BURN_PACKAGE* pPackage,
1281 __in_z LPCWSTR wzDependentProviderKey
1282 )
1283{
1284 HRESULT hr = S_OK;
1285 HKEY hkRoot = fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1286
1287 // Should be no registration to remove since we don't write keys across contexts.
1288 if (fPerMachine != pPackage->fPerMachine)
1289 {
1290 LogId(REPORT_STANDARD, MSG_DEPENDENCY_PACKAGE_SKIP_WRONGSCOPE, pPackage->sczId, LoggingPerMachineToString(fPerMachine), LoggingPerMachineToString(pPackage->fPerMachine));
1291 return;
1292 }
1293
1294 // Loop through each package provider and remove the bundle dependency key.
1295 if (pPackage->rgDependencyProviders)
1296 {
1297 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
1298 {
1299 const BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i];
1300
1301 hr = DepUnregisterDependent(hkRoot, pProvider->sczKey, wzDependentProviderKey);
1302 if (SUCCEEDED(hr))
1303 {
1304 LogId(REPORT_VERBOSE, MSG_DEPENDENCY_PACKAGE_UNREGISTERED_DEPENDENCY, wzDependentProviderKey, pProvider->sczKey, pPackage->sczId);
1305 }
1306 else if (FAILED(hr) && E_FILENOTFOUND != hr)
1307 {
1308 LogId(REPORT_VERBOSE, MSG_DEPENDENCY_PACKAGE_UNREGISTERED_DEPENDENCY_FAILED, wzDependentProviderKey, pProvider->sczKey, pPackage->sczId, hr);
1309 }
1310 }
1311 }
1312}