Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate registration for global ComWrappers instance for tracker support and marshalling #35681

Merged
merged 2 commits into from
May 5, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ public enum CreateObjectFlags
UniqueInstance = 2,
}

/// <summary>
/// Internal enumeration used by the runtime to indicate the scenario for which ComWrappers is being used.
/// </summary>
internal enum ComWrappersScenario
{
Instance = 0,
TrackerSupportGlobalInstance = 1,
MarshallingGlobalInstance = 2,
}

/// <summary>
/// Class for managing wrappers of COM IUnknown types.
/// </summary>
Expand Down Expand Up @@ -107,9 +117,14 @@ private struct ComInterfaceInstance
}

/// <summary>
/// Globally registered instance of the ComWrappers class.
/// Globally registered instance of the ComWrappers class for reference tracker support.
/// </summary>
private static ComWrappers? s_globalInstance;
private static ComWrappers? s_globalInstanceForTrackerSupport;

/// <summary>
/// Globally registered instance of the ComWrappers class for marshalling.
/// </summary>
private static ComWrappers? s_globalInstanceForMarshalling;

/// <summary>
/// Create a COM representation of the supplied object that can be passed to a non-managed environment.
Expand Down Expand Up @@ -164,10 +179,23 @@ private static bool TryGetOrCreateComInterfaceForObjectInternal(ComWrappers? imp
/// </remarks>
protected unsafe abstract ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count);

