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