winget-cli

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

commit bc9cb38e2ad941b6457d31f689f9dc912cc516b0
parent a9a02eddfe56fd1f81c17fea5e799c2831d69902
Author: JohnMcPMS <johnmcp@microsoft.com>
Date:   Thu,  6 Apr 2023 11:13:53 -0700

Use in-proc winget in PowerShell module when running as SYSTEM (#3129)

This change uses the in-proc WinRT binaries and activation path when running as `SYSTEM` in the PowerShell module.  It also makes `Assert-WinGetPackageManager` succeed as long as the OS version is high enough in that case.

There are two known caveats with this that could be addressed in a future change if needed:
1. These newly added dlls are still dependent on the VC runtime, and thus will not work unless it has been installed. This seems acceptable for development scenarios. For shipping a module without this dependency, we will need to build a statically linked binary, but only on the internal, release pipeline.
2. The code currently doesn't behave well in an STA thread, meaning that when used from `SYSTEM` the module requires running PowerShell with the MTA option.
Diffstat:
M.github/actions/spelling/expect.txt | 2++
Msrc/PowerShell/Microsoft.WinGet.Client/Commands/Common/BaseCommand.cs | 5+++--
Msrc/PowerShell/Microsoft.WinGet.Client/Common/Utilities.cs | 28+++++++++++++++++++++++++---
Msrc/PowerShell/Microsoft.WinGet.Client/Common/WinGetIntegrity.cs | 26++++++++++++++++++++++----
Dsrc/PowerShell/Microsoft.WinGet.Client/Exceptions/ExecuteAsSystemException.cs | 26--------------------------
Asrc/PowerShell/Microsoft.WinGet.Client/Exceptions/SingleThreadedApartmentException.cs | 27+++++++++++++++++++++++++++
Msrc/PowerShell/Microsoft.WinGet.Client/Helpers/ComObjectFactory.cs | 344++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Msrc/PowerShell/Microsoft.WinGet.Client/Microsoft.WinGet.Client.csproj | 19+++++++++++++++++++
Msrc/PowerShell/Microsoft.WinGet.Client/Properties/Resources.Designer.cs | 20++++++++++----------
Msrc/PowerShell/Microsoft.WinGet.Client/Properties/Resources.resx | 7++++---
10 files changed, 302 insertions(+), 202 deletions(-)

diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt @@ -157,6 +157,7 @@ IHelp iid IISOn inet +inproc installinprogress installshield instream @@ -194,6 +195,7 @@ LPBYTE LPCWSTR LPDWORD lpitemidlist +LPW maclachlan LPSTR LPWCH diff --git a/src/PowerShell/Microsoft.WinGet.Client/Commands/Common/BaseCommand.cs b/src/PowerShell/Microsoft.WinGet.Client/Commands/Common/BaseCommand.cs @@ -21,9 +21,10 @@ namespace Microsoft.WinGet.Client.Commands.Common public BaseCommand() : base() { - if (Utilities.ExecutingAsSystem) + // The inproc COM API may deadlock on an STA thread. + if (Utilities.UsesInProcWinget && Utilities.ThreadIsSTA) { - throw new ExecuteAsSystemException(); + throw new SingleThreadedApartmentException(); } } } diff --git a/src/PowerShell/Microsoft.WinGet.Client/Common/Utilities.cs b/src/PowerShell/Microsoft.WinGet.Client/Common/Utilities.cs @@ -8,6 +8,7 @@ namespace Microsoft.WinGet.Client.Common { using System; using System.Security.Principal; + using System.Threading; /// <summary> /// This class contains various helper methods for this project. @@ -36,9 +37,30 @@ namespace Microsoft.WinGet.Client.Common { get { - WindowsIdentity identity = WindowsIdentity.GetCurrent(); - WindowsPrincipal principal = new (identity); - return principal.IsInRole(WindowsBuiltInRole.SystemOperator); + return WindowsIdentity.GetCurrent().IsSystem; + } + } + + /// <summary> + /// Gets a value indicating whether the current execution context will use in-proc winget. + /// </summary> + public static bool UsesInProcWinget + { + get + { + return ExecutingAsSystem; + } + } + + /// <summary> + /// Gets a value indicating whether the current thread is executing as STA. + /// </summary> + [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "Windows only API")] + public static bool ThreadIsSTA + { + get + { + return Thread.CurrentThread.GetApartmentState() == ApartmentState.STA; } } diff --git a/src/PowerShell/Microsoft.WinGet.Client/Common/WinGetIntegrity.cs b/src/PowerShell/Microsoft.WinGet.Client/Common/WinGetIntegrity.cs @@ -26,6 +26,18 @@ namespace Microsoft.WinGet.Client.Common /// <param name="expectedVersion">Expected version.</param> public static void AssertWinGet(PSCmdlet psCmdlet, string expectedVersion) { + // In-proc shouldn't have other dependencies and thus should be ok. + if (Utilities.UsesInProcWinget) + { + // Only check the OS version support for in-proc + if (!IsSupportedOSVersion()) + { + throw new WinGetIntegrityException(IntegrityCategory.OsNotSupported); + } + + return; + } + try { // Start by calling winget without its WindowsApp PFN path. @@ -114,10 +126,8 @@ namespace Microsoft.WinGet.Client.Common // Not under %LOCALAPPDATA%\\Microsoft\\WindowsApps\PFM\ - // Windows version has to be equal or newer than 10.0.17763.0 - var minWindowsVersion = new Version(10, 0, 17763, 0); - var osVersion = Environment.OSVersion.Version; - if (osVersion.CompareTo(minWindowsVersion) < 0) + // Check OS version + if (!IsSupportedOSVersion()) { return IntegrityCategory.OsNotSupported; } @@ -143,5 +153,13 @@ namespace Microsoft.WinGet.Client.Common // If we get here, we know the package is in the machine but not registered for the user. return IntegrityCategory.AppInstallerNotRegistered; } + + private static bool IsSupportedOSVersion() + { + // Windows version has to be equal or newer than 10.0.17763.0 + var minWindowsVersion = new Version(10, 0, 17763, 0); + var osVersion = Environment.OSVersion.Version; + return osVersion.CompareTo(minWindowsVersion) >= 0; + } } } diff --git a/src/PowerShell/Microsoft.WinGet.Client/Exceptions/ExecuteAsSystemException.cs b/src/PowerShell/Microsoft.WinGet.Client/Exceptions/ExecuteAsSystemException.cs @@ -1,26 +0,0 @@ -// ----------------------------------------------------------------------------- -// <copyright file="ExecuteAsSystemException.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. Licensed under the MIT License. -// </copyright> -// ----------------------------------------------------------------------------- - -namespace Microsoft.WinGet.Client.Exceptions -{ - using System; - using Microsoft.WinGet.Client.Properties; - - /// <summary> - /// Executing as system is disabled. - /// </summary> - [Serializable] - public class ExecuteAsSystemException : Exception - { - /// <summary> - /// Initializes a new instance of the <see cref="ExecuteAsSystemException"/> class. - /// </summary> - public ExecuteAsSystemException() - : base(Resources.ExecuteAsSystemExceptionMessage) - { - } - } -} diff --git a/src/PowerShell/Microsoft.WinGet.Client/Exceptions/SingleThreadedApartmentException.cs b/src/PowerShell/Microsoft.WinGet.Client/Exceptions/SingleThreadedApartmentException.cs @@ -0,0 +1,27 @@ +// ----------------------------------------------------------------------------- +// <copyright file="SingleThreadedApartmentException.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.WinGet.Client.Exceptions +{ + using System; + using System.Management.Automation; + using Microsoft.WinGet.Client.Properties; + + /// <summary> + /// No package found. + /// </summary> + [Serializable] + public class SingleThreadedApartmentException : RuntimeException + { + /// <summary> + /// Initializes a new instance of the <see cref="SingleThreadedApartmentException"/> class. + /// </summary> + public SingleThreadedApartmentException() + : base(Resources.SingleThreadedApartmentNotSupportedMessage) + { + } + } +} diff --git a/src/PowerShell/Microsoft.WinGet.Client/Helpers/ComObjectFactory.cs b/src/PowerShell/Microsoft.WinGet.Client/Helpers/ComObjectFactory.cs @@ -1,154 +1,190 @@ -// ----------------------------------------------------------------------------- -// <copyright file="ComObjectFactory.cs" company="Microsoft Corporation"> -// Copyright (c) Microsoft Corporation. Licensed under the MIT License. -// </copyright> -// ----------------------------------------------------------------------------- - -namespace Microsoft.WinGet.Client.Factories -{ - using System; - using System.Runtime.InteropServices; - using Microsoft.Management.Deployment; - using Microsoft.WinGet.Client.Common; - using Microsoft.WinGet.Client.Exceptions; - -#if NET - using WinRT; -#endif - - /// <summary> - /// Constructs instances of classes from the <see cref="Management.Deployment" /> namespace. - /// </summary> - public class ComObjectFactory - { -#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 - [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "COM only usage.")] - private static readonly Type PackageManagerType = Type.GetTypeFromCLSID(PackageManagerClsid); - [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "COM only usage.")] - private static readonly Type FindPackagesOptionsType = Type.GetTypeFromCLSID(FindPackagesOptionsClsid); - [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "COM only usage.")] - private static readonly Type CreateCompositePackageCatalogOptionsType = Type.GetTypeFromCLSID(CreateCompositePackageCatalogOptionsClsid); - [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "COM only usage.")] - private static readonly Type InstallOptionsType = Type.GetTypeFromCLSID(InstallOptionsClsid); - [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "COM only usage.")] - private static readonly Type UninstallOptionsType = Type.GetTypeFromCLSID(UninstallOptionsClsid); - [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "COM only usage.")] - 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"); - - /// <summary> - /// Creates an instance of the <see cref="PackageManager" /> class. - /// </summary> - /// <returns>A <see cref="PackageManager" /> instance.</returns> - public virtual PackageManager CreatePackageManager() - { - return Create<PackageManager>(PackageManagerType, PackageManagerIid); - } - - /// <summary> - /// Creates an instance of the <see cref="FindPackagesOptions" /> class. - /// </summary> - /// <returns>A <see cref="FindPackagesOptions" /> instance.</returns> - public virtual FindPackagesOptions CreateFindPackagesOptions() - { - return Create<FindPackagesOptions>(FindPackagesOptionsType, FindPackagesOptionsIid); - } - - /// <summary> - /// Creates an instance of the <see cref="CreateCompositePackageCatalogOptions" /> class. - /// </summary> - /// <returns>A <see cref="CreateCompositePackageCatalogOptions" /> instance.</returns> - public virtual CreateCompositePackageCatalogOptions CreateCreateCompositePackageCatalogOptions() - { - return Create<CreateCompositePackageCatalogOptions>(CreateCompositePackageCatalogOptionsType, CreateCompositePackageCatalogOptionsIid); - } - - /// <summary> - /// Creates an instance of the <see cref="InstallOptions" /> class. - /// </summary> - /// <returns>An <see cref="InstallOptions" /> instance.</returns> - public virtual InstallOptions CreateInstallOptions() - { - return Create<InstallOptions>(InstallOptionsType, InstallOptionsIid); - } - - /// <summary> - /// Creates an instance of the <see cref="UninstallOptions" /> class. - /// </summary> - /// <returns>A <see cref="UninstallOptions" /> instance.</returns> - public virtual UninstallOptions CreateUninstallOptions() - { - return Create<UninstallOptions>(UninstallOptionsType, UninstallOptionsIid); - } - - /// <summary> - /// Creates an instance of the <see cref="PackageMatchFilter" /> class. - /// </summary> - /// <returns>A <see cref="PackageMatchFilter" /> instance.</returns> - public virtual PackageMatchFilter CreatePackageMatchFilter() - { - return Create<PackageMatchFilter>(PackageMatchFilterType, PackageMatchFilterIid); - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "COM only usage.")] - private static T Create<T>(Type type, in Guid iid) - { - 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 WinGetIntegrityException(IntegrityCategory.AppInstallerNotInstalled); - } - else - { - throw new COMException($"Failed to create instance: {hr}", hr); - } - } - } - else - { - instance = Activator.CreateInstance(type); - } - -#if NET - IntPtr pointer = Marshal.GetIUnknownForObject(instance); - return MarshalInterface<T>.FromAbi(pointer); -#else - 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); - } -} +// ----------------------------------------------------------------------------- +// <copyright file="ComObjectFactory.cs" company="Microsoft Corporation"> +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// </copyright> +// ----------------------------------------------------------------------------- + +namespace Microsoft.WinGet.Client.Factories +{ + using System; + using System.IO; + using System.Reflection; + using System.Runtime.InteropServices; + using Microsoft.Management.Deployment; + using Microsoft.WinGet.Client.Common; + using Microsoft.WinGet.Client.Exceptions; + using Windows.Networking.Sockets; + +#if NET + using WinRT; +#endif + + /// <summary> + /// Constructs instances of classes from the <see cref="Management.Deployment" /> namespace. + /// </summary> + public class ComObjectFactory + { +#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 + [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "COM only usage.")] + private static readonly Type PackageManagerType = Type.GetTypeFromCLSID(PackageManagerClsid); + [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "COM only usage.")] + private static readonly Type FindPackagesOptionsType = Type.GetTypeFromCLSID(FindPackagesOptionsClsid); + [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "COM only usage.")] + private static readonly Type CreateCompositePackageCatalogOptionsType = Type.GetTypeFromCLSID(CreateCompositePackageCatalogOptionsClsid); + [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "COM only usage.")] + private static readonly Type InstallOptionsType = Type.GetTypeFromCLSID(InstallOptionsClsid); + [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "COM only usage.")] + private static readonly Type UninstallOptionsType = Type.GetTypeFromCLSID(UninstallOptionsClsid); + [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "COM only usage.")] + 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"); + + /// <summary> + /// Initializes static members of the <see cref="ComObjectFactory"/> class. + /// </summary> + static ComObjectFactory() + { + if (Utilities.UsesInProcWinget) + { + PackageManagerSettings settings = new PackageManagerSettings(); + settings.SetCallerIdentifier("PowerShellInProc"); + } + } + + /// <summary> + /// Creates an instance of the <see cref="PackageManager" /> class. + /// </summary> + /// <returns>A <see cref="PackageManager" /> instance.</returns> + public virtual PackageManager CreatePackageManager() + { + return Create<PackageManager>(PackageManagerType, PackageManagerIid); + } + + /// <summary> + /// Creates an instance of the <see cref="FindPackagesOptions" /> class. + /// </summary> + /// <returns>A <see cref="FindPackagesOptions" /> instance.</returns> + public virtual FindPackagesOptions CreateFindPackagesOptions() + { + return Create<FindPackagesOptions>(FindPackagesOptionsType, FindPackagesOptionsIid); + } + + /// <summary> + /// Creates an instance of the <see cref="CreateCompositePackageCatalogOptions" /> class. + /// </summary> + /// <returns>A <see cref="CreateCompositePackageCatalogOptions" /> instance.</returns> + public virtual CreateCompositePackageCatalogOptions CreateCreateCompositePackageCatalogOptions() + { + return Create<CreateCompositePackageCatalogOptions>(CreateCompositePackageCatalogOptionsType, CreateCompositePackageCatalogOptionsIid); + } + + /// <summary> + /// Creates an instance of the <see cref="InstallOptions" /> class. + /// </summary> + /// <returns>An <see cref="InstallOptions" /> instance.</returns> + public virtual InstallOptions CreateInstallOptions() + { + return Create<InstallOptions>(InstallOptionsType, InstallOptionsIid); + } + + /// <summary> + /// Creates an instance of the <see cref="UninstallOptions" /> class. + /// </summary> + /// <returns>A <see cref="UninstallOptions" /> instance.</returns> + public virtual UninstallOptions CreateUninstallOptions() + { + return Create<UninstallOptions>(UninstallOptionsType, UninstallOptionsIid); + } + + /// <summary> + /// Creates an instance of the <see cref="PackageMatchFilter" /> class. + /// </summary> + /// <returns>A <see cref="PackageMatchFilter" /> instance.</returns> + public virtual PackageMatchFilter CreatePackageMatchFilter() + { + return Create<PackageMatchFilter>(PackageMatchFilterType, PackageMatchFilterIid); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "COM only usage.")] + private static T Create<T>(Type type, in Guid iid) + where T : new() + { + if (Utilities.UsesInProcWinget) + { + string executingAssemblyLocation = Assembly.GetExecutingAssembly().Location; + string executingAssemblyDirectory = Path.GetDirectoryName(executingAssemblyLocation); + SetDllDirectoryW(executingAssemblyDirectory); + + try + { + return new T(); + } + finally + { + SetDllDirectoryW(null); + } + } + + 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 WinGetIntegrityException(IntegrityCategory.AppInstallerNotInstalled); + } + else + { + throw new COMException($"Failed to create instance: {hr}", hr); + } + } + } + else + { + instance = Activator.CreateInstance(type); + } + +#if NET + IntPtr pointer = Marshal.GetIUnknownForObject(instance); + return MarshalInterface<T>.FromAbi(pointer); +#else + 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); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool SetDllDirectoryW([MarshalAs(UnmanagedType.LPWStr)] string directory); + } +} diff --git a/src/PowerShell/Microsoft.WinGet.Client/Microsoft.WinGet.Client.csproj b/src/PowerShell/Microsoft.WinGet.Client/Microsoft.WinGet.Client.csproj @@ -47,6 +47,14 @@ <OutputItemType>Content</OutputItemType> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </ProjectReference> + <ProjectReference Include="..\..\Microsoft.Management.Deployment.InProc\Microsoft.Management.Deployment.InProc.vcxproj"> + <OutputItemType>Content</OutputItemType> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </ProjectReference> + <ProjectReference Include="..\..\WindowsPackageManager\WindowsPackageManager.vcxproj"> + <OutputItemType>Content</OutputItemType> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </ProjectReference> </ItemGroup> <PropertyGroup> @@ -159,4 +167,15 @@ <Copy SourceFiles="@(DesktopBinaries)" DestinationFolder="$(PowerShellModuleLibDirectory)\$(DesktopFramework)\$(Platform)\%(RecursiveDir)" /> </Target> + <!-- Rename Microsoft.Management.Deployment.InProc.dll to Microsoft.Management.Deployment.dll --> + <Target Name="RenameMicrosoftManagementDeployment" AfterTargets="AfterBuild"> + <ItemGroup> + <RenameModuleFiles Include="$(PowerShellModuleLibDirectory)\**\Microsoft.Management.Deployment.InProc.dll"> + <NewName>Microsoft.Management.Deployment.dll</NewName> + </RenameModuleFiles> + </ItemGroup> + <Message Importance="high" Text="Renaming file '%(RenameModuleFiles.Identity)' to '$(PowerShellModuleLibDirectory)\%(RenameModuleFiles.RecursiveDir)\%(RenameModuleFiles.NewName)'" /> + <Move SourceFiles="%(RenameModuleFiles.Identity)" DestinationFiles="$(PowerShellModuleLibDirectory)\%(RenameModuleFiles.RecursiveDir)\%(RenameModuleFiles.NewName)" /> + </Target> + </Project> diff --git a/src/PowerShell/Microsoft.WinGet.Client/Properties/Resources.Designer.cs b/src/PowerShell/Microsoft.WinGet.Client/Properties/Resources.Designer.cs @@ -79,15 +79,6 @@ namespace Microsoft.WinGet.Client.Properties { } /// <summary> - /// Looks up a localized string similar to This cmdlet is currently disabled for SYSTEM.. - /// </summary> - internal static string ExecuteAsSystemExceptionMessage { - get { - return ResourceManager.GetString("ExecuteAsSystemExceptionMessage", resourceCulture); - } - } - - /// <summary> /// Looks up a localized string similar to An error occurred while searching for packages: {0}. /// </summary> internal static string FindPackagesExceptionMessage { @@ -151,7 +142,7 @@ namespace Microsoft.WinGet.Client.Properties { } /// <summary> - /// Looks up a localized string similar to The Windows Package Manager requires at least Version 1809 (October 2018 Update).. + /// Looks up a localized string similar to The Windows Package Manager requires Windows Version 1809 (October 2018 Update) or later.. /// </summary> internal static string IntegrityOsNotSupportedMessage { get { @@ -241,6 +232,15 @@ namespace Microsoft.WinGet.Client.Properties { } /// <summary> + /// Looks up a localized string similar to Single threaded apartment (STA) is not currently supported in this context; run PowerShell in Multi-threaded apartment mode (MTA).. + /// </summary> + internal static string SingleThreadedApartmentNotSupportedMessage { + get { + return ResourceManager.GetString("SingleThreadedApartmentNotSupportedMessage", resourceCulture); + } + } + + /// <summary> /// Looks up a localized string similar to User settings file is invalid.. /// </summary> internal static string UserSettingsReadException { diff --git a/src/PowerShell/Microsoft.WinGet.Client/Properties/Resources.resx b/src/PowerShell/Microsoft.WinGet.Client/Properties/Resources.resx @@ -121,9 +121,6 @@ <value>No source matches the given value: {0}</value> <comment>{Locked="{0}"} {0} - The name of the source that was not found.</comment> </data> - <data name="ExecuteAsSystemExceptionMessage" xml:space="preserve"> - <value>This cmdlet is currently disabled for SYSTEM.</value> - </data> <data name="FindPackagesExceptionMessage" xml:space="preserve"> <value>An error occurred while searching for packages: {0}</value> <comment>{Locked="{0}"} {0} - A string representation of the error status returned by the catalog.</comment> @@ -203,4 +200,8 @@ <value>The installed winget version doesn't match the expectation. Installer version '{0}' Expected version '{1}'</value> <comment>{Locked="{0}","{1}"} {0} - The winget current installed winget version. {1} - The expected winget version.</comment> </data> + <data name="SingleThreadedApartmentNotSupportedMessage" xml:space="preserve"> + <value>Single threaded apartment (STA) is not currently supported in this context; run PowerShell in Multi-threaded apartment mode (MTA).</value> + <comment>{Locked="STA","MTA"}</comment> + </data> </root> \ No newline at end of file