Add support for ComWrappers-based RCWs to the special native WeakReference support...
authorJeremy Koritzinsky <jekoritz@microsoft.com>
Fri, 8 May 2020 02:20:23 +0000 (19:20 -0700)
committerGitHub <noreply@github.com>
Fri, 8 May 2020 02:20:23 +0000 (19:20 -0700)
* Add support for ComWrappers-based RCWs to the special native WeakReference support.

Rename the WinRT weak reference handle to "native COM weak reference" handle.

* Fix line endings.

* Fix line endings (try 2).

* Revert change to prebuilt idl

* Try updating prebuilt again.

* Remove accidental duplicate of the test.

* PR feedback.

* PR Feedback.

* React to global ComWrappers changes.

* Add back WinRT enum member to prebuilt idl.

* Add back old enum member to idl for backcompat.

* Change definition of enum member to explicitly assign the same value.

* Code cleanup and go down a non-allocating route when possible.

* Switch to preemptive mode for the QI call.

* Fix contracts

* Add a check before calling GetComWeakReference so we only call it when the object has interop info attached.

* Apply early check to WeakReference<T> as well.

* Make sure we only make one call to PassiveGetSyncBlock instead of 2.

* PR Feedback.

* ComWrappersNative::GetIdentityForObject can trigger GC since we transition to and from pre-emptive when calling into the external QI.

26 files changed:
src/coreclr/src/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs
src/coreclr/src/debug/daccess/daccess.cpp
src/coreclr/src/debug/daccess/dacdbiimpl.cpp
src/coreclr/src/debug/daccess/request.cpp
src/coreclr/src/dlls/mscorrc/mscorrc.rc
src/coreclr/src/dlls/mscorrc/resource.h
src/coreclr/src/gc/gchandletable.cpp
src/coreclr/src/gc/gcinterface.h
src/coreclr/src/gc/handletable.cpp
src/coreclr/src/gc/objecthandle.cpp
src/coreclr/src/inc/cordebug.idl
src/coreclr/src/pal/prebuilt/inc/cordebug.h
src/coreclr/src/vm/appdomain.hpp
src/coreclr/src/vm/ecalllist.h
src/coreclr/src/vm/gchandleutilities.h
src/coreclr/src/vm/interoplibinterface.cpp
src/coreclr/src/vm/interoplibinterface.h
src/coreclr/src/vm/marshalnative.cpp
src/coreclr/src/vm/runtimehandles.cpp
src/coreclr/src/vm/weakreferencenative.cpp
src/coreclr/tests/src/Interop/CMakeLists.txt
src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/CMakeLists.txt [new file with mode: 0644]
src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceNative.cpp [new file with mode: 0644]
src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceTest.cs [new file with mode: 0644]
src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceTest.csproj [new file with mode: 0644]
src/coreclr/tests/src/Interop/common/ComHelpers.h

index 323e60a..8c37701 100644 (file)
@@ -331,8 +331,15 @@ namespace System.Runtime.InteropServices
             {
                 throw new InvalidOperationException(SR.InvalidOperation_ResetGlobalComWrappersInstance);
             }
+
+            SetGlobalInstanceRegisteredForTrackerSupport();
         }
 
+
+        [DllImport(RuntimeHelpers.QCall)]
+        [SuppressGCTransition]
+        private static extern void SetGlobalInstanceRegisteredForTrackerSupport();
+
         /// <summary>
         /// Register a <see cref="ComWrappers" /> instance to be used as the global instance for marshalling in the runtime.
         /// </summary>
@@ -390,4 +397,4 @@ namespace System.Runtime.InteropServices
             return (int)customQueryInterface.GetInterface(ref iid, out ppObject);
         }
     }
