Skip to content

Commit f0ba96a

Browse files
P/Invokes should use C types not C++. (#94942)
* Reduce source duplication * Use correct function signature when marshalling is enabled.
1 parent 6036eaf commit f0ba96a

15 files changed

+175
-240
lines changed

src/tests/Interop/DisabledRuntimeMarshalling/AutoLayout.cs

+1-7
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,18 @@ public unsafe class PInvokes_AutoLayout
1313
[Fact]
1414
public static void AutoLayoutStruct()
1515
{
16-
short s = 42;
17-
bool b = true;
1816
Assert.Throws<MarshalDirectiveException>(() => DisabledRuntimeMarshallingNative.CallWithAutoLayoutStruct(new AutoLayoutStruct()));
1917
}
2018

2119
[Fact]
2220
public static void StructWithAutoLayoutField()
2321
{
24-
short s = 42;
25-
bool b = true;
2622
AssertThrowsMarshalDirectiveOrTypeLoad(() => DisabledRuntimeMarshallingNative.CallWithAutoLayoutStruct(new SequentialWithAutoLayoutField()));
2723
}
2824

2925
[Fact]
3026
public static void StructWithNestedAutoLayoutField()
3127
{
32-
short s = 42;
33-
bool b = true;
3428
AssertThrowsMarshalDirectiveOrTypeLoad(() => DisabledRuntimeMarshallingNative.CallWithAutoLayoutStruct(new SequentialWithAutoLayoutNestedField()));
3529
}
3630

@@ -41,7 +35,7 @@ private static void AssertThrowsMarshalDirectiveOrTypeLoad(Action testCode)
4135
testCode();
4236
return;
4337
}
44-
catch (Exception ex) when(ex is MarshalDirectiveException or TypeLoadException)
38+
catch (Exception ex) when (ex is MarshalDirectiveException or TypeLoadException)
4539
{
4640
return;
4741
}

src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshallingNative.cpp

+17-15
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,9 @@
33

44
#include <xplatform.h>
55

6-
// MSVC versions before 19.38 generate incorrect code for this file when compiling with /O2
7-
#if defined(_MSC_VER) && (_MSC_VER < 1938)
8-
#pragma optimize("", off)
9-
#endif
10-
116
struct StructWithShortAndBool
127
{
13-
bool b;
8+
BYTE b;
149
short s;
1510
// Make sure we don't have any cases where the native code could return a value of this type one way,
1611
// but an invalid managed declaration would expect it differently. This ensures that test failures won't be
@@ -24,24 +19,31 @@ struct StructWithWCharAndShort
2419
WCHAR c;
2520
};
2621

27-
extern "C" DLL_EXPORT bool STDMETHODCALLTYPE CheckStructWithShortAndBool(StructWithShortAndBool str, short s, bool b)
22+
extern "C" DLL_EXPORT BYTE STDMETHODCALLTYPE CheckStructWithShortAndBool(StructWithShortAndBool str, short s, BYTE b)
2823
{
2924
return str.s == s && str.b == b;
3025
}
3126

32-
extern "C" DLL_EXPORT bool STDMETHODCALLTYPE CheckStructWithWCharAndShort(StructWithWCharAndShort str, short s, WCHAR c)
27+
static BOOL STDMETHODCALLTYPE CheckStructWithShortAndBoolMarshalSupport(StructWithShortAndBool str, short s, BYTE b)
3328
{
34-
return str.s == s && str.c == c;
29+
return (CheckStructWithShortAndBool(str, s, b) != 0) ? TRUE : FALSE;
3530
}
3631

37-
using CheckStructWithShortAndBoolCallback = bool (STDMETHODCALLTYPE*)(StructWithShortAndBool, short, bool);
32+
extern "C" DLL_EXPORT BYTE STDMETHODCALLTYPE CheckStructWithWCharAndShort(StructWithWCharAndShort str, short s, WCHAR c)
33+
{
34+
return str.s == s && str.c == c;
35+
}
3836