// Call to execute the abstract instance function
internal static unsafe void* CallComputeVtables(ComWrappers? comWrappersImpl, object obj, CreateComInterfaceFlags flags, out int count)
// Called by the runtime to execute the abstract instance function
internal static unsafe void* CallComputeVtables(ComWrappers? comWrappersImpl, object obj, CreateComInterfaceFlags flags, ComWrappersScenario scenario, out int count)
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
{
ComWrappers? impl = comWrappersImpl ?? s_globalInstance;
ComWrappers? impl = null;
switch (scenario)
{
case ComWrappersScenario.Instance:
impl = comWrappersImpl;
break;
case ComWrappersScenario.TrackerSupportGlobalInstance:
impl = s_globalInstanceForTrackerSupport;
break;
case ComWrappersScenario.MarshallingGlobalInstance:
impl = s_globalInstanceForMarshalling;
break;
}

if (impl is null)
{
count = -1;
Expand Down Expand Up @@ -203,10 +231,23 @@ public object GetOrCreateObjectForComInstance(IntPtr externalComObject, CreateOb
/// </remarks>
protected abstract object? CreateObject(IntPtr externalComObject, CreateObjectFlags flags);

// Call to execute the abstract instance function
internal static object? CallCreateObject(ComWrappers? comWrappersImpl, IntPtr externalComObject, CreateObjectFlags flags)
// Called by the runtime to execute the abstract instance function.
internal static object? CallCreateObject(ComWrappers? comWrappersImpl, IntPtr externalComObject, CreateObjectFlags flags, ComWrappersScenario scenario)
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
{
ComWrappers? impl = comWrappersImpl ?? s_globalInstance;
ComWrappers? impl = null;
switch (scenario)
{
case ComWrappersScenario.Instance:
impl = comWrappersImpl;
break;
case ComWrappersScenario.TrackerSupportGlobalInstance:
impl = s_globalInstanceForTrackerSupport;
break;
case ComWrappersScenario.MarshallingGlobalInstance:
impl = s_globalInstanceForMarshalling;
break;
}

if (impl == null)
return null;

Expand Down Expand Up @@ -268,32 +309,59 @@ private static bool TryGetOrCreateObjectForComInstanceInternal(ComWrappers? impl

// Call to execute the virtual instance function
internal static void CallReleaseObjects(ComWrappers? comWrappersImpl, IEnumerable objects)
=> (comWrappersImpl ?? s_globalInstance!).ReleaseObjects(objects);
=> (comWrappersImpl ?? s_globalInstanceForTrackerSupport!).ReleaseObjects(objects);

/// <summary>
/// Register this class's implementation to be used as the single global instance.
/// Register a <see cref="ComWrappers" /> instance to be used as the global instance for reference tracker support.
/// </summary>
/// <param name="instance">Instance to register</param>
/// <remarks>
/// This function can only be called a single time. Subsequent calls to this function will result
/// in a <see cref="System.InvalidOperationException"/> being thrown.
///
/// Scenarios where the global instance may be used are:
/// Scenarios where this global instance may be used are:
/// * Object tracking via the <see cref="CreateComInterfaceFlags.TrackerSupport" /> and <see cref="CreateObjectFlags.TrackerObject" /> flags.
/// * Usage of COM related Marshal APIs.
/// </remarks>
public void RegisterAsGlobalInstance()
public static void RegisterForTrackerSupport(ComWrappers instance)
{
if (null != Interlocked.CompareExchange(ref s_globalInstance, this, null))
if (instance == null)
throw new ArgumentNullException(nameof(instance));

if (null != Interlocked.CompareExchange(ref s_globalInstanceForTrackerSupport, instance, null))
{
throw new InvalidOperationException(SR.InvalidOperation_ResetGlobalComWrappersInstance);
}
}

/// <summary>
/// Register a <see cref="ComWrappers" /> instance to be used as the global instance for marshalling in the runtime.
/// </summary>
/// <param name="instance">Instance to register</param>
/// <remarks>
/// This function can only be called a single time. Subsequent calls to this function will result
/// in a <see cref="System.InvalidOperationException"/> being thrown.
///
/// Scenarios where this global instance may be used are:
/// * Usage of COM-related Marshal APIs
/// * P/Invokes with COM-related types
/// * COM activation
/// </remarks>
public static void RegisterForMarshalling(ComWrappers instance)
{
if (instance == null)
throw new ArgumentNullException(nameof(instance));

if (null != Interlocked.CompareExchange(ref s_globalInstanceForMarshalling, instance, null))
{
throw new InvalidOperationException(SR.InvalidOperation_ResetGlobalComWrappersInstance);
}

SetGlobalInstanceRegistered();
SetGlobalInstanceRegisteredForMarshalling();
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
}

[DllImport(RuntimeHelpers.QCall)]
[SuppressGCTransition]
private static extern void SetGlobalInstanceRegistered();
private static extern void SetGlobalInstanceRegisteredForMarshalling();

/// <summary>
/// Get the runtime provided IUnknown implementation.
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/src/vm/ecalllist.h
Original file line number Diff line number Diff line change
Expand Up @@ -984,7 +984,7 @@ FCFuncStart(gComWrappersFuncs)
QCFuncElement("GetIUnknownImplInternal", ComWrappersNative::GetIUnknownImpl)
QCFuncElement("TryGetOrCreateComInterfaceForObjectInternal", ComWrappersNative::TryGetOrCreateComInterfaceForObject)
QCFuncElement("TryGetOrCreateObjectForComInstanceInternal", ComWrappersNative::TryGetOrCreateObjectForComInstance)
QCFuncElement("SetGlobalInstanceRegistered", GlobalComWrappers::SetGlobalInstanceRegistered)
QCFuncElement("SetGlobalInstanceRegisteredForMarshalling", GlobalComWrappersForMarshalling::SetGlobalInstanceRegisteredForMarshalling)
FCFuncEnd()
#endif // FEATURE_COMWRAPPERS

Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/src/vm/interopconverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace
_Outptr_ IUnknown** wrapperRaw)
{
#ifdef FEATURE_COMWRAPPERS
return GlobalComWrappers::TryGetOrCreateComInterfaceForObject(instance, (void**)wrapperRaw);
return GlobalComWrappersForMarshalling::TryGetOrCreateComInterfaceForObject(instance, (void**)wrapperRaw);
#else
return false;
#endif // FEATURE_COMWRAPPERS
Expand All @@ -40,7 +40,7 @@ namespace
_Out_ OBJECTREF *pObjOut)
{
#ifdef FEATURE_COMWRAPPERS
return GlobalComWrappers::TryGetOrCreateObjectForComInstance(pUnknown, dwFlags, pObjOut);
return GlobalComWrappersForMarshalling::TryGetOrCreateObjectForComInstance(pUnknown, dwFlags, pObjOut);
#else
return false;
#endif // FEATURE_COMWRAPPERS
Expand Down
Loading