-}
\ No newline at end of file
+}
index a05d4f0..4441145 100644 (file)
@@ -8252,7 +8252,7 @@ void CALLBACK DacHandleWalker::EnumCallbackSOS(PTR_UNCHECKED_OBJECTREF handle, u
     if (param->Type == HNDTYPE_DEPENDENT)
         data.Secondary = GetDependentHandleSecondary(handle.GetAddr()).GetAddr();
 #ifdef FEATURE_COMINTEROP
-    else if (param->Type == HNDTYPE_WEAK_WINRT)
+    else if (param->Type == HNDTYPE_WEAK_NATIVE_COM)
         data.Secondary = HndGetHandleExtraInfo(handle.GetAddr());
 #endif // FEATURE_COMINTEROP
     else
index 905698a..e315265 100644 (file)
@@ -7491,8 +7491,8 @@ UINT32 DacRefWalker::GetHandleWalkerMask()
     if ((mHandleMask & CorHandleWeakRefCount) || (mHandleMask & CorHandleStrongRefCount))
         result |= (1 << HNDTYPE_REFCOUNTED);
 
-    if (mHandleMask & CorHandleWeakWinRT)
-        result |= (1 << HNDTYPE_WEAK_WINRT);
+    if (mHandleMask & CorHandleWeakNativeCom)
+        result |= (1 << HNDTYPE_WEAK_NATIVE_COM);
 #endif // FEATURE_COMINTEROP
 
     if (mHandleMask & CorHandleStrongDependent)
@@ -7667,8 +7667,8 @@ void CALLBACK DacHandleWalker::EnumCallbackDac(PTR_UNCHECKED_OBJECTREF handle, u
             data.i64ExtraData = refCnt;
             break;
 
-        case HNDTYPE_WEAK_WINRT:
-            data.dwType = (DWORD)CorHandleWeakWinRT;
+        case HNDTYPE_WEAK_NATIVE_COM:
+            data.dwType = (DWORD)CorHandleWeakNativeCom;
             break;
 #endif
 
index 2be663e..79880ff 100644 (file)
@@ -3253,7 +3253,7 @@ HRESULT ClrDataAccess::GetHandleEnum(ISOSHandleEnum **ppHandleEnum)
     unsigned int types[] = {HNDTYPE_WEAK_SHORT, HNDTYPE_WEAK_LONG, HNDTYPE_STRONG, HNDTYPE_PINNED, HNDTYPE_VARIABLE, HNDTYPE_DEPENDENT,
                             HNDTYPE_ASYNCPINNED, HNDTYPE_SIZEDREF,
 #ifdef FEATURE_COMINTEROP
-                            HNDTYPE_REFCOUNTED, HNDTYPE_WEAK_WINRT
+                            HNDTYPE_REFCOUNTED, HNDTYPE_WEAK_NATIVE_COM
 #endif
                             };
 
@@ -3291,7 +3291,7 @@ HRESULT ClrDataAccess::GetHandleEnumForGC(unsigned int gen, ISOSHandleEnum **ppH
     unsigned int types[] = {HNDTYPE_WEAK_SHORT, HNDTYPE_WEAK_LONG, HNDTYPE_STRONG, HNDTYPE_PINNED, HNDTYPE_VARIABLE, HNDTYPE_DEPENDENT,
                             HNDTYPE_ASYNCPINNED, HNDTYPE_SIZEDREF,
 #ifdef FEATURE_COMINTEROP
-                            HNDTYPE_REFCOUNTED, HNDTYPE_WEAK_WINRT
+                            HNDTYPE_REFCOUNTED, HNDTYPE_WEAK_NATIVE_COM
 #endif
                             };
 
index 8a7410e..4573e20 100644 (file)
@@ -344,7 +344,7 @@ BEGIN
     IDS_EE_WINRT_NOT_FACTORY_FOR_TYPE           "Windows Runtime factory '%1' is not a factory for Windows Runtime type '%2'."
     IDS_EE_WINRT_INVALID_FACTORY_FOR_TYPE       "Windows Runtime type '%1' has a invalid Windows Runtime factory"
     IDS_EE_CANNOTCAST_NOMARSHAL                 "The Windows Runtime Object can only be used in the threading context where it was created, because it implements INoMarshal or has MarshalingBehaviorAttribute(MarshalingType.None) set."
-    IDS_EE_WINRT_WEAKREF_BAD_TYPE               "The object resolved by a native IWeakReference has an incompatible type for its managed WeakReference instance.\r\nExpected WeakReference target type: '%1'\r\nNative IWeakReference returned type: '%2'"
+    IDS_EE_NATIVE_COM_WEAKREF_BAD_TYPE          "The object resolved by a native IWeakReference has an incompatible type for its managed WeakReference instance.\r\nExpected WeakReference target type: '%1'\r\nNative IWeakReference returned type: '%2'"
 #endif // FEATURE_COMINTEROP
 
     IDS_EE_INTEROP_CODE_SIZE_COMMENT        "Code size"
index 342c057..4011efb 100644 (file)
 
 
 #ifdef FEATURE_COMINTEROP
-#define IDS_EE_WINRT_WEAKREF_BAD_TYPE           0x262e
+#define IDS_EE_NATIVE_COM_WEAKREF_BAD_TYPE           0x262e
 #endif // FEATURE_COMINTEROP
 
 #define IDS_EE_BADMARSHAL_TYPE_ANSIBSTR         0x262f
index b7c4bf2..d3f93b4 100644 (file)
@@ -168,7 +168,7 @@ Object* GCHandleManager::InterlockedCompareExchangeObjectInHandle(OBJECTHANDLE h
 HandleType GCHandleManager::HandleFetchType(OBJECTHANDLE handle)
 {
     uint32_t type = ::HandleFetchType(handle);
-    assert(type >= HNDTYPE_WEAK_SHORT && type <= HNDTYPE_WEAK_WINRT);
+    assert(type >= HNDTYPE_WEAK_SHORT && type <= HNDTYPE_WEAK_NATIVE_COM);
     return static_cast<HandleType>(type);
 }
 
index 122106c..e9bef6a 100644 (file)
@@ -422,18 +422,18 @@ typedef enum
     HNDTYPE_SIZEDREF     = 8,
 
     /*
-     * WINRT WEAK HANDLES
+     * NATIVE WEAK HANDLES
      *
-     * WinRT weak reference handles hold two different types of weak handles to any
+     * Native weak reference handles hold two different types of weak handles to any
      * RCW with an underlying COM object that implements IWeakReferenceSource.  The
      * object reference itself is a short weak handle to the RCW.  In addition an
      * IWeakReference* to the underlying COM object is stored, allowing the handle
      * to create a new RCW if the existing RCW is collected.  This ensures that any
-     * code holding onto a WinRT weak reference can always access an RCW to the
+     * code holding onto a native weak reference can always access an RCW to the
      * underlying COM object as long as it has not been released by all of its strong
      * references.
      */
-    HNDTYPE_WEAK_WINRT   = 9
+    HNDTYPE_WEAK_NATIVE_COM   = 9
 } HandleType;
 
 typedef enum
index 898e843..1b56c74 100644 (file)
@@ -409,10 +409,10 @@ void HndDestroyHandleOfUnknownType(HHANDLETABLE hTable, OBJECTHANDLE handle)
     _ASSERTE(handle);
 
 #ifdef FEATURE_COMINTEROP
-    // If we're being asked to destroy a WinRT weak handle, that will cause a leak
+    // If we're being asked to destroy a native COM weak handle, that will cause a leak
     // of the IWeakReference* that it holds in its extra data. Instead of using this
-    // API use DestroyWinRTWeakHandle instead.
-    _ASSERTE(HandleFetchType(handle) != HNDTYPE_WEAK_WINRT);
+    // API use DestroyNativeComWeakHandle instead.
+    _ASSERTE(HandleFetchType(handle) != HNDTYPE_WEAK_NATIVE_COM);
 #endif // FEATURE_COMINTEROP
 
     // fetch the type and then free normally
index 4a4f201..e6a5160 100644 (file)
@@ -426,7 +426,7 @@ void CALLBACK ScanPointerForProfilerAndETW(_UNCHECKED_OBJECTREF *pObjRef, uintpt
     case    HNDTYPE_WEAK_SHORT:
     case    HNDTYPE_WEAK_LONG:
 #ifdef FEATURE_COMINTEROP
-    case    HNDTYPE_WEAK_WINRT:
+    case    HNDTYPE_WEAK_NATIVE_COM:
 #endif // FEATURE_COMINTEROP
         rootFlags |= kEtwGCRootFlagsWeakRef;
         break;
@@ -520,7 +520,7 @@ static const uint32_t s_rgTypeFlags[] =
     HNDF_EXTRAINFO, // HNDTYPE_DEPENDENT
     HNDF_NORMAL,    // HNDTYPE_ASYNCPINNED
     HNDF_EXTRAINFO, // HNDTYPE_SIZEDREF
-    HNDF_EXTRAINFO, // HNDTYPE_WEAK_WINRT
+    HNDF_EXTRAINFO, // HNDTYPE_WEAK_NATIVE_COM
 };
 
 int getNumberOfSlots()
@@ -1380,7 +1380,7 @@ void Ref_CheckAlive(uint32_t condemned, uint32_t maxgen, uintptr_t lp1)
     {
         HNDTYPE_WEAK_SHORT
 #ifdef FEATURE_COMINTEROP
-        , HNDTYPE_WEAK_WINRT
+        , HNDTYPE_WEAK_NATIVE_COM
 #endif // FEATURE_COMINTEROP
     };
     uint32_t flags = (((ScanContext*) lp1)->concurrent) ? HNDGCF_ASYNC : HNDGCF_NORMAL;
@@ -1439,7 +1439,7 @@ void Ref_UpdatePointers(uint32_t condemned, uint32_t maxgen, ScanContext* sc, Re
         HNDTYPE_REFCOUNTED,
 #endif // FEATURE_COMINTEROP || FEATURE_REDHAWK
 #ifdef FEATURE_COMINTEROP
-        HNDTYPE_WEAK_WINRT,
+        HNDTYPE_WEAK_NATIVE_COM,
 #endif // FEATURE_COMINTEROP
         HNDTYPE_SIZEDREF,
     };
@@ -1485,7 +1485,7 @@ void Ref_ScanHandlesForProfilerAndETW(uint32_t maxgen, uintptr_t lp1, handle_sca
         HNDTYPE_REFCOUNTED,
 #endif // FEATURE_COMINTEROP || FEATURE_REDHAWK
 #ifdef FEATURE_COMINTEROP
-        HNDTYPE_WEAK_WINRT,
+        HNDTYPE_WEAK_NATIVE_COM,
 #endif // FEATURE_COMINTEROP
         HNDTYPE_PINNED,
 //        HNDTYPE_VARIABLE,
@@ -1631,7 +1631,7 @@ void Ref_AgeHandles(uint32_t condemned, uint32_t maxgen, uintptr_t lp1)
         HNDTYPE_REFCOUNTED,
 #endif // FEATURE_COMINTEROP || FEATURE_REDHAWK
 #ifdef FEATURE_COMINTEROP
-        HNDTYPE_WEAK_WINRT,
+        HNDTYPE_WEAK_NATIVE_COM,
 #endif // FEATURE_COMINTEROP
         HNDTYPE_ASYNCPINNED,
         HNDTYPE_SIZEDREF,
@@ -1674,7 +1674,7 @@ void Ref_RejuvenateHandles(uint32_t condemned, uint32_t maxgen, uintptr_t lp1)
         HNDTYPE_REFCOUNTED,
 #endif // FEATURE_COMINTEROP || FEATURE_REDHAWK
 #ifdef FEATURE_COMINTEROP
-        HNDTYPE_WEAK_WINRT,
+        HNDTYPE_WEAK_NATIVE_COM,
 #endif // FEATURE_COMINTEROP
         HNDTYPE_ASYNCPINNED,
         HNDTYPE_SIZEDREF,
@@ -1716,7 +1716,7 @@ void Ref_VerifyHandleTable(uint32_t condemned, uint32_t maxgen, ScanContext* sc)
         HNDTYPE_REFCOUNTED,
 #endif // FEATURE_COMINTEROP || FEATURE_REDHAWK
 #ifdef FEATURE_COMINTEROP
-        HNDTYPE_WEAK_WINRT,
+        HNDTYPE_WEAK_NATIVE_COM,
 #endif // FEATURE_COMINTEROP
         HNDTYPE_ASYNCPINNED,
         HNDTYPE_SIZEDREF,
index 87e1458..be74536 100644 (file)
@@ -2567,7 +2567,8 @@ typedef enum CorGCReferenceType
     CorHandleStrongDependent = 1<<6,
     CorHandleStrongAsyncPinned = 1<<7,
     CorHandleStrongSizedByref = 1<<8,
-    CorHandleWeakWinRT = 1<<9,
+    CorHandleWeakNativeCom = 1<<9,
+    CorHandleWeakWinRT = CorHandleWeakNativeCom,
 
     CorReferenceStack = 0x80000001,
     CorReferenceFinalizer = 80000002,
index 96dc9c0..69c8975 100644 (file)
@@ -6376,7 +6376,8 @@ enum CorGCReferenceType
         CorHandleStrongDependent       = ( 1 << 6 ) ,
         CorHandleStrongAsyncPinned     = ( 1 << 7 ) ,
         CorHandleStrongSizedByref      = ( 1 << 8 ) ,
-        CorHandleWeakWinRT     = ( 1 << 9 ) ,
+        CorHandleWeakNativeCom = ( 1 << 9 ) ,
+        CorHandleWeakWinRT     = CorHandleWeakNativeCom,
         CorReferenceStack      = 0x80000001,
         CorReferenceFinalizer  = 80000002,
         CorHandleStrongOnly    = 0x1e3,
index 0ca41f0..f017b42 100644 (file)
@@ -1110,10 +1110,10 @@ public:
         return ::CreateRefcountedHandle(m_handleStore, object);
     }
 
-    OBJECTHANDLE CreateWinRTWeakHandle(OBJECTREF object, IWeakReference* pWinRTWeakReference)
+    OBJECTHANDLE CreateNativeComWeakHandle(OBJECTREF object, IWeakReference* pComWeakReference)
     {
         WRAPPER_NO_CONTRACT;
-        return ::CreateWinRTWeakHandle(m_handleStore, object, pWinRTWeakReference);
+        return ::CreateNativeComWeakHandle(m_handleStore, object, pComWeakReference);
     }
 #endif // FEATURE_COMINTEROP
 
index 87aa7b6..155ae2c 100644 (file)
@@ -986,6 +986,7 @@ FCFuncStart(gComWrappersFuncs)
     QCFuncElement("TryGetOrCreateComInterfaceForObjectInternal", ComWrappersNative::TryGetOrCreateComInterfaceForObject)
     QCFuncElement("TryGetOrCreateObjectForComInstanceInternal", ComWrappersNative::TryGetOrCreateObjectForComInstance)
     QCFuncElement("SetGlobalInstanceRegisteredForMarshalling", GlobalComWrappersForMarshalling::SetGlobalInstanceRegisteredForMarshalling)
+    QCFuncElement("SetGlobalInstanceRegisteredForTrackerSupport", GlobalComWrappersForTrackerSupport::SetGlobalInstanceRegisteredForTrackerSupport)
 FCFuncEnd()
 #endif // FEATURE_COMWRAPPERS
 
index b875644..d90a2f0 100644 (file)
@@ -201,9 +201,9 @@ inline OBJECTHANDLE CreateGlobalRefcountedHandle(OBJECTREF object)
 // Special handle creation convenience functions
 
 #ifdef FEATURE_COMINTEROP
-inline OBJECTHANDLE CreateWinRTWeakHandle(IGCHandleStore* store, OBJECTREF object, IWeakReference* pWinRTWeakReference)
+inline OBJECTHANDLE CreateNativeComWeakHandle(IGCHandleStore* store, OBJECTREF object, IWeakReference* pComWeakReference)
 {
-    OBJECTHANDLE hnd = store->CreateHandleWithExtraInfo(OBJECTREFToObject(object), HNDTYPE_WEAK_WINRT, (void*)pWinRTWeakReference);
+    OBJECTHANDLE hnd = store->CreateHandleWithExtraInfo(OBJECTREFToObject(object), HNDTYPE_WEAK_NATIVE_COM, (void*)pComWeakReference);
     if (!hnd)
     {
         COMPlusThrowOM();
@@ -363,7 +363,7 @@ inline void DestroyTypedHandle(OBJECTHANDLE handle)
 }
 
 #ifdef FEATURE_COMINTEROP
-inline void DestroyWinRTWeakHandle(OBJECTHANDLE handle)
+inline void DestroyNativeComWeakHandle(OBJECTHANDLE handle)
 {
     CONTRACTL
     {
@@ -375,7 +375,7 @@ inline void DestroyWinRTWeakHandle(OBJECTHANDLE handle)
     CONTRACTL_END;
 
     // Release the WinRT weak reference if we have one. We're assuming that this will not reenter the
-    // runtime, since if we are pointing at a managed object, we should not be using HNDTYPE_WEAK_WINRT
+    // runtime, since if we are pointing at a managed object, we should not be using HNDTYPE_WEAK_NATIVE_COM
     // but rather HNDTYPE_WEAK_SHORT or HNDTYPE_WEAK_LONG.
     void* pExtraInfo = GCHandleUtilities::GetGCHandleManager()->GetExtraInfoFromHandle(handle);
     IWeakReference* pWinRTWeakReference = reinterpret_cast<IWeakReference*>(pExtraInfo);
@@ -385,7 +385,7 @@ inline void DestroyWinRTWeakHandle(OBJECTHANDLE handle)
     }
 
     DiagHandleDestroyed(handle);
-    GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_WEAK_WINRT);
+    GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_WEAK_NATIVE_COM);
 }
 #endif
 
index 934e0bb..3eaf5ba 100644 (file)
@@ -401,7 +401,8 @@ namespace
     Volatile<ExtObjCxtCache*> ExtObjCxtCache::g_Instance;
 
     // Indicator for if a ComWrappers implementation is globally registered
-    bool g_IsGlobalComWrappersRegistered;
+    bool g_IsGlobalComWrappersRegisteredForMarshalling;
+    bool g_IsGlobalComWrappersRegisteredForTrackerSupport;
 
     // Defined handle types for the specific object uses.
     const HandleType InstanceHandleType{ HNDTYPE_STRONG };
@@ -1387,15 +1388,15 @@ void QCALLTYPE GlobalComWrappersForMarshalling::SetGlobalInstanceRegisteredForMa
     // QCALL contracts are not used here because the managed declaration
     // uses the SuppressGCTransition attribute
 
-    _ASSERTE(!g_IsGlobalComWrappersRegistered);
-    g_IsGlobalComWrappersRegistered = true;
+    _ASSERTE(!g_IsGlobalComWrappersRegisteredForMarshalling);
+    g_IsGlobalComWrappersRegisteredForMarshalling = true;
 }
 
 bool GlobalComWrappersForMarshalling::TryGetOrCreateComInterfaceForObject(
     _In_ OBJECTREF instance,
     _Outptr_ void** wrapperRaw)
 {
-    if (!g_IsGlobalComWrappersRegistered)
+    if (!g_IsGlobalComWrappersRegisteredForMarshalling)
         return false;
 
     // Switch to Cooperative mode since object references
@@ -1420,7 +1421,7 @@ bool GlobalComWrappersForMarshalling::TryGetOrCreateObjectForComInstance(
     _In_ INT32 objFromComIPFlags,
     _Out_ OBJECTREF* objRef)
 {
-    if (!g_IsGlobalComWrappersRegistered)
+    if (!g_IsGlobalComWrappersRegisteredForMarshalling)
         return false;
 
     // Determine the true identity of the object
@@ -1452,6 +1453,110 @@ bool GlobalComWrappersForMarshalling::TryGetOrCreateObjectForComInstance(
     }
 }
 
+void QCALLTYPE GlobalComWrappersForTrackerSupport::SetGlobalInstanceRegisteredForTrackerSupport()
+{
+    // QCALL contracts are not used here because the managed declaration
+    // uses the SuppressGCTransition attribute
+
+    _ASSERTE(!g_IsGlobalComWrappersRegisteredForTrackerSupport);
+    g_IsGlobalComWrappersRegisteredForTrackerSupport = true;
+}
+
+bool GlobalComWrappersForTrackerSupport::TryGetOrCreateComInterfaceForObject(
+    _In_ OBJECTREF instance,
+    _Outptr_ void** wrapperRaw)
+{
+    CONTRACTL
+    {
+        THROWS;
+        MODE_COOPERATIVE;
+    }
+    CONTRACTL_END;
+
+    if (!g_IsGlobalComWrappersRegisteredForTrackerSupport)
+        return false;
+
+    // Passing NULL as the ComWrappers implementation indicates using the globally registered instance
+    return TryGetOrCreateComInterfaceForObjectInternal(
+        NULL,
+        instance,
+        CreateComInterfaceFlags::CreateComInterfaceFlags_TrackerSupport,
+        ComWrappersScenario::TrackerSupportGlobalInstance,
+        wrapperRaw);
+}
+
+bool GlobalComWrappersForTrackerSupport::TryGetOrCreateObjectForComInstance(
+    _In_ IUnknown* externalComObject,
+    _Out_ OBJECTREF* objRef)
+{
+    CONTRACTL
+    {
+        THROWS;
+        MODE_COOPERATIVE;
+    }
+    CONTRACTL_END;
+
+    if (!g_IsGlobalComWrappersRegisteredForTrackerSupport)
+        return false;
+
+    // Determine the true identity of the object
+    SafeComHolder<IUnknown> identity;
+    {
+        GCX_PREEMP();
+
+        HRESULT hr = externalComObject->QueryInterface(IID_IUnknown, &identity);
+        _ASSERTE(hr == S_OK);
+    }
+
+    // Passing NULL as the ComWrappers implementation indicates using the globally registered instance
+    return TryGetOrCreateObjectForComInstanceInternal(
+        NULL /*comWrappersImpl*/,
+        identity,
+        CreateObjectFlags::CreateObjectFlags_TrackerObject,
+        ComWrappersScenario::TrackerSupportGlobalInstance,
+        NULL /*wrapperMaybe*/,
+        objRef);
+}
+
+IUnknown* ComWrappersNative::GetIdentityForObject(_In_ OBJECTREF* objectPROTECTED, _In_ REFIID riid)
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_TRIGGERS;
+        MODE_COOPERATIVE;
+        PRECONDITION(CheckPointer(objectPROTECTED));
+    }
+    CONTRACTL_END;
+
+    ASSERT_PROTECTED(objectPROTECTED);
+
+    SyncBlock* syncBlock = (*objectPROTECTED)->PassiveGetSyncBlock();
+    if (syncBlock == nullptr)
+    {
+        return nullptr;
+    }
+
+    InteropSyncBlockInfo* interopInfo = syncBlock->GetInteropInfoNoCreate();
+    if (interopInfo == nullptr)
+    {
+        return nullptr;
+    }
+
+    void* context;
+    if (interopInfo->TryGetExternalComObjectContext(&context))
+    {
+        IUnknown* identity = reinterpret_cast<IUnknown*>(reinterpret_cast<ExternalObjectContext*>(context)->Identity);
+        GCX_PREEMP();
+        IUnknown* result;
+        if (SUCCEEDED(identity->QueryInterface(riid, (void**)&result)))
+        {
+            return result;
+        }
+    }
+    return nullptr;
+}
+
 #endif // FEATURE_COMWRAPPERS
 
 void Interop::OnGCStarted(_In_ int nCondemnedGeneration)
