@joebigelow / wix-1 / commits / cc5fe7c7

Move registry checks for dependency ref-counting into Detect.

Sean Hall committed Feb 1, 2021 at 20:36 UTC cc5fe7c79aad14819df1b4cb134884b80a945141
12 files changed +354 -220
src/engine/core.cpp
+9 -3
@@ -97,7 +97,7 @@ extern "C" HRESULT CoreInitialize(
97 ExitOnFailure(hr, "Failed to load manifest.");
98
99 hr = ContainersInitialize(&pEngineState->containers, &pEngineState->section);
100 - ExitOnFailure(hr, "Failed to intialize containers.");
100 + ExitOnFailure(hr, "Failed to initialize containers.");
101
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);
@@ -105,6 +105,9 @@ extern "C" HRESULT CoreInitialize(
105
106 LogId(REPORT_STANDARD, MSG_BURN_COMMAND_LINE, sczSanitizedCommandLine ? sczSanitizedCommandLine : L"");
107
108 + hr = DependencyInitialize(&pEngineState->registration, pEngineState->sczIgnoreDependencies);
109 + ExitOnFailure(hr, "Failed to initialize dependency data.");
110 +
111 // Retain whether bundle was initially run elevated.
112 ProcElevated(::GetCurrentProcess(), &fElevated);
113
@@ -332,6 +335,9 @@ extern "C" HRESULT CoreDetect(
335 }
336 }
337
338 + hr = DependencyDetect(pEngineState);
339 + ExitOnFailure(hr, "Failed to detect the dependencies.");
340 +
341 // Log the detected states.
342 for (DWORD iPackage = 0; iPackage < pEngineState->packages.cPackages; ++iPackage)
343 {
@@ -419,7 +425,7 @@ extern "C" HRESULT CorePlan(
425 hr = PlanSetResumeCommand(&pEngineState->registration, action, &pEngineState->command, &pEngineState->log);
426 ExitOnFailure(hr, "Failed to set resume command");
427
422 - hr = DependencyPlanInitialize(pEngineState, &pEngineState->plan);
428 + hr = DependencyPlanInitialize(&pEngineState->registration, &pEngineState->plan);
429 ExitOnFailure(hr, "Failed to initialize the dependencies for the plan.");
430
431 if (BOOTSTRAPPER_ACTION_LAYOUT == action)
@@ -457,7 +463,7 @@ extern "C" HRESULT CorePlan(
463 BOOL fContinuePlanning = TRUE; // assume we'll be able to keep planning after registration.
464 pEngineState->plan.fPerMachine = pEngineState->registration.fPerMachine; // default the scope of the plan to the per-machine state of the bundle.
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);
467 ExitOnFailure(hr, "Failed to plan registration.");
468
469 if (fContinuePlanning)
src/engine/dependency.cpp
+200 -149
@@ -10,6 +10,12 @@ const LPCWSTR vcszIgnoreDependenciesDelim = L";";
10
11 // internal function declarations
12
13 +static HRESULT DetectPackageDependents(
14 + __in BURN_PACKAGE* pPackage,
15 + __in STRINGDICT_HANDLE sdIgnoredDependents,
16 + __in const BURN_REGISTRATION* pRegistration
17 + );
18 +
19 static HRESULT SplitIgnoreDependencies(
20 __in_z LPCWSTR wzIgnoreDependencies,
21 __deref_inout_ecount_opt(*pcDependencies) DEPENDENCY** prgDependencies,
@@ -28,11 +34,9 @@ static HRESULT GetIgnoredDependents(
34 __deref_inout STRINGDICT_HANDLE* psdIgnoredDependents
35 );
36
31 -static HRESULT GetProviderInformation(
37 +static BOOL GetProviderExists(
38 __in HKEY hkRoot,
33 - __in_z LPCWSTR wzProviderKey,
34 - __deref_opt_out_z_opt LPWSTR* psczProviderKey,
35 - __deref_opt_out_z_opt LPWSTR* psczId
39 + __in_z LPCWSTR wzProviderKey
40 );
41
42 static void CalculateDependencyActionStates(
@@ -70,20 +74,18 @@ static void UnregisterPackageDependency(
74 __in_z LPCWSTR wzDependentProviderKey
75 );
76
73 -static BOOL PackageProviderExists(
74 - __in const BURN_PACKAGE* pPackage
75 - );
76 -
77
78 // functions
79
80 -extern "C" void DependencyUninitialize(
80 +extern "C" void DependencyUninitializeProvider(
81 __in BURN_DEPENDENCY_PROVIDER* pProvider
82 )
83 {
84 ReleaseStr(pProvider->sczKey);
85 ReleaseStr(pProvider->sczVersion);
86 ReleaseStr(pProvider->sczDisplayName);
87 + ReleaseDependencyArray(pProvider->rgDependents, pProvider->cDependents);
88 +
89 memset(pProvider, 0, sizeof(BURN_DEPENDENCY_PROVIDER));
90 }
91
@@ -167,45 +169,33 @@ LExit:
169 return hr;
170 }
171
170 -extern "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
172 +extern "C" HRESULT DependencyInitialize(
173 + __in BURN_REGISTRATION* pRegistration,
174 + __in_z_opt LPCWSTR wzIgnoreDependencies
175 )
176 {
176 - HRESULT hr = E_NOTFOUND;
177 - LPWSTR wzProviderKey = NULL;
178 - HKEY hkRoot = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
177 + HRESULT hr = S_OK;
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 {
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();
182 + pRegistration->wzSelfDependent = pRegistration->sczId;
183 }
194 -
195 - // Older bundles may not have written the id so try the default.
196 - if (BURN_PACKAGE_TYPE_MSI == pPackage->type)
184 + else if (*pRegistration->sczActiveParent) // if parent was specified use that as the self dependent.
185 {
198 - wzProviderKey = pPackage->Msi.sczProductCode;
186 + pRegistration->wzSelfDependent = pRegistration->sczActiveParent;
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.");
193
201 - if (wzProviderKey)
194 + // Add the list of dependencies to ignore.
195 + if (wzIgnoreDependencies)
196 {
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.");
197 + hr = SplitIgnoreDependencies(wzIgnoreDependencies, &pRegistration->rgIgnoredDependencies, &pRegistration->cIgnoredDependencies);
198 + ExitOnFailure(hr, "Failed to split the list of dependencies to ignore.");
199 }
200
201 LExit:
@@ -236,23 +226,77 @@ LExit:
226 return hr;
227 }
228
229 +extern "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 +
280 +LExit:
281 + ReleaseDict(sdIgnoredDependents);
282 +
283 + return hr;
284 +}
285 +
286 extern "C" HRESULT DependencyPlanInitialize(
240 - __in const BURN_ENGINE_STATE* pEngineState,
287 + __in const BURN_REGISTRATION* pRegistration,
288 __in BURN_PLAN* pPlan
289 )
290 {
291 HRESULT hr = S_OK;
292
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)
293 + // TODO: After adding enumeration to STRINGDICT, a single STRINGDICT_HANDLE can be used everywhere.
294 + for (DWORD i = 0; i < pRegistration->cIgnoredDependencies; ++i)
295 {
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.");
296 + DEPENDENCY* pDependency = pRegistration->rgIgnoredDependencies + i;
297 +
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.");
300 }
301
302 LExit:
@@ -323,9 +367,6 @@ extern "C" HRESULT DependencyPlanPackageBegin(
367 {
368 HRESULT hr = S_OK;
369 STRINGDICT_HANDLE sdIgnoredDependents = NULL;
326 - DEPENDENCY* rgDependents = NULL;
327 - UINT cDependents = 0;
328 - HKEY hkHive = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
370 BURN_DEPENDENCY_ACTION dependencyExecuteAction = BURN_DEPENDENCY_ACTION_NONE;
371 BURN_DEPENDENCY_ACTION dependencyRollbackAction = BURN_DEPENDENCY_ACTION_NONE;
372
@@ -361,18 +402,31 @@ extern "C" HRESULT DependencyPlanPackageBegin(
402 }
403 else
404 {
405 + hr = S_OK;
406 +
407 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
408 {
366 - const BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i];
409 + const BURN_DEPENDENCY_PROVIDER* pProvider = pPackage->rgDependencyProviders + i;
410
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
411 + for (DWORD j = 0; j < pProvider->cDependents; ++j)
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.");
430 }
431 }
432 }
@@ -382,52 +436,46 @@ extern "C" HRESULT DependencyPlanPackageBegin(
436 CalculateDependencyActionStates(pPackage, pPlan->action, &dependencyExecuteAction, &dependencyRollbackAction);
437
438 // If dependents were found, change the action to not uninstall the package.
385 - if (0 < cDependents)
439 + if (pPackage->fDependencyManagerWasHere)
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;
441 pPackage->execute = BOOTSTRAPPER_ACTION_STATE_NONE;
442 pPackage->rollback = BOOTSTRAPPER_ACTION_STATE_NONE;
443 }
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)
444 + else
445 {
404 - BOOL fAllImportedProviders = TRUE; // assume all providers were imported.
405 - for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
446 + // Use the calculated dependency actions as the provider actions if there
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)
450 {
407 - const BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i];
408 - if (!pProvider->fImported)
451 + BOOL fAllImportedProviders = TRUE; // assume all providers were imported.
452 + for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
453 {
410 - fAllImportedProviders = FALSE;
411 - break;
454 + const BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i];
455 + if (!pProvider->fImported)
456 + {
457 + fAllImportedProviders = FALSE;
458 + break;
459 + }
460 }
413 - }
461
415 - if (!fAllImportedProviders)
416 - {
417 - pPackage->providerExecute = dependencyExecuteAction;
418 - pPackage->providerRollback = dependencyRollbackAction;
462 + if (!fAllImportedProviders)
463 + {
464 + pPackage->providerExecute = dependencyExecuteAction;
465 + pPackage->providerRollback = dependencyRollbackAction;
466 + }
467 }
420 - }
468
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)
469 + // If the package will be removed, add its providers to the growing list in the plan.
470 + if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute)
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];
475
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);
476 + hr = DepDependencyArrayAlloc(&pPlan->rgPlannedProviders, &pPlan->cPlannedProviders, pProvider->sczKey, NULL);
477 + ExitOnFailure(hr, "Failed to add the package provider key \"%ls\" to the planned list.", pProvider->sczKey);
478 + }
479 }
480 }
481
@@ -435,7 +483,6 @@ extern "C" HRESULT DependencyPlanPackageBegin(
483 pPackage->dependencyRollback = dependencyRollbackAction;
484
485 LExit:
438 - ReleaseDependencyArray(rgDependents, cDependents);
486 ReleaseDict(sdIgnoredDependents);
487
488 return hr;
@@ -652,6 +699,58 @@ extern "C" void DependencyUnregisterBundle(
699
700 // internal functions
701
702 +
703 +static 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 +
750 +LExit:
751 + return hr;
752 +}
753 +
754 /********************************************************************
755 SplitIgnoreDependencies - Splits a semicolon-delimited
756 string into a list of unique dependencies to ignore.
@@ -803,52 +902,16 @@ LExit:
902 }
903
904 /********************************************************************
806 - GetProviderId - Gets the ID of the package given the provider key.
905 + GetProviderExists - Gets whether the provider key is registered.
906
907 *********************************************************************/
809 -static HRESULT GetProviderInformation(
908 +static BOOL GetProviderExists(
909 __in HKEY hkRoot,
811 - __in_z LPCWSTR wzProviderKey,
812 - __deref_opt_out_z_opt LPWSTR* psczProviderKey,
813 - __deref_opt_out_z_opt LPWSTR* psczId
910 + __in_z LPCWSTR wzProviderKey
911 )
912 {
816 - HRESULT hr = S_OK;
817 - LPWSTR sczId = NULL;
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 -
848 -LExit:
849 - ReleaseStr(sczId);
850 -
851 - return hr;
913 + HRESULT hr = DepGetProviderInformation(hkRoot, wzProviderKey, NULL, NULL, NULL);
914 + return SUCCEEDED(hr);
915 }
916
917 /********************************************************************
@@ -886,7 +949,7 @@ static void CalculateDependencyActionStates(
949 switch (pPackage->currentState)
950 {
951 case BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE:
889 - if (!PackageProviderExists(pPackage))
952 + if (!pPackage->fPackageProviderExists)
953 {
954 break;
955 }
@@ -902,7 +965,7 @@ static void CalculateDependencyActionStates(
965 switch (pPackage->currentState)
966 {
967 case BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE:
905 - if (!PackageProviderExists(pPackage))
968 + if (!pPackage->fPackageProviderExists)
969 {
970 break;
971 }
@@ -1181,15 +1244,3 @@ static void UnregisterPackageDependency(
1244 }
1245 }
1246 }
1184 -
1185 -/********************************************************************
1186 - PackageProviderExists - Checks if a package provider is registered.
1187 -
1188 -*********************************************************************/
1189 -static BOOL PackageProviderExists(
1190 - __in const BURN_PACKAGE* pPackage
1191 - )
1192 -{
1193 - HRESULT hr = DependencyDetectProviderKeyPackageId(pPackage, NULL, NULL);
1194 - return SUCCEEDED(hr);
1195 -}
src/engine/dependency.h
+15 -14
@@ -14,11 +14,11 @@ const LPCWSTR DEPENDENCY_IGNOREDEPENDENCIES = L"IGNOREDEPENDENCIES";
14 // function declarations
15
16 /********************************************************************
17 - DependencyUninitialize - Frees and zeros memory allocated in the
18 - dependency.
17 + DependencyUninitializeProvider - Frees and zeros memory allocated in
18 + the dependency provider.
19
20 *********************************************************************/
21 -void DependencyUninitialize(
21 +void DependencyUninitializeProvider(
22 __in BURN_DEPENDENCY_PROVIDER* pProvider
23 );
24
@@ -32,16 +32,9 @@ HRESULT DependencyParseProvidersFromXml(
32 __in IXMLDOMNode* pixnPackage
33 );
34
35 -/********************************************************************
36 - DependencyDetectProviderKeyPackageId - Detect if the provider key is
37 - registered and if so what package code is registered.
38 -
39 - Note: Returns E_NOTFOUND if the provider key is not registered.
40 -*********************************************************************/
41 -HRESULT DependencyDetectProviderKeyPackageId(
42 - __in const BURN_PACKAGE* pPackage,
43 - __deref_opt_out_z_opt LPWSTR* psczProviderKey,
44 - __deref_opt_out_z_opt LPWSTR* psczId
35 +HRESULT DependencyInitialize(
36 + __in BURN_REGISTRATION* pRegistration,
37 + __in_z_opt LPCWSTR wzIgnoreDependencies
38 );
39
40 /********************************************************************
@@ -54,12 +47,20 @@ HRESULT DependencyDetectProviderKeyBundleId(
47 __in BURN_REGISTRATION* pRegistration
48 );
49
50 +/********************************************************************
51 + DependencyDetect - Detects dependency information.
52 +
53 +*********************************************************************/
54 +HRESULT DependencyDetect(
55 + __in BURN_ENGINE_STATE* pEngineState
56 + );
57 +
58 /********************************************************************
59 DependencyPlanInitialize - Initializes the plan.
60
61 *********************************************************************/
62 HRESULT DependencyPlanInitialize(
62 - __in const BURN_ENGINE_STATE* pEngineState,
63 + __in const BURN_REGISTRATION* pRegistration,
64 __in BURN_PLAN* pPlan
65 );
66
src/engine/detect.cpp
+28
@@ -41,12 +41,28 @@ extern "C" void DetectReset(
41 ReleaseNullStr(pRegistration->sczDetectedProviderKeyBundleId);
42 pRegistration->fEnabledForwardCompatibleBundle = FALSE;
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;
59
60 for (DWORD iPackage = 0; iPackage < pPackages->cPackages; ++iPackage)
61 {
62 BURN_PACKAGE* pPackage = pPackages->rgPackages + iPackage;
63
64 pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_UNKNOWN;
65 + pPackage->fPackageProviderExists = FALSE;
66
67 pPackage->cache = BURN_CACHE_STATE_NONE;
68 for (DWORD iPayload = 0; iPayload < pPackage->cPayloads; ++iPayload)
@@ -69,6 +85,18 @@ extern "C" void DetectReset(
85 ReleaseNullMem(pPackage->Msp.rgTargetProducts);
86 pPackage->Msp.cTargetProductCodes = 0;
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 + }
100 }
101
102 for (DWORD iPatchInfo = 0; iPatchInfo < pPackages->cPatchInfo; ++iPatchInfo)
src/engine/engine.mc
+9 -2
@@ -356,7 +356,7 @@ MessageId=210
356 Severity=Warning
357 SymbolicName=MSG_PLAN_SKIPPED_DUE_TO_DEPENDENTS
358 Language=English
359 -Plan skipped due to %1!u! remaining dependents
359 +Plan skipped due to remaining dependents:
360 .
361
362 MessageId=211
@@ -595,7 +595,7 @@ MessageId=327
595 Severity=Warning
596 SymbolicName=MSG_DEPENDENCY_PACKAGE_HASDEPENDENTS
597 Language=English
598 -Will not uninstall package: %1!ls!, found dependents: %2!d!
598 +Will not uninstall package: %1!ls!, found dependents:
599 .
600
601 MessageId=328
@@ -640,6 +640,13 @@ Language=English
640 Could not remove bundle dependency provider: %1!ls!, error: 0x%2!x!
641 .
642
643 +MessageId=334
644 +Severity=Warning
645 +SymbolicName=MSG_DEPENDENCY_BUNDLE_DEPENDENT
646 +Language=English
647 +Found dependent: %1!ls!, name: %2!ls!
648 +.
649 +
650 MessageId=335
651 Severity=Success
652 SymbolicName=MSG_ACQUIRE_BUNDLE_PAYLOAD
src/engine/package.cpp
+1 -1
@@ -323,7 +323,7 @@ extern "C" void PackageUninitialize(
323 {
324 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
325 {
326 - DependencyUninitialize(pPackage->rgDependencyProviders + i);
326 + DependencyUninitializeProvider(pPackage->rgDependencyProviders + i);
327 }
328 MemFree(pPackage->rgDependencyProviders);
329 }
src/engine/package.h
+4
@@ -159,6 +159,9 @@ typedef struct _BURN_DEPENDENCY_PROVIDER
159 LPWSTR sczVersion;
160 LPWSTR sczDisplayName;
161 BOOL fImported;
162 +
163 + DEPENDENCY* rgDependents; // only valid after Detect.
164 + UINT cDependents; // only valid after Detect.
165 } BURN_DEPENDENCY_PROVIDER;
166
167 typedef struct _BURN_ROLLBACK_BOUNDARY
@@ -199,6 +202,7 @@ typedef struct _BURN_PACKAGE
202
203 BOOTSTRAPPER_PACKAGE_STATE currentState; // only valid after Detect.
204 BURN_CACHE_STATE cache; // only valid after Detect.
205 + BOOL fPackageProviderExists; // only valid after Detect.
206 BOOTSTRAPPER_REQUEST_STATE defaultRequested;// only valid during Plan.
207 BOOTSTRAPPER_REQUEST_STATE requested; // only valid during Plan.
208 BOOL fAcquire; // only valid during Plan.
src/engine/plan.cpp
+63 -41
@@ -574,15 +574,12 @@ extern "C" HRESULT PlanRegistration(
574 __in BURN_REGISTRATION* pRegistration,
575 __in BOOTSTRAPPER_RESUME_TYPE resumeType,
576 __in BOOTSTRAPPER_RELATION_TYPE relationType,
577 - __in_z_opt LPCWSTR wzIgnoreDependencies,
577 __out BOOL* pfContinuePlanning
578 )
579 {
580 HRESULT hr = S_OK;
582 - LPCWSTR wzSelfDependent = NULL;
581 + STRINGDICT_HANDLE sdBundleDependents = NULL;
582 STRINGDICT_HANDLE sdIgnoreDependents = NULL;
584 - DEPENDENCY* rgDependencies = NULL;
585 - UINT cDependencies = 0;
583
584 pPlan->fRegister = TRUE; // register the bundle since we're modifying machine state.
585
@@ -591,17 +588,6 @@ extern "C" HRESULT PlanRegistration(
588
589 pPlan->fDisallowRemoval = FALSE; // by default the bundle can be planned to be removed
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 -
591 if (BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action)
592 {
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(
608
609 // If the self-dependent dependent exists, plan its removal. If we did not do this, we
610 // would prevent self-removal.
625 - if (wzSelfDependent && DependencyDependentExists(pRegistration, wzSelfDependent))
611 + if (pRegistration->fSelfRegisteredAsDependent)
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);
614 ExitOnFailure(hr, "Failed to allocate registration action.");
615
630 - hr = DependencyAddIgnoreDependencies(sdIgnoreDependents, wzSelfDependent);
616 + hr = DependencyAddIgnoreDependencies(sdIgnoreDependents, pRegistration->wzSelfDependent);
617 ExitOnFailure(hr, "Failed to add self-dependent to ignore dependents.");
618 }
619
@@ -637,10 +623,20 @@ extern "C" HRESULT PlanRegistration(
623 if (BOOTSTRAPPER_RELATION_UPGRADE != relationType)
624 {
625 // If there were other dependencies to ignore, add them.
640 - if (wzIgnoreDependencies && *wzIgnoreDependencies)
626 + for (DWORD iDependency = 0; iDependency < pRegistration->cIgnoredDependencies; ++iDependency)
627 {
642 - hr = DependencyAddIgnoreDependencies(sdIgnoreDependents, wzIgnoreDependencies);
643 - ExitOnFailure(hr, "Failed to add dependents ignored from command-line.");
628 + DEPENDENCY* pDependency = pRegistration->rgIgnoredDependencies + iDependency;
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 + }
640 }
641
642 // For addon or patch bundles, dependent related bundles should be ignored. This allows
@@ -661,22 +657,29 @@ extern "C" HRESULT PlanRegistration(
657 }
658 }
659
664 - // If there are any (non-ignored and not-planned-to-be-removed) dependents left, uninstall.
665 - hr = DepCheckDependents(pRegistration->hkRoot, pRegistration->sczProviderKey, 0, sdIgnoreDependents, &rgDependencies, &cDependencies);
666 - if (E_FILENOTFOUND == hr)
660 + // If there are any (non-ignored and not-planned-to-be-removed) dependents left, skip planning.
661 + for (DWORD iDependent = 0; iDependent < pRegistration->cDependents; ++iDependent)
662 {
668 - hr = S_OK;
669 - }
670 - else if (SUCCEEDED(hr) && cDependencies)
671 - {
672 - // TODO: callback to the BA and let it have the option to ignore any of these dependents?
663 + DEPENDENCY* pDependent = pRegistration->rgDependents + iDependent;
664 +
665 + hr = DictKeyExists(sdIgnoreDependents, pDependent->sczKey);
666 + if (E_NOTFOUND == hr)
667 + {
668 + hr = S_OK;
669
674 - pPlan->fDisallowRemoval = TRUE; // ensure the registration stays
675 - *pfContinuePlanning = FALSE; // skip the rest of planning.
670 + // TODO: callback to the BA and let it have the option to ignore this dependent?
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 + }
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.");
682 }
679 - ExitOnFailure(hr, "Failed to check for remaining dependents during planning.");
683 }
684 }
685 else
@@ -707,6 +710,23 @@ extern "C" HRESULT PlanRegistration(
710 // if broken.
711 pPlan->dependencyRegistrationAction = BURN_DEPENDENCY_REGISTRATION_ACTION_REGISTER;
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 +
730 // Register each dependent related bundle. The ensures that addons and patches are reference
731 // counted and stick around until the last targeted bundle is removed.
732 for (DWORD i = 0; i < pRegistration->relatedBundles.cRelatedBundles; ++i)
@@ -719,11 +739,16 @@ extern "C" HRESULT PlanRegistration(
739 {
740 const BURN_DEPENDENCY_PROVIDER* pProvider = pRelatedBundle->package.rgDependencyProviders + j;
741
722 - if (!DependencyDependentExists(pRegistration, pProvider->sczKey))
742 + hr = DictKeyExists(sdBundleDependents, pProvider->sczKey);
743 + if (E_NOTFOUND == hr)
744 {
745 + hr = DictAddKey(sdBundleDependents, pProvider->sczKey);
746 + ExitOnFailure(hr, "Failed to add new dependent key to bundle dependents.");
747 +
748 hr = AddRegistrationAction(pPlan, BURN_DEPENDENT_REGISTRATION_ACTION_TYPE_REGISTER, pProvider->sczKey, pRelatedBundle->package.sczId);
749 ExitOnFailure(hr, "Failed to add registration action for dependent related bundle.");
750 }
751 + ExitOnFailure(hr, "Failed to check the dictionary of bundle dependents.");
752 }
753 }
754 }
@@ -731,19 +756,16 @@ extern "C" HRESULT PlanRegistration(
756 // Only do the following if we decided there was a dependent self to register. If so and and an explicit parent was
757 // provided, register dependent self. Otherwise, if this bundle is not an addon or patch bundle then self-regisiter
758 // as our own dependent.
734 - if (wzSelfDependent && (pRegistration->sczActiveParent || !fAddonOrPatchBundle))
759 + if (pRegistration->wzSelfDependent && !pRegistration->fSelfRegisteredAsDependent && (pRegistration->sczActiveParent || !fAddonOrPatchBundle))
760 {
736 - if (!DependencyDependentExists(pRegistration, wzSelfDependent))
737 - {
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 - }
761 + hr = AddRegistrationAction(pPlan, BURN_DEPENDENT_REGISTRATION_ACTION_TYPE_REGISTER, pRegistration->wzSelfDependent, pRegistration->sczId);
762 + ExitOnFailure(hr, "Failed to add registration action for self dependent.");
763 }
764 }
765
766 LExit:
767 + ReleaseDict(sdBundleDependents);
768 ReleaseDict(sdIgnoreDependents);
746 - ReleaseDependencyArray(rgDependencies, cDependencies);
769
770 return hr;
771 }
src/engine/plan.h
-1
@@ -418,7 +418,6 @@ HRESULT PlanRegistration(
418 __in BURN_REGISTRATION* pRegistration,
419 __in BOOTSTRAPPER_RESUME_TYPE resumeType,
420 __in BOOTSTRAPPER_RELATION_TYPE relationType,
421 - __in_z_opt LPCWSTR wzIgnoreDependencies,
421 __out BOOL* pfContinuePlanning
422 );
423 HRESULT PlanPassThroughBundle(
src/engine/registration.h
+7 -2
@@ -139,8 +139,13 @@ typedef struct _BURN_REGISTRATION
139 // Update registration
140 BURN_UPDATE_REGISTRATION update;
141
142 - // Only valid after detect.
143 - BURN_RELATED_BUNDLES relatedBundles;
142 + BURN_RELATED_BUNDLES relatedBundles; // Only valid after detect.
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.
149
150 LPWSTR sczDetectedProviderKeyBundleId;
151 LPWSTR sczAncestors;
src/engine/relatedbundle.cpp
+1 -1
@@ -459,7 +459,7 @@ static HRESULT LoadRelatedBundleFromKey(
459 ExitOnFailure(hr, "Failed to initialize related bundle to represent bundle: %ls", wzRelatedBundleId);
460
461 LExit:
462 - DependencyUninitialize(&dependencyProvider);
462 + DependencyUninitializeProvider(&dependencyProvider);
463 ReleaseStr(sczCachePath);
464 ReleaseStr(sczBundleVersion);
465
src/test/BurnUnitTest/PlanTest.cpp
+17 -6
@@ -552,9 +552,23 @@ namespace Bootstrapper
552 ReleaseStr(sczFilePath);
553 }
554
555 + DependencyInitialize(&pEngineState->registration, NULL);
556 +
557 pEngineState->userExperience.pfnBAProc = PlanTestBAProc;
558 }
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 +
572 void DetectAttachedContainerAsAttached(BURN_ENGINE_STATE* pEngineState)
573 {
574 for (DWORD i = 0; i < pEngineState->containers.cContainers; ++i)
@@ -585,8 +599,7 @@ namespace Bootstrapper
599
600 void DetectPackagesAsAbsent(BURN_ENGINE_STATE* pEngineState)
601 {
588 - DetectReset(&pEngineState->registration, &pEngineState->packages);
589 - PlanReset(&pEngineState->plan, &pEngineState->packages);
602 + PlanTestDetect(pEngineState);
603
604 for (DWORD i = 0; i < pEngineState->packages.cPackages; ++i)
605 {
@@ -597,8 +610,7 @@ namespace Bootstrapper
610
611 void DetectPackagesAsPresentAndCached(BURN_ENGINE_STATE* pEngineState)
612 {
600 - DetectReset(&pEngineState->registration, &pEngineState->packages);
601 - PlanReset(&pEngineState->plan, &pEngineState->packages);
613 + PlanTestDetect(pEngineState);
614
615 pEngineState->registration.fInstalled = TRUE;
616
@@ -611,8 +623,7 @@ namespace Bootstrapper
623
624 void DetectPermanentPackagesAsPresentAndCached(BURN_ENGINE_STATE* pEngineState)
625 {
614 - DetectReset(&pEngineState->registration, &pEngineState->packages);
615 - PlanReset(&pEngineState->plan, &pEngineState->packages);
626 + PlanTestDetect(pEngineState);
627
628 pEngineState->registration.fInstalled = TRUE;
629