diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt
index 7d1718f3d7..45190c8548 100644
--- a/.github/actions/spelling/allow.txt
+++ b/.github/actions/spelling/allow.txt
@@ -37,6 +37,7 @@ aspnet
authn
authz
autocomplete
+AUTOLISTEN
auxdata
azureedge
backend
@@ -202,6 +203,7 @@ hcertstore
HCRYPTMSG
hfile
HGLOBAL
+HGlobal
HIDECANCEL
hinternet
HKCU
@@ -228,6 +230,7 @@ IDX
IFACEMETHOD
ifdef
ifndef
+ifspec
ifstream
IIS
impl
@@ -246,9 +249,11 @@ INSTALLPATH
INSTALLUILEVEL
interop
INVALIDARG
+INVALIDSID
iomanip
iostream
IPortable
+ipmo
ISAPPROVEDFOROUTPUT
isspace
istream
@@ -311,6 +316,8 @@ msixmgr
msixsdk
msixsdkx
msixtest
+MSHCTX
+MSHLFLAGS
msrc
Multifile
Multimatch
@@ -318,6 +325,7 @@ mutex
mutexes
namespace
namespaces
+ncacn
Nelon
netcoreapp
netstandard
@@ -395,18 +403,23 @@ preindexed
prepareforpackaging
PRIMARYKEY
prioritization
+processthreadsapi
PRODUCTNAME
PRODUCTVERSION
PROGRAMFILES
PROGRESSONLY
promptrestart
PROPERTYDUMP
+PROTSEQ
+Protseq
psz
+PTOKEN
ptr
publiccontainer
PUCHAR
PVOID
pwa
+pwsh
QCol
RAII
rclsid
@@ -438,6 +451,7 @@ RESTSOURCE
resw
resx
rethrowing
+REQS
roadmap
robuffer
rowcount
@@ -473,7 +487,9 @@ SHELLEXEC
SHELLEXECUTEINFO
SHELLEXECUTEINFOA
SHELLEXECUTEINFOW
+shlobj
Shlwapi
+shtypes
signtool
silentwithprogress
simplesave
@@ -497,6 +513,7 @@ src
srwlock
sscanf
sstream
+STARTUPINFO
STATEACTION
STATFLAG
STATSTG
@@ -589,6 +606,7 @@ UIA
UIF
uint
Uknown
+ULARGE
ulong
ULONGLONG
uncomment
@@ -598,6 +616,7 @@ unicode
UNICODESTRING
uninstall
uninstalling
+Unmarshal
Unregister
Unregisters
untimes
@@ -669,6 +688,7 @@ WStr
wstring
wstringstream
WTD
+wtypesbase
www
xamarin
xaml
diff --git a/.gitignore b/.gitignore
index 20106aeb70..409d93039d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -329,3 +329,8 @@ ASALocalRun/
# MFractors (Xamarin productivity tool) working folder
.mfractor/
+
+# Generated files from WinGetServer.idl
+**/WinGetServer/WinGetServer.h
+**/WinGetServer/WinGetServer_c.c
+**/WinGetServer/WinGetServer_s.c
\ No newline at end of file
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index ac86b3c968..5a84030b20 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -213,12 +213,6 @@ jobs:
CleanTargetFolder: false
OverWrite: true
- - template: templates/e2e-test.template.yml
- parameters:
- title: "E2E Tests Packaged"
- isPackaged: true
- filter: "TestCategory!=InProcess&TestCategory!=OutOfProcess"
-
- task: PowerShell@2
displayName: 'Set program files directory'
inputs:
@@ -238,12 +232,6 @@ jobs:
TargetFolder: '$(platformProgramFiles)\dotnet'
Contents: resources.pri
- - template: templates/e2e-test.template.yml
- parameters:
- title: "COM API E2E Tests (In-process)"
- isPackaged: false
- filter: "TestCategory=InProcess"
-
# Winmd accessed by test runner process (dotnet.exe)
- task: CopyFiles@2
displayName: 'Copy winmd to dotnet directory'
@@ -260,6 +248,18 @@ jobs:
TargetFolder: 'src\AppInstallerCLIPackage\bin\$(buildPlatform)\$(buildConfiguration)'
Contents: Microsoft.Management.Deployment.winmd
+ - template: templates/e2e-test.template.yml
+ parameters:
+ title: "E2E Tests Packaged"
+ isPackaged: true
+ filter: "TestCategory!=InProcess&TestCategory!=OutOfProcess"
+
+ - template: templates/e2e-test.template.yml
+ parameters:
+ title: "COM API E2E Tests (In-process)"
+ isPackaged: false
+ filter: "TestCategory=InProcess"
+
- template: templates/e2e-test.template.yml
parameters:
title: "COM API E2E Tests (Out-of-process)"
@@ -305,6 +305,7 @@ jobs:
inputs:
filePath: 'src\PowerShell\Microsoft.WinGet.Client\Copy-PlatformBinaries.ps1'
arguments: '-Platform $(buildPlatform) -Configuration $(buildConfiguration) -OutDir $(artifactsDir)\PowerShell'
+ condition: always()
- task: PublishPipelineArtifact@1
displayName: Publish Pipeline Artifacts
diff --git a/src/AppInstallerCLI.sln b/src/AppInstallerCLI.sln
index fcf90a0e76..f4464441ab 100644
--- a/src/AppInstallerCLI.sln
+++ b/src/AppInstallerCLI.sln
@@ -134,6 +134,9 @@ EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Management.Deployment.Projection", "Microsoft.Management.Deployment.Projection\Microsoft.Management.Deployment.Projection.csproj", "{0B104762-5CD8-47EE-A904-71C1C3F84DCD}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UndockedRegFreeWinRT", "Xlang\UndockedRegFreeWinRT\src\UndockedRegFreeWinRT\UndockedRegFreeWinRT\UndockedRegFreeWinRT.vcxproj", "{31ED69A8-5310-45A9-953F-56C351D2C3E1}"
+ ProjectSection(ProjectDependencies) = postProject
+ {2B00D362-AC92-41F3-A8D2-5B1599BDCA01} = {2B00D362-AC92-41F3-A8D2-5B1599BDCA01}
+ EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Detours", "Xlang\UndockedRegFreeWinRT\src\UndockedRegFreeWinRT\detours\detours.vcxproj", "{787EC629-C0FB-4BA9-9746-4A82CD06B73E}"
EndProject
@@ -992,8 +995,8 @@ Global
{31ED69A8-5310-45A9-953F-56C351D2C3E1}.Release|ARM64.ActiveCfg = Debug|Win32
{31ED69A8-5310-45A9-953F-56C351D2C3E1}.Release|x64.ActiveCfg = Release|x64
{31ED69A8-5310-45A9-953F-56C351D2C3E1}.Release|x64.Build.0 = Release|x64
- {31ED69A8-5310-45A9-953F-56C351D2C3E1}.Release|x86.ActiveCfg = Debug|Win32
- {31ED69A8-5310-45A9-953F-56C351D2C3E1}.Release|x86.Build.0 = Debug|Win32
+ {31ED69A8-5310-45A9-953F-56C351D2C3E1}.Release|x86.ActiveCfg = Release|Win32
+ {31ED69A8-5310-45A9-953F-56C351D2C3E1}.Release|x86.Build.0 = Release|Win32
{31ED69A8-5310-45A9-953F-56C351D2C3E1}.TestRelease|Any CPU.ActiveCfg = Debug|Win32
{31ED69A8-5310-45A9-953F-56C351D2C3E1}.TestRelease|Any CPU.Build.0 = Debug|Win32
{31ED69A8-5310-45A9-953F-56C351D2C3E1}.TestRelease|ARM.ActiveCfg = Debug|Win32
diff --git a/src/AppInstallerCLIE2ETests/Constants.cs b/src/AppInstallerCLIE2ETests/Constants.cs
index 68abf6193a..6cd28185c0 100644
--- a/src/AppInstallerCLIE2ETests/Constants.cs
+++ b/src/AppInstallerCLIE2ETests/Constants.cs
@@ -17,6 +17,7 @@ public class Constants
public const string MsiInstallerPathParameter = "MsiTestInstallerPath";
public const string MsixInstallerPathParameter = "MsixTestInstallerPath";
public const string PackageCertificatePathParameter = "PackageCertificatePath";
+ public const string PowerShellModulePathParameter = "PowerShellModulePath";
public const string AppInstallerTestCert = "AppInstallerTest.cer";
public const string AppInstallerTestCertThumbprint = "d03e7a688b388b1edde8476a627531c49db88017";
@@ -74,6 +75,16 @@ public class Constants
public const string TestExeUninstallerFileName = "UninstallTestExe.bat";
public const string TestExeUninstalledFileName = "TestExeUninstalled.txt";
+ // PowerShell Cmdlets
+ public const string FindCmdlet = "Find-WinGetPackage";
+ public const string GetCmdlet = "Get-WinGetPackage";
+ public const string GetSourceCmdlet = "Get-WinGetSource";
+ public const string InstallCmdlet = "Install-WinGetPackage";
+ public const string UninstallCmdlet = "Uninstall-WinGetPackage";
+ public const string UpdateCmdlet = "Update-WinGetPackage";
+
+ public const string WindowsPackageManagerServer = "WindowsPackageManagerServer";
+
// Locations
public const string LocalAppData = "LocalAppData";
diff --git a/src/AppInstallerCLIE2ETests/PowerShell/PowerShellModule.cs b/src/AppInstallerCLIE2ETests/PowerShell/PowerShellModule.cs
new file mode 100644
index 0000000000..e3eda5af2a
--- /dev/null
+++ b/src/AppInstallerCLIE2ETests/PowerShell/PowerShellModule.cs
@@ -0,0 +1,177 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace AppInstallerCLIE2ETests.PowerShell
+{
+ using NUnit.Framework;
+ using System;
+ using System.Diagnostics;
+ using System.Linq;
+
+ ///
+ /// Basic E2E smoke tests for verifying the behavior of the PowerShell module cmdlets.
+ /// Running the x86 PowerShell Module requires PowerShell Core (x86). These tests currently only target PowerShell Core (x64)
+ ///
+ [Category("PowerShell")]
+ public class PowerShellModule
+ {
+ // TODO: Consider using Pester framework for conducting more extensive PowerShell module tests.
+
+ [OneTimeSetUp]
+ public void Setup()
+ {
+ TestCommon.RunAICLICommand("source add", $"-n {Constants.TestSourceName} {Constants.TestSourceUrl}");
+ }
+
+ [OneTimeTearDown]
+ public void TearDown()
+ {
+ // TODO: This is a workaround to an issue where the server takes longer than expected to terminate when
+ // running from the E2E tests. This can cause other E2E tests to fail when attempting to reset the test source.
+ if (IsRunning(Constants.WindowsPackageManagerServer))
+ {
+ // There should only be one WinGetServer process running at a time.
+ Process serverProcess = Process.GetProcessesByName(Constants.WindowsPackageManagerServer).First();
+ serverProcess.Kill();
+ }
+
+ TestCommon.RunAICLICommand("source remove", $"{Constants.TestSourceName}");
+ }
+
+ [Test]
+ public void AssertServerShutdownAfterExecution()
+ {
+ if (!Environment.Is64BitProcess)
+ {
+ return;
+ }
+
+ var result = TestCommon.RunPowerShellCommandWithResult(Constants.GetSourceCmdlet, $"-Name {Constants.TestSourceName}");
+ Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode, $"ExitCode: {result.ExitCode} Failed with the following output: {result.StdOut}, {result.StdErr}");
+
+ Assert.IsTrue(IsRunning(Constants.WindowsPackageManagerServer), $"{Constants.WindowsPackageManagerServer} is not running.");
+ Process serverProcess = Process.GetProcessesByName(Constants.WindowsPackageManagerServer).First();
+
+ // Wait a maximum of 30 seconds for the server process to exit.
+ bool serverProcessExit = serverProcess.WaitForExit(30000);
+ Assert.IsTrue(serverProcessExit, $"{Constants.WindowsPackageManagerServer} failed to terminate after creating COM object.");
+ }
+
+ [Test]
+ public void GetWinGetSource()
+ {
+ if (!Environment.Is64BitProcess)
+ {
+ return;
+ }
+
+ var getSourceResult = TestCommon.RunPowerShellCommandWithResult(Constants.GetSourceCmdlet, $"-Name {Constants.TestSourceName}");
+ Assert.AreEqual(Constants.ErrorCode.S_OK, getSourceResult.ExitCode, $"ExitCode: {getSourceResult.ExitCode} Failed with the following output: {getSourceResult.StdOut}, {getSourceResult.StdErr}");
+ Assert.IsTrue(getSourceResult.StdOut.Contains($"{Constants.TestSourceName}"));
+ }
+
+ [Test]
+ public void FindWinGetPackage()
+ {
+ if (!Environment.Is64BitProcess)
+ {
+ return;
+ }
+
+ var result = TestCommon.RunPowerShellCommandWithResult(Constants.FindCmdlet, $"-Id {Constants.ExeInstallerPackageId}");
+ Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode, $"ExitCode: {result.ExitCode} Failed with the following output: {result.StdOut}; {result.StdErr}");
+ Assert.IsTrue(result.StdOut.Contains("TestExeInstaller"));
+ }
+
+ [Test]
+ public void GetWinGetPackage()
+ {
+ if (!Environment.Is64BitProcess)
+ {
+ return;
+ }
+
+ var installResult = TestCommon.RunPowerShellCommandWithResult(Constants.InstallCmdlet, $"-Id {Constants.MsiInstallerPackageId}");
+ var getResult = TestCommon.RunPowerShellCommandWithResult(Constants.GetCmdlet, $"-Id {Constants.MsiInstallerPackageId}");
+ var uninstallResult = TestCommon.RunPowerShellCommandWithResult(Constants.UninstallCmdlet, $"-Id {Constants.MsiInstallerPackageId}");
+
+ Assert.AreEqual(Constants.ErrorCode.S_OK, installResult.ExitCode, $"ExitCode: {installResult.ExitCode}; Failed with the following output: {installResult.StdOut}; {installResult.StdErr}");
+ Assert.AreEqual(Constants.ErrorCode.S_OK, getResult.ExitCode, $"Failed with the following output: {getResult.StdOut}");
+ Assert.AreEqual(Constants.ErrorCode.S_OK, uninstallResult.ExitCode, $"Failed with the following output: {uninstallResult.StdOut}");
+
+ Assert.IsTrue(!string.IsNullOrEmpty(installResult.StdOut));
+ Assert.IsTrue(getResult.StdOut.Contains("TestMsiInstaller"));
+ Assert.IsTrue(!string.IsNullOrEmpty(uninstallResult.StdOut));
+ }
+
+ [Test]
+ public void InstallWinGetPackage()
+ {
+ if (!Environment.Is64BitProcess)
+ {
+ return;
+ }
+
+ var installResult = TestCommon.RunPowerShellCommandWithResult(Constants.InstallCmdlet, $"-Id {Constants.ExeInstallerPackageId}");
+ var uninstallResult = TestCommon.RunPowerShellCommandWithResult(Constants.UninstallCmdlet, $"-Id {Constants.ExeInstallerPackageId}");
+
+ Assert.AreEqual(Constants.ErrorCode.S_OK, installResult.ExitCode, $"ExitCode: {installResult.ExitCode}; Failed with the following output: {installResult.StdOut}; {installResult.StdErr}");
+ Assert.AreEqual(Constants.ErrorCode.S_OK, uninstallResult.ExitCode, $"Failed with the following output: {uninstallResult.StdOut}");
+
+ Assert.IsTrue(!string.IsNullOrEmpty(installResult.StdOut));
+ Assert.IsTrue(!string.IsNullOrEmpty(uninstallResult.StdOut));
+ }
+
+ [Test]
+ public void UpdateWinGetPackage()
+ {
+ if (!Environment.Is64BitProcess)
+ {
+ return;
+ }
+
+ var installResult = TestCommon.RunPowerShellCommandWithResult(Constants.InstallCmdlet, $"-Id {Constants.ExeInstallerPackageId} -Version 1.0.0.0");
+ var updateResult = TestCommon.RunPowerShellCommandWithResult(Constants.UpdateCmdlet, $"-Id {Constants.ExeInstallerPackageId}");
+ var getResult = TestCommon.RunPowerShellCommandWithResult(Constants.GetCmdlet, $"-Id {Constants.ExeInstallerPackageId}");
+ var uninstallResult = TestCommon.RunPowerShellCommandWithResult(Constants.UninstallCmdlet, $"-Id {Constants.ExeInstallerPackageId}");
+
+ Assert.AreEqual(Constants.ErrorCode.S_OK, installResult.ExitCode, $"Failed with the following output: {installResult.StdOut}");
+ Assert.AreEqual(Constants.ErrorCode.S_OK, updateResult.ExitCode, $"Failed with the following output: {updateResult.StdOut}");
+ Assert.AreEqual(Constants.ErrorCode.S_OK, getResult.ExitCode, $"Failed with the following output: {getResult.StdOut}");
+ Assert.AreEqual(Constants.ErrorCode.S_OK, uninstallResult.ExitCode, $"Failed with the following output: {uninstallResult.StdOut}");
+
+ Assert.IsTrue(!string.IsNullOrEmpty(installResult.StdOut));
+ Assert.IsTrue(!string.IsNullOrEmpty(updateResult.StdOut));
+ Assert.IsTrue(getResult.StdOut.Contains("2.0.0.0"));
+ Assert.IsTrue(!string.IsNullOrEmpty(uninstallResult.StdOut));
+ }
+
+ ///
+ /// There is a known issue where the server takes an abnormally long time to terminate after the E2E test pwsh processes finish execution.
+ /// This test verifies that the server does indeed terminate within 5 minutes after running all of the cmdlets.
+ /// Commented out to reduce the overall duration of the build pipeline.
+ ///
+ // [Test]
+ public void VerifyServerTermination()
+ {
+ TestCommon.RunPowerShellCommandWithResult(Constants.GetSourceCmdlet, $"-Name {Constants.TestSourceName}");
+ TestCommon.RunPowerShellCommandWithResult(Constants.FindCmdlet, $"-Id {Constants.ExeInstallerPackageId}");
+ TestCommon.RunPowerShellCommandWithResult(Constants.InstallCmdlet, $"-Id {Constants.ExeInstallerPackageId} -Version 1.0.0.0");
+ TestCommon.RunPowerShellCommandWithResult(Constants.UpdateCmdlet, $"-Id {Constants.ExeInstallerPackageId}");
+ TestCommon.RunPowerShellCommandWithResult(Constants.GetCmdlet, $"-Id {Constants.ExeInstallerPackageId}");
+ TestCommon.RunPowerShellCommandWithResult(Constants.UninstallCmdlet, $"-Id {Constants.ExeInstallerPackageId}");
+
+ Assert.IsTrue(IsRunning(Constants.WindowsPackageManagerServer), $"{Constants.WindowsPackageManagerServer} is not running.");
+ Process serverProcess = Process.GetProcessesByName(Constants.WindowsPackageManagerServer).First();
+
+ // Wait a maximum of 5 minutes for the server process to exit.
+ bool serverProcessExit = serverProcess.WaitForExit(300000);
+ Assert.IsTrue(serverProcessExit, $"{Constants.WindowsPackageManagerServer} failed to terminate after creating COM object.");
+ }
+
+ private bool IsRunning(string processName)
+ {
+ return Process.GetProcessesByName(processName).Length > 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/AppInstallerCLIE2ETests/README.md b/src/AppInstallerCLIE2ETests/README.md
index 6b07a0a552..a6417e5918 100644
--- a/src/AppInstallerCLIE2ETests/README.md
+++ b/src/AppInstallerCLIE2ETests/README.md
@@ -56,7 +56,8 @@ Therefore to run the executable in the command line, simply change into the dire
| StaticFileRootPath | Path to the set of static test files that will be served as the source for testing purposes. This path should be identical to the one provided to the LocalHostWebServer|
| MsixTestInstallerPath | The MSIX (or APPX) Installer executable under test. |
| ExeTestInstallerPath |The Exe Installer executable under test. |
-| PackageCertificatePath |Signing Certificate Path used to certify test index source package|
+| PackageCertificatePath | Signing Certificate Path used to certify test index source package |
+| PowerShellModulePath | Path to the PowerShell module manifest file under test |
#### Example of Test.runsettings format:
@@ -72,6 +73,7 @@ Therefore to run the executable in the command line, simply change into the dire
+
@@ -90,6 +92,7 @@ Make sure to replace **MSFT** with your own user name. Modifying this example wi
+
diff --git a/src/AppInstallerCLIE2ETests/SetUpFixture.cs b/src/AppInstallerCLIE2ETests/SetUpFixture.cs
index 490924e250..c73d2ebfa0 100644
--- a/src/AppInstallerCLIE2ETests/SetUpFixture.cs
+++ b/src/AppInstallerCLIE2ETests/SetUpFixture.cs
@@ -5,7 +5,6 @@ namespace AppInstallerCLIE2ETests
{
using Microsoft.Win32;
using Newtonsoft.Json;
- using Newtonsoft.Json.Linq;
using NUnit.Framework;
using System;
using System.IO;
@@ -96,6 +95,11 @@ public void Setup()
TestCommon.PackageCertificatePath = TestContext.Parameters.Get(Constants.PackageCertificatePathParameter);
}
+ if (TestContext.Parameters.Exists(Constants.PowerShellModulePathParameter))
+ {
+ TestCommon.PowerShellModulePath = TestContext.Parameters.Get(Constants.PowerShellModulePathParameter);
+ }
+
ReadTestInstallerPaths();
TestIndexSetup.GenerateTestDirectory();
diff --git a/src/AppInstallerCLIE2ETests/Test.runsettings b/src/AppInstallerCLIE2ETests/Test.runsettings
index d28a7443e7..3109faab93 100644
--- a/src/AppInstallerCLIE2ETests/Test.runsettings
+++ b/src/AppInstallerCLIE2ETests/Test.runsettings
@@ -19,6 +19,7 @@
MsixTestInstallerPath: The MSIX (or APPX) Installer executable under test.
ExeTestInstallerPath: The Exe Installer executable under test.
PackageCertificatePath: Signing Certificate Path used to certify Index Source Package
+ PowerShellModulePath: Path to the PowerShell module manifest file under test
-->
@@ -32,5 +33,6 @@
+
\ No newline at end of file
diff --git a/src/AppInstallerCLIE2ETests/TestCommon.cs b/src/AppInstallerCLIE2ETests/TestCommon.cs
index f40c1e6d19..4b3574cef8 100644
--- a/src/AppInstallerCLIE2ETests/TestCommon.cs
+++ b/src/AppInstallerCLIE2ETests/TestCommon.cs
@@ -36,6 +36,8 @@ public class TestCommon
public static string PackageCertificatePath { get; set; }
+ public static string PowerShellModulePath { get; set; }
+
public static string SettingsJsonFilePath {
get
{
@@ -252,6 +254,11 @@ public static RunCommandResult RunCommandWithResult(string fileName, string args
return result;
}
+ public static RunCommandResult RunPowerShellCommandWithResult(string cmdlet, string args, int timeOut = 60000)
+ {
+ return RunCommandWithResult("pwsh.exe", $"-Command ipmo {PowerShellModulePath}; {cmdlet} {args}", timeOut);
+ }
+
public static string GetTestFile(string fileName)
{
return Path.Combine(TestContext.CurrentContext.TestDirectory, fileName);
diff --git a/src/AppInstallerCLIPackage/Package.appxmanifest b/src/AppInstallerCLIPackage/Package.appxmanifest
index d38215f422..431838174d 100644
--- a/src/AppInstallerCLIPackage/Package.appxmanifest
+++ b/src/AppInstallerCLIPackage/Package.appxmanifest
@@ -37,6 +37,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/PowerShell/Microsoft.WinGet.Client/Commands/GetSourceCommand.cs b/src/PowerShell/Microsoft.WinGet.Client/Commands/GetSourceCommand.cs
index 1daaeca661..42a0effbdb 100644
--- a/src/PowerShell/Microsoft.WinGet.Client/Commands/GetSourceCommand.cs
+++ b/src/PowerShell/Microsoft.WinGet.Client/Commands/GetSourceCommand.cs
@@ -6,7 +6,6 @@
namespace Microsoft.WinGet.Client.Commands
{
- using System;
using System.Management.Automation;
using Microsoft.Management.Deployment;
using Microsoft.WinGet.Client.Common;
diff --git a/src/PowerShell/Microsoft.WinGet.Client/Commands/InstallPackageCommand.cs b/src/PowerShell/Microsoft.WinGet.Client/Commands/InstallPackageCommand.cs
index e9affbb38b..d918bfae7e 100644
--- a/src/PowerShell/Microsoft.WinGet.Client/Commands/InstallPackageCommand.cs
+++ b/src/PowerShell/Microsoft.WinGet.Client/Commands/InstallPackageCommand.cs
@@ -4,15 +4,12 @@
//
// -----------------------------------------------------------------------------
-#pragma warning disable SA1200 // Using directives should be placed correctly
-using Windows.System;
-#pragma warning restore SA1200 // Using directives should be placed correctly
-
namespace Microsoft.WinGet.Client.Commands
-{
+{
using System.Management.Automation;
using Microsoft.Management.Deployment;
using Microsoft.WinGet.Client.Common;
+ using Windows.System;
///
/// Installs a package from the pipeline or from a configured source.
diff --git a/src/PowerShell/Microsoft.WinGet.Client/Common/BaseClientCommand.cs b/src/PowerShell/Microsoft.WinGet.Client/Common/BaseClientCommand.cs
index 05376b943e..1113163c81 100644
--- a/src/PowerShell/Microsoft.WinGet.Client/Common/BaseClientCommand.cs
+++ b/src/PowerShell/Microsoft.WinGet.Client/Common/BaseClientCommand.cs
@@ -29,9 +29,9 @@ static BaseClientCommand()
public BaseClientCommand()
: base()
{
- if (Utilities.ExecutingAsAdministrator)
+ if (Utilities.ExecutingAsSystem)
{
- throw new Exception(Utilities.ResourceManager.GetString("ExceptionAdministratorDisabled"));
+ throw new Exception(Utilities.ResourceManager.GetString("ExceptionSystemDisabled"));
}
}
diff --git a/src/PowerShell/Microsoft.WinGet.Client/Common/ErrorCode.cs b/src/PowerShell/Microsoft.WinGet.Client/Common/ErrorCode.cs
new file mode 100644
index 0000000000..68218ee799
--- /dev/null
+++ b/src/PowerShell/Microsoft.WinGet.Client/Common/ErrorCode.cs
@@ -0,0 +1,19 @@
+// -----------------------------------------------------------------------------
+//
+// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
+//
+// -----------------------------------------------------------------------------
+
+namespace Microsoft.WinGet.Client.Common
+{
+ ///
+ /// Error code constants.
+ ///
+ public class ErrorCode
+ {
+ ///
+ /// Error code for ERROR_FILE_NOT_FOUND.
+ ///
+ public const int FileNotFound = unchecked((int)0x80070002);
+ }
+}
diff --git a/src/PowerShell/Microsoft.WinGet.Client/Common/Utilities.cs b/src/PowerShell/Microsoft.WinGet.Client/Common/Utilities.cs
index 7c9e00bcfc..ee24abe44c 100644
--- a/src/PowerShell/Microsoft.WinGet.Client/Common/Utilities.cs
+++ b/src/PowerShell/Microsoft.WinGet.Client/Common/Utilities.cs
@@ -37,5 +37,18 @@ public static bool ExecutingAsAdministrator
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
}
+
+ ///
+ /// Gets a value indicating whether the current assembly is executing as a SYSTEM user.
+ ///
+ public static bool ExecutingAsSystem
+ {
+ get
+ {
+ WindowsIdentity identity = WindowsIdentity.GetCurrent();
+ WindowsPrincipal principal = new (identity);
+ return principal.IsInRole(WindowsBuiltInRole.SystemOperator);
+ }
+ }
}
}
diff --git a/src/PowerShell/Microsoft.WinGet.Client/Format.ps1xml b/src/PowerShell/Microsoft.WinGet.Client/Format.ps1xml
index 77aab233b0..3c140ab2b5 100644
--- a/src/PowerShell/Microsoft.WinGet.Client/Format.ps1xml
+++ b/src/PowerShell/Microsoft.WinGet.Client/Format.ps1xml
@@ -74,10 +74,10 @@
$_.Info.Name
- $_.Info.Type
+ $_.Info.Argument
- $_.Info.Argument
+ $_.Info.Type
diff --git a/src/PowerShell/Microsoft.WinGet.Client/Helpers/ComObjectFactory.cs b/src/PowerShell/Microsoft.WinGet.Client/Helpers/ComObjectFactory.cs
index cd4a907d50..3dc4323ea3 100644
--- a/src/PowerShell/Microsoft.WinGet.Client/Helpers/ComObjectFactory.cs
+++ b/src/PowerShell/Microsoft.WinGet.Client/Helpers/ComObjectFactory.cs
@@ -6,11 +6,12 @@
namespace Microsoft.WinGet.Client.Factories
{
- using System;
- using Microsoft.Management.Deployment;
-
+ using System;
+ using System.Runtime.InteropServices;
+ using Microsoft.Management.Deployment;
+ using Microsoft.WinGet.Client.Common;
+
#if NET
- using System.Runtime.InteropServices;
using WinRT;
#endif
@@ -19,14 +20,20 @@ namespace Microsoft.WinGet.Client.Factories
///
public class ComObjectFactory
{
-#if USE_TEST_CLSIDS
-#else
+#if USE_PROD_CLSIDS
private static readonly Guid PackageManagerClsid = Guid.Parse("C53A4F16-787E-42A4-B304-29EFFB4BF597");
private static readonly Guid FindPackagesOptionsClsid = Guid.Parse("572DED96-9C60-4526-8F92-EE7D91D38C1A");
private static readonly Guid CreateCompositePackageCatalogOptionsClsid = Guid.Parse("526534B8-7E46-47C8-8416-B1685C327D37");
private static readonly Guid InstallOptionsClsid = Guid.Parse("1095F097-EB96-453B-B4E6-1613637F3B14");
private static readonly Guid UninstallOptionsClsid = Guid.Parse("E1D9A11E-9F85-4D87-9C17-2B93143ADB8D");
private static readonly Guid PackageMatchFilterClsid = Guid.Parse("D02C9DAF-99DC-429C-B503-4E504E4AB000");
+#else
+ private static readonly Guid PackageManagerClsid = Guid.Parse("74CB3139-B7C5-4B9E-9388-E6616DEA288C");
+ private static readonly Guid FindPackagesOptionsClsid = Guid.Parse("1BD8FF3A-EC50-4F69-AEEE-DF4C9D3BAA96");
+ private static readonly Guid CreateCompositePackageCatalogOptionsClsid = Guid.Parse("EE160901-B317-4EA7-9CC6-5355C6D7D8A7");
+ private static readonly Guid InstallOptionsClsid = Guid.Parse("44FE0580-62F7-44D4-9E91-AA9614AB3E86");
+ private static readonly Guid UninstallOptionsClsid = Guid.Parse("AA2A5C04-1AD9-46C4-B74F-6B334AD7EB8C");
+ private static readonly Guid PackageMatchFilterClsid = Guid.Parse("3F85B9F4-487A-4C48-9035-2903F8A6D9E8");
#endif
private static readonly Type PackageManagerType = Type.GetTypeFromCLSID(PackageManagerClsid);
@@ -34,7 +41,14 @@ public class ComObjectFactory
private static readonly Type CreateCompositePackageCatalogOptionsType = Type.GetTypeFromCLSID(CreateCompositePackageCatalogOptionsClsid);
private static readonly Type InstallOptionsType = Type.GetTypeFromCLSID(InstallOptionsClsid);
private static readonly Type UninstallOptionsType = Type.GetTypeFromCLSID(UninstallOptionsClsid);
- private static readonly Type PackageMatchFilterType = Type.GetTypeFromCLSID(PackageMatchFilterClsid);
+ private static readonly Type PackageMatchFilterType = Type.GetTypeFromCLSID(PackageMatchFilterClsid);
+
+ private static readonly Guid PackageManagerIid = Guid.Parse("B375E3B9-F2E0-5C93-87A7-B67497F7E593");
+ private static readonly Guid FindPackagesOptionsIid = Guid.Parse("A5270EDD-7DA7-57A3-BACE-F2593553561F");
+ private static readonly Guid CreateCompositePackageCatalogOptionsIid = Guid.Parse("21ABAA76-089D-51C5-A745-C85EEFE70116");
+ private static readonly Guid InstallOptionsIid = Guid.Parse("6EE9DB69-AB48-5E72-A474-33A924CD23B3");
+ private static readonly Guid UninstallOptionsIid = Guid.Parse("3EBC67F0-8339-594B-8A42-F90B69D02BBE");
+ private static readonly Guid PackageMatchFilterIid = Guid.Parse("D981ECA3-4DE5-5AD7-967A-698C7D60FC3B");
///
/// Creates an instance of the class.
@@ -42,7 +56,7 @@ public class ComObjectFactory
/// A instance.
public virtual PackageManager CreatePackageManager()
{
- return Create(PackageManagerType);
+ return Create(PackageManagerType, PackageManagerIid);
}
///
@@ -51,7 +65,7 @@ public virtual PackageManager CreatePackageManager()
/// A instance.
public virtual FindPackagesOptions CreateFindPackagesOptions()
{
- return Create(FindPackagesOptionsType);
+ return Create(FindPackagesOptionsType, FindPackagesOptionsIid);
}
///
@@ -60,7 +74,7 @@ public virtual FindPackagesOptions CreateFindPackagesOptions()
/// A instance.
public virtual CreateCompositePackageCatalogOptions CreateCreateCompositePackageCatalogOptions()
{
- return Create(CreateCompositePackageCatalogOptionsType);
+ return Create(CreateCompositePackageCatalogOptionsType, CreateCompositePackageCatalogOptionsIid);
}
///
@@ -69,7 +83,7 @@ public virtual CreateCompositePackageCatalogOptions CreateCreateCompositePackage
/// An instance.
public virtual InstallOptions CreateInstallOptions()
{
- return Create(InstallOptionsType);
+ return Create(InstallOptionsType, InstallOptionsIid);
}
///
@@ -78,7 +92,7 @@ public virtual InstallOptions CreateInstallOptions()
/// A instance.
public virtual UninstallOptions CreateUninstallOptions()
{
- return Create(UninstallOptionsType);
+ return Create(UninstallOptionsType, UninstallOptionsIid);
}
///
@@ -87,12 +101,34 @@ public virtual UninstallOptions CreateUninstallOptions()
/// A instance.
public virtual PackageMatchFilter CreatePackageMatchFilter()
{
- return Create(PackageMatchFilterType);
+ return Create(PackageMatchFilterType, PackageMatchFilterIid);
}
- private static T Create(Type type)
+ private static T Create(Type type, in Guid iid)
{
- object instance = Activator.CreateInstance(type);
+ object instance = null;
+
+ if (Utilities.ExecutingAsAdministrator)
+ {
+ int hr = WinGetServerManualActivation_CreateInstance(type.GUID, iid, 0, out instance);
+
+ if (hr < 0)
+ {
+ if (hr == ErrorCode.FileNotFound)
+ {
+ throw new Exception(Utilities.ResourceManager.GetString("WinGetPackageNotInstalled"));
+ }
+ else
+ {
+ throw new COMException($"Failed to create instance: {hr}", hr);
+ }
+ }
+ }
+ else
+ {
+ instance = Activator.CreateInstance(type);
+ }
+
#if NET
IntPtr pointer = Marshal.GetIUnknownForObject(instance);
return MarshalInterface.FromAbi(pointer);
@@ -100,5 +136,12 @@ private static T Create(Type type)
return (T)instance;
#endif
}
+
+ [DllImport("winrtact.dll", EntryPoint = "WinGetServerManualActivation_CreateInstance", ExactSpelling = true, PreserveSig = true)]
+ private static extern int WinGetServerManualActivation_CreateInstance(
+ [In, MarshalAs(UnmanagedType.LPStruct)] Guid clsid,
+ [In, MarshalAs(UnmanagedType.LPStruct)] Guid iid,
+ uint flags,
+ [Out, MarshalAs(UnmanagedType.IUnknown)] out object instance);
}
}
diff --git a/src/PowerShell/Microsoft.WinGet.Client/Microsoft.WinGet.Client.csproj b/src/PowerShell/Microsoft.WinGet.Client/Microsoft.WinGet.Client.csproj
index 04e7ed8a68..18e712151a 100644
--- a/src/PowerShell/Microsoft.WinGet.Client/Microsoft.WinGet.Client.csproj
+++ b/src/PowerShell/Microsoft.WinGet.Client/Microsoft.WinGet.Client.csproj
@@ -16,6 +16,10 @@
$(CoreFramework);$(DesktopFramework)
+
+ USE_PROD_CLSIDS
+
+
@@ -34,7 +38,7 @@
Content
Always
-
+
Content
Always
@@ -48,7 +52,7 @@
-
+
True
True
@@ -70,14 +74,25 @@
10.0.17763.0
-
+
-
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/PowerShell/Microsoft.WinGet.Client/Properties/Resources.Designer.cs b/src/PowerShell/Microsoft.WinGet.Client/Properties/Resources.Designer.cs
index 94a6f6c577..dcb3db8807 100644
--- a/src/PowerShell/Microsoft.WinGet.Client/Properties/Resources.Designer.cs
+++ b/src/PowerShell/Microsoft.WinGet.Client/Properties/Resources.Designer.cs
@@ -70,11 +70,11 @@ internal static string ArgumentExceptionInvalidSource {
}
///
- /// Looks up a localized string similar to This cmdlet is currently disabled in an administrative context..
+ /// Looks up a localized string similar to This cmdlet is currently disabled for SYSTEM..
///
- internal static string ExceptionAdministratorDisabled {
+ internal static string ExceptionSystemDisabled {
get {
- return ResourceManager.GetString("ExceptionAdministratorDisabled", resourceCulture);
+ return ResourceManager.GetString("ExceptionSystemDisabled", resourceCulture);
}
}
@@ -149,5 +149,14 @@ internal static string VagueCriteriaExceptionMessage {
return ResourceManager.GetString("VagueCriteriaExceptionMessage", resourceCulture);
}
}
+
+ ///
+ /// Looks up a localized string similar to Unable to execute command; WinGet package not installed..
+ ///
+ internal static string WinGetPackageNotInstalled {
+ get {
+ return ResourceManager.GetString("WinGetPackageNotInstalled", resourceCulture);
+ }
+ }
}
}
diff --git a/src/PowerShell/Microsoft.WinGet.Client/Properties/Resources.resx b/src/PowerShell/Microsoft.WinGet.Client/Properties/Resources.resx
index 711ba74d6f..5ccafe9c41 100644
--- a/src/PowerShell/Microsoft.WinGet.Client/Properties/Resources.resx
+++ b/src/PowerShell/Microsoft.WinGet.Client/Properties/Resources.resx
@@ -121,8 +121,8 @@
No source matches the given value: {0}
{0} - The name of the source that was not found.
-
- This cmdlet is currently disabled in an administrative context.
+
+ This cmdlet is currently disabled for SYSTEM.
An error occurred while searching for packages: {0}
@@ -154,4 +154,7 @@
{0}, {1}, and {2} other packages matched the input criteria. Please refine the input.
{0} - The first conflicting package as a string. {1} - The second conflicting package. {2} - The number of other packages that also matched the input criteria.
+
+ Unable to execute command; WinGet package not installed.
+
\ No newline at end of file
diff --git a/src/WinGetServer/Utils.cpp b/src/WinGetServer/Utils.cpp
new file mode 100644
index 0000000000..57af9414d8
--- /dev/null
+++ b/src/WinGetServer/Utils.cpp
@@ -0,0 +1,35 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#include "Utils.h"
+#pragma warning( push )
+#pragma warning ( disable : 6001 6388 6553)
+#include
+#pragma warning( pop )
+#include
+#include
+#include
+
+unsigned char* GetUCharString(const std::string& str)
+{
+ return reinterpret_cast(const_cast(str.c_str()));
+}
+
+std::string GetUserSID()
+{
+ HANDLE hToken = NULL;
+ THROW_LAST_ERROR_IF(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken));
+
+ DWORD dwBufferSize = 0;
+ THROW_LAST_ERROR_IF(!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwBufferSize) && GetLastError() != ERROR_INSUFFICIENT_BUFFER);
+
+ std::vector buffer;
+ buffer.resize(dwBufferSize);
+ PTOKEN_USER pTokenUser = reinterpret_cast(&buffer[0]);
+
+ THROW_LAST_ERROR_IF(!GetTokenInformation(hToken, TokenUser, pTokenUser, dwBufferSize, &dwBufferSize));
+ THROW_HR_IF(CO_E_INVALIDSID, !IsValidSid(pTokenUser->User.Sid));
+
+ LPSTR pszSID = NULL;
+ THROW_LAST_ERROR_IF(!ConvertSidToStringSidA(pTokenUser->User.Sid, &pszSID));
+ return std::string{ pszSID };
+}
\ No newline at end of file
diff --git a/src/WinGetServer/Utils.h b/src/WinGetServer/Utils.h
new file mode 100644
index 0000000000..80b73dfcfb
--- /dev/null
+++ b/src/WinGetServer/Utils.h
@@ -0,0 +1,8 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#pragma once
+#include
+
+unsigned char* GetUCharString(const std::string& str);
+
+std::string GetUserSID();
\ No newline at end of file
diff --git a/src/WinGetServer/WinGetServer.idl b/src/WinGetServer/WinGetServer.idl
new file mode 100644
index 0000000000..87f8a7a42c
--- /dev/null
+++ b/src/WinGetServer/WinGetServer.idl
@@ -0,0 +1,17 @@
+import "wtypesbase.idl";
+
+[
+ uuid(0ca09dda-857f-479f-ba4b-da875d90051e),
+ version(1.0),
+ implicit_handle(handle_t WinGetServerManualActivation_IfHandle)
+]
+interface WinGetServerManualActivation
+{
+ HRESULT CreateInstance(
+ [in] GUID clsid,
+ [in] GUID iid,
+ [in] UINT32 flags,
+ [out, ref] UINT32* pcbBuffer,
+ [out, ref, size_is(, *pcbBuffer)] BYTE** ppBuffer
+ );
+}
\ No newline at end of file
diff --git a/src/WinGetServer/WinGetServer.vcxproj b/src/WinGetServer/WinGetServer.vcxproj
index 7accd8fd12..3df54e74ba 100644
--- a/src/WinGetServer/WinGetServer.vcxproj
+++ b/src/WinGetServer/WinGetServer.vcxproj
@@ -1,6 +1,5 @@
-
true
true
@@ -107,18 +106,22 @@
Windows
false
$(OutDir)..\Microsoft.Management.Deployment;$(OutDir)..\AppInstallerCLICore;$(OutDir)..\JsonCppLib;$(OutDir)..\AppInstallerRepositoryCore;$(OutDir)..\YamlCppLib;$(OutDir)..\AppInstallerCommonCore;$(OutDir)..\cpprestsdk;%(AdditionalLibraryDirectories)
- %(AdditionalDependencies)
+ Rpcrt4.lib;Advapi32.lib;Shell32.lib;Ole32.lib;%(AdditionalDependencies)
Disabled
_DEBUG;%(PreprocessorDefinitions)
+ stdcpp17
+ stdcpp17
+ stdcpp17
WIN32;%(PreprocessorDefinitions)
+ stdcpp17
@@ -127,6 +130,10 @@
true
true
NDEBUG;%(PreprocessorDefinitions)
+ stdcpp17
+ stdcpp17
+ stdcpp17
+ stdcpp17
true
@@ -137,23 +144,42 @@
/debug:full /debugtype:cv,fixup /incremental:no %(AdditionalOptions)
+
+
+ USE_PROD_WINGET_SERVER;%(PreprocessorDefinitions)
+
+
+
+ true
+
+
+
+
{2046b5af-666d-4ce8-8d3e-c32c57908a56}
+
+
+ false
+ Stub
+ Stub
+ true
+ WinGetServer.h
+
+
-
diff --git a/src/WinGetServer/WinGetServer.vcxproj.filters b/src/WinGetServer/WinGetServer.vcxproj.filters
index 1b7135e521..71519a4d9d 100644
--- a/src/WinGetServer/WinGetServer.vcxproj.filters
+++ b/src/WinGetServer/WinGetServer.vcxproj.filters
@@ -18,11 +18,23 @@
Header Files
+
+ Header Files
+
Source Files
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
@@ -36,4 +48,9 @@
Resource Files
+
+
+ Source Files
+
+
\ No newline at end of file
diff --git a/src/WinGetServer/WinGetServerManualActivation_Client.cpp b/src/WinGetServer/WinGetServerManualActivation_Client.cpp
new file mode 100644
index 0000000000..b74b8d0fcd
--- /dev/null
+++ b/src/WinGetServer/WinGetServerManualActivation_Client.cpp
@@ -0,0 +1,157 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+#include "WinGetServer.h"
+#include "Utils.h"
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if USE_PROD_WINGET_SERVER
+const std::wstring_view s_ServerExePath = L"Microsoft\\WindowsApps\\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe\\WindowsPackageManagerServer.exe";
+#else
+const std::wstring_view s_ServerExePath = L"Microsoft\\WindowsApps\\WinGetDevCLI_8wekyb3d8bbwe\\WindowsPackageManagerServerDev.exe";
+#endif
+
+_Must_inspect_result_
+_Ret_maybenull_ _Post_writable_byte_size_(size)
+void* __RPC_USER MIDL_user_allocate(_In_ size_t size)
+{
+ return malloc(size);
+}
+
+void __RPC_USER MIDL_user_free(_Pre_maybenull_ _Post_invalid_ void* ptr)
+{
+ if (ptr)
+ {
+ free(ptr);
+ }
+}
+
+std::filesystem::path GetKnownFolderPath(const KNOWNFOLDERID& id)
+{
+ wil::unique_cotaskmem_string knownFolder = nullptr;
+ THROW_IF_FAILED(SHGetKnownFolderPath(id, KF_FLAG_NO_ALIAS | KF_FLAG_DONT_VERIFY | KF_FLAG_NO_PACKAGE_REDIRECTION, NULL, &knownFolder));
+ return knownFolder.get();
+}
+
+struct FreeWithRpcStringFree { void operator()(RPC_CSTR* in) { RpcStringFreeA(in); } };
+using UniqueRpcString = std::unique_ptr;
+
+struct DeleteWithMidlFree { void operator()(void* m) { MIDL_user_free(m); } };
+using UniqueMidl = std::unique_ptr;
+
+void InitializeRpcBinding()
+{
+ std::string protocol = "ncacn_np";
+ std::string endpoint = "\\pipe\\WinGetServerManualActivation_" + GetUserSID();
+
+ unsigned char* binding = nullptr;
+ UniqueRpcString bindingPtr;
+
+ RPC_STATUS status = RpcStringBindingComposeA(nullptr, GetUCharString(protocol), nullptr, GetUCharString(endpoint), nullptr, &binding);
+ THROW_HR_IF(HRESULT_FROM_WIN32(status), status != RPC_S_OK);
+ bindingPtr.reset(&binding);
+
+ status = RpcBindingFromStringBindingA(binding, &WinGetServerManualActivation_IfHandle);
+ THROW_HR_IF(HRESULT_FROM_WIN32(status), status != RPC_S_OK);
+}
+
+HRESULT LaunchWinGetServerWithManualActivation()
+{
+ const std::filesystem::path& localAppDataPath = GetKnownFolderPath(FOLDERID_LocalAppData);
+ const std::filesystem::path& serverExePath = localAppDataPath / s_ServerExePath;
+ std::wstring commandLineInput = std::wstring{ serverExePath } + L" --manualActivation";
+
+ STARTUPINFO info = { sizeof(info) };
+ wil::unique_process_information process;
+
+ RETURN_LAST_ERROR_IF(!CreateProcessW(NULL, &commandLineInput[0], NULL, NULL, FALSE, 0, NULL, NULL, &info, &process));
+
+ // Wait for manual reset event from server before proceeding with COM activation.
+ wil::unique_event manualResetEvent;
+ if (manualResetEvent.try_open(L"WinGetServerStartEvent"))
+ {
+ manualResetEvent.wait();
+ }
+
+ return S_OK;
+}
+
+HRESULT CallCreateInstance(REFCLSID rclsid, REFIID riid, UINT32 flags, UINT32* bufferByteCount, BYTE** buffer)
+{
+ RpcTryExcept
+ {
+ RETURN_IF_FAILED(CreateInstance(rclsid, riid, flags, bufferByteCount, buffer));
+ }
+ RpcExcept(1)
+ {
+ return HRESULT_FROM_WIN32(RpcExceptionCode());
+ }
+ RpcEndExcept;
+
+ return S_OK;
+}
+
+HRESULT CreateComInstance(REFCLSID rclsid, REFIID riid, UINT32 flags, void** out)
+{
+ UINT32 bufferByteCount = 0;
+ BYTE* buffer = nullptr;
+ UniqueMidl bufferPtr;
+
+ RETURN_IF_FAILED(CallCreateInstance(rclsid, riid, flags, &bufferByteCount, &buffer));
+
+ bufferPtr.reset(buffer);
+
+ wil::com_ptr stream;
+ RETURN_IF_FAILED(CreateStreamOnHGlobal(nullptr, TRUE, &stream));
+ RETURN_IF_FAILED(stream->Write(buffer, bufferByteCount, nullptr));
+ RETURN_IF_FAILED(stream->Seek({}, STREAM_SEEK_SET, nullptr));
+
+ wil::com_ptr output;
+ RETURN_IF_FAILED(CoUnmarshalInterface(stream.get(), riid, reinterpret_cast(&output)));
+ *out = output.detach();
+ return S_OK;
+}
+
+extern "C" HRESULT WinGetServerManualActivation_CreateInstance(REFCLSID rclsid, REFIID riid, UINT32 flags, void** out)
+{
+ RETURN_HR_IF_NULL(E_POINTER, out);
+
+ static std::once_flag rpcBindingOnce;
+ try
+ {
+ std::call_once(rpcBindingOnce, InitializeRpcBinding);
+ }
+ CATCH_RETURN();
+
+ HRESULT result = CreateComInstance(rclsid, riid, flags, out);
+ if (FAILED(result))
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ result = LaunchWinGetServerWithManualActivation();
+ if (result == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+ {
+ break;
+ }
+
+ result = CreateComInstance(rclsid, riid, flags, out);
+ if (SUCCEEDED(result))
+ {
+ break;
+ }
+
+ Sleep(200);
+ }
+ }
+
+ return result;
+}
\ No newline at end of file
diff --git a/src/WinGetServer/WinMain.cpp b/src/WinGetServer/WinMain.cpp
index 2d5077827d..1ec630bb95 100644
--- a/src/WinGetServer/WinMain.cpp
+++ b/src/WinGetServer/WinMain.cpp
@@ -1,12 +1,21 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
+#define NOMINMAX
#pragma warning( push )
-#pragma warning ( disable : 6553)
+#pragma warning ( disable : 6001 6388 6553)
#include
+#include
#pragma warning( pop )
-#include
#include
+#include
+#include
#include
+#include "WinGetServer.h"
+#include "Utils.h"
+
+#include
+#include
+#include
// Holds the wwinmain open until COM tells us there are no more server connections
wil::unique_event _comServerExitEvent;
@@ -18,26 +27,141 @@ static void _releaseNotifier() noexcept
_comServerExitEvent.SetEvent();
}
-int __stdcall wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ LPWSTR, _In_ int)
+HRESULT WindowsPackageManagerServerInitializeRPCServer()
+{
+ std::string userSID = GetUserSID();
+ std::string endpoint = "\\pipe\\WinGetServerManualActivation_" + userSID;
+ RPC_STATUS status = RpcServerUseProtseqEpA(GetUCharString("ncacn_np"), RPC_C_PROTSEQ_MAX_REQS_DEFAULT, GetUCharString(endpoint), nullptr);
+ RETURN_HR_IF(HRESULT_FROM_WIN32(status), status != RPC_S_OK);
+
+ // The goal of this security descriptor is to restrict RPC server access only to the user in admin mode.
+ // (ML;;NW;;;HI) specifies a high mandatory integrity level (requires admin).
+ // (A;;GA;;;UserSID) specifies access only for the user with the user SID (i.e. self).
+ wil::unique_hlocal_security_descriptor securityDescriptor;
+ std::string securityDescriptorString = "S:(ML;;NW;;;HI)D:(A;;GA;;;" + userSID + ")";
+ RETURN_LAST_ERROR_IF(!ConvertStringSecurityDescriptorToSecurityDescriptorA(securityDescriptorString.c_str(), SDDL_REVISION_1, &securityDescriptor, nullptr));
+
+ status = RpcServerRegisterIf3(WinGetServerManualActivation_v1_0_s_ifspec, nullptr, nullptr, RPC_IF_ALLOW_LOCAL_ONLY | RPC_IF_AUTOLISTEN, RPC_C_LISTEN_MAX_CALLS_DEFAULT, 0, nullptr, securityDescriptor.get());
+ RETURN_HR_IF(HRESULT_FROM_WIN32(status), status != RPC_S_OK);
+
+ return S_OK;
+}
+
+_Must_inspect_result_
+_Ret_maybenull_ _Post_writable_byte_size_(size)
+void* __RPC_USER MIDL_user_allocate(_In_ size_t size)
+{
+ return malloc(size);
+}
+
+void __RPC_USER MIDL_user_free(_Pre_maybenull_ _Post_invalid_ void* ptr)
+{
+ if (ptr)
+ {
+ free(ptr);
+ }
+}
+
+extern "C" HRESULT CreateInstance(
+ /* [in] */ GUID clsid,
+ /* [in] */ GUID iid,
+ /* [in] */ UINT32,
+ /* [ref][out] */ UINT32 * pcbBuffer,
+ /* [size_is][size_is][ref][out] */ BYTE * *ppBuffer)
+{
+ RETURN_HR_IF_NULL(E_POINTER, pcbBuffer);
+ RETURN_HR_IF_NULL(E_POINTER, ppBuffer);
+
+ wil::com_ptr stream;
+ RETURN_IF_FAILED(CreateStreamOnHGlobal(nullptr, TRUE, &stream));
+
+ wil::com_ptr instance;
+ RETURN_IF_FAILED(WindowsPackageManagerServerCreateInstance(clsid, iid, reinterpret_cast(&instance)));
+
+ RETURN_IF_FAILED(CoMarshalInterface(stream.get(), iid, instance.get(), MSHCTX_LOCAL, nullptr, MSHLFLAGS_NORMAL));
+
+ ULARGE_INTEGER streamSize{};
+ RETURN_IF_FAILED(stream->Seek({}, STREAM_SEEK_CUR, &streamSize));
+ RETURN_HR_IF(E_NOT_SUFFICIENT_BUFFER, streamSize.QuadPart > std::numeric_limits::max());
+
+ UINT32 bufferSize = static_cast(streamSize.QuadPart);
+
+ struct DeleteWithMidlFree { void operator()(void* m) { MIDL_user_free(m); } };
+ std::unique_ptr buffer{ reinterpret_cast(MIDL_user_allocate(bufferSize)) };
+
+ RETURN_IF_FAILED(stream->Seek({}, STREAM_SEEK_SET, nullptr));
+ ULONG bytesRead = 0;
+ RETURN_IF_FAILED(stream->Read(buffer.get(), bufferSize, &bytesRead));
+ RETURN_HR_IF(E_UNEXPECTED, bytesRead != bufferSize);
+
+ *pcbBuffer = bufferSize;
+ *ppBuffer = buffer.release();
+
+ return S_OK;
+}
+
+int __stdcall wWinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ LPWSTR cmdLine, _In_ int)
{
- winrt::init_apartment();
+ wil::SetResultLoggingCallback(&WindowsPackageManagerServerWilResultLoggingCallback);
+
+ RETURN_IF_FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED));
// Enable fast rundown of objects so that the server exits faster when clients go away.
{
- winrt::com_ptr globalOptions;
- winrt::check_hresult(CoCreateInstance(CLSID_GlobalOptions, nullptr, CLSCTX_INPROC, IID_PPV_ARGS(&globalOptions)));
- winrt::check_hresult(globalOptions->Set(COMGLB_RO_SETTINGS, COMGLB_FAST_RUNDOWN));
+ wil::com_ptr globalOptions;
+ RETURN_IF_FAILED(CoCreateInstance(CLSID_GlobalOptions, nullptr, CLSCTX_INPROC, IID_PPV_ARGS(&globalOptions)));
+ RETURN_IF_FAILED(globalOptions->Set(COMGLB_RO_SETTINGS, COMGLB_FAST_RUNDOWN));
}
RETURN_IF_FAILED(WindowsPackageManagerServerInitialize());
+ // Command line parsing
+ int argc = 0;
+ LPWSTR* argv = CommandLineToArgvW(cmdLine, &argc);
+ RETURN_LAST_ERROR_IF(!argv);
+
+ bool manualActivation = false;
+
+ // If command line gets more complicated, consider more complex parsing
+ if (argc == 1 && std::wstring_view{ L"--manualActivation" } == argv[0])
+ {
+ manualActivation = true;
+ }
+
_comServerExitEvent.create();
RETURN_IF_FAILED(WindowsPackageManagerServerModuleCreate(&_releaseNotifier));
try
{
// Register all the CoCreatableClassWrlCreatorMapInclude classes
RETURN_IF_FAILED(WindowsPackageManagerServerModuleRegister());
+
+ if (manualActivation)
+ {
+ HANDLE hMutex = NULL;
+ hMutex = CreateMutex(NULL, FALSE, TEXT("WinGetServerMutex"));
+ RETURN_LAST_ERROR_IF_NULL(hMutex);
+
+ DWORD waitResult = WaitForSingleObject(hMutex, 0);
+ if (waitResult != WAIT_OBJECT_0 && waitResult != WAIT_ABANDONED)
+ {
+ return HRESULT_FROM_WIN32(ERROR_SERVICE_ALREADY_RUNNING);
+ }
+
+ RETURN_IF_FAILED(WindowsPackageManagerServerInitializeRPCServer());
+ }
+
+ // Manual reset event to notify the client that the server is available.
+ wil::unique_event manualResetEvent;
+ if (!manualResetEvent.try_create(wil::EventOptions::ManualReset, L"WinGetServerStartEvent"))
+ {
+ manualResetEvent.open(L"WinGetServerStartEvent");
+ }
+
+ manualResetEvent.SetEvent();
+
_comServerExitEvent.wait();
+
+ manualResetEvent.reset();
RETURN_IF_FAILED(WindowsPackageManagerServerModuleUnregister());
}
CATCH_RETURN()
diff --git a/src/WinGetServer/packages.config b/src/WinGetServer/packages.config
index 5e899619db..0d7cdb0046 100644
--- a/src/WinGetServer/packages.config
+++ b/src/WinGetServer/packages.config
@@ -1,5 +1,4 @@
-
\ No newline at end of file
diff --git a/src/WindowsPackageManager/Source.def b/src/WindowsPackageManager/Source.def
index 669121749c..816849baae 100644
--- a/src/WindowsPackageManager/Source.def
+++ b/src/WindowsPackageManager/Source.def
@@ -5,6 +5,8 @@ EXPORTS
WindowsPackageManagerServerModuleCreate
WindowsPackageManagerServerModuleRegister
WindowsPackageManagerServerModuleUnregister
+ WindowsPackageManagerServerWilResultLoggingCallback
+ WindowsPackageManagerServerCreateInstance
WindowsPackageManagerInProcModuleInitialize
WindowsPackageManagerInProcModuleTerminate
WindowsPackageManagerInProcModuleGetClassObject
diff --git a/src/WindowsPackageManager/WindowsPackageManager.h b/src/WindowsPackageManager/WindowsPackageManager.h
index d3198c2870..1842e27b8c 100644
--- a/src/WindowsPackageManager/WindowsPackageManager.h
+++ b/src/WindowsPackageManager/WindowsPackageManager.h
@@ -3,6 +3,9 @@
#pragma once
#include
+// Forward declaration
+namespace wil { struct FailureInfo; }
+
extern "C"
{
#define WINDOWS_PACKAGE_MANAGER_API_CALLING_CONVENTION __stdcall
@@ -25,6 +28,12 @@ extern "C"
// Unregisters the server module class factories.
WINDOWS_PACKAGE_MANAGER_API WindowsPackageManagerServerModuleUnregister();
+ // Callback for logging the WIL result reported from the server.
+ void WINDOWS_PACKAGE_MANAGER_API_CALLING_CONVENTION WindowsPackageManagerServerWilResultLoggingCallback(const wil::FailureInfo& info) noexcept;
+
+ // Creates an out-of-proc instance for manual activation scenarios.
+ WINDOWS_PACKAGE_MANAGER_API WindowsPackageManagerServerCreateInstance(REFCLSID rclsid, REFIID riid, void** out);
+
// Creates module for in-proc COM invocation.
WINDOWS_PACKAGE_MANAGER_API WindowsPackageManagerInProcModuleInitialize();
diff --git a/src/WindowsPackageManager/WindowsPackageManager.vcxproj b/src/WindowsPackageManager/WindowsPackageManager.vcxproj
index 345dc4753d..42389b3043 100644
--- a/src/WindowsPackageManager/WindowsPackageManager.vcxproj
+++ b/src/WindowsPackageManager/WindowsPackageManager.vcxproj
@@ -166,9 +166,9 @@
Disabled
_DEBUG;%(PreprocessorDefinitions)
- $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerCommonCore;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)
- $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerCommonCore;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)
- $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerCommonCore;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)
+ $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)
+ $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)
+ $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)
true
true
true
@@ -210,7 +210,7 @@
WIN32;%(PreprocessorDefinitions)
- $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerCommonCore;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)
+ $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)
true
false
stdcpp17
@@ -227,10 +227,10 @@
true
true
NDEBUG;%(PreprocessorDefinitions)
- $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerCommonCore;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)
- $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerCommonCore;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)
- $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerCommonCore;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)
- $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerCommonCore;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)
+ $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)
+ $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)
+ $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)
+ $(ProjectDir);$(ProjectDir)..\AppInstallerCLICore\Public\;$(ProjectDir)..\AppInstallerRepositoryCore;$(ProjectDir)..\AppInstallerCommonCore\Public;$(ProjectDir)..\Microsoft.Management.Deployment\Public;%(AdditionalIncludeDirectories)
true
true
true
diff --git a/src/WindowsPackageManager/main.cpp b/src/WindowsPackageManager/main.cpp
index f575e4769b..8ee8a3bc52 100644
--- a/src/WindowsPackageManager/main.cpp
+++ b/src/WindowsPackageManager/main.cpp
@@ -10,6 +10,9 @@
#include "WindowsPackageManager.h"
#include
+#include
+#include
+#include
#include
using namespace winrt::Microsoft::Management::Deployment;
@@ -58,6 +61,21 @@ extern "C"
}
CATCH_RETURN();
+ void WINDOWS_PACKAGE_MANAGER_API_CALLING_CONVENTION WindowsPackageManagerServerWilResultLoggingCallback(const wil::FailureInfo& failure) noexcept try
+ {
+ AppInstaller::Logging::Telemetry().LogFailure(failure);
+ }
+ CATCH_LOG();
+
+ WINDOWS_PACKAGE_MANAGER_API WindowsPackageManagerServerCreateInstance(REFCLSID rclsid, REFIID riid, void** out) try
+ {
+ RETURN_HR_IF_NULL(E_POINTER, out);
+ ::Microsoft::WRL::ComPtr factory;
+ RETURN_IF_FAILED(::Microsoft::WRL::Module<::Microsoft::WRL::ModuleType::OutOfProc>::GetModule().GetClassObject(rclsid, IID_PPV_ARGS(&factory)));
+ RETURN_HR(factory->CreateInstance(nullptr, riid, out));
+ }
+ CATCH_RETURN();
+
WINDOWS_PACKAGE_MANAGER_API WindowsPackageManagerInProcModuleInitialize() try
{
::Microsoft::WRL::Module<::Microsoft::WRL::ModuleType::InProc>::Create();
diff --git a/src/Xlang/UndockedRegFreeWinRT/src/UndockedRegFreeWinRT/UndockedRegFreeWinRT/UndockedRegFreeWinRT.vcxproj b/src/Xlang/UndockedRegFreeWinRT/src/UndockedRegFreeWinRT/UndockedRegFreeWinRT/UndockedRegFreeWinRT.vcxproj
index b31d1dcd5c..5767510aac 100644
--- a/src/Xlang/UndockedRegFreeWinRT/src/UndockedRegFreeWinRT/UndockedRegFreeWinRT/UndockedRegFreeWinRT.vcxproj
+++ b/src/Xlang/UndockedRegFreeWinRT/src/UndockedRegFreeWinRT/UndockedRegFreeWinRT/UndockedRegFreeWinRT.vcxproj
@@ -98,7 +98,7 @@
Windows
true
false
- comsuppw.lib;shlwapi.lib;xmllite.lib;runtimeobject.lib;Pathcch.lib;Rometadata.lib
+ comsuppw.lib;shlwapi.lib;xmllite.lib;runtimeobject.lib;Pathcch.lib;Rometadata.lib;Rpcrt4.lib;Shell32.lib;Advapi32.lib
winrtact.def
@@ -117,7 +117,7 @@
Windows
true
false
- comsuppw.lib;shlwapi.lib;xmllite.lib;runtimeobject.lib;Pathcch.lib;Rometadata.lib
+ comsuppw.lib;shlwapi.lib;xmllite.lib;runtimeobject.lib;Pathcch.lib;Rometadata.lib;Rpcrt4.lib;Shell32.lib;Advapi32.lib
winrtact.def
@@ -140,7 +140,7 @@
true
true
false
- comsuppw.lib;shlwapi.lib;xmllite.lib;runtimeobject.lib;Pathcch.lib;Rometadata.lib
+ comsuppw.lib;shlwapi.lib;xmllite.lib;runtimeobject.lib;Pathcch.lib;Rometadata.lib;Rpcrt4.lib;Shell32.lib;Advapi32.lib
winrtact.def
@@ -163,7 +163,7 @@
true
true
false
- comsuppw.lib;shlwapi.lib;xmllite.lib;runtimeobject.lib;Pathcch.lib;Rometadata.lib
+ comsuppw.lib;shlwapi.lib;xmllite.lib;runtimeobject.lib;Pathcch.lib;Rometadata.lib;Rpcrt4.lib;Shell32.lib;Advapi32.lib
winrtact.def
@@ -173,6 +173,10 @@
+
+
+
+
diff --git a/src/Xlang/UndockedRegFreeWinRT/src/UndockedRegFreeWinRT/UndockedRegFreeWinRT/UndockedRegFreeWinRT.vcxproj.filters b/src/Xlang/UndockedRegFreeWinRT/src/UndockedRegFreeWinRT/UndockedRegFreeWinRT/UndockedRegFreeWinRT.vcxproj.filters
index 92faa391ba..6062b1002e 100644
--- a/src/Xlang/UndockedRegFreeWinRT/src/UndockedRegFreeWinRT/UndockedRegFreeWinRT/UndockedRegFreeWinRT.vcxproj.filters
+++ b/src/Xlang/UndockedRegFreeWinRT/src/UndockedRegFreeWinRT/UndockedRegFreeWinRT/UndockedRegFreeWinRT.vcxproj.filters
@@ -1,46 +1,58 @@
-
-
-
-
- {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
- cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
-
-
- {93995380-89BD-4b04-88EB-625FBE52EBFB}
- h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
-
-
- {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
- rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
-
-
-
-
-
- Source Files
-
-
-
-
-
- Source Files
-
-
- Source Files
-
-
- Header Files
-
-
- Source Files
-
-
-
-
- Header Files
-
-
- Header Files
-
-
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+
+ Source Files
+
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Header Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
\ No newline at end of file
diff --git a/src/Xlang/UndockedRegFreeWinRT/src/UndockedRegFreeWinRT/UndockedRegFreeWinRT/winrtact.def b/src/Xlang/UndockedRegFreeWinRT/src/UndockedRegFreeWinRT/UndockedRegFreeWinRT/winrtact.def
index 3d1de76376..c7341b4437 100644
--- a/src/Xlang/UndockedRegFreeWinRT/src/UndockedRegFreeWinRT/UndockedRegFreeWinRT/winrtact.def
+++ b/src/Xlang/UndockedRegFreeWinRT/src/UndockedRegFreeWinRT/UndockedRegFreeWinRT/winrtact.def
@@ -1,4 +1,5 @@
LIBRARY winrtact
EXPORTS
- winrtact_Initialize
\ No newline at end of file
+ winrtact_Initialize
+ WinGetServerManualActivation_CreateInstance
\ No newline at end of file
diff --git a/templates/e2e-test.template.yml b/templates/e2e-test.template.yml
index 7e38114bd6..8b36c84506 100644
--- a/templates/e2e-test.template.yml
+++ b/templates/e2e-test.template.yml
@@ -25,7 +25,8 @@ steps:
-MsiTestInstallerPath $(System.DefaultWorkingDirectory)\src\AppInstallerCLIE2ETests\TestData\AppInstallerTestMsiInstaller.msi
-MsixTestInstallerPath $(Build.ArtifactStagingDirectory)\AppInstallerTestMsixInstaller.msix
-ExeTestInstallerPath $(buildOutDir)\AppInstallerTestExeInstaller\AppInstallerTestExeInstaller.exe
- -PackageCertificatePath $(AppInstallerTest.secureFilePath)'
+ -PackageCertificatePath $(AppInstallerTest.secureFilePath)
+ -PowerShellModulePath $(buildOutDir)\PowerShell\Microsoft.WinGet.Client.psd1'
${{ else }}:
overrideTestrunParameters: '-PackagedContext false
-AICLIPath $(System.DefaultWorkingDirectory)\src\AppInstallerCLIPackage\bin\$(buildPlatform)\$(buildConfiguration)\AppInstallerCLI\winget.exe
@@ -34,4 +35,5 @@ steps:
-MsiTestInstallerPath $(System.DefaultWorkingDirectory)\src\AppInstallerCLIE2ETests\TestData\AppInstallerTestMsiInstaller.msi
-MsixTestInstallerPath $(Build.ArtifactStagingDirectory)\AppInstallerTestMsixInstaller.msix
-ExeTestInstallerPath $(buildOutDir)\AppInstallerTestExeInstaller\AppInstallerTestExeInstaller.exe
- -PackageCertificatePath $(AppInstallerTest.secureFilePath)'
+ -PackageCertificatePath $(AppInstallerTest.secureFilePath)
+ -PowerShellModulePath $(buildOutDir)\PowerShell\Microsoft.WinGet.Client.psd1'