index 6a5884a..3e5abda 100644 (file)
@@ -37,6 +37,9 @@ public: // Lifetime management for COM Wrappers
 
 public: // COM activation
     static void MarkWrapperAsComActivated(_In_ IUnknown* wrapperMaybe);
+
+public: // Unwrapping support
+    static IUnknown* GetIdentityForObject(_In_ OBJECTREF* objectPROTECTED, _In_ REFIID riid);
 };
 
 class GlobalComWrappersForMarshalling
@@ -58,6 +61,25 @@ public: // Functions operating on a registered global instance for marshalling
         _Out_ OBJECTREF* objRef);
 };
 
+
+class GlobalComWrappersForTrackerSupport
+{
+public:
+    // Native QCall for the ComWrappers managed type to indicate a global instance
+    // is registered for tracker support. This should be set if the private static member
+    // representing the global instance for tracker support on ComWrappers is non-null.
+    static void QCALLTYPE SetGlobalInstanceRegisteredForTrackerSupport();
+
+public: // Functions operating on a registered global instance for tracker support
+    static bool TryGetOrCreateComInterfaceForObject(
+        _In_ OBJECTREF instance,
+        _Outptr_ void** wrapperRaw);
+
+    static bool TryGetOrCreateObjectForComInstance(
+        _In_ IUnknown* externalComObject,
+        _Out_ OBJECTREF* objRef);
+};
+
 #endif // FEATURE_COMWRAPPERS
 
 class Interop
