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

Implement new COM interop API for RCW/CCW creation/management #32091

Merged
merged 83 commits into from
Mar 7, 2020
Merged
Show file tree
Hide file tree
Changes from 82 commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
6dae493
Add API to SPCL.
AaronRobinsonMSFT Jan 21, 2020
aa43ec8
Revert previous work.
AaronRobinsonMSFT Jan 21, 2020
e8846f1
Add API in stub form.
AaronRobinsonMSFT Jan 22, 2020
7e0c328
Implement RuntimeHelpers.AllocateTypeAssociatedMemory()
AaronRobinsonMSFT Jan 22, 2020
a1b0507
Add tests for RuntimeHelpers.AllocateTypeAssociatedMemory
AaronRobinsonMSFT Jan 22, 2020
39d5155
Update interop lib import/export API headers
AaronRobinsonMSFT Jan 23, 2020
8e4e655
Implement the ComWrappers.GetIUnknownImpl() API
AaronRobinsonMSFT Jan 23, 2020
1e88958
Add project for testing ComWrappers API.
AaronRobinsonMSFT Jan 23, 2020
c375198
Stub out remaining ComWrapper QCall APIs
AaronRobinsonMSFT Jan 24, 2020
2b118c6
Add pseudo implementation and test for ComWrappers.RegisterForReferen…
AaronRobinsonMSFT Jan 24, 2020
705d02f
Add and validate metasigs for invoking static methods in ComWrappers …
AaronRobinsonMSFT Jan 24, 2020
7ec6cc9
Implement the runtime interation for managed object wrapper creation.
AaronRobinsonMSFT Jan 28, 2020
67949a7
Write test for creation of managed object wrapper with tracker support.
AaronRobinsonMSFT Jan 28, 2020
4ed9275
Make managed object wrappers persistent until the associated managed …
AaronRobinsonMSFT Jan 28, 2020
9249f51
Update export namespaces in InteropLib
AaronRobinsonMSFT Jan 29, 2020
2a22388
Surround UNREACHABLE() with braces because of how it is defined.
AaronRobinsonMSFT Jan 29, 2020
33720f7
Remove unnecessary GCProtect sections.
AaronRobinsonMSFT Jan 30, 2020
1a87a11
Retain the External Object Context in the SyncBlock and handle cleanup.
AaronRobinsonMSFT Jan 31, 2020
dbfa73f
Rename ExtObjCxtIterator to RuntimeCallContext.
AaronRobinsonMSFT Feb 2, 2020
1073eba
Change the CreateReference() API to an informing style API (i.e. Foun…
AaronRobinsonMSFT Feb 2, 2020
0d80d43
Make global pegging field on RCWWalker public.
AaronRobinsonMSFT Feb 5, 2020
152a5e4
Place all exported functions into a single compilation unit for Inter…
AaronRobinsonMSFT Feb 5, 2020
1bfb390
Add new API to make object release requests.
AaronRobinsonMSFT Feb 6, 2020
3792204
Address object release issues.
AaronRobinsonMSFT Feb 6, 2020
c83e6ec
Update public API
AaronRobinsonMSFT Feb 7, 2020
d402fec
Add support for checking if an external object implements the
AaronRobinsonMSFT Feb 8, 2020
e508c34
Add comment about IEnumerable optimization.
AaronRobinsonMSFT Feb 8, 2020
46c357c
Delay load ole32.dll to get RoGetAgileReference using GetProcAddress.
AaronRobinsonMSFT Feb 8, 2020
0d3b9cf
TEST - WIP
AaronRobinsonMSFT Feb 8, 2020
6e41699
Reduce uses of GetReferenceTracker() - unsafe function.
AaronRobinsonMSFT Feb 8, 2020
4a58326
Validation bug for converting to MOW.
AaronRobinsonMSFT Feb 9, 2020
f40127f
Move the ComInterfaceEntry to the ABI namespace.
AaronRobinsonMSFT Feb 10, 2020
a023e85
Mock Tracker Runtime impl
AaronRobinsonMSFT Feb 10, 2020
942b19e
Forward declare Win32 API.
AaronRobinsonMSFT Feb 11, 2020
76eae00
Spelling mistake.
AaronRobinsonMSFT Feb 11, 2020
fa9af01
Move registration of global ComWrappers to be entirely in managed code.
AaronRobinsonMSFT Feb 11, 2020
c00ebd2
Remove unused message.
AaronRobinsonMSFT Feb 12, 2020
4eb1240
Add error message to managed resources.
AaronRobinsonMSFT Feb 12, 2020
61dc744
Implement Peg/Unpeg
AaronRobinsonMSFT Feb 13, 2020
4d41a28
Add additional testing.
AaronRobinsonMSFT Feb 13, 2020
241e204
Test ignore cache logic.
AaronRobinsonMSFT Feb 13, 2020
aeb9403
Change EnsureActiveWrapperAndAddRef() API to take an indirect OBJECTREF
AaronRobinsonMSFT Feb 13, 2020
362ea4b
Fix Release builds
AaronRobinsonMSFT Feb 13, 2020
4d4d395
Apply review feedback about active wrapper API.
AaronRobinsonMSFT Feb 14, 2020
5a9cbb4
Update src/coreclr/src/interop/comwrappers.h
AaronRobinsonMSFT Feb 14, 2020
48a1480
Bug in ignore cache scenario - found during local GCStress run.
AaronRobinsonMSFT Feb 14, 2020
4bea8da
Finish off minimal testing scenarios.
AaronRobinsonMSFT Feb 14, 2020
1bfea8c
Fix build issues on macOS using clang.
AaronRobinsonMSFT Feb 14, 2020
1bb76c9
Update Windows' build in response to macOS build fixes.
AaronRobinsonMSFT Feb 14, 2020
96ca3dc
Release build fixes
AaronRobinsonMSFT Feb 14, 2020
c05b565
Remove ATL dependency from Mock Reference Tracker runtime library.
AaronRobinsonMSFT Feb 15, 2020
6e4fcce
Always include ComHelper.h in COM tests.
AaronRobinsonMSFT Feb 15, 2020
2006fc6
Add Release() impl on test ComSmartPtr<T>.
AaronRobinsonMSFT Feb 15, 2020
0041a35
Create a "support" and "nosupport" ComWrappers implementation.
AaronRobinsonMSFT Feb 15, 2020
05c0035
Properly add a platform not supported implementation for ComWrappers.
AaronRobinsonMSFT Feb 15, 2020
8a69732
Really remove the ComWrappers.NoSupport.cs file.
AaronRobinsonMSFT Feb 15, 2020
e8d616c
Forgot GetIUnknownImpl() API in the not supported version of ComWrapp…
AaronRobinsonMSFT Feb 15, 2020
b8703b1
Remove InteropLib shutdown logic.
AaronRobinsonMSFT Feb 15, 2020
07cbc68
Acquire RefCache at the same time as creating ObjectCache. This avoids
AaronRobinsonMSFT Feb 16, 2020
c609b1c
Add StressLogs to InteropLibInterface
AaronRobinsonMSFT Feb 16, 2020
20a5385
Cast OBJECTREFs so they work in StressLog macros.
AaronRobinsonMSFT Feb 16, 2020
8e97865
Add a ComWrappers feature flag.
AaronRobinsonMSFT Feb 19, 2020
5fa679c
Remove duplicate entry.
AaronRobinsonMSFT Feb 20, 2020
e836507
Review feedback.
AaronRobinsonMSFT Feb 21, 2020
e60bce2
Add Type? to the GetOrCreateObjectForComInstance() API call.
AaronRobinsonMSFT Feb 22, 2020
75e8401
Revert "Add Type? to the GetOrCreateObjectForComInstance() API call."
AaronRobinsonMSFT Feb 24, 2020
33194f9
Update GetOrCreateObjectForComInstance() to accept 'object?' as the
AaronRobinsonMSFT Feb 24, 2020
7147244
Validate failure for reuse of wrapper for external object.
AaronRobinsonMSFT Feb 24, 2020
1d87df4
Fix bug in failure case of attempting to reuse a wrapper.
AaronRobinsonMSFT Feb 24, 2020
17b5404
Remove IAgileReference usage.
AaronRobinsonMSFT Feb 24, 2020
9cc5ccc
Apply API review comments.
AaronRobinsonMSFT Mar 3, 2020
1ae8587
Update test to align with API changes.
AaronRobinsonMSFT Mar 3, 2020
96fa8cc
Merge conflict.
AaronRobinsonMSFT Mar 3, 2020
fc2f20a
Review feedback.
AaronRobinsonMSFT Mar 3, 2020
9c4ecd5
Add stub for AllocateTypeAssociatedMemory() in Mono build.
AaronRobinsonMSFT Mar 4, 2020
bc25078
Style and name.
AaronRobinsonMSFT Mar 4, 2020
d96ef4b
Move RuntimeHelpers.AllocateTypeAssociatedMemory tests to src/libraries.
AaronRobinsonMSFT Mar 6, 2020
bfa455d
Missed static
AaronRobinsonMSFT Mar 6, 2020
b7c5c44
Skip tests on Mono.
AaronRobinsonMSFT Mar 6, 2020
f305cb0
Unit test fix for RuntimeHelpers.AllocateTypeAssociatedMemory().
AaronRobinsonMSFT Mar 7, 2020
642ca9b
Bad merge on rebase.
AaronRobinsonMSFT Mar 7, 2020
fa45add
Minor rewording for the interoplib interface.
AaronRobinsonMSFT Mar 7, 2020
c7c6839
Feedback on naming.
AaronRobinsonMSFT Mar 7, 2020
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
2 changes: 2 additions & 0 deletions src/coreclr/clr.featuredefines.props
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<FeatureArrayStubAsIL Condition="'$(Platform)' != 'x86'">true</FeatureArrayStubAsIL>
<FeatureMulticastStubAsIL Condition="'$(Platform)' != 'x86'">true</FeatureMulticastStubAsIL>
<FeatureStubsAsIL Condition="'$(Platform)' == 'arm64'">true</FeatureStubsAsIL>
<FeatureComWrappers>true</FeatureComWrappers>
<FeatureCominterop>true</FeatureCominterop>
<FeatureClassicCominterop>true</FeatureClassicCominterop>
<FeatureCominteropUnmanagedActivation>true</FeatureCominteropUnmanagedActivation>
Expand All @@ -54,6 +55,7 @@
<DefineConstants Condition="'$(FeatureStubsAsIL)' == 'true'">$(DefineConstants);FEATURE_STUBS_AS_IL</DefineConstants>
<DefineConstants Condition="'$(FeatureClassicCominterop)' == 'true'">$(DefineConstants);FEATURE_CLASSIC_COMINTEROP</DefineConstants>
<DefineConstants Condition="'$(FeatureCollectibleALC)' == 'true'">$(DefineConstants);FEATURE_COLLECTIBLE_ALC</DefineConstants>
<DefineConstants Condition="'$(FeatureComWrappers)' == 'true'">$(DefineConstants);FEATURE_COMWRAPPERS</DefineConstants>
<DefineConstants Condition="'$(FeatureCominterop)' == 'true'">$(DefineConstants);FEATURE_COMINTEROP</DefineConstants>
<DefineConstants Condition="'$(FeatureCominteropApartmentSupport)' == 'true'">$(DefineConstants);FEATURE_COMINTEROP_APARTMENT_SUPPORT</DefineConstants>
<DefineConstants Condition="'$(FeatureCominteropUnmanagedActivation)' == 'true'">$(DefineConstants);FEATURE_COMINTEROP_UNMANAGED_ACTIVATION</DefineConstants>
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/clrdefinitions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ add_compile_definitions($<$<NOT:$<BOOL:$<TARGET_PROPERTY:CROSSGEN_COMPONENT>>>:F
add_definitions(-DFEATURE_COLLECTIBLE_TYPES)

if(CLR_CMAKE_TARGET_WIN32)
add_definitions(-DFEATURE_COMWRAPPERS)
add_definitions(-DFEATURE_CLASSIC_COMINTEROP)
add_definitions(-DFEATURE_COMINTEROP)
add_definitions(-DFEATURE_COMINTEROP_APARTMENT_SUPPORT)
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ add_subdirectory(tools)
add_subdirectory(unwinder)
add_subdirectory(ildasm)
add_subdirectory(ilasm)
add_subdirectory(interop)

if(CLR_CMAKE_HOST_UNIX)
add_subdirectory(palrt)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,9 @@
<ItemGroup>
<Compile Include="$(BclSourcesRoot)\System\Diagnostics\Eventing\XplatEventLogger.cs" Condition="'$(FeatureXplatEventSource)' == 'true'" />
</ItemGroup>
<ItemGroup Condition="'$(FeatureComWrappers)' == 'true'">
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\ComWrappers.cs" />
</ItemGroup>
<ItemGroup Condition="'$(FeatureCominterop)' == 'true'">
<Compile Include="$(CommonPath)System\Runtime\InteropServices\IDispatch.cs">
<Link>Common\System\Runtime\InteropServices\IDispatch.cs</Link>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,28 @@ internal static unsafe bool ObjectHasComponentSize(object obj)

return (MethodTable *)Unsafe.Add(ref Unsafe.As<byte, IntPtr>(ref obj.GetRawData()), -1);
}

/// <summary>
/// Allocate memory that is associated with the <paramref name="type"/> and
/// will be freed if and when the <see cref="System.Type"/> is unloaded.
/// </summary>
/// <param name="type">Type associated with the allocated memory.</param>
/// <param name="size">Amount of memory in bytes to allocate.</param>
/// <returns>The allocated memory</returns>
public static IntPtr AllocateTypeAssociatedMemory(Type type, int size)
{
RuntimeType? rt = type as RuntimeType;
if (rt == null)
throw new ArgumentException(SR.Arg_MustBeType, nameof(type));

if (size < 0)
throw new ArgumentOutOfRangeException(nameof(size));

return AllocateTypeAssociatedMemoryInternal(new QCallTypeHandle(ref rt), (uint)size);
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
}

[DllImport(RuntimeHelpers.QCall)]
private static extern IntPtr AllocateTypeAssociatedMemoryInternal(QCallTypeHandle type, uint size);
}

