aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2021-02-01 20:36:39 -0600
committerSean Hall <r.sean.hall@gmail.com>2021-02-04 22:16:10 -0600
commitcc5fe7c79aad14819df1b4cb134884b80a945141 (patch)
tree4b0ab44744a6b989f784292d438ef0654d9b03ac
parentcede270b2bd3da6bd8d5205b8834e786c8d6c1ce (diff)
downloadwix-cc5fe7c79aad14819df1b4cb134884b80a945141.tar.gz
wix-cc5fe7c79aad14819df1b4cb134884b80a945141.tar.bz2
wix-cc5fe7c79aad14819df1b4cb134884b80a945141.zip
Move registry checks for dependency ref-counting into Detect.
-rw-r--r--src/engine/core.cpp12
-rw-r--r--src/engine/dependency.cpp349
-rw-r--r--src/engine/dependency.h29
-rw-r--r--src/engine/detect.cpp28
-rw-r--r--src/engine/engine.mc11
-rw-r--r--src/engine/package.cpp2
-rw-r--r--src/engine/package.h4
-rw-r--r--src/engine/plan.cpp104
-rw-r--r--src/engine/plan.h1
-rw-r--r--src/engine/registration.h9
-rw-r--r--src/engine/relatedbundle.cpp2
-rw-r--r--src/test/BurnUnitTest/PlanTest.cpp23
12 files changed, 354 insertions, 220 deletions
diff --git a/src/engine/core.cpp b/src/engine/core.cpp
index 77e2dd82..ae09ea65 100644
--- a/src/engine/core.cpp
+++ b/src/engine/core.cpp
@@ -97,7 +97,7 @@ extern "C" HRESULT CoreInitialize(
97 ExitOnFailure(hr, "Failed to load manifest."); 97 ExitOnFailure(hr, "Failed to load manifest.");
98 98
99 hr = ContainersInitialize(&pEngineState->containers, &pEngineState->section); 99 hr = ContainersInitialize(&pEngineState->containers, &pEngineState->section);
100 ExitOnFailure(hr, "Failed to intialize containers."); 100 ExitOnFailure(hr, "Failed to initialize containers.");
101 101
102 // Parse command line. 102 // Parse command line.
103 hr = ParseCommandLine(pEngineState->argc, pEngineState->argv, &pEngineState->command, &pEngineState->companionConnection, &pEngineState->embeddedConnection, &pEngineState->variables, &pEngineState->mode, &pEngineState->automaticUpdates, &pEngineState->fDisableSystemRestore, &sczSourceProcessPath, &sczOriginalSource, &pEngineState->fDisableUnelevate, &pEngineState->log.dwAttributes, &pEngineState->log.sczPath, &pEngineState->registration.sczActiveParent, &pEngineState->sczIgnoreDependencies, &pEngineState->registration.sczAncestors, &sczSanitizedCommandLine); 103 hr = ParseCommandLine(pEngineState->argc, pEngineState->argv, &pEngineState->command, &pEngineState->companionConnection, &pEngineState->embeddedConnection, &pEngineState->variables, &pEngineState->mode, &pEngineState->automaticUpdates, &pEngineState->fDisableSystemRestore, &sczSourceProcessPath, &sczOriginalSource, &pEngineState->fDisableUnelevate, &pEngineState->log.dwAttributes, &pEngineState->log.sczPath, &pEngineState->registration.sczActiveParent, &pEngineState->sczIgnoreDependencies, &pEngineState->registration.sczAncestors, &sczSanitizedCommandLine);
@@ -105,6 +105,9 @@ extern "C" HRESULT CoreInitialize(
105 105
106 LogId(REPORT_STANDARD, MSG_BURN_COMMAND_LINE, sczSanitizedCommandLine ? sczSanitizedCommandLine : L""); 106 LogId(REPORT_STANDARD, MSG_BURN_COMMAND_LINE, sczSanitizedCommandLine ? sczSanitizedCommandLine : L"");
107 107
108 hr = DependencyInitialize(&pEngineState->registration, pEngineState->sczIgnoreDependencies);
109 ExitOnFailure(hr, "Failed to initialize dependency data.");
110
108 // Retain whether bundle was initially run elevated. 111 // Retain whether bundle was initially run elevated.
109 ProcElevated(::GetCurrentProcess(), &fElevated); 112 ProcElevated(::GetCurrentProcess(), &fElevated);
110 113
@@ -332,6 +335,9 @@ extern "C" HRESULT CoreDetect(
332 } 335 }
333 } 336 }
334 337
338 hr = DependencyDetect(pEngineState);
339 ExitOnFailure(hr, "Failed to detect the dependencies.");
340
335 // Log the detected states. 341 // Log the detected states.
336 for (DWORD iPackage = 0; iPackage < pEngineState->packages.cPackages; ++iPackage) 342 for (DWORD iPackage = 0; iPackage < pEngineState->packages.cPackages; ++iPackage)
337 { 343 {
@@ -419,7 +425,7 @@ extern "C" HRESULT CorePlan(
419 hr = PlanSetResumeCommand(&pEngineState->registration, action, &pEngineState->command, &pEngineState->log); 425 hr = PlanSetResumeCommand(&pEngineState->registration, action, &pEngineState->command, &pEngineState->log);
420 ExitOnFailure(hr, "Failed to set resume command"); 426 ExitOnFailure(hr, "Failed to set resume command");
421 427
422 hr = DependencyPlanInitialize(pEngineState, &pEngineState->plan); 428 hr = DependencyPlanInitialize(&pEngineState->registration, &pEngineState->plan);
423 ExitOnFailure(hr, "Failed to initialize the dependencies for the plan."); 429 ExitOnFailure(hr, "Failed to initialize the dependencies for the plan.");
424 430
425 if (BOOTSTRAPPER_ACTION_LAYOUT == action) 431 if (BOOTSTRAPPER_ACTION_LAYOUT == action)
@@ -457,7 +463,7 @@ extern "C" HRESULT CorePlan(
457 BOOL fContinuePlanning = TRUE; // assume we'll be able to keep planning after registration. 463 BOOL fContinuePlanning = TRUE; // assume we'll be able to keep planning after registration.
458 pEngineState->plan.fPerMachine = pEngineState->registration.fPerMachine; // default the scope of the plan to the per-machine state of the bundle. 464 pEngineState->plan.fPerMachine = pEngineState->registration.fPerMachine; // default the scope of the plan to the per-machine state of the bundle.
459 465
460 hr = PlanRegistration(&pEngineState->plan, &pEngineState->registration, pEngineState->command.resumeType, pEngineState->command.relationType, pEngineState->sczIgnoreDependencies, &fContinuePlanning); 466 hr = PlanRegistration(&pEngineState->plan, &pEngineState->registration, pEngineState->command.resumeType, pEngineState->command.relationType, &fContinuePlanning);
461 ExitOnFailure(hr, "Failed to plan registration."); 467 ExitOnFailure(hr, "Failed to plan registration.");
462 468
463 if (fContinuePlanning) 469 if (fContinuePlanning)
diff --git a/src/engine/dependency.cpp b/src/engine/dependency.cpp
index af4ab0a1..1c33aaf2 100644
--- a/src/engine/dependency.cpp
+++ b/src/engine/dependency.cpp
@@ -10,6 +10,12 @@ const LPCWSTR vcszIgnoreDependenciesDelim = L";";
10 10
11// internal function declarations 11// internal function declarations
12 12
13static HRESULT DetectPackageDependents(
14 __in BURN_PACKAGE* pPackage,
15 __in STRINGDICT_HANDLE sdIgnoredDependents,
16 __in const BURN_REGISTRATION* pRegistration
17 );
18
13static HRESULT SplitIgnoreDependencies( 19static HRESULT SplitIgnoreDependencies(
14 __in_z LPCWSTR wzIgnoreDependencies, 20 __in_z LPCWSTR wzIgnoreDependencies,
15 __deref_inout_ecount_opt(*pcDependencies) DEPENDENCY** prgDependencies, 21 __deref_inout_ecount_opt(*pcDependencies) DEPENDENCY** prgDependencies,
@@ -28,11 +34,9 @@ static HRESULT GetIgnoredDependents(
28 __deref_inout STRINGDICT_HANDLE* psdIgnoredDependents 34 __deref_inout STRINGDICT_HANDLE* psdIgnoredDependents
29 ); 35 );
30 36
31static HRESULT GetProviderInformation( 37static BOOL GetProviderExists(
32 __in HKEY hkRoot, 38 __in HKEY hkRoot,
33 __in_z LPCWSTR wzProviderKey, 39 __in_z LPCWSTR wzProviderKey
34 __deref_opt_out_z_opt LPWSTR* psczProviderKey,
35 __deref_opt_out_z_opt LPWSTR* psczId
36 ); 40 );
37 41
38static void CalculateDependencyActionStates( 42static void CalculateDependencyActionStates(
@@ -70,20 +74,18 @@ static void UnregisterPackageDependency(
70 __in_z LPCWSTR wzDependentProviderKey 74 __in_z LPCWSTR wzDependentProviderKey
71 ); 75 );
72 76
73static BOOL PackageProviderExists(
74 __in const BURN_PACKAGE* pPackage
75 );
76
77 77
78// functions 78// functions
79 79
80extern "C" void DependencyUninitialize( 80extern "C" void DependencyUninitializeProvider(
81 __in BURN_DEPENDENCY_PROVIDER* pProvider 81 __in BURN_DEPENDENCY_PROVIDER* pProvider
82 ) 82 )
83{ 83{
84 ReleaseStr(pProvider->sczKey); 84 ReleaseStr(pProvider->sczKey);
85 ReleaseStr(pProvider->sczVersion); 85 ReleaseStr(pProvider->sczVersion);
86 ReleaseStr(pProvider->sczDisplayName); 86 ReleaseStr(pProvider->sczDisplayName);
87 ReleaseDependencyArray(pProvider->rgDependents, pProvider->cDependents);
88
87 memset(pProvider, 0, sizeof(BURN_DEPENDENCY_PROVIDER)); 89 memset(pProvider, 0, sizeof(BURN_DEPENDENCY_PROVIDER));
88} 90}
89 91
@@ -167,45 +169,33 @@ LExit:
167 return hr; 169 return hr;
168} 170}
169 171
170extern "C" HRESULT DependencyDetectProviderKeyPackageId( 172extern "C" HRESULT DependencyInitialize(
171 __in const BURN_PACKAGE* pPackage, 173 __in BURN_REGISTRATION* pRegistration,
172 __deref_opt_out_z_opt LPWSTR* psczProviderKey, 174 __in_z_opt LPCWSTR wzIgnoreDependencies
173 __deref_opt_out_z_opt LPWSTR* psczId
174 ) 175 )
175{ 176{
176 HRESULT hr = E_NOTFOUND; 177 HRESULT hr = S_OK;
177 LPWSTR wzProviderKey = NULL;
178 HKEY hkRoot = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
179 178
180 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i) 179 // If no parent was specified at all, use the bundle id as the self dependent.
180 if (!pRegistration->sczActiveParent)
181 { 181 {
182 const BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i]; 182 pRegistration->wzSelfDependent = pRegistration->sczId;
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 } 183 }
194 184 else if (*pRegistration->sczActiveParent) // if parent was specified use that as the self dependent.
195 // Older bundles may not have written the id so try the default.
196 if (BURN_PACKAGE_TYPE_MSI == pPackage->type)
197 { 185 {
198 wzProviderKey = pPackage->Msi.sczProductCode; 186 pRegistration->wzSelfDependent = pRegistration->sczActiveParent;
199 } 187 }
188 // else parent:none was used which means we should not register a dependency on ourself.
189
190 // The current bundle provider key should always be ignored for dependency checks.
191 hr = DepDependencyArrayAlloc(&pRegistration->rgIgnoredDependencies, &pRegistration->cIgnoredDependencies, pRegistration->sczProviderKey, NULL);
192 ExitOnFailure(hr, "Failed to add the bundle provider key to the list of dependencies to ignore.");
200 193
201 if (wzProviderKey) 194 // Add the list of dependencies to ignore.
195 if (wzIgnoreDependencies)
202 { 196 {
203 hr = GetProviderInformation(hkRoot, wzProviderKey, psczProviderKey, psczId); 197 hr = SplitIgnoreDependencies(wzIgnoreDependencies, &pRegistration->rgIgnoredDependencies, &pRegistration->cIgnoredDependencies);
204 if (E_NOTFOUND == hr) 198 ExitOnFailure(hr, "Failed to split the list of dependencies to ignore.");
205 {
206 ExitFunction();
207 }
208 ExitOnFailure(hr, "Failed to get the package default provider information.");
209 } 199 }
210 200
211LExit: 201LExit:
@@ -236,23 +226,77 @@ LExit:
236 return hr; 226 return hr;
237} 227}
238 228
229extern "C" HRESULT DependencyDetect(
230 __in BURN_ENGINE_STATE* pEngineState
231 )
232{
233 HRESULT hr = S_OK;
234 BURN_REGISTRATION* pRegistration = &pEngineState->registration;
235 STRINGDICT_HANDLE sdIgnoredDependents = NULL;
236 BURN_PACKAGE* pPackage = NULL;
237
238 // Always leave this empty so that all dependents get detected. Plan will ignore dependents based on its own logic.
239 hr = DictCreateStringList(&sdIgnoredDependents, INITIAL_STRINGDICT_SIZE, DICT_FLAG_CASEINSENSITIVE);
240 ExitOnFailure(hr, "Failed to create the string dictionary.");
241
242 hr = DepCheckDependents(pRegistration->hkRoot, pRegistration->sczProviderKey, 0, sdIgnoredDependents, &pRegistration->rgDependents, &pRegistration->cDependents);
243 if (E_FILENOTFOUND != hr)
244 {
245 ExitOnFailure(hr, "Failed dependents check on bundle");
246 }
247 else
248 {
249 hr = S_OK;
250 }
251
252 for (DWORD iPackage = 0; iPackage < pEngineState->packages.cPackages; ++iPackage)
253 {
254 pPackage = pEngineState->packages.rgPackages + iPackage;
255 hr = DetectPackageDependents(pPackage, sdIgnoredDependents, pRegistration);
256 ExitOnFailure(hr, "Failed to detect dependents for package '%ls'", pPackage->sczId);
257 }
258
259 for (DWORD iRelatedBundle = 0; iRelatedBundle < pEngineState->registration.relatedBundles.cRelatedBundles; ++iRelatedBundle)
260 {
261 pPackage = &pEngineState->registration.relatedBundles.rgRelatedBundles[iRelatedBundle].package;
262 hr = DetectPackageDependents(pPackage, sdIgnoredDependents, pRegistration);
263 ExitOnFailure(hr, "Failed to detect dependents for related bundle '%ls'", pPackage->sczId);
264 }
265
266 if (pRegistration->wzSelfDependent)
267 {
268 for (DWORD i = 0; i < pRegistration->cDependents; ++i)
269 {
270 DEPENDENCY* pDependent = pRegistration->rgDependents + i;
271
272 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pRegistration->wzSelfDependent, -1, pDependent->sczKey, -1))
273 {
274 pRegistration->fSelfRegisteredAsDependent = TRUE;
275 break;
276 }
277 }
278 }
279
280LExit:
281 ReleaseDict(sdIgnoredDependents);
282
283 return hr;
284}
285
239extern "C" HRESULT DependencyPlanInitialize( 286extern "C" HRESULT DependencyPlanInitialize(
240 __in const BURN_ENGINE_STATE* pEngineState, 287 __in const BURN_REGISTRATION* pRegistration,
241 __in BURN_PLAN* pPlan 288 __in BURN_PLAN* pPlan
242 ) 289 )
243{ 290{
244 HRESULT hr = S_OK; 291 HRESULT hr = S_OK;
245 292
246 // The current bundle provider key should always be ignored for dependency checks. 293 // TODO: After adding enumeration to STRINGDICT, a single STRINGDICT_HANDLE can be used everywhere.
247 hr = DepDependencyArrayAlloc(&pPlan->rgPlannedProviders, &pPlan->cPlannedProviders, pEngineState->registration.sczProviderKey, NULL); 294 for (DWORD i = 0; i < pRegistration->cIgnoredDependencies; ++i)
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 { 295 {
253 // TODO: After adding enumeration to STRINGDICT, a single STRINGDICT_HANDLE can be used everywhere. 296 DEPENDENCY* pDependency = pRegistration->rgIgnoredDependencies + i;
254 hr = SplitIgnoreDependencies(pEngineState->sczIgnoreDependencies, &pPlan->rgPlannedProviders, &pPlan->cPlannedProviders); 297
255 ExitOnFailure(hr, "Failed to split the list of dependencies to ignore."); 298 hr = DepDependencyArrayAlloc(&pPlan->rgPlannedProviders, &pPlan->cPlannedProviders, pDependency->sczKey, pDependency->sczName);
299 ExitOnFailure(hr, "Failed to add the detected provider to the list of dependencies to ignore.");
256 } 300 }
257 301
258LExit: 302LExit:
@@ -323,9 +367,6 @@ extern "C" HRESULT DependencyPlanPackageBegin(
323{ 367{
324 HRESULT hr = S_OK; 368 HRESULT hr = S_OK;
325 STRINGDICT_HANDLE sdIgnoredDependents = NULL; 369 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; 370 BURN_DEPENDENCY_ACTION dependencyExecuteAction = BURN_DEPENDENCY_ACTION_NONE;
330 BURN_DEPENDENCY_ACTION dependencyRollbackAction = BURN_DEPENDENCY_ACTION_NONE; 371 BURN_DEPENDENCY_ACTION dependencyRollbackAction = BURN_DEPENDENCY_ACTION_NONE;
331 372
@@ -361,18 +402,31 @@ extern "C" HRESULT DependencyPlanPackageBegin(
361 } 402 }
362 else 403 else
363 { 404 {
405 hr = S_OK;
406
364 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i) 407 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
365 { 408 {
366 const BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i]; 409 const BURN_DEPENDENCY_PROVIDER* pProvider = pPackage->rgDependencyProviders + i;
367 410
368 hr = DepCheckDependents(hkHive, pProvider->sczKey, 0, sdIgnoredDependents, &rgDependents, &cDependents); 411 for (DWORD j = 0; j < pProvider->cDependents; ++j)
369 if (E_FILENOTFOUND != hr)
370 {
371 ExitOnFailure(hr, "Failed dependents check on package provider: %ls", pProvider->sczKey);
372 }
373 else
374 { 412 {
375 hr = S_OK; 413 const DEPENDENCY* pDependency = pProvider->rgDependents + j;
414
415 hr = DictKeyExists(sdIgnoredDependents, pDependency->sczKey);
416 if (E_NOTFOUND == hr)
417 {
418 hr = S_OK;
419
420 if (!pPackage->fDependencyManagerWasHere)
421 {
422 pPackage->fDependencyManagerWasHere = TRUE;
423
424 LogId(REPORT_STANDARD, MSG_DEPENDENCY_PACKAGE_HASDEPENDENTS, pPackage->sczId);
425 }
426
427 LogId(REPORT_VERBOSE, MSG_DEPENDENCY_PACKAGE_DEPENDENT, pDependency->sczKey, LoggingStringOrUnknownIfNull(pDependency->sczName));
428 }
429 ExitOnFailure(hr, "Failed to check the dictionary of ignored dependents.");
376 } 430 }
377 } 431 }
378 } 432 }
@@ -382,52 +436,46 @@ extern "C" HRESULT DependencyPlanPackageBegin(
382 CalculateDependencyActionStates(pPackage, pPlan->action, &dependencyExecuteAction, &dependencyRollbackAction); 436 CalculateDependencyActionStates(pPackage, pPlan->action, &dependencyExecuteAction, &dependencyRollbackAction);
383 437
384 // If dependents were found, change the action to not uninstall the package. 438 // If dependents were found, change the action to not uninstall the package.
385 if (0 < cDependents) 439 if (pPackage->fDependencyManagerWasHere)
386 { 440 {
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; 441 pPackage->execute = BOOTSTRAPPER_ACTION_STATE_NONE;
397 pPackage->rollback = BOOTSTRAPPER_ACTION_STATE_NONE; 442 pPackage->rollback = BOOTSTRAPPER_ACTION_STATE_NONE;
398 } 443 }
399 // Use the calculated dependency actions as the provider actions if there 444 else
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 { 445 {
404 BOOL fAllImportedProviders = TRUE; // assume all providers were imported. 446 // Use the calculated dependency actions as the provider actions if there
405 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i) 447 // are any non-imported providers that need to be registered and the package
448 // is current (not obsolete).
449 if (BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE != pPackage->currentState)
406 { 450 {
407 const BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i]; 451 BOOL fAllImportedProviders = TRUE; // assume all providers were imported.
408 if (!pProvider->fImported) 452 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
409 { 453 {
410 fAllImportedProviders = FALSE; 454 const BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i];
411 break; 455 if (!pProvider->fImported)
456 {
457 fAllImportedProviders = FALSE;
458 break;
459 }
412 } 460 }
413 }
414 461
415 if (!fAllImportedProviders) 462 if (!fAllImportedProviders)
416 { 463 {
417 pPackage->providerExecute = dependencyExecuteAction; 464 pPackage->providerExecute = dependencyExecuteAction;
418 pPackage->providerRollback = dependencyRollbackAction; 465 pPackage->providerRollback = dependencyRollbackAction;
466 }
419 } 467 }
420 }
421 468
422 // If the package will be removed, add its providers to the growing list in the plan. 469 // If the package will be removed, add its providers to the growing list in the plan.
423 if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute) 470 if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute)
424 {
425 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
426 { 471 {
427 const BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i]; 472 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
473 {
474 const BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i];
428 475
429 hr = DepDependencyArrayAlloc(&pPlan->rgPlannedProviders, &pPlan->cPlannedProviders, pProvider->sczKey, NULL); 476 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); 477 ExitOnFailure(hr, "Failed to add the package provider key \"%ls\" to the planned list.", pProvider->sczKey);
478 }
431 } 479 }
432 } 480 }
433 481
@@ -435,7 +483,6 @@ extern "C" HRESULT DependencyPlanPackageBegin(
435 pPackage->dependencyRollback = dependencyRollbackAction; 483 pPackage->dependencyRollback = dependencyRollbackAction;
436 484
437LExit: 485LExit:
438 ReleaseDependencyArray(rgDependents, cDependents);
439 ReleaseDict(sdIgnoredDependents); 486 ReleaseDict(sdIgnoredDependents);
440 487
441 return hr; 488 return hr;
@@ -652,6 +699,58 @@ extern "C" void DependencyUnregisterBundle(
652 699
653// internal functions 700// internal functions
654 701
702
703static HRESULT DetectPackageDependents(
704 __in BURN_PACKAGE* pPackage,
705 __in STRINGDICT_HANDLE sdIgnoredDependents,
706 __in const BURN_REGISTRATION* pRegistration
707 )
708{
709 HRESULT hr = S_OK;
710 HKEY hkHive = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
711
712 // There's currently no point in getting the dependents if the scope doesn't match,
713 // because they will just get ignored.
714 if (pRegistration->fPerMachine != pPackage->fPerMachine)
715 {
716 ExitFunction();
717 }
718
719 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
720 {
721 BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i];
722
723 hr = DepCheckDependents(hkHive, pProvider->sczKey, 0, sdIgnoredDependents, &pProvider->rgDependents, &pProvider->cDependents);
724 if (E_FILENOTFOUND != hr)
725 {
726 ExitOnFailure(hr, "Failed dependents check on package provider: %ls", pProvider->sczKey);
727
728 if (!pPackage->fPackageProviderExists && (0 < pProvider->cDependents || GetProviderExists(hkHive, pProvider->sczKey)))
729 {
730 pPackage->fPackageProviderExists = TRUE;
731 }
732 }
733 else
734 {
735 hr = S_OK;
736
737 if (!pPackage->fPackageProviderExists && GetProviderExists(hkHive, pProvider->sczKey))
738 {
739 pPackage->fPackageProviderExists = TRUE;
740 }
741 }
742 }
743
744 // Older bundles may not have written the id so try the default.
745 if (!pPackage->fPackageProviderExists && BURN_PACKAGE_TYPE_MSI == pPackage->type && pPackage->Msi.sczProductCode && GetProviderExists(hkHive, pPackage->Msi.sczProductCode))
746 {
747 pPackage->fPackageProviderExists = TRUE;
748 }
749
750LExit:
751 return hr;
752}
753
655/******************************************************************** 754/********************************************************************
656 SplitIgnoreDependencies - Splits a semicolon-delimited 755 SplitIgnoreDependencies - Splits a semicolon-delimited
657 string into a list of unique dependencies to ignore. 756 string into a list of unique dependencies to ignore.
@@ -803,52 +902,16 @@ LExit:
803} 902}
804 903
805/******************************************************************** 904/********************************************************************
806 GetProviderId - Gets the ID of the package given the provider key. 905 GetProviderExists - Gets whether the provider key is registered.
807 906
808*********************************************************************/ 907*********************************************************************/
809static HRESULT GetProviderInformation( 908static BOOL GetProviderExists(
810 __in HKEY hkRoot, 909 __in HKEY hkRoot,
811 __in_z LPCWSTR wzProviderKey, 910 __in_z LPCWSTR wzProviderKey
812 __deref_opt_out_z_opt LPWSTR* psczProviderKey,
813 __deref_opt_out_z_opt LPWSTR* psczId
814 ) 911 )
815{ 912{
816 HRESULT hr = S_OK; 913 HRESULT hr = DepGetProviderInformation(hkRoot, wzProviderKey, NULL, NULL, NULL);
817 LPWSTR sczId = NULL; 914 return SUCCEEDED(hr);
818
819 hr = DepGetProviderInformation(hkRoot, wzProviderKey, &sczId, NULL, NULL);
820 if (E_NOTFOUND == hr)
821 {
822 ExitFunction();
823 }
824 ExitOnFailure(hr, "Failed to get the provider key package id.");
825
826 // If the id was registered return it and exit.
827 if (sczId && *sczId)
828 {
829 if (psczProviderKey)
830 {
831 hr = StrAllocString(psczProviderKey, wzProviderKey, 0);
832 ExitOnFailure(hr, "Failed to copy the provider key.");
833 }
834
835 if (psczId)
836 {
837 *psczId = sczId;
838 sczId = NULL;
839 }
840
841 ExitFunction();
842 }
843 else
844 {
845 hr = E_NOTFOUND;
846 }
847
848LExit:
849 ReleaseStr(sczId);
850
851 return hr;
852} 915}
853 916
854/******************************************************************** 917/********************************************************************
@@ -886,7 +949,7 @@ static void CalculateDependencyActionStates(
886 switch (pPackage->currentState) 949 switch (pPackage->currentState)
887 { 950 {
888 case BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE: 951 case BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE:
889 if (!PackageProviderExists(pPackage)) 952 if (!pPackage->fPackageProviderExists)
890 { 953 {
891 break; 954 break;
892 } 955 }
@@ -902,7 +965,7 @@ static void CalculateDependencyActionStates(
902 switch (pPackage->currentState) 965 switch (pPackage->currentState)
903 { 966 {
904 case BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE: 967 case BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE:
905 if (!PackageProviderExists(pPackage)) 968 if (!pPackage->fPackageProviderExists)
906 { 969 {
907 break; 970 break;
908 } 971 }
@@ -1181,15 +1244,3 @@ static void UnregisterPackageDependency(
1181 } 1244 }
1182 } 1245 }
1183} 1246}
1184
1185/********************************************************************
1186 PackageProviderExists - Checks if a package provider is registered.
1187
1188*********************************************************************/
1189static BOOL PackageProviderExists(
1190 __in const BURN_PACKAGE* pPackage
1191 )
1192{
1193 HRESULT hr = DependencyDetectProviderKeyPackageId(pPackage, NULL, NULL);
1194 return SUCCEEDED(hr);
1195}
diff --git a/src/engine/dependency.h b/src/engine/dependency.h
index 905857e0..5390bede 100644
--- a/src/engine/dependency.h
+++ b/src/engine/dependency.h
@@ -14,11 +14,11 @@ const LPCWSTR DEPENDENCY_IGNOREDEPENDENCIES = L"IGNOREDEPENDENCIES";
14// function declarations 14// function declarations
15 15
16/******************************************************************** 16/********************************************************************
17 DependencyUninitialize - Frees and zeros memory allocated in the 17 DependencyUninitializeProvider - Frees and zeros memory allocated in
18 dependency. 18 the dependency provider.
19 19
20*********************************************************************/ 20*********************************************************************/
21void DependencyUninitialize( 21void DependencyUninitializeProvider(
22 __in BURN_DEPENDENCY_PROVIDER* pProvider 22 __in BURN_DEPENDENCY_PROVIDER* pProvider
23 ); 23 );
24 24
@@ -32,16 +32,9 @@ HRESULT DependencyParseProvidersFromXml(
32 __in IXMLDOMNode* pixnPackage 32 __in IXMLDOMNode* pixnPackage
33 ); 33 );
34 34
35/******************************************************************** 35HRESULT DependencyInitialize(
36 DependencyDetectProviderKeyPackageId - Detect if the provider key is 36 __in BURN_REGISTRATION* pRegistration,
37 registered and if so what package code is registered. 37 __in_z_opt LPCWSTR wzIgnoreDependencies
38
39 Note: Returns E_NOTFOUND if the provider key is not registered.
40*********************************************************************/
41HRESULT DependencyDetectProviderKeyPackageId(
42 __in const BURN_PACKAGE* pPackage,
43 __deref_opt_out_z_opt LPWSTR* psczProviderKey,
44 __deref_opt_out_z_opt LPWSTR* psczId
45 ); 38 );
46 39
47/******************************************************************** 40/********************************************************************
@@ -55,11 +48,19 @@ HRESULT DependencyDetectProviderKeyBundleId(
55 ); 48 );
56 49
57/******************************************************************** 50/********************************************************************
51 DependencyDetect - Detects dependency information.
52
53*********************************************************************/
54HRESULT DependencyDetect(
55 __in BURN_ENGINE_STATE* pEngineState
56 );
57
58/********************************************************************
58 DependencyPlanInitialize - Initializes the plan. 59 DependencyPlanInitialize - Initializes the plan.
59 60
60*********************************************************************/ 61*********************************************************************/
61HRESULT DependencyPlanInitialize( 62HRESULT DependencyPlanInitialize(
62 __in const BURN_ENGINE_STATE* pEngineState, 63 __in const BURN_REGISTRATION* pRegistration,
63 __in BURN_PLAN* pPlan 64 __in BURN_PLAN* pPlan
64 ); 65 );
65 66
diff --git a/src/engine/detect.cpp b/src/engine/detect.cpp
index 63e66539..3b8d63e2 100644
--- a/src/engine/detect.cpp
+++ b/src/engine/detect.cpp
@@ -41,12 +41,28 @@ extern "C" void DetectReset(
41 ReleaseNullStr(pRegistration->sczDetectedProviderKeyBundleId); 41 ReleaseNullStr(pRegistration->sczDetectedProviderKeyBundleId);
42 pRegistration->fEnabledForwardCompatibleBundle = FALSE; 42 pRegistration->fEnabledForwardCompatibleBundle = FALSE;
43 PackageUninitialize(&pRegistration->forwardCompatibleBundle); 43 PackageUninitialize(&pRegistration->forwardCompatibleBundle);
44 pRegistration->fSelfRegisteredAsDependent = FALSE;
45
46 if (pRegistration->rgIgnoredDependencies)
47 {
48 ReleaseDependencyArray(pRegistration->rgIgnoredDependencies, pRegistration->cIgnoredDependencies);
49 }
50 pRegistration->rgIgnoredDependencies = NULL;
51 pRegistration->cIgnoredDependencies = 0;
52
53 if (pRegistration->rgDependents)
54 {
55 ReleaseDependencyArray(pRegistration->rgDependents, pRegistration->cDependents);
56 }
57 pRegistration->rgDependents = NULL;
58 pRegistration->cDependents = 0;
44 59
45 for (DWORD iPackage = 0; iPackage < pPackages->cPackages; ++iPackage) 60 for (DWORD iPackage = 0; iPackage < pPackages->cPackages; ++iPackage)
46 { 61 {
47 BURN_PACKAGE* pPackage = pPackages->rgPackages + iPackage; 62 BURN_PACKAGE* pPackage = pPackages->rgPackages + iPackage;
48 63
49 pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_UNKNOWN; 64 pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_UNKNOWN;
65 pPackage->fPackageProviderExists = FALSE;
50 66
51 pPackage->cache = BURN_CACHE_STATE_NONE; 67 pPackage->cache = BURN_CACHE_STATE_NONE;
52 for (DWORD iPayload = 0; iPayload < pPackage->cPayloads; ++iPayload) 68 for (DWORD iPayload = 0; iPayload < pPackage->cPayloads; ++iPayload)
@@ -69,6 +85,18 @@ extern "C" void DetectReset(
69 ReleaseNullMem(pPackage->Msp.rgTargetProducts); 85 ReleaseNullMem(pPackage->Msp.rgTargetProducts);
70 pPackage->Msp.cTargetProductCodes = 0; 86 pPackage->Msp.cTargetProductCodes = 0;
71 } 87 }
88
89 for (DWORD iProvider = 0; iProvider < pPackage->cDependencyProviders; ++iProvider)
90 {
91 BURN_DEPENDENCY_PROVIDER* pProvider = pPackage->rgDependencyProviders + iProvider;
92
93 if (pProvider->rgDependents)
94 {
95 ReleaseDependencyArray(pProvider->rgDependents, pProvider->cDependents);
96 }
97 pProvider->rgDependents = NULL;
98 pProvider->cDependents = 0;
99 }
72 } 100 }
73 101
74 for (DWORD iPatchInfo = 0; iPatchInfo < pPackages->cPatchInfo; ++iPatchInfo) 102 for (DWORD iPatchInfo = 0; iPatchInfo < pPackages->cPatchInfo; ++iPatchInfo)
diff --git a/src/engine/engine.mc b/src/engine/engine.mc
index ad86308c..d6e9751a 100644
--- a/src/engine/engine.mc
+++ b/src/engine/engine.mc
@@ -356,7 +356,7 @@ MessageId=210
356Severity=Warning 356Severity=Warning
357SymbolicName=MSG_PLAN_SKIPPED_DUE_TO_DEPENDENTS 357SymbolicName=MSG_PLAN_SKIPPED_DUE_TO_DEPENDENTS
358Language=English 358Language=English
359Plan skipped due to %1!u! remaining dependents 359Plan skipped due to remaining dependents:
360. 360.
361 361
362MessageId=211 362MessageId=211
@@ -595,7 +595,7 @@ MessageId=327
595Severity=Warning 595Severity=Warning
596SymbolicName=MSG_DEPENDENCY_PACKAGE_HASDEPENDENTS 596SymbolicName=MSG_DEPENDENCY_PACKAGE_HASDEPENDENTS
597Language=English 597Language=English
598Will not uninstall package: %1!ls!, found dependents: %2!d! 598Will not uninstall package: %1!ls!, found dependents:
599. 599.
600 600
601MessageId=328 601MessageId=328
@@ -640,6 +640,13 @@ Language=English
640Could not remove bundle dependency provider: %1!ls!, error: 0x%2!x! 640Could not remove bundle dependency provider: %1!ls!, error: 0x%2!x!
641. 641.
642 642
643MessageId=334
644Severity=Warning
645SymbolicName=MSG_DEPENDENCY_BUNDLE_DEPENDENT
646Language=English
647Found dependent: %1!ls!, name: %2!ls!
648.
649
643MessageId=335 650MessageId=335
644Severity=Success 651Severity=Success
645SymbolicName=MSG_ACQUIRE_BUNDLE_PAYLOAD 652SymbolicName=MSG_ACQUIRE_BUNDLE_PAYLOAD
diff --git a/src/engine/package.cpp b/src/engine/package.cpp
index 527766eb..701dda08 100644
--- a/src/engine/package.cpp
+++ b/src/engine/package.cpp
@@ -323,7 +323,7 @@ extern "C" void PackageUninitialize(
323 { 323 {
324 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i) 324 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
325 { 325 {
326 DependencyUninitialize(pPackage->rgDependencyProviders + i); 326 DependencyUninitializeProvider(pPackage->rgDependencyProviders + i);
327 } 327 }
328 MemFree(pPackage->rgDependencyProviders); 328 MemFree(pPackage->rgDependencyProviders);
329 } 329 }
diff --git a/src/engine/package.h b/src/engine/package.h
index 1a4f7060..8f801e85 100644
--- a/src/engine/package.h
+++ b/src/engine/package.h
@@ -159,6 +159,9 @@ typedef struct _BURN_DEPENDENCY_PROVIDER
159 LPWSTR sczVersion; 159 LPWSTR sczVersion;
160 LPWSTR sczDisplayName; 160 LPWSTR sczDisplayName;
161 BOOL fImported; 161 BOOL fImported;
162
163 DEPENDENCY* rgDependents; // only valid after Detect.
164 UINT cDependents; // only valid after Detect.
162} BURN_DEPENDENCY_PROVIDER; 165} BURN_DEPENDENCY_PROVIDER;
163 166
164typedef struct _BURN_ROLLBACK_BOUNDARY 167typedef struct _BURN_ROLLBACK_BOUNDARY
@@ -199,6 +202,7 @@ typedef struct _BURN_PACKAGE
199 202
200 BOOTSTRAPPER_PACKAGE_STATE currentState; // only valid after Detect. 203 BOOTSTRAPPER_PACKAGE_STATE currentState; // only valid after Detect.
201 BURN_CACHE_STATE cache; // only valid after Detect. 204 BURN_CACHE_STATE cache; // only valid after Detect.
205 BOOL fPackageProviderExists; // only valid after Detect.
202 BOOTSTRAPPER_REQUEST_STATE defaultRequested;// only valid during Plan. 206 BOOTSTRAPPER_REQUEST_STATE defaultRequested;// only valid during Plan.
203 BOOTSTRAPPER_REQUEST_STATE requested; // only valid during Plan. 207 BOOTSTRAPPER_REQUEST_STATE requested; // only valid during Plan.
204 BOOL fAcquire; // only valid during Plan. 208 BOOL fAcquire; // only valid during Plan.
diff --git a/src/engine/plan.cpp b/src/engine/plan.cpp
index a45eab62..6f5407b9 100644
--- a/src/engine/plan.cpp
+++ b/src/engine/plan.cpp
@@ -574,15 +574,12 @@ extern "C" HRESULT PlanRegistration(
574 __in BURN_REGISTRATION* pRegistration, 574 __in BURN_REGISTRATION* pRegistration,
575 __in BOOTSTRAPPER_RESUME_TYPE resumeType, 575 __in BOOTSTRAPPER_RESUME_TYPE resumeType,
576 __in BOOTSTRAPPER_RELATION_TYPE relationType, 576 __in BOOTSTRAPPER_RELATION_TYPE relationType,
577 __in_z_opt LPCWSTR wzIgnoreDependencies,
578 __out BOOL* pfContinuePlanning 577 __out BOOL* pfContinuePlanning
579 ) 578 )
580{ 579{
581 HRESULT hr = S_OK; 580 HRESULT hr = S_OK;
582 LPCWSTR wzSelfDependent = NULL; 581 STRINGDICT_HANDLE sdBundleDependents = NULL;
583 STRINGDICT_HANDLE sdIgnoreDependents = NULL; 582 STRINGDICT_HANDLE sdIgnoreDependents = NULL;
584 DEPENDENCY* rgDependencies = NULL;
585 UINT cDependencies = 0;
586 583
587 pPlan->fRegister = TRUE; // register the bundle since we're modifying machine state. 584 pPlan->fRegister = TRUE; // register the bundle since we're modifying machine state.
588 585
@@ -591,17 +588,6 @@ extern "C" HRESULT PlanRegistration(
591 588
592 pPlan->fDisallowRemoval = FALSE; // by default the bundle can be planned to be removed 589 pPlan->fDisallowRemoval = FALSE; // by default the bundle can be planned to be removed
593 590
594 // If no parent was specified at all, use the bundle id as the self dependent.
595 if (!pRegistration->sczActiveParent)
596 {
597 wzSelfDependent = pRegistration->sczId;
598 }
599 else if (*pRegistration->sczActiveParent) // if parent was specified use that as the self dependent.
600 {
601 wzSelfDependent = pRegistration->sczActiveParent;
602 }
603 // else parent:none was used which means we should not register a dependency on ourself.
604
605 if (BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action) 591 if (BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action)
606 { 592 {
607 // If our provider key was detected and it points to our current bundle then we can 593 // If our provider key was detected and it points to our current bundle then we can
@@ -622,12 +608,12 @@ extern "C" HRESULT PlanRegistration(
622 608
623 // If the self-dependent dependent exists, plan its removal. If we did not do this, we 609 // If the self-dependent dependent exists, plan its removal. If we did not do this, we
624 // would prevent self-removal. 610 // would prevent self-removal.
625 if (wzSelfDependent && DependencyDependentExists(pRegistration, wzSelfDependent)) 611 if (pRegistration->fSelfRegisteredAsDependent)
626 { 612 {
627 hr = AddRegistrationAction(pPlan, BURN_DEPENDENT_REGISTRATION_ACTION_TYPE_UNREGISTER, wzSelfDependent, pRegistration->sczId); 613 hr = AddRegistrationAction(pPlan, BURN_DEPENDENT_REGISTRATION_ACTION_TYPE_UNREGISTER, pRegistration->wzSelfDependent, pRegistration->sczId);
628 ExitOnFailure(hr, "Failed to allocate registration action."); 614 ExitOnFailure(hr, "Failed to allocate registration action.");
629 615
630 hr = DependencyAddIgnoreDependencies(sdIgnoreDependents, wzSelfDependent); 616 hr = DependencyAddIgnoreDependencies(sdIgnoreDependents, pRegistration->wzSelfDependent);
631 ExitOnFailure(hr, "Failed to add self-dependent to ignore dependents."); 617 ExitOnFailure(hr, "Failed to add self-dependent to ignore dependents.");
632 } 618 }
633 619
@@ -637,10 +623,20 @@ extern "C" HRESULT PlanRegistration(
637 if (BOOTSTRAPPER_RELATION_UPGRADE != relationType) 623 if (BOOTSTRAPPER_RELATION_UPGRADE != relationType)
638 { 624 {
639 // If there were other dependencies to ignore, add them. 625 // If there were other dependencies to ignore, add them.
640 if (wzIgnoreDependencies && *wzIgnoreDependencies) 626 for (DWORD iDependency = 0; iDependency < pRegistration->cIgnoredDependencies; ++iDependency)
641 { 627 {
642 hr = DependencyAddIgnoreDependencies(sdIgnoreDependents, wzIgnoreDependencies); 628 DEPENDENCY* pDependency = pRegistration->rgIgnoredDependencies + iDependency;
643 ExitOnFailure(hr, "Failed to add dependents ignored from command-line."); 629
630 hr = DictKeyExists(sdIgnoreDependents, pDependency->sczKey);
631 if (E_NOTFOUND != hr)
632 {
633 ExitOnFailure(hr, "Failed to check the dictionary of ignored dependents.");
634 }
635 else
636 {
637 hr = DictAddKey(sdIgnoreDependents, pDependency->sczKey);
638 ExitOnFailure(hr, "Failed to add dependent key to ignored dependents.");
639 }
644 } 640 }
645 641
646 // For addon or patch bundles, dependent related bundles should be ignored. This allows 642 // For addon or patch bundles, dependent related bundles should be ignored. This allows
@@ -661,22 +657,29 @@ extern "C" HRESULT PlanRegistration(
661 } 657 }
662 } 658 }
663 659
664 // If there are any (non-ignored and not-planned-to-be-removed) dependents left, uninstall. 660 // If there are any (non-ignored and not-planned-to-be-removed) dependents left, skip planning.
665 hr = DepCheckDependents(pRegistration->hkRoot, pRegistration->sczProviderKey, 0, sdIgnoreDependents, &rgDependencies, &cDependencies); 661 for (DWORD iDependent = 0; iDependent < pRegistration->cDependents; ++iDependent)
666 if (E_FILENOTFOUND == hr)
667 { 662 {
668 hr = S_OK; 663 DEPENDENCY* pDependent = pRegistration->rgDependents + iDependent;
669 } 664
670 else if (SUCCEEDED(hr) && cDependencies) 665 hr = DictKeyExists(sdIgnoreDependents, pDependent->sczKey);
671 { 666 if (E_NOTFOUND == hr)
672 // TODO: callback to the BA and let it have the option to ignore any of these dependents? 667 {
668 hr = S_OK;
673 669
674 pPlan->fDisallowRemoval = TRUE; // ensure the registration stays 670 // TODO: callback to the BA and let it have the option to ignore this dependent?
675 *pfContinuePlanning = FALSE; // skip the rest of planning. 671 if (!pPlan->fDisallowRemoval)
672 {
673 pPlan->fDisallowRemoval = TRUE; // ensure the registration stays
674 *pfContinuePlanning = FALSE; // skip the rest of planning.
675
676 LogId(REPORT_STANDARD, MSG_PLAN_SKIPPED_DUE_TO_DEPENDENTS);
677 }
676 678
677 LogId(REPORT_STANDARD, MSG_PLAN_SKIPPED_DUE_TO_DEPENDENTS, cDependencies); 679 LogId(REPORT_VERBOSE, MSG_DEPENDENCY_BUNDLE_DEPENDENT, pDependent->sczKey, LoggingStringOrUnknownIfNull(pDependent->sczName));
680 }
681 ExitOnFailure(hr, "Failed to check for remaining dependents during planning.");
678 } 682 }
679 ExitOnFailure(hr, "Failed to check for remaining dependents during planning.");
680 } 683 }
681 } 684 }
682 else 685 else
@@ -707,6 +710,23 @@ extern "C" HRESULT PlanRegistration(
707 // if broken. 710 // if broken.
708 pPlan->dependencyRegistrationAction = BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER; 711 pPlan->dependencyRegistrationAction = BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER;
709 712
713 // Create the dictionary of bundle dependents.
714 hr = DictCreateStringList(&sdBundleDependents, 5, DICT_FLAG_CASEINSENSITIVE);
715 ExitOnFailure(hr, "Failed to create the string dictionary.");
716
717 for (DWORD iDependent = 0; iDependent < pRegistration->cDependents; ++iDependent)
718 {
719 DEPENDENCY* pDependent = pRegistration->rgDependents + iDependent;
720
721 hr = DictKeyExists(sdBundleDependents, pDependent->sczKey);
722 if (E_NOTFOUND == hr)
723 {
724 hr = DictAddKey(sdBundleDependents, pDependent->sczKey);
725 ExitOnFailure(hr, "Failed to add dependent key to bundle dependents.");
726 }
727 ExitOnFailure(hr, "Failed to check the dictionary of bundle dependents.");
728 }
729
710 // Register each dependent related bundle. The ensures that addons and patches are reference 730 // Register each dependent related bundle. The ensures that addons and patches are reference
711 // counted and stick around until the last targeted bundle is removed. 731 // counted and stick around until the last targeted bundle is removed.
712 for (DWORD i = 0; i < pRegistration->relatedBundles.cRelatedBundles; ++i) 732 for (DWORD i = 0; i < pRegistration->relatedBundles.cRelatedBundles; ++i)
@@ -719,11 +739,16 @@ extern "C" HRESULT PlanRegistration(
719 { 739 {
720 const BURN_DEPENDENCY_PROVIDER* pProvider = pRelatedBundle->package.rgDependencyProviders + j; 740 const BURN_DEPENDENCY_PROVIDER* pProvider = pRelatedBundle->package.rgDependencyProviders + j;
721 741
722 if (!DependencyDependentExists(pRegistration, pProvider->sczKey)) 742 hr = DictKeyExists(sdBundleDependents, pProvider->sczKey);
743 if (E_NOTFOUND == hr)
723 { 744 {
745 hr = DictAddKey(sdBundleDependents, pProvider->sczKey);
746 ExitOnFailure(hr, "Failed to add new dependent key to bundle dependents.");
747
724 hr = AddRegistrationAction(pPlan, BURN_DEPENDENT_REGISTRATION_ACTION_TYPE_REGISTER, pProvider->sczKey, pRelatedBundle->package.sczId); 748 hr = AddRegistrationAction(pPlan, BURN_DEPENDENT_REGISTRATION_ACTION_TYPE_REGISTER, pProvider->sczKey, pRelatedBundle->package.sczId);
725 ExitOnFailure(hr, "Failed to add registration action for dependent related bundle."); 749 ExitOnFailure(hr, "Failed to add registration action for dependent related bundle.");
726 } 750 }
751 ExitOnFailure(hr, "Failed to check the dictionary of bundle dependents.");
727 } 752 }
728 } 753 }
729 } 754 }
@@ -731,19 +756,16 @@ extern "C" HRESULT PlanRegistration(
731 // Only do the following if we decided there was a dependent self to register. If so and and an explicit parent was 756 // Only do the following if we decided there was a dependent self to register. If so and and an explicit parent was
732 // provided, register dependent self. Otherwise, if this bundle is not an addon or patch bundle then self-regisiter 757 // provided, register dependent self. Otherwise, if this bundle is not an addon or patch bundle then self-regisiter
733 // as our own dependent. 758 // as our own dependent.
734 if (wzSelfDependent && (pRegistration->sczActiveParent || !fAddonOrPatchBundle)) 759 if (pRegistration->wzSelfDependent && !pRegistration->fSelfRegisteredAsDependent && (pRegistration->sczActiveParent || !fAddonOrPatchBundle))
735 { 760 {
736 if (!DependencyDependentExists(pRegistration, wzSelfDependent)) 761 hr = AddRegistrationAction(pPlan, BURN_DEPENDENT_REGISTRATION_ACTION_TYPE_REGISTER, pRegistration->wzSelfDependent, pRegistration->sczId);
737 { 762 ExitOnFailure(hr, "Failed to add registration action for self dependent.");
738 hr = AddRegistrationAction(pPlan, BURN_DEPENDENT_REGISTRATION_ACTION_TYPE_REGISTER, wzSelfDependent, pRegistration->sczId);
739 ExitOnFailure(hr, "Failed to add registration action for self dependent.");
740 }
741 } 763 }
742 } 764 }
743 765
744LExit: 766LExit:
767 ReleaseDict(sdBundleDependents);
745 ReleaseDict(sdIgnoreDependents); 768 ReleaseDict(sdIgnoreDependents);
746 ReleaseDependencyArray(rgDependencies, cDependencies);
747 769
748 return hr; 770 return hr;
749} 771}
diff --git a/src/engine/plan.h b/src/engine/plan.h
index cb64f891..54189973 100644
--- a/src/engine/plan.h
+++ b/src/engine/plan.h
@@ -418,7 +418,6 @@ HRESULT PlanRegistration(
418 __in BURN_REGISTRATION* pRegistration, 418 __in BURN_REGISTRATION* pRegistration,
419 __in BOOTSTRAPPER_RESUME_TYPE resumeType, 419 __in BOOTSTRAPPER_RESUME_TYPE resumeType,
420 __in BOOTSTRAPPER_RELATION_TYPE relationType, 420 __in BOOTSTRAPPER_RELATION_TYPE relationType,
421 __in_z_opt LPCWSTR wzIgnoreDependencies,
422 __out BOOL* pfContinuePlanning 421 __out BOOL* pfContinuePlanning
423 ); 422 );
424HRESULT PlanPassThroughBundle( 423HRESULT PlanPassThroughBundle(
diff --git a/src/engine/registration.h b/src/engine/registration.h
index dc9bc5b7..c1e52ac9 100644
--- a/src/engine/registration.h
+++ b/src/engine/registration.h
@@ -139,8 +139,13 @@ typedef struct _BURN_REGISTRATION
139 // Update registration 139 // Update registration
140 BURN_UPDATE_REGISTRATION update; 140 BURN_UPDATE_REGISTRATION update;
141 141
142 // Only valid after detect. 142 BURN_RELATED_BUNDLES relatedBundles; // Only valid after detect.
143 BURN_RELATED_BUNDLES relatedBundles; 143 DEPENDENCY* rgIgnoredDependencies; // Only valid after detect.
144 UINT cIgnoredDependencies; // Only valid after detect.
145 DEPENDENCY* rgDependents; // Only valid after detect.
146 UINT cDependents; // Only valid after detect.
147 LPCWSTR wzSelfDependent; // Only valid after detect.
148 BOOL fSelfRegisteredAsDependent; // Only valid after detect.
144 149
145 LPWSTR sczDetectedProviderKeyBundleId; 150 LPWSTR sczDetectedProviderKeyBundleId;
146 LPWSTR sczAncestors; 151 LPWSTR sczAncestors;
diff --git a/src/engine/relatedbundle.cpp b/src/engine/relatedbundle.cpp
index 7b0da4a4..bc79b954 100644
--- a/src/engine/relatedbundle.cpp
+++ b/src/engine/relatedbundle.cpp
@@ -459,7 +459,7 @@ static HRESULT LoadRelatedBundleFromKey(
459 ExitOnFailure(hr, "Failed to initialize related bundle to represent bundle: %ls", wzRelatedBundleId); 459 ExitOnFailure(hr, "Failed to initialize related bundle to represent bundle: %ls", wzRelatedBundleId);
460 460
461LExit: 461LExit:
462 DependencyUninitialize(&dependencyProvider); 462 DependencyUninitializeProvider(&dependencyProvider);
463 ReleaseStr(sczCachePath); 463 ReleaseStr(sczCachePath);
464 ReleaseStr(sczBundleVersion); 464 ReleaseStr(sczBundleVersion);
465 465
diff --git a/src/test/BurnUnitTest/PlanTest.cpp b/src/test/BurnUnitTest/PlanTest.cpp
index 71e455c3..fb4ca246 100644
--- a/src/test/BurnUnitTest/PlanTest.cpp
+++ b/src/test/BurnUnitTest/PlanTest.cpp
@@ -552,9 +552,23 @@ namespace Bootstrapper
552 ReleaseStr(sczFilePath); 552 ReleaseStr(sczFilePath);
553 } 553 }
554 554
555 DependencyInitialize(&pEngineState->registration, NULL);
556
555 pEngineState->userExperience.pfnBAProc = PlanTestBAProc; 557 pEngineState->userExperience.pfnBAProc = PlanTestBAProc;
556 } 558 }
557 559
560 void PlanTestDetect(BURN_ENGINE_STATE* pEngineState)
561 {
562 HRESULT hr = S_OK;
563 BURN_REGISTRATION* pRegistration = &pEngineState->registration;
564
565 DetectReset(pRegistration, &pEngineState->packages);
566 PlanReset(&pEngineState->plan, &pEngineState->packages);
567
568 hr = DepDependencyArrayAlloc(&pRegistration->rgIgnoredDependencies, &pRegistration->cIgnoredDependencies, pRegistration->sczProviderKey, NULL);
569 NativeAssert::Succeeded(hr, "Failed to add the bundle provider key to the list of dependencies to ignore.");
570 }
571
558 void DetectAttachedContainerAsAttached(BURN_ENGINE_STATE* pEngineState) 572 void DetectAttachedContainerAsAttached(BURN_ENGINE_STATE* pEngineState)
559 { 573 {
560 for (DWORD i = 0; i < pEngineState->containers.cContainers; ++i) 574 for (DWORD i = 0; i < pEngineState->containers.cContainers; ++i)
@@ -585,8 +599,7 @@ namespace Bootstrapper
585 599
586 void DetectPackagesAsAbsent(BURN_ENGINE_STATE* pEngineState) 600 void DetectPackagesAsAbsent(BURN_ENGINE_STATE* pEngineState)
587 { 601 {
588 DetectReset(&pEngineState->registration, &pEngineState->packages); 602 PlanTestDetect(pEngineState);
589 PlanReset(&pEngineState->plan, &pEngineState->packages);
590 603
591 for (DWORD i = 0; i < pEngineState->packages.cPackages; ++i) 604 for (DWORD i = 0; i < pEngineState->packages.cPackages; ++i)
592 { 605 {
@@ -597,8 +610,7 @@ namespace Bootstrapper
597 610
598 void DetectPackagesAsPresentAndCached(BURN_ENGINE_STATE* pEngineState) 611 void DetectPackagesAsPresentAndCached(BURN_ENGINE_STATE* pEngineState)
599 { 612 {
600 DetectReset(&pEngineState->registration, &pEngineState->packages); 613 PlanTestDetect(pEngineState);
601 PlanReset(&pEngineState->plan, &pEngineState->packages);
602 614
603 pEngineState->registration.fInstalled = TRUE; 615 pEngineState->registration.fInstalled = TRUE;
604 616
@@ -611,8 +623,7 @@ namespace Bootstrapper
611 623
612 void DetectPermanentPackagesAsPresentAndCached(BURN_ENGINE_STATE* pEngineState) 624 void DetectPermanentPackagesAsPresentAndCached(BURN_ENGINE_STATE* pEngineState)
613 { 625 {
614 DetectReset(&pEngineState->registration, &pEngineState->packages); 626 PlanTestDetect(pEngineState);
615 PlanReset(&pEngineState->plan, &pEngineState->packages);
616 627
617 pEngineState->registration.fInstalled = TRUE; 628 pEngineState->registration.fInstalled = TRUE;
618 629