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