39-
extern "C" DLL_EXPORT CheckStructWithShortAndBoolCallback STDMETHODCALLTYPE GetStructWithShortAndBoolCallback()
37+
extern "C" DLL_EXPORT void* STDMETHODCALLTYPE GetStructWithShortAndBoolCallback(BYTE marshalSupported)
4038
{
41-
return &CheckStructWithShortAndBool;
39+
return (marshalSupported != 0)
40+
? (void*)&CheckStructWithShortAndBoolMarshalSupport
41+
: (void*)&CheckStructWithShortAndBool;
4242
}
4343

44-
extern "C" DLL_EXPORT bool STDMETHODCALLTYPE CallCheckStructWithShortAndBoolCallback(CheckStructWithShortAndBoolCallback cb, StructWithShortAndBool str, short s, bool b)
44+
using CheckStructWithShortAndBoolCallback = BYTE (STDMETHODCALLTYPE*)(StructWithShortAndBool, short, BYTE);
45+
46+
extern "C" DLL_EXPORT BYTE STDMETHODCALLTYPE CallCheckStructWithShortAndBoolCallback(CheckStructWithShortAndBoolCallback cb, StructWithShortAndBool str, short s, BYTE b)
4547
{
4648
return cb(str, s, b);
4749
}
@@ -54,14 +56,14 @@ extern "C" DLL_EXPORT BYTE PassThrough(BYTE b)
5456
extern "C" DLL_EXPORT void Invalid(...) {}
5557

5658

57-
extern "C" DLL_EXPORT bool STDMETHODCALLTYPE CheckStructWithShortAndBoolWithVariantBool(StructWithShortAndBool str, short s, VARIANT_BOOL b)
59+
extern "C" DLL_EXPORT BYTE STDMETHODCALLTYPE CheckStructWithShortAndBoolWithVariantBool(StructWithShortAndBool str, short s, VARIANT_BOOL b)
5860
{
5961
// Specifically use VARIANT_TRUE here as invalid marshalling (in the "disabled runtime marshalling" case) will incorrectly marshal VARAINT_TRUE
6062
// but could accidentally marshal VARIANT_FALSE correctly since it is 0, which is the same representation as a zero or sign extension of the C# false value.
6163
return str.s == s && str.b == (b == VARIANT_TRUE);
6264
}
6365

64-
using CheckStructWithShortAndBoolWithVariantBoolCallback = bool (STDMETHODCALLTYPE*)(StructWithShortAndBool, short, VARIANT_BOOL);
66+
using CheckStructWithShortAndBoolWithVariantBoolCallback = BYTE (STDMETHODCALLTYPE*)(StructWithShortAndBool, short, VARIANT_BOOL);
6567

