From 95319d26f759d3f9c5ccba5db14bbb1a06c4d9ac Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 17:38:35 +0000 Subject: [PATCH 1/6] Convert more COM interop MethodDescCallSite to UCO Converts COM interop code from MethodDescCallSite to UnmanagedCallersOnly (UCO) pattern for three sites: 1. DispatchEx_GetMemberProperties (Property case): replaces two MethodDescCallSite invocations (for CanRead/CanWrite) with a single UCO helper GetDispatchExPropertyFlags in StubHelpers. 2. ICustomQueryInterface.GetInterface: replaces the callback struct pattern with a UCO helper CallICustomQueryInterface. Also removes the cached MethodDesc field m_pICustomQueryInterfaceGetInterfaceMD from ComCallWrapperTemplate. 3. ConnectionPoint.InvokeProviderMethod: replaces MethodDescCallSite calls for delegate construction and provider invocation with a single UCO helper InvokeConnectionPointProviderMethod. Removes the UIntPtr ctor fallback path (addressing pending feedback). Also removes the m_ohDelegate field and related methods (GetOHDelegate/SetOHDelegate/GetObjCreateDelegate/SetObjCreateDelegate) from EEClass/MethodTable since the delegate-based COM object creation callback feature in CreateAggregatedInstance is removed. Adds [RequiresUnsafe] to GetIEnumeratorToEnumVariantMarshaler UCO overload to be consistent with the new UCO methods. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/System/StubHelpers.cs | 72 +++++++++++++++++ src/coreclr/vm/class.h | 22 +---- src/coreclr/vm/comcallablewrapper.cpp | 81 +++---------------- src/coreclr/vm/comcallablewrapper.h | 3 - src/coreclr/vm/comconnectionpoints.cpp | 44 +++++----- src/coreclr/vm/corelib.h | 3 + src/coreclr/vm/metasig.h | 4 + src/coreclr/vm/methodtable.cpp | 54 ------------- src/coreclr/vm/methodtable.h | 6 -- src/coreclr/vm/runtimecallablewrapper.cpp | 61 +------------- src/coreclr/vm/stdinterfaces.cpp | 32 ++------ 11 files changed, 123 insertions(+), 259 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs index 042a34158eaa9b..b7e647bfcf203f 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs @@ -1503,6 +1503,7 @@ internal static void SetPendingExceptionObject(Exception? exception) [SupportedOSPlatform("windows")] [UnmanagedCallersOnly] + [RequiresUnsafe] private static unsafe void GetIEnumeratorToEnumVariantMarshaler(object* pResult, Exception* pException) { try @@ -1514,6 +1515,77 @@ private static unsafe void GetIEnumeratorToEnumVariantMarshaler(object* pResult, *pException = ex; } } + + private const int DispatchExPropertyCanRead = 1; + private const int DispatchExPropertyCanWrite = 2; + + [SupportedOSPlatform("windows")] + [UnmanagedCallersOnly] + [RequiresUnsafe] + private static unsafe void GetDispatchExPropertyFlags(PropertyInfo* pMemberInfo, int* pResult, Exception* pException) + { + try + { + int result = 0; + PropertyInfo property = *pMemberInfo; + if (property.CanRead) + { + result |= DispatchExPropertyCanRead; + } + + if (property.CanWrite) + { + result |= DispatchExPropertyCanWrite; + } + + *pResult = result; + } + catch (Exception ex) + { + *pException = ex; + } + } + + [SupportedOSPlatform("windows")] + [UnmanagedCallersOnly] + [RequiresUnsafe] + private static unsafe int CallICustomQueryInterface(ICustomQueryInterface* pObject, Guid* pIid, IntPtr* ppObject, Exception* pException) + { + try + { + return (int)(*pObject).GetInterface(ref *pIid, out *ppObject); + } + catch (Exception ex) + { + *pException = ex; + return 0; + } + } + + [SupportedOSPlatform("windows")] + [UnmanagedCallersOnly] + [RequiresUnsafe] + private static unsafe void InvokeConnectionPointProviderMethod( + object* pProvider, + delegate* providerMethodEntryPoint, + object* pDelegate, + delegate* delegateCtorMethodEntryPoint, + object* pSubscriber, + nint pEventMethodCodePtr, + Exception* pException) + { + try + { + // Construct the delegate before invoking the provider method. + delegateCtorMethodEntryPoint(*pDelegate, *pSubscriber, pEventMethodCodePtr); + + providerMethodEntryPoint(*pProvider, *pDelegate); + } + catch (Exception ex) + { + *pException = ex; + } + } #endif internal static object CreateCustomMarshaler(IntPtr pMD, int paramToken, IntPtr hndManagedType) diff --git a/src/coreclr/vm/class.h b/src/coreclr/vm/class.h index 9894f59da8f482..13d1ee37a8d3cd 100644 --- a/src/coreclr/vm/class.h +++ b/src/coreclr/vm/class.h @@ -1468,16 +1468,6 @@ class EEClass // DO NOT CREATE A NEW EEClass USING NEW! GetOptionalFields()->m_pCoClassForIntf = th; } - OBJECTHANDLE GetOHDelegate() - { - LIMITED_METHOD_CONTRACT; - return m_ohDelegate; - } - void SetOHDelegate (OBJECTHANDLE _ohDelegate) - { - LIMITED_METHOD_CONTRACT; - m_ohDelegate = _ohDelegate; - } // Set the COM interface type. CorIfaceAttr GetComInterfaceType() { @@ -1688,16 +1678,8 @@ class EEClass // DO NOT CREATE A NEW EEClass USING NEW! PTR_MethodDescChunk m_pChunks; #ifdef FEATURE_COMINTEROP - union - { - // For CLR wrapper objects that extend an unmanaged class, this field - // may contain a delegate to be called to allocate the aggregated - // unmanaged class (instead of using CoCreateInstance). - OBJECTHANDLE m_ohDelegate; - - // For interfaces this contains the COM interface type. - CorIfaceAttr m_ComInterfaceType; - }; + // For interfaces this contains the COM interface type. + CorIfaceAttr m_ComInterfaceType; ComCallWrapperTemplate *m_pccwTemplate; // points to interop data structures used when this type is exposed to COM #endif // FEATURE_COMINTEROP diff --git a/src/coreclr/vm/comcallablewrapper.cpp b/src/coreclr/vm/comcallablewrapper.cpp index 1b0c6eea5a4e45..b2a76e0a13c4f2 100644 --- a/src/coreclr/vm/comcallablewrapper.cpp +++ b/src/coreclr/vm/comcallablewrapper.cpp @@ -2314,52 +2314,6 @@ IUnknown* ComCallWrapper::GetBasicIP(bool inspectionOnly) RETURN ((cbRef != 0xbadf00d) ? pIntf : NULL); } -struct InvokeICustomQueryInterfaceGetInterfaceArgs -{ - ComCallWrapper *pWrap; - GUID *pGuid; - IUnknown **ppUnk; - CustomQueryInterfaceResult *pRetVal; -}; - -VOID __stdcall InvokeICustomQueryInterfaceGetInterface_CallBack(LPVOID ptr) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - PRECONDITION(CheckPointer(ptr)); - } - CONTRACTL_END; - InvokeICustomQueryInterfaceGetInterfaceArgs *pArgs = (InvokeICustomQueryInterfaceGetInterfaceArgs*)ptr; - - { - GCX_COOP(); - OBJECTREF pObj = pArgs->pWrap->GetObjectRef(); - - GCPROTECT_BEGIN(pObj); - - // 1. Get MD - MethodDesc *pMD = pArgs->pWrap->GetSimpleWrapper()->GetComCallWrapperTemplate()->GetICustomQueryInterfaceGetInterfaceMD(); - - // 2. Get Object Handle - OBJECTHANDLE hndCustomQueryInterface = pArgs->pWrap->GetObjectHandle(); - - // 3 construct the MethodDescCallSite - MethodDescCallSite GetInterface(pMD, hndCustomQueryInterface); - - ARG_SLOT Args[] = { - ObjToArgSlot(pObj), - PtrToArgSlot(pArgs->pGuid), - PtrToArgSlot(pArgs->ppUnk), - }; - - *(pArgs->pRetVal) = (CustomQueryInterfaceResult)GetInterface.Call_RetArgSlot(Args); - GCPROTECT_END(); - } -} - //-------------------------------------------------------------------------- // check if the interface is supported, return a index into the IMap // returns -1, if pIntfMT is not supported @@ -2601,9 +2555,19 @@ static bool GetComIPFromCCW_HandleCustomQI( guid = riid; } - InvokeICustomQueryInterfaceGetInterfaceArgs args = {pWrap, &guid, ppUnkOut, &retVal}; + { + GCX_COOP(); + OBJECTREF pObj = pWrap->GetObjectRef(); - InvokeICustomQueryInterfaceGetInterface_CallBack(&args); + GCPROTECT_BEGIN(pObj); + + INT32 result = static_cast(CustomQueryInterfaceResult::NotHandled); + UnmanagedCallersOnlyCaller callICustomQueryInterface(METHOD__STUBHELPERS__CALL_ICUSTOM_QUERY_INTERFACE); + result = callICustomQueryInterface.InvokeThrowing_Ret(&pObj, &guid, ppUnkOut); + + retVal = static_cast(result); + GCPROTECT_END(); + } // return if user already handle the QI if (retVal == Handled) @@ -4674,7 +4638,6 @@ ComCallWrapperTemplate* ComCallWrapperTemplate::CreateTemplate(TypeHandle thClas pTemplate->m_pClassComMT = NULL; // Defer setting this up. pTemplate->m_pBasicComMT = NULL; pTemplate->m_pDefaultItf = NULL; - pTemplate->m_pICustomQueryInterfaceGetInterfaceMD = NULL; pTemplate->m_flags = 0; // Determine the COM visibility of classes in our hierarchy. @@ -4794,7 +4757,6 @@ ComCallWrapperTemplate *ComCallWrapperTemplate::CreateTemplateForInterface(Metho pTemplate->m_pClassComMT = NULL; pTemplate->m_pBasicComMT = NULL; pTemplate->m_pDefaultItf = pItfMT; - pTemplate->m_pICustomQueryInterfaceGetInterfaceMD = NULL; pTemplate->m_flags = enum_RepresentsVariantInterface; // Initialize the one ComMethodTable @@ -4927,25 +4889,6 @@ ComMethodTable *ComCallWrapperTemplate::SetupComMethodTableForClass(MethodTable RETURN pIClassXComMT; } - -MethodDesc * ComCallWrapperTemplate::GetICustomQueryInterfaceGetInterfaceMD() -{ - CONTRACT (MethodDesc*) - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - PRECONDITION(m_flags & enum_ImplementsICustomQueryInterface); - } - CONTRACT_END; - - if (m_pICustomQueryInterfaceGetInterfaceMD == NULL) - m_pICustomQueryInterfaceGetInterfaceMD = m_thClass.GetMethodTable()->GetMethodDescForInterfaceMethod( - CoreLibBinder::GetMethod(METHOD__ICUSTOM_QUERYINTERFACE__GET_INTERFACE), - TRUE /* throwOnConflict */); - RETURN m_pICustomQueryInterfaceGetInterfaceMD; -} - //-------------------------------------------------------------------------- // Module* ComCallMethodDesc::GetModule() // Get Module diff --git a/src/coreclr/vm/comcallablewrapper.h b/src/coreclr/vm/comcallablewrapper.h index 64292714243b37..9b0b4bb93ee7f1 100644 --- a/src/coreclr/vm/comcallablewrapper.h +++ b/src/coreclr/vm/comcallablewrapper.h @@ -235,8 +235,6 @@ class ComCallWrapperTemplate // Sets up the class method table for the IClassX and also lays it out. static ComMethodTable *SetupComMethodTableForClass(MethodTable *pMT, BOOL bLayOutComMT); - MethodDesc * GetICustomQueryInterfaceGetInterfaceMD(); - BOOL HasInvisibleParent() { LIMITED_METHOD_CONTRACT; @@ -328,7 +326,6 @@ class ComCallWrapperTemplate enum_IsSafeTypeForMarshalling = 0x2000, // The class can be safely marshalled out of process via DCOM }; DWORD m_flags; - MethodDesc* m_pICustomQueryInterfaceGetInterfaceMD; ULONG m_cbInterfaces; SLOT* m_rgpIPtr[1]; }; diff --git a/src/coreclr/vm/comconnectionpoints.cpp b/src/coreclr/vm/comconnectionpoints.cpp index 6442c534436567..2a9b12e6e1d3c5 100644 --- a/src/coreclr/vm/comconnectionpoints.cpp +++ b/src/coreclr/vm/comconnectionpoints.cpp @@ -539,7 +539,16 @@ void ConnectionPoint::InvokeProviderMethod( OBJECTREF pProvider, OBJECTREF pSubs // Retrieve the EE class representing the argument. MethodTable *pDelegateCls = MethodSig.GetLastTypeHandleThrowing().GetMethodTable(); - // Make sure we activate the assembly containing the target method desc + // Initialize the delegate using the arguments structure. + // Generics: ensure we get the right MethodDesc here and in similar places + MethodDesc *pDlgCtorMD = MemberLoader::FindConstructor(pDelegateCls, &gsig_IM_Obj_IntPtr_RetVoid); + + // The loader is responsible for only accepting well-formed delegate classes. + _ASSERTE(pDlgCtorMD); + + // Make sure we activate assemblies containing target method descs. + pProvMethodDesc->EnsureActive(); + pDlgCtorMD->EnsureActive(); pEventMethodDesc->EnsureActive(); // Allocate an object based on the method table of the delegate class. @@ -547,29 +556,16 @@ void ConnectionPoint::InvokeProviderMethod( OBJECTREF pProvider, OBJECTREF pSubs GCPROTECT_BEGIN( pDelegate ); { - // Initialize the delegate using the arguments structure. - // Generics: ensure we get the right MethodDesc here and in similar places - // Accept both void (object, native int) and void (object, native uint) - MethodDesc *pDlgCtorMD = MemberLoader::FindConstructor(pDelegateCls, &gsig_IM_Obj_IntPtr_RetVoid); - if (pDlgCtorMD == NULL) - pDlgCtorMD = MemberLoader::FindConstructor(pDelegateCls, &gsig_IM_Obj_UIntPtr_RetVoid); - - // The loader is responsible for only accepting well-formed delegate classes. - _ASSERTE(pDlgCtorMD); - - MethodDescCallSite dlgCtor(pDlgCtorMD); - - ARG_SLOT CtorArgs[3] = { ObjToArgSlot(pDelegate), - ObjToArgSlot(pSubscriber), - (ARG_SLOT)pEventMethodDesc->GetMultiCallableAddrOfCode() - }; - dlgCtor.Call(CtorArgs); - - MethodDescCallSite prov(pProvMethodDesc, &pProvider); - - // Do the actual invocation of the method method. - ARG_SLOT Args[2] = { ObjToArgSlot( pProvider ), ObjToArgSlot( pDelegate ) }; - prov.Call(Args); + UnmanagedCallersOnlyCaller invokeConnectionPointProviderMethod(METHOD__STUBHELPERS__INVOKE_CONNECTION_POINT_PROVIDER_METHOD); + + // Construct the delegate and invoke the provider method in one helper. + invokeConnectionPointProviderMethod.InvokeThrowing( + &pProvider, + (INT_PTR)pProvMethodDesc->GetSingleCallableAddrOfCode(), + &pDelegate, + (INT_PTR)pDlgCtorMD->GetSingleCallableAddrOfCode(), + &pSubscriber, + (INT_PTR)pEventMethodDesc->GetSingleCallableAddrOfCode()); } GCPROTECT_END(); } diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 3d58d3bf98c82d..6e16bc759ee946 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -1053,6 +1053,9 @@ DEFINE_METHOD(STUBHELPERS, GET_PENDING_EXCEPTION_OBJECT, GetPendingExce DEFINE_METHOD(STUBHELPERS, CREATE_CUSTOM_MARSHALER, CreateCustomMarshaler, SM_IntPtr_Int_IntPtr_RetObj) #ifdef FEATURE_COMINTEROP DEFINE_METHOD(STUBHELPERS, GET_IENUMERATOR_TO_ENUM_VARIANT_MARSHALER, GetIEnumeratorToEnumVariantMarshaler, SM_PtrObj_PtrException_RetVoid) +DEFINE_METHOD(STUBHELPERS, GET_DISPATCH_EX_PROPERTY_FLAGS, GetDispatchExPropertyFlags, SM_PtrPropertyInfo_PtrInt_PtrException_RetVoid) +DEFINE_METHOD(STUBHELPERS, CALL_ICUSTOM_QUERY_INTERFACE, CallICustomQueryInterface, SM_PtrICustomQueryInterface_PtrGuid_PtrIntPtr_PtrException_RetInt) +DEFINE_METHOD(STUBHELPERS, INVOKE_CONNECTION_POINT_PROVIDER_METHOD, InvokeConnectionPointProviderMethod, NoSig) #endif // FEATURE_COMINTEROP DEFINE_METHOD(STUBHELPERS, CHECK_STRING_LENGTH, CheckStringLength, SM_Int_RetVoid) diff --git a/src/coreclr/vm/metasig.h b/src/coreclr/vm/metasig.h index 0ff156f0883adc..58791b91890a1c 100644 --- a/src/coreclr/vm/metasig.h +++ b/src/coreclr/vm/metasig.h @@ -214,6 +214,10 @@ DEFINE_METASIG(SM(RefByte_RefByte_UIntPtr_RetVoid, r(b) r(b) U, v)) DEFINE_METASIG(SM(RefByte_Byte_UIntPtr_RetVoid, r(b) b U, v)) DEFINE_METASIG(SM(RefByte_UIntPtr_RetVoid, r(b) U, v)) DEFINE_METASIG(SM(PtrVoid_Byte_UInt_RetVoid, P(v) b K, v)) +#ifdef FEATURE_COMINTEROP +DEFINE_METASIG_T(SM(PtrICustomQueryInterface_PtrGuid_PtrIntPtr_PtrException_RetInt, P(C(ICUSTOM_QUERYINTERFACE)) P(g(GUID)) P(I) P(C(EXCEPTION)), i)) +DEFINE_METASIG_T(SM(PtrPropertyInfo_PtrInt_PtrException_RetVoid, P(C(PROPERTY_INFO)) P(i) P(C(EXCEPTION)), v)) +#endif // FEATURE_COMINTEROP DEFINE_METASIG(SM(IntPtr_RefObj_IntPtr_RetVoid, I r(j) I, v)) DEFINE_METASIG(SM(IntPtr_RefObj_IntPtr_Int_RetVoid, I r(j) I i,v)) DEFINE_METASIG(SM(IntPtr_IntPtr_Int_Int_IntPtr_RetVoid, I I i i I, v)) diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 9d609123829ca0..0234a880c986fe 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -708,44 +708,6 @@ MethodTable* CreateMinimalMethodTable(Module* pContainingModule, return pMT; } - -#ifdef FEATURE_COMINTEROP -//========================================================================================== -OBJECTREF MethodTable::GetObjCreateDelegate() -{ - CONTRACTL - { - MODE_COOPERATIVE; - GC_NOTRIGGER; - NOTHROW; - } - CONTRACTL_END; - _ASSERT(!IsInterface()); - if (GetOHDelegate()) - return ObjectFromHandle(GetOHDelegate()); - else - return NULL; -} - -//========================================================================================== -void MethodTable::SetObjCreateDelegate(OBJECTREF orDelegate) -{ - CONTRACTL - { - MODE_COOPERATIVE; - GC_NOTRIGGER; - THROWS; // From CreateHandle - } - CONTRACTL_END; - - if (GetOHDelegate()) - StoreObjectInHandle(GetOHDelegate(), orDelegate); - else - SetOHDelegate (GetAppDomain()->CreateHandle(orDelegate)); -} -#endif // FEATURE_COMINTEROP - - //========================================================================================== void MethodTable::SetInterfaceMap(WORD wNumInterfaces, InterfaceInfo_t* iMap) { @@ -4888,22 +4850,6 @@ BOOL MethodTable::IsExtensibleRCW() return IsComObjectType() && !GetClass()->IsComImport(); } -//========================================================================================== -OBJECTHANDLE MethodTable::GetOHDelegate() -{ - WRAPPER_NO_CONTRACT; - _ASSERTE(GetClass()); - return GetClass()->GetOHDelegate(); -} - -//========================================================================================== -void MethodTable::SetOHDelegate (OBJECTHANDLE _ohDelegate) -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(GetClass()); - GetClass()->SetOHDelegate(_ohDelegate); -} - //========================================================================================== // Helper to skip over COM class in the hierarchy MethodTable* MethodTable::GetComPlusParentMethodTable() diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index b99dcb293337be..23cc148a09fe57 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -1027,9 +1027,6 @@ class MethodTable CorIfaceAttr GetComInterfaceType(); void SetComInterfaceType(CorIfaceAttr ItfType); - OBJECTHANDLE GetOHDelegate(); - void SetOHDelegate (OBJECTHANDLE _ohDelegate); - CorClassIfaceAttr GetComClassInterfaceType(); TypeHandle GetDefItfForComClassItf(); @@ -1062,9 +1059,6 @@ class MethodTable BOOL SetComClassFactory(ClassFactoryBase *pFactory); #endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION - OBJECTREF GetObjCreateDelegate(); - void SetObjCreateDelegate(OBJECTREF orDelegate); - private: // This is for COM Interop backwards compatibility BOOL InsertComInteropData(InteropMethodTableData *pData); diff --git a/src/coreclr/vm/runtimecallablewrapper.cpp b/src/coreclr/vm/runtimecallablewrapper.cpp index db58879480b80a..dd484dc5b87f67 100644 --- a/src/coreclr/vm/runtimecallablewrapper.cpp +++ b/src/coreclr/vm/runtimecallablewrapper.cpp @@ -282,9 +282,6 @@ OBJECTREF ComClassFactory::CreateAggregatedInstance(MethodTable* pMTClass, BOOL HRESULT hr = S_OK; NewRCWHolder pNewRCW; - BOOL bUseDelegate = FALSE; - - MethodTable *pCallbackMT = NULL; OBJECTREF oref = NULL; COMOBJECTREF cref = NULL; @@ -295,68 +292,14 @@ OBJECTREF ComClassFactory::CreateAggregatedInstance(MethodTable* pMTClass, BOOL //get wrapper for the object, this could enable GC CCWHolder pComWrap = ComCallWrapper::InlineGetWrapper((OBJECTREF *)&cref); - // Make sure the ClassInitializer has run, since the user might have - // wanted to set up a COM object creation callback. - pMTClass->CheckRunClassInitThrowing(); - - // If the user is going to use a delegate to allocate the COM object - // (rather than CoCreateInstance), we need to know now, before we enable - // preemptive GC mode (since we touch object references in the - // determination). - // We don't just check the current class to see if it has a cllabck - // registered, we check up the class chain to see if any of our parents - // did. - - pCallbackMT = pMTClass; - while ((pCallbackMT != NULL) && - (pCallbackMT->GetObjCreateDelegate() == NULL) && - !pCallbackMT->IsComImport()) - { - pCallbackMT = pCallbackMT->GetParentMethodTable(); - } - - if (pCallbackMT && !pCallbackMT->IsComImport()) - bUseDelegate = TRUE; - DebuggerExitFrame __def; // get the IUnknown interface for the managed object pOuter = ComCallWrapper::GetComIPFromCCW(pComWrap, IID_IUnknown, NULL); _ASSERTE(pOuter != NULL); - // If the user has set a delegate to allocate the COM object, use it. - // Otherwise we just CoCreateInstance it. - if (bUseDelegate) - { - ARG_SLOT args[2]; - - OBJECTREF orDelegate = pCallbackMT->GetObjCreateDelegate(); - MethodDesc *pMeth = COMDelegate::GetMethodDesc(orDelegate); - - GCPROTECT_BEGIN(orDelegate) - { - _ASSERTE(pMeth); - MethodDescCallSite delegateMethod(pMeth, &orDelegate); - - // Get the OR on which we are going to invoke the method and set it - // as the first parameter in arg above. - args[0] = (ARG_SLOT)OBJECTREFToObject(COMDelegate::GetTargetObject(orDelegate)); - - // Pass the IUnknown of the aggregator as the second argument. - args[1] = (ARG_SLOT)(IUnknown*)pOuter; - - // Call the method... - pUnk = (IUnknown *)delegateMethod.Call_RetArgSlot(args); - if (!pUnk) - COMPlusThrowHR(E_FAIL); - } - GCPROTECT_END(); - } - else - { - _ASSERTE(m_pClassMT); - pUnk = CreateInstanceInternal(pOuter, &fDidContainment); - } + _ASSERTE(m_pClassMT); + pUnk = CreateInstanceInternal(pOuter, &fDidContainment); __def.Pop(); diff --git a/src/coreclr/vm/stdinterfaces.cpp b/src/coreclr/vm/stdinterfaces.cpp index 50b39ed1eb3921..1e386956ab8a36 100644 --- a/src/coreclr/vm/stdinterfaces.cpp +++ b/src/coreclr/vm/stdinterfaces.cpp @@ -1887,34 +1887,18 @@ HRESULT __stdcall DispatchEx_GetMemberProperties ( case Property: { - BOOL bCanRead = FALSE; - BOOL bCanWrite = FALSE; - - // Find the MethodDesc's for the CanRead property. - MethodDesc *pCanReadMD = MemberLoader::FindPropertyMethod(MemberInfoObj->GetMethodTable(), PROPERTY_INFO_CAN_READ_PROP, PropertyGet); - _ASSERTE_MSG((pCanReadMD != NULL), "Unable to find getter method for property PropertyInfo::CanRead"); - MethodDescCallSite canRead(pCanReadMD, &MemberInfoObj); - - // Find the MethodDesc's for the CanWrite property. - MethodDesc *pCanWriteMD = MemberLoader::FindPropertyMethod(MemberInfoObj->GetMethodTable(), PROPERTY_INFO_CAN_WRITE_PROP, PropertyGet); - _ASSERTE_MSG((pCanWriteMD != NULL), "Unable to find setter method for property PropertyInfo::CanWrite"); - MethodDescCallSite canWrite(pCanWriteMD, &MemberInfoObj); - - // Check to see if the property can be read. - ARG_SLOT CanReadArgs[] = + enum : INT32 { - ObjToArgSlot(MemberInfoObj) + DispatchExPropertyCanRead = 1, + DispatchExPropertyCanWrite = 2, }; - bCanRead = canRead.Call_RetBool(CanReadArgs); - - // Check to see if the property can be written to. - ARG_SLOT CanWriteArgs[] = - { - ObjToArgSlot(MemberInfoObj) - }; + INT32 propertyFlags = 0; + UnmanagedCallersOnlyCaller getDispatchExPropertyFlags(METHOD__STUBHELPERS__GET_DISPATCH_EX_PROPERTY_FLAGS); + getDispatchExPropertyFlags.InvokeThrowing(&MemberInfoObj, &propertyFlags); - bCanWrite = canWrite.Call_RetBool(CanWriteArgs); + bool bCanRead = (propertyFlags & DispatchExPropertyCanRead) != 0; + bool bCanWrite = (propertyFlags & DispatchExPropertyCanWrite) != 0; *pgrfdex = (bCanRead ? fdexPropCanGet : fdexPropCannotGet) | (bCanWrite ? fdexPropCanPut : fdexPropCannotPut) | From 6d9324dd6bd94c609296c62c141d1f5458c420b6 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Fri, 20 Mar 2026 11:11:30 -0700 Subject: [PATCH 2/6] Apply suggestion from @jkotas --- src/coreclr/vm/comcallablewrapper.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/coreclr/vm/comcallablewrapper.cpp b/src/coreclr/vm/comcallablewrapper.cpp index b2a76e0a13c4f2..d91459baf7b9b1 100644 --- a/src/coreclr/vm/comcallablewrapper.cpp +++ b/src/coreclr/vm/comcallablewrapper.cpp @@ -2561,9 +2561,8 @@ static bool GetComIPFromCCW_HandleCustomQI( GCPROTECT_BEGIN(pObj); - INT32 result = static_cast(CustomQueryInterfaceResult::NotHandled); UnmanagedCallersOnlyCaller callICustomQueryInterface(METHOD__STUBHELPERS__CALL_ICUSTOM_QUERY_INTERFACE); - result = callICustomQueryInterface.InvokeThrowing_Ret(&pObj, &guid, ppUnkOut); + INT32 result = callICustomQueryInterface.InvokeThrowing_Ret(&pObj, &guid, ppUnkOut); retVal = static_cast(result); GCPROTECT_END(); From 27f1e8c7b6a23fb55d05e15e86ebcce5bb624d02 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Fri, 20 Mar 2026 11:13:14 -0700 Subject: [PATCH 3/6] Apply suggestion from @jkotas --- src/coreclr/vm/comconnectionpoints.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/vm/comconnectionpoints.cpp b/src/coreclr/vm/comconnectionpoints.cpp index 2a9b12e6e1d3c5..e457f00434c924 100644 --- a/src/coreclr/vm/comconnectionpoints.cpp +++ b/src/coreclr/vm/comconnectionpoints.cpp @@ -542,6 +542,8 @@ void ConnectionPoint::InvokeProviderMethod( OBJECTREF pProvider, OBJECTREF pSubs // Initialize the delegate using the arguments structure. // Generics: ensure we get the right MethodDesc here and in similar places MethodDesc *pDlgCtorMD = MemberLoader::FindConstructor(pDelegateCls, &gsig_IM_Obj_IntPtr_RetVoid); + if (pDlgCtorMD == NULL) + pDlgCtorMD = MemberLoader::FindConstructor(pDelegateCls, &gsig_IM_Obj_UIntPtr_RetVoid); // The loader is responsible for only accepting well-formed delegate classes. _ASSERTE(pDlgCtorMD); From 9297f814996bbf7d63ca9087c6e3b21023674f34 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Fri, 20 Mar 2026 11:16:50 -0700 Subject: [PATCH 4/6] Apply suggestion from @jkotas --- src/coreclr/vm/comconnectionpoints.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/vm/comconnectionpoints.cpp b/src/coreclr/vm/comconnectionpoints.cpp index e457f00434c924..4e797a9335f07f 100644 --- a/src/coreclr/vm/comconnectionpoints.cpp +++ b/src/coreclr/vm/comconnectionpoints.cpp @@ -563,11 +563,11 @@ void ConnectionPoint::InvokeProviderMethod( OBJECTREF pProvider, OBJECTREF pSubs // Construct the delegate and invoke the provider method in one helper. invokeConnectionPointProviderMethod.InvokeThrowing( &pProvider, - (INT_PTR)pProvMethodDesc->GetSingleCallableAddrOfCode(), + pProvMethodDesc->GetSingleCallableAddrOfCode(), &pDelegate, - (INT_PTR)pDlgCtorMD->GetSingleCallableAddrOfCode(), + pDlgCtorMD->GetSingleCallableAddrOfCode(), &pSubscriber, - (INT_PTR)pEventMethodDesc->GetSingleCallableAddrOfCode()); + pEventMethodDesc->GetMultiCallableAddrOfCode()); } GCPROTECT_END(); } From 67ffd616952e091e99bd376eaa17ed8908d670c7 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Fri, 20 Mar 2026 11:17:45 -0700 Subject: [PATCH 5/6] Apply suggestion from @jkotas --- src/coreclr/vm/comconnectionpoints.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/vm/comconnectionpoints.cpp b/src/coreclr/vm/comconnectionpoints.cpp index 4e797a9335f07f..1179941c66331d 100644 --- a/src/coreclr/vm/comconnectionpoints.cpp +++ b/src/coreclr/vm/comconnectionpoints.cpp @@ -540,7 +540,6 @@ void ConnectionPoint::InvokeProviderMethod( OBJECTREF pProvider, OBJECTREF pSubs MethodTable *pDelegateCls = MethodSig.GetLastTypeHandleThrowing().GetMethodTable(); // Initialize the delegate using the arguments structure. - // Generics: ensure we get the right MethodDesc here and in similar places MethodDesc *pDlgCtorMD = MemberLoader::FindConstructor(pDelegateCls, &gsig_IM_Obj_IntPtr_RetVoid); if (pDlgCtorMD == NULL) pDlgCtorMD = MemberLoader::FindConstructor(pDelegateCls, &gsig_IM_Obj_UIntPtr_RetVoid); From f01d71f66a1897acbfa52778d249f0204c11965d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Mar 2026 22:50:03 +0000 Subject: [PATCH 6/6] Address review feedback: GetDispatchExPropertyFlags returns int, use InvokeThrowing_Ret Co-authored-by: AaronRobinsonMSFT <30635565+AaronRobinsonMSFT@users.noreply.github.com> Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/dde670ee-197d-4271-8596-d75d3cca3116 --- src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs | 5 +++-- src/coreclr/vm/comconnectionpoints.cpp | 2 +- src/coreclr/vm/corelib.h | 2 +- src/coreclr/vm/metasig.h | 2 +- src/coreclr/vm/stdinterfaces.cpp | 3 +-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs index a290fb5f1f2de4..04829818b7d427 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs @@ -1550,7 +1550,7 @@ private static unsafe void GetIEnumeratorToEnumVariantMarshaler(object* pResult, [SupportedOSPlatform("windows")] [UnmanagedCallersOnly] [RequiresUnsafe] - private static unsafe void GetDispatchExPropertyFlags(PropertyInfo* pMemberInfo, int* pResult, Exception* pException) + private static unsafe int GetDispatchExPropertyFlags(PropertyInfo* pMemberInfo, Exception* pException) { try { @@ -1566,11 +1566,12 @@ private static unsafe void GetDispatchExPropertyFlags(PropertyInfo* pMemberInfo, result |= DispatchExPropertyCanWrite; } - *pResult = result; + return result; } catch (Exception ex) { *pException = ex; + return 0; } } diff --git a/src/coreclr/vm/comconnectionpoints.cpp b/src/coreclr/vm/comconnectionpoints.cpp index 1179941c66331d..cfc089c2651afd 100644 --- a/src/coreclr/vm/comconnectionpoints.cpp +++ b/src/coreclr/vm/comconnectionpoints.cpp @@ -559,7 +559,7 @@ void ConnectionPoint::InvokeProviderMethod( OBJECTREF pProvider, OBJECTREF pSubs { UnmanagedCallersOnlyCaller invokeConnectionPointProviderMethod(METHOD__STUBHELPERS__INVOKE_CONNECTION_POINT_PROVIDER_METHOD); - // Construct the delegate and invoke the provider method in one helper. + // Using GetMultiCallableAddrOfCode() for the event target since it is stored for future invokes. invokeConnectionPointProviderMethod.InvokeThrowing( &pProvider, pProvMethodDesc->GetSingleCallableAddrOfCode(), diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index f7471d4297b7f8..51fd4dee8af33c 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -1053,7 +1053,7 @@ DEFINE_METHOD(STUBHELPERS, GET_PENDING_EXCEPTION_OBJECT, GetPendingExce DEFINE_METHOD(STUBHELPERS, CREATE_CUSTOM_MARSHALER, CreateCustomMarshaler, SM_IntPtr_Int_IntPtr_RetObj) #ifdef FEATURE_COMINTEROP DEFINE_METHOD(STUBHELPERS, GET_IENUMERATOR_TO_ENUM_VARIANT_MARSHALER, GetIEnumeratorToEnumVariantMarshaler, SM_PtrObj_PtrException_RetVoid) -DEFINE_METHOD(STUBHELPERS, GET_DISPATCH_EX_PROPERTY_FLAGS, GetDispatchExPropertyFlags, SM_PtrPropertyInfo_PtrInt_PtrException_RetVoid) +DEFINE_METHOD(STUBHELPERS, GET_DISPATCH_EX_PROPERTY_FLAGS, GetDispatchExPropertyFlags, SM_PtrPropertyInfo_PtrException_RetInt) DEFINE_METHOD(STUBHELPERS, CALL_ICUSTOM_QUERY_INTERFACE, CallICustomQueryInterface, SM_PtrICustomQueryInterface_PtrGuid_PtrIntPtr_PtrException_RetInt) DEFINE_METHOD(STUBHELPERS, INVOKE_CONNECTION_POINT_PROVIDER_METHOD, InvokeConnectionPointProviderMethod, NoSig) #endif // FEATURE_COMINTEROP diff --git a/src/coreclr/vm/metasig.h b/src/coreclr/vm/metasig.h index 2627f680cf2091..8dac8a5bba99e4 100644 --- a/src/coreclr/vm/metasig.h +++ b/src/coreclr/vm/metasig.h @@ -216,7 +216,7 @@ DEFINE_METASIG(SM(RefByte_UIntPtr_RetVoid, r(b) U, v)) DEFINE_METASIG(SM(PtrVoid_Byte_UInt_RetVoid, P(v) b K, v)) #ifdef FEATURE_COMINTEROP DEFINE_METASIG_T(SM(PtrICustomQueryInterface_PtrGuid_PtrIntPtr_PtrException_RetInt, P(C(ICUSTOM_QUERYINTERFACE)) P(g(GUID)) P(I) P(C(EXCEPTION)), i)) -DEFINE_METASIG_T(SM(PtrPropertyInfo_PtrInt_PtrException_RetVoid, P(C(PROPERTY_INFO)) P(i) P(C(EXCEPTION)), v)) +DEFINE_METASIG_T(SM(PtrPropertyInfo_PtrException_RetInt, P(C(PROPERTY_INFO)) P(C(EXCEPTION)), i)) #endif // FEATURE_COMINTEROP DEFINE_METASIG(SM(IntPtr_RefObj_IntPtr_RetVoid, I r(j) I, v)) DEFINE_METASIG(SM(IntPtr_RefObj_IntPtr_Int_RetVoid, I r(j) I i,v)) diff --git a/src/coreclr/vm/stdinterfaces.cpp b/src/coreclr/vm/stdinterfaces.cpp index 1e386956ab8a36..a7cb4e9ef35235 100644 --- a/src/coreclr/vm/stdinterfaces.cpp +++ b/src/coreclr/vm/stdinterfaces.cpp @@ -1893,9 +1893,8 @@ HRESULT __stdcall DispatchEx_GetMemberProperties ( DispatchExPropertyCanWrite = 2, }; - INT32 propertyFlags = 0; UnmanagedCallersOnlyCaller getDispatchExPropertyFlags(METHOD__STUBHELPERS__GET_DISPATCH_EX_PROPERTY_FLAGS); - getDispatchExPropertyFlags.InvokeThrowing(&MemberInfoObj, &propertyFlags); + INT32 propertyFlags = getDispatchExPropertyFlags.InvokeThrowing_Ret(&MemberInfoObj); bool bCanRead = (propertyFlags & DispatchExPropertyCanRead) != 0; bool bCanWrite = (propertyFlags & DispatchExPropertyCanWrite) != 0;