diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Resources/Strings.resx b/src/coreclr/nativeaot/System.Private.CoreLib/src/Resources/Strings.resx
index c1578ad1a155..28eac7190c2e 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Resources/Strings.resx
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Resources/Strings.resx
@@ -3097,4 +3097,7 @@
The argv[0] argument cannot include a double quote.
+
+ Attempt to update previously set global instance.
+
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
index 9cbef4c2c297..0c237f8af254 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
@@ -208,6 +208,7 @@
+
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.CoreRT.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.CoreRT.cs
new file mode 100644
index 000000000000..6f26cba112c1
--- /dev/null
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.CoreRT.cs
@@ -0,0 +1,384 @@
+// 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
+{
+ ///
+ /// Enumeration of flags for .
+ ///
+ [Flags]
+ public enum CreateComInterfaceFlags
+ {
+ None = 0,
+
+ ///
+ /// The caller will provide an IUnknown Vtable.
+ ///
+ ///
+ /// 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 Reference Tracker hosting
+ /// calling of the IUnknown API during a GC is possible.
+ ///
+ CallerDefinedIUnknown = 1,
+
+ ///
+ /// Flag used to indicate the COM interface should implement IReferenceTrackerTarget.
+ /// 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.
+ ///
+ TrackerSupport = 2,
+ }
+
+ ///
+ /// Enumeration of flags for .
+ ///
+ [Flags]
+ public enum CreateObjectFlags
+ {
+ None = 0,
+
+ ///
+ /// Indicate if the supplied external COM object implements the IReferenceTracker.
+ ///
+ TrackerObject = 1,
+
+ ///
+ /// Ignore any internal caching and always create a unique instance.
+ ///
+ UniqueInstance = 2,
+ }
+
+ ///
+ /// Internal enumeration used by the runtime to indicate the scenario for which ComWrappers is being used.
+ ///
+ internal enum ComWrappersScenario
+ {
+ Instance = 0,
+ TrackerSupportGlobalInstance = 1,
+ MarshallingGlobalInstance = 2,
+ }
+
+ ///
+ /// Class for managing wrappers of COM IUnknown types.
+ ///
+ [CLSCompliant(false)]
+ public abstract partial class ComWrappers
+ {
+ ///
+ /// Interface type and pointer to targeted VTable.
+ ///
+ public struct ComInterfaceEntry
+ {
+ ///
+ /// Interface IID.
+ ///
+ public Guid IID;
+
+ ///
+ /// Memory must have the same lifetime as the memory returned from the call to .
+ ///
+ public IntPtr Vtable;
+ }
+
+ ///
+ /// ABI for function dispatch of a COM interface.
+ ///
+ public struct ComInterfaceDispatch
+ {
+ public IntPtr Vtable;
+
+ ///
+ /// Given a from a generated Vtable, convert to the target type.
+ ///
+ /// Desired type.
+ /// Pointer supplied to Vtable function entry.
+ /// Instance of type associated with dispatched function call.
+ public static unsafe T GetInstance(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(GCHandle.InternalGet(comInstance->GcHandle));
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct ComInterfaceInstance
+ {
+ internal IntPtr GcHandle;
+ }
+ }
+
+ ///
+ /// Globally registered instance of the ComWrappers class for reference tracker support.
+ ///
+ private static ComWrappers? s_globalInstanceForTrackerSupport;
+
+ ///
+ /// Globally registered instance of the ComWrappers class for marshalling.
+ ///
+ private static ComWrappers? s_globalInstanceForMarshalling;
+
+ ///
+ /// Create a COM representation of the supplied object that can be passed to a non-managed environment.
+ ///
+ /// The managed object to expose outside the .NET runtime.
+ /// Flags used to configure the generated interface.
+ /// The generated COM interface that can be passed outside the .NET runtime.
+ public IntPtr GetOrCreateComInterfaceForObject(object instance, CreateComInterfaceFlags flags)
+ {
+ IntPtr ptr;
+ if (!TryGetOrCreateComInterfaceForObjectInternal(this, instance, flags, out ptr))
+ throw new ArgumentException();
+
+ return ptr;
+ }
+
+ ///
+ /// Create a COM representation of the supplied object that can be passed to a non-managed environment.
+ ///
+ /// The implementation to use when creating the COM representation.
+ /// The managed object to expose outside the .NET runtime.
+ /// Flags used to configure the generated interface.
+ /// The generated COM interface that can be passed outside the .NET runtime or IntPtr.Zero if it could not be created.
+ /// Returns true if a COM representation could be created, false otherwise
+ ///
+ /// If is null, the global instance (if registered) will be used.
+ ///
+ private static bool TryGetOrCreateComInterfaceForObjectInternal(ComWrappers? impl, object instance, CreateComInterfaceFlags flags, out IntPtr retValue)
+ {
+ if (instance == null)
+ throw new ArgumentNullException(nameof(instance));
+
+ throw new NotImplementedException();
+ }
+
+ ///
+ /// Compute the desired Vtable for respecting the values of .
+ ///
+ /// Target of the returned Vtables.
+ /// Flags used to compute Vtables.
+ /// The number of elements contained in the returned memory.
+ /// pointer containing memory for all COM interface entries.
+ ///
+ /// All memory returned from this function must either be unmanaged memory, pinned managed memory, or have been
+ /// allocated with the API.
+ ///
+ /// If the interface entries cannot be created and a negative or null
and a non-zero are returned,
+ /// the call to will throw a .
+ ///
+ protected unsafe abstract ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count);
+
+ // 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)
+ {
+ 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;
+ return null;
+ }
+
+ return impl.ComputeVtables(obj, flags, out count);
+ }
+
+ ///
+ /// Get the currently registered managed object or creates a new managed object and registers it.
+ ///
+ /// Object to import for usage into the .NET runtime.
+ /// Flags used to describe the external object.
+ /// Returns a managed object associated with the supplied external COM object.
+ public object GetOrCreateObjectForComInstance(IntPtr externalComObject, CreateObjectFlags flags)
+ {
+ object? obj;
+ if (!TryGetOrCreateObjectForComInstanceInternal(this, externalComObject, flags, null, out obj))
+ throw new ArgumentNullException();
+
+ return obj!;
+ }
+
+ ///
+ /// Create a managed object for the object pointed at by respecting the values of .
+ ///
+ /// Object to import for usage into the .NET runtime.
+ /// Flags used to describe the external object.
+ /// Returns a managed object associated with the supplied external COM object.
+ ///
+ /// If the object cannot be created and null
is returned, the call to will throw a .
+ ///
+ 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)
+ {
+ 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;
+
+ return impl.CreateObject(externalComObject, flags);
+ }
+
+ ///
+ /// Get the currently registered managed object or uses the supplied managed object and registers it.
+ ///
+ /// Object to import for usage into the .NET runtime.
+ /// Flags used to describe the external object.
+ /// The to be used as the wrapper for the external object
+ /// Returns a managed object associated with the supplied external COM object.
+ ///
+ /// If the instance already has an associated external object a will be thrown.
+ ///
+ public object GetOrRegisterObjectForComInstance(IntPtr externalComObject, CreateObjectFlags flags, object wrapper)
+ {
+ if (wrapper == null)
+ throw new ArgumentNullException(nameof(externalComObject));
+
+ object? obj;
+ if (!TryGetOrCreateObjectForComInstanceInternal(this, externalComObject, flags, wrapper, out obj))
+ throw new ArgumentNullException();
+
+ return obj!;
+ }
+
+ ///
+ /// Get the currently registered managed object or creates a new managed object and registers it.
+ ///
+ /// The implementation to use when creating the managed object.
+ /// Object to import for usage into the .NET runtime.
+ /// Flags used to describe the external object.
+ /// The to be used as the wrapper for the external object.
+ /// The managed object associated with the supplied external COM object or null if it could not be created.
+ /// Returns true if a managed object could be retrieved/created, false otherwise
+ ///
+ /// If is null, the global instance (if registered) will be used.
+ ///
+ private static bool TryGetOrCreateObjectForComInstanceInternal(ComWrappers? impl, IntPtr externalComObject, CreateObjectFlags flags, object? wrapperMaybe, out object? retValue)
+ {
+ if (externalComObject == IntPtr.Zero)
+ throw new ArgumentNullException(nameof(externalComObject));
+
+ object? wrapperMaybeLocal = wrapperMaybe;
+ retValue = null;
+ throw new NotImplementedException();
+ }
+
+ ///
+ /// Called when a request is made for a collection of objects to be released outside of normal object or COM interface lifetime.
+ ///
+ /// Collection of objects to release.
+ protected abstract void ReleaseObjects(IEnumerable objects);
+
+ // Call to execute the virtual instance function
+ internal static void CallReleaseObjects(ComWrappers? comWrappersImpl, IEnumerable objects)
+ => (comWrappersImpl ?? s_globalInstanceForTrackerSupport!).ReleaseObjects(objects);
+
+ ///
+ /// Register a instance to be used as the global instance for reference tracker support.
+ ///
+ /// Instance to register
+ ///
+ /// This function can only be called a single time. Subsequent calls to this function will result
+ /// in a being thrown.
+ ///
+ /// Scenarios where this global instance may be used are:
+ /// * Object tracking via the and flags.
+ ///
+ public static void RegisterForTrackerSupport(ComWrappers instance)
+ {
+ if (instance == null)
+ throw new ArgumentNullException(nameof(instance));
+
+ if (null != Interlocked.CompareExchange(ref s_globalInstanceForTrackerSupport, instance, null))
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_ResetGlobalComWrappersInstance);
+ }
+
+ throw new NotImplementedException();
+ }
+
+
+ ///
+ /// Register a instance to be used as the global instance for marshalling in the runtime.
+ ///
+ /// Instance to register
+ ///
+ /// This function can only be called a single time. Subsequent calls to this function will result
+ /// in a 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
+ ///
+ 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);
+ }
+
+ // 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.
+ throw new NotImplementedException();
+ }
+
+ ///
+ /// Get the runtime provided IUnknown implementation.
+ ///
+ /// Function pointer to QueryInterface.
+ /// Function pointer to AddRef.
+ /// Function pointer to Release.
+ protected static void GetIUnknownImpl(out IntPtr fpQueryInterface, out IntPtr fpAddRef, out IntPtr fpRelease)
+ => throw new NotImplementedException();
+
+ internal static int CallICustomQueryInterface(object customQueryInterfaceMaybe, ref Guid iid, out IntPtr ppObject)
+ {
+ var customQueryInterface = customQueryInterfaceMaybe as ICustomQueryInterface;
+ if (customQueryInterface is null)
+ {
+ ppObject = IntPtr.Zero;
+ return -1; // See TryInvokeICustomQueryInterfaceResult
+ }
+
+ return (int)customQueryInterface.GetInterface(ref iid, out ppObject);
+ }
+ }
+}