Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 73 additions & 13 deletions src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,20 @@ internal static void ConvertToNative(object objSrc, IntPtr pDstVariant)
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ObjectMarshaler_ConvertToNative")]
private static partial void ConvertToNative(ObjectHandleOnStack objSrc, IntPtr pDstVariant);

internal static void ConvertToNativeVariantArrayElement(object objSrc, IntPtr pDstVariant)
{
Comment thread
jkoritzinsky marked this conversation as resolved.
// The destination must already hold a previously-marshaled VARIANT (this
// overload only replaces an existing array element in place); objSrc itself
// has no narrower type assumption than ConvertToNative since a VT_VARIANT
// array element can hold any VARIANT-compatible managed type.
Debug.Assert(pDstVariant != IntPtr.Zero);
ConvertToNativeVariantArrayElement(ObjectHandleOnStack.Create(ref objSrc), pDstVariant);
}

[ErrorHandler(typeof(QCallExceptionStatusMarshaller), ErrorLocation.HiddenLastParameter)]
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ObjectMarshaler_ConvertToNativeVariantArrayElement")]
private static partial void ConvertToNativeVariantArrayElement(ObjectHandleOnStack objSrc, IntPtr pDstVariant);

internal static object ConvertToManaged(IntPtr pSrcVariant)
{
object? retObject = null;
Expand Down Expand Up @@ -2036,24 +2050,23 @@ public static unsafe void Free(byte* unmanaged)
}

[SupportedOSPlatform("windows")]
internal sealed class HeterogeneousInterfaceArrayElementMarshaler : IArrayElementMarshaler<object?, HeterogeneousInterfaceArrayElementMarshaler>
internal sealed class TypedClassInterfaceArrayElementMarshaler<TArrayElement, TInterface> : IArrayElementMarshaler<TArrayElement?, TypedClassInterfaceArrayElementMarshaler<TArrayElement, TInterface>>
where TArrayElement : class
where TInterface : class
{
public static unsafe void ConvertToUnmanaged(ref object? managed, byte* unmanaged)
public static unsafe void ConvertToUnmanaged(ref TArrayElement? managed, byte* unmanaged)
{
if (managed is null)
{
*(IntPtr*)unmanaged = IntPtr.Zero;
}
else
{
// Resolve the default COM interface for each element based on its runtime type.
// This matches the heterogeneous path in MarshalInterfaceArrayComToOleHelper
// where GetDefaultInterfaceMTForClass is called per-element.
*(IntPtr*)unmanaged = Marshal.GetComInterfaceForObject(managed, managed.GetType());
*(IntPtr*)unmanaged = Marshal.GetComInterfaceForObject(managed, typeof(TInterface));
}
}

public static unsafe void ConvertToManaged(ref object? managed, byte* unmanaged)
public static unsafe void ConvertToManaged(ref TArrayElement? managed, byte* unmanaged)
{
IntPtr pUnk = *(IntPtr*)unmanaged;
if (pUnk == IntPtr.Zero)
Expand All @@ -2062,7 +2075,7 @@ public static unsafe void ConvertToManaged(ref object? managed, byte* unmanaged)
}
else
{
managed = Marshal.GetObjectForIUnknown(pUnk);
managed = (TArrayElement)Marshal.GetObjectForIUnknown(pUnk);
Comment thread
jkoritzinsky marked this conversation as resolved.
}
}

Expand All @@ -2075,7 +2088,53 @@ public static unsafe void Free(byte* unmanaged)
}
}

static unsafe nuint IArrayElementMarshaler<object?, HeterogeneousInterfaceArrayElementMarshaler>.UnmanagedSize => (nuint)sizeof(IntPtr);
static unsafe nuint IArrayElementMarshaler<TArrayElement?, TypedClassInterfaceArrayElementMarshaler<TArrayElement, TInterface>>.UnmanagedSize => (nuint)sizeof(IntPtr);
}

