diff options
author | Sean Hall <r.sean.hall@gmail.com> | 2021-02-01 20:36:39 -0600 |
---|---|---|
committer | Sean Hall <r.sean.hall@gmail.com> | 2021-02-04 22:16:10 -0600 |
commit | cc5fe7c79aad14819df1b4cb134884b80a945141 (patch) | |
tree | 4b0ab44744a6b989f784292d438ef0654d9b03ac | |
parent | cede270b2bd3da6bd8d5205b8834e786c8d6c1ce (diff) | |
download | wix-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.cpp | 12 | ||||
-rw-r--r-- | src/engine/dependency.cpp | 349 | ||||
-rw-r--r-- | src/engine/dependency.h | 29 | ||||
-rw-r--r-- | src/engine/detect.cpp | 28 | ||||
-rw-r--r-- | src/engine/engine.mc | 11 | ||||
-rw-r--r-- | src/engine/package.cpp | 2 | ||||
-rw-r--r-- | src/engine/package.h | 4 | ||||
-rw-r--r-- | src/engine/plan.cpp | 104 | ||||
-rw-r--r-- | src/engine/plan.h | 1 | ||||
-rw-r--r-- | src/engine/registration.h | 9 | ||||
-rw-r--r-- | src/engine/relatedbundle.cpp | 2 | ||||
-rw-r--r-- | src/test/BurnUnitTest/PlanTest.cpp | 23 |
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 | ||
13 | static HRESULT DetectPackageDependents( | ||
14 | __in BURN_PACKAGE* pPackage, | ||
15 | __in STRINGDICT_HANDLE sdIgnoredDependents, | ||
16 | __in const BURN_REGISTRATION* pRegistration | ||
17 | ); | ||
18 | |||
13 | static HRESULT SplitIgnoreDependencies( | 19 | static 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 | ||
31 | static HRESULT GetProviderInformation( | 37 | static 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 | ||
38 | static void CalculateDependencyActionStates( | 42 | static void CalculateDependencyActionStates( |
@@ -70,20 +74,18 @@ static void UnregisterPackageDependency( | |||
70 | __in_z LPCWSTR wzDependentProviderKey | 74 | __in_z LPCWSTR wzDependentProviderKey |
71 | ); | 75 | ); |
72 | 76 | ||
73 | static BOOL PackageProviderExists( | ||
74 | __in const BURN_PACKAGE* pPackage | ||
75 | ); | ||
76 | |||
77 | 77 | ||
78 | // functions | 78 | // functions |
79 | 79 | ||
80 | extern "C" void DependencyUninitialize( | 80 | extern "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 | ||
170 | extern "C" HRESULT DependencyDetectProviderKeyPackageId( | 172 | extern "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 | ||
211 | LExit: | 201 | LExit: |
@@ -236,23 +226,77 @@ LExit: | |||
236 | return hr; | 226 | return hr; |
237 | } | 227 | } |
238 | 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 | |||
239 | extern "C" HRESULT DependencyPlanInitialize( | 286 | extern "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 | ||
258 | LExit: | 302 | LExit: |
@@ -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 | ||
437 | LExit: | 485 | LExit: |
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 | |||
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 | |||
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 | *********************************************************************/ |
809 | static HRESULT GetProviderInformation( | 908 | static 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 | |||
848 | LExit: | ||
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 | *********************************************************************/ | ||
1189 | static 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 | *********************************************************************/ |
21 | void DependencyUninitialize( | 21 | void 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 | /******************************************************************** | 35 | HRESULT 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 | *********************************************************************/ | ||
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 | ||
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 | *********************************************************************/ | ||
54 | HRESULT DependencyDetect( | ||
55 | __in BURN_ENGINE_STATE* pEngineState | ||
56 | ); | ||
57 | |||
58 | /******************************************************************** | ||
58 | DependencyPlanInitialize - Initializes the plan. | 59 | DependencyPlanInitialize - Initializes the plan. |
59 | 60 | ||
60 | *********************************************************************/ | 61 | *********************************************************************/ |
61 | HRESULT DependencyPlanInitialize( | 62 | HRESULT 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 | |||
356 | Severity=Warning | 356 | Severity=Warning |
357 | SymbolicName=MSG_PLAN_SKIPPED_DUE_TO_DEPENDENTS | 357 | SymbolicName=MSG_PLAN_SKIPPED_DUE_TO_DEPENDENTS |
358 | Language=English | 358 | Language=English |
359 | Plan skipped due to %1!u! remaining dependents | 359 | Plan skipped due to remaining dependents: |
360 | . | 360 | . |
361 | 361 | ||
362 | MessageId=211 | 362 | MessageId=211 |
@@ -595,7 +595,7 @@ MessageId=327 | |||
595 | Severity=Warning | 595 | Severity=Warning |
596 | SymbolicName=MSG_DEPENDENCY_PACKAGE_HASDEPENDENTS | 596 | SymbolicName=MSG_DEPENDENCY_PACKAGE_HASDEPENDENTS |
597 | Language=English | 597 | Language=English |
598 | Will not uninstall package: %1!ls!, found dependents: %2!d! | 598 | Will not uninstall package: %1!ls!, found dependents: |
599 | . | 599 | . |
600 | 600 | ||
601 | MessageId=328 | 601 | MessageId=328 |
@@ -640,6 +640,13 @@ Language=English | |||
640 | Could not remove bundle dependency provider: %1!ls!, error: 0x%2!x! | 640 | Could not remove bundle dependency provider: %1!ls!, error: 0x%2!x! |
641 | . | 641 | . |
642 | 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 | |||
643 | MessageId=335 | 650 | MessageId=335 |
644 | Severity=Success | 651 | Severity=Success |
645 | SymbolicName=MSG_ACQUIRE_BUNDLE_PAYLOAD | 652 | SymbolicName=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 | ||
164 | typedef struct _BURN_ROLLBACK_BOUNDARY | 167 | typedef 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 | ||
744 | LExit: | 766 | LExit: |
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 | ); |
424 | HRESULT PlanPassThroughBundle( | 423 | HRESULT 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 | ||
461 | LExit: | 461 | LExit: |
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 | ||