winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }