* Block route trip of function pointer as Delegate field.
Add tests for scenario.
* Update MarshalStructAsParamDLL.cpp
THROWS;
GC_TRIGGERS;
MODE_COOPERATIVE;
+ PRECONDITION(pCallback != NULL);
+ PRECONDITION(pMT != NULL);
}
CONTRACTL_END;
- if (!pCallback)
- {
- return NULL;
- }
-
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// Check if this callback was originally a managed method passed out to unmanaged code.
//
return pDelegate;
}
+ // Validate the MethodTable is a delegate type
+ if (!pMT->IsDelegate())
+ COMPlusThrow(kArgumentException);
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// This is an unmanaged callsite. We need to create a new delegate.
EmitLoadNativeValue(pslILEmit);
pslILEmit->EmitLDTOKEN(pslILEmit->GetToken(m_pargs->m_pMT));
pslILEmit->EmitCALL(METHOD__TYPE__GET_TYPE_FROM_HANDLE, 1, 1); // Type System.Type.GetTypeFromHandle(RuntimeTypeHandle handle)
- pslILEmit->EmitCALL(METHOD__MARSHAL__GET_DELEGATE_FOR_FUNCTION_POINTER, 2, 1); // Delegate System.Marshal.GetDelegateForFunctionPointer(IntPtr p, Type t)
- EmitStoreManagedValue(pslILEmit);
+ // COMPAT: There is a subtle difference between argument and field marshaling with Delegate types.
+ // During field marshaling, the plain Delegate type can be used even though that type doesn't
+ // represent a concrete type. Argument marshaling doesn't permit this so we use the public
+ // API which will validate that Delegate and MulticastDelegate aren't directly used.
if (IsFieldMarshal(m_dwMarshalFlags))
{
+ // Delegate System.Marshal.GetDelegateForFunctionPointerInternal(IntPtr p, Type t)
+ pslILEmit->EmitCALL(METHOD__MARSHAL__GET_DELEGATE_FOR_FUNCTION_POINTER_INTERNAL, 2, 1);
+ EmitStoreManagedValue(pslILEmit);
+
// Field marshalling of delegates supports marshalling back null from native code.
// Parameter and return value marshalling does not.
ILCodeLabel* pFinishedLabel = pslILEmit->NewCodeLabel();
}
else
{
+ // Delegate System.Marshal.GetDelegateForFunctionPointer(IntPtr p, Type t)
+ pslILEmit->EmitCALL(METHOD__MARSHAL__GET_DELEGATE_FOR_FUNCTION_POINTER, 2, 1);
+ EmitStoreManagedValue(pslILEmit);
pslILEmit->EmitLabel(pNullLabel);
}
#ifdef FEATURE_COMINTEROP
DEFINE_METHOD(MARSHAL, GET_HR_FOR_EXCEPTION, GetHRForException, SM_Exception_RetInt)
#endif // FEATURE_COMINTEROP
-DEFINE_METHOD(MARSHAL, GET_FUNCTION_POINTER_FOR_DELEGATE, GetFunctionPointerForDelegate, SM_Delegate_RetIntPtr)
-DEFINE_METHOD(MARSHAL, GET_DELEGATE_FOR_FUNCTION_POINTER, GetDelegateForFunctionPointer, SM_IntPtr_Type_RetDelegate)
+DEFINE_METHOD(MARSHAL, GET_FUNCTION_POINTER_FOR_DELEGATE, GetFunctionPointerForDelegate, SM_Delegate_RetIntPtr)
+DEFINE_METHOD(MARSHAL, GET_DELEGATE_FOR_FUNCTION_POINTER, GetDelegateForFunctionPointer, SM_IntPtr_Type_RetDelegate)
+DEFINE_METHOD(MARSHAL, GET_DELEGATE_FOR_FUNCTION_POINTER_INTERNAL, GetDelegateForFunctionPointerInternal, SM_IntPtr_Type_RetDelegate)
+
DEFINE_METHOD(MARSHAL, ALLOC_CO_TASK_MEM, AllocCoTaskMem, SM_Int_RetIntPtr)
DEFINE_METHOD(MARSHAL, FREE_CO_TASK_MEM, FreeCoTaskMem, SM_IntPtr_RetVoid)
DEFINE_FIELD(MARSHAL, SYSTEM_MAX_DBCS_CHAR_SIZE, SystemMaxDBCSCharSize)
RunMarshalSeqStructAsParamByValInOut();
RunMarshalSeqStructAsParamByRefInOut();
RunMarshalSeqStructAsReturn();
-
+ RunMarshalSeqStructDelegateField();
+
if (failures > 0)
{
Console.WriteLine("\nTEST FAILED!");
[DllImport("MarshalStructAsParam")]
static extern MultipleBool GetBools(bool b1, bool b2);
+ [DllImport("MarshalStructAsParam")]
+ static extern IntPtr GetNativeIntIntFunction();
+
+ [DllImport("MarshalStructAsParam")]
+ static extern void MarshalStructAsParam_DelegateFieldMarshaling(ref DelegateFieldMarshaling dfm);
+
#region Marshal struct method in PInvoke
[SecuritySafeCritical]
unsafe private static void MarshalStructAsParam_AsSeqByVal(StructID id)
Console.WriteLine("Structure of two bools marshalled to BOOLs returned from native to managed failed");
}
}
-}
+ private static void RunMarshalSeqStructDelegateField()
+ {
+ Console.WriteLine($"\nRunning {nameof(Managed.RunMarshalSeqStructDelegateField)}...");
+
+ var dfm = new DelegateFieldMarshaling();
+ try
+ {
+ MarshalStructAsParam_DelegateFieldMarshaling(ref dfm);
+ }
+ catch
+ {
+ Console.WriteLine($"Marshaling null function pointer as ${nameof(Delegate)} field should succeed");
+ failures++;
+ }
-
+ dfm.IntIntFunction = new IntIntDelegate(IntIntImpl);
+ try
+ {
+ MarshalStructAsParam_DelegateFieldMarshaling(ref dfm);
+ }
+ catch
+ {
+ Console.WriteLine($"Marshaling function pointer as ${nameof(Delegate)} field should succeed");
+ failures++;
+ }
+
+ dfm.IntIntFunction = Marshal.GetDelegateForFunctionPointer<IntIntDelegate>(GetNativeIntIntFunction());
+ try
+ {
+ MarshalStructAsParam_DelegateFieldMarshaling(ref dfm);
+ Console.WriteLine("Marshaling native function pointer should fail");
+ failures++;
+ }
+ catch (ArgumentException)
+ {
+ // Should be ArgumentException for native function pointer round trip.
+ }
+ catch
+ {
+ Console.WriteLine($"Marshaling native function pointer should throw {nameof(ArgumentException)}");
+ failures++;
+ }
+
+ int IntIntImpl(int a)
+ {
+ return a;
+ }
+ }
+}
{
return {b1, b2};
}
+
+using IntIntDelegate = int (STDMETHODCALLTYPE*)(int a);
+
+struct DelegateFieldMarshaling
+{
+ IntIntDelegate IntIntFunction;
+};
+
+namespace
+{
+ int STDMETHODCALLTYPE IntIntImpl(int a)
+ {
+ return a;
+ }
+}
+
+extern "C" DLL_EXPORT void* STDMETHODCALLTYPE GetNativeIntIntFunction()
+{
+ return (void*)&IntIntImpl;
+}
+
+extern "C" DLL_EXPORT void STDMETHODCALLTYPE MarshalStructAsParam_DelegateFieldMarshaling(DelegateFieldMarshaling* d)
+{
+ // Nothing to do
+}
public char[] arr;
public float f;
}
+
+delegate int IntIntDelegate(int a);
+
+[StructLayout(LayoutKind.Sequential)]
+public struct DelegateFieldMarshaling
+{
+ public Delegate IntIntFunction;
+}