This commit is contained in:
Martí Climent
2024-03-25 15:38:19 +01:00
parent e184ffc781
commit f6ca17b8bb
12 changed files with 587 additions and 0 deletions
+14
View File
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\WindowsPackageManager Interop\WindowsPackageManager Interop.csproj" />
</ItemGroup>
</Project>
+61
View File
@@ -0,0 +1,61 @@
using System.Security.Principal;
// Include WinGet Namespace
using WindowsPackageManager.Interop;
namespace WingetTest
{
internal class Program
{
static public void Main(string[] args)
{
while(true)
{
Console.WriteLine(" ");
Console.Write("Enter search query: ");
string? Query = Console.ReadLine();
if(Query == null || Query == "")
break;
FindPackagesForQuery(Query).Wait();
}
}
private static async Task FindPackagesForQuery(string Query)
{
WindowsPackageManagerFactory WinGetFactory;
bool IsAdministrator = new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);
// If the user is an administrator, use the elevated factory. Otherwhise COM will crash
if(IsAdministrator)
WinGetFactory = new WindowsPackageManagerElevatedFactory();
else
WinGetFactory = new WindowsPackageManagerStandardFactory();
// Create Package Manager and get available catalogs
var Manager = WinGetFactory.CreatePackageManager();
var AvailableCatalogs = Manager.GetPackageCatalogs();
foreach (var Catalog in AvailableCatalogs.ToArray())
{
// Create a filter to search for packages
var FilterList = WinGetFactory.CreateFindPackagesOptions();
// Add the query to the filter
var NameFilter = WinGetFactory.CreatePackageMatchFilter();
NameFilter.Field = Microsoft.Management.Deployment.PackageMatchField.Name;
NameFilter.Value = Query;
FilterList.Filters.Add(NameFilter);
// Find the packages with the filters
var SearchResults = await Catalog.Connect().PackageCatalog.FindPackagesAsync(FilterList);
foreach (var Match in SearchResults.Matches.ToArray())
{
// Print the packages
var Package = Match.CatalogPackage;
Console.WriteLine(Package.Name);
}
}
}
}
}
+61
View File
@@ -0,0 +1,61 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.10.34707.107
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WindowsPackageManager Interop", "WindowsPackageManager Interop\WindowsPackageManager Interop.csproj", "{39D02ACA-38AC-41B4-8ED4-DC591AAC5B1F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo Console App", "Demo Console App\Demo Console App.csproj", "{D30DB5C6-8D6E-4EA9-99C5-C3B495C0109C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|arm64 = Debug|arm64
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|arm64 = Release|arm64
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{39D02ACA-38AC-41B4-8ED4-DC591AAC5B1F}.Debug|Any CPU.ActiveCfg = Debug|x64
{39D02ACA-38AC-41B4-8ED4-DC591AAC5B1F}.Debug|Any CPU.Build.0 = Debug|x64
{39D02ACA-38AC-41B4-8ED4-DC591AAC5B1F}.Debug|arm64.ActiveCfg = Debug|arm64
{39D02ACA-38AC-41B4-8ED4-DC591AAC5B1F}.Debug|arm64.Build.0 = Debug|arm64
{39D02ACA-38AC-41B4-8ED4-DC591AAC5B1F}.Debug|x64.ActiveCfg = Debug|x64
{39D02ACA-38AC-41B4-8ED4-DC591AAC5B1F}.Debug|x64.Build.0 = Debug|x64
{39D02ACA-38AC-41B4-8ED4-DC591AAC5B1F}.Debug|x86.ActiveCfg = Debug|x86
{39D02ACA-38AC-41B4-8ED4-DC591AAC5B1F}.Debug|x86.Build.0 = Debug|x86
{39D02ACA-38AC-41B4-8ED4-DC591AAC5B1F}.Release|Any CPU.ActiveCfg = Release|x64
{39D02ACA-38AC-41B4-8ED4-DC591AAC5B1F}.Release|Any CPU.Build.0 = Release|x64
{39D02ACA-38AC-41B4-8ED4-DC591AAC5B1F}.Release|arm64.ActiveCfg = Release|arm64
{39D02ACA-38AC-41B4-8ED4-DC591AAC5B1F}.Release|arm64.Build.0 = Release|arm64
{39D02ACA-38AC-41B4-8ED4-DC591AAC5B1F}.Release|x64.ActiveCfg = Release|x64
{39D02ACA-38AC-41B4-8ED4-DC591AAC5B1F}.Release|x64.Build.0 = Release|x64
{39D02ACA-38AC-41B4-8ED4-DC591AAC5B1F}.Release|x86.ActiveCfg = Release|x86
{39D02ACA-38AC-41B4-8ED4-DC591AAC5B1F}.Release|x86.Build.0 = Release|x86
{D30DB5C6-8D6E-4EA9-99C5-C3B495C0109C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D30DB5C6-8D6E-4EA9-99C5-C3B495C0109C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D30DB5C6-8D6E-4EA9-99C5-C3B495C0109C}.Debug|arm64.ActiveCfg = Debug|Any CPU
{D30DB5C6-8D6E-4EA9-99C5-C3B495C0109C}.Debug|arm64.Build.0 = Debug|Any CPU
{D30DB5C6-8D6E-4EA9-99C5-C3B495C0109C}.Debug|x64.ActiveCfg = Debug|Any CPU
{D30DB5C6-8D6E-4EA9-99C5-C3B495C0109C}.Debug|x64.Build.0 = Debug|Any CPU
{D30DB5C6-8D6E-4EA9-99C5-C3B495C0109C}.Debug|x86.ActiveCfg = Debug|Any CPU
{D30DB5C6-8D6E-4EA9-99C5-C3B495C0109C}.Debug|x86.Build.0 = Debug|Any CPU
{D30DB5C6-8D6E-4EA9-99C5-C3B495C0109C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D30DB5C6-8D6E-4EA9-99C5-C3B495C0109C}.Release|Any CPU.Build.0 = Release|Any CPU
{D30DB5C6-8D6E-4EA9-99C5-C3B495C0109C}.Release|arm64.ActiveCfg = Release|Any CPU
{D30DB5C6-8D6E-4EA9-99C5-C3B495C0109C}.Release|arm64.Build.0 = Release|Any CPU
{D30DB5C6-8D6E-4EA9-99C5-C3B495C0109C}.Release|x64.ActiveCfg = Release|Any CPU
{D30DB5C6-8D6E-4EA9-99C5-C3B495C0109C}.Release|x64.Build.0 = Release|Any CPU
{D30DB5C6-8D6E-4EA9-99C5-C3B495C0109C}.Release|x86.ActiveCfg = Release|Any CPU
{D30DB5C6-8D6E-4EA9-99C5-C3B495C0109C}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E855C1C8-5A5C-45A1-BBD0-5253A0E190F2}
EndGlobalSection
EndGlobal
@@ -0,0 +1,39 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
namespace WindowsPackageManager.Interop;
public class WinGetConfigurationException : Exception
{
// WinGet Configuration error codes:
// https://github.com/microsoft/winget-cli/blob/master/src/PowerShell/Microsoft.WinGet.Configuration.Engine/Exceptions/ErrorCodes.cs
public const int WingetConfigErrorInvalidConfigurationFile = unchecked((int)0x8A15C001);
public const int WingetConfigErrorInvalidYaml = unchecked((int)0x8A15C002);
public const int WingetConfigErrorInvalidFieldType = unchecked((int)0x8A15C003);
public const int WingetConfigErrorUnknownConfigurationFileVersion = unchecked((int)0x8A15C004);
public const int WingetConfigErrorSetApplyFailed = unchecked((int)0x8A15C005);
public const int WingetConfigErrorDuplicateIdentifier = unchecked((int)0x8A15C006);
public const int WingetConfigErrorMissingDependency = unchecked((int)0x8A15C007);
public const int WingetConfigErrorDependencyUnsatisfied = unchecked((int)0x8A15C008);
public const int WingetConfigErrorAssertionFailed = unchecked((int)0x8A15C009);
public const int WingetConfigErrorManuallySkipped = unchecked((int)0x8A15C00A);
public const int WingetConfigErrorWarningNotAccepted = unchecked((int)0x8A15C00B);
public const int WingetConfigErrorSetDependencyCycle = unchecked((int)0x8A15C00C);
public const int WingetConfigErrorInvalidFieldValue = unchecked((int)0x8A15C00D);
public const int WingetConfigErrorMissingField = unchecked((int)0x8A15C00E);
// WinGet Configuration unit error codes:
public const int WinGetConfigUnitNotFound = unchecked((int)0x8A15C101);
public const int WinGetConfigUnitNotFoundRepository = unchecked((int)0x8A15C102);
public const int WinGetConfigUnitMultipleMatches = unchecked((int)0x8A15C103);
public const int WinGetConfigUnitInvokeGet = unchecked((int)0x8A15C104);
public const int WinGetConfigUnitInvokeTest = unchecked((int)0x8A15C105);
public const int WinGetConfigUnitInvokeSet = unchecked((int)0x8A15C106);
public const int WinGetConfigUnitModuleConflict = unchecked((int)0x8A15C107);
public const int WinGetConfigUnitImportModule = unchecked((int)0x8A15C108);
public const int WinGetConfigUnitInvokeInvalidResult = unchecked((int)0x8A15C109);
public const int WinGetConfigUnitSettingConfigRoot = unchecked((int)0x8A15C110);
public const int WinGetConfigUnitImportModuleAdmin = unchecked((int)0x8A15C111);
}
@@ -0,0 +1,7 @@
CoCreateInstance
CoMarshalInterface
CoUnmarshalInterface
CreateStreamOnHGlobal
HRESULT_FROM_WIN32
MSHCTX
MSHLFLAGS
@@ -0,0 +1,67 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
<RootNamespace>DevHome.SetupFlow.Common</RootNamespace>
<Platforms>x86;x64;arm64</Platforms>
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
<Nullable>disable</Nullable>
</PropertyGroup>
<!--
CsWinRT properties:
https://github.com/microsoft/CsWinRT/blob/master/nuget/readme.md
-->
<PropertyGroup>
<CsWinRTWindowsMetadata>10.0.19041.0</CsWinRTWindowsMetadata>
<CsWinRTIncludes>Microsoft.Management.Deployment</CsWinRTIncludes>
</PropertyGroup>
<ItemGroup>
<CsWinRTInputs Include="$(TargetDir)\Microsoft.Management.Deployment.winmd" />
<Content Include="$(TargetDir)\Microsoft.Management.Deployment.winmd" Link="Microsoft.Management.Deployment.winmd" CopyToOutputDirectory="PreserveNewest" />
<Content Include="$(TargetDir)\Microsoft.Management.Configuration.dll" Link="Microsoft.Management.Configuration.dll" CopyToOutputDirectory="PreserveNewest" />
<Content Include="$(TargetDir)\Microsoft.Management.Configuration.winmd" Link="Microsoft.Management.Configuration.winmd" CopyToOutputDirectory="PreserveNewest" />
<!-- This DLL from the winget COM interop package allows activating the winget server elevated -->
<Content Include="$(TargetDir)\winrtact.dll" Link="winrtact.dll" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0" />
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.0.7" />
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.49-beta">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<!--
Microsoft.WindowsPackageManager.ComInterop nuget targets .NET Framework:
https://www.nuget.org/packages/Microsoft.WindowsPackageManager.ComInterop#readme-body-tab
To workaround this issue in this .net project:
- Suppress warning 1701 (Package not compatible)
- Do not include nuget assets
- Generate a property for this package so the path can be referenced
- Copy the WINMD to the $(TargetDir) before the build starts
- Feed the $(TargetDir)\WINMD path to CsWinRT in order to generate the projected classes
NOTE: Suppressing the warning only is not enough as this will cause CoreClrInitFailure (0x80008089) error.
-->
<PackageReference Include="Microsoft.WindowsPackageManager.ComInterop" Version="1.7.10091-preview">
<NoWarn>NU1701</NoWarn>
<GeneratePathProperty>true</GeneratePathProperty>
<IncludeAssets>none</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.WindowsPackageManager.Configuration.OutOfProc" Version="1.7.10091-preview">
<GeneratePathProperty>True</GeneratePathProperty>
</PackageReference>
</ItemGroup>
<Target Name="CopyWinmdToTargetDir" BeforeTargets="BeforeBuild">
<Copy SourceFiles="$(PkgMicrosoft_WindowsPackageManager_ComInterop)\lib\Microsoft.Management.Deployment.winmd" DestinationFolder="$(TargetDir)" />
<Copy SourceFiles="$(PkgMicrosoft_WindowsPackageManager_ComInterop)\runtimes\win10-$(Platform)\native\winrtact.dll" DestinationFolder="$(TargetDir)" />
<Copy SourceFiles="$(PkgMicrosoft_WindowsPackageManager_Configuration_OutOfProc)\runtimes\win10-$(Platform)\native\Microsoft.Management.Configuration.dll" DestinationFolder="$(TargetDir)" />
<Copy SourceFiles="$(PkgMicrosoft_WindowsPackageManager_Configuration_OutOfProc)\runtimes\win10-$(Platform)\native\Microsoft.Management.Configuration.winmd" DestinationFolder="$(TargetDir)" />
</Target>
</Project>
@@ -0,0 +1,50 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
namespace WindowsPackageManager.Interop;
internal sealed class ClassModel
{
/// <summary>
/// Gets the interface for the projected class type generated by CsWinRT
/// </summary>
public Type InterfaceType { get; init; }
/// <summary>
/// Gets the projected class type generated by CsWinRT
/// </summary>
public Type ProjectedClassType { get; init; }
/// <summary>
/// Gets the clsids for each context (e.g. OutOfProcProd, OutOfProcDev)
/// </summary>
public IReadOnlyDictionary<ClsidContext, Guid> Clsids { get; init; }
/// <summary>
/// Get CLSID based on the provided context
/// </summary>
/// <param name="context">Context</param>
/// <returns>CLSID for the provided context.</returns>
/// <exception cref="InvalidOperationException">Throw an exception if the clsid context is not available for the current instance.</exception>
public Guid GetClsid(ClsidContext context)
{
if (!Clsids.TryGetValue(context, out var clsid))
{
throw new InvalidOperationException($"{ProjectedClassType.FullName} is not implemented in context {context}");
}
return clsid;
}
/// <summary>
/// Get IID corresponding to the COM object
/// </summary>
/// <returns>IID.</returns>
public Guid GetIid()
{
return InterfaceType.GUID;
}
}
@@ -0,0 +1,118 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using Microsoft.Management.Deployment;
namespace WindowsPackageManager.Interop;
internal static class ClassesDefinition
{
private static Dictionary<Type, ClassModel> Classes { get; } = new()
{
[typeof(PackageManager)] = new()
{
ProjectedClassType = typeof(PackageManager),
InterfaceType = typeof(IPackageManager),
Clsids = new Dictionary<ClsidContext, Guid>()
{
[ClsidContext.Prod] = new Guid("C53A4F16-787E-42A4-B304-29EFFB4BF597"),
[ClsidContext.Dev] = new Guid("74CB3139-B7C5-4B9E-9388-E6616DEA288C"),
},
},
[typeof(FindPackagesOptions)] = new()
{
ProjectedClassType = typeof(FindPackagesOptions),
InterfaceType = typeof(IFindPackagesOptions),
Clsids = new Dictionary<ClsidContext, Guid>()
{
[ClsidContext.Prod] = new Guid("572DED96-9C60-4526-8F92-EE7D91D38C1A"),
[ClsidContext.Dev] = new Guid("1BD8FF3A-EC50-4F69-AEEE-DF4C9D3BAA96"),
},
},
[typeof(CreateCompositePackageCatalogOptions)] = new()
{
ProjectedClassType = typeof(CreateCompositePackageCatalogOptions),
InterfaceType = typeof(ICreateCompositePackageCatalogOptions),
Clsids = new Dictionary<ClsidContext, Guid>()
{
[ClsidContext.Prod] = new Guid("526534B8-7E46-47C8-8416-B1685C327D37"),
[ClsidContext.Dev] = new Guid("EE160901-B317-4EA7-9CC6-5355C6D7D8A7"),
},
},
[typeof(InstallOptions)] = new()
{
ProjectedClassType = typeof(InstallOptions),
InterfaceType = typeof(IInstallOptions),
Clsids = new Dictionary<ClsidContext, Guid>()
{
[ClsidContext.Prod] = new Guid("1095F097-EB96-453B-B4E6-1613637F3B14"),
[ClsidContext.Dev] = new Guid("44FE0580-62F7-44D4-9E91-AA9614AB3E86"),
},
},
[typeof(UninstallOptions)] = new()
{
ProjectedClassType = typeof(UninstallOptions),
InterfaceType = typeof(IUninstallOptions),
Clsids = new Dictionary<ClsidContext, Guid>()
{
[ClsidContext.Prod] = new Guid("E1D9A11E-9F85-4D87-9C17-2B93143ADB8D"),
[ClsidContext.Dev] = new Guid("AA2A5C04-1AD9-46C4-B74F-6B334AD7EB8C"),
},
},
[typeof(PackageMatchFilter)] = new()
{
ProjectedClassType = typeof(PackageMatchFilter),
InterfaceType = typeof(IPackageMatchFilter),
Clsids = new Dictionary<ClsidContext, Guid>()
{
[ClsidContext.Prod] = new Guid("D02C9DAF-99DC-429C-B503-4E504E4AB000"),
[ClsidContext.Dev] = new Guid("3F85B9F4-487A-4C48-9035-2903F8A6D9E8"),
},
},
};
/// <summary>
/// Get CLSID based on the provided context for the specified type
/// </summary>
/// <typeparam name="T">Projected class type</typeparam>
/// <param name="context">Context</param>
/// <returns>CLSID for the provided context and type, or throw an exception if not found.</returns>
/// <exception cref="InvalidOperationException">Throws an exception if type is not a project class.</exception>
public static Guid GetClsid<T>(ClsidContext context)
{
ValidateType<T>();
return Classes[typeof(T)].GetClsid(context);
}
/// <summary>
/// Get IID corresponding to the COM object
/// </summary>
/// <typeparam name="T">Projected class type</typeparam>
/// <returns>IID or throw an exception if not found.</returns>
/// <exception cref="InvalidOperationException">Throws an exception if type is not a project class.</exception>
public static Guid GetIid<T>()
{
ValidateType<T>();
return Classes[typeof(T)].GetIid();
}
/// <summary>
/// Validate that the provided type is defined.
/// </summary>
/// <param name="type">Projected class type</param>
/// <exception cref="InvalidOperationException">Throws an exception if type is not a project class.</exception>
private static void ValidateType<TType>()
{
if (!Classes.ContainsKey(typeof(TType)))
{
throw new InvalidOperationException($"{typeof(TType).Name} is not a projected class type.");
}
}
}
@@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
namespace WindowsPackageManager.Interop;
public enum ClsidContext
{
// Production CLSID Guids
Prod,
// Development CLSID Guids
Dev,
}
@@ -0,0 +1,60 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Runtime.InteropServices;
using WinRT;
namespace WindowsPackageManager.Interop;
/// <summary>
/// Factory for creating winget COM objects using manual activation
/// to have them in an elevated context.
/// </summary>
/// <remarks>
/// This needs to be called from an elevated context, or the winget
/// server will reject the connection.
///
/// The WinGetServerManualActivation_CreateInstance function used here is defined in
/// https://github.com/microsoft/winget-cli/blob/master/src/WinGetServer/WinGetServerManualActivation_Client.cpp
///
/// This class is based on what the winget cmdlets do. See
/// https://github.com/microsoft/winget-cli/blob/master/src/PowerShell/Microsoft.WinGet.Client/Helpers/ComObjectFactory.cs
/// </remarks>
public class WindowsPackageManagerElevatedFactory : WindowsPackageManagerFactory
{
// The only CLSID context supported by the DLL we call is Prod.
// If we want to use Dev classes we have to use a Dev version of the DLL.
public WindowsPackageManagerElevatedFactory()
: base(ClsidContext.Prod)
{
}
protected override unsafe T CreateInstance<T>(Guid clsid, Guid iid)
{
void* pUnknown = null;
try
{
var hr = WinGetServerManualActivation_CreateInstance(in clsid, in iid, 0, out pUnknown);
Marshal.ThrowExceptionForHR(hr);
return MarshalInterface<T>.FromAbi((IntPtr)pUnknown);
}
finally
{
// CoCreateInstance and FromAbi both AddRef on the native object.
// Release once to prevent memory leak.
if (pUnknown is not null)
{
Marshal.Release((IntPtr)pUnknown);
}
}
}
[DllImport("winrtact.dll", ExactSpelling = true)]
private static unsafe extern int WinGetServerManualActivation_CreateInstance(
in Guid clsid,
in Guid iid,
uint flags,
out void* instance);
}
@@ -0,0 +1,58 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using Microsoft.Management.Deployment;
namespace WindowsPackageManager.Interop;
/// <summary>
/// Factory class for creating WinGet COM objects.
/// Details about each method can be found in the source IDL:
/// https://github.com/microsoft/winget-cli/blob/master/src/Microsoft.Management.Deployment/PackageManager.idl
/// </summary>
public abstract class WindowsPackageManagerFactory
{
private readonly ClsidContext _clsidContext;
public WindowsPackageManagerFactory(ClsidContext clsidContext)
{
_clsidContext = clsidContext;
}
/// <summary>
/// Creates an instance of the class <typeparamref name="T"/>.
/// </summary>
/// <remarks>
/// Type <typeparamref name="T"/> must be one of the types defined in the winget COM API.
/// Implementations of this method can assume that <paramref name="clsid"/> and <paramref name="iid"/>
/// are the right GUIDs for the class in the given context.
/// </remarks>
protected abstract T CreateInstance<T>(Guid clsid, Guid iid);
public PackageManager CreatePackageManager() => CreateInstance<PackageManager>();
public FindPackagesOptions CreateFindPackagesOptions() => CreateInstance<FindPackagesOptions>();
public CreateCompositePackageCatalogOptions CreateCreateCompositePackageCatalogOptions() => CreateInstance<CreateCompositePackageCatalogOptions>();
public InstallOptions CreateInstallOptions() => CreateInstance<InstallOptions>();
public UninstallOptions CreateUninstallOptions() => CreateInstance<UninstallOptions>();
public PackageMatchFilter CreatePackageMatchFilter() => CreateInstance<PackageMatchFilter>();
/// <summary>
/// Creates an instance of the class <typeparamref name="T"/>.
/// </summary>
/// <remarks>
/// This is a helper for calling the derived class's <see cref="CreateInstance{T}(Guid, Guid)"/>
/// method with the appropriate GUIDs.
/// </remarks>
private T CreateInstance<T>()
{
var clsid = ClassesDefinition.GetClsid<T>(_clsidContext);
var iid = ClassesDefinition.GetIid<T>();
return CreateInstance<T>(clsid, iid);
}
}
@@ -0,0 +1,39 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Runtime.InteropServices;
using Windows.Win32;
using Windows.Win32.System.Com;
using WinRT;
namespace WindowsPackageManager.Interop;
public class WindowsPackageManagerStandardFactory : WindowsPackageManagerFactory
{
public WindowsPackageManagerStandardFactory(ClsidContext clsidContext = ClsidContext.Prod)
: base(clsidContext)
{
}
protected override T CreateInstance<T>(Guid clsid, Guid iid)
{
var pUnknown = IntPtr.Zero;
try
{
var hr = PInvoke.CoCreateInstance(clsid, null, CLSCTX.CLSCTX_LOCAL_SERVER, iid, out var result);
Marshal.ThrowExceptionForHR(hr);
pUnknown = Marshal.GetIUnknownForObject(result);
return MarshalGeneric<T>.FromAbi(pUnknown);
}
finally
{
// CoCreateInstance and FromAbi both AddRef on the native object.
// Release once to prevent memory leak.
if (pUnknown != IntPtr.Zero)
{
Marshal.Release(pUnknown);
}
}
}
}