summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Koritzinsky <jkoritzinsky@gmail.com>2019-01-11 11:12:01 -0800
committerGitHub <noreply@github.com>2019-01-11 11:12:01 -0800
commit55b0d2790c75efe2b4a29a561127599668658e05 (patch)
treedf27a20d05bfb0429987c7424c2e47531fc78819
parentca68a16fcb31162990fa9af9910e852a6cb66782 (diff)
downloadcoreclr-55b0d2790c75efe2b4a29a561127599668658e05.tar.gz
coreclr-55b0d2790c75efe2b4a29a561127599668658e05.tar.bz2
coreclr-55b0d2790c75efe2b4a29a561127599668658e05.zip
Enable returning more complex structures via PInvoke returns. (#21470)
* Add test verifying behavior in dotnet/coreclr#19676. * Clean up test code. * Test what happens if we enable returning structures by value. * Use braced initializer. * Update Decimal tests to expect that returning a decimal by LPStruct or Currency works. * Change handle-in-struct marshalling to expect a NotSupportedException thrown at marshal time instead of expecting a MarshalDirectiveException at signature time. * Update Decimal Reverse-PInvoke tests. * Disable some previously disabled return marshalling types and add a nice comment block explaining why they're disabled. * Enable marshalling DateTime return values and add a test. * Rename IsUnuspportedValueTypeReturn * Add return test for ArrayWithOffset * Remove extraneous P/Invoke. * Fix spelling. * Add test for successfully returning a struct that has one field of a type that is return-type blocked. * Add explicit struct return test. * Clean up tests. * Fix grammer. * Add test for struct whose managed layout doesn't require a stdcall return buffer but whose native layout does. * Add test verifying HandleRef behavior. * Clean up IsUnsupportedTypedefReturn per PR feedback.
-rw-r--r--src/vm/dllimport.cpp45
-rw-r--r--src/vm/mlinfo.cpp28
-rw-r--r--src/vm/mlinfo.h2
-rw-r--r--tests/src/Interop/PInvoke/Array/MarshalArrayAsField/AsByValArray/AsByValArrayTest.cs6
-rw-r--r--tests/src/Interop/PInvoke/Array/MarshalArrayAsField/LPArrayNative/MarshalArrayByValArrayNative.cpp7
-rw-r--r--tests/src/Interop/PInvoke/ArrayWithOffset/ArrayWithOffsetNative.cpp5
-rw-r--r--tests/src/Interop/PInvoke/ArrayWithOffset/ArrayWithOffsetTest.cs1
-rw-r--r--tests/src/Interop/PInvoke/ArrayWithOffset/PInvokeDefs.cs3
-rw-r--r--tests/src/Interop/PInvoke/CriticalHandles/StructTest/StructTest.cs2
-rw-r--r--tests/src/Interop/PInvoke/DateTime/DateTimeTest.cs6
-rw-r--r--tests/src/Interop/PInvoke/DateTime/NativeDateTime.cpp5
-rw-r--r--tests/src/Interop/PInvoke/Decimal/PInvoke/DecNative.cpp4
-rw-r--r--tests/src/Interop/PInvoke/Decimal/PInvoke/DecimalTest.cs38
-rw-r--r--tests/src/Interop/PInvoke/Decimal/ReversePInvoke/DecimalTest.cs2
-rw-r--r--tests/src/Interop/PInvoke/Miscellaneous/HandleRef/HandleRefNative.cpp4
-rw-r--r--tests/src/Interop/PInvoke/Miscellaneous/HandleRef/HandleRefTest.cs6
-rw-r--r--tests/src/Interop/PInvoke/SafeHandles/Misc.Unsupported/MiscUnsupportedTest.cs4
-rw-r--r--tests/src/Interop/PInvoke/Varargs/VarargsNative.cpp2
-rw-r--r--tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutExp.cs17
-rw-r--r--tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutSeq.cs39
-rw-r--r--tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp43
-rw-r--r--tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h38
-rw-r--r--tests/src/Interop/StructMarshalling/PInvoke/Struct.cs67
23 files changed, 304 insertions, 70 deletions
diff --git a/src/vm/dllimport.cpp b/src/vm/dllimport.cpp
index 2ce100b4b9..8c86882006 100644
--- a/src/vm/dllimport.cpp
+++ b/src/vm/dllimport.cpp
@@ -3706,31 +3706,38 @@ static MarshalInfo::MarshalType DoMarshalReturnValue(MetaSig& msig,
else
#endif // FEATURE_COMINTEROP
{
- if (marshalType > MarshalInfo::MARSHAL_TYPE_DOUBLE && IsUnsupportedValueTypeReturn(msig))
- {
- if (marshalType == MarshalInfo::MARSHAL_TYPE_BLITTABLEVALUECLASS
- || marshalType == MarshalInfo::MARSHAL_TYPE_GUID
- || marshalType == MarshalInfo::MARSHAL_TYPE_DECIMAL
+ if (marshalType == MarshalInfo::MARSHAL_TYPE_BLITTABLEVALUECLASS
+ || marshalType == MarshalInfo::MARSHAL_TYPE_VALUECLASS
+ || marshalType == MarshalInfo::MARSHAL_TYPE_GUID
+ || marshalType == MarshalInfo::MARSHAL_TYPE_DECIMAL
#ifdef FEATURE_COMINTEROP
- || marshalType == MarshalInfo::MARSHAL_TYPE_DATETIME
+ || marshalType == MarshalInfo::MARSHAL_TYPE_DATETIME
#endif // FEATURE_COMINTEROP
- )
- {
- if (SF_IsHRESULTSwapping(dwStubFlags))
- {
- // V1 restriction: we could implement this but it's late in the game to do so.
- COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_UNSUPPORTED_SIG);
- }
- }
- else if (marshalType == MarshalInfo::MARSHAL_TYPE_HANDLEREF)
- {
- COMPlusThrow(kMarshalDirectiveException, IDS_EE_BADMARSHAL_HANDLEREFRESTRICTION);
- }
- else
+ )
+ {
+ if (SF_IsHRESULTSwapping(dwStubFlags))
{
+ // V1 restriction: we could implement this but it's late in the game to do so.
COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_UNSUPPORTED_SIG);
}
}
+ else if (marshalType == MarshalInfo::MARSHAL_TYPE_CURRENCY
+ || marshalType == MarshalInfo::MARSHAL_TYPE_ARRAYWITHOFFSET
+ || marshalType == MarshalInfo::MARSHAL_TYPE_ARGITERATOR
+#ifdef FEATURE_COMINTEROP
+ || marshalType == MarshalInfo::MARSHAL_TYPE_OLECOLOR
+#endif // FEATURE_COMINTEROP
+ )
+ {
+ // Each of these types are non-blittable and according to its managed size should be returned in a return buffer on x86 in stdcall.
+ // However, its native size is small enough to be returned by-value.
+ // We don't know the native type representation early enough to get this correct, so we throw an exception here.
+ COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_UNSUPPORTED_SIG);
+ }
+ else if (IsUnsupportedTypedrefReturn(msig))
+ {
+ COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_UNSUPPORTED_SIG);
+ }
#ifdef FEATURE_COMINTEROP
if (marshalType == MarshalInfo::MARSHAL_TYPE_OBJECT && !SF_IsHRESULTSwapping(dwStubFlags))
diff --git a/src/vm/mlinfo.cpp b/src/vm/mlinfo.cpp
index d220e5dd6d..cc9760aed6 100644
--- a/src/vm/mlinfo.cpp
+++ b/src/vm/mlinfo.cpp
@@ -5129,33 +5129,11 @@ LExit:;
RETURN;
}
-bool IsUnsupportedValueTypeReturn(MetaSig& msig)
+bool IsUnsupportedTypedrefReturn(MetaSig& msig)
{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END
-
- CorElementType type = msig.GetReturnTypeNormalized();
-
- if (type == ELEMENT_TYPE_VALUETYPE || type == ELEMENT_TYPE_TYPEDBYREF)
- {
-#ifdef _TARGET_X86_
- // On x86, the internal CorElementType for value types is normalized by the type loader
- // (see calls to ComputeInternalCorElementTypeForValueType in MethodTableBuilder).
- // We don't need to redo the normalization here.
- return true;
-#else
- TypeHandle th = msig.GetRetTypeHandleThrowing();
-
- return EEClass::ComputeInternalCorElementTypeForValueType(th.GetMethodTable()) == ELEMENT_TYPE_VALUETYPE;
-#endif // _TARGET_X86_
- }
+ WRAPPER_NO_CONTRACT;
- return false;
+ return msig.GetReturnTypeNormalized() == ELEMENT_TYPE_TYPEDBYREF;
}
#ifndef CROSSGEN_COMPILE
diff --git a/src/vm/mlinfo.h b/src/vm/mlinfo.h
index 0ac146c3b7..91afec99b0 100644
--- a/src/vm/mlinfo.h
+++ b/src/vm/mlinfo.h
@@ -888,7 +888,7 @@ protected:
VOID ThrowInteropParamException(UINT resID, UINT paramIdx);
VOID CollateParamTokens(IMDInternalImport *pInternalImport, mdMethodDef md, ULONG numargs, mdParamDef *aParams);
-bool IsUnsupportedValueTypeReturn(MetaSig& msig);
+bool IsUnsupportedTypedrefReturn(MetaSig& msig);
void FindCopyCtor(Module *pModule, MethodTable *pMT, MethodDesc **pMDOut);
void FindDtor(Module *pModule, MethodTable *pMT, MethodDesc **pMDOut);
diff --git a/tests/src/Interop/PInvoke/Array/MarshalArrayAsField/AsByValArray/AsByValArrayTest.cs b/tests/src/Interop/PInvoke/Array/MarshalArrayAsField/AsByValArray/AsByValArrayTest.cs
index a047c7d1c1..f72db4db09 100644
--- a/tests/src/Interop/PInvoke/Array/MarshalArrayAsField/AsByValArray/AsByValArrayTest.cs
+++ b/tests/src/Interop/PInvoke/Array/MarshalArrayAsField/AsByValArray/AsByValArrayTest.cs
@@ -649,6 +649,9 @@ class Test
//for RunTest5
//get struct on C++ side as sequential class
[DllImport("MarshalArrayByValArrayNative", CallingConvention = CallingConvention.Cdecl)]
+ static extern S_INTArray_Seq S_INTArray_Ret_ByValue();
+
+ [DllImport("MarshalArrayByValArrayNative", CallingConvention = CallingConvention.Cdecl)]
static extern C_INTArray_Seq S_INTArray_Ret();
[DllImport("MarshalArrayByValArrayNative", CallingConvention = CallingConvention.Cdecl)]
static extern C_UINTArray_Seq S_UINTArray_Ret();
@@ -1081,6 +1084,9 @@ class Test
static void RunTest5(string report)
{
Console.WriteLine(report);
+
+ S_INTArray_Seq retval = S_INTArray_Ret_ByValue();
+ Assert.IsTrue(Equals(InitArray<int>(ARRAY_SIZE), retval.arr));
C_INTArray_Seq retval1 = S_INTArray_Ret();
Assert.IsTrue(Equals(InitArray<int>(ARRAY_SIZE), retval1.arr));
diff --git a/tests/src/Interop/PInvoke/Array/MarshalArrayAsField/LPArrayNative/MarshalArrayByValArrayNative.cpp b/tests/src/Interop/PInvoke/Array/MarshalArrayAsField/LPArrayNative/MarshalArrayByValArrayNative.cpp
index edbdf6f5b7..a0fcb5a8ec 100644
--- a/tests/src/Interop/PInvoke/Array/MarshalArrayAsField/LPArrayNative/MarshalArrayByValArrayNative.cpp
+++ b/tests/src/Interop/PInvoke/Array/MarshalArrayAsField/LPArrayNative/MarshalArrayByValArrayNative.cpp
@@ -494,6 +494,13 @@ extern "C" DLL_EXPORT BOOL __cdecl TakeStructArrayExpClassByVal( S_StructArray *
/*----------------------------------------------------------------------------
return a struct including a C array
----------------------------------------------------------------------------*/
+extern "C" DLL_EXPORT S_INTArray __cdecl S_INTArray_Ret_ByValue()
+{
+ INIT_EXPECTED_STRUCT( S_INTArray, ARRAY_SIZE, INT );
+
+ return *expected;
+}
+
extern "C" DLL_EXPORT S_INTArray* __cdecl S_INTArray_Ret()
{
INIT_EXPECTED_STRUCT( S_INTArray, ARRAY_SIZE, INT );
diff --git a/tests/src/Interop/PInvoke/ArrayWithOffset/ArrayWithOffsetNative.cpp b/tests/src/Interop/PInvoke/ArrayWithOffset/ArrayWithOffsetNative.cpp
index 44d6e83795..4701574ac7 100644
--- a/tests/src/Interop/PInvoke/ArrayWithOffset/ArrayWithOffsetNative.cpp
+++ b/tests/src/Interop/PInvoke/ArrayWithOffset/ArrayWithOffsetNative.cpp
@@ -17,3 +17,8 @@ extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE Marshal_Invalid(void* invalid)
{
return FALSE;
}
+
+extern "C" DLL_EXPORT void* STDMETHODCALLTYPE Marshal_Invalid_Return()
+{
+ return nullptr;
+}
diff --git a/tests/src/Interop/PInvoke/ArrayWithOffset/ArrayWithOffsetTest.cs b/tests/src/Interop/PInvoke/ArrayWithOffset/ArrayWithOffsetTest.cs
index 9f3d91ad9e..66865174c8 100644
--- a/tests/src/Interop/PInvoke/ArrayWithOffset/ArrayWithOffsetTest.cs
+++ b/tests/src/Interop/PInvoke/ArrayWithOffset/ArrayWithOffsetTest.cs
@@ -42,6 +42,7 @@ unsafe class ArrayWithOffsetTest
Assert.Throws<MarshalDirectiveException>(() => ArrayWithOffsetNative.Marshal_Invalid(arrayWithOffset));
Assert.Throws<MarshalDirectiveException>(() => ArrayWithOffsetNative.Marshal_Invalid(ref arrayWithOffset));
+ Assert.Throws<MarshalDirectiveException>(() => ArrayWithOffsetNative.Marshal_Invalid_Return());
}
catch (Exception e)
{
diff --git a/tests/src/Interop/PInvoke/ArrayWithOffset/PInvokeDefs.cs b/tests/src/Interop/PInvoke/ArrayWithOffset/PInvokeDefs.cs
index cefe6fc51a..57f47f4d40 100644
--- a/tests/src/Interop/PInvoke/ArrayWithOffset/PInvokeDefs.cs
+++ b/tests/src/Interop/PInvoke/ArrayWithOffset/PInvokeDefs.cs
@@ -16,4 +16,7 @@ unsafe class ArrayWithOffsetNative
[DllImport(nameof(ArrayWithOffsetNative))]
public static extern bool Marshal_Invalid(ref ArrayWithOffset array);
+
+ [DllImport(nameof(ArrayWithOffsetNative))]
+ public static extern ArrayWithOffset Marshal_Invalid_Return();
}
diff --git a/tests/src/Interop/PInvoke/CriticalHandles/StructTest/StructTest.cs b/tests/src/Interop/PInvoke/CriticalHandles/StructTest/StructTest.cs
index abd2c3f8c9..9c774fca7f 100644
--- a/tests/src/Interop/PInvoke/CriticalHandles/StructTest/StructTest.cs
+++ b/tests/src/Interop/PInvoke/CriticalHandles/StructTest/StructTest.cs
@@ -87,7 +87,7 @@ public class CriticalHandleStructTest
public static void Ret()
{
IntPtr handleValue = MyCriticalHandle.GetUniqueHandle();
- Assert.Throws<MarshalDirectiveException>(() => Native.Ret(handleValue));
+ Assert.Throws<NotSupportedException>(() => Native.Ret(handleValue));
}
public static void Out()
diff --git a/tests/src/Interop/PInvoke/DateTime/DateTimeTest.cs b/tests/src/Interop/PInvoke/DateTime/DateTimeTest.cs
index 897af36602..cc662b96e1 100644
--- a/tests/src/Interop/PInvoke/DateTime/DateTimeTest.cs
+++ b/tests/src/Interop/PInvoke/DateTime/DateTimeTest.cs
@@ -46,6 +46,9 @@ class DatetimeTest
[DllImport("NativeDateTime.dll", CallingConvention = CallingConvention.StdCall)]
private static extern bool Marshal_Out_stdcall([Out][MarshalAs(UnmanagedType.Struct)] out DateTime t);
+ [DllImport("NativeDateTime.dll")]
+ private static extern DateTime PassThroughDate(DateTime d);
+
[DllImport("NativeDateTime.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern bool MarshalSeqStruct_InOut_cdecl([In, Out][MarshalAs(UnmanagedType.Struct)] ref Stru_Seq_DateAsStructAsFld t);
@@ -125,6 +128,9 @@ class DatetimeTest
Assert.IsTrue(MarshalExpStruct_InOut_cdecl(ref StDate2), "MarshalExpStruct_InOut_cdecl : Native side check failed");
Assert.AreEqual(ExpectedRetdate, StDate2.dt, "MarshalExpStruct_InOut_cdecl : Returned date is wrong");
+ DateTime date3 = new DateTime(2008, 7, 4);
+ Assert.AreEqual(date3, PassThroughDate(date3));
+
#endregion
#region DelegatePInvoke
diff --git a/tests/src/Interop/PInvoke/DateTime/NativeDateTime.cpp b/tests/src/Interop/PInvoke/DateTime/NativeDateTime.cpp
index 3d96241028..35a9ecc590 100644
--- a/tests/src/Interop/PInvoke/DateTime/NativeDateTime.cpp
+++ b/tests/src/Interop/PInvoke/DateTime/NativeDateTime.cpp
@@ -225,3 +225,8 @@ extern "C" DLL_EXPORT Datetime_Del_MarshalSeqStruct_InOut_cdecl __stdcall GetDel
{
return MarshalSeqStruct_InOut_cdecl;
}
+
+extern "C" DATE DLL_EXPORT STDMETHODCALLTYPE PassThroughDate(DATE d)
+{
+ return d;
+}
diff --git a/tests/src/Interop/PInvoke/Decimal/PInvoke/DecNative.cpp b/tests/src/Interop/PInvoke/Decimal/PInvoke/DecNative.cpp
index ee236d12cc..a853f7eed1 100644
--- a/tests/src/Interop/PInvoke/Decimal/PInvoke/DecNative.cpp
+++ b/tests/src/Interop/PInvoke/Decimal/PInvoke/DecNative.cpp
@@ -124,9 +124,9 @@ extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE TakeDecAsOutParamAsLPStructByRef(DE
}
}
-extern "C" DLL_EXPORT DECIMAL STDMETHODCALLTYPE RetDec()
+extern "C" DLL_EXPORT DECIMAL* STDMETHODCALLTYPE RetDec()
{
- return g_DECIMAL_MaxValue;
+ return &g_DECIMAL_MaxValue;
}
// CY
diff --git a/tests/src/Interop/PInvoke/Decimal/PInvoke/DecimalTest.cs b/tests/src/Interop/PInvoke/Decimal/PInvoke/DecimalTest.cs
index eeed3d64ca..e6566d7a07 100644
--- a/tests/src/Interop/PInvoke/Decimal/PInvoke/DecimalTest.cs
+++ b/tests/src/Interop/PInvoke/Decimal/PInvoke/DecimalTest.cs
@@ -6,7 +6,6 @@ using System;
using System.Runtime.InteropServices;
#pragma warning disable 618
-#region Struct Def
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
public struct Stru_Exp_DecAsCYAsFld
{
@@ -28,7 +27,12 @@ public struct Stru_Seq_DecAsLPStructAsFld
[MarshalAs(UnmanagedType.LPStruct)]
public decimal dec;
}
-#endregion
+
+public struct NestedCurrency
+{
+ [MarshalAs(UnmanagedType.Currency)]
+ public decimal dec;
+}
public class CMain
{
@@ -49,6 +53,8 @@ public class CMain
[DllImport("DecNative")]
[return: MarshalAs(UnmanagedType.Currency)]
static extern decimal RetCY();
+ [DllImport("DecNative", EntryPoint = "RetCY")]
+ static extern NestedCurrency RetCYStruct();
[DllImport("DecNative")]
static extern bool TakeStru_Exp_DecAsCYAsFldByInOutRef([Out] out Stru_Exp_DecAsCYAsFld s);
@@ -84,20 +90,10 @@ public class CMain
return false;
}
- bool exceptionThrown = false;
- try
- {
- RetDec();
- }
- catch (MarshalDirectiveException)
+ dec = RetDec();
+ if (dec != decimal.MaxValue)
{
- exceptionThrown = true;
- }
-
- if (!exceptionThrown)
- {
- Console.WriteLine("Expected MarshalDirectiveException is not thrown");
- return false;
+ Console.WriteLine($"Test Failed. Expected 'decimal.MaxValue'. Got {dec}");
}
Console.WriteLine("MarshalAsLPStruct end.");
@@ -132,8 +128,8 @@ public class CMain
return false;
}
-
bool exceptionThrown = false;
+
try
{
RetCY();
@@ -142,10 +138,16 @@ public class CMain
{
exceptionThrown = true;
}
-
if (!exceptionThrown)
{
- Console.WriteLine("Expected MarshalDirectiveException is not thrown");
+ Console.WriteLine("Expected MarshalDirectiveException from RetCY() not thrown");
+ return false;
+ }
+
+ cy = RetCYStruct().dec;
+ if (cy != CY_MIN_VALUE)
+ {
+ Console.WriteLine($"Test Failed: RetCYStruct. Expected 'CY_MIN_VALUE'. Got '{cy}'.");
return false;
}
diff --git a/tests/src/Interop/PInvoke/Decimal/ReversePInvoke/DecimalTest.cs b/tests/src/Interop/PInvoke/Decimal/ReversePInvoke/DecimalTest.cs
index cc2f2f85e7..d63b455f37 100644
--- a/tests/src/Interop/PInvoke/Decimal/ReversePInvoke/DecimalTest.cs
+++ b/tests/src/Interop/PInvoke/Decimal/ReversePInvoke/DecimalTest.cs
@@ -277,7 +277,7 @@ public class CMain
}
if (!exceptionThrown)
{
- Console.WriteLine("Expected MarshalDirectiveException from TakeDecAsInOutParamAsLPStructByRef(ref dec) not thrown");
+ Console.WriteLine("Expected MarshalDirectiveException from ReverseCall_CYRet(new Dele_CYRet(CYRet)) not thrown");
return false;
}
diff --git a/tests/src/Interop/PInvoke/Miscellaneous/HandleRef/HandleRefNative.cpp b/tests/src/Interop/PInvoke/Miscellaneous/HandleRef/HandleRefNative.cpp
index bc5d61e96e..9104bf6239 100644
--- a/tests/src/Interop/PInvoke/Miscellaneous/HandleRef/HandleRefNative.cpp
+++ b/tests/src/Interop/PInvoke/Miscellaneous/HandleRef/HandleRefNative.cpp
@@ -83,3 +83,7 @@ extern "C" DLL_EXPORT int STDMETHODCALLTYPE TestNoGC(int *pintValue, GCCallback
return intReturn;
}
+extern "C" DLL_EXPORT void* STDMETHODCALLTYPE InvalidMarshalPointer_Return()
+{
+ return nullptr;
+}
diff --git a/tests/src/Interop/PInvoke/Miscellaneous/HandleRef/HandleRefTest.cs b/tests/src/Interop/PInvoke/Miscellaneous/HandleRef/HandleRefTest.cs
index 6eba3cb7b1..02dc8ff464 100644
--- a/tests/src/Interop/PInvoke/Miscellaneous/HandleRef/HandleRefTest.cs
+++ b/tests/src/Interop/PInvoke/Miscellaneous/HandleRef/HandleRefTest.cs
@@ -22,6 +22,9 @@ class HandleRefTest
[DllImport(@"HandleRefNative", CallingConvention = CallingConvention.Winapi)]
private static extern int TestNoGC(HandleRef pintValue, Action gcCallback);
+ [DllImport(@"HandleRefNative")]
+ private static extern HandleRef InvalidMarshalPointer_Return();
+
public unsafe static int Main(string[] args)
{
try{
@@ -64,6 +67,9 @@ class HandleRefTest
Assert.AreEqual(intReturn, TestNoGC(hr4, gcCallback), "The return value is wrong");
Console.WriteLine("Native code finished");
+ Console.WriteLine("InvalidMarshalPointer_Return");
+ Assert.Throws<MarshalDirectiveException>(() => InvalidMarshalPointer_Return());
+
return 100;
} catch (Exception e){
Console.WriteLine($"Test Failure: {e}");
diff --git a/tests/src/Interop/PInvoke/SafeHandles/Misc.Unsupported/MiscUnsupportedTest.cs b/tests/src/Interop/PInvoke/SafeHandles/Misc.Unsupported/MiscUnsupportedTest.cs
index d5e84550b3..078c940223 100644
--- a/tests/src/Interop/PInvoke/SafeHandles/Misc.Unsupported/MiscUnsupportedTest.cs
+++ b/tests/src/Interop/PInvoke/SafeHandles/Misc.Unsupported/MiscUnsupportedTest.cs
@@ -67,7 +67,7 @@ public class SHTester_Misc
//4-returning structures (with SH subclass fields) from unmanaged code as pure return values
Console.WriteLine("Testing SHReturnStruct...");
- Assert.Throws<MarshalDirectiveException>(() => SHReturnStruct(), "FAILED! Exception not thrown.");
+ Assert.Throws<NotSupportedException>(() => SHReturnStruct(), "FAILED! Exception not thrown.");
//6-passing structures with SH Array fields
hndArray = new SafeFileHandle[Helper.N];
@@ -111,4 +111,4 @@ public class SHTester_Misc
Console.WriteLine("Testing SHStructParam_OutRetVal...");
Assert.Throws<MarshalDirectiveException>(() => s = SHStructParam_OutRetVal(), "FAILED! Exception not thrown.");
}
-} \ No newline at end of file
+}
diff --git a/tests/src/Interop/PInvoke/Varargs/VarargsNative.cpp b/tests/src/Interop/PInvoke/Varargs/VarargsNative.cpp
index e2034a9f47..a4f6b4639c 100644
--- a/tests/src/Interop/PInvoke/Varargs/VarargsNative.cpp
+++ b/tests/src/Interop/PInvoke/Varargs/VarargsNative.cpp
@@ -11,6 +11,8 @@ extern "C" DLL_EXPORT void __cdecl TestVarArgs(LPWSTR formattedString, SIZE_T bu
va_start(args, format);
vswprintf_s(formattedString, bufferSize, format, args);
+
+ va_end(args);
}
extern "C" DLL_EXPORT void STDMETHODCALLTYPE TestArgIterator(LPWSTR formattedString, SIZE_T bufferSize, LPCWSTR format, va_list args)
diff --git a/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutExp.cs b/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutExp.cs
index 43492d7c49..262ec0b1ad 100644
--- a/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutExp.cs
+++ b/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutExp.cs
@@ -29,6 +29,7 @@ public class Managed
RunMarshalStructAsParamAsExpByRefOut();
RunMarshalStructAsParamAsExpByValInOut();
RunMarshalStructAsParamAsExpByRefInOut();
+ RunMarshalStructAsReturn();
if (failures > 0)
{
@@ -205,6 +206,8 @@ public class Managed
[DllImport("MarshalStructAsParam", EntryPoint = "MarshalStructAsParam_AsExpByRefLongStructPack16Explicit")]
static extern bool MarshalStructAsParam_AsExpByRefInOutLongStructPack16Explicit([In, Out] ref LongStructPack16Explicit str1);
#endregion
+ [DllImport("MarshalStructAsParam")]
+ static extern LongStructPack16Explicit GetLongStruct(long l1, long l2);
#region Marshal Explicit struct method
[SecuritySafeCritical]
@@ -1567,4 +1570,16 @@ public class Managed
MarshalStructAsParam_AsExpByRefInOut(StructID.IntStructPack8ExplicitId);
MarshalStructAsParam_AsExpByRefInOut(StructID.LongStructPack16ExplicitId);
}
-} \ No newline at end of file
+
+ private static void RunMarshalStructAsReturn()
+ {
+ Console.WriteLine("\nVerify marshal Explicit layout struct as return.");
+
+ LongStructPack16Explicit longStruct = GetLongStruct(123456, 78910);
+ if(longStruct.l1 != 123456 || longStruct.l2 != 78910)
+ {
+ Console.WriteLine("Failed to return LongStructPack16Explicit.");
+ failures++;
+ }
+ }
+}
diff --git a/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutSeq.cs b/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutSeq.cs
index 736a72a1cd..22bb03c34e 100644
--- a/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutSeq.cs
+++ b/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutSeq.cs
@@ -59,6 +59,7 @@ public class Managed
RunMarshalSeqStructAsParamByRefOut();
RunMarshalSeqStructAsParamByValInOut();
RunMarshalSeqStructAsParamByRefInOut();
+ RunMarshalSeqStructAsReturn();
if (failures > 0)
{
@@ -315,6 +316,15 @@ public class Managed
[DllImport("MarshalStructAsParam")]
static extern bool MarshalStructAsParam_AsSeqByValSequentialAggregateSequentialWrapper(AggregateSequentialWrapper wrapper);
+ [DllImport("MarshalStructAsParam")]
+ static extern HFA GetHFA(float f1, float f2, float f3, float f4);
+
+ [DllImport("MarshalStructAsParam")]
+ static extern ManyInts GetMultiplesOf(int i);
+
+ [DllImport("MarshalStructAsParam")]
+ static extern MultipleBool GetBools(bool b1, bool b2);
+
#region Marshal struct method in PInvoke
[SecuritySafeCritical]
unsafe private static void MarshalStructAsParam_AsSeqByVal(StructID id)
@@ -2373,6 +2383,35 @@ public class Managed
MarshalStructAsParam_AsSeqByRefInOut(StructID.IncludeOuterIntegerStructSequentialId);
MarshalStructAsParam_AsSeqByRefInOut(StructID.S11Id);
}
+
+ private static void RunMarshalSeqStructAsReturn()
+ {
+ Console.WriteLine("\nVerify marshalsequential layout struct as return.");
+
+ HFA hfa = GetHFA(12.34f, 52.12f, 64.124f, 675.452351322f);
+ if (hfa.f1 != 12.34f || hfa.f2 != 52.12f || hfa.f3 != 64.124f || hfa.f4 != 675.452351322f)
+ {
+ Console.WriteLine("4-float structure returned from native to managed failed.");
+ }
+
+ ManyInts multiples = GetMultiplesOf(2);
+
+ int i = 1;
+ foreach (int multiple in multiples)
+ {
+ if (multiple != 2 * i)
+ {
+ Console.WriteLine("Structure of 20 ints returned from native to managed failed.");
+ }
+ i++;
+ }
+
+ MultipleBool bools = GetBools(true, true);
+ if (!bools.b1 || !bools.b2)
+ {
+ Console.WriteLine("Structure of two bools marshalled to BOOLs returned from native to managed failed");
+ }
+ }
}
diff --git a/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp b/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp
index ef4012fcf5..be3f04688e 100644
--- a/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp
+++ b/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp
@@ -1178,3 +1178,46 @@ extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE MarshalStructAsParam_AsExpByRefOutL
return TRUE;
}
+extern "C" DLL_EXPORT HFA STDMETHODCALLTYPE GetHFA(float f1, float f2, float f3, float f4)
+{
+ return {f1, f2, f3, f4};
+}
+
+extern "C" DLL_EXPORT ManyInts STDMETHODCALLTYPE GetMultiplesOf(int value)
+{
+ ManyInts multiples =
+ {
+ value * 1,
+ value * 2,
+ value * 3,
+ value * 4,
+ value * 5,
+ value * 6,
+ value * 7,
+ value * 8,
+ value * 9,
+ value * 10,
+ value * 11,
+ value * 12,
+ value * 13,
+ value * 14,
+ value * 15,
+ value * 16,
+ value * 17,
+ value * 18,
+ value * 19,
+ value * 20,
+ };
+
+ return multiples;
+}
+
+extern "C" DLL_EXPORT LongStructPack16Explicit STDMETHODCALLTYPE GetLongStruct(LONG64 val1, LONG64 val2)
+{
+ return {val1, val2};
+}
+
+extern "C" DLL_EXPORT MultipleBools STDMETHODCALLTYPE GetBools(BOOL b1, BOOL b2)
+{
+ return {b1, b2};
+}
diff --git a/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h b/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h
index 0383af4520..4cb49e192a 100644
--- a/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h
+++ b/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h
@@ -819,6 +819,44 @@ bool IsCorrectLongStructPack16Explicit(LongStructPack16Explicit* p)
return true;
}
+struct HFA
+{
+ float f1;
+ float f2;
+ float f3;
+ float f4;
+};
+
+struct ManyInts
+{
+ int i1;
+ int i2;
+ int i3;
+ int i4;
+ int i5;
+ int i6;
+ int i7;
+ int i8;
+ int i9;
+ int i10;
+ int i11;
+ int i12;
+ int i13;
+ int i14;
+ int i15;
+ int i16;
+ int i17;
+ int i18;
+ int i19;
+ int i20;
+};
+
+struct MultipleBools
+{
+ BOOL b1;
+ BOOL b2;
+};
+
struct IntWithInnerSequential
{
int i1;
diff --git a/tests/src/Interop/StructMarshalling/PInvoke/Struct.cs b/tests/src/Interop/StructMarshalling/PInvoke/Struct.cs
index 38a466d0ac..af9d762825 100644
--- a/tests/src/Interop/StructMarshalling/PInvoke/Struct.cs
+++ b/tests/src/Interop/StructMarshalling/PInvoke/Struct.cs
@@ -297,3 +297,70 @@ public struct LongStructPack16Explicit
[FieldOffset(8)]
public long l2;
}
+
+
+[StructLayout(LayoutKind.Sequential)]
+public struct HFA
+{
+ public float f1;
+ public float f2;
+ public float f3;
+ public float f4;
+}
+
+[StructLayout(LayoutKind.Sequential)]
+public struct ManyInts
+{
+ public int i1;
+ public int i2;
+ public int i3;
+ public int i4;
+ public int i5;
+ public int i6;
+ public int i7;
+ public int i8;
+ public int i9;
+ public int i10;
+ public int i11;
+ public int i12;
+ public int i13;
+ public int i14;
+ public int i15;
+ public int i16;
+ public int i17;
+ public int i18;
+ public int i19;
+ public int i20;
+
+ public System.Collections.Generic.IEnumerator<int> GetEnumerator()
+ {
+ yield return i1;
+ yield return i2;
+ yield return i3;
+ yield return i4;
+ yield return i5;
+ yield return i6;
+ yield return i7;
+ yield return i8;
+ yield return i9;
+ yield return i10;
+ yield return i11;
+ yield return i12;
+ yield return i13;
+ yield return i14;
+ yield return i15;
+ yield return i16;
+ yield return i17;
+ yield return i18;
+ yield return i19;
+ yield return i20;
+ }
+}
+
+
+[StructLayout(LayoutKind.Sequential)]
+public struct MultipleBool
+{
+ public bool b1;
+ public bool b2;
+}