[SupportedOSPlatform("windows")]
internal sealed class TypedClassArrayElementMarshaler<TArrayElement, TIsDispatch> : IArrayElementMarshaler<TArrayElement?, TypedClassArrayElementMarshaler<TArrayElement, TIsDispatch>>
where TArrayElement : class
where TIsDispatch : IMarshalerOption
{
public static unsafe void ConvertToUnmanaged(ref TArrayElement? managed, byte* unmanaged)
{
if (managed is null)
{
*(IntPtr*)unmanaged = IntPtr.Zero;
}
else if (TIsDispatch.Enabled)
{
*(IntPtr*)unmanaged = Marshal.GetIDispatchForObject(managed);
}
else
{
*(IntPtr*)unmanaged = Marshal.GetIUnknownForObject(managed);
}
}

public static unsafe void ConvertToManaged(ref TArrayElement? managed, byte* unmanaged)
{
IntPtr pUnk = *(IntPtr*)unmanaged;
if (pUnk == IntPtr.Zero)
{
managed = null;
}
else
{
managed = (TArrayElement)Marshal.GetObjectForIUnknown(pUnk);
}
}

public static unsafe void Free(byte* unmanaged)
{
IntPtr pUnk = *(IntPtr*)unmanaged;
if (pUnk != IntPtr.Zero)
{
Marshal.Release(pUnk);
}
}

static unsafe nuint IArrayElementMarshaler<TArrayElement?, TypedClassArrayElementMarshaler<TArrayElement, TIsDispatch>>.UnmanagedSize => (nuint)sizeof(IntPtr);
}

internal sealed class VariantArrayElementMarshaler<TNativeDataValid> : IArrayElementMarshaler<object?, VariantArrayElementMarshaler<TNativeDataValid>>
Expand All @@ -2088,11 +2147,12 @@ public static unsafe void ConvertToUnmanaged(ref object? managed, byte* unmanage
// Native buffer is uninitialized — zero it so ConvertToNative
// doesn't see garbage VT_BYREF bits.
*(ComVariant*)unmanaged = default;
ObjectMarshaler.ConvertToNative(managed!, (IntPtr)unmanaged);
}
else
{
ObjectMarshaler.ConvertToNativeVariantArrayElement(managed!, (IntPtr)unmanaged);
}
// When TNativeDataValid is enabled, the existing VARIANT may have
// VT_BYREF set. ConvertToNative checks vt & VT_BYREF and calls
// MarshalOleRefVariantForObject to write through the byref pointer.
ObjectMarshaler.ConvertToNative(managed!, (IntPtr)unmanaged);
}