6668
extern "C" DLL_EXPORT CheckStructWithShortAndBoolWithVariantBoolCallback STDMETHODCALLTYPE GetStructWithShortAndBoolWithVariantBoolCallback()
6769
{
+123-41
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ public StructWithShortAndBool(short s, bool b)
2525

2626
public struct StructWithShortAndBoolWithMarshalAs
2727
{
28+
#if DISABLE_RUNTIME_MARSHALLING
2829
[MarshalAs(UnmanagedType.VariantBool)]
30+
#else
31+
[MarshalAs(UnmanagedType.U1)]
32+
#endif
2933
bool b;
3034
short s;
3135
int padding;
@@ -41,6 +45,10 @@ public StructWithShortAndBoolWithMarshalAs(short s, bool b)
4145
public struct StructWithWCharAndShort
4246
{
4347
short s;
48+
#if DISABLE_RUNTIME_MARSHALLING
49+
#else
50+
[MarshalAs(UnmanagedType.U2)]
51+
#endif
4452
char c;
4553

4654
public StructWithWCharAndShort(short s, char c)
@@ -54,7 +62,11 @@ public StructWithWCharAndShort(short s, char c)
5462
public struct StructWithWCharAndShortWithMarshalAs
5563
{
5664
short s;
65+
#if DISABLE_RUNTIME_MARSHALLING
5766
[MarshalAs(UnmanagedType.U1)]
67+
#else
68+
[MarshalAs(UnmanagedType.U2)]
69+
#endif
5870
char c;
5971

6072
public StructWithWCharAndShortWithMarshalAs(short s, char c)
@@ -76,6 +88,7 @@ public StructWithShortAndGeneric(short s, T t)
7688
}
7789
}
7890

91+
#if DISABLE_RUNTIME_MARSHALLING
7992
public struct StructWithString
8093
{
8194
string s;
@@ -89,6 +102,7 @@ public StructWithString(string s)
89102
[StructLayout(LayoutKind.Sequential)]
90103
public class LayoutClass
91104
{}
105+
#endif
92106

93107
[StructLayout(LayoutKind.Auto)]
94108
public struct AutoLayoutStruct
@@ -106,52 +120,142 @@ public struct SequentialWithAutoLayoutNestedField
106120
SequentialWithAutoLayoutField field;
107121
}
108122

123+
#if DISABLE_RUNTIME_MARSHALLING
109124
public enum ByteEnum : byte
110125
{
111126
Value = 42
112127
}
113128

129+
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "PassThrough")]
130+
public static extern byte GetEnumUnderlyingValue(ByteEnum b);
131+
#endif
132+
114133
[DllImport(nameof(DisabledRuntimeMarshallingNative))]
134+
#if !DISABLE_RUNTIME_MARSHALLING
135+
[return:MarshalAs(UnmanagedType.U1)]
136+
#endif
115137
public static extern bool CheckStructWithShortAndBool(StructWithShortAndBool str, short s, bool b);
138+
116139
[DllImport(nameof(DisabledRuntimeMarshallingNative))]
117-
public static extern bool CheckStructWithShortAndBool(StructWithShortAndBoolWithMarshalAs str, short s, [MarshalAs(UnmanagedType.I4)] bool b);
140+
#if DISABLE_RUNTIME_MARSHALLING
141+
public static extern bool CheckStructWithShortAndBool(StructWithShortAndBoolWithMarshalAs str, short s, bool b);
142+
#else
143+
[return:MarshalAs(UnmanagedType.U1)]
144+
public static extern bool CheckStructWithShortAndBool(StructWithShortAndBoolWithMarshalAs str, short s, [MarshalAs(UnmanagedType.Bool)] bool b);
145+
#endif
146+
118147
[DllImport(nameof(DisabledRuntimeMarshallingNative))]
148+
#if !DISABLE_RUNTIME_MARSHALLING
149+
[return:MarshalAs(UnmanagedType.U1)]
150+
#endif
119151
public static extern bool CheckStructWithWCharAndShort(StructWithWCharAndShort str, short s, char c);
152+
120153
[DllImport(nameof(DisabledRuntimeMarshallingNative))]
154+
#if !DISABLE_RUNTIME_MARSHALLING
155+
[return:MarshalAs(UnmanagedType.U1)]
156+
#endif
121157
public static extern bool CheckStructWithWCharAndShort(StructWithWCharAndShortWithMarshalAs str, short s, char c);
158+
122159
[DllImport(nameof(DisabledRuntimeMarshallingNative))]
160+
#if !DISABLE_RUNTIME_MARSHALLING
161+
[return:MarshalAs(UnmanagedType.U1)]
162+
#endif
123163
public static extern bool CheckStructWithWCharAndShort(StructWithShortAndGeneric<char> str, short s, char c);
124164

125165
[DllImport(nameof(DisabledRuntimeMarshallingNative))]
166+
#if !DISABLE_RUNTIME_MARSHALLING
167+
[return:MarshalAs(UnmanagedType.U1)]
168+
#endif
126169
public static extern bool CheckStructWithWCharAndShort(StructWithShortAndGeneric<short> str, short s, short c);
127170

