[runtime] Fix the freeing of BStr members in pinvoke. (#9184)
[mono-project.git] / mono / tests / marshal2.cs
blob7216cb08559c72bb9c926469df2f82f76b4fcfbe
1 //
2 // Tests for Marshal.StructureToPtr and PtrToStructure
3 //
5 using System;
6 using System.Text;
7 using System.Runtime.InteropServices;
9 public class Tests {
12 [StructLayout (LayoutKind.Sequential)]
13 public class SimpleObj {
14 public int a;
15 public int b;
17 public void test () {}
20 [StructLayout (LayoutKind.Sequential)]
21 public struct SimpleStruct2 {
22 public int a;
23 public int b;
26 [StructLayout (LayoutKind.Sequential, CharSet=CharSet.Ansi)]
27 public struct SimpleStruct {
28 public int a;
29 public bool bool1;
30 public bool bool2;
31 public int b;
32 [MarshalAs (UnmanagedType.ByValArray, SizeConst=2)] public short[] a1;
33 [MarshalAs (UnmanagedType.ByValTStr, SizeConst=4)] public string s1;
34 public SimpleStruct2 emb1;
35 public SimpleObj emb2;
36 public string s2;
37 public double x;
38 [MarshalAs (UnmanagedType.ByValArray, SizeConst=2)]
39 public char[] a2;
42 [StructLayout (LayoutKind.Sequential, CharSet=CharSet.Ansi)]
43 public struct ByValTStrStruct {
44 [MarshalAs (UnmanagedType.ByValTStr, SizeConst=4)] public string s1;
45 public int i;
48 [StructLayout (LayoutKind.Sequential, CharSet=CharSet.Unicode)]
49 public struct ByValWStrStruct {
50 [MarshalAs (UnmanagedType.ByValTStr, SizeConst=4)] public string s1;
51 public int i;
54 [StructLayout (LayoutKind.Sequential, Pack=1)]
55 public struct PackStruct1 {
56 float f;
59 [StructLayout (LayoutKind.Sequential)]
60 public struct PackStruct2 {
61 byte b;
62 PackStruct1 s;
65 [StructLayout (LayoutKind.Sequential)]
66 struct InvalidArrayForMarshalingStruct
68 // Missing the following needed directive
69 // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
70 public readonly char[] CharArray;
73 [StructLayout(LayoutKind.Sequential)]
74 struct TwoDimensionalArrayStruct
76 public TwoDimensionalArrayStruct(int[,] vals)
78 TwoDimensionalArray = vals;
81 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
82 public readonly int[,] TwoDimensionalArray;
85 public unsafe static int Main (String[] args) {
86 if (TestDriver.RunTests (typeof (Tests), args) != 0)
87 return 34;
88 return 0;
91 public static int test_0_structure_to_ptr () {
92 SimpleStruct ss = new SimpleStruct ();
93 int size = Marshal.SizeOf (typeof (SimpleStruct));
95 //if (size != 52)
96 //return 1;
98 IntPtr p = Marshal.AllocHGlobal (size);
99 ss.a = 1;
100 ss.bool1 = true;
101 ss.bool2 = false;
102 ss.b = 2;
103 ss.a1 = new short [2];
104 ss.a1 [0] = 6;
105 ss.a1 [1] = 5;
106 ss.s1 = "abcd";
107 ss.emb1 = new SimpleStruct2 ();
108 ss.emb1.a = 3;
109 ss.emb1.b = 4;
110 ss.emb2 = new SimpleObj ();
111 ss.emb2.a = 10;
112 ss.emb2.b = 11;
113 ss.s2 = "just a test";
114 ss.x = 1.5;
115 ss.a2 = new char [2];
116 ss.a2 [0] = 'a';
117 ss.a2 [1] = 'b';
119 Marshal.StructureToPtr (ss, p, false);
120 Type t = ss.GetType ();
122 if (Marshal.ReadInt32 (p, (int)Marshal.OffsetOf (t, "a")) != 1)
123 return 1;
124 if (Marshal.ReadInt32 (p, (int)Marshal.OffsetOf (t, "bool1")) != 1)
125 return 2;
126 if (Marshal.ReadInt32 (p, (int)Marshal.OffsetOf (t, "bool2")) != 0)
127 return 3;
128 if (Marshal.ReadInt32 (p, (int)Marshal.OffsetOf (t, "b")) != 2)
129 return 4;
130 if (Marshal.ReadInt16 (p, 16) != 6)
131 return 5;
132 if (Marshal.ReadInt16 (p, 18) != 5)
133 return 6;
134 if (Marshal.ReadByte (p, 20) != 97)
135 return 7;
136 if (Marshal.ReadByte (p, 21) != 98)
137 return 8;
138 if (Marshal.ReadByte (p, 22) != 99)
139 return 9;
140 if (Marshal.ReadByte (p, 23) != 0)
141 return 10;
142 if (Marshal.ReadInt32 (p, 24) != 3)
143 return 11;
144 if (Marshal.ReadInt32 (p, 28) != 4)
145 return 12;
146 if (Marshal.ReadInt32 (p, 32) != 10)
147 return 13;
148 if (Marshal.ReadInt32 (p, 36) != 11)
149 return 14;
150 if (Marshal.ReadByte (p, (int)Marshal.OffsetOf (t, "a2")) != 97)
151 return 15;
152 if (Marshal.ReadByte (p, (int)Marshal.OffsetOf (t, "a2") + 1) != 98)
153 return 16;
155 SimpleStruct cp = (SimpleStruct)Marshal.PtrToStructure (p, ss.GetType ());
157 if (cp.a != 1)
158 return 16;
160 if (cp.bool1 != true)
161 return 17;
163 if (cp.bool2 != false)
164 return 18;
166 if (cp.b != 2)
167 return 19;
169 if (cp.a1 [0] != 6)
170 return 20;
172 if (cp.a1 [1] != 5)
173 return 21;
175 if (cp.s1 != "abc")
176 return 22;
178 if (cp.emb1.a != 3)
179 return 23;
181 if (cp.emb1.b != 4)
182 return 24;
184 if (cp.emb2.a != 10)
185 return 25;
187 if (cp.emb2.b != 11)
188 return 26;
190 if (cp.s2 != "just a test")
191 return 27;
193 if (cp.x != 1.5)
194 return 28;
196 if (cp.a2 [0] != 'a')
197 return 29;
199 if (cp.a2 [1] != 'b')
200 return 30;
201 return 0;
204 [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)]
205 public struct Struct1
207 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
208 public string Field1;
209 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
210 public string Field2;
211 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
212 public string Field3;
215 public static int test_0_byvaltstr () {
216 ByValTStrStruct s = new ByValTStrStruct ();
218 IntPtr p2 = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (ByValTStrStruct)));
219 Marshal.StructureToPtr(s, p2, false);
221 /* Check that the ByValTStr is initialized correctly */
222 for (int i = 0; i < 4; ++i)
223 if (Marshal.ReadByte (p2, i) != 0)
224 return 31;
226 s.s1 = "ABCD";
227 s.i = 55;
229 Marshal.StructureToPtr(s, p2, false);
231 ByValTStrStruct s2 = (ByValTStrStruct)Marshal.PtrToStructure (p2, typeof (ByValTStrStruct));
233 /* The fourth char is lost because of null-termination */
234 if (s2.s1 != "ABC")
235 return 32;
237 if (s2.i != 55)
238 return 33;
240 // Check that decoding also respects the size, even when there is no null terminator
241 byte[] data = Encoding.ASCII.GetBytes ("ABCDXXXX");
242 int size = Marshal.SizeOf (typeof (ByValTStrStruct));
243 IntPtr buffer = Marshal.AllocHGlobal (size);
244 Marshal.Copy (data, 0, buffer, size);
246 s2 = (ByValTStrStruct)Marshal.PtrToStructure (buffer, typeof (ByValTStrStruct));
247 if (s2.s1 != "ABC")
248 return 34;
250 return 0;
253 public static int test_0_byvaltstr_unicode () {
254 ByValWStrStruct s = new ByValWStrStruct ();
256 IntPtr p2 = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (ByValWStrStruct)));
257 Marshal.StructureToPtr(s, p2, false);
259 /* Check that the ByValWStr is initialized correctly */
260 for (int i = 0; i < 8; ++i)
261 if (Marshal.ReadByte (p2, i) != 0)
262 return 31;
264 s.s1 = "ABCD";
265 s.i = 55;
267 Marshal.StructureToPtr(s, p2, false);
269 ByValWStrStruct s2 = (ByValWStrStruct)Marshal.PtrToStructure (p2, typeof (ByValWStrStruct));
271 /* The fourth char is lost because of null-termination */
272 if (s2.s1 != "ABC")
273 return 32;
275 if (s2.i != 55)
276 return 33;
277 return 0;
280 public static int test_0_byvaltstr_max_size () {
281 string buffer = "12345678123456789012345678901234";
283 IntPtr ptr = Marshal.StringToBSTR (buffer);
285 Struct1 data = (Struct1)Marshal.PtrToStructure (ptr, typeof (Struct1));
286 if (data.Field1 != "12345678")
287 return 1;
288 if (data.Field2 != "1234567890")
289 return 2;
290 if (data.Field3 != "12345678901234")
291 return 3;
292 return 0;
295 // Check that the 'Pack' directive on a struct changes the min alignment of the struct as well (#12110)
296 public static int test_0_struct_pack () {
297 if (Marshal.OffsetOf (typeof (PackStruct2), "s") != new IntPtr (1))
298 return 1;
299 return 0;
302 public static int test_0_generic_ptr_to_struct () {
303 int size = Marshal.SizeOf (typeof (SimpleStruct2));
304 IntPtr p = Marshal.AllocHGlobal (size);
306 Marshal.WriteInt32 (p, 0, 1); //a
307 Marshal.WriteInt32 (p, 4, 2); //a
309 var s = Marshal.PtrToStructure<SimpleStruct2> (p);
311 if (s.a != 1)
312 return 1;
313 if (s.b != 2)
314 return 2;
315 return 0;
318 public static int test_0_invalid_array_throws () {
319 var ptr = Marshal.AllocHGlobal(Marshal.SizeOf (typeof (InvalidArrayForMarshalingStruct)));
320 try {
321 Marshal.PtrToStructure (ptr, typeof (InvalidArrayForMarshalingStruct));
323 catch (MarshalDirectiveException e) {
324 return 0;
326 return 1;
329 public static int test_0_multidimentional_arrays () {
330 var structToMarshal = new TwoDimensionalArrayStruct (new[, ] { {1, 2, 3}, {4, 5, 6} });
331 var ptr = Marshal.AllocHGlobal (Marshal.SizeOf (structToMarshal));
332 Marshal.StructureToPtr (structToMarshal, ptr, false);
333 unsafe {
334 if(((int*)ptr)[4] == 5)
335 return 0;
337 return 1;