public static unsafe void ConvertToManaged(ref object? managed, byte* unmanaged)
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/vm/corelib.h
Original file line number Diff line number Diff line change
Expand Up @@ -1270,7 +1270,8 @@ DEFINE_CLASS(BSTR_ARRAY_ELEMENT_MARSHALER, StubHelpers, BSTRArrayElementMar
DEFINE_CLASS(CURRENCY_ARRAY_ELEMENT_MARSHALER, StubHelpers, CurrencyArrayElementMarshaler)
DEFINE_CLASS(INTERFACE_ARRAY_ELEMENT_MARSHALER, StubHelpers, InterfaceArrayElementMarshaler`1)
DEFINE_CLASS(TYPED_INTERFACE_ARRAY_ELEMENT_MARSHALER, StubHelpers, TypedInterfaceArrayElementMarshaler`1)
DEFINE_CLASS(HETEROGENEOUS_INTERFACE_ARRAY_ELEMENT_MARSHALER, StubHelpers, HeterogeneousInterfaceArrayElementMarshaler)
DEFINE_CLASS(TYPED_CLASS_INTERFACE_ARRAY_ELEMENT_MARSHALER, StubHelpers, TypedClassInterfaceArrayElementMarshaler`2)
DEFINE_CLASS(TYPED_CLASS_ARRAY_ELEMENT_MARSHALER, StubHelpers, TypedClassArrayElementMarshaler`2)
DEFINE_CLASS(VARIANT_ARRAY_ELEMENT_MARSHALER, StubHelpers, VariantArrayElementMarshaler`1)
#endif // FEATURE_COMINTEROP
DEFINE_CLASS(MARSHALER_OPTION_ENABLED, StubHelpers, IMarshalerOption+EnabledOption)
Expand Down
8 changes: 4 additions & 4 deletions src/coreclr/vm/dispparammarshaler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,8 @@ DispParamArrayMarshaler::DispParamArrayMarshaler(VARTYPE ElementVT, MethodTable

if (ElementVT != VT_EMPTY && pElementMT != NULL)
{
m_pConvertContentsToManagedCode = GetInstantiatedSafeArrayMethod(METHOD__STUBHELPERS__CONVERT_ARRAY_CONTENTS_TO_MANAGED, ElementVT, pElementMT, FALSE)->GetMultiCallableAddrOfCode();
m_pConvertContentsToUnmanagedCode = GetInstantiatedSafeArrayMethod(METHOD__STUBHELPERS__CONVERT_ARRAY_CONTENTS_TO_UNMANAGED, ElementVT, pElementMT, FALSE)->GetMultiCallableAddrOfCode();
m_pConvertContentsToManagedCode = GetInstantiatedSafeArrayMethod(METHOD__STUBHELPERS__CONVERT_ARRAY_CONTENTS_TO_MANAGED, ElementVT, pElementMT)->GetMultiCallableAddrOfCode();
m_pConvertContentsToUnmanagedCode = GetInstantiatedSafeArrayMethod(METHOD__STUBHELPERS__CONVERT_ARRAY_CONTENTS_TO_UNMANAGED, ElementVT, pElementMT)->GetMultiCallableAddrOfCode();
}
}

Expand Down Expand Up @@ -270,7 +270,7 @@ void DispParamArrayMarshaler::MarshalNativeToManaged(VARIANT *pSrcVar, OBJECTREF
if (pConvertCode == NULL)
{
GCX_PREEMP();
pConvertCode = GetInstantiatedSafeArrayMethod(METHOD__STUBHELPERS__CONVERT_ARRAY_CONTENTS_TO_MANAGED, vt, pElemMT, FALSE)->GetMultiCallableAddrOfCode();
pConvertCode = GetInstantiatedSafeArrayMethod(METHOD__STUBHELPERS__CONVERT_ARRAY_CONTENTS_TO_MANAGED, vt, pElemMT)->GetMultiCallableAddrOfCode();
}
OleVariant::MarshalArrayRefForSafeArray(pSafeArray, (BASEARRAYREF*)pDestObj, vt, pElemMT, pConvertCode);
}
Expand Down Expand Up @@ -315,7 +315,7 @@ void DispParamArrayMarshaler::MarshalManagedToNative(OBJECTREF *pSrcObj, VARIANT
if (pConvertCode == NULL)
{
GCX_PREEMP();
pConvertCode = GetInstantiatedSafeArrayMethod(METHOD__STUBHELPERS__CONVERT_ARRAY_CONTENTS_TO_UNMANAGED, vt, pElemMT, FALSE)->GetMultiCallableAddrOfCode();
pConvertCode = GetInstantiatedSafeArrayMethod(METHOD__STUBHELPERS__CONVERT_ARRAY_CONTENTS_TO_UNMANAGED, vt, pElemMT)->GetMultiCallableAddrOfCode();
}
OleVariant::MarshalSafeArrayForArrayRef((BASEARRAYREF*)pSrcObj, pSafeArray, vt, pElemMT, pConvertCode);
}
Expand Down
16 changes: 10 additions & 6 deletions src/coreclr/vm/ilmarshalers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4289,15 +4289,19 @@ namespace
MethodTable* pDefaultItfMT = GetDefaultInterfaceMTForClass(arrayElementTypeHandle.AsMethodTable(), &bDispatch);
if (pDefaultItfMT != NULL)
{
TypeHandle thElement(arrayElementTypeHandle);
TypeHandle thItf(pDefaultItfMT);
*pElementType = thItf;
*ppMarshalerMT = TypeHandle(CoreLibBinder::GetClass(CLASS__TYPED_INTERFACE_ARRAY_ELEMENT_MARSHALER)).Instantiate(Instantiation(&thItf, 1)).AsMethodTable();
TypeHandle thArgs[2] = { thElement, thItf };
*pElementType = thElement;
*ppMarshalerMT = TypeHandle(CoreLibBinder::GetClass(CLASS__TYPED_CLASS_INTERFACE_ARRAY_ELEMENT_MARSHALER)).Instantiate(Instantiation(thArgs, 2)).AsMethodTable();
}
else
{
TypeHandle thDispatch(bDispatch ? pEnabledMT : pDisabledMT);
*pElementType = TypeHandle(g_pObjectClass);
*ppMarshalerMT = TypeHandle(CoreLibBinder::GetClass(CLASS__INTERFACE_ARRAY_ELEMENT_MARSHALER)).Instantiate(Instantiation(&thDispatch, 1)).AsMethodTable();
TypeHandle thElement(arrayElementTypeHandle);
TypeHandle thArgs[2] = { thElement, thDispatch };
*pElementType = thElement;
*ppMarshalerMT = TypeHandle(CoreLibBinder::GetClass(CLASS__TYPED_CLASS_ARRAY_ELEMENT_MARSHALER)).Instantiate(Instantiation(thArgs, 2)).AsMethodTable();
}
}
else
Expand Down Expand Up @@ -4739,12 +4743,12 @@ void ILSafeArrayMarshaler::EmitCreateMngdMarshaler(ILCodeStream* pslILEmit)
BOOL bNativeDataValid = !!(fStatic & MngdSafeArrayMarshaler::SCSF_NativeDataValid);
MethodDesc* pConvertToNativeMD = GetInstantiatedSafeArrayMethod(
METHOD__STUBHELPERS__CONVERT_ARRAY_CONTENTS_TO_UNMANAGED,
mops.elementType, pElementMT, FALSE, bNativeDataValid);
mops.elementType, pElementMT, bNativeDataValid);
pslILEmit->EmitLDFTN(pslILEmit->GetToken(pConvertToNativeMD));

MethodDesc* pConvertToManagedMD = GetInstantiatedSafeArrayMethod(
METHOD__STUBHELPERS__CONVERT_ARRAY_CONTENTS_TO_MANAGED,
mops.elementType, pElementMT, FALSE);
mops.elementType, pElementMT);
pslILEmit->EmitLDFTN(pslILEmit->GetToken(pConvertToManagedMD));

pslILEmit->EmitCALL(METHOD__MNGD_SAFE_ARRAY_MARSHALER__CREATE_MARSHALER, 6, 0);
Expand Down
8 changes: 4 additions & 4 deletions src/coreclr/vm/interoputil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1952,9 +1952,9 @@ HRESULT TryGetDefaultInterfaceForClass(TypeHandle hndClass, TypeHandle *pHndDefC
return hr;
}

// Returns the default interface for a class if it's an explicit interface or the AutoDual
// class interface. Sets *pbDispatch otherwise. This is the logic used by array marshaling
// in code:OleVariant::MarshalInterfaceArrayComToOleHelper.
// Returns the default interface for a class if it's an explicit interface.
// Sets *pbDispatch for a generated class interface; a class MethodTable cannot
// be passed to the managed typed interface array marshaler.
MethodTable *GetDefaultInterfaceMTForClass(MethodTable *pMT, BOOL *pbDispatch)
{
CONTRACTL
Expand All @@ -1974,7 +1974,6 @@ MethodTable *GetDefaultInterfaceMTForClass(MethodTable *pMT, BOOL *pbDispatch)
switch (DefItfType)
{
case DefaultInterfaceType_Explicit:
case DefaultInterfaceType_AutoDual:
{
return hndDefItfClass.GetMethodTable();
}
Expand All @@ -1986,6 +1985,7 @@ MethodTable *GetDefaultInterfaceMTForClass(MethodTable *pMT, BOOL *pbDispatch)
return NULL;
}

case DefaultInterfaceType_AutoDual:
case DefaultInterfaceType_AutoDispatch:
{
*pbDispatch = TRUE;
Expand Down
Loading
Loading