From 4b4fbf69e143830143743b452408539e0b7ded4d Mon Sep 17 00:00:00 2001 From: Ryan Fu Date: Fri, 3 Feb 2023 13:26:20 -0800 Subject: [PATCH 1/4] add support for elevation requirement in COM --- .../Converters.cpp | 17 ++++++++++++++ .../Converters.h | 1 + .../PackageInstallerInfo.cpp | 4 ++++ .../PackageInstallerInfo.h | 2 ++ .../PackageManager.idl | 22 ++++++++++++++++++- 5 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Management.Deployment/Converters.cpp b/src/Microsoft.Management.Deployment/Converters.cpp index 2fe7071e63..e35f43bdfc 100644 --- a/src/Microsoft.Management.Deployment/Converters.cpp +++ b/src/Microsoft.Management.Deployment/Converters.cpp @@ -322,4 +322,21 @@ namespace winrt::Microsoft::Management::Deployment::implementation return ::AppInstaller::Manifest::ScopeEnum::Unknown; } + + winrt::Microsoft::Management::Deployment::ElevationRequirement GetDeploymentElevationRequirement(::AppInstaller::Manifest::ElevationRequirementEnum elevationRequirement) + { + switch (elevationRequirement) + { + case ::AppInstaller::Manifest::ElevationRequirementEnum::ElevationRequired: + return Microsoft::Management::Deployment::ElevationRequirement::ElevationRequired; + case ::AppInstaller::Manifest::ElevationRequirementEnum::ElevationProhibited: + return Microsoft::Management::Deployment::ElevationRequirement::ElevationProhibited; + case ::AppInstaller::Manifest::ElevationRequirementEnum::ElevatesSelf: + return Microsoft::Management::Deployment::ElevationRequirement::ElevatesSelf; + case ::AppInstaller::Manifest::ElevationRequirementEnum::Unknown: + return Microsoft::Management::Deployment::ElevationRequirement::Unknown; + } + + return Microsoft::Management::Deployment::ElevationRequirement::Unknown; + } } diff --git a/src/Microsoft.Management.Deployment/Converters.h b/src/Microsoft.Management.Deployment/Converters.h index f3ee6bd684..2baa29ed2d 100644 --- a/src/Microsoft.Management.Deployment/Converters.h +++ b/src/Microsoft.Management.Deployment/Converters.h @@ -21,6 +21,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation winrt::Microsoft::Management::Deployment::PackageInstallerType GetDeploymentInstallerType(::AppInstaller::Manifest::InstallerTypeEnum installerType); winrt::Microsoft::Management::Deployment::PackageInstallerScope GetDeploymentInstallerScope(::AppInstaller::Manifest::ScopeEnum installerScope); ::AppInstaller::Manifest::ScopeEnum GetManifestUninstallScope(winrt::Microsoft::Management::Deployment::PackageUninstallScope scope); + winrt::Microsoft::Management::Deployment::ElevationRequirement GetDeploymentElevationRequirement(::AppInstaller::Manifest::ElevationRequirementEnum elevationRequirement); #define WINGET_GET_OPERATION_RESULT_STATUS(_installResultStatus_, _uninstallResultStatus_) \ if constexpr (std::is_same_v) \ diff --git a/src/Microsoft.Management.Deployment/PackageInstallerInfo.cpp b/src/Microsoft.Management.Deployment/PackageInstallerInfo.cpp index 871fa806f7..01f55b9df2 100644 --- a/src/Microsoft.Management.Deployment/PackageInstallerInfo.cpp +++ b/src/Microsoft.Management.Deployment/PackageInstallerInfo.cpp @@ -33,4 +33,8 @@ namespace winrt::Microsoft::Management::Deployment::implementation { return winrt::to_hstring(m_manifestInstaller.Locale); } + winrt::Microsoft::Management::Deployment::ElevationRequirement PackageInstallerInfo::ElevationRequirement() + { + return GetDeploymentElevationRequirement(m_manifestInstaller.ElevationRequirement); + } } diff --git a/src/Microsoft.Management.Deployment/PackageInstallerInfo.h b/src/Microsoft.Management.Deployment/PackageInstallerInfo.h index 0a6aec276a..6a0021b6cf 100644 --- a/src/Microsoft.Management.Deployment/PackageInstallerInfo.h +++ b/src/Microsoft.Management.Deployment/PackageInstallerInfo.h @@ -19,6 +19,8 @@ namespace winrt::Microsoft::Management::Deployment::implementation winrt::Windows::System::ProcessorArchitecture Architecture(); winrt::Microsoft::Management::Deployment::PackageInstallerScope Scope(); hstring Locale(); + // Contract 6.0 + winrt::Microsoft::Management::Deployment::ElevationRequirement ElevationRequirement(); #if !defined(INCLUDE_ONLY_INTERFACE_METHODS) private: diff --git a/src/Microsoft.Management.Deployment/PackageManager.idl b/src/Microsoft.Management.Deployment/PackageManager.idl index 87c15c62cf..8dd7276f97 100644 --- a/src/Microsoft.Management.Deployment/PackageManager.idl +++ b/src/Microsoft.Management.Deployment/PackageManager.idl @@ -335,6 +335,20 @@ namespace Microsoft.Management.Deployment System, }; + /// The package installer elevation requirement. + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 6)] + enum ElevationRequirement + { + /// Elevation requirement not declared. + Unknown, + /// Package installer requires elevation. + ElevationRequired, + /// Package installer prohibits elevation. + ElevationProhibited, + /// Package installer elevates self. + ElevatesSelf, + }; + /// Interface for retrieving information about a package installer. [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 5)] runtimeclass PackageInstallerInfo @@ -348,7 +362,13 @@ namespace Microsoft.Management.Deployment /// The package installer scope. PackageInstallerScope Scope { get; }; /// The package installer locale. - String Locale{ get; }; + String Locale { get; }; + + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 6)] + { + /// The package installer elevation requirement. + ElevationRequirement ElevationRequirement { get; }; + } }; /// The installed status type. The values need to match InstalledStatusType from winget/RepositorySearch.h. From 708cc7b9bcb20df30cbef279632f028dd825fa39 Mon Sep 17 00:00:00 2001 From: Ryan Fu Date: Wed, 8 Feb 2023 13:13:39 -0800 Subject: [PATCH 2/4] add e2e tests and get applicable installer api --- .../Interop/InstallInterop.cs | 37 +++++++++++++++++++ ...TestZipInstaller_PackageInstallerInfo.yaml | 21 +++++++++++ .../PackageManager.idl | 7 ++++ .../PackageVersionInfo.cpp | 21 +++++++++++ .../PackageVersionInfo.h | 2 + 5 files changed, 88 insertions(+) create mode 100644 src/AppInstallerCLIE2ETests/TestData/Manifests/TestZipInstaller_PackageInstallerInfo.yaml diff --git a/src/AppInstallerCLIE2ETests/Interop/InstallInterop.cs b/src/AppInstallerCLIE2ETests/Interop/InstallInterop.cs index cbb814e519..5b02fb3e76 100644 --- a/src/AppInstallerCLIE2ETests/Interop/InstallInterop.cs +++ b/src/AppInstallerCLIE2ETests/Interop/InstallInterop.cs @@ -12,6 +12,7 @@ namespace AppInstallerCLIE2ETests.Interop using Microsoft.Management.Deployment; using Microsoft.Management.Deployment.Projection; using NUnit.Framework; + using Windows.System; /// /// Install interop. @@ -516,5 +517,41 @@ public async Task InstallRequireUserScopeAndUnknown() // Assert Assert.AreEqual(InstallResultStatus.Ok, installResult.Status); } + + /// + /// Test to verify the GetApplicableInstaller() COM call returns the correct manifest installer metadata. + /// + [Test] + public void GetApplicableInstaller() + { + // Find package + var searchResult = this.FindAllPackages(this.testSource, PackageMatchField.Id, PackageFieldMatchOption.Equals, "AppInstallerTest.PackageInstallerInfo"); + Assert.AreEqual(1, searchResult.Count); + + // Configure installation + var catalogPackage = searchResult[0].CatalogPackage; + var packageVersionId = catalogPackage.AvailableVersions[0]; + var packageVersionInfo = catalogPackage.GetPackageVersionInfo(packageVersionId); + + // Use install options with no applicable match. + var badInstallOptions = this.TestFactory.CreateInstallOptions(); + badInstallOptions.PackageInstallScope = PackageInstallScope.System; + + Assert.IsNull(packageVersionInfo.GetApplicableInstaller(badInstallOptions)); + + // Use install options with valid applicable match. + var installOptions = this.TestFactory.CreateInstallOptions(); + installOptions.PackageInstallScope = PackageInstallScope.User; + var packageInstallerInfo = packageVersionInfo.GetApplicableInstaller(installOptions); + + // Assert + Assert.IsNotNull(packageInstallerInfo); + Assert.AreEqual(ElevationRequirement.ElevationRequired, packageInstallerInfo.ElevationRequirement); + Assert.AreEqual(ProcessorArchitecture.X64, packageInstallerInfo.Architecture); + Assert.AreEqual(PackageInstallerType.Zip, packageInstallerInfo.InstallerType); + Assert.AreEqual(PackageInstallerType.Exe, packageInstallerInfo.NestedInstallerType); + Assert.AreEqual(PackageInstallScope.User, packageInstallerInfo.Scope); + Assert.AreEqual("en-US", packageInstallerInfo.Locale); + } } } \ No newline at end of file diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestZipInstaller_PackageInstallerInfo.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestZipInstaller_PackageInstallerInfo.yaml new file mode 100644 index 0000000000..ad91b12b1f --- /dev/null +++ b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestZipInstaller_PackageInstallerInfo.yaml @@ -0,0 +1,21 @@ +# Test manifest for verifying the behavior of retrieving a PackageInstallerInfo COM object. +PackageIdentifier: AppInstallerTest.PackageInstallerInfo +PackageVersion: 1.0.0.0 +PackageName: TestPackageInstallerInfo +PackageLocale: en-US +Publisher: AppInstallerTest +License: Test +ShortDescription: E2E test for PackageInstallerInfo COM object. +Installers: + - Architecture: x64 + Scope: User + InstallerUrl: https://localhost:5001/TestKit/AppInstallerTestZipInstaller/AppInstallerTestZipInstaller.zip + InstallerType: zip + InstallerSha256: + NestedInstallerType: exe + NestedInstallerFiles: + - RelativeFilePath: AppInstallerTestExeInstaller.exe + ElevationRequirement: elevationRequired + InstallerLocale: en-US +ManifestType: singleton +ManifestVersion: 1.4.0 \ No newline at end of file diff --git a/src/Microsoft.Management.Deployment/PackageManager.idl b/src/Microsoft.Management.Deployment/PackageManager.idl index 8dd7276f97..135277667d 100644 --- a/src/Microsoft.Management.Deployment/PackageManager.idl +++ b/src/Microsoft.Management.Deployment/PackageManager.idl @@ -280,6 +280,13 @@ namespace Microsoft.Management.Deployment /// a lot of fields and no one requesting it. /// Gets the manifest of this package version. /// virtual Manifest::Manifest GetManifest() = 0; + + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 6)] + { + /// Gets the applicable installer for this package version. + PackageInstallerInfo GetApplicableInstaller(InstallOptions options); + + } } /// IMPLEMENTATION NOTE: PackageVersionKey from winget/RepositorySearch.h diff --git a/src/Microsoft.Management.Deployment/PackageVersionInfo.cpp b/src/Microsoft.Management.Deployment/PackageVersionInfo.cpp index 0d8dcbfb59..4bb1ab9c79 100644 --- a/src/Microsoft.Management.Deployment/PackageVersionInfo.cpp +++ b/src/Microsoft.Management.Deployment/PackageVersionInfo.cpp @@ -7,6 +7,7 @@ #include "PackageVersionInfo.g.cpp" #include "PackageCatalogInfo.h" #include "PackageCatalog.h" +#include "PackageInstallerInfo.h" #include "CatalogPackage.h" #include "ComContext.h" #include "Workflows/WorkflowBase.h" @@ -138,4 +139,24 @@ namespace winrt::Microsoft::Management::Deployment::implementation { return m_packageVersion; } + winrt::Microsoft::Management::Deployment::PackageInstallerInfo PackageVersionInfo::GetApplicableInstaller(InstallOptions options) + { + AppInstaller::CLI::Execution::COMContext context; + PopulateContextFromInstallOptions(&context, options); + AppInstaller::Repository::IPackageVersion::Metadata installationMetadata; + AppInstaller::CLI::Workflow::ManifestComparator manifestComparator{ context, installationMetadata }; + AppInstaller::Manifest::Manifest manifest = m_packageVersion->GetManifest(); + auto result = manifestComparator.GetPreferredInstaller(manifest); + + if (result.installer.has_value()) + { + auto packageInstallerInfo = winrt::make_self>(); + packageInstallerInfo->Initialize(result.installer.value()); + return *packageInstallerInfo; + } + else + { + return NULL; + } + } } diff --git a/src/Microsoft.Management.Deployment/PackageVersionInfo.h b/src/Microsoft.Management.Deployment/PackageVersionInfo.h index c0bb708ac6..1cf9a9bc54 100644 --- a/src/Microsoft.Management.Deployment/PackageVersionInfo.h +++ b/src/Microsoft.Management.Deployment/PackageVersionInfo.h @@ -26,6 +26,8 @@ namespace winrt::Microsoft::Management::Deployment::implementation winrt::Microsoft::Management::Deployment::CompareResult CompareToVersion(hstring versionString); // Contract version 4 bool HasApplicableInstaller(InstallOptions options); + // Contract version 6 + winrt::Microsoft::Management::Deployment::PackageInstallerInfo GetApplicableInstaller(InstallOptions options); #if !defined(INCLUDE_ONLY_INTERFACE_METHODS) private: From 8ab91d839b90ca143793a7ca8825019f17ea1d4e Mon Sep 17 00:00:00 2001 From: Ryan Fu Date: Wed, 8 Feb 2023 14:01:47 -0800 Subject: [PATCH 3/4] fix enum check --- src/AppInstallerCLIE2ETests/Interop/InstallInterop.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AppInstallerCLIE2ETests/Interop/InstallInterop.cs b/src/AppInstallerCLIE2ETests/Interop/InstallInterop.cs index 5b02fb3e76..274a9e9353 100644 --- a/src/AppInstallerCLIE2ETests/Interop/InstallInterop.cs +++ b/src/AppInstallerCLIE2ETests/Interop/InstallInterop.cs @@ -550,7 +550,7 @@ public void GetApplicableInstaller() Assert.AreEqual(ProcessorArchitecture.X64, packageInstallerInfo.Architecture); Assert.AreEqual(PackageInstallerType.Zip, packageInstallerInfo.InstallerType); Assert.AreEqual(PackageInstallerType.Exe, packageInstallerInfo.NestedInstallerType); - Assert.AreEqual(PackageInstallScope.User, packageInstallerInfo.Scope); + Assert.AreEqual(PackageInstallerScope.User, packageInstallerInfo.Scope); Assert.AreEqual("en-US", packageInstallerInfo.Locale); } } From 12a9896c635a804301f7c8b0b8785cec7370ab48 Mon Sep 17 00:00:00 2001 From: Ryan Fu Date: Mon, 13 Feb 2023 00:03:04 -0800 Subject: [PATCH 4/4] respond to comments --- src/AppInstallerCLIE2ETests/Interop/InstallInterop.cs | 3 +-- src/Microsoft.Management.Deployment/PackageManager.idl | 7 ------- .../PackageVersionInfo.cpp | 10 +++++----- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/AppInstallerCLIE2ETests/Interop/InstallInterop.cs b/src/AppInstallerCLIE2ETests/Interop/InstallInterop.cs index 274a9e9353..fe05c48c92 100644 --- a/src/AppInstallerCLIE2ETests/Interop/InstallInterop.cs +++ b/src/AppInstallerCLIE2ETests/Interop/InstallInterop.cs @@ -12,7 +12,6 @@ namespace AppInstallerCLIE2ETests.Interop using Microsoft.Management.Deployment; using Microsoft.Management.Deployment.Projection; using NUnit.Framework; - using Windows.System; /// /// Install interop. @@ -547,7 +546,7 @@ public void GetApplicableInstaller() // Assert Assert.IsNotNull(packageInstallerInfo); Assert.AreEqual(ElevationRequirement.ElevationRequired, packageInstallerInfo.ElevationRequirement); - Assert.AreEqual(ProcessorArchitecture.X64, packageInstallerInfo.Architecture); + Assert.AreEqual(Windows.System.ProcessorArchitecture.X64, packageInstallerInfo.Architecture); Assert.AreEqual(PackageInstallerType.Zip, packageInstallerInfo.InstallerType); Assert.AreEqual(PackageInstallerType.Exe, packageInstallerInfo.NestedInstallerType); Assert.AreEqual(PackageInstallerScope.User, packageInstallerInfo.Scope); diff --git a/src/Microsoft.Management.Deployment/PackageManager.idl b/src/Microsoft.Management.Deployment/PackageManager.idl index 135277667d..a9cc6f400e 100644 --- a/src/Microsoft.Management.Deployment/PackageManager.idl +++ b/src/Microsoft.Management.Deployment/PackageManager.idl @@ -274,18 +274,11 @@ namespace Microsoft.Management.Deployment /// Gets the publisher string for this package version, if one is available. String Publisher { get; }; } - - /// DESIGN NOTE: - /// GetManifest from IPackageVersion in winget/RepositorySearch 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; [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 6)] { /// Gets the applicable installer for this package version. PackageInstallerInfo GetApplicableInstaller(InstallOptions options); - } } diff --git a/src/Microsoft.Management.Deployment/PackageVersionInfo.cpp b/src/Microsoft.Management.Deployment/PackageVersionInfo.cpp index 4bb1ab9c79..a541133bee 100644 --- a/src/Microsoft.Management.Deployment/PackageVersionInfo.cpp +++ b/src/Microsoft.Management.Deployment/PackageVersionInfo.cpp @@ -28,6 +28,10 @@ namespace winrt::Microsoft::Management::Deployment::implementation { m_packageVersion = std::move(packageVersion); } + std::shared_ptr<::AppInstaller::Repository::IPackageVersion> PackageVersionInfo::GetRepositoryPackageVersion() + { + return m_packageVersion; + } hstring PackageVersionInfo::GetMetadata(winrt::Microsoft::Management::Deployment::PackageVersionMetadataField const& metadataField) { ::AppInstaller::Repository::PackageVersionMetadata metadataKey = GetRepositoryPackageVersionMetadata(metadataField); @@ -135,10 +139,6 @@ namespace winrt::Microsoft::Management::Deployment::implementation auto result = manifestComparator.GetPreferredInstaller(manifest); return result.installer.has_value(); } - std::shared_ptr<::AppInstaller::Repository::IPackageVersion> PackageVersionInfo::GetRepositoryPackageVersion() - { - return m_packageVersion; - } winrt::Microsoft::Management::Deployment::PackageInstallerInfo PackageVersionInfo::GetApplicableInstaller(InstallOptions options) { AppInstaller::CLI::Execution::COMContext context; @@ -156,7 +156,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation } else { - return NULL; + return nullptr; } } }