// Helper class to assist with unsafe pinning of arbitrary objects.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
// 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 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.
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
/// </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>
/// 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 IntPtr Vtable;

/// <summary>
/// Given a <see cref="System.IntPtr"/> from a generated Vtable, convert to the target type.
/// </summary>
/// <typeparam name="T">Desired type.</typeparam>
/// <param name="dispatchPtr">Pointer supplied to Vtable function entry.</param>
/// <returns>Instance of type associated with dispatched function call.</returns>
public static unsafe T GetInstance<T>(ComInterfaceDispatch* dispatchPtr) where T : class
{
// See the dispatch section in the runtime for details on the masking below.
const long DispatchThisPtrMask = ~0xfL;
var comInstance = *(ComInterfaceInstance**)(((long)dispatchPtr) & DispatchThisPtrMask);

return Unsafe.As<T>(GCHandle.InternalGet(comInstance->GcHandle));
}

private struct ComInterfaceInstance
{
public IntPtr GcHandle;
}
}

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

/// <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>
public IntPtr GetOrCreateComInterfaceForObject(object instance, CreateComInterfaceFlags flags)
{
if (instance == null)
throw new ArgumentNullException(nameof(instance));

AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
ComWrappers impl = this;
return GetOrCreateComInterfaceForObjectInternal(ObjectHandleOnStack.Create(ref impl), ObjectHandleOnStack.Create(ref instance), flags);
}

