Skip to content

Commit

Permalink
Fixes after refactoring in dotnet/runtime
Browse files Browse the repository at this point in the history
  • Loading branch information
kant2002 committed Feb 8, 2021
1 parent ca7cf22 commit 9c5744a
Showing 1 changed file with 82 additions and 112 deletions.
Original file line number Diff line number Diff line change
@@ -1,61 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections;
using System.Threading;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Internal.Runtime.CompilerServices;

namespace System.Runtime.InteropServices
{
/// <summary>
/// Enumeration of flags for <see cref="ComWrappers.GetOrCreateComInterfaceForObject(object, CreateComInterfaceFlags)"/>.
/// </summary>
[Flags]
public enum CreateComInterfaceFlags
{
None = 0,

/// <summary>
/// The caller will provide an IUnknown Vtable.
/// </summary>
/// <remarks>
/// This is useful in scenarios when the caller has no need to rely on an IUnknown instance
/// that is used when running managed code is not possible (i.e. during a GC). In traditional
/// COM scenarios this is common, but scenarios involving <see href="https://docs.microsoft.com/windows/win32/api/windows.ui.xaml.hosting.referencetracker/nn-windows-ui-xaml-hosting-referencetracker-ireferencetrackertarget">Reference Tracker hosting</see>
/// calling of the IUnknown API during a GC is possible.
/// </remarks>
CallerDefinedIUnknown = 1,

/// <summary>
/// Flag used to indicate the COM interface should implement <see href="https://docs.microsoft.com/windows/win32/api/windows.ui.xaml.hosting.referencetracker/nn-windows-ui-xaml-hosting-referencetracker-ireferencetrackertarget">IReferenceTrackerTarget</see>.
/// When this flag is passed, the resulting COM interface will have an internal implementation of IUnknown
/// and as such none should be supplied by the caller.
/// </summary>
TrackerSupport = 2,
}

/// <summary>
/// Enumeration of flags for <see cref="ComWrappers.GetOrCreateObjectForComInstance(IntPtr, CreateObjectFlags)"/>.
/// </summary>
[Flags]
public enum CreateObjectFlags
{
None = 0,

/// <summary>
/// Indicate if the supplied external COM object implements the <see href="https://docs.microsoft.com/windows/win32/api/windows.ui.xaml.hosting.referencetracker/nn-windows-ui-xaml-hosting-referencetracker-ireferencetracker">IReferenceTracker</see>.
/// </summary>
TrackerObject = 1,

/// <summary>
/// Ignore any internal caching and always create a unique instance.
/// </summary>
UniqueInstance = 2,
}

/// <summary>
/// Internal enumeration used by the runtime to indicate the scenario for which ComWrappers is being used.
/// </summary>
Expand All @@ -69,32 +23,13 @@ internal enum ComWrappersScenario
/// <summary>
/// Class for managing wrappers of COM IUnknown types.
/// </summary>
[CLSCompliant(false)]
public abstract partial class ComWrappers
{
/// <summary>
/// Interface type and pointer to targeted VTable.
/// </summary>
public struct ComInterfaceEntry
{
/// <summary>
/// Interface IID.
/// </summary>
public Guid IID;

/// <summary>
/// Memory must have the same lifetime as the memory returned from the call to <see cref="ComputeVtables(object, CreateComInterfaceFlags, out int)"/>.
/// </summary>
public IntPtr Vtable;
}

/// <summary>
/// ABI for function dispatch of a COM interface.
/// </summary>
public struct ComInterfaceDispatch
public partial struct ComInterfaceDispatch
{
public IntPtr Vtable;

/// <summary>
/// Given a <see cref="System.IntPtr"/> from a generated Vtable, convert to the target type.
/// </summary>
Expand All @@ -110,10 +45,9 @@ public static unsafe T GetInstance<T>(ComInterfaceDispatch* dispatchPtr) where T
return Unsafe.As<T>(GCHandle.InternalGet(comInstance->GcHandle));
}

[StructLayout(LayoutKind.Sequential)]
private struct ComInterfaceInstance
{
internal IntPtr GcHandle;
public IntPtr GcHandle;
}
}

Expand All @@ -127,17 +61,25 @@ private struct ComInterfaceInstance
/// </summary>
private static ComWrappers? s_globalInstanceForMarshalling;

private static long s_instanceCounter;
private readonly long id = Interlocked.Increment(ref s_instanceCounter);

/// <summary>
/// Create a COM representation of the supplied object that can be passed to a non-managed environment.
/// </summary>
/// <param name="instance">The managed object to expose outside the .NET runtime.</param>
/// <param name="flags">Flags used to configure the generated interface.</param>
/// <returns>The generated COM interface that can be passed outside the .NET runtime.</returns>
/// <remarks>
/// If a COM representation was previously created for the specified <paramref name="instance" /> using
/// this <see cref="ComWrappers" /> instance, the previously created COM interface will be returned.
/// If not, a new one will be created.
/// </remarks>
public IntPtr GetOrCreateComInterfaceForObject(object instance, CreateComInterfaceFlags flags)
{
IntPtr ptr;
if (!TryGetOrCreateComInterfaceForObjectInternal(this, instance, flags, out ptr))
throw new ArgumentException();
throw new ArgumentException(null, nameof(instance));

return ptr;
}
Expand All @@ -153,29 +95,18 @@ public IntPtr GetOrCreateComInterfaceForObject(object instance, CreateComInterfa
/// <remarks>
/// If <paramref name="impl" /> is <c>null</c>, the global instance (if registered) will be used.
/// </remarks>
private static bool TryGetOrCreateComInterfaceForObjectInternal(ComWrappers? impl, object instance, CreateComInterfaceFlags flags, out IntPtr retValue)
private static bool TryGetOrCreateComInterfaceForObjectInternal(ComWrappers impl, object instance, CreateComInterfaceFlags flags, out IntPtr retValue)
{
if (instance == null)
throw new ArgumentNullException(nameof(instance));

throw new NotImplementedException();
return TryGetOrCreateComInterfaceForObjectInternal(ObjectHandleOnStack.Create(ref impl), impl.id, ObjectHandleOnStack.Create(ref instance), flags, out retValue);
}

/// <summary>
/// Compute the desired Vtable for <paramref name="obj"/> respecting the values of <paramref name="flags"/>.
/// </summary>
/// <param name="obj">Target of the returned Vtables.</param>
/// <param name="flags">Flags used to compute Vtables.</param>
/// <param name="count">The number of elements contained in the returned memory.</param>
/// <returns><see cref="ComInterfaceEntry" /> pointer containing memory for all COM interface entries.</returns>
/// <remarks>
/// All memory returned from this function must either be unmanaged memory, pinned managed memory, or have been
/// allocated with the <see cref="System.Runtime.CompilerServices.RuntimeHelpers.AllocateTypeAssociatedMemory(Type, int)"/> API.
///
/// If the interface entries cannot be created and a negative <paramref name="count" /> or <code>null</code> and a non-zero <paramref name="count" /> are returned,
/// the call to <see cref="ComWrappers.GetOrCreateComInterfaceForObject(object, CreateComInterfaceFlags)"/> will throw a <see cref="System.ArgumentException"/>.
/// </remarks>
protected unsafe abstract ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count);
private static bool TryGetOrCreateComInterfaceForObjectInternal(ObjectHandleOnStack comWrappersImpl, long wrapperId, ObjectHandleOnStack instance, CreateComInterfaceFlags flags, out IntPtr retValue)
{
throw new NotImplementedException();
}

// Called by the runtime to execute the abstract instance function
internal static unsafe void* CallComputeVtables(ComWrappersScenario scenario, ComWrappers? comWrappersImpl, object obj, CreateComInterfaceFlags flags, out int count)
Expand Down Expand Up @@ -209,26 +140,20 @@ private static bool TryGetOrCreateComInterfaceForObjectInternal(ComWrappers? imp
/// <param name="externalComObject">Object to import for usage into the .NET runtime.</param>
/// <param name="flags">Flags used to describe the external object.</param>
/// <returns>Returns a managed object associated with the supplied external COM object.</returns>
/// <remarks>
/// If a managed object was previously created for the specified <paramref name="externalComObject" />
/// using this <see cref="ComWrappers" /> instance, the previously created object will be returned.
/// If not, a new one will be created.
/// </remarks>
public object GetOrCreateObjectForComInstance(IntPtr externalComObject, CreateObjectFlags flags)
{
object? obj;
if (!TryGetOrCreateObjectForComInstanceInternal(this, externalComObject, flags, null, out obj))
throw new ArgumentNullException();
if (!TryGetOrCreateObjectForComInstanceInternal(this, externalComObject, IntPtr.Zero, flags, null, out obj))
throw new ArgumentNullException(nameof(externalComObject));

return obj!;
}

/// <summary>
/// Create a managed object for the object pointed at by <paramref name="externalComObject"/> respecting the values of <paramref name="flags"/>.
/// </summary>
/// <param name="externalComObject">Object to import for usage into the .NET runtime.</param>
/// <param name="flags">Flags used to describe the external object.</param>
/// <returns>Returns a managed object associated with the supplied external COM object.</returns>
/// <remarks>
/// If the object cannot be created and <code>null</code> is returned, the call to <see cref="ComWrappers.GetOrCreateObjectForComInstance(IntPtr, CreateObjectFlags)"/> will throw a <see cref="System.ArgumentNullException"/>.
/// </remarks>
protected abstract object? CreateObject(IntPtr externalComObject, CreateObjectFlags flags);

// Called by the runtime to execute the abstract instance function.
internal static object? CallCreateObject(ComWrappersScenario scenario, ComWrappers? comWrappersImpl, IntPtr externalComObject, CreateObjectFlags flags)
{
Expand Down Expand Up @@ -263,13 +188,34 @@ public object GetOrCreateObjectForComInstance(IntPtr externalComObject, CreateOb
/// If the <paramref name="wrapper"/> instance already has an associated external object a <see cref="System.NotSupportedException"/> will be thrown.
/// </remarks>
public object GetOrRegisterObjectForComInstance(IntPtr externalComObject, CreateObjectFlags flags, object wrapper)
{
return GetOrRegisterObjectForComInstance(externalComObject, flags, wrapper, IntPtr.Zero);
}

/// <summary>
/// Get the currently registered managed object or uses the supplied managed object and registers it.
/// </summary>
/// <param name="externalComObject">Object to import for usage into the .NET runtime.</param>
/// <param name="flags">Flags used to describe the external object.</param>
/// <param name="wrapper">The <see cref="object"/> to be used as the wrapper for the external object</param>
/// <param name="inner">Inner for COM aggregation scenarios</param>
/// <returns>Returns a managed object associated with the supplied external COM object.</returns>
/// <remarks>
/// This method override is for registering an aggregated COM instance with its associated inner. The inner
/// will be released when the associated wrapper is eventually freed. Note that it will be released on a thread
/// in an unknown apartment state. If the supplied inner is not known to be a free-threaded instance then
/// it is advised to not supply the inner.
///
/// If the <paramref name="wrapper"/> instance already has an associated external object a <see cref="System.NotSupportedException"/> will be thrown.
/// </remarks>
public object GetOrRegisterObjectForComInstance(IntPtr externalComObject, CreateObjectFlags flags, object wrapper, IntPtr inner)
{
if (wrapper == null)
throw new ArgumentNullException(nameof(externalComObject));
throw new ArgumentNullException(nameof(wrapper));

object? obj;
if (!TryGetOrCreateObjectForComInstanceInternal(this, externalComObject, flags, wrapper, out obj))
throw new ArgumentNullException();
if (!TryGetOrCreateObjectForComInstanceInternal(this, externalComObject, inner, flags, wrapper, out obj))
throw new ArgumentNullException(nameof(externalComObject));

return obj!;
}
Expand All @@ -279,28 +225,38 @@ public object GetOrRegisterObjectForComInstance(IntPtr externalComObject, Create
/// </summary>
/// <param name="impl">The <see cref="ComWrappers" /> implementation to use when creating the managed object.</param>
/// <param name="externalComObject">Object to import for usage into the .NET runtime.</param>
/// <param name="innerMaybe">The inner instance if aggregation is involved</param>
/// <param name="flags">Flags used to describe the external object.</param>
/// <param name="wrapperMaybe">The <see cref="object"/> to be used as the wrapper for the external object.</param>
/// <param name="retValue">The managed object associated with the supplied external COM object or <c>null</c> if it could not be created.</param>
/// <returns>Returns <c>true</c> if a managed object could be retrieved/created, <c>false</c> otherwise</returns>
/// <remarks>
/// If <paramref name="impl" /> is <c>null</c>, the global instance (if registered) will be used.
/// </remarks>
private static bool TryGetOrCreateObjectForComInstanceInternal(ComWrappers? impl, IntPtr externalComObject, CreateObjectFlags flags, object? wrapperMaybe, out object? retValue)
private static bool TryGetOrCreateObjectForComInstanceInternal(
ComWrappers impl,
IntPtr externalComObject,
IntPtr innerMaybe,
CreateObjectFlags flags,
object? wrapperMaybe,
out object? retValue)
{
if (externalComObject == IntPtr.Zero)
throw new ArgumentNullException(nameof(externalComObject));

// If the inner is supplied the Aggregation flag should be set.
if (innerMaybe != IntPtr.Zero && !flags.HasFlag(CreateObjectFlags.Aggregation))
throw new InvalidOperationException(SR.InvalidOperation_SuppliedInnerMustBeMarkedAggregation);

object? wrapperMaybeLocal = wrapperMaybe;
retValue = null;
throw new NotImplementedException();
return TryGetOrCreateObjectForComInstanceInternal(ObjectHandleOnStack.Create(ref impl), impl.id, externalComObject, innerMaybe, flags, ObjectHandleOnStack.Create(ref wrapperMaybeLocal), ObjectHandleOnStack.Create(ref retValue));
}

/// <summary>
/// Called when a request is made for a collection of objects to be released outside of normal object or COM interface lifetime.
/// </summary>
/// <param name="objects">Collection of objects to release.</param>
protected abstract void ReleaseObjects(IEnumerable objects);
private static bool TryGetOrCreateObjectForComInstanceInternal(ObjectHandleOnStack comWrappersImpl, long wrapperId, IntPtr externalComObject, IntPtr innerMaybe, CreateObjectFlags flags, ObjectHandleOnStack wrapper, ObjectHandleOnStack retValue)
{
throw new NotImplementedException();
}

// Call to execute the virtual instance function
internal static void CallReleaseObjects(ComWrappers? comWrappersImpl, IEnumerable objects)
Expand All @@ -327,9 +283,13 @@ public static void RegisterForTrackerSupport(ComWrappers instance)
throw new InvalidOperationException(SR.InvalidOperation_ResetGlobalComWrappersInstance);
}

throw new NotImplementedException();
SetGlobalInstanceRegisteredForTrackerSupport(instance.id);
}

private static void SetGlobalInstanceRegisteredForTrackerSupport(long id)
{
throw new NotImplementedException();
}

/// <summary>
/// Register a <see cref="ComWrappers" /> instance to be used as the global instance for marshalling in the runtime.
Expand Down Expand Up @@ -357,6 +317,11 @@ public static void RegisterForMarshalling(ComWrappers instance)
// Indicate to the runtime that a global instance has been registered for marshalling.
// This allows the native runtime know to call into the managed ComWrappers only if a
// global instance is registered for marshalling.
SetGlobalInstanceRegisteredForMarshalling(instance.id);
}

private static void SetGlobalInstanceRegisteredForMarshalling(long id)
{
throw new NotImplementedException();
}

Expand All @@ -367,7 +332,12 @@ public static void RegisterForMarshalling(ComWrappers instance)
/// <param name="fpAddRef">Function pointer to AddRef.</param>
/// <param name="fpRelease">Function pointer to Release.</param>
protected static void GetIUnknownImpl(out IntPtr fpQueryInterface, out IntPtr fpAddRef, out IntPtr fpRelease)
=> throw new NotImplementedException();
=> GetIUnknownImplInternal(out fpQueryInterface, out fpAddRef, out fpRelease);

private static void GetIUnknownImplInternal(out IntPtr fpQueryInterface, out IntPtr fpAddRef, out IntPtr fpRelease)
{
throw new NotImplementedException();
}

internal static int CallICustomQueryInterface(object customQueryInterfaceMaybe, ref Guid iid, out IntPtr ppObject)
{
Expand Down

0 comments on commit 9c5744a

Please sign in to comment.