171+
#if DISABLE_RUNTIME_MARSHALLING
172+
[DllImport(nameof(DisabledRuntimeMarshallingNative))]
173+
public static extern bool CallCheckStructWithShortAndBoolCallback(delegate* unmanaged<StructWithShortAndBool, short, bool, bool> cb, StructWithShortAndBool str, short s, bool b);
174+
#endif
175+
176+
public static IntPtr GetStructWithShortAndBoolCallback()
177+
{
178+
#if DISABLE_RUNTIME_MARSHALLING
179+
return GetStructWithShortAndBoolCallback(false);
180+
#else
181+
return GetStructWithShortAndBoolCallback(true);
182+
#endif
183+
[DllImport(nameof(DisabledRuntimeMarshallingNative))]
184+
static extern IntPtr GetStructWithShortAndBoolCallback([MarshalAs(UnmanagedType.U1)] bool marshalSupported);
185+
}
186+
187+
[DllImport(nameof(DisabledRuntimeMarshallingNative))]
188+
public static extern IntPtr GetStructWithShortAndBoolWithVariantBoolCallback();
189+
190+
#if DISABLE_RUNTIME_MARSHALLING
191+
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "PassThrough")]
192+
public static extern bool GetByteAsBool(byte b);
193+
#endif
194+
195+
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")]
196+
public static extern void CallWithAutoLayoutStruct(AutoLayoutStruct s);
197+
198+
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")]
199+
public static extern void CallWithAutoLayoutStruct(SequentialWithAutoLayoutField s);
200+
201+
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")]
202+
public static extern void CallWithAutoLayoutStruct(SequentialWithAutoLayoutNestedField s);
203+
204+
#if DISABLE_RUNTIME_MARSHALLING
205+
[DllImport(nameof(DisabledRuntimeMarshallingNative))]
206+
[return:MarshalAs(UnmanagedType.U1)]
207+
public static extern bool CheckStructWithShortAndBoolWithVariantBool(StructWithShortAndBool str, short s, [MarshalAs(UnmanagedType.VariantBool)] bool b);
208+
#else
209+
[DllImport(nameof(DisabledRuntimeMarshallingNative))]
210+
[return:MarshalAs(UnmanagedType.U1)]
211+
public static extern bool CheckStructWithShortAndBoolWithVariantBool(StructWithShortAndBoolWithMarshalAs str, short s, [MarshalAs(UnmanagedType.VariantBool)] bool b);
212+
#endif
213+
214+
// Apply the UnmanagedFunctionPointer attributes with the default calling conventions so that Mono's AOT compiler
215+
// recognizes that these delegate types are used in interop and should have managed->native thunks generated for them.
216+
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
217+
public delegate bool CheckStructWithShortAndBoolCallback(StructWithShortAndBool str, short s, bool b);
218+
219+
#if DISABLE_RUNTIME_MARSHALLING
220+
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
221+
public delegate bool CheckStructWithShortAndBoolWithVariantBoolCallback(StructWithShortAndBool str, short s, [MarshalAs(UnmanagedType.VariantBool)] bool b);
222+
#else
223+
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
224+
public delegate bool CheckStructWithShortAndBoolWithMarshalAsAndVariantBoolCallback(StructWithShortAndBoolWithMarshalAs str, short s, [MarshalAs(UnmanagedType.VariantBool)] bool b);
225+
#endif
226+
227+
[UnmanagedCallersOnly]
228+
public static bool CheckStructWithShortAndBoolManaged(StructWithShortAndBool str, short s, bool b)
229+
{
230+
return str.s == s && str.b == b;
231+
}
232+
233+
#if DISABLE_RUNTIME_MARSHALLING
128234
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid", CharSet = CharSet.Ansi)]
129235
public static extern void CheckStringWithAnsiCharSet(string s);
236+
130237
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid", CharSet = CharSet.Unicode)]
131238
public static extern void CheckStringWithUnicodeCharSet(string s);
239+
132240
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid", CharSet = CharSet.Unicode)]
133241
public static extern string GetStringWithUnicodeCharSet();
242+
134243
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")]
135244
public static extern void CheckStructWithStructWithString(StructWithString s);
245+
136246
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")]
137247
public static extern void CheckLayoutClass(LayoutClass c);
248+
138249
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid", SetLastError = true)]
139250
public static extern void CallWithSetLastError();
251+
140252
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")]
141253
[LCIDConversion(0)]
142254
public static extern void CallWithLCID();
255+
143256
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid", PreserveSig = false)]
144257
public static extern int CallWithHResultSwap();
145258

146-
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")]
147-
public static extern void CallWithAutoLayoutStruct(AutoLayoutStruct s);
148-
149-
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")]
150-
public static extern void CallWithAutoLayoutStruct(SequentialWithAutoLayoutField s);
151-
152-
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")]
153-
public static extern void CallWithAutoLayoutStruct(SequentialWithAutoLayoutNestedField s);
154-
155259
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")]
156260
public static extern void CallWithByRef(ref int i);
157261

@@ -161,50 +265,28 @@ public enum ByteEnum : byte
161265
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")]
162266
public static extern void CallWithInt128(Int128 i);
163267

