PackageManager.cpp (79391B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #include "pch.h" 4 #include "Public/AppInstallerCLICore.h" 5 #include "Microsoft/PredefinedInstalledSourceFactory.h" 6 #include "Commands/RootCommand.h" 7 #include "ComContext.h" 8 #include "ExecutionContext.h" 9 #include "Workflows/WorkflowBase.h" 10 #include <winget/Authentication.h> 11 #include <winget/UserSettings.h> 12 #include <winget/Manifest.h> 13 #include "Commands/COMCommand.h" 14 #include <AppInstallerArchitecture.h> 15 #include <AppInstallerTelemetry.h> 16 #include <AppInstallerErrors.h> 17 #pragma warning( push ) 18 #pragma warning ( disable : 4467 6388) 19 // 6388 Allow CreateInstance. 20 #include <wil\cppwinrt_wrl.h> 21 // 4467 Allow use of uuid attribute for com object creation. 22 #include "PackageManager.h" 23 #pragma warning( pop ) 24 #include "PackageManager.g.cpp" 25 #include "CatalogPackage.h" 26 #include "DownloadResult.h" 27 #include "InstallResult.h" 28 #include "UninstallResult.h" 29 #include "RepairResult.h" 30 #include "PackageCatalogInfo.h" 31 #include "PackageCatalogReference.h" 32 #include "PackageVersionInfo.h" 33 #include "PackageVersionId.h" 34 #include "AddPackageCatalogResult.h" 35 #include "RemovePackageCatalogResult.h" 36 #include "Converters.h" 37 #include "Helpers.h" 38 #include "ContextOrchestrator.h" 39 #include "AppInstallerRuntime.h" 40 #include <optional> 41 #include <PackageCatalogProgress.h> 42 43 using namespace std::literals::chrono_literals; 44 using namespace ::AppInstaller::CLI; 45 using namespace ::AppInstaller::CLI::Execution; 46 47 namespace winrt::Microsoft::Management::Deployment::implementation 48 { 49 namespace 50 { 51 void LogStartupIfApplicable() 52 { 53 static std::once_flag logStartupOnceFlag; 54 std::call_once(logStartupOnceFlag, 55 [&]() 56 { 57 ::AppInstaller::Logging::Telemetry().SetCaller(GetCallerName()); 58 ::AppInstaller::Logging::Telemetry().LogStartup(true); 59 }); 60 } 61 62 winrt::Microsoft::Management::Deployment::AddPackageCatalogResult GetAddPackageCatalogResult(winrt::hresult terminationStatus) 63 { 64 winrt::Microsoft::Management::Deployment::AddPackageCatalogStatus status = GetPackageCatalogOperationStatus<AddPackageCatalogStatus>(terminationStatus); 65 auto addPackageCatalogResult = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::AddPackageCatalogResult>>(); 66 addPackageCatalogResult->Initialize(status, terminationStatus); 67 return *addPackageCatalogResult; 68 } 69 70 void CheckForDuplicateSource(const std::string& name, const std::string& type, const std::string& sourceUri) 71 { 72 auto sourceList = ::AppInstaller::Repository::Source::GetCurrentSources(); 73 74 std::string sourceType = type; 75 76 // [NOTE:] If the source type is not specified, the default source type will be used for validation.In cases where the source type is empty, 77 // it remains unassigned until the add operation, at which point it is assigned.Without this default assignment, an empty string could be 78 // compared to the default type, potentially allowing different source names with the same URI to be seen as unique. 79 // To avoid this, assign the default source type prior to comparison. 80 if (sourceType.empty()) 81 { 82 // This method of obtaining the default source type is slightly expensive as it requires creating a SourceFactory object 83 // and fetching the type name.Nonetheless, it future-proofs the code against any changes in the SourceFactory's default type. 84 sourceType = ::AppInstaller::Repository::Source::GetDefaultSourceType(); 85 } 86 87 for (const auto& source : sourceList) 88 { 89 THROW_HR_IF(APPINSTALLER_CLI_ERROR_SOURCE_NAME_ALREADY_EXISTS, ::AppInstaller::Utility::ICUCaseInsensitiveEquals(source.Name, name)); 90 91 bool sourceUriAlreadyExists = !source.Arg.empty() && source.Arg == sourceUri && source.Type == sourceType; 92 THROW_HR_IF(APPINSTALLER_CLI_ERROR_SOURCE_ARG_ALREADY_EXISTS, sourceUriAlreadyExists); 93 } 94 } 95 96 ::AppInstaller::Repository::Source CreateSourceFromOptions(const winrt::Microsoft::Management::Deployment::AddPackageCatalogOptions& options) 97 { 98 std::string name = winrt::to_string(options.Name()); 99 std::string type = winrt::to_string(options.Type()); 100 std::string sourceUri = winrt::to_string(options.SourceUri()); 101 102 AppInstaller::Repository::SourceTrustLevel trustLevel = AppInstaller::Repository::SourceTrustLevel::None; 103 if (options.TrustLevel() == winrt::Microsoft::Management::Deployment::PackageCatalogTrustLevel::Trusted) 104 { 105 trustLevel = AppInstaller::Repository::SourceTrustLevel::Trusted; 106 } 107 108 CheckForDuplicateSource(name, type, sourceUri); 109 110 ::AppInstaller::Repository::Source source = ::AppInstaller::Repository::Source{ name, sourceUri, type, trustLevel, options.Explicit() }; 111 112 std::string customHeader = winrt::to_string(options.CustomHeader()); 113 if (!customHeader.empty()) 114 { 115 source.SetCustomHeader(customHeader); 116 } 117 118 auto sourceInfo = source.GetInformation(); 119 120 if (sourceInfo.Authentication.Type == ::AppInstaller::Authentication::AuthenticationType::Unknown) 121 { 122 THROW_HR(APPINSTALLER_CLI_ERROR_AUTHENTICATION_TYPE_NOT_SUPPORTED); 123 } 124 125 return source; 126 } 127 128 winrt::Microsoft::Management::Deployment::RemovePackageCatalogResult GetRemovePackageCatalogResult(winrt::hresult terminationStatus) 129 { 130 winrt::Microsoft::Management::Deployment::RemovePackageCatalogStatus status = GetPackageCatalogOperationStatus<RemovePackageCatalogStatus>(terminationStatus); 131 auto removeResult = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::RemovePackageCatalogResult>>(); 132 removeResult->Initialize(status, terminationStatus); 133 return *removeResult; 134 } 135 136 std::optional<::AppInstaller::Repository::SourceDetails> GetMatchingSource(const std::string& name) 137 { 138 auto sourceList = ::AppInstaller::Repository::Source::GetCurrentSources(); 139 140 for (const auto& source : sourceList) 141 { 142 if (::AppInstaller::Utility::ICUCaseInsensitiveEquals(source.Name, name)) 143 { 144 return source; // Return the first matching source 145 } 146 } 147 148 return std::nullopt; // Return std::nullopt if no matching source is found 149 } 150 } 151 152 PackageManager::PackageManager() 153 { 154 Execution::ContextOrchestrator::RegisterForShutdownSynchronization(); 155 } 156 157 winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Management::Deployment::PackageCatalogReference> PackageManager::GetPackageCatalogs() 158 { 159 LogStartupIfApplicable(); 160 Windows::Foundation::Collections::IVector<Microsoft::Management::Deployment::PackageCatalogReference> catalogs{ winrt::single_threaded_vector<Microsoft::Management::Deployment::PackageCatalogReference>() }; 161 std::vector<::AppInstaller::Repository::SourceDetails> sources = ::AppInstaller::Repository::Source::GetCurrentSources(); 162 for (uint32_t i = 0; i < sources.size(); i++) 163 { 164 auto packageCatalogInfo = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::PackageCatalogInfo>>(); 165 ::AppInstaller::Repository::Source sourceReference{ sources.at(i).Name }; 166 packageCatalogInfo->Initialize(sourceReference.GetDetails()); 167 auto packageCatalogRef = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::PackageCatalogReference>>(); 168 packageCatalogRef->Initialize(*packageCatalogInfo, sourceReference); 169 catalogs.Append(*packageCatalogRef); 170 } 171 return catalogs.GetView(); 172 } 173 174 winrt::Microsoft::Management::Deployment::PackageCatalogReference PackageManager::GetPredefinedPackageCatalog(winrt::Microsoft::Management::Deployment::PredefinedPackageCatalog const& predefinedPackageCatalog) 175 { 176 LogStartupIfApplicable(); 177 ::AppInstaller::Repository::Source source; 178 switch (predefinedPackageCatalog) 179 { 180 case winrt::Microsoft::Management::Deployment::PredefinedPackageCatalog::OpenWindowsCatalog: 181 source = ::AppInstaller::Repository::Source{ ::AppInstaller::Repository::WellKnownSource::WinGet }; 182 break; 183 case winrt::Microsoft::Management::Deployment::PredefinedPackageCatalog::MicrosoftStore: 184 source = ::AppInstaller::Repository::Source{ ::AppInstaller::Repository::WellKnownSource::MicrosoftStore }; 185 break; 186 case winrt::Microsoft::Management::Deployment::PredefinedPackageCatalog::DesktopFrameworks: 187 source = ::AppInstaller::Repository::Source{ ::AppInstaller::Repository::WellKnownSource::DesktopFrameworks }; 188 break; 189 default: 190 throw hresult_invalid_argument(); 191 } 192 auto packageCatalogInfo = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::PackageCatalogInfo>>(); 193 packageCatalogInfo->Initialize(source.GetDetails()); 194 auto packageCatalogRef = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::PackageCatalogReference>>(); 195 packageCatalogRef->Initialize(*packageCatalogInfo, source); 196 return *packageCatalogRef; 197 } 198 199 winrt::Microsoft::Management::Deployment::PackageCatalogReference PackageManager::GetLocalPackageCatalog(winrt::Microsoft::Management::Deployment::LocalPackageCatalog const& localPackageCatalog) 200 { 201 LogStartupIfApplicable(); 202 ::AppInstaller::Repository::Source source; 203 switch (localPackageCatalog) 204 { 205 case winrt::Microsoft::Management::Deployment::LocalPackageCatalog::InstalledPackages: 206 source = ::AppInstaller::Repository::Source{ ::AppInstaller::Repository::PredefinedSource::Installed }; 207 break; 208 case winrt::Microsoft::Management::Deployment::LocalPackageCatalog::InstallingPackages: 209 source = ::AppInstaller::Repository::Source{ ::AppInstaller::Repository::PredefinedSource::Installing }; 210 break; 211 default: 212 throw hresult_invalid_argument(); 213 } 214 auto packageCatalogInfo = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::PackageCatalogInfo>>(); 215 packageCatalogInfo->Initialize(source.GetDetails()); 216 auto packageCatalogRef = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::PackageCatalogReference>>(); 217 packageCatalogRef->Initialize(*packageCatalogInfo, source); 218 return *packageCatalogRef; 219 } 220 221 winrt::Microsoft::Management::Deployment::PackageCatalogReference PackageManager::GetPackageCatalogByName(hstring const& catalogName) 222 { 223 LogStartupIfApplicable(); 224 std::string name = winrt::to_string(catalogName); 225 if (name.empty()) 226 { 227 return nullptr; 228 } 229 230 ::AppInstaller::Repository::Source source{ name }; 231 // Create the catalog object if the source is found, otherwise return null. Don't throw. 232 if (source) 233 { 234 auto packageCatalogInfo = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::PackageCatalogInfo>>(); 235 packageCatalogInfo->Initialize(source.GetDetails()); 236 auto packageCatalogRef = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::PackageCatalogReference>>(); 237 packageCatalogRef->Initialize(*packageCatalogInfo, source); 238 return *packageCatalogRef; 239 } 240 else 241 { 242 return nullptr; 243 } 244 } 245 246 void AddPackageManifestToContext(winrt::Microsoft::Management::Deployment::PackageVersionInfo packageVersionInfo, ::AppInstaller::CLI::Execution::Context* context) 247 { 248 winrt::Microsoft::Management::Deployment::implementation::PackageVersionInfo* packageVersionInfoImpl = get_self<winrt::Microsoft::Management::Deployment::implementation::PackageVersionInfo>(packageVersionInfo); 249 std::shared_ptr<::AppInstaller::Repository::IPackageVersion> internalPackageVersion = packageVersionInfoImpl->GetRepositoryPackageVersion(); 250 ::AppInstaller::Manifest::Manifest manifest = internalPackageVersion->GetManifest(); 251 252 std::string targetLocale; 253 if (context->Args.Contains(::AppInstaller::CLI::Execution::Args::Type::Locale)) 254 { 255 targetLocale = context->Args.GetArg(::AppInstaller::CLI::Execution::Args::Type::Locale); 256 } 257 manifest.ApplyLocale(targetLocale); 258 259 context->GetThreadGlobals().GetTelemetryLogger().LogManifestFields(manifest.Id, manifest.DefaultLocalization.Get<::AppInstaller::Manifest::Localization::PackageName>(), manifest.Version); 260 261 context->Add<::AppInstaller::CLI::Execution::Data::Manifest>(std::move(manifest)); 262 context->Add<::AppInstaller::CLI::Execution::Data::PackageVersion>(std::move(internalPackageVersion)); 263 } 264 265 void AddInstalledVersionToContext(winrt::Microsoft::Management::Deployment::PackageVersionInfo installedVersionInfo, ::AppInstaller::CLI::Execution::Context* context) 266 { 267 winrt::Microsoft::Management::Deployment::implementation::PackageVersionInfo* installedVersionInfoImpl = get_self<winrt::Microsoft::Management::Deployment::implementation::PackageVersionInfo>(installedVersionInfo); 268 std::shared_ptr<::AppInstaller::Repository::IPackageVersion> internalInstalledVersion = installedVersionInfoImpl->GetRepositoryPackageVersion(); 269 context->Add<AppInstaller::CLI::Execution::Data::InstalledPackageVersion>(internalInstalledVersion); 270 } 271 272 winrt::Microsoft::Management::Deployment::PackageCatalogReference PackageManager::CreateCompositePackageCatalog(winrt::Microsoft::Management::Deployment::CreateCompositePackageCatalogOptions const& options) 273 { 274 LogStartupIfApplicable(); 275 if (!options) 276 { 277 // Can't make a composite source if the options aren't specified. 278 throw hresult_invalid_argument(); 279 } 280 281 for (uint32_t i = 0; i < options.Catalogs().Size(); ++i) 282 { 283 auto catalog = options.Catalogs().GetAt(i); 284 if (catalog.IsComposite()) 285 { 286 // Can't make a composite source out of a source that's already a composite. 287 throw hresult_invalid_argument(); 288 } 289 } 290 auto packageCatalogImpl = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::PackageCatalogReference>>(); 291 packageCatalogImpl->Initialize(options); 292 return *packageCatalogImpl; 293 } 294 295 winrt::Microsoft::Management::Deployment::InstallResult GetInstallResult(::Workflow::ExecutionStage executionStage, winrt::hresult terminationHR, uint32_t installerError, winrt::hstring correlationData, bool rebootRequired) 296 { 297 winrt::Microsoft::Management::Deployment::InstallResultStatus installResultStatus = GetOperationResultStatus<InstallResultStatus>(executionStage, terminationHR); 298 auto installResult = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::InstallResult>>(); 299 installResult->Initialize(installResultStatus, terminationHR, installerError, correlationData, rebootRequired); 300 return *installResult; 301 } 302 303 winrt::Microsoft::Management::Deployment::UninstallResult GetUninstallResult(::Workflow::ExecutionStage executionStage, winrt::hresult terminationHR, uint32_t uninstallerError, winrt::hstring correlationData, bool rebootRequired) 304 { 305 winrt::Microsoft::Management::Deployment::UninstallResultStatus uninstallResultStatus = GetOperationResultStatus<UninstallResultStatus>(executionStage, terminationHR); 306 auto uninstallResult = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::UninstallResult>>(); 307 uninstallResult->Initialize(uninstallResultStatus, terminationHR, uninstallerError, correlationData, rebootRequired); 308 return *uninstallResult; 309 } 310 311 winrt::Microsoft::Management::Deployment::DownloadResult GetDownloadResult(::Workflow::ExecutionStage executionStage, winrt::hresult terminationHR, winrt::hstring correlationData) 312 { 313 winrt::Microsoft::Management::Deployment::DownloadResultStatus downloadResultStatus = GetOperationResultStatus<DownloadResultStatus>(executionStage, terminationHR); 314 auto downloadResult = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::DownloadResult>>(); 315 downloadResult->Initialize(downloadResultStatus, terminationHR, correlationData); 316 return *downloadResult; 317 } 318 319 winrt::Microsoft::Management::Deployment::RepairResult GetRepairResult(::Workflow::ExecutionStage executionStage, winrt::hresult terminationHR, uint32_t repairError, winrt::hstring correlationData, bool rebootRequired) 320 { 321 winrt::Microsoft::Management::Deployment::RepairResultStatus repairResultStatus = GetOperationResultStatus<RepairResultStatus>(executionStage, terminationHR); 322 auto repairResult = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::RepairResult>>(); 323 repairResult->Initialize(repairResultStatus, terminationHR, repairError, correlationData, rebootRequired); 324 return *repairResult; 325 } 326 327 template <typename TResult> 328 TResult GetOperationResult(::Workflow::ExecutionStage executionStage, winrt::hresult terminationHR, uint32_t operationError, winrt::hstring correlationData, bool rebootRequired) 329 { 330 if constexpr (std::is_same_v<TResult, winrt::Microsoft::Management::Deployment::InstallResult>) 331 { 332 return GetInstallResult(executionStage, terminationHR, operationError, correlationData, rebootRequired); 333 } 334 else if constexpr (std::is_same_v<TResult, winrt::Microsoft::Management::Deployment::UninstallResult>) 335 { 336 return GetUninstallResult(executionStage, terminationHR, operationError, correlationData, rebootRequired); 337 } 338 else if constexpr (std::is_same_v<TResult, winrt::Microsoft::Management::Deployment::DownloadResult>) 339 { 340 return GetDownloadResult(executionStage, terminationHR, correlationData); 341 } 342 else if constexpr (std::is_same_v<TResult, winrt::Microsoft::Management::Deployment::RepairResult>) 343 { 344 return GetRepairResult(executionStage, terminationHR, operationError, correlationData, rebootRequired); 345 } 346 } 347 348 #define WINGET_GET_PROGRESS_STATE(_installState_, _uninstallState_, _repairState_) \ 349 if constexpr (std::is_same_v<TState, winrt::Microsoft::Management::Deployment::PackageInstallProgressState>) \ 350 { \ 351 progressState = TState::_installState_; \ 352 } \ 353 else if constexpr (std::is_same_v<TState, winrt::Microsoft::Management::Deployment::PackageUninstallProgressState>) \ 354 { \ 355 progressState = TState::_uninstallState_; \ 356 } \ 357 else if constexpr (std::is_same_v<TState, winrt::Microsoft::Management::Deployment::PackageRepairProgressState>) \ 358 { \ 359 progressState = TState::_repairState_; \ 360 } \ 361 362 template <typename TProgress, typename TState> 363 std::optional<TProgress> GetProgress( 364 ReportType reportType, 365 uint64_t current, 366 uint64_t maximum, 367 ::AppInstaller::ProgressType progressType, 368 ::Workflow::ExecutionStage executionPhase) 369 { 370 bool reportProgress = false; 371 TState progressState = TState::Queued; 372 double downloadProgress = 0; 373 double operationProgress = 0; 374 uint64_t downloadBytesDownloaded = 0; 375 uint64_t downloadBytesRequired = 0; 376 switch (executionPhase) 377 { 378 case ::Workflow::ExecutionStage::Initial: 379 case ::Workflow::ExecutionStage::ParseArgs: 380 case ::Workflow::ExecutionStage::Discovery: 381 // We already reported queued progress up front. 382 break; 383 case ::Workflow::ExecutionStage::Download: 384 if constexpr (std::is_same_v<TProgress, winrt::Microsoft::Management::Deployment::InstallProgress> || 385 std::is_same_v<TProgress, winrt::Microsoft::Management::Deployment::PackageDownloadProgress>) 386 { 387 progressState = TState::Downloading; 388 if (reportType == ReportType::BeginProgress) 389 { 390 reportProgress = true; 391 } 392 else if (progressType == ::AppInstaller::ProgressType::Bytes) 393 { 394 downloadBytesDownloaded = current; 395 downloadBytesRequired = maximum; 396 if (maximum > 0 && maximum >= current) 397 { 398 reportProgress = true; 399 downloadProgress = static_cast<double>(current) / static_cast<double>(maximum); 400 } 401 } 402 } 403 break; 404 case ::Workflow::ExecutionStage::PreExecution: 405 // Wait until installer starts to report operation. 406 break; 407 case ::Workflow::ExecutionStage::Execution: 408 WINGET_GET_PROGRESS_STATE(Installing, Uninstalling, Repairing); 409 downloadProgress = 1; 410 if (reportType == ReportType::ExecutionPhaseUpdate) 411 { 412 // Operation is starting. Send progress so callers know the AsyncOperation can't be cancelled. 413 reportProgress = true; 414 } 415 else if (reportType == ReportType::EndProgress) 416 { 417 // Operation is "finished". May not have succeeded. 418 reportProgress = true; 419 operationProgress = 1; 420 } 421 else if (progressType == ::AppInstaller::ProgressType::Percent) 422 { 423 if (maximum > 0 && maximum >= current) 424 { 425 // Operation is progressing 426 reportProgress = true; 427 operationProgress = static_cast<double>(current) / static_cast<double>(maximum); 428 } 429 } 430 break; 431 case ::Workflow::ExecutionStage::PostExecution: 432 if (reportType == ReportType::ExecutionPhaseUpdate) 433 { 434 // Send PostInstall progress when it switches to PostExecution phase. 435 reportProgress = true; 436 WINGET_GET_PROGRESS_STATE(PostInstall, PostUninstall, PostRepair); 437 downloadProgress = 1; 438 operationProgress = 1; 439 } 440 break; 441 } 442 if (reportProgress) 443 { 444 if constexpr (std::is_same_v<TProgress, winrt::Microsoft::Management::Deployment::InstallProgress>) 445 { 446 TProgress progress{ progressState, downloadBytesDownloaded, downloadBytesRequired, downloadProgress, operationProgress }; 447 return progress; 448 } 449 else if constexpr (std::is_same_v<TProgress, winrt::Microsoft::Management::Deployment::UninstallProgress>) 450 { 451 TProgress progress{ progressState, operationProgress }; 452 return progress; 453 } 454 else if constexpr (std::is_same_v<TProgress, winrt::Microsoft::Management::Deployment::PackageDownloadProgress>) 455 { 456 TProgress progress{ progressState, downloadBytesDownloaded, downloadBytesRequired, downloadProgress }; 457 return progress; 458 } 459 else if constexpr (std::is_same_v<TProgress, winrt::Microsoft::Management::Deployment::RepairProgress>) 460 { 461 TProgress progress{ progressState, operationProgress }; 462 return progress; 463 } 464 } 465 else 466 { 467 return {}; 468 } 469 } 470 471 template <typename TOptions> 472 Microsoft::Management::Deployment::PackageVersionInfo GetPackageVersionInfo(winrt::Microsoft::Management::Deployment::CatalogPackage package, TOptions options) 473 { 474 Microsoft::Management::Deployment::PackageVersionInfo packageVersionInfo{ nullptr }; 475 476 winrt::Microsoft::Management::Deployment::PackageVersionId versionId = (options) ? options.PackageVersionId() : nullptr; 477 // If the version of the package is specified use that, otherwise use the default. 478 if (versionId) 479 { 480 packageVersionInfo = package.GetPackageVersionInfo(versionId); 481 } 482 else 483 { 484 if constexpr (std::is_same_v<TOptions, winrt::Microsoft::Management::Deployment::InstallOptions>) 485 { 486 packageVersionInfo = package.DefaultInstallVersion(); 487 } 488 else if constexpr (std::is_same_v<TOptions, winrt::Microsoft::Management::Deployment::DownloadOptions>) 489 { 490 // For download, applicability check is not needed. Just use latest. 491 if (package.AvailableVersions().Size() > 0) 492 { 493 packageVersionInfo = package.GetPackageVersionInfo(package.AvailableVersions().GetAt(0)); 494 } 495 } 496 } 497 // If the specified version wasn't found then return a failure. This is unusual, since all packages that came from a non-local catalog have a default version, 498 // and the versionId is strongly typed and comes from the CatalogPackage.GetAvailableVersions. 499 // If version is not specified, DefaultInstallVersion may be empty due to applicability check. 500 THROW_HR_IF(versionId ? APPINSTALLER_CLI_ERROR_NO_MANIFEST_FOUND : APPINSTALLER_CLI_ERROR_NO_APPLICABLE_INSTALLER, !packageVersionInfo); 501 return packageVersionInfo; 502 } 503 504 void PopulateContextFromInstallOptions( 505 ::AppInstaller::CLI::Execution::Context* context, 506 winrt::Microsoft::Management::Deployment::InstallOptions options) 507 { 508 if (options) 509 { 510 if (!options.LogOutputPath().empty()) 511 { 512 context->Args.AddArg(Execution::Args::Type::Log, ::AppInstaller::Utility::ConvertToUTF8(options.LogOutputPath())); 513 context->Args.AddArg(Execution::Args::Type::VerboseLogs); 514 } 515 if (options.AllowHashMismatch()) 516 { 517 context->Args.AddArg(Execution::Args::Type::HashOverride); 518 } 519 520 if (options.BypassIsStoreClientBlockedPolicyCheck()) 521 { 522 context->SetFlags(Execution::ContextFlag::BypassIsStoreClientBlockedPolicyCheck); 523 } 524 525 if (options.Force()) 526 { 527 context->Args.AddArg(Execution::Args::Type::Force); 528 } 529 530 // If the PackageInstallScope is anything other than ::Any then set it as a requirement. 531 auto manifestScope = GetManifestScope(options.PackageInstallScope()); 532 if (manifestScope.first != ::AppInstaller::Manifest::ScopeEnum::Unknown) 533 { 534 context->Args.AddArg(Execution::Args::Type::InstallScope, ScopeToString(manifestScope.first)); 535 context->Add<Execution::Data::AllowUnknownScope>(manifestScope.second); 536 } 537 538 if (options.PackageInstallMode() == PackageInstallMode::Interactive) 539 { 540 context->Args.AddArg(Execution::Args::Type::Interactive); 541 } 542 else if (options.PackageInstallMode() == PackageInstallMode::Silent) 543 { 544 context->Args.AddArg(Execution::Args::Type::Silent); 545 } 546 547 auto installerType = GetManifestInstallerType(options.InstallerType()); 548 if (installerType != AppInstaller::Manifest::InstallerTypeEnum::Unknown) 549 { 550 context->Args.AddArg(Execution::Args::Type::InstallerType, AppInstaller::Manifest::InstallerTypeToString(installerType)); 551 } 552 553 if (!options.PreferredInstallLocation().empty()) 554 { 555 context->Args.AddArg(Execution::Args::Type::InstallLocation, ::AppInstaller::Utility::ConvertToUTF8(options.PreferredInstallLocation())); 556 } 557 558 if (!options.ReplacementInstallerArguments().empty()) 559 { 560 context->Args.AddArg(Execution::Args::Type::Override, ::AppInstaller::Utility::ConvertToUTF8(options.ReplacementInstallerArguments())); 561 } 562 563 if (!options.AdditionalInstallerArguments().empty()) 564 { 565 context->Args.AddArg(Execution::Args::Type::CustomSwitches, ::AppInstaller::Utility::ConvertToUTF8(options.AdditionalInstallerArguments())); 566 } 567 568 if (options.AllowedArchitectures().Size() != 0) 569 { 570 std::vector<AppInstaller::Utility::Architecture> allowedArchitectures; 571 for (auto architecture : options.AllowedArchitectures()) 572 { 573 auto convertedArchitecture = GetUtilityArchitecture(architecture); 574 if (convertedArchitecture) 575 { 576 allowedArchitectures.push_back(convertedArchitecture.value()); 577 } 578 } 579 context->Add<Data::AllowedArchitectures>(std::move(allowedArchitectures)); 580 } 581 582 // Note: AdditionalPackageCatalogArguments is not needed during install since the manifest is already known so no additional calls to the source are needed. The property is deprecated. 583 584 if (options.AcceptPackageAgreements()) 585 { 586 context->Args.AddArg(Execution::Args::Type::AcceptPackageAgreements); 587 } 588 589 if (options.SkipDependencies()) 590 { 591 context->Args.AddArg(Execution::Args::Type::SkipDependencies); 592 } 593 594 if (options.AuthenticationArguments()) 595 { 596 context->Args.AddArg(Execution::Args::Type::AuthenticationMode, ::AppInstaller::Authentication::AuthenticationModeToString(GetAuthenticationMode(options.AuthenticationArguments().AuthenticationMode()))); 597 context->Args.AddArg(Execution::Args::Type::AuthenticationAccount, ::AppInstaller::Utility::ConvertToUTF8(options.AuthenticationArguments().AuthenticationAccount())); 598 } 599 } 600 else 601 { 602 // Note: If no install options are specified, we assume the caller is accepting the package agreements by default. 603 context->Args.AddArg(Execution::Args::Type::AcceptPackageAgreements); 604 } 605 } 606 607 void PopulateContextFromUninstallOptions( 608 ::AppInstaller::CLI::Execution::Context* context, 609 winrt::Microsoft::Management::Deployment::UninstallOptions options) 610 { 611 if (options) 612 { 613 if (!options.LogOutputPath().empty()) 614 { 615 context->Args.AddArg(Execution::Args::Type::Log, ::AppInstaller::Utility::ConvertToUTF8(options.LogOutputPath())); 616 context->Args.AddArg(Execution::Args::Type::VerboseLogs); 617 } 618 if (options.Force()) 619 { 620 context->Args.AddArg(Execution::Args::Type::Force); 621 } 622 623 if (options.PackageUninstallMode() == PackageUninstallMode::Interactive) 624 { 625 context->Args.AddArg(Execution::Args::Type::Interactive); 626 } 627 else if (options.PackageUninstallMode() == PackageUninstallMode::Silent) 628 { 629 context->Args.AddArg(Execution::Args::Type::Silent); 630 } 631 632 auto uninstallScope = GetManifestUninstallScope(options.PackageUninstallScope()); 633 if (uninstallScope != ::AppInstaller::Manifest::ScopeEnum::Unknown) 634 { 635 context->Args.AddArg(Execution::Args::Type::InstallScope, ScopeToString(uninstallScope)); 636 } 637 } 638 } 639 640 void PopulateContextFromDownloadOptions( 641 ::AppInstaller::CLI::Execution::Context* context, 642 winrt::Microsoft::Management::Deployment::DownloadOptions options) 643 { 644 if (options) 645 { 646 if (!options.DownloadDirectory().empty()) 647 { 648 context->Args.AddArg(Execution::Args::Type::DownloadDirectory, ::AppInstaller::Utility::ConvertToUTF8(options.DownloadDirectory())); 649 } 650 if (!options.Locale().empty()) 651 { 652 context->Args.AddArg(Execution::Args::Type::Locale, ::AppInstaller::Utility::ConvertToUTF8(options.Locale())); 653 } 654 if (options.AllowHashMismatch()) 655 { 656 context->Args.AddArg(Execution::Args::Type::HashOverride); 657 } 658 if (options.SkipDependencies()) 659 { 660 context->Args.AddArg(Execution::Args::Type::SkipDependencies); 661 } 662 if (options.AcceptPackageAgreements()) 663 { 664 context->Args.AddArg(Execution::Args::Type::AcceptPackageAgreements); 665 } 666 auto manifestScope = GetManifestScope(options.Scope()); 667 if (manifestScope.first != ::AppInstaller::Manifest::ScopeEnum::Unknown) 668 { 669 context->Args.AddArg(Execution::Args::Type::InstallScope, ScopeToString(manifestScope.first)); 670 } 671 672 auto architecture = options.Architecture(); 673 if (architecture != Windows::System::ProcessorArchitecture::Unknown) 674 { 675 auto convertedArchitecture = GetUtilityArchitecture(architecture); 676 if (convertedArchitecture) 677 { 678 context->Args.AddArg(Execution::Args::Type::InstallerArchitecture, ToString(convertedArchitecture.value())); 679 } 680 } 681 682 auto installerType = GetManifestInstallerType(options.InstallerType()); 683 if (installerType != AppInstaller::Manifest::InstallerTypeEnum::Unknown) 684 { 685 context->Args.AddArg(Execution::Args::Type::InstallerType, AppInstaller::Manifest::InstallerTypeToString(installerType)); 686 } 687 688 if (options.AuthenticationArguments()) 689 { 690 context->Args.AddArg(Execution::Args::Type::AuthenticationMode, ::AppInstaller::Authentication::AuthenticationModeToString(GetAuthenticationMode(options.AuthenticationArguments().AuthenticationMode()))); 691 context->Args.AddArg(Execution::Args::Type::AuthenticationAccount, ::AppInstaller::Utility::ConvertToUTF8(options.AuthenticationArguments().AuthenticationAccount())); 692 } 693 694 if (options.SkipMicrosoftStoreLicense()) 695 { 696 context->Args.AddArg(Execution::Args::Type::SkipMicrosoftStorePackageLicense); 697 } 698 699 WindowsPlatform platform = options.Platform(); 700 if (platform != WindowsPlatform::Unknown) 701 { 702 context->Args.AddArg(Execution::Args::Type::Platform, AppInstaller::Manifest::PlatformToString(GetPlatformEnum(platform))); 703 } 704 705 hstring targetOSVersion = options.TargetOSVersion(); 706 if (!targetOSVersion.empty()) 707 { 708 context->Args.AddArg(Execution::Args::Type::OSVersion, ::AppInstaller::Utility::ConvertToUTF8(targetOSVersion)); 709 } 710 } 711 } 712 713 void PopulateContextFromRepairOptions( 714 ::AppInstaller::CLI::Execution::Context* context, 715 winrt::Microsoft::Management::Deployment::RepairOptions options) 716 { 717 if (options) 718 { 719 if (!options.LogOutputPath().empty()) 720 { 721 context->Args.AddArg(Execution::Args::Type::Log, ::AppInstaller::Utility::ConvertToUTF8(options.LogOutputPath())); 722 context->Args.AddArg(Execution::Args::Type::VerboseLogs); 723 } 724 725 if (options.PackageRepairMode() == PackageRepairMode::Interactive) 726 { 727 context->Args.AddArg(Execution::Args::Type::Interactive); 728 } 729 else if (options.PackageRepairMode() == PackageRepairMode::Silent) 730 { 731 context->Args.AddArg(Execution::Args::Type::Silent); 732 } 733 734 if (options.AcceptPackageAgreements()) 735 { 736 context->Args.AddArg(Execution::Args::Type::AcceptPackageAgreements); 737 } 738 739 if (options.AllowHashMismatch()) 740 { 741 context->Args.AddArg(Execution::Args::Type::HashOverride); 742 } 743 744 if (options.BypassIsStoreClientBlockedPolicyCheck()) 745 { 746 context->SetFlags(Execution::ContextFlag::BypassIsStoreClientBlockedPolicyCheck); 747 } 748 749 if (options.Force()) 750 { 751 context->Args.AddArg(Execution::Args::Type::Force); 752 } 753 754 auto repairScope = GetManifestRepairScope(options.PackageRepairScope()); 755 if (repairScope != ::AppInstaller::Manifest::ScopeEnum::Unknown) 756 { 757 context->Args.AddArg(Execution::Args::Type::InstallScope, ScopeToString(repairScope)); 758 } 759 760 if (options.AuthenticationArguments()) 761 { 762 context->Args.AddArg(Execution::Args::Type::AuthenticationMode, ::AppInstaller::Authentication::AuthenticationModeToString(GetAuthenticationMode(options.AuthenticationArguments().AuthenticationMode()))); 763 context->Args.AddArg(Execution::Args::Type::AuthenticationAccount, ::AppInstaller::Utility::ConvertToUTF8(options.AuthenticationArguments().AuthenticationAccount())); 764 } 765 } 766 } 767 768 template <typename TOptions> 769 std::unique_ptr<COMContext> CreateContextFromOperationOptions( 770 TOptions options, 771 std::wstring callerProcessInfoString) 772 { 773 std::unique_ptr<COMContext> context = std::make_unique<COMContext>(); 774 hstring correlationData = (options) ? options.CorrelationData() : L""; 775 776 context->SetContextLoggers(correlationData, GetComCallerName(AppInstaller::Utility::ConvertToUTF8(callerProcessInfoString))); 777 778 // Convert the options to arguments for the installer. 779 if constexpr (std::is_same_v<TOptions, winrt::Microsoft::Management::Deployment::InstallOptions>) 780 { 781 PopulateContextFromInstallOptions(context.get(), options); 782 } 783 else if constexpr (std::is_same_v<TOptions, winrt::Microsoft::Management::Deployment::UninstallOptions>) 784 { 785 PopulateContextFromUninstallOptions(context.get(), options); 786 } 787 else if constexpr (std::is_same_v<TOptions, winrt::Microsoft::Management::Deployment::DownloadOptions>) 788 { 789 PopulateContextFromDownloadOptions(context.get(), options); 790 } 791 else if constexpr (std::is_same_v<TOptions, winrt::Microsoft::Management::Deployment::RepairOptions>) 792 { 793 PopulateContextFromRepairOptions(context.get(), options); 794 } 795 796 return context; 797 } 798 799 std::shared_ptr<Execution::OrchestratorQueueItem> GetExistingQueueItemForPackage(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::PackageCatalogInfo catalogInfo) 800 { 801 std::shared_ptr<Execution::OrchestratorQueueItem> queueItem = nullptr; 802 std::unique_ptr<COMContext> context = std::make_unique<COMContext>(); 803 if (catalogInfo) 804 { 805 // If the caller has passed in the catalog they expect the package to have come from, then only look for an install from that catalog. 806 // Fail if they've used a catalog that doesn't have an Id. This can currently happen for Info objects that come from PackageCatalogReference objects for REST catalogs. 807 THROW_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS, catalogInfo.Id().empty()); 808 auto searchItem = Execution::OrchestratorQueueItemFactory::CreateItemForSearch(std::wstring{ package.Id() }, std::wstring{ catalogInfo.Id() }, std::move(context)); 809 queueItem = Execution::ContextOrchestrator::Instance().GetQueueItem(searchItem->GetId()); 810 return queueItem; 811 } 812 813 // If the caller has not specified the catalog, then check InstalledVersion. When the package comes from the Installing catalog the PackageCatalog 814 // of the InstalledVersion will be set to the original catalog that the install was from, so checking the InstalledVersion first is most likely to 815 // find a result. 816 Microsoft::Management::Deployment::PackageVersionInfo installedVersionInfo = package.InstalledVersion(); 817 if (installedVersionInfo) 818 { 819 auto searchItem = Execution::OrchestratorQueueItemFactory::CreateItemForSearch(std::wstring{ package.Id() }, std::wstring{ installedVersionInfo.PackageCatalog().Info().Id() }, std::move(context)); 820 queueItem = Execution::ContextOrchestrator::Instance().GetQueueItem(searchItem->GetId()); 821 if (queueItem) 822 { 823 return queueItem; 824 } 825 } 826 827 // If InstalledVersion was not found, check DefaultInstallVersion 828 Microsoft::Management::Deployment::PackageVersionInfo defaultInstallVersionInfo = package.DefaultInstallVersion(); 829 if (defaultInstallVersionInfo) 830 { 831 auto searchItem = Execution::OrchestratorQueueItemFactory::CreateItemForSearch(std::wstring{ package.Id() }, std::wstring{ defaultInstallVersionInfo.PackageCatalog().Info().Id() }, std::move(context)); 832 queueItem = Execution::ContextOrchestrator::Instance().GetQueueItem(searchItem->GetId()); 833 if (queueItem) 834 { 835 return queueItem; 836 } 837 } 838 839 // Finally check all catalogs in AvailableVersions. 840 for (Microsoft::Management::Deployment::PackageVersionId versionId : package.AvailableVersions()) 841 { 842 auto searchItem = Execution::OrchestratorQueueItemFactory::CreateItemForSearch(std::wstring{ package.Id() }, std::wstring{ package.GetPackageVersionInfo(versionId).PackageCatalog().Info().Id() }, std::move(context)); 843 queueItem = Execution::ContextOrchestrator::Instance().GetQueueItem(searchItem->GetId()); 844 if (queueItem) 845 { 846 return queueItem; 847 } 848 } 849 return nullptr; 850 } 851 852 std::unique_ptr<Execution::OrchestratorQueueItem> CreateQueueItemForInstall( 853 std::unique_ptr<::AppInstaller::CLI::Execution::COMContext> comContext, 854 winrt::Microsoft::Management::Deployment::CatalogPackage package, 855 winrt::Microsoft::Management::Deployment::InstallOptions options, 856 bool isUpgrade) 857 { 858 // Add manifest and PackageVersion to context for install/upgrade. 859 // If the version of the package is specified use that, otherwise use the default. 860 Microsoft::Management::Deployment::PackageVersionInfo packageVersionInfo = GetPackageVersionInfo(package, options); 861 AddPackageManifestToContext(packageVersionInfo, comContext.get()); 862 863 if (isUpgrade) 864 { 865 AppInstaller::Utility::VersionAndChannel installedVersion{ winrt::to_string(package.InstalledVersion().Version()), winrt::to_string(package.InstalledVersion().Channel()) }; 866 AppInstaller::Utility::VersionAndChannel upgradeVersion{ winrt::to_string(packageVersionInfo.Version()), winrt::to_string(packageVersionInfo.Channel()) }; 867 868 // Perform upgrade version check 869 if (upgradeVersion.GetVersion().IsUnknown()) 870 { 871 if (!(options.AllowUpgradeToUnknownVersion() && 872 AppInstaller::Utility::ICUCaseInsensitiveEquals(installedVersion.GetChannel().ToString(), upgradeVersion.GetChannel().ToString()))) 873 { 874 THROW_HR(APPINSTALLER_CLI_ERROR_UPGRADE_VERSION_UNKNOWN); 875 } 876 } 877 else if (!installedVersion.IsUpdatedBy(upgradeVersion)) 878 { 879 THROW_HR(APPINSTALLER_CLI_ERROR_UPGRADE_VERSION_NOT_NEWER); 880 } 881 882 // Set upgrade flag 883 comContext->SetFlags(AppInstaller::CLI::Execution::ContextFlag::InstallerExecutionUseUpdate); 884 // Add installed version 885 AddInstalledVersionToContext(package.InstalledVersion(), comContext.get()); 886 } 887 888 return Execution::OrchestratorQueueItemFactory::CreateItemForInstall(std::wstring{ package.Id() }, std::wstring{ packageVersionInfo.PackageCatalog().Info().Id() }, std::move(comContext), isUpgrade); 889 } 890 891 std::unique_ptr<Execution::OrchestratorQueueItem> CreateQueueItemForUninstall( 892 std::unique_ptr<::AppInstaller::CLI::Execution::COMContext> comContext, 893 winrt::Microsoft::Management::Deployment::CatalogPackage package) 894 { 895 // Add installed version 896 AddInstalledVersionToContext(package.InstalledVersion(), comContext.get()); 897 898 // Add Package which is used by RecordUninstall later for removing from tracking catalog of correlated available sources as best effort 899 winrt::Microsoft::Management::Deployment::implementation::CatalogPackage* catalogPackageImpl = get_self<winrt::Microsoft::Management::Deployment::implementation::CatalogPackage>(package); 900 std::shared_ptr<::AppInstaller::Repository::ICompositePackage> internalPackage = catalogPackageImpl->GetRepositoryPackage(); 901 comContext->Add<AppInstaller::CLI::Execution::Data::Package>(internalPackage); 902 903 return Execution::OrchestratorQueueItemFactory::CreateItemForUninstall(std::wstring{ package.Id() }, std::wstring{ package.InstalledVersion().PackageCatalog().Info().Id() }, std::move(comContext)); 904 } 905 906 std::unique_ptr<Execution::OrchestratorQueueItem> CreateQueueItemForDownload( 907 std::unique_ptr<::AppInstaller::CLI::Execution::COMContext> comContext, 908 winrt::Microsoft::Management::Deployment::CatalogPackage package, 909 winrt::Microsoft::Management::Deployment::DownloadOptions options) 910 { 911 // Add manifest and PackageVersion to context for download. 912 // If the version of the package is specified use that, otherwise use the default. 913 Microsoft::Management::Deployment::PackageVersionInfo packageVersionInfo = GetPackageVersionInfo(package, options); 914 AddPackageManifestToContext(packageVersionInfo, comContext.get()); 915 916 comContext->SetFlags(AppInstaller::CLI::Execution::ContextFlag::InstallerDownloadOnly); 917 918 return Execution::OrchestratorQueueItemFactory::CreateItemForDownload(std::wstring{ package.Id() }, std::wstring{ packageVersionInfo.PackageCatalog().Info().Id() }, std::move(comContext)); 919 } 920 921 std::unique_ptr<Execution::OrchestratorQueueItem> CreateQueueItemForRepair( 922 std::unique_ptr<::AppInstaller::CLI::Execution::COMContext> comContext, 923 winrt::Microsoft::Management::Deployment::CatalogPackage package) 924 { 925 // Add installed version 926 AddInstalledVersionToContext(package.InstalledVersion(), comContext.get()); 927 928 // Add Package which is used to co-relate installed package with available package for repair 929 winrt::Microsoft::Management::Deployment::implementation::CatalogPackage* catalogPackageImpl = get_self<winrt::Microsoft::Management::Deployment::implementation::CatalogPackage>(package); 930 std::shared_ptr<::AppInstaller::Repository::ICompositePackage> internalPackage = catalogPackageImpl->GetRepositoryPackage(); 931 comContext->Add<AppInstaller::CLI::Execution::Data::Package>(internalPackage); 932 933 comContext->SetFlags(AppInstaller::CLI::Execution::ContextFlag::InstallerExecutionUseRepair); 934 935 return Execution::OrchestratorQueueItemFactory::CreateItemForRepair(std::wstring{ package.Id() }, std::wstring{ package.InstalledVersion().PackageCatalog().Info().Id() }, std::move(comContext)); 936 } 937 938 template <typename TResult, typename TProgress, typename TOptions, typename TProgressState> 939 winrt::Windows::Foundation::IAsyncOperationWithProgress<TResult, TProgress> GetPackageOperation( 940 bool canCancelQueueItem, 941 std::shared_ptr<Execution::OrchestratorQueueItem> queueItemParam, 942 winrt::Microsoft::Management::Deployment::CatalogPackage package = nullptr, 943 TOptions options = nullptr, 944 std::wstring callerProcessInfoString = {}, 945 bool isUpgrade = false) 946 { 947 winrt::hresult terminationHR = S_OK; 948 uint32_t operationError = 0; 949 hstring correlationData = (options) ? options.CorrelationData() : L""; 950 ::Workflow::ExecutionStage executionStage = ::Workflow::ExecutionStage::Initial; 951 952 try 953 { 954 // re-scope the parameter to inside the try block to avoid lifetime management issues. 955 std::shared_ptr<Execution::OrchestratorQueueItem> queueItem = std::move(queueItemParam); 956 957 auto report_progress{ co_await winrt::get_progress_token() }; 958 auto cancellationToken{ co_await winrt::get_cancellation_token() }; 959 // co_await does not guarantee that it's on a background thread, so do so explicitly. 960 co_await winrt::resume_background(); 961 962 if (queueItem == nullptr) 963 { 964 std::unique_ptr<COMContext> comContext = CreateContextFromOperationOptions<TOptions>(options, callerProcessInfoString); 965 966 if constexpr (std::is_same_v<TOptions, winrt::Microsoft::Management::Deployment::InstallOptions>) 967 { 968 queueItem = CreateQueueItemForInstall(std::move(comContext), package, options, isUpgrade); 969 } 970 else if constexpr (std::is_same_v<TOptions, winrt::Microsoft::Management::Deployment::UninstallOptions>) 971 { 972 queueItem = CreateQueueItemForUninstall(std::move(comContext), package); 973 } 974 else if constexpr (std::is_same_v<TOptions, winrt::Microsoft::Management::Deployment::DownloadOptions>) 975 { 976 queueItem = CreateQueueItemForDownload(std::move(comContext), package, options); 977 } 978 else if constexpr (std::is_same_v<TOptions, winrt::Microsoft::Management::Deployment::RepairOptions>) 979 { 980 queueItem = CreateQueueItemForRepair(std::move(comContext), package); 981 } 982 983 Execution::ContextOrchestrator::Instance().EnqueueAndRunItem(queueItem); 984 985 if constexpr (std::is_same_v<TProgress, winrt::Microsoft::Management::Deployment::PackageInstallProgressState>) 986 { 987 TProgress queuedProgress{ TProgressState::Queued, 0, 0, 0 }; 988 report_progress(queuedProgress); 989 } 990 else if constexpr (std::is_same_v<TProgress, winrt::Microsoft::Management::Deployment::PackageUninstallProgressState>) 991 { 992 TProgress queuedProgress{ TProgressState::Queued, 0 }; 993 report_progress(queuedProgress); 994 } 995 else if constexpr (std::is_same_v<TProgress, winrt::Microsoft::Management::Deployment::PackageDownloadProgressState>) 996 { 997 TProgress queuedProgress{ TProgressState::Queued, 0 }; 998 report_progress(queuedProgress); 999 } 1000 else if constexpr (std::is_same_v<TProgress, winrt::Microsoft::Management::Deployment::PackageRepairProgressState>) 1001 { 1002 TProgress queuedProgress{ TProgressState::Queued, 0 }; 1003 report_progress(queuedProgress); 1004 } 1005 } 1006 { 1007 // correlation data is not passed in when retrieving an existing queue item, so get it from the existing context. 1008 correlationData = hstring(queueItem->GetContext().GetCorrelationJson()); 1009 } 1010 1011 wil::unique_event progressEvent{ wil::EventOptions::None }; 1012 1013 std::atomic<TProgress> operationProgress; 1014 queueItem->GetContext().AddProgressCallbackFunction([&operationProgress, &progressEvent]( 1015 ReportType reportType, 1016 uint64_t current, 1017 uint64_t maximum, 1018 ::AppInstaller::ProgressType progressType, 1019 ::Workflow::ExecutionStage executionPhase) 1020 { 1021 std::optional<TProgress> operationProgressOptional = GetProgress<TProgress, TProgressState>(reportType, current, maximum, progressType, executionPhase); 1022 if (operationProgressOptional.has_value()) 1023 { 1024 operationProgress = operationProgressOptional.value(); 1025 progressEvent.SetEvent(); 1026 } 1027 return; 1028 } 1029 ); 1030 1031 std::weak_ptr<Execution::OrchestratorQueueItem> weakQueueItem(queueItem); 1032 cancellationToken.callback([weakQueueItem, &canCancelQueueItem] 1033 { 1034 if (canCancelQueueItem) 1035 { 1036 auto strongQueueItem = weakQueueItem.lock(); 1037 if (strongQueueItem) { 1038 // The cancellation of the AsyncOperation on the client triggers Cancel which causes the Execute to end. 1039 Execution::ContextOrchestrator::Instance().CancelQueueItem(*strongQueueItem); 1040 } 1041 } 1042 }); 1043 1044 // Wait for completion or progress events. 1045 // Waiting for both on the same thread ensures that progress is never reported after the async operation itself has completed. 1046 bool completionEventFired = false; 1047 HANDLE operationEvents[2]; 1048 operationEvents[0] = progressEvent.get(); 1049 operationEvents[1] = queueItem->GetCompletedEvent().get(); 1050 while (!completionEventFired) 1051 { 1052 DWORD dwEvent = WaitForMultipleObjects( 1053 _countof(operationEvents) /* number of events */, 1054 operationEvents /* event array */, 1055 FALSE /* bWaitAll, FALSE to wake on any event */, 1056 INFINITE /* wait until operation completion */); 1057 1058 switch (dwEvent) 1059 { 1060 // operationEvents[0] was signaled, progress 1061 case WAIT_OBJECT_0 + 0: 1062 // The report_progress call will hang when making callbacks to suspended processes so it's important that this is now on a background thread. 1063 // Progress events are not queued - some will be missed if multiple progress events are fired from the ComContext to the callback 1064 // while the report_progress call is hung\in progress. 1065 // Duplicate progress events can be fired if another progress event comes from the ComContext to the callback after the listener 1066 // has been awaked, but before it has gotten the installProgress. 1067 report_progress(operationProgress); 1068 break; 1069 1070 // operationEvents[1] was signaled, operation completed 1071 case WAIT_OBJECT_0 + 1: 1072 completionEventFired = true; 1073 break; 1074 1075 // Return value is invalid. 1076 default: 1077 THROW_LAST_ERROR(); 1078 } 1079 } 1080 1081 if (completionEventFired) 1082 { 1083 // The install command has finished, check for success/failure and how far it got. 1084 terminationHR = queueItem->GetContext().GetTerminationHR(); 1085 executionStage = queueItem->GetContext().GetExecutionStage(); 1086 if (queueItem->GetContext().Contains(Data::OperationReturnCode)) 1087 { 1088 operationError = static_cast<uint32_t>(queueItem->GetContext().Get<Data::OperationReturnCode>()); 1089 } 1090 } 1091 } 1092 WINGET_CATCH_STORE(terminationHR, APPINSTALLER_CLI_ERROR_COMMAND_FAILED); 1093 1094 // TODO - RebootRequired not yet populated, msi arguments not returned from Execute. 1095 co_return GetOperationResult<TResult>(executionStage, terminationHR, operationError, correlationData, false); 1096 } 1097 1098 template <typename TResult, typename TProgress> 1099 winrt::Windows::Foundation::IAsyncOperationWithProgress<TResult, TProgress> GetEmptyAsynchronousResultForOperation( 1100 HRESULT hr, 1101 hstring correlationData) 1102 { 1103 // If a function uses co_await or co_return (i.e. if it is a co_routine), it cannot use return directly. 1104 // This helper helps a function that is not a coroutine itself to return errors asynchronously. 1105 co_return GetOperationResult<TResult>(::Workflow::ExecutionStage::Initial, hr, 0, correlationData, false); 1106 } 1107 1108 #define WINGET_RETURN_INSTALL_RESULT_HR_IF(hr, boolVal) { if(boolVal) { return GetEmptyAsynchronousResultForOperation<Deployment::InstallResult, Deployment::InstallProgress>(hr, correlationData); }} 1109 #define WINGET_RETURN_INSTALL_RESULT_HR_IF_FAILED(hr) { WINGET_RETURN_INSTALL_RESULT_HR_IF(hr, FAILED(hr)) } 1110 1111 winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Microsoft::Management::Deployment::InstallResult, winrt::Microsoft::Management::Deployment::InstallProgress> PackageManager::InstallPackageAsync(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::InstallOptions options) 1112 { 1113 hstring correlationData = (options) ? options.CorrelationData() : L""; 1114 1115 // options and catalog can both be null, package must be set. 1116 WINGET_RETURN_INSTALL_RESULT_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS, !package); 1117 1118 HRESULT hr = S_OK; 1119 std::wstring callerProcessInfoString; 1120 try 1121 { 1122 // Check for permissions and get caller info for telemetry. 1123 // This must be done before any co_awaits since it requires info from the rpc caller thread. 1124 auto [hrGetCallerId, callerProcessId] = GetCallerProcessId(); 1125 WINGET_RETURN_INSTALL_RESULT_HR_IF_FAILED(hrGetCallerId); 1126 WINGET_RETURN_INSTALL_RESULT_HR_IF_FAILED(EnsureProcessHasCapability(Capability::PackageManagement, callerProcessId)); 1127 callerProcessInfoString = TryGetCallerProcessInfo(callerProcessId); 1128 } 1129 WINGET_CATCH_STORE(hr, APPINSTALLER_CLI_ERROR_COMMAND_FAILED); 1130 WINGET_RETURN_INSTALL_RESULT_HR_IF_FAILED(hr); 1131 1132 return GetPackageOperation<Deployment::InstallResult, Deployment::InstallProgress, Deployment::InstallOptions, Deployment::PackageInstallProgressState>( 1133 true /*canCancelQueueItem*/, nullptr /*queueItem*/, package, options, std::move(callerProcessInfoString)); 1134 } 1135 1136 winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Microsoft::Management::Deployment::InstallResult, winrt::Microsoft::Management::Deployment::InstallProgress> PackageManager::UpgradePackageAsync(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::InstallOptions options) 1137 { 1138 hstring correlationData = (options) ? options.CorrelationData() : L""; 1139 1140 // options and catalog can both be null, package must be set. 1141 WINGET_RETURN_INSTALL_RESULT_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS, !package); 1142 // the package should have an installed version to be upgraded. 1143 WINGET_RETURN_INSTALL_RESULT_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS, !package.InstalledVersion()); 1144 1145 HRESULT hr = S_OK; 1146 std::wstring callerProcessInfoString; 1147 try 1148 { 1149 // Check for permissions and get caller info for telemetry. 1150 // This must be done before any co_awaits since it requires info from the rpc caller thread. 1151 auto [hrGetCallerId, callerProcessId] = GetCallerProcessId(); 1152 WINGET_RETURN_INSTALL_RESULT_HR_IF_FAILED(hrGetCallerId); 1153 WINGET_RETURN_INSTALL_RESULT_HR_IF_FAILED(EnsureProcessHasCapability(Capability::PackageManagement, callerProcessId)); 1154 callerProcessInfoString = TryGetCallerProcessInfo(callerProcessId); 1155 } 1156 WINGET_CATCH_STORE(hr, APPINSTALLER_CLI_ERROR_COMMAND_FAILED); 1157 WINGET_RETURN_INSTALL_RESULT_HR_IF_FAILED(hr); 1158 1159 return GetPackageOperation<Deployment::InstallResult, Deployment::InstallProgress, Deployment::InstallOptions, Deployment::PackageInstallProgressState>( 1160 true /*canCancelQueueItem*/, nullptr /*queueItem*/, package, options, std::move(callerProcessInfoString), true /* isUpgrade */); 1161 } 1162 1163 winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Microsoft::Management::Deployment::InstallResult, winrt::Microsoft::Management::Deployment::InstallProgress> PackageManager::GetInstallProgress(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::PackageCatalogInfo catalogInfo) 1164 { 1165 hstring correlationData; 1166 WINGET_RETURN_INSTALL_RESULT_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS, !package); 1167 1168 HRESULT hr = S_OK; 1169 std::shared_ptr<Execution::OrchestratorQueueItem> queueItem = nullptr; 1170 bool canCancelQueueItem = false; 1171 try 1172 { 1173 // Check for permissions 1174 // This must be done before any co_awaits since it requires info from the rpc caller thread. 1175 auto [hrGetCallerId, callerProcessId] = GetCallerProcessId(); 1176 WINGET_RETURN_INSTALL_RESULT_HR_IF_FAILED(hrGetCallerId); 1177 canCancelQueueItem = SUCCEEDED(EnsureProcessHasCapability(Capability::PackageManagement, callerProcessId)); 1178 if (!canCancelQueueItem) 1179 { 1180 WINGET_RETURN_INSTALL_RESULT_HR_IF_FAILED(EnsureProcessHasCapability(Capability::PackageQuery, callerProcessId)); 1181 } 1182 1183 // Get the queueItem synchronously. 1184 queueItem = GetExistingQueueItemForPackage(package, catalogInfo); 1185 if (queueItem == nullptr || 1186 (queueItem->GetPackageOperationType() != PackageOperationType::Install && queueItem->GetPackageOperationType() != PackageOperationType::Upgrade)) 1187 { 1188 return nullptr; 1189 } 1190 } 1191 WINGET_CATCH_STORE(hr, APPINSTALLER_CLI_ERROR_COMMAND_FAILED); 1192 WINGET_RETURN_INSTALL_RESULT_HR_IF_FAILED(hr); 1193 1194 return GetPackageOperation<Deployment::InstallResult, Deployment::InstallProgress, Deployment::InstallOptions, Deployment::PackageInstallProgressState>( 1195 canCancelQueueItem, std::move(queueItem)); 1196 } 1197 1198 #define WINGET_RETURN_UNINSTALL_RESULT_HR_IF(hr, boolVal) { if(boolVal) { return GetEmptyAsynchronousResultForOperation<Deployment::UninstallResult, Deployment::UninstallProgress>(hr, correlationData); }} 1199 #define WINGET_RETURN_UNINSTALL_RESULT_HR_IF_FAILED(hr) { WINGET_RETURN_UNINSTALL_RESULT_HR_IF(hr, FAILED(hr)) } 1200 1201 winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Microsoft::Management::Deployment::UninstallResult, winrt::Microsoft::Management::Deployment::UninstallProgress> PackageManager::UninstallPackageAsync(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::UninstallOptions options) 1202 { 1203 hstring correlationData = (options) ? options.CorrelationData() : L""; 1204 1205 // options and catalog can both be null, package must be set. 1206 WINGET_RETURN_UNINSTALL_RESULT_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS, !package); 1207 // the package should have an installed version to be uninstalled. 1208 WINGET_RETURN_UNINSTALL_RESULT_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS, !package.InstalledVersion()); 1209 1210 HRESULT hr = S_OK; 1211 std::wstring callerProcessInfoString; 1212 try 1213 { 1214 // Check for permissions and get caller info for telemetry. 1215 // This must be done before any co_awaits since it requires info from the rpc caller thread. 1216 auto [hrGetCallerId, callerProcessId] = GetCallerProcessId(); 1217 WINGET_RETURN_UNINSTALL_RESULT_HR_IF_FAILED(hrGetCallerId); 1218 WINGET_RETURN_UNINSTALL_RESULT_HR_IF_FAILED(EnsureProcessHasCapability(Capability::PackageManagement, callerProcessId)); 1219 callerProcessInfoString = TryGetCallerProcessInfo(callerProcessId); 1220 } 1221 WINGET_CATCH_STORE(hr, APPINSTALLER_CLI_ERROR_COMMAND_FAILED); 1222 WINGET_RETURN_UNINSTALL_RESULT_HR_IF_FAILED(hr); 1223 1224 return GetPackageOperation<Deployment::UninstallResult, Deployment::UninstallProgress, Deployment::UninstallOptions, Deployment::PackageUninstallProgressState>( 1225 true /*canCancelQueueItem*/, nullptr /*queueItem*/, package, options, std::move(callerProcessInfoString)); 1226 } 1227 1228 winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Microsoft::Management::Deployment::UninstallResult, winrt::Microsoft::Management::Deployment::UninstallProgress> PackageManager::GetUninstallProgress(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::PackageCatalogInfo catalogInfo) 1229 { 1230 hstring correlationData; 1231 WINGET_RETURN_UNINSTALL_RESULT_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS, !package); 1232 1233 HRESULT hr = S_OK; 1234 std::shared_ptr<Execution::OrchestratorQueueItem> queueItem = nullptr; 1235 bool canCancelQueueItem = false; 1236 try 1237 { 1238 // Check for permissions 1239 // This must be done before any co_awaits since it requires info from the rpc caller thread. 1240 auto [hrGetCallerId, callerProcessId] = GetCallerProcessId(); 1241 WINGET_RETURN_UNINSTALL_RESULT_HR_IF_FAILED(hrGetCallerId); 1242 canCancelQueueItem = SUCCEEDED(EnsureProcessHasCapability(Capability::PackageManagement, callerProcessId)); 1243 if (!canCancelQueueItem) 1244 { 1245 WINGET_RETURN_UNINSTALL_RESULT_HR_IF_FAILED(EnsureProcessHasCapability(Capability::PackageQuery, callerProcessId)); 1246 } 1247 1248 // Get the queueItem synchronously. 1249 queueItem = GetExistingQueueItemForPackage(package, catalogInfo); 1250 if (queueItem == nullptr || 1251 queueItem->GetPackageOperationType() != PackageOperationType::Uninstall) 1252 { 1253 return nullptr; 1254 } 1255 } 1256 WINGET_CATCH_STORE(hr, APPINSTALLER_CLI_ERROR_COMMAND_FAILED); 1257 WINGET_RETURN_UNINSTALL_RESULT_HR_IF_FAILED(hr); 1258 1259 return GetPackageOperation<Deployment::UninstallResult, Deployment::UninstallProgress, Deployment::UninstallOptions, Deployment::PackageUninstallProgressState>( 1260 canCancelQueueItem, std::move(queueItem)); 1261 } 1262 1263 #define WINGET_RETURN_DOWNLOAD_RESULT_HR_IF(hr, boolVal) { if(boolVal) { return GetEmptyAsynchronousResultForOperation<Deployment::DownloadResult, Deployment::PackageDownloadProgress>(hr, correlationData); }} 1264 #define WINGET_RETURN_DOWNLOAD_RESULT_HR_IF_FAILED(hr) { WINGET_RETURN_DOWNLOAD_RESULT_HR_IF(hr, FAILED(hr)) } 1265 1266 winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Microsoft::Management::Deployment::DownloadResult, winrt::Microsoft::Management::Deployment::PackageDownloadProgress> PackageManager::DownloadPackageAsync(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::DownloadOptions options) 1267 { 1268 hstring correlationData = (options) ? options.CorrelationData() : L""; 1269 1270 // options and catalog can both be null, package must be set. 1271 WINGET_RETURN_DOWNLOAD_RESULT_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS, !package); 1272 1273 HRESULT hr = S_OK; 1274 std::wstring callerProcessInfoString; 1275 try 1276 { 1277 // Check for permissions and get caller info for telemetry. 1278 // This must be done before any co_awaits since it requires info from the rpc caller thread. 1279 auto [hrGetCallerId, callerProcessId] = GetCallerProcessId(); 1280 WINGET_RETURN_DOWNLOAD_RESULT_HR_IF_FAILED(hrGetCallerId); 1281 WINGET_RETURN_DOWNLOAD_RESULT_HR_IF_FAILED(EnsureComCallerHasCapability(Capability::PackageQuery)); 1282 callerProcessInfoString = TryGetCallerProcessInfo(callerProcessId); 1283 } 1284 WINGET_CATCH_STORE(hr, APPINSTALLER_CLI_ERROR_COMMAND_FAILED); 1285 WINGET_RETURN_DOWNLOAD_RESULT_HR_IF_FAILED(hr); 1286 1287 return GetPackageOperation<Deployment::DownloadResult, Deployment::PackageDownloadProgress, Deployment::DownloadOptions, Deployment::PackageDownloadProgressState>( 1288 true /*canCancelQueueItem*/, nullptr /*queueItem*/, package, options, std::move(callerProcessInfoString)); 1289 } 1290 1291 winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Microsoft::Management::Deployment::DownloadResult, winrt::Microsoft::Management::Deployment::PackageDownloadProgress> PackageManager::GetDownloadProgress(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::PackageCatalogInfo catalogInfo) 1292 { 1293 hstring correlationData; 1294 WINGET_RETURN_DOWNLOAD_RESULT_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS, !package); 1295 1296 HRESULT hr = S_OK; 1297 std::shared_ptr<Execution::OrchestratorQueueItem> queueItem = nullptr; 1298 try 1299 { 1300 WINGET_RETURN_DOWNLOAD_RESULT_HR_IF_FAILED(EnsureComCallerHasCapability(Capability::PackageQuery)); 1301 1302 // Get the queueItem synchronously. 1303 queueItem = GetExistingQueueItemForPackage(package, catalogInfo); 1304 if (queueItem == nullptr || 1305 queueItem->GetPackageOperationType() != PackageOperationType::Download) 1306 { 1307 return nullptr; 1308 } 1309 } 1310 WINGET_CATCH_STORE(hr, APPINSTALLER_CLI_ERROR_COMMAND_FAILED); 1311 WINGET_RETURN_DOWNLOAD_RESULT_HR_IF_FAILED(hr); 1312 1313 return GetPackageOperation<Deployment::DownloadResult, Deployment::PackageDownloadProgress, Deployment::DownloadOptions, Deployment::PackageDownloadProgressState>(true, std::move(queueItem)); 1314 } 1315 1316 #define WINGET_RETURN_REPAIR_RESULT_HR_IF(hr, boolVal) { if(boolVal) { return GetEmptyAsynchronousResultForOperation<Deployment::RepairResult, Deployment::RepairProgress>(hr, correlationData); }} 1317 #define WINGET_RETURN_REPAIR_RESULT_HR_IF_FAILED(hr) { WINGET_RETURN_REPAIR_RESULT_HR_IF(hr, FAILED(hr)) } 1318 1319 winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Microsoft::Management::Deployment::RepairResult, winrt::Microsoft::Management::Deployment::RepairProgress> PackageManager::RepairPackageAsync(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::RepairOptions options) 1320 { 1321 hstring correlationData = (options) ? options.CorrelationData() : L""; 1322 1323 // options and catalog can both be null, package must be set. 1324 WINGET_RETURN_REPAIR_RESULT_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS, !package); 1325 // the package should have an installed version to be repaired. 1326 WINGET_RETURN_REPAIR_RESULT_HR_IF(APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS, !package.InstalledVersion()); 1327 1328 HRESULT hr = S_OK; 1329 std::wstring callerProcessInfoString; 1330 try 1331 { 1332 // Check for permissions and get caller info for telemetry. 1333 // This must be done before any co_awaits since it requires info from the rpc caller thread. 1334 auto [hrGetCallerId, callerProcessId] = GetCallerProcessId(); 1335 WINGET_RETURN_REPAIR_RESULT_HR_IF_FAILED(hrGetCallerId); 1336 WINGET_RETURN_REPAIR_RESULT_HR_IF_FAILED(EnsureProcessHasCapability(Capability::PackageManagement, callerProcessId)); 1337 callerProcessInfoString = TryGetCallerProcessInfo(callerProcessId); 1338 } 1339 WINGET_CATCH_STORE(hr, APPINSTALLER_CLI_ERROR_COMMAND_FAILED); 1340 WINGET_RETURN_REPAIR_RESULT_HR_IF_FAILED(hr); 1341 1342 return GetPackageOperation<Deployment::RepairResult, Deployment::RepairProgress, Deployment::RepairOptions, Deployment::PackageRepairProgressState>( 1343 true /*canCancelQueueItem*/, nullptr /*queueItem*/, package, options, std::move(callerProcessInfoString)); 1344 } 1345 1346 winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Microsoft::Management::Deployment::AddPackageCatalogResult, double> PackageManager::AddPackageCatalogAsync(winrt::Microsoft::Management::Deployment::AddPackageCatalogOptions options) 1347 { 1348 LogStartupIfApplicable(); 1349 1350 // options must be set. 1351 THROW_HR_IF_NULL(E_POINTER, options); 1352 THROW_HR_IF(E_INVALIDARG, options.Name().empty()); 1353 THROW_HR_IF(E_INVALIDARG, options.SourceUri().empty()); 1354 1355 HRESULT terminationHR = S_OK; 1356 try { 1357 1358 // Check if running as admin/system. 1359 // [NOTE:] For OutOfProc calls, the Windows Package Manager Service executes in the context initiated by the caller process, 1360 // so the same admin/system validation check is applicable for both InProc and OutOfProc calls. 1361 THROW_HR_IF(APPINSTALLER_CLI_ERROR_COMMAND_REQUIRES_ADMIN, !AppInstaller::Runtime::IsRunningAsAdminOrSystem()); 1362 1363 ::AppInstaller::Repository::Source sourceToAdd = CreateSourceFromOptions(options); 1364 1365 auto strong_this = get_strong(); 1366 auto report_progress{ co_await winrt::get_progress_token() }; 1367 co_await winrt::resume_background(); 1368 1369 std::string type = winrt::to_string(options.Type()); 1370 auto packageCatalogProgressSink = winrt::Microsoft::Management::Deployment::ProgressSinkFactory::CreatePackageCatalogProgressSink(type, report_progress ); 1371 1372 packageCatalogProgressSink->BeginProgress(); 1373 ::AppInstaller::ProgressCallback progress(packageCatalogProgressSink.get()); 1374 sourceToAdd.Add(progress); 1375 packageCatalogProgressSink->EndProgress(false); 1376 } 1377 catch (...) 1378 { 1379 terminationHR = AppInstaller::CLI::Workflow::HandleException(nullptr, std::current_exception()); 1380 } 1381 1382 co_return GetAddPackageCatalogResult(terminationHR); 1383 } 1384 1385 winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Microsoft::Management::Deployment::RemovePackageCatalogResult, double> PackageManager::RemovePackageCatalogAsync(winrt::Microsoft::Management::Deployment::RemovePackageCatalogOptions options) 1386 { 1387 LogStartupIfApplicable(); 1388 1389 // options must be set. 1390 THROW_HR_IF_NULL(E_POINTER, options); 1391 THROW_HR_IF(E_INVALIDARG, options.Name().empty()); 1392 1393 HRESULT terminationHR = S_OK; 1394 try { 1395 1396 // Check if running as admin/system. 1397 // [NOTE:] For OutOfProc calls, the Windows Package Manager Service executes in the context initiated by the caller process, 1398 // so the same admin/system validation check is applicable for both InProc and OutOfProc calls. 1399 THROW_HR_IF(APPINSTALLER_CLI_ERROR_COMMAND_REQUIRES_ADMIN, !AppInstaller::Runtime::IsRunningAsAdminOrSystem()); 1400 1401 auto matchingSource = GetMatchingSource(winrt::to_string(options.Name())); 1402 THROW_HR_IF(APPINSTALLER_CLI_ERROR_SOURCE_NAME_DOES_NOT_EXIST, !matchingSource.has_value()); 1403 1404 auto strong_this = get_strong(); 1405 auto report_progress{ co_await winrt::get_progress_token() }; 1406 co_await winrt::resume_background(); 1407 1408 auto packageCatalogProgressSink = winrt::Microsoft::Management::Deployment::ProgressSinkFactory::CreatePackageCatalogProgressSink(matchingSource.value().Type, report_progress, true); 1409 1410 packageCatalogProgressSink->BeginProgress(); 1411 ::AppInstaller::Repository::Source sourceToRemove = ::AppInstaller::Repository::Source{ matchingSource.value().Name }; 1412 ::AppInstaller::ProgressCallback progress(packageCatalogProgressSink.get()); 1413 1414 // If the PreserveData option is set, this is equivalent to the WinGet CLI Reset command on a single source; otherwise, it removes the source. 1415 if (options.PreserveData()) 1416 { 1417 THROW_HR_IF(APPINSTALLER_CLI_ERROR_SOURCE_NAME_DOES_NOT_EXIST, !sourceToRemove.DropSource(matchingSource.value().Name)); 1418 } 1419 else 1420 { 1421 sourceToRemove.Remove(progress); 1422 } 1423 packageCatalogProgressSink->EndProgress(false); 1424 } 1425 catch (...) 1426 { 1427 terminationHR = AppInstaller::CLI::Workflow::HandleException(nullptr, std::current_exception()); 1428 } 1429 1430 co_return GetRemovePackageCatalogResult(terminationHR); 1431 } 1432 1433 winrt::hstring PackageManager::Version() const 1434 { 1435 return winrt::hstring{ AppInstaller::Utility::ConvertToUTF16(AppInstaller::Runtime::GetClientVersion()) }; 1436 } 1437 1438 CoCreatableMicrosoftManagementDeploymentClass(PackageManager); 1439 }