From f9266401edb631f6c41d51d81dfa61e1cc25f9f4 Mon Sep 17 00:00:00 2001
From: Madhusudhan-MSFT <53235553+Madhusudhan-MSFT@users.noreply.github.com>
Date: Mon, 28 Oct 2024 10:26:20 -0700
Subject: [PATCH] WinGet Source COM Api (#4813)
WinGet Source COM API Support
### This update includes the following changes:
1. Implementation of WinGet COM Package Catalog Management APIs:
- PackageManager.AddPackageCatalogAsync: Allows adding a new Package
Catalog repository to the Windows Package Manager access list.
Administrative rights are required to execute this API..
- PackageManager.RemovePackageCatalogAsync: Enables the removal of an
existing Package Catalog from the Windows Package Manager access list.
Administrative rights are required to execute this API.
- By default, the 'PreserveData' field is set to false, removing both
the PackageCatalog registration data and system artifacts.
- When 'PreserveData' is set to true, only the PackageCatalog
registration data is removed, while system artifacts remain.
- PackageCatalogReference.RefreshPackageCatalogAsync: Allows updating an
existing Package Catalog repository.
2. Necessary C# WinRT Projection to invoke the above API calls from the
test classes.
3. PackageCatalogInterop E2E Inproc and OutOfproc Test Cases to
validate:
- AddPackageCatalogAsync
- RemovePackageCatalogAsync
- RefreshPackageCatalogAsync
4. Added a CallbackDispatcherSink struct that handles and dispatches
progress callbacks for the scenario described above, ensuring progress
is reported to the caller.
5. Updated Package.appxmanifest and
Microsoft.Management.Deployment.InProc.dll.manifest to include the
necessary COM RuntimeClass CLSIDs related to the aforementioned APIs
### How Validated:
1. Compiled AppInstaller.sln
2. Deployed AppInstallerCLIPackage
3. Copied Microsoft.Management.Deployment.winmd next to dot.exe process
that runs test cases
4. Executed InProc tests locally and verified all tests pass.
![image](https://github.com/user-attachments/assets/1c677b85-6610-4b52-bf34-d784ba86d9db)
related: #4170
- [x] I have signed the [Contributor License
Agreement](https://cla.opensource.microsoft.com/microsoft/winget-pkgs).
- [x] This pull request is related to an issue.
-----
###### Microsoft Reviewers: [Open in
CodeFlow](https://microsoft.github.io/open-pr/?codeflow=https://github.com/microsoft/winget-cli/pull/4813)
---
.../Interop/GroupPolicyForInterop.cs | 78 +++++
.../Interop/PackageCatalogInterop.cs | 328 ++++++++++++++++++
.../Package.appxmanifest | 4 +
.../Public/AppInstallerProgress.h | 2 +-
.../Public/winget/Runtime.h | 3 +
src/AppInstallerSharedLib/Runtime.cpp | 5 +
....Management.Deployment.InProc.dll.manifest | 8 +
.../Factory.cpp | 11 +-
.../ClassesDefinition.cs | 24 ++
.../WinGetProjectionFactory.cs | 6 +-
.../AddPackageCatalogOptions.cpp | 66 ++++
.../AddPackageCatalogOptions.h | 51 +++
.../AddPackageCatalogResult.cpp | 25 ++
.../AddPackageCatalogResult.h | 28 ++
.../ComClsids.cpp | 12 +-
.../Converters.cpp | 31 ++
.../Converters.h | 57 +++
.../Microsoft.Management.Deployment.vcxproj | 12 +
...soft.Management.Deployment.vcxproj.filters | 12 +
.../PackageCatalogProgress.cpp | 157 +++++++++
.../PackageCatalogProgress.h | 73 ++++
.../PackageCatalogReference.cpp | 39 +++
.../PackageCatalogReference.h | 4 +-
.../PackageManager.cpp | 181 +++++++++-
.../PackageManager.h | 5 +
.../PackageManager.idl | 139 +++++++-
.../Public/ComClsids.h | 6 +
.../RefreshPackageCatalogResult.cpp | 27 ++
.../RefreshPackageCatalogResult.h | 27 ++
.../RemovePackageCatalogOptions.cpp | 35 ++
.../RemovePackageCatalogOptions.h | 35 ++
.../RemovePackageCatalogResult.cpp | 25 ++
.../RemovePackageCatalogResult.h | 27 ++
.../RepairOptions.h | 2 +-
src/WindowsPackageManager/main.cpp | 2 +
35 files changed, 1538 insertions(+), 9 deletions(-)
create mode 100644 src/AppInstallerCLIE2ETests/Interop/PackageCatalogInterop.cs
create mode 100644 src/Microsoft.Management.Deployment/AddPackageCatalogOptions.cpp
create mode 100644 src/Microsoft.Management.Deployment/AddPackageCatalogOptions.h
create mode 100644 src/Microsoft.Management.Deployment/AddPackageCatalogResult.cpp
create mode 100644 src/Microsoft.Management.Deployment/AddPackageCatalogResult.h
create mode 100644 src/Microsoft.Management.Deployment/PackageCatalogProgress.cpp
create mode 100644 src/Microsoft.Management.Deployment/PackageCatalogProgress.h
create mode 100644 src/Microsoft.Management.Deployment/RefreshPackageCatalogResult.cpp
create mode 100644 src/Microsoft.Management.Deployment/RefreshPackageCatalogResult.h
create mode 100644 src/Microsoft.Management.Deployment/RemovePackageCatalogOptions.cpp
create mode 100644 src/Microsoft.Management.Deployment/RemovePackageCatalogOptions.h
create mode 100644 src/Microsoft.Management.Deployment/RemovePackageCatalogResult.cpp
create mode 100644 src/Microsoft.Management.Deployment/RemovePackageCatalogResult.h
diff --git a/src/AppInstallerCLIE2ETests/Interop/GroupPolicyForInterop.cs b/src/AppInstallerCLIE2ETests/Interop/GroupPolicyForInterop.cs
index 45f34a91d3..e86e27beca 100644
--- a/src/AppInstallerCLIE2ETests/Interop/GroupPolicyForInterop.cs
+++ b/src/AppInstallerCLIE2ETests/Interop/GroupPolicyForInterop.cs
@@ -9,6 +9,7 @@ namespace AppInstallerCLIE2ETests.Interop
using System;
using System.IO;
using System.Text;
+ using System.Threading;
using System.Threading.Tasks;
using AppInstallerCLIE2ETests.Helpers;
using Microsoft.Management.Deployment;
@@ -51,6 +52,16 @@ public void CleanUp()
GroupPolicyHelper.DeleteExistingPolicies();
}
+ ///
+ /// Test class Tear down.
+ ///
+ [OneTimeTearDown]
+ public void TestClassTearDown()
+ {
+ // Restore the tests source if it was removed as the affects subsequent tests.
+ TestCommon.SetupTestSource();
+ }
+
///
/// Validates disabling WinGetPolicy should block COM/WinRT Objects creation (InProcess and OutOfProcess).
///
@@ -91,6 +102,14 @@ public void DisableWinGetPolicy()
Assert.AreEqual(Constants.BlockByWinGetPolicyErrorMessage, groupPolicyException.Message);
Assert.AreEqual(Constants.ErrorCode.ERROR_BLOCKED_BY_POLICY, groupPolicyException.HResult);
+ groupPolicyException = Assert.Catch(() => { AddPackageCatalogOptions packageManagerSettings = this.TestFactory.CreateAddPackageCatalogOptions(); });
+ Assert.AreEqual(Constants.BlockByWinGetPolicyErrorMessage, groupPolicyException.Message);
+ Assert.AreEqual(Constants.ErrorCode.ERROR_BLOCKED_BY_POLICY, groupPolicyException.HResult);
+
+ groupPolicyException = Assert.Catch(() => { RemovePackageCatalogOptions packageManagerSettings = this.TestFactory.CreateRemovePackageCatalogOptions(); });
+ Assert.AreEqual(Constants.BlockByWinGetPolicyErrorMessage, groupPolicyException.Message);
+ Assert.AreEqual(Constants.ErrorCode.ERROR_BLOCKED_BY_POLICY, groupPolicyException.HResult);
+
// PackageManagerSettings is not implemented in context OutOfProcDev
if (this.TestFactory.Context == ClsidContext.InProc)
{
@@ -159,6 +178,65 @@ public async Task DisableWinGetCommandLineInterfacesPolicy()
var packageVersion = "2.0.0.0";
string downloadDir = Path.Combine(TestCommon.GetDefaultDownloadDirectory(), $"{Constants.ModifyRepairInstaller}_{packageVersion}");
TestCommon.AssertInstallerDownload(downloadDir, "TestModifyRepair", packageVersion, ProcessorArchitecture.X86, TestCommon.Scope.Unknown, PackageInstallerType.Burn, "en-US");
+
+ // Add, update and remove package catalog
+ await this.AddUpdateRemovePackageCatalog();
+ }
+
+ private async Task AddUpdateRemovePackageCatalog()
+ {
+ // Remove the tests source if it exists.
+ await this.RemovePackageCatalog();
+
+ PackageManager packageManager = this.TestFactory.CreatePackageManager();
+
+ // Add package catalog
+ AddPackageCatalogOptions options = this.TestFactory.CreateAddPackageCatalogOptions();
+ options.SourceUri = Constants.TestSourceUrl;
+ options.Name = Constants.TestSourceName;
+ options.TrustLevel = PackageCatalogTrustLevel.Trusted;
+
+ var addCatalogResult = await packageManager.AddPackageCatalogAsync(options);
+ Assert.IsNotNull(addCatalogResult);
+ Assert.AreEqual(AddPackageCatalogStatus.Ok, addCatalogResult.Status);
+
+ // Get package catalog
+ var packageCatalog = packageManager.GetPackageCatalogByName(options.Name);
+
+ Assert.IsNotNull(packageCatalog);
+ Assert.AreEqual(options.Name, packageCatalog.Info.Name);
+ Assert.AreEqual(options.SourceUri, packageCatalog.Info.Argument);
+ var lastUpdatedTime = packageCatalog.Info.LastUpdateTime;
+
+ // Update package catalog
+ // Sleep for 30 seconds to make sure the last updated time is different after the refresh.
+ Thread.Sleep(TimeSpan.FromSeconds(30));
+
+ var updateResult = await packageCatalog.RefreshPackageCatalogAsync();
+ Assert.IsNotNull(updateResult);
+ Assert.AreEqual(RefreshPackageCatalogStatus.Ok, updateResult.Status);
+
+ packageCatalog = packageManager.GetPackageCatalogByName(options.Name);
+ Assert.IsTrue(packageCatalog.Info.LastUpdateTime > lastUpdatedTime);
+
+ // Remove package catalog
+ await this.RemovePackageCatalog();
+ }
+
+ private async Task RemovePackageCatalog()
+ {
+ PackageManager packageManager = this.TestFactory.CreatePackageManager();
+
+ // Remove the tests source if it exists.
+ RemovePackageCatalogOptions removePackageCatalogOptions = this.TestFactory.CreateRemovePackageCatalogOptions();
+ removePackageCatalogOptions.Name = Constants.TestSourceName;
+
+ var removeCatalogResult = await packageManager.RemovePackageCatalogAsync(removePackageCatalogOptions);
+ Assert.IsNotNull(removeCatalogResult);
+ Assert.AreEqual(RemovePackageCatalogStatus.Ok, removeCatalogResult.Status);
+
+ var packageCatalog = packageManager.GetPackageCatalogByName(removePackageCatalogOptions.Name);
+ Assert.IsNull(packageCatalog);
}
}
}
diff --git a/src/AppInstallerCLIE2ETests/Interop/PackageCatalogInterop.cs b/src/AppInstallerCLIE2ETests/Interop/PackageCatalogInterop.cs
new file mode 100644
index 0000000000..c38cb36f6b
--- /dev/null
+++ b/src/AppInstallerCLIE2ETests/Interop/PackageCatalogInterop.cs
@@ -0,0 +1,328 @@
+// -----------------------------------------------------------------------------
+//
+// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
+//
+// -----------------------------------------------------------------------------
+namespace AppInstallerCLIE2ETests.Interop
+{
+ using System;
+ using System.IO;
+ using System.Threading;
+ using System.Threading.Tasks;
+ using AppInstallerCLIE2ETests.Helpers;
+ using Microsoft.CodeAnalysis;
+ using Microsoft.Management.Deployment;
+ using Microsoft.Management.Deployment.Projection;
+ using NUnit.Framework;
+ using Windows.System;
+
+ ///
+ /// Package catalog interop class.
+ ///
+ [TestFixtureSource(typeof(InstanceInitializersSource), nameof(InstanceInitializersSource.InProcess), Category = nameof(InstanceInitializersSource.InProcess))]
+ [TestFixtureSource(typeof(InstanceInitializersSource), nameof(InstanceInitializersSource.OutOfProcess), Category = nameof(InstanceInitializersSource.OutOfProcess))]
+ public class PackageCatalogInterop : BaseInterop
+ {
+ private PackageManager packageManager;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// initializer.
+ public PackageCatalogInterop(IInstanceInitializer initializer)
+ : base(initializer)
+ {
+ }
+
+ ///
+ /// Set up.
+ ///
+ [SetUp]
+ public void Setup()
+ {
+ // Remove the tests source if it exists.
+ TestCommon.RunAICLICommand("source remove", Constants.TestSourceName);
+
+ this.packageManager = this.TestFactory.CreatePackageManager();
+ }
+
+ ///
+ /// Add and remove package catalog.
+ ///
+ /// representing the asynchronous unit test.
+ [Test]
+ public async Task AddRemovePackageCatalog()
+ {
+ AddPackageCatalogOptions options = this.TestFactory.CreateAddPackageCatalogOptions();
+ options.SourceUri = Constants.TestSourceUrl;
+ options.Name = Constants.TestSourceName;
+ options.TrustLevel = PackageCatalogTrustLevel.Trusted;
+
+ await this.AddAndValidatePackageCatalogAsync(options, AddPackageCatalogStatus.Ok);
+
+ RemovePackageCatalogOptions removePackageCatalogOptions = this.TestFactory.CreateRemovePackageCatalogOptions();
+ removePackageCatalogOptions.Name = Constants.TestSourceName;
+ var removeCatalogResult = await this.packageManager.RemovePackageCatalogAsync(removePackageCatalogOptions);
+ Assert.IsNotNull(removeCatalogResult);
+ Assert.AreEqual(RemovePackageCatalogStatus.Ok, removeCatalogResult.Status);
+
+ var testSource = this.packageManager.GetPackageCatalogByName(Constants.TestSourceName);
+ Assert.IsNull(testSource);
+ }
+
+ ///
+ /// Add package catalog with invalid options.
+ ///
+ [Test]
+ public void AddPackageCatalogWithInvalidOptions()
+ {
+ // Add package catalog with null options.
+ Assert.ThrowsAsync(async () => await this.packageManager.AddPackageCatalogAsync(null));
+
+ // Add package catalog with empty options.
+ Assert.ThrowsAsync(async () => await this.packageManager.AddPackageCatalogAsync(this.TestFactory.CreateAddPackageCatalogOptions()));
+ }
+
+ ///
+ /// Add package catalog with a duplicate name and verify it returns SourceNameExists.
+ ///
+ /// representing the asynchronous unit test.
+ [Test]
+ public async Task AddPackageCatalog_DuplicateName_ReturnsSourceNameExists()
+ {
+ AddPackageCatalogOptions options = this.TestFactory.CreateAddPackageCatalogOptions();
+ options.SourceUri = Constants.TestSourceUrl;
+ options.Name = Constants.TestSourceName;
+ options.TrustLevel = PackageCatalogTrustLevel.Trusted;
+
+ await this.AddAndValidatePackageCatalogAsync(options, AddPackageCatalogStatus.Ok);
+
+ // Add the same package catalog again.
+ await this.AddAndValidatePackageCatalogAsync(options, AddPackageCatalogStatus.InvalidOptions, Constants.ErrorCode.ERROR_SOURCE_NAME_ALREADY_EXISTS);
+
+ // Remove the tests source if it exists.
+ RemovePackageCatalogOptions removePackageCatalogOptions = this.TestFactory.CreateRemovePackageCatalogOptions();
+ removePackageCatalogOptions.Name = Constants.TestSourceName;
+ await this.RemoveAndValidatePackageCatalogAsync(removePackageCatalogOptions, RemovePackageCatalogStatus.Ok);
+ }
+
+ ///
+ /// Add package catalog with a duplicate source uri and verify it returns SourceArg AlreadyExists.
+ ///
+ /// representing the asynchronous unit test.
+ [Test]
+ public async Task AddPackageCatalog_DuplicateSourceUri_ReturnSourceArgAlreadyExists()
+ {
+ AddPackageCatalogOptions options = this.TestFactory.CreateAddPackageCatalogOptions();
+ options.SourceUri = Constants.TestSourceUrl;
+ options.Name = Constants.TestSourceName;
+ options.TrustLevel = PackageCatalogTrustLevel.Trusted;
+
+ await this.AddAndValidatePackageCatalogAsync(options, AddPackageCatalogStatus.Ok);
+
+ // Add the same package catalog again.
+ options.Name = "TestSource2";
+ await this.AddAndValidatePackageCatalogAsync(options, AddPackageCatalogStatus.InvalidOptions, Constants.ErrorCode.ERROR_SOURCE_ARG_ALREADY_EXISTS);
+
+ // Remove the tests source if it exists.
+ RemovePackageCatalogOptions removePackageCatalogOptions = this.TestFactory.CreateRemovePackageCatalogOptions();
+ removePackageCatalogOptions.Name = Constants.TestSourceName;
+ await this.RemoveAndValidatePackageCatalogAsync(removePackageCatalogOptions, RemovePackageCatalogStatus.Ok);
+ }
+
+ ///
+ /// Add package catalog with invalid source uri.
+ ///
+ /// representing the asynchronous unit test.
+ [Test]
+ public async Task AddPackageCatalogWithInvalidSourceUri()
+ {
+ AddPackageCatalogOptions options = this.TestFactory.CreateAddPackageCatalogOptions();
+ options.SourceUri = "InvalidUri";
+ options.Name = Constants.TestSourceName;
+ options.TrustLevel = PackageCatalogTrustLevel.Trusted;
+
+ await this.AddAndValidatePackageCatalogAsync(options, AddPackageCatalogStatus.InternalError);
+ }
+
+ ///
+ /// Add package catalog with insecure source uri.
+ ///
+ /// representing the asynchronous unit test.
+ [Test]
+ public async Task AddPackageCatalogWithHttpSourceUri()
+ {
+ AddPackageCatalogOptions options = this.TestFactory.CreateAddPackageCatalogOptions();
+ options.SourceUri = "http://microsoft.com";
+ options.Name = "Insecure";
+ options.TrustLevel = PackageCatalogTrustLevel.Trusted;
+
+ await this.AddAndValidatePackageCatalogAsync(options, AddPackageCatalogStatus.InvalidOptions, Constants.ErrorCode.ERROR_SOURCE_NOT_SECURE);
+ }
+
+ ///
+ /// Add package catalog with invalid type.
+ ///
+ /// representing the asynchronous unit test.
+ [Test]
+ public async Task AddPackageCatalogWithInvalidType()
+ {
+ AddPackageCatalogOptions options = this.TestFactory.CreateAddPackageCatalogOptions();
+ options.SourceUri = Constants.TestSourceUrl;
+ options.Name = Constants.TestSourceName;
+ options.Type = "InvalidType";
+
+ await this.AddAndValidatePackageCatalogAsync(options, AddPackageCatalogStatus.InvalidOptions, Constants.ErrorCode.ERROR_INVALID_SOURCE_TYPE);
+ }
+
+ ///
+ /// Add, update and remove package catalog.
+ ///
+ /// representing the asynchronous unit test.
+ [Test]
+ public async Task AddUpdateRemovePackageCatalog()
+ {
+ AddPackageCatalogOptions options = this.TestFactory.CreateAddPackageCatalogOptions();
+ options.SourceUri = Constants.TestSourceUrl;
+ options.Name = Constants.TestSourceName;
+ options.TrustLevel = PackageCatalogTrustLevel.Trusted;
+
+ await this.AddCatalogAndVerifyStatusAsync(options, AddPackageCatalogStatus.Ok);
+
+ var packageCatalog = this.GetAndValidatePackageCatalog(options);
+ var lastUpdatedTime = packageCatalog.Info.LastUpdateTime;
+
+ // Sleep for 30 seconds to make sure the last updated time is different after the refresh.
+ Thread.Sleep(TimeSpan.FromSeconds(30));
+
+ var updateResult = await packageCatalog.RefreshPackageCatalogAsync();
+ Assert.IsNotNull(updateResult);
+ Assert.AreEqual(RefreshPackageCatalogStatus.Ok, updateResult.Status);
+
+ packageCatalog = this.GetAndValidatePackageCatalog(options);
+ Assert.IsTrue(packageCatalog.Info.LastUpdateTime > lastUpdatedTime);
+
+ RemovePackageCatalogOptions removePackageCatalogOptions = this.TestFactory.CreateRemovePackageCatalogOptions();
+ removePackageCatalogOptions.Name = Constants.TestSourceName;
+ await this.RemoveAndValidatePackageCatalogAsync(removePackageCatalogOptions, RemovePackageCatalogStatus.Ok);
+ }
+
+ ///
+ /// Add, remove package catalog with PreserveData filed set..
+ ///
+ /// representing the asynchronous unit test.
+ [Test]
+ public async Task AddRemovePackageCatalogWithPreserveDataFiledSet()
+ {
+ AddPackageCatalogOptions options = this.TestFactory.CreateAddPackageCatalogOptions();
+ options.SourceUri = Constants.TestSourceUrl;
+ options.Name = Constants.TestSourceName;
+ options.TrustLevel = PackageCatalogTrustLevel.Trusted;
+
+ await this.AddAndValidatePackageCatalogAsync(options, AddPackageCatalogStatus.Ok);
+
+ RemovePackageCatalogOptions removePackageCatalogOptions = this.TestFactory.CreateRemovePackageCatalogOptions();
+ removePackageCatalogOptions.Name = Constants.TestSourceName;
+ removePackageCatalogOptions.PreserveData = true;
+
+ await this.RemoveAndValidatePackageCatalogAsync(removePackageCatalogOptions, RemovePackageCatalogStatus.Ok);
+ }
+
+ ///
+ /// Remove package catalog with invalid options.
+ ///
+ [Test]
+ public void RemovePackageCatalogWithInvalidOptions()
+ {
+ // Remove package catalog with null options.
+ Assert.ThrowsAsync(async () => await this.packageManager.RemovePackageCatalogAsync(null));
+
+ // Remove package catalog with empty options.
+ Assert.ThrowsAsync(async () => await this.packageManager.RemovePackageCatalogAsync(this.TestFactory.CreateRemovePackageCatalogOptions()));
+ }
+
+ ///
+ /// Remove a package catalog that is not present.
+ ///
+ /// representing the asynchronous unit test.
+ [Test]
+ public async Task RemoveNonExistingPackageCatalog()
+ {
+ RemovePackageCatalogOptions removePackageCatalogOptions = this.TestFactory.CreateRemovePackageCatalogOptions();
+ removePackageCatalogOptions.Name = Constants.TestSourceName;
+
+ await this.RemoveAndValidatePackageCatalogAsync(removePackageCatalogOptions, RemovePackageCatalogStatus.InvalidOptions, Constants.ErrorCode.ERROR_SOURCE_NAME_DOES_NOT_EXIST);
+ }
+
+ ///
+ /// Test class Tear down.
+ ///
+ [OneTimeTearDown]
+ public void TestClassTearDown()
+ {
+ // Restore the tests source if it was removed as the affects subsequent tests.
+ TestCommon.SetupTestSource();
+ }
+
+ private async Task AddCatalogAndVerifyStatusAsync(AddPackageCatalogOptions addPackageCatalogOptions, AddPackageCatalogStatus expectedStatus, int expectedErrorCode = 0)
+ {
+ var addCatalogResult = await this.packageManager.AddPackageCatalogAsync(addPackageCatalogOptions);
+ Assert.IsNotNull(addCatalogResult);
+ Assert.AreEqual(expectedStatus, addCatalogResult.Status);
+
+ if (expectedStatus != AddPackageCatalogStatus.Ok && expectedErrorCode != 0)
+ {
+ Assert.AreEqual(expectedErrorCode, addCatalogResult.ExtendedErrorCode.HResult);
+ }
+ }
+
+ private PackageCatalogReference GetAndValidatePackageCatalog(AddPackageCatalogOptions addPackageCatalogOptions)
+ {
+ var packageCatalog = this.packageManager.GetPackageCatalogByName(addPackageCatalogOptions.Name);
+
+ Assert.IsNotNull(packageCatalog);
+ Assert.AreEqual(addPackageCatalogOptions.Name, packageCatalog.Info.Name);
+ Assert.AreEqual(addPackageCatalogOptions.SourceUri, packageCatalog.Info.Argument);
+
+ return packageCatalog;
+ }
+
+ private async Task AddAndValidatePackageCatalogAsync(AddPackageCatalogOptions addPackageCatalogOptions, AddPackageCatalogStatus expectedStatus, int expectedErrorCode = 0)
+ {
+ // Add the package catalog and verify the status
+ var addCatalogResult = await this.packageManager.AddPackageCatalogAsync(addPackageCatalogOptions);
+ Assert.IsNotNull(addCatalogResult);
+ Assert.AreEqual(expectedStatus, addCatalogResult.Status);
+
+ if (expectedStatus != AddPackageCatalogStatus.Ok)
+ {
+ // Only validate the error code if the status is not Ok and the expected error code is not 0
+ if (expectedErrorCode != 0)
+ {
+ Assert.AreEqual(expectedErrorCode, addCatalogResult.ExtendedErrorCode.HResult);
+ }
+
+ return;
+ }
+
+ // Validate the added package catalog if the status is Ok
+ this.GetAndValidatePackageCatalog(addPackageCatalogOptions);
+ }
+
+ private async Task RemoveAndValidatePackageCatalogAsync(RemovePackageCatalogOptions removePackageCatalogOptions, RemovePackageCatalogStatus expectedStatus, int expectedErrorCode = 0)
+ {
+ var removeCatalogResult = await this.packageManager.RemovePackageCatalogAsync(removePackageCatalogOptions);
+ Assert.IsNotNull(removeCatalogResult);
+ Assert.AreEqual(expectedStatus, removeCatalogResult.Status);
+
+ if (expectedStatus != RemovePackageCatalogStatus.Ok && expectedErrorCode != 0)
+ {
+ Assert.AreEqual(expectedErrorCode, removeCatalogResult.ExtendedErrorCode.HResult);
+ return;
+ }
+
+ var packageCatalog = this.packageManager.GetPackageCatalogByName(removePackageCatalogOptions.Name);
+ Assert.IsNull(packageCatalog);
+ }
+ }
+}
diff --git a/src/AppInstallerCLIPackage/Package.appxmanifest b/src/AppInstallerCLIPackage/Package.appxmanifest
index 6ed816f412..6ef3f5aa9d 100644
--- a/src/AppInstallerCLIPackage/Package.appxmanifest
+++ b/src/AppInstallerCLIPackage/Package.appxmanifest
@@ -80,6 +80,10 @@
+
+
+
+
diff --git a/src/AppInstallerCommonCore/Public/AppInstallerProgress.h b/src/AppInstallerCommonCore/Public/AppInstallerProgress.h
index 9ba643dc34..7d7460b137 100644
--- a/src/AppInstallerCommonCore/Public/AppInstallerProgress.h
+++ b/src/AppInstallerCommonCore/Public/AppInstallerProgress.h
@@ -19,7 +19,7 @@ namespace AppInstaller
}
// The semantic meaning of the progress values.
- enum class ProgressType: uint32_t
+ enum class ProgressType : uint32_t
{
// Progress will not be sent.
None,
diff --git a/src/AppInstallerSharedLib/Public/winget/Runtime.h b/src/AppInstallerSharedLib/Public/winget/Runtime.h
index 61fbe0d19e..6c09b98cf4 100644
--- a/src/AppInstallerSharedLib/Public/winget/Runtime.h
+++ b/src/AppInstallerSharedLib/Public/winget/Runtime.h
@@ -40,6 +40,9 @@ namespace AppInstaller::Runtime
// Determines whether the process is running with local system context.
bool IsRunningAsSystem();
+ // Determines whether the process is running with administrator or system privileges.
+ bool IsRunningAsAdminOrSystem();
+
// Returns true if this is a release build; false if not.
inline constexpr bool IsReleaseBuild()
{
diff --git a/src/AppInstallerSharedLib/Runtime.cpp b/src/AppInstallerSharedLib/Runtime.cpp
index 89a0b297a5..2c35ea3135 100644
--- a/src/AppInstallerSharedLib/Runtime.cpp
+++ b/src/AppInstallerSharedLib/Runtime.cpp
@@ -208,4 +208,9 @@ namespace AppInstaller::Runtime
{
return wil::test_token_membership(nullptr, SECURITY_NT_AUTHORITY, SECURITY_LOCAL_SYSTEM_RID);
}
+
+ bool IsRunningAsAdminOrSystem()
+ {
+ return IsRunningAsAdmin() || IsRunningAsSystem();
+ }
}
diff --git a/src/Microsoft.Management.Deployment.InProc/Microsoft.Management.Deployment.InProc.dll.manifest b/src/Microsoft.Management.Deployment.InProc/Microsoft.Management.Deployment.InProc.dll.manifest
index f9e41531c7..4e9725d652 100644
--- a/src/Microsoft.Management.Deployment.InProc/Microsoft.Management.Deployment.InProc.dll.manifest
+++ b/src/Microsoft.Management.Deployment.InProc/Microsoft.Management.Deployment.InProc.dll.manifest
@@ -47,5 +47,13 @@
clsid="{30C024C4-852C-4DD4-9810-1348C51EF9BB}"
threadingModel="Both"
description="RepairOptions"/>
+
+
diff --git a/src/Microsoft.Management.Deployment.OutOfProc/Factory.cpp b/src/Microsoft.Management.Deployment.OutOfProc/Factory.cpp
index ad7c0d66ca..89bd2f4048 100644
--- a/src/Microsoft.Management.Deployment.OutOfProc/Factory.cpp
+++ b/src/Microsoft.Management.Deployment.OutOfProc/Factory.cpp
@@ -22,6 +22,8 @@ namespace Microsoft::Management::Deployment::OutOfProc
constexpr CLSID CLSID_DownloadOptions = { 0x4CBABE76, 0x7322, 0x4BE4, { 0x9C, 0xEA, 0x25, 0x89, 0xA8, 0x06, 0x82, 0xDC } }; //4CBABE76-7322-4BE4-9CEA-2589A80682DC
constexpr CLSID CLSID_AuthenticationArguments = { 0xBA580786, 0xBDE3, 0x4F6C, { 0xB8, 0xF3, 0x44, 0x69, 0x8A, 0xC8, 0x71, 0x1A } }; //BA580786-BDE3-4F6C-B8F3-44698AC8711A
constexpr CLSID CLSID_RepairOptions = { 0x0498F441, 0x3097, 0x455F, { 0x9C, 0xAF, 0x14, 0x8F, 0x28, 0x29, 0x38, 0x65 } }; //0498F441-3097-455F-9CAF-148F28293865
+ constexpr CLSID CLSID_AddPackageCatalogOptions = { 0xDB9D012D, 0x00D7, 0x47EE, { 0x8F, 0xB1, 0x60, 0x6E, 0x10, 0xAC, 0x4F, 0x51 } }; //DB9D012D-00D7-47EE-8FB1-606E10AC4F51
+ constexpr CLSID CLSID_RemovePackageCatalogOptions = { 0x032B1C58, 0xB975, 0x469B, { 0xA0, 0x13, 0xE6, 0x32, 0xB6, 0xEC, 0xE8, 0xD8 } }; //032B1C58-B975-469B-A013-E632B6ECE8D8
#else
constexpr CLSID CLSID_PackageManager = { 0x74CB3139, 0xB7C5, 0x4B9E, { 0x93, 0x88, 0xE6, 0x61, 0x6D, 0xEA, 0x28, 0x8C } }; //74CB3139-B7C5-4B9E-9388-E6616DEA288C
constexpr CLSID CLSID_InstallOptions = { 0x44FE0580, 0x62F7, 0x44D4, { 0x9E, 0x91, 0xAA, 0x96, 0x14, 0xAB, 0x3E, 0x86 } }; //44FE0580-62F7-44D4-9E91-AA9614AB3E86
@@ -32,6 +34,9 @@ namespace Microsoft::Management::Deployment::OutOfProc
constexpr CLSID CLSID_DownloadOptions = { 0x8EF324ED, 0x367C, 0x4880, { 0x83, 0xE5, 0xBB, 0x2A, 0xBD, 0x0B, 0x72, 0xF6 } }; //8EF324ED-367C-4880-83E5-BB2ABD0B72F6
constexpr CLSID CLSID_AuthenticationArguments = { 0x6484A61D, 0x50FA, 0x41F0, { 0xB7, 0x1E, 0xF4, 0x37, 0x0C, 0x6E, 0xB3, 0x7C } }; //6484A61D-50FA-41F0-B71E-F4370C6EB37C
constexpr CLSID CLSID_RepairOptions = { 0xE62BB1E7, 0xC7B2, 0x4AEC, { 0x9E, 0x28, 0xFB, 0x64, 0x9B, 0x30, 0xFF, 0x03 } }; //E62BB1E7-C7B2-4AEC-9E28-FB649B30FF03
+ constexpr CLSID CLSID_AddPackageCatalogOptions = { 0xD58C7E4C, 0x70E6, 0x476C, { 0xA5, 0xD4, 0x80, 0x34, 0x1E, 0xD8, 0x02, 0x52 } }; //D58C7E4C-70E6-476C-A5D4-80341ED80252
+ constexpr CLSID CLSID_RemovePackageCatalogOptions = { 0x87A96609, 0x1A39, 0x4955, { 0xBE, 0x72, 0x71, 0x74, 0xE1, 0x47, 0xB7, 0xDC } }; //87A96609-1A39-4955-BE72-7174E147B7DC
+
#endif
struct NameCLSIDPair
@@ -40,7 +45,7 @@ namespace Microsoft::Management::Deployment::OutOfProc
GUID CLSID;
};
- constexpr std::array s_nameCLSIDPairs
+ constexpr std::array s_nameCLSIDPairs
{
NameCLSIDPair{ L"Microsoft.Management.Deployment.PackageManager"sv, CLSID_PackageManager },
NameCLSIDPair{ L"Microsoft.Management.Deployment.InstallOptions"sv, CLSID_InstallOptions },
@@ -50,7 +55,9 @@ namespace Microsoft::Management::Deployment::OutOfProc
NameCLSIDPair{ L"Microsoft.Management.Deployment.CreateCompositePackageCatalogOptions"sv, CLSID_CreateCompositePackageCatalogOptions },
NameCLSIDPair{ L"Microsoft.Management.Deployment.DownloadOptions"sv, CLSID_DownloadOptions },
NameCLSIDPair{ L"Microsoft.Management.Deployment.AuthenticationArguments"sv, CLSID_AuthenticationArguments },
- NameCLSIDPair{ L"Microsoft.Management.Deployment.RepairOptions"sv, CLSID_RepairOptions }
+ NameCLSIDPair{ L"Microsoft.Management.Deployment.RepairOptions"sv, CLSID_RepairOptions },
+ NameCLSIDPair{ L"Microsoft.Management.Deployment.AddPackageCatalogOptions"sv, CLSID_AddPackageCatalogOptions },
+ NameCLSIDPair{ L"Microsoft.Management.Deployment.RemovePackageCatalogOptions"sv, CLSID_RemovePackageCatalogOptions },
};
bool IsCLSIDPresent(const GUID& clsid)
diff --git a/src/Microsoft.Management.Deployment.Projection/ClassesDefinition.cs b/src/Microsoft.Management.Deployment.Projection/ClassesDefinition.cs
index bf39299cc8..ed6adfb500 100644
--- a/src/Microsoft.Management.Deployment.Projection/ClassesDefinition.cs
+++ b/src/Microsoft.Management.Deployment.Projection/ClassesDefinition.cs
@@ -126,6 +126,30 @@ internal static class ClassesDefinition
[ClsidContext.OutOfProc] = new Guid("0498F441-3097-455F-9CAF-148F28293865"),
[ClsidContext.OutOfProcDev] = new Guid("E62BB1E7-C7B2-4AEC-9E28-FB649B30FF03"),
}
+ },
+
+ [typeof(AddPackageCatalogOptions)] = new()
+ {
+ ProjectedClassType = typeof(AddPackageCatalogOptions),
+ InterfaceType = typeof(IAddPackageCatalogOptions),
+ Clsids = new Dictionary()
+ {
+ [ClsidContext.InProc] = new Guid("24E6F1FA-E4C3-4ACD-965D-DF213FD58F15"),
+ [ClsidContext.OutOfProc] = new Guid("DB9D012D-00D7-47EE-8FB1-606E10AC4F51"),
+ [ClsidContext.OutOfProcDev] = new Guid("D58C7E4C-70E6-476C-A5D4-80341ED80252"),
+ }
+ },
+
+ [typeof(RemovePackageCatalogOptions)] = new()
+ {
+ ProjectedClassType = typeof(RemovePackageCatalogOptions),
+ InterfaceType = typeof(IRemovePackageCatalogOptions),
+ Clsids = new Dictionary()
+ {
+ [ClsidContext.InProc] = new Guid("1125D3A6-E2CE-479A-91D5-71A3F6F8B00B"),
+ [ClsidContext.OutOfProc] = new Guid("032B1C58-B975-469B-A013-E632B6ECE8D8"),
+ [ClsidContext.OutOfProcDev] = new Guid("87A96609-1A39-4955-BE72-7174E147B7DC"),
+ }
}
};
diff --git a/src/Microsoft.Management.Deployment.Projection/WinGetProjectionFactory.cs b/src/Microsoft.Management.Deployment.Projection/WinGetProjectionFactory.cs
index 73b75d5c70..5201492b2f 100644
--- a/src/Microsoft.Management.Deployment.Projection/WinGetProjectionFactory.cs
+++ b/src/Microsoft.Management.Deployment.Projection/WinGetProjectionFactory.cs
@@ -33,8 +33,12 @@ public WinGetProjectionFactory(IInstanceInitializer instanceInitializer)
public AuthenticationArguments CreateAuthenticationArguments() => InstanceInitializer.CreateInstance();
- public PackageManagerSettings CreatePackageManagerSettings() => InstanceInitializer.CreateInstance();
+ public PackageManagerSettings CreatePackageManagerSettings() => InstanceInitializer.CreateInstance();
public RepairOptions CreateRepairOptions() => InstanceInitializer.CreateInstance();
+
+ public AddPackageCatalogOptions CreateAddPackageCatalogOptions() => InstanceInitializer.CreateInstance();
+
+ public RemovePackageCatalogOptions CreateRemovePackageCatalogOptions() => InstanceInitializer.CreateInstance();
}
}
diff --git a/src/Microsoft.Management.Deployment/AddPackageCatalogOptions.cpp b/src/Microsoft.Management.Deployment/AddPackageCatalogOptions.cpp
new file mode 100644
index 0000000000..b31d0962f5
--- /dev/null
+++ b/src/Microsoft.Management.Deployment/AddPackageCatalogOptions.cpp
@@ -0,0 +1,66 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#include "pch.h"
+#pragma warning( push )
+#pragma warning ( disable : 4467 6388)
+// 6388 Allow CreateInstance.
+#include
+// 4467 Allow use of uuid attribute for com object creation.
+#include "AddPackageCatalogOptions.h"
+#pragma warning( pop )
+#include "AddPackageCatalogOptions.g.cpp"
+#include "Converters.h"
+#include "Helpers.h"
+
+namespace winrt::Microsoft::Management::Deployment::implementation
+{
+ hstring AddPackageCatalogOptions::Name()
+ {
+ return hstring(m_name);
+ }
+ void AddPackageCatalogOptions::Name(hstring const& value)
+ {
+ m_name = value;
+ }
+ hstring AddPackageCatalogOptions::SourceUri()
+ {
+ return hstring(m_sourceUri);
+ }
+ void AddPackageCatalogOptions::SourceUri(hstring const& value)
+ {
+ m_sourceUri = value;
+ }
+ hstring AddPackageCatalogOptions::Type()
+ {
+ return hstring(m_type);
+ }
+ void AddPackageCatalogOptions::Type(hstring const& value)
+ {
+ m_type = value;
+ }
+ winrt::Microsoft::Management::Deployment::PackageCatalogTrustLevel AddPackageCatalogOptions::TrustLevel()
+ {
+ return m_trustLevel;
+ }
+ void AddPackageCatalogOptions::TrustLevel(winrt::Microsoft::Management::Deployment::PackageCatalogTrustLevel const& value)
+ {
+ m_trustLevel = value;
+ }
+ hstring AddPackageCatalogOptions::CustomHeader()
+ {
+ return hstring(m_customHeader);
+ }
+ void AddPackageCatalogOptions::CustomHeader(hstring const& value)
+ {
+ m_customHeader = value;
+ }
+ bool AddPackageCatalogOptions::Explicit()
+ {
+ return m_explicit;
+ }
+ void AddPackageCatalogOptions::Explicit(bool const& value)
+ {
+ m_explicit = value;
+ }
+ CoCreatableMicrosoftManagementDeploymentClass(AddPackageCatalogOptions);
+}
diff --git a/src/Microsoft.Management.Deployment/AddPackageCatalogOptions.h b/src/Microsoft.Management.Deployment/AddPackageCatalogOptions.h
new file mode 100644
index 0000000000..d7a32b774e
--- /dev/null
+++ b/src/Microsoft.Management.Deployment/AddPackageCatalogOptions.h
@@ -0,0 +1,51 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#pragma once
+#include "AddPackageCatalogOptions.g.h"
+#include "public/ComClsids.h"
+
+namespace winrt::Microsoft::Management::Deployment::implementation
+{
+ [uuid(WINGET_OUTOFPROC_COM_CLSID_AddPackageCatalogOptions)]
+ struct AddPackageCatalogOptions : AddPackageCatalogOptionsT
+ {
+ AddPackageCatalogOptions() = default;
+
+ hstring Name();
+ void Name(hstring const& value);
+
+ hstring SourceUri();
+ void SourceUri(hstring const& value);
+
+ hstring Type();
+ void Type(hstring const& value);
+
+ winrt::Microsoft::Management::Deployment::PackageCatalogTrustLevel TrustLevel();
+ void TrustLevel(winrt::Microsoft::Management::Deployment::PackageCatalogTrustLevel const& value);
+
+ hstring CustomHeader();
+ void CustomHeader(hstring const& value);
+
+ bool Explicit();
+ void Explicit(bool const& value);
+
+#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
+ private:
+ hstring m_name = L"";
+ hstring m_sourceUri = L"";
+ hstring m_type = L"";
+ winrt::Microsoft::Management::Deployment::PackageCatalogTrustLevel m_trustLevel = winrt::Microsoft::Management::Deployment::PackageCatalogTrustLevel::None;
+ hstring m_customHeader = L"";
+ bool m_explicit = false;
+#endif
+ };
+}
+
+#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
+namespace winrt::Microsoft::Management::Deployment::factory_implementation
+{
+ struct AddPackageCatalogOptions : AddPackageCatalogOptionsT
+ {
+ };
+}
+#endif
diff --git a/src/Microsoft.Management.Deployment/AddPackageCatalogResult.cpp b/src/Microsoft.Management.Deployment/AddPackageCatalogResult.cpp
new file mode 100644
index 0000000000..f337c873e0
--- /dev/null
+++ b/src/Microsoft.Management.Deployment/AddPackageCatalogResult.cpp
@@ -0,0 +1,25 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#include "pch.h"
+#include "AddPackageCatalogResult.h"
+#include "AddPackageCatalogResult.g.cpp"
+#include
+
+namespace winrt::Microsoft::Management::Deployment::implementation
+{
+ void AddPackageCatalogResult::Initialize(
+ winrt::Microsoft::Management::Deployment::AddPackageCatalogStatus status,
+ winrt::hresult extendedErrorCode)
+ {
+ m_status = status;
+ m_extendedErrorCode = extendedErrorCode;
+ }
+ winrt::Microsoft::Management::Deployment::AddPackageCatalogStatus AddPackageCatalogResult::Status()
+ {
+ return m_status;
+ }
+ winrt::hresult AddPackageCatalogResult::ExtendedErrorCode()
+ {
+ return m_extendedErrorCode;
+ }
+}
diff --git a/src/Microsoft.Management.Deployment/AddPackageCatalogResult.h b/src/Microsoft.Management.Deployment/AddPackageCatalogResult.h
new file mode 100644
index 0000000000..a12def883b
--- /dev/null
+++ b/src/Microsoft.Management.Deployment/AddPackageCatalogResult.h
@@ -0,0 +1,28 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#pragma once
+#include "AddPackageCatalogResult.g.h"
+
+namespace winrt::Microsoft::Management::Deployment::implementation
+{
+ struct AddPackageCatalogResult : AddPackageCatalogResultT
+ {
+ AddPackageCatalogResult() = default;
+
+#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
+ void Initialize(
+ winrt::Microsoft::Management::Deployment::AddPackageCatalogStatus status,
+ winrt::hresult extendedErrorCode);
+#endif
+
+ winrt::Microsoft::Management::Deployment::AddPackageCatalogStatus Status();
+ winrt::hresult ExtendedErrorCode();
+
+#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
+ private:
+ winrt::Microsoft::Management::Deployment::AddPackageCatalogStatus m_status = winrt::Microsoft::Management::Deployment::AddPackageCatalogStatus::Ok;
+ winrt::hresult m_extendedErrorCode = S_OK;
+#endif
+ };
+}
+#pragma once
diff --git a/src/Microsoft.Management.Deployment/ComClsids.cpp b/src/Microsoft.Management.Deployment/ComClsids.cpp
index d76c1daf10..1cf315ba5c 100644
--- a/src/Microsoft.Management.Deployment/ComClsids.cpp
+++ b/src/Microsoft.Management.Deployment/ComClsids.cpp
@@ -14,7 +14,9 @@
#include "PackageManagerSettings.h"
#include "DownloadOptions.h"
#include "AuthenticationArguments.h"
-#include "RepairOptions.h"
+#include "RepairOptions.h"
+#include "AddPackageCatalogOptions.h"
+#include "RemovePackageCatalogOptions.h"
#pragma warning( pop )
namespace winrt::Microsoft::Management::Deployment
@@ -60,6 +62,14 @@ namespace winrt::Microsoft::Management::Deployment
else if (IsEqualCLSID(clsid, WINGET_INPROC_COM_CLSID_RepairOptions))
{
return __uuidof(winrt::Microsoft::Management::Deployment::implementation::RepairOptions);
+ }
+ else if (IsEqualCLSID(clsid, WINGET_INPROC_COM_CLSID_AddPackageCatalogOptions))
+ {
+ return __uuidof(winrt::Microsoft::Management::Deployment::implementation::AddPackageCatalogOptions);
+ }
+ else if (IsEqualCLSID(clsid, WINGET_INPROC_COM_CLSID_RemovePackageCatalogOptions))
+ {
+ return __uuidof(winrt::Microsoft::Management::Deployment::implementation::RemovePackageCatalogOptions);
}
else
{
diff --git a/src/Microsoft.Management.Deployment/Converters.cpp b/src/Microsoft.Management.Deployment/Converters.cpp
index e016a95dd4..08338dd306 100644
--- a/src/Microsoft.Management.Deployment/Converters.cpp
+++ b/src/Microsoft.Management.Deployment/Converters.cpp
@@ -497,4 +497,35 @@ namespace winrt::Microsoft::Management::Deployment::implementation
return result;
}
+
+ AddPackageCatalogStatus GetAddPackageCatalogOperationStatus(winrt::hresult hresult)
+ {
+ switch (hresult)
+ {
+ case APPINSTALLER_CLI_ERROR_AUTHENTICATION_TYPE_NOT_SUPPORTED:
+ return AddPackageCatalogStatus::AuthenticationError;
+ case APPINSTALLER_CLI_ERROR_SOURCE_NOT_SECURE:
+ case APPINSTALLER_CLI_ERROR_INVALID_SOURCE_TYPE:
+ case APPINSTALLER_CLI_ERROR_SOURCE_NOT_REMOTE:
+ case APPINSTALLER_CLI_ERROR_SOURCE_NAME_ALREADY_EXISTS:
+ case APPINSTALLER_CLI_ERROR_SOURCE_ARG_ALREADY_EXISTS:
+ return AddPackageCatalogStatus::InvalidOptions;
+ default:
+ return HandleCommonCatalogOperationStatus(hresult);
+ }
+ }
+
+ RemovePackageCatalogStatus GetRemovePackageCatalogOperationStatus(winrt::hresult hresult)
+ {
+ switch (hresult)
+ {
+ case APPINSTALLER_CLI_ERROR_SOURCE_NAME_DOES_NOT_EXIST:
+ return RemovePackageCatalogStatus::InvalidOptions;
+ case APPINSTALLER_CLI_ERROR_INVALID_SOURCE_TYPE:
+ return RemovePackageCatalogStatus::CatalogError;
+ default:
+ return HandleCommonCatalogOperationStatus(hresult);
+ }
+ }
+
}
diff --git a/src/Microsoft.Management.Deployment/Converters.h b/src/Microsoft.Management.Deployment/Converters.h
index fa0993e3ae..a861302341 100644
--- a/src/Microsoft.Management.Deployment/Converters.h
+++ b/src/Microsoft.Management.Deployment/Converters.h
@@ -31,6 +31,8 @@ namespace winrt::Microsoft::Management::Deployment::implementation
::AppInstaller::Authentication::AuthenticationMode GetAuthenticationMode(winrt::Microsoft::Management::Deployment::AuthenticationMode authMode);
::AppInstaller::Authentication::AuthenticationArguments GetAuthenticationArguments(winrt::Microsoft::Management::Deployment::AuthenticationArguments authArgs);
::AppInstaller::Manifest::ScopeEnum GetManifestRepairScope(winrt::Microsoft::Management::Deployment::PackageRepairScope scope);
+ winrt::Microsoft::Management::Deployment::AddPackageCatalogStatus GetAddPackageCatalogOperationStatus(winrt::hresult hresult);
+ winrt::Microsoft::Management::Deployment::RemovePackageCatalogStatus GetRemovePackageCatalogOperationStatus(winrt::hresult hresult);
#define WINGET_GET_OPERATION_RESULT_STATUS(_installResultStatus_, _uninstallResultStatus_, _downloadResultStatus_, _repairResultStatus_) \
if constexpr (std::is_same_v) \
@@ -141,4 +143,59 @@ namespace winrt::Microsoft::Management::Deployment::implementation
return resultStatus;
}
+
+ template
+ TStatus HandleCommonCatalogOperationStatus(winrt::hresult hresult)
+ {
+ // Common status handling for AddPackageCatalogStatus and RemovePackageCatalogStatus.
+ if constexpr (std::is_same_v || std::is_same_v)
+ {
+ switch (hresult)
+ {
+ case APPINSTALLER_CLI_ERROR_COMMAND_REQUIRES_ADMIN:
+ case E_ACCESSDENIED:
+ return TStatus::AccessDenied;
+ case APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS:
+ case E_INVALIDARG:
+ return TStatus::InvalidOptions;
+ default:
+ break;
+ }
+ }
+
+ // Common status handling for AddPackageCatalogStatus, RemovePackageCatalogStatus, and RefreshPackageCatalogStatus.
+ switch (hresult)
+ {
+ case S_OK:
+ return TStatus::Ok;
+ case APPINSTALLER_CLI_ERROR_BLOCKED_BY_POLICY:
+ return TStatus::GroupPolicyError;
+ case APPINSTALLER_CLI_ERROR_SOURCE_DATA_INTEGRITY_FAILURE:
+ return TStatus::CatalogError;
+ case APPINSTALLER_CLI_ERROR_INTERNAL_ERROR:
+ default:
+ return TStatus::InternalError;
+ }
+ }
+
+ template
+ TStatus GetPackageCatalogOperationStatus(winrt::hresult hresult)
+ {
+ if constexpr (std::is_same_v)
+ {
+ return GetAddPackageCatalogOperationStatus(hresult);
+ }
+ else if constexpr (std::is_same_v)
+ {
+ return GetRemovePackageCatalogOperationStatus(hresult);
+ }
+ else if constexpr (std::is_same_v)
+ {
+ return HandleCommonCatalogOperationStatus(hresult);
+ }
+ else
+ {
+ throw winrt::hresult_error(E_UNEXPECTED);
+ }
+ }
}
diff --git a/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj b/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj
index a1c3e41274..57f0161936 100644
--- a/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj
+++ b/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj
@@ -183,6 +183,8 @@
+
+
@@ -205,6 +207,7 @@
+
@@ -217,13 +220,18 @@
+
+
+
+
+
@@ -247,6 +255,7 @@
+
@@ -259,12 +268,15 @@
Create
+
+
+
diff --git a/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj.filters b/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj.filters
index 128b48aeff..78c593d394 100644
--- a/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj.filters
+++ b/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj.filters
@@ -40,6 +40,12 @@
+
+
+
+
+
+
@@ -85,6 +91,12 @@
+
+
+
+
+
+
diff --git a/src/Microsoft.Management.Deployment/PackageCatalogProgress.cpp b/src/Microsoft.Management.Deployment/PackageCatalogProgress.cpp
new file mode 100644
index 0000000000..e82f1d7fdb
--- /dev/null
+++ b/src/Microsoft.Management.Deployment/PackageCatalogProgress.cpp
@@ -0,0 +1,157 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#include "pch.h"
+#include "PackageCatalogProgress.h"
+#include "AppInstallerStrings.h"
+#include "Microsoft/PredefinedInstalledSourceFactory.h"
+
+using namespace AppInstaller;
+using namespace AppInstaller::Repository;
+
+namespace winrt::Microsoft::Management::Deployment
+{
+ namespace ProgressSinkFactory
+ {
+ std::shared_ptr CreatePackageCatalogProgressSink(std::string sourceType, std::function progressReporter, bool removeOperation)
+ {
+ if (sourceType.empty()
+ || Utility::CaseInsensitiveEquals( Repository::Microsoft::PredefinedInstalledSourceFactory::Type(), sourceType))
+ {
+ std::vector> progressWeights;
+
+ // There is no download operation for remove operation, so use only percentage based progress to account for uninstall.
+ if (removeOperation)
+ {
+ // it is percentage based progress.
+ progressWeights.push_back(std::make_pair(AppInstaller::ProgressType::Percent, 1.0));
+ }
+ else
+ {
+ // Add/Update operation has two progress types:
+ // 1. Bytes for downloading index and
+ // 2. Percent for index installation.
+ progressWeights.push_back(std::make_pair(AppInstaller::ProgressType::Bytes, 0.7));
+ progressWeights.push_back(std::make_pair(AppInstaller::ProgressType::Percent, 0.3));
+ }
+
+ return std::make_shared(progressWeights, progressReporter);
+ }
+ else
+ {
+ return std::make_shared(progressReporter);
+ }
+ }
+ }
+
+ CompletionOnlyProgressSink::CompletionOnlyProgressSink(std::function progressReporter) :
+ m_progressReporter(progressReporter)
+ {
+ if (!m_progressReporter)
+ {
+ THROW_HR(E_INVALIDARG);
+ }
+ }
+
+ void CompletionOnlyProgressSink::OnProgress(uint64_t /*current*/, uint64_t /*maximum*/, AppInstaller::ProgressType /*type*/)
+ {
+ }
+
+ void CompletionOnlyProgressSink::SetProgressMessage(std::string_view /*message*/)
+ {
+ }
+
+ void CompletionOnlyProgressSink::BeginProgress()
+ {
+ m_progressReporter(0);
+ }
+
+ void CompletionOnlyProgressSink::EndProgress(bool /*hideProgressWhenDone*/)
+ {
+ m_progressReporter(100);
+ }
+
+ PreIndexedPackageCatalogProgressSink::PreIndexedPackageCatalogProgressSink(std::vector> progressWeights, std::function progressReporter) :
+ m_progressWeights(progressWeights), m_progressReporter(progressReporter)
+ {
+ if (!m_progressReporter)
+ {
+ THROW_HR(E_INVALIDARG);
+ }
+
+ // If no weights are provided, default to percent.
+ if (m_progressWeights.empty())
+ {
+ m_progressWeights.push_back(std::make_pair(AppInstaller::ProgressType::Percent, 1.0));
+ }
+
+ // Calculate the total weight.
+ double totalWeight = 0;
+ for (const auto& weight : m_progressWeights)
+ {
+ if (weight.first != AppInstaller::ProgressType::None)
+ {
+ totalWeight += weight.second;
+ }
+ }
+
+ // If the total weight is greater than 1, throw an exception.
+ if (totalWeight != 1.0)
+ {
+ THROW_HR(E_INVALIDARG);
+ }
+ }
+
+ void PreIndexedPackageCatalogProgressSink::OnProgress(uint64_t current, uint64_t maximum, AppInstaller::ProgressType type)
+ {
+ if (maximum == 0 || type == AppInstaller::ProgressType::None)
+ {
+ return;
+ }
+
+ double progress = static_cast(current) / maximum;
+ m_progressValues[type] = progress;
+
+ double totalProgress = 0.0;
+ double totalWeight = 0.0;
+
+ // Calculate the total progress.
+ for (const auto& [progressType, weight] : m_progressWeights)
+ {
+ double progressValue = m_progressValues[progressType];
+
+ // [NOTE:] Sequential execution assumption & Handling incomplete progress reports :
+ // This progress calculation assumes that each operation is executed sequentially, meaning the download must be complete before
+ // the installation begins.If the download fails, the installation will not proceed.However, there may be cases where the previous
+ // operation completes successfully, but its onprogress callback does not report 100% completion(e.g., the last progress report for
+ // the download was at 90%, but the download is complete, and the installation has started).This can result in the total progress not
+ // reaching 100% after the last operation completes due to the gap in the previous operation's progress report.To handle this, consider
+ // the progress for the last operation as complete by assigning its full weight while computing progress for the following operation.
+ // For example, while computing progress for the installation, consider the download operation complete even if it did not report progress
+ // exactly at 100%.
+ if (progressValue != 0)
+ {
+ totalProgress = totalWeight;
+ }
+
+ // Adjust the total progress value based on the weight.
+ totalWeight += weight;
+ totalProgress += progressValue * weight;
+ }
+
+ m_progressReporter(totalProgress * 100);
+ }
+
+ void PreIndexedPackageCatalogProgressSink::SetProgressMessage(std::string_view /*message*/)
+ {
+ }
+
+ void PreIndexedPackageCatalogProgressSink::BeginProgress()
+ {
+ m_progressReporter(0);
+ }
+
+ void PreIndexedPackageCatalogProgressSink::EndProgress(bool /*hideProgressWhenDone*/)
+ {
+ m_progressReporter(100);
+ }
+}
diff --git a/src/Microsoft.Management.Deployment/PackageCatalogProgress.h b/src/Microsoft.Management.Deployment/PackageCatalogProgress.h
new file mode 100644
index 0000000000..4f175d054e
--- /dev/null
+++ b/src/Microsoft.Management.Deployment/PackageCatalogProgress.h
@@ -0,0 +1,73 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#pragma once
+#include "AppInstallerProgress.h"
+#include
+#include
+
+namespace winrt::Microsoft::Management::Deployment
+{
+ namespace ProgressSinkFactory
+ {
+ ///
+ /// Creates a progress sink for package catalog operations based on sourceType.
+ ///
+ /// sourceType.
+ /// callback function that reports progress to caller.
+ /// Default value is false. Identifies if the operation is a PackageCatalog removal and requests the ProgressSink.
+ /// IProgressSink.
+ std::shared_ptr CreatePackageCatalogProgressSink(std::string sourceType, std::function progressReporter, bool removeOperation = false);
+ }
+
+ ///
+ /// Progress sink that only reports start and completion to caller.
+ ///
+ struct CompletionOnlyProgressSink : AppInstaller::IProgressSink
+ {
+ ///
+ /// Constructor.
+ ///
+ /// callback that reports progress to caller.
+ CompletionOnlyProgressSink(std::function progressReporter);
+
+ void OnProgress(uint64_t current, uint64_t maximum, AppInstaller::ProgressType type) override;
+ void SetProgressMessage(std::string_view message) override;
+ void BeginProgress() override;
+ void EndProgress(bool hideProgressWhenDone) override;
+
+ private:
+ std::function m_progressReporter;
+ };
+
+ ///
+ /// Progress sink for pre-indexed package catalog operations.
+ /// capable of reporting progress for download and installation of index.
+ /// Add/update operation has two progress types: Bytes for downloading index and Percent for index installation.
+ /// Remove operation has only percentage based progress.
+ ///
+ struct PreIndexedPackageCatalogProgressSink : AppInstaller::IProgressSink
+ {
+ ///
+ /// Constructor.
+ ///
+ /// ProgressType weight map.
+ /// Callback function that reports progress to caller.
+ PreIndexedPackageCatalogProgressSink(std::vector> progressWeights, std::function progressReporter);
+
+ ///
+ /// Reports combined progress to caller when configured for multiple progress types.
+ ///
+ /// The current progress value.
+ /// The maximum progress value.
+ /// ProgressType for which progress is applicable.
+ void OnProgress(uint64_t current, uint64_t maximum, AppInstaller::ProgressType type) override;
+ void SetProgressMessage(std::string_view message) override;
+ void BeginProgress() override;
+ void EndProgress(bool hideProgressWhenDone) override;
+
+ private:
+ std::vector> m_progressWeights;
+ std::function m_progressReporter;
+ std::unordered_map m_progressValues;
+ };
+}
diff --git a/src/Microsoft.Management.Deployment/PackageCatalogReference.cpp b/src/Microsoft.Management.Deployment/PackageCatalogReference.cpp
index 4d9f0cc197..c2787e8924 100644
--- a/src/Microsoft.Management.Deployment/PackageCatalogReference.cpp
+++ b/src/Microsoft.Management.Deployment/PackageCatalogReference.cpp
@@ -18,9 +18,23 @@
#include
#include
#include
+#include
+#include
+#include
namespace winrt::Microsoft::Management::Deployment::implementation
{
+ namespace
+ {
+ winrt::Microsoft::Management::Deployment::RefreshPackageCatalogResult GetRefreshPackageCatalogResult(winrt::hresult terminationStatus)
+ {
+ winrt::Microsoft::Management::Deployment::RefreshPackageCatalogStatus status = GetPackageCatalogOperationStatus(terminationStatus);
+ auto updateResult = winrt::make_self>();
+ updateResult->Initialize(status, terminationStatus);
+ return *updateResult;
+ }
+ }
+
void PackageCatalogReference::Initialize(winrt::Microsoft::Management::Deployment::PackageCatalogInfo packageCatalogInfo, ::AppInstaller::Repository::Source sourceReference)
{
m_info = packageCatalogInfo;
@@ -289,4 +303,29 @@ namespace winrt::Microsoft::Management::Deployment::implementation
});
return m_authenticationInfo;
}
+
+ winrt::Windows::Foundation::IAsyncOperationWithProgress PackageCatalogReference::RefreshPackageCatalogAsync()
+ {
+ HRESULT terminationHR = S_OK;
+ try {
+ // Check for permissions and get caller info for telemetry
+ THROW_IF_FAILED(EnsureComCallerHasCapability(Capability::PackageQuery));
+
+ auto report_progress{ co_await winrt::get_progress_token() };
+ co_await winrt::resume_background();
+
+ auto packageCatalogProgressSink = winrt::Microsoft::Management::Deployment::ProgressSinkFactory::CreatePackageCatalogProgressSink(this->m_sourceReference.GetDetails().Type, report_progress);
+
+ packageCatalogProgressSink->BeginProgress();
+ ::AppInstaller::ProgressCallback progress(packageCatalogProgressSink.get());
+ this->m_sourceReference.Update(progress);
+ packageCatalogProgressSink->EndProgress(false);
+ }
+ catch (...)
+ {
+ terminationHR = AppInstaller::CLI::Workflow::HandleException(nullptr, std::current_exception());
+ }
+
+ co_return GetRefreshPackageCatalogResult(terminationHR);
+ }
}
diff --git a/src/Microsoft.Management.Deployment/PackageCatalogReference.h b/src/Microsoft.Management.Deployment/PackageCatalogReference.h
index fbfc68fe24..75539d926a 100644
--- a/src/Microsoft.Management.Deployment/PackageCatalogReference.h
+++ b/src/Microsoft.Management.Deployment/PackageCatalogReference.h
@@ -32,7 +32,9 @@ namespace winrt::Microsoft::Management::Deployment::implementation
void InstalledPackageInformationOnly(bool value);
winrt::Microsoft::Management::Deployment::AuthenticationArguments AuthenticationArguments();
void AuthenticationArguments(winrt::Microsoft::Management::Deployment::AuthenticationArguments const& value);
- winrt::Microsoft::Management::Deployment::AuthenticationInfo AuthenticationInfo();
+ winrt::Microsoft::Management::Deployment::AuthenticationInfo AuthenticationInfo();
+ // Contract 12.0
+ winrt::Windows::Foundation::IAsyncOperationWithProgress RefreshPackageCatalogAsync();
#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
private:
diff --git a/src/Microsoft.Management.Deployment/PackageManager.cpp b/src/Microsoft.Management.Deployment/PackageManager.cpp
index 6e21cab2e1..e0b3c7c87d 100644
--- a/src/Microsoft.Management.Deployment/PackageManager.cpp
+++ b/src/Microsoft.Management.Deployment/PackageManager.cpp
@@ -30,9 +30,14 @@
#include "PackageCatalogReference.h"
#include "PackageVersionInfo.h"
#include "PackageVersionId.h"
+#include "AddPackageCatalogResult.h"
+#include "RemovePackageCatalogResult.h"
#include "Converters.h"
#include "Helpers.h"
#include "ContextOrchestrator.h"
+#include "AppInstallerRuntime.h"
+#include
+#include
using namespace std::literals::chrono_literals;
using namespace ::AppInstaller::CLI;
@@ -52,6 +57,95 @@ namespace winrt::Microsoft::Management::Deployment::implementation
::AppInstaller::Logging::Telemetry().LogStartup(true);
});
}
+
+ winrt::Microsoft::Management::Deployment::AddPackageCatalogResult GetAddPackageCatalogResult(winrt::hresult terminationStatus)
+ {
+ winrt::Microsoft::Management::Deployment::AddPackageCatalogStatus status = GetPackageCatalogOperationStatus(terminationStatus);
+ auto addPackageCatalogResult = winrt::make_self>();
+ addPackageCatalogResult->Initialize(status, terminationStatus);
+ return *addPackageCatalogResult;
+ }
+
+ void CheckForDuplicateSource(const std::string& name, const std::string& type, const std::string& sourceUri)
+ {
+ auto sourceList = ::AppInstaller::Repository::Source::GetCurrentSources();
+
+ std::string sourceType = type;
+
+ // [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,
+ // it remains unassigned until the add operation, at which point it is assigned.Without this default assignment, an empty string could be
+ // compared to the default type, potentially allowing different source names with the same URI to be seen as unique.
+ // To avoid this, assign the default source type prior to comparison.
+ if (sourceType.empty())
+ {
+ // This method of obtaining the default source type is slightly expensive as it requires creating a SourceFactory object
+ // and fetching the type name.Nonetheless, it future-proofs the code against any changes in the SourceFactory's default type.
+ sourceType = ::AppInstaller::Repository::Source::GetDefaultSourceType();
+ }
+
+ for (const auto& source : sourceList)
+ {
+ THROW_HR_IF(APPINSTALLER_CLI_ERROR_SOURCE_NAME_ALREADY_EXISTS, ::AppInstaller::Utility::ICUCaseInsensitiveEquals(source.Name, name));
+
+ bool sourceUriAlreadyExists = !source.Arg.empty() && source.Arg == sourceUri && source.Type == sourceType;
+ THROW_HR_IF(APPINSTALLER_CLI_ERROR_SOURCE_ARG_ALREADY_EXISTS, sourceUriAlreadyExists);
+ }
+ }
+
+ ::AppInstaller::Repository::Source CreateSourceFromOptions(const winrt::Microsoft::Management::Deployment::AddPackageCatalogOptions& options)
+ {
+ std::string name = winrt::to_string(options.Name());
+ std::string type = winrt::to_string(options.Type());
+ std::string sourceUri = winrt::to_string(options.SourceUri());
+
+ AppInstaller::Repository::SourceTrustLevel trustLevel = AppInstaller::Repository::SourceTrustLevel::None;
+ if (options.TrustLevel() == winrt::Microsoft::Management::Deployment::PackageCatalogTrustLevel::Trusted)
+ {
+ trustLevel = AppInstaller::Repository::SourceTrustLevel::Trusted;
+ }
+
+ CheckForDuplicateSource(name, type, sourceUri);
+
+ ::AppInstaller::Repository::Source source = ::AppInstaller::Repository::Source{ name, sourceUri, type, trustLevel, options.Explicit() };
+
+ std::string customHeader = winrt::to_string(options.CustomHeader());
+ if (!customHeader.empty())
+ {
+ source.SetCustomHeader(customHeader);
+ }
+
+ auto sourceInfo = source.GetInformation();
+
+ if (sourceInfo.Authentication.Type == ::AppInstaller::Authentication::AuthenticationType::Unknown)
+ {
+ THROW_HR(APPINSTALLER_CLI_ERROR_AUTHENTICATION_TYPE_NOT_SUPPORTED);
+ }
+
+ return source;
+ }
+
+ winrt::Microsoft::Management::Deployment::RemovePackageCatalogResult GetRemovePackageCatalogResult(winrt::hresult terminationStatus)
+ {
+ winrt::Microsoft::Management::Deployment::RemovePackageCatalogStatus status = GetPackageCatalogOperationStatus(terminationStatus);
+ auto removeResult = winrt::make_self>();
+ removeResult->Initialize(status, terminationStatus);
+ return *removeResult;
+ }
+
+ std::optional<::AppInstaller::Repository::SourceDetails> GetMatchingSource(const std::string& name)
+ {
+ auto sourceList = ::AppInstaller::Repository::Source::GetCurrentSources();
+
+ for (const auto& source : sourceList)
+ {
+ if (::AppInstaller::Utility::ICUCaseInsensitiveEquals(source.Name, name))
+ {
+ return source; // Return the first matching source
+ }
+ }
+
+ return std::nullopt; // Return std::nullopt if no matching source is found
+ }
}
winrt::Windows::Foundation::Collections::IVectorView PackageManager::GetPackageCatalogs()
@@ -843,7 +937,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation
}
else if constexpr (std::is_same_v)
{
- TProgress queuedProgress{ TProgressState::Queued, 0};
+ TProgress queuedProgress{ TProgressState::Queued, 0 };
report_progress(queuedProgress);
}
else if constexpr (std::is_same_v)
@@ -1197,5 +1291,90 @@ namespace winrt::Microsoft::Management::Deployment::implementation
true /*canCancelQueueItem*/, nullptr /*queueItem*/, package, options, std::move(callerProcessInfoString));
}
+ winrt::Windows::Foundation::IAsyncOperationWithProgress PackageManager::AddPackageCatalogAsync(winrt::Microsoft::Management::Deployment::AddPackageCatalogOptions options)
+ {
+ LogStartupIfApplicable();
+
+ // options must be set.
+ THROW_HR_IF_NULL(E_POINTER, options);
+ THROW_HR_IF(E_INVALIDARG, options.Name().empty());
+ THROW_HR_IF(E_INVALIDARG, options.SourceUri().empty());
+
+ HRESULT terminationHR = S_OK;
+ try {
+
+ // Check if running as admin/system.
+ // [NOTE:] For OutOfProc calls, the Windows Package Manager Service executes in the context initiated by the caller process,
+ // so the same admin/system validation check is applicable for both InProc and OutOfProc calls.
+ THROW_HR_IF(APPINSTALLER_CLI_ERROR_COMMAND_REQUIRES_ADMIN, !AppInstaller::Runtime::IsRunningAsAdminOrSystem());
+
+ ::AppInstaller::Repository::Source sourceToAdd = CreateSourceFromOptions(options);
+
+ auto report_progress{ co_await winrt::get_progress_token() };
+ co_await winrt::resume_background();
+
+ std::string type = winrt::to_string(options.Type());
+ auto packageCatalogProgressSink = winrt::Microsoft::Management::Deployment::ProgressSinkFactory::CreatePackageCatalogProgressSink(type, report_progress );
+
+ packageCatalogProgressSink->BeginProgress();
+ ::AppInstaller::ProgressCallback progress(packageCatalogProgressSink.get());
+ sourceToAdd.Add(progress);
+ packageCatalogProgressSink->EndProgress(false);
+ }
+ catch (...)
+ {
+ terminationHR = AppInstaller::CLI::Workflow::HandleException(nullptr, std::current_exception());
+ }
+
+ co_return GetAddPackageCatalogResult(terminationHR);
+ }
+
+ winrt::Windows::Foundation::IAsyncOperationWithProgress PackageManager::RemovePackageCatalogAsync(winrt::Microsoft::Management::Deployment::RemovePackageCatalogOptions options)
+ {
+ LogStartupIfApplicable();
+
+ // options must be set.
+ THROW_HR_IF_NULL(E_POINTER, options);
+ THROW_HR_IF(E_INVALIDARG, options.Name().empty());
+
+ HRESULT terminationHR = S_OK;
+ try {
+
+ // Check if running as admin/system.
+ // [NOTE:] For OutOfProc calls, the Windows Package Manager Service executes in the context initiated by the caller process,
+ // so the same admin/system validation check is applicable for both InProc and OutOfProc calls.
+ THROW_HR_IF(APPINSTALLER_CLI_ERROR_COMMAND_REQUIRES_ADMIN, !AppInstaller::Runtime::IsRunningAsAdminOrSystem());
+
+ auto matchingSource = GetMatchingSource(winrt::to_string(options.Name()));
+ THROW_HR_IF(APPINSTALLER_CLI_ERROR_SOURCE_NAME_DOES_NOT_EXIST, !matchingSource.has_value());
+
+ auto report_progress{ co_await winrt::get_progress_token() };
+ co_await winrt::resume_background();
+
+ auto packageCatalogProgressSink = winrt::Microsoft::Management::Deployment::ProgressSinkFactory::CreatePackageCatalogProgressSink(matchingSource.value().Type, report_progress, true);
+
+ packageCatalogProgressSink->BeginProgress();
+ ::AppInstaller::Repository::Source sourceToRemove = ::AppInstaller::Repository::Source{ matchingSource.value().Name };
+ ::AppInstaller::ProgressCallback progress(packageCatalogProgressSink.get());
+
+ // If the PreserveData option is set, this is equivalent to the WinGet CLI Reset command on a single source; otherwise, it removes the source.
+ if (options.PreserveData())
+ {
+ THROW_HR_IF(APPINSTALLER_CLI_ERROR_SOURCE_NAME_DOES_NOT_EXIST, !sourceToRemove.DropSource(matchingSource.value().Name));
+ }
+ else
+ {
+ sourceToRemove.Remove(progress);
+ }
+ packageCatalogProgressSink->EndProgress(false);
+ }
+ catch (...)
+ {
+ terminationHR = AppInstaller::CLI::Workflow::HandleException(nullptr, std::current_exception());
+ }
+
+ co_return GetRemovePackageCatalogResult(terminationHR);
+ }
+
CoCreatableMicrosoftManagementDeploymentClass(PackageManager);
}
diff --git a/src/Microsoft.Management.Deployment/PackageManager.h b/src/Microsoft.Management.Deployment/PackageManager.h
index 0ce0b32560..1758962bd9 100644
--- a/src/Microsoft.Management.Deployment/PackageManager.h
+++ b/src/Microsoft.Management.Deployment/PackageManager.h
@@ -44,6 +44,11 @@ namespace winrt::Microsoft::Management::Deployment::implementation
// Contract 11.0
winrt::Windows::Foundation::IAsyncOperationWithProgress
RepairPackageAsync(winrt::Microsoft::Management::Deployment::CatalogPackage package, winrt::Microsoft::Management::Deployment::RepairOptions options);
+ // Contract 12.0
+ winrt::Windows::Foundation::IAsyncOperationWithProgress
+ AddPackageCatalogAsync(winrt::Microsoft::Management::Deployment::AddPackageCatalogOptions options);
+ winrt::Windows::Foundation::IAsyncOperationWithProgress
+ RemovePackageCatalogAsync(winrt::Microsoft::Management::Deployment::RemovePackageCatalogOptions options);
};
#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
diff --git a/src/Microsoft.Management.Deployment/PackageManager.idl b/src/Microsoft.Management.Deployment/PackageManager.idl
index 8c5c166698..943177fc45 100644
--- a/src/Microsoft.Management.Deployment/PackageManager.idl
+++ b/src/Microsoft.Management.Deployment/PackageManager.idl
@@ -2,7 +2,7 @@
// Licensed under the MIT License.
namespace Microsoft.Management.Deployment
{
- [contractversion(11)] // For version 1.9
+ [contractversion(12)] // For version 1.10
apicontract WindowsPackageManagerContract{};
/// State of the install
@@ -863,6 +863,25 @@ namespace Microsoft.Management.Deployment
}
}
+ [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 12)]
+ enum RefreshPackageCatalogStatus
+ {
+ Ok,
+ GroupPolicyError,
+ CatalogError,
+ InternalError,
+ };
+
+ /// IMPLEMENTATION NOTE: RefreshPackageCatalogResult
+ [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 12)]
+ runtimeclass RefreshPackageCatalogResult
+ {
+ RefreshPackageCatalogStatus Status { get; };
+
+ /// Error codes
+ HRESULT ExtendedErrorCode { get; };
+ };
+
/// A reference to a catalog that callers can try to Connect.
[contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)]
runtimeclass PackageCatalogReference
@@ -917,6 +936,14 @@ namespace Microsoft.Management.Deployment
/// This is defined by individual package catalog.
AuthenticationInfo AuthenticationInfo { get; };
}
+
+ [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 12)]
+ {
+ /// Updates the package catalog.
+ /// The progress value, represented as a double, indicates the percentage of update package catalog operation completion.
+ /// The progress range is from 0 to 100.
+ Windows.Foundation.IAsyncOperationWithProgress RefreshPackageCatalogAsync();
+ }
}
/// Catalogs with PackageCatalogOrigin Predefined
@@ -1351,6 +1378,103 @@ namespace Microsoft.Management.Deployment
String InstallationNotes { get; };
}
+ /// IMPLEMENTATION NOTE: AddPackageCatalogOptions
+ [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 12)]
+ runtimeclass AddPackageCatalogOptions
+ {
+ AddPackageCatalogOptions();
+
+ /// The name of the package catalog.
+ /// SAMPLE VALUES: For OpenWindowsCatalog "winget".
+ /// For contoso sample on msdn "contoso"
+ String Name;
+
+ /// The SourceUri 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 SourceUri;
+
+ /// ALLOWED VALUES: "Microsoft.Rest", "Microsoft.PreIndexed.Package"
+ /// SAMPLE VALUES: For OpenWindowsCatalog "Microsoft.PreIndexed.Package".
+ /// For contoso sample on msdn "Microsoft.PreIndexed.Package"
+ String Type;
+
+ /// The trust level of the catalog to add.
+ PackageCatalogTrustLevel TrustLevel;
+
+ /// Custom header to pass to the catalog.
+ String CustomHeader;
+
+ /// Excludes a source from discovery unless specified.
+ Boolean Explicit;
+ };
+
+ /// IMPLEMENTATION NOTE: AddPackageCatalogStatus
+ [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 12)]
+ enum AddPackageCatalogStatus
+ {
+ Ok,
+ GroupPolicyError,
+ CatalogError,
+ InternalError,
+ InvalidOptions,
+ AccessDenied,
+ AuthenticationError,
+ };
+
+ /// IMPLEMENTATION NOTE: AddPackageCatalogResult
+ [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 12)]
+ runtimeclass AddPackageCatalogResult
+ {
+ AddPackageCatalogStatus Status { get; };
+
+ /// Error codes
+ HRESULT ExtendedErrorCode { get; };
+ };
+
+ /// IMPLEMENTATION NOTE: RemovePackageCatalogOptions
+ [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 12)]
+ runtimeclass RemovePackageCatalogOptions
+ {
+ RemovePackageCatalogOptions();
+
+ /// The name of the package catalog.
+ /// SAMPLE VALUES: For OpenWindowsCatalog "winget".
+ /// For contoso sample on msdn "contoso"
+ String Name;
+
+ /// By default, the value is 'false', resulting in the removal of the package catalog registration
+ /// from the winget Package catalogs list and the deletion of all associated system artifacts. This
+ /// mirrors the WinGet Source remove operation on a specific Package Catalog.
+ /// If set to 'true', it removes the package catalog registration from the Windows Package Catalogs
+ /// list without any cleanup, similar to the WinGet source reset operation on a specific Package
+ /// Catalog.
+ Boolean PreserveData;
+ };
+
+ /// IMPLEMENTATION NOTE: RemovePackageCatalogStatus
+ [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 12)]
+ enum RemovePackageCatalogStatus
+ {
+ Ok,
+ GroupPolicyError,
+ CatalogError,
+ InternalError,
+ AccessDenied,
+ InvalidOptions,
+ };
+
+ /// IMPLEMENTATION NOTE: RemovePackageCatalogResult
+ /// Result of removing a package catalog.
+ [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 12)]
+ runtimeclass RemovePackageCatalogResult
+ {
+ RemovePackageCatalogStatus Status { get; };
+
+ /// Error codes
+ HRESULT ExtendedErrorCode { get; };
+ };
+
[contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)]
runtimeclass PackageManager
{
@@ -1370,6 +1494,19 @@ namespace Microsoft.Management.Deployment
/// (Installing, Installed) together at the same time.
PackageCatalogReference CreateCompositePackageCatalog(CreateCompositePackageCatalogOptions options);
+ [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 12)]
+ {
+ /// Add a catalog to the Windows Package Catalogs.
+ /// The progress value, represented as a double, indicates the percentage of add package catalog operation completion.
+ /// The progress range is from 0 to 100.
+ Windows.Foundation.IAsyncOperationWithProgress AddPackageCatalogAsync(AddPackageCatalogOptions options);
+
+ /// Unregisters a Package Catalog from the Windows Package Catalogs and eliminates the system artifacts based on the provided options.
+ /// The progress value, represented as a double, indicates the percentage of remove package catalog operation completion.
+ /// The progress range is from 0 to 100.
+ Windows.Foundation.IAsyncOperationWithProgress RemovePackageCatalogAsync(RemovePackageCatalogOptions options);
+ }
+
/// Install the specified package
Windows.Foundation.IAsyncOperationWithProgress InstallPackageAsync(CatalogPackage package, InstallOptions options);
diff --git a/src/Microsoft.Management.Deployment/Public/ComClsids.h b/src/Microsoft.Management.Deployment/Public/ComClsids.h
index 8d787d635f..75f14afbd6 100644
--- a/src/Microsoft.Management.Deployment/Public/ComClsids.h
+++ b/src/Microsoft.Management.Deployment/Public/ComClsids.h
@@ -15,6 +15,8 @@
#define WINGET_OUTOFPROC_COM_CLSID_DownloadOptions "4CBABE76-7322-4BE4-9CEA-2589A80682DC"
#define WINGET_OUTOFPROC_COM_CLSID_AuthenticationArguments "BA580786-BDE3-4F6C-B8F3-44698AC8711A"
#define WINGET_OUTOFPROC_COM_CLSID_RepairOptions "0498F441-3097-455F-9CAF-148F28293865"
+#define WINGET_OUTOFPROC_COM_CLSID_AddPackageCatalogOptions "DB9D012D-00D7-47EE-8FB1-606E10AC4F51"
+#define WINGET_OUTOFPROC_COM_CLSID_RemovePackageCatalogOptions "032B1C58-B975-469B-A013-E632B6ECE8D8"
#else
#define WINGET_OUTOFPROC_COM_CLSID_PackageManager "74CB3139-B7C5-4B9E-9388-E6616DEA288C"
#define WINGET_OUTOFPROC_COM_CLSID_FindPackagesOptions "1BD8FF3A-EC50-4F69-AEEE-DF4C9D3BAA96"
@@ -26,6 +28,8 @@
#define WINGET_OUTOFPROC_COM_CLSID_DownloadOptions "8EF324ED-367C-4880-83E5-BB2ABD0B72F6"
#define WINGET_OUTOFPROC_COM_CLSID_AuthenticationArguments "6484A61D-50FA-41F0-B71E-F4370C6EB37C"
#define WINGET_OUTOFPROC_COM_CLSID_RepairOptions "E62BB1E7-C7B2-4AEC-9E28-FB649B30FF03"
+#define WINGET_OUTOFPROC_COM_CLSID_AddPackageCatalogOptions "D58C7E4C-70E6-476C-A5D4-80341ED80252"
+#define WINGET_OUTOFPROC_COM_CLSID_RemovePackageCatalogOptions "87A96609-1A39-4955-BE72-7174E147B7DC"
#endif
// Clsids only used in in-proc invocation
@@ -44,6 +48,8 @@ namespace winrt::Microsoft::Management::Deployment
const CLSID WINGET_INPROC_COM_CLSID_DownloadOptions = { 0x4288DF96, 0xFDC9, 0x4B68, 0xB4, 0x03, 0x19, 0x3D, 0xBB, 0xF5, 0x6A, 0x24 }; // 4288DF96-FDC9-4B68-B403-193DBBF56A24
const CLSID WINGET_INPROC_COM_CLSID_AuthenticationArguments = { 0x8D593114, 0x1CF1, 0x43B9, 0x87, 0x22, 0x4D, 0xBB, 0x30, 0x10, 0x32, 0x96 }; // 8D593114-1CF1-43B9-8722-4DBB30103296
const CLSID WINGET_INPROC_COM_CLSID_RepairOptions = { 0x30c024c4, 0x852c, 0x4dd4, 0x98, 0x10, 0x13, 0x48, 0xc5, 0x1e, 0xf9, 0xbb }; // {30C024C4-852C-4DD4-9810-1348C51EF9BB}
+ const CLSID WINGET_INPROC_COM_CLSID_AddPackageCatalogOptions = { 0x24e6f1fa, 0xe4c3, 0x4acd, 0x96, 0x5d, 0xdf, 0x21, 0x3f, 0xd5, 0x8f, 0x15 }; // {24E6F1FA-E4C3-4ACD-965D-DF213FD58F15}
+ const CLSID WINGET_INPROC_COM_CLSID_RemovePackageCatalogOptions = { 0x1125d3a6, 0xe2ce, 0x479a, 0x91, 0xd5, 0x71, 0xa3, 0xf6, 0xf8, 0xb0, 0xb }; // {1125D3A6-E2CE-479A-91D5-71A3F6F8B00B}
CLSID GetRedirectedClsidFromInProcClsid(REFCLSID clsid);
}
diff --git a/src/Microsoft.Management.Deployment/RefreshPackageCatalogResult.cpp b/src/Microsoft.Management.Deployment/RefreshPackageCatalogResult.cpp
new file mode 100644
index 0000000000..7a0fe2c586
--- /dev/null
+++ b/src/Microsoft.Management.Deployment/RefreshPackageCatalogResult.cpp
@@ -0,0 +1,27 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#include "pch.h"
+#include "RefreshPackageCatalogResult.h"
+#include "RefreshPackageCatalogResult.g.cpp"
+#include
+
+namespace winrt::Microsoft::Management::Deployment::implementation
+{
+ void RefreshPackageCatalogResult::Initialize(
+ winrt::Microsoft::Management::Deployment::RefreshPackageCatalogStatus status,
+ winrt::hresult extendedErrorCode)
+ {
+ m_status = status;
+ m_extendedErrorCode = extendedErrorCode;
+ }
+
+ winrt::Microsoft::Management::Deployment::RefreshPackageCatalogStatus RefreshPackageCatalogResult::Status()
+ {
+ return m_status;
+ }
+
+ winrt::hresult RefreshPackageCatalogResult::ExtendedErrorCode()
+ {
+ return m_extendedErrorCode;
+ }
+}
diff --git a/src/Microsoft.Management.Deployment/RefreshPackageCatalogResult.h b/src/Microsoft.Management.Deployment/RefreshPackageCatalogResult.h
new file mode 100644
index 0000000000..08fd3cb448
--- /dev/null
+++ b/src/Microsoft.Management.Deployment/RefreshPackageCatalogResult.h
@@ -0,0 +1,27 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#pragma once
+#include "RefreshPackageCatalogResult.g.h"
+
+namespace winrt::Microsoft::Management::Deployment::implementation
+{
+ struct RefreshPackageCatalogResult : RefreshPackageCatalogResultT
+ {
+ RefreshPackageCatalogResult() = default;
+
+#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
+ void Initialize(
+ winrt::Microsoft::Management::Deployment::RefreshPackageCatalogStatus status,
+ winrt::hresult extendedErrorCode);
+#endif
+
+ winrt::Microsoft::Management::Deployment::RefreshPackageCatalogStatus Status();
+ winrt::hresult ExtendedErrorCode();
+
+#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
+ private:
+ winrt::Microsoft::Management::Deployment::RefreshPackageCatalogStatus m_status = winrt::Microsoft::Management::Deployment::RefreshPackageCatalogStatus::Ok;
+ winrt::hresult m_extendedErrorCode = S_OK;
+#endif
+ };
+}
diff --git a/src/Microsoft.Management.Deployment/RemovePackageCatalogOptions.cpp b/src/Microsoft.Management.Deployment/RemovePackageCatalogOptions.cpp
new file mode 100644
index 0000000000..e66d3dcb0f
--- /dev/null
+++ b/src/Microsoft.Management.Deployment/RemovePackageCatalogOptions.cpp
@@ -0,0 +1,35 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#include "pch.h"
+#pragma warning( push )
+#pragma warning ( disable : 4467 6388)
+// 6388 Allow CreateInstance.
+#include
+// 4467 Allow use of uuid attribute for com object creation.
+#include "RemovePackageCatalogOptions.h"
+#pragma warning( pop )
+#include "RemovePackageCatalogOptions.g.cpp"
+#include "Converters.h"
+#include "Helpers.h"
+
+namespace winrt::Microsoft::Management::Deployment::implementation
+{
+ hstring RemovePackageCatalogOptions::Name()
+ {
+ return hstring(m_name);
+ }
+ void RemovePackageCatalogOptions::Name(hstring const& value)
+ {
+ m_name = value;
+ }
+ bool RemovePackageCatalogOptions::PreserveData()
+ {
+ return m_preserveData;
+ }
+ void RemovePackageCatalogOptions::PreserveData(bool const& value)
+ {
+ m_preserveData = value;
+ }
+
+ CoCreatableMicrosoftManagementDeploymentClass(RemovePackageCatalogOptions);
+}
diff --git a/src/Microsoft.Management.Deployment/RemovePackageCatalogOptions.h b/src/Microsoft.Management.Deployment/RemovePackageCatalogOptions.h
new file mode 100644
index 0000000000..583043d6f1
--- /dev/null
+++ b/src/Microsoft.Management.Deployment/RemovePackageCatalogOptions.h
@@ -0,0 +1,35 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#pragma once
+#include "RemovePackageCatalogOptions.g.h"
+#include "public/ComClsids.h"
+
+namespace winrt::Microsoft::Management::Deployment::implementation
+{
+ [uuid(WINGET_OUTOFPROC_COM_CLSID_RemovePackageCatalogOptions)]
+ struct RemovePackageCatalogOptions : RemovePackageCatalogOptionsT
+ {
+ RemovePackageCatalogOptions() = default;
+
+ hstring Name();
+ void Name(hstring const& value);
+
+ bool PreserveData();
+ void PreserveData(bool const& value);
+
+#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
+ private:
+ hstring m_name = L"";
+ bool m_preserveData = false;
+#endif
+ };
+}
+
+#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
+namespace winrt::Microsoft::Management::Deployment::factory_implementation
+{
+ struct RemovePackageCatalogOptions : RemovePackageCatalogOptionsT
+ {
+ };
+}
+#endif
diff --git a/src/Microsoft.Management.Deployment/RemovePackageCatalogResult.cpp b/src/Microsoft.Management.Deployment/RemovePackageCatalogResult.cpp
new file mode 100644
index 0000000000..b74be4bf79
--- /dev/null
+++ b/src/Microsoft.Management.Deployment/RemovePackageCatalogResult.cpp
@@ -0,0 +1,25 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#include "pch.h"
+#include "RemovePackageCatalogResult.h"
+#include "RemovePackageCatalogResult.g.cpp"
+#include
+
+namespace winrt::Microsoft::Management::Deployment::implementation
+{
+ void RemovePackageCatalogResult::Initialize(
+ winrt::Microsoft::Management::Deployment::RemovePackageCatalogStatus status,
+ winrt::hresult extendedErrorCode)
+ {
+ m_status = status;
+ m_extendedErrorCode = extendedErrorCode;
+ }
+ winrt::Microsoft::Management::Deployment::RemovePackageCatalogStatus RemovePackageCatalogResult::Status()
+ {
+ return m_status;
+ }
+ winrt::hresult RemovePackageCatalogResult::ExtendedErrorCode()
+ {
+ return m_extendedErrorCode;
+ }
+}
diff --git a/src/Microsoft.Management.Deployment/RemovePackageCatalogResult.h b/src/Microsoft.Management.Deployment/RemovePackageCatalogResult.h
new file mode 100644
index 0000000000..1f00690e1e
--- /dev/null
+++ b/src/Microsoft.Management.Deployment/RemovePackageCatalogResult.h
@@ -0,0 +1,27 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#pragma once
+#include "RemovePackageCatalogResult.g.h"
+
+namespace winrt::Microsoft::Management::Deployment::implementation
+{
+ struct RemovePackageCatalogResult : RemovePackageCatalogResultT
+ {
+ RemovePackageCatalogResult() = default;
+
+#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
+ void Initialize(
+ winrt::Microsoft::Management::Deployment::RemovePackageCatalogStatus status,
+ winrt::hresult extendedErrorCode);
+#endif
+
+ winrt::Microsoft::Management::Deployment::RemovePackageCatalogStatus Status();
+ winrt::hresult ExtendedErrorCode();
+
+#if !defined(INCLUDE_ONLY_INTERFACE_METHODS)
+ private:
+ winrt::Microsoft::Management::Deployment::RemovePackageCatalogStatus m_status = winrt::Microsoft::Management::Deployment::RemovePackageCatalogStatus::Ok;
+ winrt::hresult m_extendedErrorCode = S_OK;
+#endif
+ };
+}
diff --git a/src/Microsoft.Management.Deployment/RepairOptions.h b/src/Microsoft.Management.Deployment/RepairOptions.h
index 2794d1f231..2b083bef6a 100644
--- a/src/Microsoft.Management.Deployment/RepairOptions.h
+++ b/src/Microsoft.Management.Deployment/RepairOptions.h
@@ -7,7 +7,7 @@
namespace winrt::Microsoft::Management::Deployment::implementation
{
[uuid(WINGET_OUTOFPROC_COM_CLSID_RepairOptions)]
- struct RepairOptions : RepairOptionsT
+ struct RepairOptions : RepairOptionsT
{
RepairOptions();
diff --git a/src/WindowsPackageManager/main.cpp b/src/WindowsPackageManager/main.cpp
index 21016db93d..751d75caa2 100644
--- a/src/WindowsPackageManager/main.cpp
+++ b/src/WindowsPackageManager/main.cpp
@@ -30,6 +30,8 @@ CoCreatableClassWrlCreatorMapInclude(PackageMatchFilter);
CoCreatableClassWrlCreatorMapInclude(AuthenticationArguments);
CoCreatableClassWrlCreatorMapInclude(PackageManagerSettings);
CoCreatableClassWrlCreatorMapInclude(RepairOptions);
+CoCreatableClassWrlCreatorMapInclude(AddPackageCatalogOptions);
+CoCreatableClassWrlCreatorMapInclude(RemovePackageCatalogOptions);
// Shim for configuration static functions
CoCreatableClassWrlCreatorMapInclude(ConfigurationStaticFunctionsShim);