winget-cli

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

commit e50438ea2d5b82fd8fbfa5b383a634e60dff8725
parent 8f653e0ccd0a290fd9be462a5a716a00a21ccaf6
Author: sreadingMSFT <74242768+sreadingMSFT@users.noreply.github.com>
Date:   Fri, 27 Aug 2021 09:59:17 -0700

Draft API proposal for #888 Support for UWP callers and a non command line interface API (#889)


Diffstat:
M.github/actions/spelling/allow.txt | 2++
M.github/actions/spelling/expect.txt | 1+
Adoc/specs/#888 - Com Api.md | 874+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 877 insertions(+), 0 deletions(-)

diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt @@ -461,6 +461,7 @@ Timeline todo tolower toupper +TOutput towlower TRACELOGGING triaged @@ -554,6 +555,7 @@ wstring wstringstream www xamarin +xaml XElement xlang xml diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt @@ -239,6 +239,7 @@ PMS positionals powertoys productcode +pseudocode pvk pvm pwabuilder diff --git a/doc/specs/#888 - Com Api.md b/doc/specs/#888 - Com Api.md @@ -0,0 +1,874 @@ +# 1. Background + +The Windows Package Manager currently exposes a command line interface to search for packages, +install them, view progress, and more. This API is designed to provide another way for callers to +make use of that functionality. The API will be preferred by callers that want to receive progress +and completion events, and UWP packages that do not have permission to launch command line processes. +The goal for this api is to provide the full set of install functionality possible using the Windows +Package Manager command line. The command line is documented at +https://docs.microsoft.com/en-us/windows/package-manager/winget/ + +# 2. Description + +Windows Package Manager is a package manager for windows applications. It comes with a predefined +repository of applications and users can add new repositories using the winget command line. This +API allows packaged apps with the packageManagement capability and other higher privilege processes +to start, manage, and monitor installation of packages that are listed in Windows Package Manager +repositories. + +# 3. Examples + +Sample member values for the following examples: +m_installAppId = L"Microsoft.VisualStudioCode"; + +## 3.1. Create objects + +Creation of objects has to be done through CoCreateInstance rather than normal winrt initialization +since it's hosted by an out of proc com server. These helper methods will be used in the rest of the +examples. + +```c++ (C++ish pseudocode) + AppInstaller CreateAppInstaller() { + return winrt::create_instance<AppInstaller>(CLSID_AppInstaller, CLSCTX_ALL); + } + InstallOptions CreateInstallOptions() { + return winrt::create_instance<InstallOptions>(CLSID_InstallOptions, CLSCTX_ALL); + } + FindPackagesOptions CreateFindPackagesOptions() { + return winrt::create_instance<FindPackagesOptions>(CLSID_FindPackagesOptions, CLSCTX_ALL); + } + CreateCompositeAppCatalogOptions CreateCreateCompositeAppCatalogOptions() { + return winrt::create_instance<CreateCompositeAppCatalogOptions>(CLSID_CreateCompositeAppCatalogOptions, CLSCTX_ALL); + } + PackageMatchFilter CreatePackageMatchFilter() { + return winrt::create_instance<PackageMatchFilter>(CLSID_PackageMatchFilter, CLSCTX_ALL); + } +``` + +## 3.2. Search + +The api can be used to search for packages in a catalog known to Windows Package Manager. This can +be used to get availability information or start an install. + +```c++ (C++ish pseudocode) + + // Sample of using synchronous methods on background thread. + CatalogPackage MainPage::FindPackageOnBackgroundThread() + { + PackageManager packageManager = CreatePackageManager(); + PackageCatalogReference catalogRef{ + packageManager.GetPredefinedPackageCatalog(PredefinedPackageCatalog::OpenWindowsCatalog) }; + ConnectResult connectResult = catalogRef.Connect(); + if (connectResult.Status() != ConnectResultStatus::Ok) + { + return nullptr; + } + PackageCatalog catalog = connectResult.PackageCatalog(); + + FindPackagesOptions findPackagesOptions = CreateFindPackagesOptions(); + PackageMatchFilter filter = CreatePackageMatchFilter(); + filter.Field(PackageMatchField::Id); + filter.Option(PackageFieldMatchOption::Equals); + filter.Value(m_installAppId); + findPackagesOptions.Filters().Append(filter); + // We've already switched to a background thread, so do everything synchronously. + FindPackagesResult findPackagesResult{ catalog.FindPackages(findPackagesOptions) }; + + winrt::IVectorView<MatchResult> matches = findPackagesResult.Matches(); + if (matches.Size() == 0) + { + return nullptr; + } + return matches.GetAt(0).CatalogPackage(); + } + + // Sample of using async methods. + IAsyncOperation<CatalogPackage> MainPage::FindPackageInCatalogAsync(PackageCatalog catalog, + std::wstring packageId) + { + FindPackagesOptions findPackagesOptions = CreateFindPackagesOptions(); + PackageMatchFilter filter = CreatePackageMatchFilter(); + filter.Field(PackageMatchField::Id); + filter.Option(PackageFieldMatchOption::Equals); + filter.Value(packageId); + findPackagesOptions.Filters().Append(filter); + FindPackagesResult findPackagesResult{ co_await catalog.FindPackagesAsync(findPackagesOptions) }; + + winrt::IVectorView<MatchResult> matches = findPackagesResult.Matches(); + if (matches.Size() == 0) + { + co_return nullptr; + } + co_return matches.GetAt(0).CatalogPackage(); + } + + IAsyncOperation<CatalogPackage> MainPage::FindPackageAsync() + { + PackageManager packageManager = CreatePackageManager(); + PackageCatalogReference catalogRef{ + packageManager.GetPredefinedPackageCatalog(PredefinedPackageCatalog::OpenWindowsCatalog) }; + ConnectResult connectResult = catalogRef.Connect(); + if (connectResult.Status() != ConnectResultStatus::Ok) + { + co_return nullptr; + } + PackageCatalog catalog = connectResult.PackageCatalog(); + co_return FindPackageInCatalogAsync(catalog, m_installAppId).get(); + } +``` + +## 3.3. Install + +```c++ (C++ish pseudocode) + + IAsyncOperationWithProgress<InstallResult, InstallProgress> MainPage::InstallPackage(CatalogPackage package) + { + PackageManager packageManager = CreatePackageManager(); + InstallOptions installOptions = CreateInstallOptions(); + installOptions.PackageInstallScope(PackageInstallScope::Any); + + return packageManager.InstallPackageAsync(package, installOptions); + } + + IAsyncAction UpdateUIProgress( + InstallProgress progress, + winrt::Windows::UI::Xaml::Controls::ProgressBar progressBar, + winrt::Windows::UI::Xaml::Controls::TextBlock statusText) + { + co_await winrt::resume_foreground(progressBar.Dispatcher()); + progressBar.Value(progress.DownloadProgress*100); + + std::wstring downloadText{ L"Downloading. " }; + switch (progress.State) + { + case PackageInstallProgressState::Queued: + statusText.Text(L"Queued"); + break; + case PackageInstallProgressState::Downloading: + downloadText += std::to_wstring(progress.BytesDownloaded) + L" bytes of " + std::to_wstring(progress.BytesRequired); + statusText.Text(downloadText); + break; + case PackageInstallProgressState::Installing: + statusText.Text(L"Installing"); + progressBar.IsIndeterminate(true); + break; + case PackageInstallProgressState::PostInstall: + statusText.Text(L"Finishing install"); + break; + case PackageInstallProgressState::Finished: + statusText.Text(L"Finished install."); + progressBar.IsIndeterminate(false); + break; + default: + statusText.Text(L""); + } + co_return; + } + + // This method is called from a background thread. + IAsyncAction UpdateUIForInstall( + IAsyncOperationWithProgress<InstallResult, InstallProgress> installPackageOperation, + winrt::Windows::UI::Xaml::Controls::Button installButton, + winrt::Windows::UI::Xaml::Controls::Button cancelButton, + winrt::Windows::UI::Xaml::Controls::ProgressBar progressBar, + winrt::Windows::UI::Xaml::Controls::TextBlock statusText) + { + if (installPackageOperation) + { + + installPackageOperation.Progress([=]( + IAsyncOperationWithProgress<InstallResult, InstallProgress> const& /* sender */, + InstallProgress const& progress) + { + UpdateUIProgress(progressBar, statusText, 50, stateStr).get(); + }); + + + winrt::hresult installOperationHr = S_OK; + std::wstring errorMessage{ L"Unknown Error" }; + InstallResult installResult{ nullptr }; + try + { + installResult = co_await installPackageOperation; + } + catch (hresult_canceled const&) + { + errorMessage = L"Cancelled"; + OutputDebugString(L"Operation was cancelled"); + } + catch (...) + { + // Operation failed + // Example: HRESULT_FROM_WIN32(ERROR_DISK_FULL). + installOperationHr = winrt::to_hresult(); + // Example: "There is not enough space on the disk." + errorMessage = winrt::to_message(); + OutputDebugString(L"Operation failed"); + } + + // Switch back to ui thread context. + co_await winrt::resume_foreground(progressBar.Dispatcher()); + + cancelButton.IsEnabled(false); + installButton.IsEnabled(true); + progressBar.IsIndeterminate(false); + + if (installPackageOperation.Status() == AsyncStatus::Canceled) + { + installButton.Content(box_value(L"Retry")); + statusText.Text(L"Install cancelled."); + } + if (installPackageOperation.Status() == AsyncStatus::Error || installResult == nullptr) + { + installButton.Content(box_value(L"Retry")); + statusText.Text(errorMessage); + } + else if (installResult.RebootRequired()) + { + installButton.Content(box_value(L"Install")); + statusText.Text(L"Reboot to finish installation."); + } + else if (installResult.Status() == InstallResultStatus::Ok) + { + installButton.Content(box_value(L"Install")); + statusText.Text(L"Finished."); + } + else + { + installButton.Content(box_value(L"Install")); + statusText.Text(L"Install failed."); + } + } + } + + IAsyncAction MainPage::StartInstall( + winrt::Windows::UI::Xaml::Controls::Button installButton, + winrt::Windows::UI::Xaml::Controls::Button cancelButton, + winrt::Windows::UI::Xaml::Controls::ProgressBar progressBar, + winrt::Windows::UI::Xaml::Controls::TextBlock statusText) + { + installButton.IsEnabled(false); + cancelButton.IsEnabled(true); + + co_await winrt::resume_background(); + + PackageManager packageManager = CreatePackageManager(); + PackageCatalogReference catalogRef{ + packageManager.GetPredefinedPackageCatalog(PredefinedPackageCatalog::OpenWindowsCatalog) }; + ConnectResult connectResult = catalogRef.Connect(); + if (connectResult.Status() != ConnectResultStatus::Ok) + { + co_await winrt::resume_foreground(progressBar.Dispatcher()); + statusText.Text(L"Connecting to catalog failed."); + co_return; + } + PackageCatalog catalog = connectResult.PackageCatalog(); + + FindPackagesResult findPackagesResult{ FindPackageOnBackgroundThread(catalog, m_installAppId) }; + + winrt::IVectorView<MatchResult> matches = findPackagesResult.Matches(); + if (matches.Size() > 0) + { + m_installPackageOperation = InstallPackage(matches.GetAt(0).CatalogPackage()); + UpdateUIForInstall(m_installPackageOperation, installButton, cancelButton, progressBar, statusText); + } + else + { + co_await winrt::resume_foreground(progressBar.Dispatcher()); + statusText.Text(L"Could not find package."); + co_return; + } + } +``` + +## 3.4.1 Cancel + +The async operation can be stored, or the install code can wait on an event that can be triggered. + +```c++ (C++ish pseudocode) + void MainPage::CancelButtonClickHandler(IInspectable const&, RoutedEventArgs const&) + { + if (m_installPackageOperation) + { + m_installPackageOperation.Cancel(); + } + } +``` + +## 3.5. Open a catalog by name + +Open a catalog known to the caller. There is no way to use the api to add a catalog, that must be done +on the command line. + +```c++ (C++ish pseudocode) + IAsyncOperation<PackageCatalog> MainPage::FindSourceAsync(std::wstring packageSource) + { + PackageManager packageManager = CreatePackageManager(); + PackageCatalogReference catalogRef{ packageManager.GetPackageCatalogByName(packageSource) }; + if (catalogRef) + { + ConnectResult connectResult{ co_await catalogRef.ConnectAsync() }; + // PackageCatalog will be null if connectResult.ErrorCode() is a failure + PackageCatalog catalog = connectResult.PackageCatalog(); + co_return catalog; + } + } +``` + +# 4 Remarks + +Notes have been added inline throughout the api details. + + +For this api there are multiple similar apis that are +relevant with regard to naming and consistency. There is the Windows Package Manager command line which uses +"source" to describe the various repositories that can host packages and "search" to describe looking up an app. +https://docs.microsoft.com/en-us/windows/package-manager/winget/ +There is the Windows::ApplicationModel::PackageCatalog which exists as a Windows API for installing packages +and monitoring their installation progress. +https://docs.microsoft.com/en-us/uwp/api/windows.applicationmodel.packagecatalog?view=winrt-19041 +And there is Windows.Management.Deployment.PackageManager which allows packages with the packageManagement +capability to install msix apps and uses "Find" to describe looking up an app +https://docs.microsoft.com/en-us/uwp/api/windows.management.deployment.packagemanager?view=winrt-19041 + +This API has aligned with those Windows APIs in using \*Catalog and Find. + +# 5 API Details + +```c# (but really MIDL3) +namespace Microsoft.Management.Deployment +{ + [contractversion(1)] + apicontract WindowsPackageManagerContract{}; + + /// State of the install. + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + enum PackageInstallProgressState + { + /// The install is queued but not yet active. Cancellation of the IAsyncOperationWithProgress in this + /// state will prevent the package from downloading or installing. + Queued, + /// The installer is downloading. Cancellation of the IAsyncOperationWithProgress in this state will + /// end the download and prevent the package from installing. + Downloading, + /// The install is in progress. Cancellation of the IAsyncOperationWithProgress in this state will not + /// stop the installation or the post install cleanup. + Installing, + /// The installer has completed and cleanup actions are in progress. Cancellation of the + /// IAsyncOperationWithProgress in this state will not stop cleanup or roll back the install. + PostInstall, + /// The operation has completed. + Finished, + }; + + /// Progress object for the install + /// DESIGN NOTE: percentage for the install as a whole is purposefully not included as there is no way to + /// estimate progress when the installer is running. + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + struct InstallProgress + { + /// State of the install + PackageInstallProgressState State; + /// DESIGN NOTE: BytesDownloaded may only be available for downloads done by Windows Package Manager itself. + /// Number of bytes downloaded if known + UInt64 BytesDownloaded; + /// DESIGN NOTE: BytesRequired may only be available for downloads done by Windows Package Manager itself. + /// Number of bytes required if known + UInt64 BytesRequired; + /// Download percentage completed + Double DownloadProgress; + /// Install percentage if known. + Double InstallationProgress; + }; + + /// Status of the Install call + /// Implementation Note: Errors mapped from AppInstallerErrors.h + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + enum InstallResultStatus + { + Ok, + BlockedByPolicy, + CatalogError, + InternalError, + InvalidOptions, + DownloadError, + InstallError, + ManifestError, + NoApplicableInstallers, + }; + + /// Result of the install + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + runtimeclass InstallResult + { + /// Used by a caller to correlate the install with a caller's data. + String CorrelationData{ get; }; + /// Whether a restart is required to complete the install. + Boolean RebootRequired{ get; }; + + /// Batched error code, example APPINSTALLER_CLI_ERROR_SHELLEXEC_INSTALL_FAILED + InstallResultStatus Status{ get; }; + /// Specific error if known, from downloader or installer itself, example ERROR_INSTALL_PACKAGE_REJECTED + HRESULT ExtendedErrorCode{ get; }; + } + + /// IMPLEMENTATION NOTE: SourceOrigin from AppInstallerRepositorySource.h + /// Defines the origin of the package catalog details. + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + enum PackageCatalogOrigin + { + /// Predefined means it came as part of the Windows Package Manager package and cannot be removed. + Predefined, + /// User means it was added by the user and could be removed. + User, + }; + + /// IMPLEMENTATION NOTE: SourceTrustLevel from AppInstallerRepositorySource.h + /// Defines the trust level of the package catalog. + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + enum PackageCatalogTrustLevel + { + None, + Trusted, + }; + + /// IMPLEMENTATION NOTE: SourceDetails from AppInstallerRepositorySource.h + /// Interface for retrieving information about an package catalog without acting on it. + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + runtimeclass PackageCatalogInfo + { + /// The package catalog's unique identifier. + /// SAMPLE VALUES: For OpenWindowsCatalog "Microsoft.Winget.Source_8wekyb3d8bbwe" + /// For contoso sample on msdn "contoso" + String Id { get; }; + /// The name of the package catalog. + /// SAMPLE VALUES: For OpenWindowsCatalog "winget". + /// For contoso sample on msdn "contoso" + String Name { get; }; + /// The type of the package catalog. + /// ALLOWED VALUES: "Microsoft.Rest", "Microsoft.PreIndexed.Package" + /// SAMPLE VALUES: For OpenWindowsCatalog "Microsoft.PreIndexed.Package". + /// For contoso sample on msdn "Microsoft.PreIndexed.Package" + String Type { get; }; + /// The argument used when adding the package catalog. + /// SAMPLE VALUES: For OpenWindowsCatalog "https://winget.azureedge.net/cache" + /// For contoso sample on msdn "https://pkgmgr-int.azureedge.net/cache" + String Argument { get; }; + /// The last time that this package catalog was updated. + Windows.Foundation.DateTime LastUpdateTime { get; }; + /// The origin of the package catalog. + PackageCatalogOrigin Origin { get; }; + /// The trust level of the package catalog + PackageCatalogTrustLevel TrustLevel { get; }; + } + + /// A metadata item of a package version. + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + enum PackageVersionMetadataField + { + /// The InstallerType of an installed package + InstallerType, + /// The Scope of an installed package + InstalledScope, + /// The system path where the package is installed + InstalledLocation, + /// The standard uninstall command; which may be interactive + StandardUninstallCommand, + /// An uninstall command that should be non-interactive + SilentUninstallCommand, + /// The publisher of the package + PublisherDisplayName, + }; + + /// IMPLEMENTATION NOTE: IPackageVersion from AppInstallerRepositorySearch.h + /// A single package version. + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + runtimeclass PackageVersionInfo + { + /// IMPLEMENTATION NOTE: PackageVersionMetadata fields from AppInstallerRepositorySearch.h + /// Gets any metadata associated with this package version. + /// Primarily stores data on installed packages. + /// Metadata fields may have no value (e.g. packages that aren't installed will not have an InstalledLocation). + String GetMetadata(PackageVersionMetadataField metadataField); + /// IMPLEMENTATION NOTE: PackageVersionProperty fields from AppInstallerRepositorySearch.h + String Id { get; }; + String DisplayName { get; }; + String Version { get; }; + String Channel { get; }; + /// DESIGN NOTE: RelativePath from AppInstallerRepositorySearch.h is excluded as not needed. + /// String RelativePath; + + /// IMPLEMENTATION NOTE: PackageVersionMultiProperty fields from AppInstallerRepositorySearch.h + /// PackageFamilyName and ProductCode can have multiple values. + Windows.Foundation.Collections.IVectorView<String> PackageFamilyNames { get; }; + Windows.Foundation.Collections.IVectorView<String> ProductCodes { get; }; + + /// Gets the package catalog where this package version is from. + PackageCatalog PackageCatalog { get; }; + + /// DESIGN NOTE: + /// GetManifest from IPackageVersion in AppInstallerRepositorySearch is not implemented in V1. That class has + /// a lot of fields and no one requesting it. + /// Gets the manifest of this package version. + /// virtual Manifest::Manifest GetManifest() = 0; + } + + /// IMPLEMENTATION NOTE: PackageVersionKey from AppInstallerRepositorySearch.h + /// A key to identify a package version within a package. + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + runtimeclass PackageVersionId + { + /// The package catalog id that this version came from. + String PackageCatalogId { get; }; + /// The version. + String Version { get; }; + /// The channel. + String Channel { get; }; + }; + + /// IMPLEMENTATION NOTE: IPackage from AppInstallerRepositorySearch.h + /// A package, potentially containing information about it's local state and the available versions. + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + runtimeclass CatalogPackage + { + /// IMPLEMENTATION NOTE: PackageProperty fields from AppInstallerRepositorySearch.h + /// Gets a property of this package. + String Id { get; }; + String Name { get; }; + + /// Gets the installed package information if the package is installed. + PackageVersionInfo InstalledVersion{ get; }; + + /// Gets all available versions of this package. Ordering is not guaranteed. + Windows.Foundation.Collections.IVectorView<PackageVersionId> AvailableVersions { get; }; + + /// Gets the version of this package that will be installed if version is not set in InstallOptions. + PackageVersionInfo DefaultInstallVersion { get; }; + + /// Gets a specific version of this package. + PackageVersionInfo GetPackageVersionInfo(PackageVersionId versionKey); + + /// Gets a value indicating whether an available version is newer than the installed version. + Boolean IsUpdateAvailable { get; }; + + /// DESIGN NOTE: + /// IsSame from IPackage in AppInstallerRepositorySearch is not implemented in V1. + /// Determines if the given IPackage refers to the same package as this one. + /// virtual bool IsSame(const IPackage*) const = 0; + } + + /// IMPLEMENTATION NOTE: CompositeSearchBehavior from AppInstallerRepositorySource.h + /// Search behavior for composite catalogs. + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + enum CompositeSearchBehavior + { + /// Search local catalogs only + LocalCatalogs, + /// Search remote catalogs only, don't check local catalogs for InstalledVersion + RemotePackagesFromRemoteCatalogs, + /// Search remote catalogs, and check local catalogs for InstalledVersion + RemotePackagesFromAllCatalogs, + /// Search both local and remote catalogs. + AllCatalogs, + }; + + /// IMPLEMENTATION NOTE: PackageFieldMatchOption from AppInstallerRepositorySearch.h + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + enum PackageFieldMatchOption + { + Equals, + EqualsCaseInsensitive, + StartsWithCaseInsensitive, + ContainsCaseInsensitive, + }; + + /// IMPLEMENTATION NOTE: PackageFieldMatchOption from AppInstallerRepositorySearch.h + /// The field to match on. + /// The values must be declared in order of preference in search results. + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + enum PackageMatchField + { + CatalogDefault, + Id, + Name, + Moniker, + Command, + Tag, + /// DESIGN NOTE: The following PackageFieldMatchOption from AppInstallerRepositorySearch.h are not implemented in V1. + /// PackageFamilyName, + /// ProductCode, + /// NormalizedNameAndPublisher, + }; + + /// IMPLEMENTATION NOTE: PackageMatchFilter from AppInstallerRepositorySearch.h + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + runtimeclass PackageMatchFilter + { + PackageMatchFilter(); + /// The type of string comparison for matching + PackageFieldMatchOption Option; + /// The field to search + PackageMatchField Field; + /// The value to match + String Value; + /// DESIGN NOTE: "Additional" from RequestMatch AppInstallerRepositorySearch.h is not implemented here. + } + + /// IMPLEMENTATION NOTE: MatchResult from AppInstallerRepositorySearch.h + /// A single result from the search. + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + runtimeclass MatchResult + { + /// The package found by the search request. + CatalogPackage CatalogPackage { get; }; + + /// The highest order field on which the package matched the search. + PackageMatchFilter MatchCriteria { get; }; + } + + /// Status of the FindPackages call + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + enum FindPackagesResultStatus + { + Ok, + BlockedByPolicy, + CatalogError, + InternalError, + InvalidOptions + }; + + /// IMPLEMENTATION NOTE: SearchResult from AppInstallerRepositorySearch.h + /// Search result data returned from FindPackages + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + runtimeclass FindPackagesResult + { + /// Error codes + FindPackagesResultStatus Status{ get; }; + + /// The full set of results from the search. + Windows.Foundation.Collections.IVectorView<MatchResult> Matches { get; }; + + /// If true, the results were truncated by the given ResultLimit + /// USAGE NOTE: Windows Package Manager does not support result pagination, there is no way to continue + /// getting more results. + Boolean WasLimitExceeded{ get; }; + } + + /// Options for FindPackages + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + runtimeclass FindPackagesOptions + { + FindPackagesOptions(); + + /// DESIGN NOTE: + /// This class maps to SearchRequest from AppInstallerRepositorySearch.h + /// That class is a container for data used to filter the available manifests in an package catalog. + /// Its properties can be thought of as: + /// (Query || Selectors...) && Filters... + /// If Query and Selectors are both empty, the starting data set will be the entire database. + /// Everything && Filters... + /// Query is PackageMatchField::CatalogDefault and in the Selector list. + /// USAGE NOTE: Only one selector with PackageMatchField::CatalogDefault is allowed. + + /// Selectors = you have to match at least one selector (if there are no selectors, then nothing is selected) + Windows.Foundation.Collections.IVector<PackageMatchFilter> Selectors { get; }; + /// Filters = you have to match all filters(if there are no filters, then there is no filtering of selected items) + Windows.Foundation.Collections.IVector<PackageMatchFilter> Filters{ get; }; + + /// Restricts the length of the returned results to the specified count. + UInt32 ResultLimit; + } + + /// IMPLEMENTATION NOTE: ISource from AppInstallerRepositorySource.h + /// A catalog for searching for packages + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + runtimeclass PackageCatalog + { + /// Gets a value indicating whether this package catalog is a composite of other package catalogs, + /// and thus the packages may come from disparate package catalogs as well. + Boolean IsComposite { get; }; + /// The details of the package catalog if it is not a composite. + PackageCatalogInfo Info { get; }; + + /// Searches for Packages in the catalog. + Windows.Foundation.IAsyncOperation<FindPackagesResult> FindPackagesAsync(FindPackagesOptions options); + FindPackagesResult FindPackages(FindPackagesOptions options); + } + + /// Status of the Connect call + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + enum ConnectResultStatus + { + Ok, + CatalogError, + }; + + /// Result of the Connect call + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + runtimeclass ConnectResult + { + /// Error codes + ConnectResultStatus Status{ get; }; + + PackageCatalog PackageCatalog { get; }; + } + + /// A reference to a catalog that callers can try to Connect. + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + runtimeclass PackageCatalogReference + { + /// Gets a value indicating whether this package catalog is a composite of other package catalogs, + /// and thus the packages may come from disparate package catalogs as well. + Boolean IsComposite { get; }; + /// The details of the package catalog if it is not a composite. + PackageCatalogInfo Info { get; }; + + /// Opens a catalog. Required before searching. For remote catalogs (i.e. not Installed and Installing) this + /// may require downloading information from a server. + Windows.Foundation.IAsyncOperation<ConnectResult> ConnectAsync(); + ConnectResult Connect(); + } + + /// Catalogs with PackageCatalogOrigin Predefined + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + enum PredefinedPackageCatalog + { + OpenWindowsCatalog, + }; + + /// Local Catalogs with PackageCatalogOrigin Predefined + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + enum LocalPackageCatalog + { + InstalledPackages, + }; + + /// Options for creating a composite catalog. + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + runtimeclass CreateCompositePackageCatalogOptions + { + CreateCompositePackageCatalogOptions(); + + /// Create a composite catalog to allow searching a user defined or pre defined source + /// and a local source (Installed packages) together + IVector<PackageCatalogReference> Catalogs { get; }; + /// Sets the default search behavior if the catalog is a composite catalog. + CompositeSearchBehavior CompositeSearchBehavior; + } + + /// Required install scope for the package. If the package does not have an installer that + /// supports the specified scope the Install call will fail with InstallResultStatus.NoApplicableInstallers + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + enum PackageInstallScope + { + /// An installer with any install scope is valid. + Any, + /// Only User install scope installers are valid + User, + /// Only System installers will be valid + System, + }; + + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + enum PackageInstallMode + { + /// The default experience for the installer. Installer may show some UI. + Default, + /// Runs the installer in silent mode. This suppresses the installer's UI to the extent + /// possible (installer may still show some required UI). + Silent, + /// Runs the installer in interactive mode. + Interactive, + }; + + /// Options when installing a package. + /// Intended to allow full compatibility with the "winget install" command line interface. + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + runtimeclass InstallOptions + { + InstallOptions(); + + /// Optionally specifies the version from the package to install. If unspecified the version matching + /// CatalogPackage.GetLatestVersion() is used. + PackageVersionId PackageVersionId; + + /// Specifies alternate location to install package (if supported). + String PreferredInstallLocation; + /// User or Machine. + PackageInstallScope PackageInstallScope; + /// Silent, Interactive, or Default + PackageInstallMode PackageInstallMode; + /// Directs the logging to a log file. If provided, the installer must have have write access to the file + String LogOutputPath; + /// Continues the install even if the hash in the catalog does not match the linked installer. + Boolean AllowHashMismatch; + /// A string that will be passed to the installer. + /// IMPLEMENTATION NOTE: maps to "--override" in the winget cmd line + String ReplacementInstallerArguments; + + /// Used by a caller to correlate the install with a caller's data. + /// The string must be JSON encoded. + String CorrelationData; + /// A string that will be passed to the source server if using a REST source + String AdditionalPackageCatalogArguments; + } + + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] + runtimeclass PackageManager + { + PackageManager(); + + /// Get the available catalogs. Each source will have a separate catalog. + /// This does not open the catalog. These catalogs can be used individually or merged with CreateCompositePackageCatalogAsync. + /// IMPLEMENTATION NOTE: This is a list of sources returned by Windows Package Manager source list + Windows.Foundation.Collections.IVectorView<PackageCatalogReference> GetPackageCatalogs(); + /// Get a built in catalog + PackageCatalogReference GetPredefinedPackageCatalog(PredefinedPackageCatalog predefinedPackageCatalog); + /// Get a built in catalog + PackageCatalogReference GetLocalPackageCatalog(LocalPackageCatalog localPackageCatalog); + /// Get a catalog by a known name + PackageCatalogReference GetPackageCatalogByName(String catalogName); + /// Get a composite catalog to allow searching a user defined or pre defined source and a local source + /// (Installing, Installed) together at the same time. + PackageCatalogReference CreateCompositePackageCatalog(CreateCompositePackageCatalogOptions options); + + /// Install the specified package + Windows.Foundation.IAsyncOperationWithProgress<InstallResult, InstallProgress> InstallPackageAsync(CatalogPackage package, InstallOptions options); + } + + /// Force midl3 to generate vector marshalling info. + declare + { + interface Windows.Foundation.Collections.IVector<PackageCatalog>; + interface Windows.Foundation.Collections.IVectorView<PackageCatalog>; + interface Windows.Foundation.Collections.IVector<PackageCatalogInfo>; + interface Windows.Foundation.Collections.IVectorView<PackageCatalogInfo>; + interface Windows.Foundation.Collections.IVector<PackageCatalogReference>; + interface Windows.Foundation.Collections.IVectorView<PackageCatalogReference>; + interface Windows.Foundation.Collections.IVector<CatalogPackage>; + interface Windows.Foundation.Collections.IVectorView<CatalogPackage>; + interface Windows.Foundation.Collections.IVector<FindPackagesOptions>; + interface Windows.Foundation.Collections.IVectorView<FindPackagesOptions>; + interface Windows.Foundation.Collections.IVector<FindPackagesResult>; + interface Windows.Foundation.Collections.IVectorView<FindPackagesResult>; + interface Windows.Foundation.Collections.IVector<CreateCompositePackageCatalogOptions>; + interface Windows.Foundation.Collections.IVectorView<CreateCompositePackageCatalogOptions>; + interface Windows.Foundation.Collections.IVector<InstallOptions>; + interface Windows.Foundation.Collections.IVectorView<InstallOptions>; + interface Windows.Foundation.Collections.IVector<InstallResult>; + interface Windows.Foundation.Collections.IVectorView<InstallResult>; + interface Windows.Foundation.Collections.IVector<MatchResult>; + interface Windows.Foundation.Collections.IVectorView<MatchResult>; + interface Windows.Foundation.Collections.IVector<PackageManager>; + interface Windows.Foundation.Collections.IVectorView<PackageManager>; + interface Windows.Foundation.Collections.IVector<PackageMatchFilter>; + interface Windows.Foundation.Collections.IVectorView<PackageMatchFilter>; + interface Windows.Foundation.Collections.IVector<PackageVersionId>; + interface Windows.Foundation.Collections.IVectorView<PackageVersionId>; + interface Windows.Foundation.Collections.IVector<PackageVersionInfo>; + interface Windows.Foundation.Collections.IVectorView<PackageVersionInfo>; + } +} +``` + +# Appendix