ComHelpers
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Windows.Win32.Foundation;
using Windows.Win32.System.Com;
namespace Windows.Win32
{
internal static class ComHelpers
{
private static readonly HRESULT COR_E_OBJECTDISPOSED = (HRESULT)(-2146232798);
private static readonly HRESULT S_OK = (HRESULT)0;
internal static bool BuiltInComSupported { get; } = !AppContext.TryGetSwitch("System.Runtime.InteropServices.BuiltInComInterop.IsSupported", out bool isEnabled) | isEnabled;
internal unsafe static ComScope<T> GetComScope<[IsUnmanaged] T>([Nullable(2)] object object) where T : struct, IComIID
{
return new ComScope<T>(GetComPointer<T>(object));
}
internal static ComScope<T> TryGetComScope<[IsUnmanaged] T>([Nullable(2)] object object) where T : struct, IComIID
{
HRESULT hr;
return TryGetComScope<T>(object, out hr);
}
internal unsafe static ComScope<T> TryGetComScope<[IsUnmanaged] T>([Nullable(2)] object object, out HRESULT hr) where T : struct, IComIID
{
return new ComScope<T>(TryGetComPointer<T>(object, out hr));
}
internal unsafe static T* GetComPointer<[IsUnmanaged] T>([Nullable(2)] object object) where T : struct, IComIID
{
HRESULT result;
T* result2 = TryGetComPointer<T>(object, out result);
result.ThrowOnFailure((IntPtr)0);
return result2;
}
internal unsafe static T* TryGetComPointer<[IsUnmanaged] T>([Nullable(2)] object object) where T : struct, IComIID
{
HRESULT result;
return TryGetComPointer<T>(object, out result);
}
internal static bool SupportsInterface<[IsUnmanaged] T>([Nullable(2)] object object) where T : struct, IComIID
{
HRESULT hr;
ComScope<T> comScope = TryGetComScope<T>(object, out hr);
try {
return hr.Succeeded;
} finally {
comScope.Dispose();
}
}
internal unsafe static T* TryGetComPointer<[IsUnmanaged] T>([Nullable(2)] object object, out HRESULT result) where T : struct, IComIID
{
if (object == null) {
result = HRESULT.E_POINTER;
return null;
}
IUnknown* ptr = null;
IntPtr unknown;
if (object is IManagedWrapper)
ptr = (IUnknown*)(long)WinFormsComWrappers.Instance.GetOrCreateComInterfaceForObject(object, CreateComInterfaceFlags.None);
else if (!ComWrappers.TryGetComInstance(object, out unknown)) {
try {
ptr = (IUnknown*)(long)Marshal.GetIUnknownForObject(object);
} catch (Exception) {
}
} else {
ptr = (IUnknown*)(long)unknown;
}
if (ptr == null) {
result = HRESULT.E_NOINTERFACE;
return null;
}
if (typeof(T) == typeof(IUnknown)) {
result = HRESULT.S_OK;
return (T*)ptr;
}
result = ptr->QueryInterface(ref IID.GetRef<T>(), out void* ppvObject);
ptr->Release();
return (T*)ppvObject;
}
public unsafe static bool TryUnwrapComWrapperCCW<[Nullable(1)] TWrapper>(IUnknown* unknown, [Nullable(2)] [NotNullWhen(true)] out TWrapper interface) where TWrapper : class
{
if (ComWrappers.TryGetObject((IntPtr)unknown, out object obj)) {
TWrapper val = obj as TWrapper;
if (val != null) {
interface = val;
return true;
}
}
interface = null;
return false;
}
internal unsafe static bool TryGetObjectForIUnknown<[Nullable(1)] TObject, [IsUnmanaged] TInterface>(ComScope<TInterface> comScope, [Nullable(2)] [NotNullWhen(true)] out TObject object) where TObject : class where TInterface : struct, IComIID
{
return TryGetObjectForIUnknown<TObject, TInterface>(comScope.Value, out object);
}
internal unsafe static bool TryGetObjectForIUnknown<[Nullable(1)] TObject, [IsUnmanaged] TInterface>(TInterface* comPointer, [Nullable(2)] [NotNullWhen(true)] out TObject object) where TObject : class where TInterface : struct, IComIID
{
if (comPointer == null) {
object = null;
return false;
}
IUnknown* ptr = (IUnknown*)comPointer;
if (typeof(TInterface) == typeof(IUnknown))
return TryGetObjectForIUnknown(ptr, out object);
if (ptr->QueryInterface(IID.Get<IUnknown>(), (void**)(&ptr)).Failed) {
object = null;
return false;
}
return TryGetObjectForIUnknown(ptr, out object);
}
internal unsafe static bool TryGetObjectForIUnknown<[Nullable(1)] TObject>(IUnknown* unknown, [Nullable(2)] [NotNullWhen(true)] out TObject object) where TObject : class
{
return TryGetObjectForIUnknown(unknown, false, out object);
}
internal unsafe static bool TryGetObjectForIUnknown<[Nullable(1)] TObject>(IUnknown* unknown, bool takeOwnership, [Nullable(2)] [NotNullWhen(true)] out TObject object) where TObject : class
{
object = null;
if (unknown != null)
try {
object = (TObject)GetObjectForIUnknown(unknown);
return true;
} catch (Exception) {
return false;
} finally {
if (takeOwnership)
unknown->Release();
}
return false;
}
internal unsafe static bool WrapsManagedObject<[IsUnmanaged] T>([Nullable(1)] object object, T* comPointer) where T : struct, IComIID
{
if (comPointer != null) {
ComScope<IUnknown> scope = new ComScope<IUnknown>(null);
try {
((IUnknown*)comPointer)->QueryInterface(IID.Get<IUnknown>(), (void**)ref scope).ThrowOnFailure((IntPtr)0);
if (!ComWrappers.TryGetObject((IntPtr)ref scope, out object obj)) {
ComScope<IUnknown> comScope = new ComScope<IUnknown>((IUnknown*)(long)Marshal.GetIUnknownForObject(object));
try {
return comScope.Value == (void*)ref scope;
} finally {
comScope.Dispose();
}
}
return object == obj;
} finally {
scope.Dispose();
}
}
return false;
}
[return: Nullable(1)]
internal unsafe static object GetObjectForIUnknown<[IsUnmanaged] TInterface>(TInterface* comPointer) where TInterface : struct, IComIID
{
if (comPointer == null)
throw new ArgumentNullException("comPointer");
IUnknown* ptr = (IUnknown*)comPointer;
if (typeof(TInterface) == typeof(IUnknown))
return GetObjectForIUnknown(ptr);
ptr->QueryInterface(IID.Get<IUnknown>(), (void**)(&ptr)).ThrowOnFailure((IntPtr)0);
return GetObjectForIUnknown(ptr);
}
[return: Nullable(1)]
internal unsafe static object GetObjectForIUnknown<[IsUnmanaged] TInterface>(ComScope<TInterface> comScope) where TInterface : struct, IComIID
{
return GetObjectForIUnknown<TInterface>(comScope.Value);
}
[return: Nullable(1)]
internal unsafe static object GetObjectForIUnknown(IUnknown* unknown)
{
if (unknown == null)
throw new ArgumentNullException("unknown");
if (ComWrappers.TryGetObject((IntPtr)unknown, out object obj))
return obj;
if (BuiltInComSupported)
return Marshal.GetObjectForIUnknown((IntPtr)unknown);
return WinFormsComStrategy.Instance.GetOrCreateObjectForComInstance((IntPtr)unknown, CreateObjectFlags.Unwrap);
}
public unsafe static ComScope<ITypeInfo> GetRegisteredTypeInfo(Guid typeLibrary, ushort majorVersion, ushort minorVersion, Guid interfaceId)
{
ComScope<ITypeLib> scope = new ComScope<ITypeLib>(null);
try {
PInvokeCore.LoadRegTypeLib(ref typeLibrary, majorVersion, minorVersion, 0, (ITypeLib**)ref scope).ThrowOnFailure((IntPtr)0);
ComScope<ITypeInfo> scope2 = new ComScope<ITypeInfo>(null);
scope.Value->GetTypeInfoOfGuid(ref interfaceId, (ITypeInfo**)ref scope2).ThrowOnFailure((IntPtr)0);
return scope2;
} finally {
scope.Dispose();
}
}
internal unsafe static HRESULT UnwrapCCW<[IsUnmanaged] TThis, TInterface>(TThis* this, out TInterface object) where TThis : struct where TInterface : class
{
object = ComWrappers.ComInterfaceDispatch.GetInstance<TInterface>((ComWrappers.ComInterfaceDispatch*)this);
if (object != null)
return S_OK;
return COR_E_OBJECTDISPOSED;
}
internal unsafe static void PopulateIUnknown<[IsUnmanaged] TComInterface>(IUnknown.Vtbl* vtable) where TComInterface : struct
{
PopulateIUnknownImpl<TComInterface>(vtable);
if (vtable->QueryInterface_1 == (IntPtr)(void*)null)
throw new NotImplementedException("v-tables cannot be accessed unless the Windows.Win32.ComHelpers.PopulateIUnknownImpl partial method is implemented.");
}
private unsafe static void PopulateIUnknownImpl<[IsUnmanaged] TComInterface>(IUnknown.Vtbl* vtable) where TComInterface : struct
{
WinFormsComWrappers.PopulateIUnknownVTable(vtable);
}
}
}