From 5ce7dd519570c849cde616a6ac82c89762dc4666 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Wed, 25 Mar 2026 17:56:46 -0700 Subject: [PATCH 1/4] Revert "Partially revert PR #125326: revert ComActivator/LicenseInteropProxy changes (#125706)" This reverts commit 3e797833fbecf9abc2bebd2ac997d8a23a44e9f7. This commit also does the following: - Fix test bug in LicenseTesting.h - Rewrite BSTRHolder to a simpler form - Remove layers in the managed site - Use the BSTR marshaller instead of Marshal class helpers - Remove unused signatures --- .../Runtime/InteropServices/ComActivator.cs | 53 +++++++++++++------ src/coreclr/inc/holder.h | 41 ++++++++++++++ src/coreclr/inc/utilcode.h | 6 --- src/coreclr/utilcode/comex.cpp | 2 +- src/coreclr/vm/corelib.h | 6 +-- src/coreclr/vm/interoputil.cpp | 2 +- src/coreclr/vm/metasig.h | 10 ---- src/coreclr/vm/runtimecallablewrapper.cpp | 38 ++++--------- .../COM/NETClients/Licensing/Program.cs | 6 +-- .../Interop/COM/NativeServer/LicenseTesting.h | 2 +- 10 files changed, 97 insertions(+), 69 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs b/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs index 5ac78f35cdcee0..9a03b145cc6acc 100644 --- a/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs +++ b/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs @@ -9,6 +9,7 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; using System.Runtime.Loader; using System.Runtime.Versioning; @@ -762,10 +763,17 @@ private static extern bool Contains( [UnsafeAccessorType(LicInfoHelperLicenseContextTypeName)] object? licInfoHelperContext, string assemblyName); - // Helper function to create an object from the native side - public static object Create() + [UnmanagedCallersOnly] + private static unsafe void Create(object* pResult, Exception* pException) { - return new LicenseInteropProxy(); + try + { + *pResult = new LicenseInteropProxy(); + } + catch (Exception ex) + { + *pException = ex; + } } // Determine if the type supports licensing @@ -866,31 +874,42 @@ public static object AllocateAndValidateLicense([DynamicallyAccessedMembers(Dyna } } - // See usage in native RCW code - public void GetCurrentContextInfo(RuntimeTypeHandle rth, out bool isDesignTime, out IntPtr bstrKey) + [UnmanagedCallersOnly] + private static unsafe void GetCurrentContextInfo(LicenseInteropProxy* pProxy, MethodTable* pMT, bool* pIsDesignTime, ushort** pBstrKey, Exception* pException) { - Type targetRcwTypeMaybe = Type.GetTypeFromHandle(rth)!; - - _licContext = GetCurrentContextInfo(null, targetRcwTypeMaybe, out isDesignTime, out string? key); + try + { + RuntimeType targetRcwTypeMaybe = RuntimeTypeHandle.GetRuntimeType(pMT); + pProxy->_licContext = GetCurrentContextInfo(null, targetRcwTypeMaybe, out *pIsDesignTime, out string? key); - _targetRcwType = targetRcwTypeMaybe; - bstrKey = Marshal.StringToBSTR((string)key!); + pProxy->_targetRcwType = targetRcwTypeMaybe; + *pBstrKey = BStrStringMarshaller.ConvertToUnmanaged(key); + } + catch (Exception ex) + { + *pException = ex; + } } // The CLR invokes this when instantiating a licensed COM // object inside a designtime license context. // It's purpose is to save away the license key that the CLR // retrieved using RequestLicKey(). - public void SaveKeyInCurrentContext(IntPtr bstrKey) + [UnmanagedCallersOnly] + private static unsafe void SaveKeyInCurrentContext(LicenseInteropProxy* pProxy, ushort* bstrKey, Exception* pException) { - if (bstrKey == IntPtr.Zero) + try { - return; + string? key = BStrStringMarshaller.ConvertToManaged(bstrKey); + if (key is not null) + { + SetSavedLicenseKey(pProxy->_licContext!, pProxy->_targetRcwType!, key); + } + } + catch (Exception ex) + { + *pException = ex; } - - string key = Marshal.PtrToStringBSTR(bstrKey); - - SetSavedLicenseKey(_licContext!, _targetRcwType!, key); } } } diff --git a/src/coreclr/inc/holder.h b/src/coreclr/inc/holder.h index 026173b372b3ce..cf14455feaa348 100644 --- a/src/coreclr/inc/holder.h +++ b/src/coreclr/inc/holder.h @@ -1244,6 +1244,47 @@ class HKEYHolder }; #endif // HOST_WINDOWS +#ifdef FEATURE_COMINTEROP +class BSTRHolder final +{ + BSTR m_str; +public: + BSTRHolder() + : m_str{} + { + STATIC_CONTRACT_LEAF; + } + explicit BSTRHolder(BSTR str) + : m_str{ str } + { + STATIC_CONTRACT_LEAF; + } + ~BSTRHolder() noexcept + { + STATIC_CONTRACT_WRAPPER; + Free(); + } + + void Free() + { + STATIC_CONTRACT_WRAPPER; + ::SysFreeString(m_str); + m_str = NULL; + } + + void Attach(BSTR str) + { + STATIC_CONTRACT_WRAPPER; + Free(); + _ASSERTE(m_str == NULL); + m_str = str; + } + + BSTR* operator&() { STATIC_CONTRACT_LEAF; return &m_str; } + operator BSTR() const { STATIC_CONTRACT_LEAF; return m_str; } +}; +#endif // FEATURE_COMINTEROP + //---------------------------------------------------------------------------- // // External data access does not want certain holder implementations diff --git a/src/coreclr/inc/utilcode.h b/src/coreclr/inc/utilcode.h index 5f433ef7010bea..d074869642da63 100644 --- a/src/coreclr/inc/utilcode.h +++ b/src/coreclr/inc/utilcode.h @@ -3453,12 +3453,6 @@ namespace util INDEBUG(BOOL DbgIsExecutable(LPVOID lpMem, SIZE_T length);) -#ifdef FEATURE_COMINTEROP -FORCEINLINE void HolderSysFreeString(BSTR str) { CONTRACT_VIOLATION(ThrowsViolation); SysFreeString(str); } - -typedef Wrapper BSTRHolder; -#endif - BOOL IsIPInModule(PTR_VOID pModuleBaseAddress, PCODE ip); namespace UtilCode diff --git a/src/coreclr/utilcode/comex.cpp b/src/coreclr/utilcode/comex.cpp index 83785fbf46b221..0e6321242323ac 100644 --- a/src/coreclr/utilcode/comex.cpp +++ b/src/coreclr/utilcode/comex.cpp @@ -44,7 +44,7 @@ void COMException::GetMessage(SString &string) if (m_pErrorInfo != NULL) { - BSTRHolder message(NULL); + BSTRHolder message; if (SUCCEEDED(m_pErrorInfo->GetDescription(&message))) string.Set(message, SysStringLen(message)); } diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 51fd4dee8af33c..029fffc9d93f10 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -185,9 +185,9 @@ DEFINE_METHOD(COM_OBJECT, CTOR, .ctor, #endif // FOR_ILLINK DEFINE_CLASS(LICENSE_INTEROP_PROXY, InternalInteropServices, LicenseInteropProxy) -DEFINE_METHOD(LICENSE_INTEROP_PROXY, CREATE, Create, SM_RetObj) -DEFINE_METHOD(LICENSE_INTEROP_PROXY, GETCURRENTCONTEXTINFO, GetCurrentContextInfo, IM_RuntimeTypeHandle_RefBool_RefIntPtr_RetVoid) -DEFINE_METHOD(LICENSE_INTEROP_PROXY, SAVEKEYINCURRENTCONTEXT, SaveKeyInCurrentContext, IM_IntPtr_RetVoid) +DEFINE_METHOD(LICENSE_INTEROP_PROXY, CREATE, Create, NoSig) +DEFINE_METHOD(LICENSE_INTEROP_PROXY, GETCURRENTCONTEXTINFO, GetCurrentContextInfo, NoSig) +DEFINE_METHOD(LICENSE_INTEROP_PROXY, SAVEKEYINCURRENTCONTEXT, SaveKeyInCurrentContext, NoSig) #endif // FEATURE_COMINTEROP END_ILLINK_FEATURE_SWITCH() diff --git a/src/coreclr/vm/interoputil.cpp b/src/coreclr/vm/interoputil.cpp index 3bd9c9ad7531b4..f14be9700ef1a7 100644 --- a/src/coreclr/vm/interoputil.cpp +++ b/src/coreclr/vm/interoputil.cpp @@ -3299,7 +3299,7 @@ void IUInvokeDispMethod( // We managed to retrieve an IDispatchEx IP so we will use it to // retrieve the DISPID. - BSTRHolder bstrTmpName = SysAllocString(aNamesToConvert[0]); + BSTRHolder bstrTmpName{ SysAllocString(aNamesToConvert[0]) }; if (!bstrTmpName) COMPlusThrowOM(); diff --git a/src/coreclr/vm/metasig.h b/src/coreclr/vm/metasig.h index 8dac8a5bba99e4..e6fd8821a0de5a 100644 --- a/src/coreclr/vm/metasig.h +++ b/src/coreclr/vm/metasig.h @@ -287,15 +287,6 @@ DEFINE_METASIG(SM(Obj_RetVoid, j, v)) DEFINE_METASIG(SM(Obj_RetInt, j, i)) DEFINE_METASIG(SM(Obj_RetIntPtr, j, I)) -#ifdef FEATURE_COMINTEROP -DEFINE_METASIG_T(SM(Obj_Int_RefComVariant_RetVoid, j i r(g(COMVARIANT)), v)) -DEFINE_METASIG_T(SM(Obj_RefComVariant_RetVoid, j r(g(COMVARIANT)), v)) -DEFINE_METASIG_T(SM(RefComVariant_RetObject, r(g(COMVARIANT)), j)) -DEFINE_METASIG_T(IM(RuntimeTypeHandle_RefBool_RefIntPtr_RetVoid, g(RT_TYPE_HANDLE) r(F) r(I), v)) - -#endif - - DEFINE_METASIG(SM(Str_RetInt, s, i)) DEFINE_METASIG(SM(Int_Str_RetIntPtr, i s, I)) DEFINE_METASIG(SM(Int_Str_IntPtr_RetIntPtr, i s I, I)) @@ -313,7 +304,6 @@ DEFINE_METASIG_T(IM(RetModule, _, C(MODULE))) DEFINE_METASIG_T(IM(PtrNativeAssemblyNameParts, P(g(NATIVE_ASSEMBLY_NAME_PARTS)), v)) DEFINE_METASIG(SM(PtrCharPtrVoid, P(u) P(v), v)) DEFINE_METASIG(IM(RetObj, _, j)) -DEFINE_METASIG(SM(RetObj, _, j)) DEFINE_METASIG(IM(RetStr, _, s)) DEFINE_METASIG_T(IM(RetType, _, C(TYPE))) diff --git a/src/coreclr/vm/runtimecallablewrapper.cpp b/src/coreclr/vm/runtimecallablewrapper.cpp index 3993c5293f138b..afc684ce7b8392 100644 --- a/src/coreclr/vm/runtimecallablewrapper.cpp +++ b/src/coreclr/vm/runtimecallablewrapper.cpp @@ -99,7 +99,7 @@ IUnknown *ComClassFactory::CreateInstanceFromClassFactory(IClassFactory *pClassF HRESULT hr = S_OK; SafeComHolder pClassFact2 = NULL; SafeComHolder pUnk = NULL; - BSTRHolder bstrKey = NULL; + BSTRHolder bstrKey; // If the class doesn't support licensing or if it is missing a managed // type to use for querying a license, just use IClassFactory. @@ -121,40 +121,30 @@ IUnknown *ComClassFactory::CreateInstanceFromClassFactory(IClassFactory *pClassF } else { - _ASSERTE(m_pClassMT != NULL); - // Get the type to query for licensing. - TypeHandle rth = TypeHandle(m_pClassMT); + _ASSERTE(m_pClassMT != NULL); struct { OBJECTREF pProxy; - OBJECTREF pType; } gc; gc.pProxy = NULL; // LicenseInteropProxy - gc.pType = NULL; GCPROTECT_BEGIN(gc); // Create an instance of the object - MethodDescCallSite createObj(METHOD__LICENSE_INTEROP_PROXY__CREATE); - gc.pProxy = createObj.Call_RetOBJECTREF(NULL); - gc.pType = rth.GetManagedClassObject(); + UnmanagedCallersOnlyCaller createObj(METHOD__LICENSE_INTEROP_PROXY__CREATE); + createObj.InvokeThrowing(&gc.pProxy); // Query the current licensing context - MethodDescCallSite getCurrentContextInfo(METHOD__LICENSE_INTEROP_PROXY__GETCURRENTCONTEXTINFO, &gc.pProxy); - CLR_BOOL fDesignTime = FALSE; - ARG_SLOT args[4]; - args[0] = ObjToArgSlot(gc.pProxy); - args[1] = ObjToArgSlot(gc.pType); - args[2] = (ARG_SLOT)&fDesignTime; - args[3] = (ARG_SLOT)(BSTR*)&bstrKey; + UnmanagedCallersOnlyCaller getCurrentContextInfo(METHOD__LICENSE_INTEROP_PROXY__GETCURRENTCONTEXTINFO); - getCurrentContextInfo.Call(args); + CLR_BOOL fDesignTime = FALSE; + getCurrentContextInfo.InvokeThrowing(&gc.pProxy, m_pClassMT, &fDesignTime, &bstrKey); if (fDesignTime) { - // If designtime, we're supposed to obtain the runtime license key + // If design-time, we're supposed to obtain the runtime license key // from the component and save it away in the license context. // (the design tool can then grab it and embedded it into the // app it is creating) @@ -163,9 +153,7 @@ IUnknown *ComClassFactory::CreateInstanceFromClassFactory(IClassFactory *pClassF // It's illegal for our helper to return a non-null bstrKey // when the context is design-time. But we'll try to do the // right thing anyway. - _ASSERTE(!"We're not supposed to get here, but we'll try to cope anyway."); - SysFreeString(bstrKey); - bstrKey = NULL; + bstrKey.Free(); } { @@ -181,11 +169,8 @@ IUnknown *ComClassFactory::CreateInstanceFromClassFactory(IClassFactory *pClassF // Store the requested license key if (SUCCEEDED(hr)) { - MethodDescCallSite saveKeyInCurrentContext(METHOD__LICENSE_INTEROP_PROXY__SAVEKEYINCURRENTCONTEXT, &gc.pProxy); - - args[0] = ObjToArgSlot(gc.pProxy); - args[1] = (ARG_SLOT)(BSTR)bstrKey; - saveKeyInCurrentContext.Call(args); + UnmanagedCallersOnlyCaller saveKeyInCurrentContext(METHOD__LICENSE_INTEROP_PROXY__SAVEKEYINCURRENTCONTEXT); + saveKeyInCurrentContext.InvokeThrowing(&gc.pProxy, (BSTR)bstrKey); } } @@ -210,7 +195,6 @@ IUnknown *ComClassFactory::CreateInstanceFromClassFactory(IClassFactory *pClassF else { // It is runtime and we have a license key. - _ASSERTE(bstrKey != NULL); hr = pClassFact2->CreateInstanceLic(punkOuter, NULL, IID_IUnknown, bstrKey, (void**)&pUnk); if (FAILED(hr) && punkOuter) { diff --git a/src/tests/Interop/COM/NETClients/Licensing/Program.cs b/src/tests/Interop/COM/NETClients/Licensing/Program.cs index e8f21273b4f76d..13bce04d9eff9b 100644 --- a/src/tests/Interop/COM/NETClients/Licensing/Program.cs +++ b/src/tests/Interop/COM/NETClients/Licensing/Program.cs @@ -75,9 +75,9 @@ public override void SetSavedLicenseKey(Type type, string key) } } - static void ActivateUnderDesigntimeContext() + static void ActivateUnderDesignTimeContext() { - Console.WriteLine($"Calling {nameof(ActivateUnderDesigntimeContext)}..."); + Console.WriteLine($"Calling {nameof(ActivateUnderDesignTimeContext)}..."); LicenseContext prev = LicenseManager.CurrentContext; try @@ -134,7 +134,7 @@ public static int TestEntryPoint() try { ActivateLicensedObject(); - ActivateUnderDesigntimeContext(); + ActivateUnderDesignTimeContext(); ActivateUnderRuntimeContext(); } catch (Exception e) diff --git a/src/tests/Interop/COM/NativeServer/LicenseTesting.h b/src/tests/Interop/COM/NativeServer/LicenseTesting.h index a67676c38c7f25..f56081a238728c 100644 --- a/src/tests/Interop/COM/NativeServer/LicenseTesting.h +++ b/src/tests/Interop/COM/NativeServer/LicenseTesting.h @@ -28,7 +28,7 @@ class LicenseTesting : public UnknownImpl, public ILicenseTesting public: LicenseTesting(_In_opt_ BSTR lic) - : _lic{ lic } + : _lic{ TP_SysAllocString(lic) } { if (s_DenyLicense) throw CLASS_E_NOTLICENSED; From eb67706bf62d710b05cc59e00fd2f5a0fc22444d Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Wed, 25 Mar 2026 18:15:33 -0700 Subject: [PATCH 2/4] Feedback --- src/coreclr/inc/holder.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/coreclr/inc/holder.h b/src/coreclr/inc/holder.h index cf14455feaa348..a32c622710278f 100644 --- a/src/coreclr/inc/holder.h +++ b/src/coreclr/inc/holder.h @@ -1265,6 +1265,11 @@ class BSTRHolder final Free(); } + BSTRHolder(const BSTRHolder&) = delete; + BSTRHolder& operator=(const BSTRHolder&) = delete; + BSTRHolder(BSTRHolder&&) = delete; + BSTRHolder& operator=(BSTRHolder&&) = delete; + void Free() { STATIC_CONTRACT_WRAPPER; @@ -1280,7 +1285,13 @@ class BSTRHolder final m_str = str; } - BSTR* operator&() { STATIC_CONTRACT_LEAF; return &m_str; } + BSTR* operator&() + { + STATIC_CONTRACT_LEAF; + _ASSERTE(m_str == NULL); + return &m_str; + } + operator BSTR() const { STATIC_CONTRACT_LEAF; return m_str; } }; #endif // FEATURE_COMINTEROP From 56f981d5a24d3dc4d5713a6091755b20e4177433 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Thu, 26 Mar 2026 10:53:38 -0700 Subject: [PATCH 3/4] Refactor LicenseInteropProxy to use constructor for initialization and update method signatures --- .../Runtime/InteropServices/ComActivator.cs | 36 ++++++++----------- src/coreclr/vm/corelib.h | 5 ++- src/coreclr/vm/runtimecallablewrapper.cpp | 13 +++---- 3 files changed, 20 insertions(+), 34 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs b/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs index 9a03b145cc6acc..9e36c087c0bbb0 100644 --- a/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs +++ b/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs @@ -707,9 +707,14 @@ internal sealed class LicenseInteropProxy private const string LicenseRefTypeName = "System.ComponentModel.License&, System.ComponentModel.TypeConverter"; private const string LicInfoHelperLicenseContextTypeName = "System.ComponentModel.LicenseManager+LicInfoHelperLicenseContext, System.ComponentModel.TypeConverter"; - // RCW Activation - private object? _licContext; - private Type? _targetRcwType; + private readonly object _licContext; + private readonly Type _targetRcwType; + + private LicenseInteropProxy(object licContext, Type targetRcwType) + { + _licContext = licContext; + _targetRcwType = targetRcwType; + } [UnsafeAccessor(UnsafeAccessorKind.Method)] private static extern void SetSavedLicenseKey( @@ -735,7 +740,7 @@ private static extern bool ValidateAndRetrieveLicenseDetails( [UnsafeAccessor(UnsafeAccessorKind.StaticMethod)] [return: UnsafeAccessorType(LicenseContextTypeName)] - private static extern object? GetCurrentContextInfo( + private static extern object GetCurrentContextInfo( [UnsafeAccessorType(LicenseInteropHelperTypeName)] object? licInteropHelper, Type type, out bool isDesignTime, @@ -763,19 +768,6 @@ private static extern bool Contains( [UnsafeAccessorType(LicInfoHelperLicenseContextTypeName)] object? licInfoHelperContext, string assemblyName); - [UnmanagedCallersOnly] - private static unsafe void Create(object* pResult, Exception* pException) - { - try - { - *pResult = new LicenseInteropProxy(); - } - catch (Exception ex) - { - *pException = ex; - } - } - // Determine if the type supports licensing public static bool HasLicense(Type type) { @@ -875,15 +867,15 @@ public static object AllocateAndValidateLicense([DynamicallyAccessedMembers(Dyna } [UnmanagedCallersOnly] - private static unsafe void GetCurrentContextInfo(LicenseInteropProxy* pProxy, MethodTable* pMT, bool* pIsDesignTime, ushort** pBstrKey, Exception* pException) + private static unsafe void GetCurrentContextInfoAndProxy(MethodTable* pMT, bool* pIsDesignTime, ushort** pBstrKey, object* pProxy, Exception* pException) { try { RuntimeType targetRcwTypeMaybe = RuntimeTypeHandle.GetRuntimeType(pMT); - pProxy->_licContext = GetCurrentContextInfo(null, targetRcwTypeMaybe, out *pIsDesignTime, out string? key); + object licContext = GetCurrentContextInfo(null, targetRcwTypeMaybe, out *pIsDesignTime, out string? key); - pProxy->_targetRcwType = targetRcwTypeMaybe; *pBstrKey = BStrStringMarshaller.ConvertToUnmanaged(key); + *pProxy = new LicenseInteropProxy(licContext, targetRcwTypeMaybe); } catch (Exception ex) { @@ -892,7 +884,7 @@ private static unsafe void GetCurrentContextInfo(LicenseInteropProxy* pProxy, Me } // The CLR invokes this when instantiating a licensed COM - // object inside a designtime license context. + // object inside a design-time license context. // It's purpose is to save away the license key that the CLR // retrieved using RequestLicKey(). [UnmanagedCallersOnly] @@ -903,7 +895,7 @@ private static unsafe void SaveKeyInCurrentContext(LicenseInteropProxy* pProxy, string? key = BStrStringMarshaller.ConvertToManaged(bstrKey); if (key is not null) { - SetSavedLicenseKey(pProxy->_licContext!, pProxy->_targetRcwType!, key); + SetSavedLicenseKey(pProxy->_licContext, pProxy->_targetRcwType, key); } } catch (Exception ex) diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 029fffc9d93f10..03bc4760d985a6 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -185,9 +185,8 @@ DEFINE_METHOD(COM_OBJECT, CTOR, .ctor, #endif // FOR_ILLINK DEFINE_CLASS(LICENSE_INTEROP_PROXY, InternalInteropServices, LicenseInteropProxy) -DEFINE_METHOD(LICENSE_INTEROP_PROXY, CREATE, Create, NoSig) -DEFINE_METHOD(LICENSE_INTEROP_PROXY, GETCURRENTCONTEXTINFO, GetCurrentContextInfo, NoSig) -DEFINE_METHOD(LICENSE_INTEROP_PROXY, SAVEKEYINCURRENTCONTEXT, SaveKeyInCurrentContext, NoSig) +DEFINE_METHOD(LICENSE_INTEROP_PROXY, GETCURRENTCONTEXTINFO_AND_PROXY, GetCurrentContextInfoAndProxy, NoSig) +DEFINE_METHOD(LICENSE_INTEROP_PROXY, SAVEKEYINCURRENTCONTEXT, SaveKeyInCurrentContext, NoSig) #endif // FEATURE_COMINTEROP END_ILLINK_FEATURE_SWITCH() diff --git a/src/coreclr/vm/runtimecallablewrapper.cpp b/src/coreclr/vm/runtimecallablewrapper.cpp index afc684ce7b8392..6c028b2108c14c 100644 --- a/src/coreclr/vm/runtimecallablewrapper.cpp +++ b/src/coreclr/vm/runtimecallablewrapper.cpp @@ -128,19 +128,14 @@ IUnknown *ComClassFactory::CreateInstanceFromClassFactory(IClassFactory *pClassF { OBJECTREF pProxy; } gc; - gc.pProxy = NULL; // LicenseInteropProxy - + gc.pProxy = NULL; GCPROTECT_BEGIN(gc); - // Create an instance of the object - UnmanagedCallersOnlyCaller createObj(METHOD__LICENSE_INTEROP_PROXY__CREATE); - createObj.InvokeThrowing(&gc.pProxy); - - // Query the current licensing context - UnmanagedCallersOnlyCaller getCurrentContextInfo(METHOD__LICENSE_INTEROP_PROXY__GETCURRENTCONTEXTINFO); + // Create instance and query the current licensing context + UnmanagedCallersOnlyCaller getCurrentContextInfoAndProxy(METHOD__LICENSE_INTEROP_PROXY__GETCURRENTCONTEXTINFO_AND_PROXY); CLR_BOOL fDesignTime = FALSE; - getCurrentContextInfo.InvokeThrowing(&gc.pProxy, m_pClassMT, &fDesignTime, &bstrKey); + getCurrentContextInfoAndProxy.InvokeThrowing(m_pClassMT, &fDesignTime, &bstrKey, &gc.pProxy); if (fDesignTime) { From 16457e8b7cf3ec68c477234d5eef09c4f6f70a76 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Thu, 26 Mar 2026 17:01:28 -0700 Subject: [PATCH 4/4] Fix memory leak by freeing _lic before throwing CLASS_E_NOTLICENSED in LicenseTesting constructor --- src/tests/Interop/COM/NativeServer/LicenseTesting.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tests/Interop/COM/NativeServer/LicenseTesting.h b/src/tests/Interop/COM/NativeServer/LicenseTesting.h index f56081a238728c..013089f3fe2323 100644 --- a/src/tests/Interop/COM/NativeServer/LicenseTesting.h +++ b/src/tests/Interop/COM/NativeServer/LicenseTesting.h @@ -31,7 +31,10 @@ class LicenseTesting : public UnknownImpl, public ILicenseTesting : _lic{ TP_SysAllocString(lic) } { if (s_DenyLicense) + { + CoreClrBStrFree(_lic); throw CLASS_E_NOTLICENSED; + } } ~LicenseTesting()