diff options
Diffstat (limited to 'src')
| -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 | ||