index 2e06801..75c1e51 100644 (file)
@@ -558,7 +558,7 @@ FCIMPL2(LPVOID, MarshalNative::GCHandleInternalAlloc, Object *obj, int type)
 
     OBJECTREF objRef(obj);
 
-    assert(type >= HNDTYPE_WEAK_SHORT && type <= HNDTYPE_WEAK_WINRT);
+    assert(type >= HNDTYPE_WEAK_SHORT && type <= HNDTYPE_WEAK_NATIVE_COM);
 
     if (CORProfilerTrackGC())
     {
index a16bc1a..82c793b 100644 (file)
@@ -1110,7 +1110,7 @@ PVOID QCALLTYPE RuntimeTypeHandle::GetGCHandle(QCall::TypeHandle pTypeHandle, IN
     GCX_COOP();
 
     TypeHandle th = pTypeHandle.AsTypeHandle();
-    assert(handleType >= HNDTYPE_WEAK_SHORT && handleType <= HNDTYPE_WEAK_WINRT);
+    assert(handleType >= HNDTYPE_WEAK_SHORT && handleType <= HNDTYPE_WEAK_NATIVE_COM);
     objHandle = AppDomain::GetCurrentDomain()->CreateTypedHandle(NULL, static_cast<HandleType>(handleType));
     th.GetLoaderAllocator()->RegisterHandleForCleanup(objHandle);
 
index b1dc825..2cdb83c 100644 (file)
@@ -16,6 +16,7 @@
 #include "typestring.h"
 #include "typeparse.h"
 #include "threadsuspend.h"
+#include "interoplibinterface.h"
 
 //************************************************************************
 
@@ -34,7 +35,7 @@ const LPVOID specialWeakReferenceHandles[3] = { 0, 0, 0 };
 
 //
 // A WeakReference instance can hold one of three types of handles - short or long weak handles,
-// or a WinRT weak reference handle.  The WinRT weak reference handle has the extra capability
+// or a native COM weak reference handle.  The native COM weak reference handle has the extra capability
 // of recreating an RCW for a COM object which is still alive even though the previous RCW had
 // been collected.   In order to differentiate this type of handle from the standard weak handles,
 // the bottom bit is stolen.
@@ -50,23 +51,23 @@ const LPVOID specialWeakReferenceHandles[3] = { 0, 0, 0 };
 // The following functions are to set, test, and unset that bit before the handle is used.
 //
 
-// Determine if an object handle is a WinRT weak reference handle
-bool IsWinRTWeakReferenceHandle(OBJECTHANDLE handle)
+// Determine if an object handle is a native COM weak reference handle
+bool IsNativeComWeakReferenceHandle(OBJECTHANDLE handle)
 {
     STATIC_CONTRACT_LEAF;
     return (reinterpret_cast<UINT_PTR>(handle) & 0x1) != 0x0;
 }
 
-// Mark an object handle as being a WinRT weak reference handle
-OBJECTHANDLE SetWinRTWeakReferenceHandle(OBJECTHANDLE handle)
+// Mark an object handle as being a native COM weak reference handle
+OBJECTHANDLE SetNativeComWeakReferenceHandle(OBJECTHANDLE handle)
 {
     STATIC_CONTRACT_LEAF;
 
-    _ASSERTE(!IsWinRTWeakReferenceHandle(handle));
+    _ASSERTE(!IsNativeComWeakReferenceHandle(handle));
     return reinterpret_cast<OBJECTHANDLE>(reinterpret_cast<UINT_PTR>(handle) | 0x1);
 }
 
-// Get the object handle value even if the object is a WinRT weak reference
+// Get the object handle value even if the object is a native COM weak reference
 OBJECTHANDLE GetHandleValue(OBJECTHANDLE handle)
 {
     STATIC_CONTRACT_LEAF;
@@ -102,17 +103,17 @@ private:
 
 #ifdef FEATURE_COMINTEROP
 
-// Get a WinRT weak reference for the object underlying an RCW if applicable.  If the incoming object cannot
-// use a WinRT weak reference, nullptr is returned.  Otherwise, an AddRef-ed IWeakReference* for the COM
+// Get a native COM weak reference for the object underlying an RCW if applicable.  If the incoming object cannot
+// use a native COM weak reference, nullptr is returned.  Otherwise, an AddRef-ed IWeakReference* for the COM
 // object underlying the RCW is returned.
 //
-// In order to qualify to be used with a HNDTYPE_WEAK_WINRT, the incoming object must:
+// In order to qualify to be used with a HNDTYPE_WEAK_NATIVE_COM, the incoming object must:
 //  * be an RCW
 //  * respond to a QI for IWeakReferenceSource
 //  * succeed when asked for an IWeakReference*
 //
 // Note that *pObject should be GC protected on the way into this method
-IWeakReference* GetWinRTWeakReference(OBJECTREF* pObject)
+IWeakReference* GetComWeakReference(OBJECTREF* pObject)
 {
     CONTRACTL
     {
@@ -132,21 +133,24 @@ IWeakReference* GetWinRTWeakReference(OBJECTREF* pObject)
 
     MethodTable* pMT = (*pObject)->GetMethodTable();
 
-    // If the object is not an RCW, then we do not want to use a WinRT weak reference to it
-    if (!pMT->IsComObjectType())
-    {
-        return nullptr;
-    }
+    SafeComHolder<IWeakReferenceSource> pWeakReferenceSource(nullptr);
 
-    // If the object is a managed type deriving from a COM type, then we also do not want to use a WinRT
+    // If the object is not an RCW, then we do not want to use a native COM weak reference to it
+    // If the object is a managed type deriving from a COM type, then we also do not want to use a native COM
     // weak reference to it.  (Otherwise, we'll wind up resolving IWeakReference-s back into the CLR
     // when we don't want to have reentrancy).
-    if (pMT != g_pBaseCOMObject && pMT->IsExtensibleRCW())
+    if (pMT->IsComObjectType()
+     && (pMT == g_pBaseCOMObject || !pMT->IsExtensibleRCW()))
     {
-        return nullptr;
+        pWeakReferenceSource = reinterpret_cast<IWeakReferenceSource*>(GetComIPFromObjectRef(pObject, IID_IWeakReferenceSource, false /* throwIfNoComIP */));
+    }
+#ifdef FEATURE_COMWRAPPERS
+    else
+    {
+        pWeakReferenceSource = reinterpret_cast<IWeakReferenceSource*>(ComWrappersNative::GetIdentityForObject(pObject, IID_IWeakReferenceSource));
     }
+#endif
 
-    SafeComHolder<IWeakReferenceSource> pWeakReferenceSource(reinterpret_cast<IWeakReferenceSource*>(GetComIPFromObjectRef(pObject, IID_IWeakReferenceSource, false /* throwIfNoComIP */)));
     if (pWeakReferenceSource == nullptr)
     {
         return nullptr;
@@ -162,17 +166,17 @@ IWeakReference* GetWinRTWeakReference(OBJECTREF* pObject)
     return pWeakReference.Extract();
 }
 
-// Given an object handle that stores a WinRT weak reference, attempt to create an RCW
-// and store it back in the handle, returning the RCW.  If the underlying WinRT object
+// Given an object handle that stores a native COM weak reference, attempt to create an RCW
+// and store it back in the handle, returning the RCW.  If the underlying native COM object
 // is not alive, then the result is NULL.
 //
 // In order to create a new RCW, we must:
-//   * Have an m_handle of HNDTYPE_WEAK_WINRT (ie the bottom bit of m_handle is set)
+//   * Have an m_handle of HNDTYPE_WEAK_NATIVE_COM (ie the bottom bit of m_handle is set)
 //   * Have stored an IWeakReference* in the handle extra info when setting up the handle
-//     (see GetWinRTWeakReference)
+//     (see GetComWeakReference)
 //   * The IWeakReference* must respond to a Resolve request for IID_IInspectable
 //   *
-NOINLINE Object* LoadWinRTWeakReferenceTarget(WEAKREFERENCEREF weakReference, TypeHandle targetType, LPVOID __me)
+NOINLINE Object* LoadComWeakReferenceTarget(WEAKREFERENCEREF weakReference, TypeHandle targetType, LPVOID __me)
 {
     CONTRACTL
     {
@@ -200,14 +204,14 @@ NOINLINE Object* LoadWinRTWeakReferenceTarget(WEAKREFERENCEREF weakReference, Ty
     //
     // Since we're acquiring and releasing the lock multiple times, we need to check the handle state each time we
     // reacquire the lock to make sure that another thread hasn't reassigned the target of the handle or finalized it
-    SafeComHolder<IWeakReference> pWinRTWeakReference = nullptr;
+    SafeComHolder<IWeakReference> pComWeakReference = nullptr;
     {
         WeakHandleSpinLockHolder handle(AcquireWeakHandleSpinLock(gc.weakReference), &gc.weakReference);
         GCX_NOTRIGGER();
 
         // Make sure that while we were not holding the spin lock, another thread did not change the target of
         // this weak reference.  Only fetch the IWeakReference* if we still have a valid handle holding a NULL object
-        // and the handle is still a HNDTYPE_WEAK_WINRT type handle.
+        // and the handle is still a HNDTYPE_WEAK_NATIVE_COM type handle.
         if ((handle.Handle != NULL) && !IS_SPECIAL_HANDLE(handle.Handle))
         {
             if (*(Object **)(handle.Handle) != NULL)
@@ -217,22 +221,22 @@ NOINLINE Object* LoadWinRTWeakReferenceTarget(WEAKREFERENCEREF weakReference, Ty
                 // weak reference is targeting.
                 gc.target = ObjectToOBJECTREF(*(Object **)(handle.Handle));
             }
-            else if(IsWinRTWeakReferenceHandle(handle.RawHandle))
+            else if(IsNativeComWeakReferenceHandle(handle.RawHandle))
             {
-                _ASSERTE(GCHandleUtilities::GetGCHandleManager()->HandleFetchType(handle.Handle) == HNDTYPE_WEAK_WINRT);
+                _ASSERTE(GCHandleUtilities::GetGCHandleManager()->HandleFetchType(handle.Handle) == HNDTYPE_WEAK_NATIVE_COM);
 
                 // Retrieve the associated IWeakReference* for this weak reference.  Add a reference to it while we release
                 // the spin lock so that another thread doesn't release it out from underneath us.
                 //
-                // Setting pWinRTWeakReference will claim that it triggers a GC, however that's not true in this case because
+                // Setting pComWeakReference will claim that it triggers a GC, however that's not true in this case because
                 // it's always set to NULL here and there's nothing for it to release.
-                _ASSERTE(pWinRTWeakReference.IsNull());
+                _ASSERTE(pComWeakReference.IsNull());
                 CONTRACT_VIOLATION(GCViolation);
                 IGCHandleManager *mgr = GCHandleUtilities::GetGCHandleManager();
-                pWinRTWeakReference = reinterpret_cast<IWeakReference*>(mgr->GetExtraInfoFromHandle(handle.Handle));
-                if (!pWinRTWeakReference.IsNull())
+                pComWeakReference = reinterpret_cast<IWeakReference*>(mgr->GetExtraInfoFromHandle(handle.Handle));
+                if (!pComWeakReference.IsNull())
                 {
-                    pWinRTWeakReference->AddRef();
+                    pComWeakReference->AddRef();
                 }
             }
         }
@@ -242,16 +246,16 @@ NOINLINE Object* LoadWinRTWeakReferenceTarget(WEAKREFERENCEREF weakReference, Ty
     // identity of the underlying COM object (assuming that object is still alive).  This work is done without holding the
     // spin lock since it will call out to arbitrary code and as such we need to switch to preemptive mode.
     SafeComHolder<IUnknown> pTargetIdentity = nullptr;
-    if (pWinRTWeakReference != nullptr)
+    if (pComWeakReference != nullptr)
     {
         _ASSERTE(gc.target == NULL);
 
         GCX_PREEMP();
 
-        // Using the IWeakReference*, get ahold of the target WinRT object's IInspectable*.  If this resolve fails, then we
-        // assume that the underlying WinRT object is no longer alive, and thus we cannot create a new RCW for it.
+        // Using the IWeakReference*, get ahold of the target native COM object's IInspectable*.  If this resolve fails, then we
+        // assume that the underlying native COM object is no longer alive, and thus we cannot create a new RCW for it.
         SafeComHolderPreemp<IInspectable> pTarget = nullptr;
-        if (SUCCEEDED(pWinRTWeakReference->Resolve(IID_IInspectable, &pTarget)))
+        if (SUCCEEDED(pComWeakReference->Resolve(IID_IInspectable, &pTarget)))
         {
             if (!pTarget.IsNull())
             {
@@ -264,7 +268,11 @@ NOINLINE Object* LoadWinRTWeakReferenceTarget(WEAKREFERENCEREF weakReference, Ty
     // If we were able to get an IUnkown identity for the object, then we can find or create an associated RCW for it.
     if (!pTargetIdentity.IsNull())
     {
-        GetObjectRefFromComIP(&gc.rcw, pTargetIdentity);
+        // Try the global COM wrappers first before falling back to the built-in system.
+        if (!GlobalComWrappersForTrackerSupport::TryGetOrCreateObjectForComInstance(pTargetIdentity, &gc.rcw))
+        {
+            GetObjectRefFromComIP(&gc.rcw, pTargetIdentity);
+        }
     }
 
     // If we were able to get an RCW, then we need to reacquire the spin lock and store the RCW in the handle.  Note that
@@ -272,7 +280,7 @@ NOINLINE Object* LoadWinRTWeakReferenceTarget(WEAKREFERENCEREF weakReference, Ty
     // building the RCW.  In that case, we will defer to the hadle that the other thread set, and let the RCW die.
     if (gc.rcw != NULL)
     {
-        // Make sure the type we got back from the WinRT object is compatible with the type the managed
+        // Make sure the type we got back from the native COM object is compatible with the type the managed
         // weak reference expects.  (For instance, in the WeakReference<T> case, the returned type
         // had better be compatible with T).
         TypeHandle rcwType(gc.rcw->GetMethodTable());
@@ -284,7 +292,7 @@ NOINLINE Object* LoadWinRTWeakReferenceTarget(WEAKREFERENCEREF weakReference, Ty
             SString resolvedTypeName;
             TypeString::AppendType(resolvedTypeName, rcwType, TypeString::FormatNamespace | TypeString::FormatFullInst | TypeString::FormatAssembly);
 
-            COMPlusThrow(kInvalidCastException, IDS_EE_WINRT_WEAKREF_BAD_TYPE, weakReferenceTypeName.GetUnicode(), resolvedTypeName.GetUnicode());
+            COMPlusThrow(kInvalidCastException, IDS_EE_NATIVE_COM_WEAKREF_BAD_TYPE, weakReferenceTypeName.GetUnicode(), resolvedTypeName.GetUnicode());
         }
 
         WeakHandleSpinLockHolder handle(AcquireWeakHandleSpinLock(gc.weakReference), &gc.weakReference);
@@ -420,12 +428,21 @@ FCIMPL3(void, WeakReferenceNative::Create, WeakReferenceObject * pThisUNSAFE, Ob
 
     // Create the handle.
 #ifdef FEATURE_COMINTEROP
-    IWeakReference* pRawWinRTWeakReference = GetWinRTWeakReference(&gc.pTarget);
-    if (pRawWinRTWeakReference != nullptr)
+    IWeakReference* pRawComWeakReference = nullptr;
+    if (gc.pTarget != NULL)
     {
-        SafeComHolder<IWeakReference> pWinRTWeakReferenceHolder(pRawWinRTWeakReference);
-        gc.pThis->m_Handle = SetWinRTWeakReferenceHandle(GetAppDomain()->CreateWinRTWeakHandle(gc.pTarget, pWinRTWeakReferenceHolder));
-        pWinRTWeakReferenceHolder.SuppressRelease();
+        SyncBlock* pSyncBlock = gc.pTarget->PassiveGetSyncBlock();
+        if (pSyncBlock != nullptr && pSyncBlock->GetInteropInfoNoCreate() != nullptr)
+        {
+            pRawComWeakReference = GetComWeakReference(&gc.pTarget);
+        }
+    }
+
+    if (pRawComWeakReference != nullptr)
+    {
+        SafeComHolder<IWeakReference> pComWeakReferenceHolder(pRawComWeakReference);
+        gc.pThis->m_Handle = SetNativeComWeakReferenceHandle(GetAppDomain()->CreateNativeComWeakHandle(gc.pTarget, pComWeakReferenceHolder));
+        pComWeakReferenceHolder.SuppressRelease();
     }
     else
 #endif // FEATURE_COMINTEROP
@@ -463,12 +480,21 @@ FCIMPL3(void, WeakReferenceOfTNative::Create, WeakReferenceObject * pThisUNSAFE,
 
     // Create the handle.
 #ifdef FEATURE_COMINTEROP
-    IWeakReference* pRawWinRTWeakReference = GetWinRTWeakReference(&gc.pTarget);
-    if (pRawWinRTWeakReference != nullptr)
+    IWeakReference* pRawComWeakReference = nullptr;
+    if (gc.pTarget != NULL)
+    {
+        SyncBlock* pSyncBlock = gc.pTarget->PassiveGetSyncBlock();
+        if (pSyncBlock != nullptr && pSyncBlock->GetInteropInfoNoCreate() != nullptr)
+        {
+            pRawComWeakReference = GetComWeakReference(&gc.pTarget);
+        }
+    }
+
+    if (pRawComWeakReference != nullptr)
     {
-        SafeComHolder<IWeakReference> pWinRTWeakReferenceHolder(pRawWinRTWeakReference);
-        gc.pThis->m_Handle = SetWinRTWeakReferenceHandle(GetAppDomain()->CreateWinRTWeakHandle(gc.pTarget, pWinRTWeakReferenceHolder));
-        pWinRTWeakReferenceHolder.SuppressRelease();
+        SafeComHolder<IWeakReference> pComWeakReferenceHolder(pRawComWeakReference);
+        gc.pThis->m_Handle = SetNativeComWeakReferenceHandle(GetAppDomain()->CreateNativeComWeakHandle(gc.pTarget, pComWeakReferenceHolder));
+        pComWeakReferenceHolder.SuppressRelease();
     }
     else
 #endif // FEATURE_COMINTEROP
@@ -499,7 +525,7 @@ void FinalizeWeakReference(Object * obj)
     // The suspension state of the runtime must be prevented from changing while in this function in order for this to be safe.
     OBJECTHANDLE handle = ThreadSuspend::SysIsSuspended() ? pThis->m_Handle.LoadWithoutBarrier() : AcquireWeakHandleSpinLock(pThis);
     OBJECTHANDLE handleToDestroy = NULL;
-    bool isWeakWinRTHandle = false;
+    bool isWeakNativeComHandle = false;
 
     // Check for not yet constructed or already finalized handle
     if ((handle != NULL) && !IS_SPECIAL_HANDLE(handle))
@@ -509,8 +535,8 @@ void FinalizeWeakReference(Object * obj)
         // Cache the old handle value
         HandleType handleType = GCHandleUtilities::GetGCHandleManager()->HandleFetchType(handleToDestroy);
 #ifdef FEATURE_COMINTEROP
-        _ASSERTE(handleType == HNDTYPE_WEAK_LONG || handleType == HNDTYPE_WEAK_SHORT || handleType == HNDTYPE_WEAK_WINRT);
-        isWeakWinRTHandle = handleType == HNDTYPE_WEAK_WINRT;
+        _ASSERTE(handleType == HNDTYPE_WEAK_LONG || handleType == HNDTYPE_WEAK_SHORT || handleType == HNDTYPE_WEAK_NATIVE_COM);
+        isWeakNativeComHandle = handleType == HNDTYPE_WEAK_NATIVE_COM;
 #else // !FEATURE_COMINTEROP
         _ASSERTE(handleType == HNDTYPE_WEAK_LONG || handleType == HNDTYPE_WEAK_SHORT);
 #endif // FEATURE_COMINTEROP
@@ -528,9 +554,9 @@ void FinalizeWeakReference(Object * obj)
     if (handleToDestroy != NULL)
     {
 #ifdef FEATURE_COMINTEROP
-        if (isWeakWinRTHandle)
+        if (isWeakNativeComHandle)
         {
-            DestroyWinRTWeakHandle(handleToDestroy);
+            DestroyNativeComWeakHandle(handleToDestroy);
         }
         else
 #endif // FEATURE_COMINTEROP
@@ -645,14 +671,14 @@ FCIMPL1(Object *, WeakReferenceNative::GetTarget, WeakReferenceObject * pThisUNS
     OBJECTREF pTarget = GetWeakReferenceTarget(pThis);
 
 #ifdef FEATURE_COMINTEROP
-    // If we found an object, or we're not a WinRT weak reference, then we're done.  Othewrise
-    // we can try to create a new RCW to the underlying WinRT object if it's still alive.
-    if (pTarget != NULL || !IsWinRTWeakReferenceHandle(pThis->m_Handle))
+    // If we found an object, or we're not a native COM weak reference, then we're done.  Othewrise
+    // we can try to create a new RCW to the underlying native COM object if it's still alive.
+    if (pTarget != NULL || !IsNativeComWeakReferenceHandle(pThis->m_Handle))
     {
         FC_GC_POLL_AND_RETURN_OBJREF(pTarget);
     }
 
-    FC_INNER_RETURN(Object*, LoadWinRTWeakReferenceTarget(pThis, g_pObjectClass, GetEEFuncEntryPointMacro(WeakReferenceNative::GetTarget)));
+    FC_INNER_RETURN(Object*, LoadComWeakReferenceTarget(pThis, g_pObjectClass, GetEEFuncEntryPointMacro(WeakReferenceNative::GetTarget)));
 #else // !FEATURE_COMINTEROP
     FC_GC_POLL_AND_RETURN_OBJREF(pTarget);
 #endif // FEATURE_COMINTEROP
@@ -673,14 +699,14 @@ FCIMPL1(Object *, WeakReferenceOfTNative::GetTarget, WeakReferenceObject * pThis
 
 
 #ifdef FEATURE_COMINTEROP
-    // If we found an object, or we're not a WinRT weak reference, then we're done.  Othewrise
-    // we can try to create a new RCW to the underlying WinRT object if it's still alive.
-    if (pTarget != NULL || !IsWinRTWeakReferenceHandle(pThis->m_Handle))
+    // If we found an object, or we're not a native COM weak reference, then we're done.  Othewrise
+    // we can try to create a new RCW to the underlying native COM object if it's still alive.
+    if (pTarget != NULL || !IsNativeComWeakReferenceHandle(pThis->m_Handle))
     {
         FC_GC_POLL_AND_RETURN_OBJREF(pTarget);
     }
 
-    FC_INNER_RETURN(Object*, LoadWinRTWeakReferenceTarget(pThis, pThis->GetMethodTable()->GetInstantiation()[0], GetEEFuncEntryPointMacro(WeakReferenceOfTNative::GetTarget)));
+    FC_INNER_RETURN(Object*, LoadComWeakReferenceTarget(pThis, pThis->GetMethodTable()->GetInstantiation()[0], GetEEFuncEntryPointMacro(WeakReferenceOfTNative::GetTarget)));
 #else // !FEATURE_COMINTEROP
     FC_GC_POLL_AND_RETURN_OBJREF(pTarget);
 #endif // FEATURE_COMINTEROP
@@ -711,7 +737,7 @@ FCIMPLEND
 
 #include <optsmallperfcritical.h>
 
-// Slow path helper for setting the target of a weak reference.  This code is used if a WinRT weak reference might
+// Slow path helper for setting the target of a weak reference.  This code is used if a native COM weak reference might
 // be required.
 NOINLINE void SetWeakReferenceTarget(WEAKREFERENCEREF weakReference, OBJECTREF target, LPVOID __me)
 {
@@ -721,7 +747,7 @@ NOINLINE void SetWeakReferenceTarget(WEAKREFERENCEREF weakReference, OBJECTREF t
     HELPER_METHOD_FRAME_BEGIN_ATTRIB_2(Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2, target, weakReference);
 
 #ifdef FEATURE_COMINTEROP
-    SafeComHolder<IWeakReference> pTargetWeakReference(GetWinRTWeakReference(&target));
+    SafeComHolder<IWeakReference> pTargetWeakReference(GetComWeakReference(&target));
 #endif // FEATURE_COMINTEROP
 
 
@@ -735,30 +761,30 @@ NOINLINE void SetWeakReferenceTarget(WEAKREFERENCEREF weakReference, OBJECTREF t
     // Existing target is a GC object, new target is a GC object:
     //  * Just store the new object in the handle
     //
-    // Existing target is WinRT, new target is WinRT:
+    // Existing target is native COM weak reference, new target is native COM weak reference:
     //   * Release the existing IWeakReference*
     //   * Store the new IWeakReference*
     //   * Store the new object in the handle
     //
-    // Existing target is WinRT, new target is GC:
+    // Existing target is native COM weak reference, new target is GC:
     //   * Release the existing IWeakReference*
     //   * Store null to the IWeakReference* field
     //   * Store the new object in the handle
     //
-    // Existing target is GC, new target is WinRT:
+    // Existing target is GC, new target is native COM weak reference:
     //   * Destroy the existing handle
-    //   * Allocate a new WinRT weak handle for the new target
+    //   * Allocate a new native COM weak handle for the new target
     //
 
-    if (IsWinRTWeakReferenceHandle(handle.RawHandle))
+    if (IsNativeComWeakReferenceHandle(handle.RawHandle))
     {
-        // If the existing reference is a WinRT weak reference, we need to release its IWeakReference pointer
+        // If the existing reference is a native COM weak reference, we need to release its IWeakReference pointer
         // and update it with the new weak reference pointer.  If the incoming object is not an RCW that can
         // use IWeakReference, then pTargetWeakReference will be null.  Therefore, no matter what the incoming
         // object type is, we can unconditionally store pTargetWeakReference to the object handle's extra data.
         IGCHandleManager *mgr = GCHandleUtilities::GetGCHandleManager();
         IWeakReference* pExistingWeakReference = reinterpret_cast<IWeakReference*>(mgr->GetExtraInfoFromHandle(handle.Handle));
-        mgr->SetExtraInfoForHandle(handle.Handle, HNDTYPE_WEAK_WINRT, reinterpret_cast<void*>(pTargetWeakReference.GetValue()));
+        mgr->SetExtraInfoForHandle(handle.Handle, HNDTYPE_WEAK_NATIVE_COM, reinterpret_cast<void*>(pTargetWeakReference.GetValue()));
         StoreObjectInHandle(handle.Handle, target);
 
         if (pExistingWeakReference != nullptr)
@@ -768,15 +794,15 @@ NOINLINE void SetWeakReferenceTarget(WEAKREFERENCEREF weakReference, OBJECTREF t
     }
     else if (pTargetWeakReference != nullptr)
     {
-        // The existing handle is not a WinRT weak reference, but we need to store the new object in
-        // a WinRT weak reference.  Therefore we need to destroy the old handle and create a new WinRT
+        // The existing handle is not a native COM weak reference, but we need to store the new object in
+        // a native COM weak reference.  Therefore we need to destroy the old handle and create a new native COM
         // handle.  The new handle needs to be allocated first to prevent the weak reference from holding
         // a destroyed handle if we fail to allocate the new one.
-        _ASSERTE(!IsWinRTWeakReferenceHandle(handle.RawHandle));
+        _ASSERTE(!IsNativeComWeakReferenceHandle(handle.RawHandle));
         OBJECTHANDLE previousHandle = handle.RawHandle;
 
-        handle.Handle = GetAppDomain()->CreateWinRTWeakHandle(target, pTargetWeakReference);
-        handle.RawHandle = SetWinRTWeakReferenceHandle(handle.Handle);
+        handle.Handle = GetAppDomain()->CreateNativeComWeakHandle(target, pTargetWeakReference);
+        handle.RawHandle = SetNativeComWeakReferenceHandle(handle.Handle);
 
         DestroyTypedHandle(previousHandle);
     }
@@ -822,7 +848,7 @@ FCIMPL2(void, WeakReferenceNative::SetTarget, WeakReferenceObject * pThisUNSAFE,
 
         // If the existing handle is a GC weak handle and the new target is not an RCW, then
         // we can avoid setting up a helper method frame and just reset the handle directly.
-        if (!IsWinRTWeakReferenceHandle(handle))
+        if (!IsNativeComWeakReferenceHandle(handle))
         {
             if (pTarget == NULL || !pTarget->GetMethodTable()->IsComObjectType())
             {
@@ -875,7 +901,7 @@ FCIMPL2(void, WeakReferenceOfTNative::SetTarget, WeakReferenceObject * pThisUNSA
 
         // If the existing handle is a GC weak handle and the new target is not an RCW, then
         // we can avoid setting up a helper method frame and just reset the handle directly.
-        if (!IsWinRTWeakReferenceHandle(handle))
+        if (!IsNativeComWeakReferenceHandle(handle))
         {
             if (pTarget == NULL || !pTarget->GetMethodTable()->IsComObjectType())
             {
index 8a39e97..778d9ab 100644 (file)
@@ -81,6 +81,7 @@ if(CLR_CMAKE_TARGET_WIN32)
     add_subdirectory(COM/NativeClients/Dispatch)
     add_subdirectory(COM/NativeClients/Events)
     add_subdirectory(COM/ComWrappers/MockReferenceTrackerRuntime)
+    add_subdirectory(COM/ComWrappers/WeakReference)
     add_subdirectory(WinRT/NativeComponent)
 
     # IJW isn't supported on ARM64
diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/CMakeLists.txt b/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/CMakeLists.txt
new file mode 100644 (file)
index 0000000..8166db2
--- /dev/null
@@ -0,0 +1,10 @@
+project (WeakReferenceNative)
+include_directories( ${INC_PLATFORM_DIR} )
+set(SOURCES WeakReferenceNative.cpp)
+
+# add the shared library
+add_library (WeakReferenceNative SHARED ${SOURCES})
+target_link_libraries(WeakReferenceNative ${LINK_LIBRARIES_ADDITIONAL})
+
+# add the install targets
+install (TARGETS WeakReferenceNative DESTINATION bin)
diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceNative.cpp b/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceNative.cpp
new file mode 100644 (file)
index 0000000..5617b11
--- /dev/null
@@ -0,0 +1,124 @@
+// 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.
+
+#include <xplatform.h>
+#include <ComHelpers.h>
+#include <inspectable.h>
+#include <WeakReference.h>
+
+namespace
+{
+    struct WeakReference : public IWeakReference, public UnknownImpl
+    {
+        IInspectable* _reference;
+        std::atomic<ULONG> _strongRefCount;
+
+        WeakReference(IInspectable* reference, ULONG strongRefCount)
+            : _reference(reference),
+            _strongRefCount(strongRefCount)
+        {}
+
+        ULONG AddStrongRef()
+        {
+            assert(_strongRefCount > 0);
+            return (++_strongRefCount);
+        }
+
+        ULONG ReleaseStrongRef()
+        {
+            assert(_strongRefCount > 0);
+            return --_strongRefCount;
+        }
+
+        STDMETHOD(Resolve)(REFIID riid, IInspectable** ppvObject)
+        {
+            if (_strongRefCount > 0)
+            {
+                void* pObject;
+                HRESULT hr = _reference->QueryInterface(riid, &pObject);
+                *ppvObject = reinterpret_cast<IInspectable*>(pObject);
+                return hr;
+            }
+            return E_NOINTERFACE;
+        }
+
+        STDMETHOD(QueryInterface)(
+            /* [in] */ REFIID riid,
+            /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject)
+        {
+            return DoQueryInterface(riid, ppvObject, static_cast<IWeakReference*>(this));
+        }
+
+        DEFINE_REF_COUNTING()
+    };
+
+    struct WeakReferencableObject : public IWeakReferenceSource, public IInspectable, public UnknownImpl
+    {
+        ComSmartPtr<WeakReference> _weakReference;
+        STDMETHOD(GetWeakReference)(_COM_Outptr_ IWeakReference** ppWeakReference)
+        {
+            if (!_weakReference)
+            {
+                ULONG refCount = UnknownImpl::GetRefCount();
+                _weakReference = new WeakReference(this, refCount);
+            }
+            _weakReference->AddRef();
+            *ppWeakReference = _weakReference;
+            return S_OK;
+        }
+
+        STDMETHOD(GetRuntimeClassName)(HSTRING* pRuntimeClassName)
+        {
+            return E_NOTIMPL;
+        }
+
+        STDMETHOD(GetIids)(
+            ULONG *iidCount,
+            IID   **iids)
+        {
+            return E_NOTIMPL;
+        }
+
+        STDMETHOD(GetTrustLevel)(TrustLevel *trustLevel)
+        {
+            *trustLevel = FullTrust;
+            return S_OK;
+        }
+
+        STDMETHOD(QueryInterface)(
+            /* [in] */ REFIID riid,
+            /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject)
+        {
+            HRESULT hr = DoQueryInterface(riid, ppvObject, static_cast<IWeakReferenceSource*>(this), static_cast<IInspectable*>(this), static_cast<IWeakReferenceSource*>(this));
+            if (SUCCEEDED(hr) && _weakReference)
+            {
+                _weakReference->AddStrongRef();
+            }
+            return hr;
+        }
+        STDMETHOD_(ULONG, AddRef)(void)
+        {
+            if (_weakReference)
+            {
+                return _weakReference->AddStrongRef();
+            }
+            return UnknownImpl::DoAddRef();
+        }
+        STDMETHOD_(ULONG, Release)(void)
+        {
+            if (_weakReference)
+            {
+                ULONG c = _weakReference->ReleaseStrongRef();
+                if (c == 0)
+                    delete this;
+                return c;
+            }
+            return UnknownImpl::DoRelease();
+        }
+    };
+}
+extern "C" DLL_EXPORT WeakReferencableObject* STDMETHODCALLTYPE CreateWeakReferencableObject()
+{
+    return new WeakReferencableObject();
+}
diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceTest.cs b/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceTest.cs
new file mode 100644 (file)
index 0000000..acde6f6
--- /dev/null
@@ -0,0 +1,137 @@
+// 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.
+
+namespace ComWrappersTests
+{
+    using System;
+    using System.Collections;
+    using System.Collections.Generic;
+    using System.Runtime.CompilerServices;
+    using System.Runtime.InteropServices;
+    using TestLibrary;
+
+    static class WeakReferenceNative
+    {
+        [DllImport(nameof(WeakReferenceNative))]
+        public static extern IntPtr CreateWeakReferencableObject();
+    }
+
+    public struct VtblPtr
+    {
+        public IntPtr Vtbl;
+    }
+
+    public class WeakReferencableWrapper
+    {
+        private struct Vtbl
+        {
+            public IntPtr QueryInterface;
+            public _AddRef AddRef;
+            public _Release Release;
+        }
+
+        private delegate int _AddRef(IntPtr This);
+        private delegate int _Release(IntPtr This);
+
+        private readonly IntPtr instance;
+        private readonly Vtbl vtable;
+
+        public WeakReferencableWrapper(IntPtr instance)
+        {
+            var inst = Marshal.PtrToStructure<VtblPtr>(instance);
+            this.vtable = Marshal.PtrToStructure<Vtbl>(inst.Vtbl);
+            this.instance = instance;
+        }
+
+        ~WeakReferencableWrapper()
+        {
+            if (this.instance != IntPtr.Zero)
+            {
+                this.vtable.Release(this.instance);
+            }
+        }
+    }
+
+    class Program
+    {
+        class TestComWrappers : ComWrappers
+        {
+            protected unsafe override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count)
+            {
+                count = 0;
+                return null;
+            }
+
+            protected override object CreateObject(IntPtr externalComObject, CreateObjectFlags flag)
+            {
+                return new WeakReferencableWrapper(externalComObject);
+            }
+
+            protected override void ReleaseObjects(IEnumerable objects)
+            {
+            }
+
+            public static readonly ComWrappers Instance = new TestComWrappers();
+        }
+
+        static void ValidateNativeWeakReference()
+        {
+            Console.WriteLine($"Running {nameof(ValidateNativeWeakReference)}...");
+
+            static (WeakReference<WeakReferencableWrapper>, IntPtr) GetWeakReference()
+            {
+                var cw = new TestComWrappers();
+
+                IntPtr objRaw = WeakReferenceNative.CreateWeakReferencableObject();
+
+                var obj = (WeakReferencableWrapper)cw.GetOrCreateObjectForComInstance(objRaw, CreateObjectFlags.None);
+
+                // The returned WeakReferencableWrapper from ComWrappers takes ownership
+                // of the ref returned from CreateWeakReferencableObject.
+                // Call Marshal.AddRef to ensure that objRaw owns a reference.
+                Marshal.AddRef(objRaw);
+
+                return (new WeakReference<WeakReferencableWrapper>(obj), objRaw);
+            }
+
+            static bool CheckIfWeakReferenceIsAlive(WeakReference<WeakReferencableWrapper> wr)
+            {
+                return wr.TryGetTarget(out _);
+            }
+
+            var (weakRef, nativeRef) = GetWeakReference();
+            GC.Collect();
+            GC.WaitForPendingFinalizers();
+            // A weak reference to an RCW wrapping an IWeakReference should stay alive even after the RCW dies
+            Assert.IsTrue(CheckIfWeakReferenceIsAlive(weakRef));
+
+            // Release the last native reference.
+            Marshal.Release(nativeRef);
+
+            GC.Collect();
+            GC.WaitForPendingFinalizers();
+
+            // After all native references die and the RCW is collected, the weak reference should be dead and stay dead.
+            Assert.IsFalse(CheckIfWeakReferenceIsAlive(weakRef));
+
+        }
+
+        static int Main(string[] doNotUse)
+        {
+            try
+            {
+                ComWrappers.RegisterForTrackerSupport(TestComWrappers.Instance);
+                ValidateNativeWeakReference();
+            }
+            catch (Exception e)
+            {
+                Console.WriteLine($"Test Failure: {e}");
+                return 101;
+            }
+
+            return 100;
+        }
+    }
+}
+
diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceTest.csproj b/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceTest.csproj
new file mode 100644 (file)
index 0000000..edcc331
--- /dev/null
@@ -0,0 +1,24 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <!-- Test unsupported outside of windows -->
+    <TestUnsupportedOutsideWindows>true</TestUnsupportedOutsideWindows>
+    <!-- Native COM interfaces left alive at the test exit -->
+    <UnloadabilityIncompatible>true</UnloadabilityIncompatible>
+    <DisableProjectBuild Condition="'$(TargetsWindows)' != 'true'">true</DisableProjectBuild>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+  <Import Project="$([MSBuild]::GetPathOfFileAbove(Interop.settings.targets))" />
+  <ItemGroup>
+    <Compile Include="WeakReferenceTest.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="CMakeLists.txt" />
+  </ItemGroup>
+  <PropertyGroup>
+    <CLRTestNeedTarget>1</CLRTestNeedTarget>
+  </PropertyGroup>
+  <ItemGroup>
+    <TraitTags Include="OsSpecific" />
+  </ItemGroup>
+</Project>
index c90ff7a..673f190 100644 (file)
@@ -105,6 +105,12 @@ public:
         return c;
     }
 
+protected:
+    ULONG GetRefCount()
+    {
+        return _refCount;
+    }
+
 private:
     std::atomic<ULONG> _refCount = 1;
 };