[DllImport(RuntimeHelpers.QCall)]
private static extern IntPtr GetOrCreateComInterfaceForObjectInternal(ObjectHandleOnStack comWrappersImpl, ObjectHandleOnStack instance, CreateComInterfaceFlags flags);

/// <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 <code>null</code> is returned, the call to <see cref="ComWrappers.GetOrCreateComInterfaceForObject(object, CreateComInterfaceFlags)"/> will throw a <see cref="System.ArgumentNullException"/>.
/// </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)
=> (comWrappersImpl ?? s_globalInstance!).ComputeVtables(obj, flags, out count);

/// <summary>
/// Get the currently registered managed object or creates a new 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>
/// <returns>Returns a managed object associated with the supplied external COM object.</returns>
public object GetOrCreateObjectForComInstance(IntPtr externalComObject, CreateObjectFlags flags)
{
return GetOrCreateObjectForComInstanceInternal(externalComObject, flags, null);
}

/// <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"/>.
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
/// </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)
=> (comWrappersImpl ?? s_globalInstance!).CreateObject(externalComObject, flags);

/// <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>
/// <returns>Returns a managed object associated with the supplied external COM object.</returns>
/// <remarks>
/// 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)
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
{
if (wrapper == null)
throw new ArgumentNullException(nameof(externalComObject));

return GetOrCreateObjectForComInstanceInternal(externalComObject, flags, wrapper);
}