164-
[DllImport(nameof(DisabledRuntimeMarshallingNative))]
165-
public static extern delegate* unmanaged<StructWithShortAndBool, short, bool, bool> GetStructWithShortAndBoolCallback();
166-
167-
[DllImport(nameof(DisabledRuntimeMarshallingNative))]
168-
public static extern delegate* unmanaged<StructWithShortAndBool, short, bool, bool> GetStructWithShortAndBoolWithVariantBoolCallback();
169-
170-
[DllImport(nameof(DisabledRuntimeMarshallingNative))]
171-
public static extern bool CallCheckStructWithShortAndBoolCallback(delegate* unmanaged<StructWithShortAndBool, short, bool, bool> cb, StructWithShortAndBool str, short s, bool b);
172-
173-
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "PassThrough")]
174-
public static extern bool GetByteAsBool(byte b);
175-
176-
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "PassThrough")]
177-
public static extern byte GetEnumUnderlyingValue(ByteEnum b);
178-
179-
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "CheckStructWithShortAndBoolWithVariantBool")]
180-
[return:MarshalAs(UnmanagedType.U1)]
181-
public static extern bool CheckStructWithShortAndBoolWithVariantBool_FailureExpected(StructWithShortAndBool str, short s, [MarshalAs(UnmanagedType.VariantBool)] bool b);
268+
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")]
269+
public static extern void CallWithUInt128(UInt128 i);
182270

183271
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")]
184272
public static extern void CallWith(Nullable<int> s);
273+
185274
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")]
186275
public static extern void CallWith(Span<int> s);
276+
187277
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")]
188278
public static extern void CallWith(ReadOnlySpan<int> ros);
279+
189280
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")]
190281
public static extern void CallWith(Vector64<int> v);
282+
191283
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")]
192284
public static extern void CallWith(Vector128<int> v);
285+
193286
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")]
194287
public static extern void CallWith(Vector256<int> v);
288+
195289
[DllImport(nameof(DisabledRuntimeMarshallingNative), EntryPoint = "Invalid")]
196290
public static extern void CallWith(Vector<int> v);
197-
198-
// Apply the UnmanagedFunctionPointer attributes with the default calling conventions so that Mono's AOT compiler
199-
// recognizes that these delegate types are used in interop and should have managed->native thunks generated for them.
200-
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
201-
public delegate bool CheckStructWithShortAndBoolCallback(StructWithShortAndBool str, short s, bool b);
202-
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
203-
public delegate bool CheckStructWithShortAndBoolWithVariantBoolCallback(StructWithShortAndBool str, short s, [MarshalAs(UnmanagedType.VariantBool)] bool b);
204-
205-
[UnmanagedCallersOnly]
206-
public static bool CheckStructWithShortAndBoolManaged(StructWithShortAndBool str, short s, bool b)
207-
{
208-
return str.s == s && str.b == b;
209-
}
291+
#endif
210292
}

src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeAssemblyDisabled.csproj

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
</PropertyGroup>
99
<ItemGroup>
1010
<Compile Include="PInvokeAssemblyMarshallingDisabled/*.cs" />
11-
<Compile Include="*.cs" />
11+
<Compile Include="AutoLayout.cs" />
12+
<Compile Include="FunctionPointers.cs" />
13+
<Compile Include="RuntimeMarshallingDisabledAttribute.cs" />
1214
</ItemGroup>
1315
<ItemGroup>
1416
<ProjectReference Include="Native_DisabledMarshalling/DisabledRuntimeMarshallingNative_DisabledMarshalling.csproj" />

src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeAssemblyEnabled.csproj

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
</PropertyGroup>
77
<ItemGroup>
88
<Compile Include="PInvokeAssemblyMarshallingEnabled/*.cs" />
9-
<Compile Include="*.cs" />
9+
<Compile Include="AutoLayout.cs" />
10+
<Compile Include="FunctionPointers.cs" />
11+
<Compile Include="RuntimeMarshallingDisabledAttribute.cs" />
1012
</ItemGroup>
1113
<ItemGroup>
1214
<ProjectReference Include="Native_Default/DisabledRuntimeMarshallingNative_Default.csproj" />

0 commit comments

Comments
 (0)