private object GetOrCreateObjectForComInstanceInternal(IntPtr externalComObject, CreateObjectFlags flags, object? wrapperMaybe)
{
if (externalComObject == IntPtr.Zero)
throw new ArgumentNullException(nameof(externalComObject));

ComWrappers impl = this;
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
object? wrapperMaybeLocal = wrapperMaybe;
object? retValue = null;
GetOrCreateObjectForComInstanceInternal(ObjectHandleOnStack.Create(ref impl), externalComObject, flags, ObjectHandleOnStack.Create(ref wrapperMaybeLocal), ObjectHandleOnStack.Create(ref retValue));

return retValue!;
}

[DllImport(RuntimeHelpers.QCall)]
private static extern void GetOrCreateObjectForComInstanceInternal(ObjectHandleOnStack comWrappersImpl, IntPtr externalComObject, CreateObjectFlags flags, ObjectHandleOnStack wrapper, ObjectHandleOnStack 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);

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

/// <summary>
/// Register this class's implementation to be used as the single global instance.
/// </summary>
/// <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:
/// * Object tracking via the <see cref="CreateComInterfaceFlags.TrackerSupport" /> and <see cref="CreateObjectFlags.TrackerObject" /> flags.
/// * Usage of COM related Marshal APIs.
/// </remarks>
public void RegisterAsGlobalInstance()
{
if (null != Interlocked.CompareExchange(ref s_globalInstance, this, null))
{
throw new InvalidOperationException(SR.InvalidOperation_ResetGlobalComWrappersInstance);
}
}

/// <summary>
/// Get the runtime provided IUnknown implementation.
/// </summary>
/// <param name="fpQueryInterface">Function pointer to QueryInterface.</param>
/// <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)
=> GetIUnknownImplInternal(out fpQueryInterface, out fpAddRef, out fpRelease);

[DllImport(RuntimeHelpers.QCall)]
private static extern void GetIUnknownImplInternal(out IntPtr fpQueryInterface, out IntPtr fpAddRef, out IntPtr fpRelease);
}
}
2 changes: 2 additions & 0 deletions src/coreclr/src/dlls/mscoree/coreclr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ set(CORECLR_LIBRARIES
gcinfo # Condition="'$(TargetCpu)'=='amd64' or '$(TargetCpu)' == 'arm' or '$(TargetCpu)' == 'arm64'"
ildbsymlib
utilcode
v3binder
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
libraries-native
interop
)

if(CLR_CMAKE_TARGET_WIN32)
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/src/inc/CrstTypes.def
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,9 @@ End
Crst RCWCleanupList
End

Crst ExternalObjectContextCache
End

Crst ReDacl
End

Expand Down
Loading