Merge pull request #19867 from echesakovMSFT/BuildCrossBitnessCrossGenAsWell
[platform/upstream/coreclr.git] / src / System.Private.CoreLib / src / System / Runtime / InteropServices / Marshal.cs
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 using System.Collections.Generic;
6 using System.Reflection;
7 using System.Reflection.Emit;
8 using System.Security;
9 using System.Text;
10 using System.Runtime.CompilerServices;
11 using System.Runtime.ConstrainedExecution;
12 using Win32Native = Microsoft.Win32.Win32Native;
13 using System.Diagnostics;
14 using System.Runtime.InteropServices.ComTypes;
15 using System.StubHelpers;
16
17 namespace System.Runtime.InteropServices
18 {
19     public enum CustomQueryInterfaceMode
20     {
21         Ignore = 0,
22         Allow = 1
23     }
24
25     /// <summary>
26     /// This class contains methods that are mainly used to marshal between unmanaged
27     /// and managed types.
28     /// </summary>
29     public static partial class Marshal
30     {
31 #if FEATURE_COMINTEROP
32         internal static Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");
33 #endif //FEATURE_COMINTEROP
34
35         private const int LMEM_FIXED = 0;
36         private const int LMEM_MOVEABLE = 2;
37 #if !FEATURE_PAL
38         private const long HiWordMask = unchecked((long)0xffffffffffff0000L);
39 #endif //!FEATURE_PAL
40
41         // Win32 has the concept of Atoms, where a pointer can either be a pointer
42         // or an int.  If it's less than 64K, this is guaranteed to NOT be a 
43         // pointer since the bottom 64K bytes are reserved in a process' page table.
44         // We should be careful about deallocating this stuff.  Extracted to
45         // a function to avoid C# problems with lack of support for IntPtr.
46         // We have 2 of these methods for slightly different semantics for NULL.
47         private static bool IsWin32Atom(IntPtr ptr)
48         {
49 #if FEATURE_PAL
50             return false;
51 #else
52             long lPtr = (long)ptr;
53             return 0 == (lPtr & HiWordMask);
54 #endif
55         }
56
57         /// <summary>
58         /// The default character size for the system. This is always 2 because
59         /// the framework only runs on UTF-16 systems.
60         /// </summary>
61         public static readonly int SystemDefaultCharSize = 2;
62
63         /// <summary>
64         /// The max DBCS character size for the system.
65         /// </summary>
66         public static readonly int SystemMaxDBCSCharSize = GetSystemMaxDBCSCharSize();
67
68         /// <summary>
69         /// Helper method to retrieve the system's maximum DBCS character size.
70         /// </summary>
71         [MethodImpl(MethodImplOptions.InternalCall)]
72         private static extern int GetSystemMaxDBCSCharSize();
73
74         public static unsafe string PtrToStringAnsi(IntPtr ptr)
75         {
76             if (IntPtr.Zero == ptr)
77             {
78                 return null;
79             }
80             else if (IsWin32Atom(ptr))
81             {
82                 return null;
83             }
84
85             int nb = Win32Native.lstrlenA(ptr);
86             if (nb == 0)
87             {
88                 return string.Empty;
89             }
90
91             return new string((sbyte*)ptr);
92         }
93
94         public static unsafe string PtrToStringAnsi(IntPtr ptr, int len)
95         {
96             if (ptr == IntPtr.Zero)
97             {
98                 throw new ArgumentNullException(nameof(ptr));
99             }
100             if (len < 0)
101             {
102                 throw new ArgumentException(null, nameof(len));
103             }
104
105             return new string((sbyte*)ptr, 0, len);
106         }
107
108         public static unsafe string PtrToStringUni(IntPtr ptr, int len)
109         {
110             if (ptr == IntPtr.Zero)
111             {
112                 throw new ArgumentNullException(nameof(ptr));
113             }
114             if (len < 0)
115             {
116                 throw new ArgumentException(SR.ArgumentOutOfRange_NeedNonNegNum, nameof(len));
117             }
118
119             return new string((char*)ptr, 0, len);
120         }
121
122         public static string PtrToStringAuto(IntPtr ptr, int len)
123         {
124             // Ansi platforms are no longer supported
125             return PtrToStringUni(ptr, len);
126         }
127
128         public static unsafe string PtrToStringUni(IntPtr ptr)
129         {
130             if (IntPtr.Zero == ptr)
131             {
132                 return null;
133             }
134             else if (IsWin32Atom(ptr))
135             {
136                 return null;
137             }
138
139             return new string((char*)ptr);
140         }
141
142         public static string PtrToStringAuto(IntPtr ptr)
143         {
144             // Ansi platforms are no longer supported
145             return PtrToStringUni(ptr);
146         }
147
148         public static unsafe string PtrToStringUTF8(IntPtr ptr)
149         {
150             if (IntPtr.Zero == ptr)
151             {
152                 return null;
153             }
154
155             int nbBytes = StubHelpers.StubHelpers.strlen((sbyte*)ptr.ToPointer());
156             return PtrToStringUTF8(ptr, nbBytes);
157         }
158
159         public static unsafe string PtrToStringUTF8(IntPtr ptr, int byteLen)
160         {
161             if (byteLen < 0)
162             {
163                 throw new ArgumentOutOfRangeException(nameof(byteLen), SR.ArgumentOutOfRange_NeedNonNegNum);
164             }
165             else if (IntPtr.Zero == ptr)
166             {
167                 return null;
168             }
169             else if (IsWin32Atom(ptr))
170             {
171                 return null;
172             }
173             else if (byteLen == 0)
174             {
175                 return string.Empty;
176             }
177
178             byte* pByte = (byte*)ptr.ToPointer();
179             return Encoding.UTF8.GetString(pByte, byteLen);
180         }
181
182         public static int SizeOf(object structure)
183         {
184             if (structure == null)
185             {
186                 throw new ArgumentNullException(nameof(structure));
187             }
188
189             return SizeOfHelper(structure.GetType(), true);
190         }
191
192         public static int SizeOf<T>(T structure) => SizeOf((object)structure);
193
194         public static int SizeOf(Type t)
195         {
196             if (t == null)
197             {
198                 throw new ArgumentNullException(nameof(t));
199             }
200             if (!(t is RuntimeType))
201             {
202                 throw new ArgumentException(SR.Argument_MustBeRuntimeType, nameof(t));
203             }
204             if (t.IsGenericType)
205             {
206                 throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(t));
207             }
208
209             return SizeOfHelper(t, throwIfNotMarshalable: true);
210         }
211
212         public static int SizeOf<T>() => SizeOf(typeof(T));
213
214         [MethodImpl(MethodImplOptions.InternalCall)]
215         internal static extern int SizeOfHelper(Type t, bool throwIfNotMarshalable);
216
217         public static IntPtr OffsetOf(Type t, string fieldName)
218         {
219             if (t == null)
220             {
221                 throw new ArgumentNullException(nameof(t));
222             }
223
224             FieldInfo f = t.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
225             if (f == null)
226             {
227                 throw new ArgumentException(SR.Format(SR.Argument_OffsetOfFieldNotFound, t.FullName), nameof(fieldName));
228             }
229
230             if (!(f is RtFieldInfo rtField))
231             {
232                 throw new ArgumentException(SR.Argument_MustBeRuntimeFieldInfo, nameof(fieldName));
233             }
234
235             return OffsetOfHelper(rtField);
236         }
237
238         public static IntPtr OffsetOf<T>(string fieldName) => OffsetOf(typeof(T), fieldName);
239
240         [MethodImpl(MethodImplOptions.InternalCall)]
241         private static extern IntPtr OffsetOfHelper(IRuntimeFieldInfo f);
242
243         /// <summary>
244         /// IMPORTANT NOTICE: This method does not do any verification on the array.
245         /// It must be used with EXTREME CAUTION since passing in an array that is
246         /// not pinned or in the fixed heap can cause unexpected results.
247         /// </summary>
248         [MethodImpl(MethodImplOptions.InternalCall)]
249         public static extern IntPtr UnsafeAddrOfPinnedArrayElement(Array arr, int index);
250
251         public static IntPtr UnsafeAddrOfPinnedArrayElement<T>(T[] arr, int index)
252         {
253             return UnsafeAddrOfPinnedArrayElement((Array)arr, index);
254         }
255
256         public static void Copy(int[] source, int startIndex, IntPtr destination, int length)
257         {
258             CopyToNative(source, startIndex, destination, length);
259         }
260
261         public static void Copy(char[] source, int startIndex, IntPtr destination, int length)
262         {
263             CopyToNative(source, startIndex, destination, length);
264         }
265
266         public static void Copy(short[] source, int startIndex, IntPtr destination, int length)
267         {
268             CopyToNative(source, startIndex, destination, length);
269         }
270
271         public static void Copy(long[] source, int startIndex, IntPtr destination, int length)
272         {
273             CopyToNative(source, startIndex, destination, length);
274         }
275
276         public static void Copy(float[] source, int startIndex, IntPtr destination, int length)
277         {
278             CopyToNative(source, startIndex, destination, length);
279         }
280
281         public static void Copy(double[] source, int startIndex, IntPtr destination, int length)
282         {
283             CopyToNative(source, startIndex, destination, length);
284         }
285
286         public static void Copy(byte[] source, int startIndex, IntPtr destination, int length)
287         {
288             CopyToNative(source, startIndex, destination, length);
289         }
290
291         public static void Copy(IntPtr[] source, int startIndex, IntPtr destination, int length)
292         {
293             CopyToNative(source, startIndex, destination, length);
294         }
295
296         [MethodImpl(MethodImplOptions.InternalCall)]
297         private static extern void CopyToNative(object source, int startIndex, IntPtr destination, int length);
298
299         public static void Copy(IntPtr source, int[] destination, int startIndex, int length)
300         {
301             CopyToManaged(source, destination, startIndex, length);
302         }
303
304         public static void Copy(IntPtr source, char[] destination, int startIndex, int length)
305         {
306             CopyToManaged(source, destination, startIndex, length);
307         }
308
309         public static void Copy(IntPtr source, short[] destination, int startIndex, int length)
310         {
311             CopyToManaged(source, destination, startIndex, length);
312         }
313
314         public static void Copy(IntPtr source, long[] destination, int startIndex, int length)
315         {
316             CopyToManaged(source, destination, startIndex, length);
317         }
318
319         public static void Copy(IntPtr source, float[] destination, int startIndex, int length)
320         {
321             CopyToManaged(source, destination, startIndex, length);
322         }
323
324         public static void Copy(IntPtr source, double[] destination, int startIndex, int length)
325         {
326             CopyToManaged(source, destination, startIndex, length);
327         }
328
329         public static void Copy(IntPtr source, byte[] destination, int startIndex, int length)
330         {
331             CopyToManaged(source, destination, startIndex, length);
332         }
333
334         public static void Copy(IntPtr source, IntPtr[] destination, int startIndex, int length)
335         {
336             CopyToManaged(source, destination, startIndex, length);
337         }
338
339         [MethodImpl(MethodImplOptions.InternalCall)]
340         private static extern void CopyToManaged(IntPtr source, object destination, int startIndex, int length);
341         
342         public static byte ReadByte(object ptr, int ofs)
343         {
344             return ReadValueSlow(ptr, ofs, (IntPtr nativeHome, int offset) => ReadByte(nativeHome, offset));
345         }
346
347         public static unsafe byte ReadByte(IntPtr ptr, int ofs)
348         {
349             try
350             {
351                 byte* addr = (byte*)ptr + ofs;
352                 return *addr;
353             }
354             catch (NullReferenceException)
355             {
356                 // this method is documented to throw AccessViolationException on any AV
357                 throw new AccessViolationException();
358             }
359         }
360
361         public static byte ReadByte(IntPtr ptr) => ReadByte(ptr, 0);
362
363         public static short ReadInt16(object ptr, int ofs)
364         {
365             return ReadValueSlow(ptr, ofs, (IntPtr nativeHome, int offset) => ReadInt16(nativeHome, offset));
366         }
367
368         public static unsafe short ReadInt16(IntPtr ptr, int ofs)
369         {
370             try
371             {
372                 byte* addr = (byte*)ptr + ofs;
373                 if ((unchecked((int)addr) & 0x1) == 0)
374                 {
375                     // aligned read
376                     return *((short*)addr);
377                 }
378                 else
379                 {
380                     // unaligned read
381                     short val;
382                     byte* valPtr = (byte*)&val;
383                     valPtr[0] = addr[0];
384                     valPtr[1] = addr[1];
385                     return val;
386                 }
387             }
388             catch (NullReferenceException)
389             {
390                 // this method is documented to throw AccessViolationException on any AV
391                 throw new AccessViolationException();
392             }
393         }
394
395         public static short ReadInt16(IntPtr ptr) => ReadInt16(ptr, 0);
396
397         public static int ReadInt32(object ptr, int ofs)
398         {
399             return ReadValueSlow(ptr, ofs, (IntPtr nativeHome, int offset) => ReadInt32(nativeHome, offset));
400         }
401
402         public static unsafe int ReadInt32(IntPtr ptr, int ofs)
403         {
404             try
405             {
406                 byte* addr = (byte*)ptr + ofs;
407                 if ((unchecked((int)addr) & 0x3) == 0)
408                 {
409                     // aligned read
410                     return *((int*)addr);
411                 }
412                 else
413                 {
414                     // unaligned read
415                     int val;
416                     byte* valPtr = (byte*)&val;
417                     valPtr[0] = addr[0];
418                     valPtr[1] = addr[1];
419                     valPtr[2] = addr[2];
420                     valPtr[3] = addr[3];
421                     return val;
422                 }
423             }
424             catch (NullReferenceException)
425             {
426                 // this method is documented to throw AccessViolationException on any AV
427                 throw new AccessViolationException();
428             }
429         }
430
431         public static int ReadInt32(IntPtr ptr) => ReadInt32(ptr, 0);
432
433         public static IntPtr ReadIntPtr(object ptr, int ofs)
434         {
435 #if BIT64
436             return (IntPtr)ReadInt64(ptr, ofs);
437 #else // 32
438             return (IntPtr)ReadInt32(ptr, ofs);
439 #endif
440         }
441
442         public static IntPtr ReadIntPtr(IntPtr ptr, int ofs)
443         {
444 #if BIT64
445             return (IntPtr)ReadInt64(ptr, ofs);
446 #else // 32
447             return (IntPtr)ReadInt32(ptr, ofs);
448 #endif
449         }
450
451         public static IntPtr ReadIntPtr(IntPtr ptr) => ReadIntPtr(ptr, 0);
452
453         public static long ReadInt64([MarshalAs(UnmanagedType.AsAny), In] object ptr, int ofs)
454         {
455             return ReadValueSlow(ptr, ofs, (IntPtr nativeHome, int offset) => ReadInt64(nativeHome, offset));
456         }
457
458         public static unsafe long ReadInt64(IntPtr ptr, int ofs)
459         {
460             try
461             {
462                 byte* addr = (byte*)ptr + ofs;
463                 if ((unchecked((int)addr) & 0x7) == 0)
464                 {
465                     // aligned read
466                     return *((long*)addr);
467                 }
468                 else
469                 {
470                     // unaligned read
471                     long val;
472                     byte* valPtr = (byte*)&val;
473                     valPtr[0] = addr[0];
474                     valPtr[1] = addr[1];
475                     valPtr[2] = addr[2];
476                     valPtr[3] = addr[3];
477                     valPtr[4] = addr[4];
478                     valPtr[5] = addr[5];
479                     valPtr[6] = addr[6];
480                     valPtr[7] = addr[7];
481                     return val;
482                 }
483             }
484             catch (NullReferenceException)
485             {
486                 // this method is documented to throw AccessViolationException on any AV
487                 throw new AccessViolationException();
488             }
489         }
490
491         public static long ReadInt64(IntPtr ptr) => ReadInt64(ptr, 0);
492
493         //====================================================================
494         // Read value from marshaled object (marshaled using AsAny)
495         // It's quite slow and can return back dangling pointers
496         // It's only there for backcompact
497         // People should instead use the IntPtr overloads
498         //====================================================================
499         private static unsafe T ReadValueSlow<T>(object ptr, int ofs, Func<IntPtr, int, T> readValueHelper)
500         {
501             // Consumers of this method are documented to throw AccessViolationException on any AV
502             if (ptr == null)
503             {
504                 throw new AccessViolationException();
505             }
506
507             const int Flags = 
508                 (int)AsAnyMarshaler.AsAnyFlags.In | 
509                 (int)AsAnyMarshaler.AsAnyFlags.IsAnsi | 
510                 (int)AsAnyMarshaler.AsAnyFlags.IsBestFit;
511
512             MngdNativeArrayMarshaler.MarshalerState nativeArrayMarshalerState = new MngdNativeArrayMarshaler.MarshalerState();
513             AsAnyMarshaler marshaler = new AsAnyMarshaler(new IntPtr(&nativeArrayMarshalerState));
514
515             IntPtr pNativeHome = IntPtr.Zero;
516
517             try
518             {
519                 pNativeHome = marshaler.ConvertToNative(ptr, Flags);
520                 return readValueHelper(pNativeHome, ofs);
521             }
522             finally
523             {
524                 marshaler.ClearNative(pNativeHome);
525             }
526         }
527
528         public static unsafe void WriteByte(IntPtr ptr, int ofs, byte val)
529         {
530             try
531             {
532                 byte* addr = (byte*)ptr + ofs;
533                 *addr = val;
534             }
535             catch (NullReferenceException)
536             {
537                 // this method is documented to throw AccessViolationException on any AV
538                 throw new AccessViolationException();
539             }
540         }
541
542         public static void WriteByte(object ptr, int ofs, byte val)
543         {
544             WriteValueSlow(ptr, ofs, val, (IntPtr nativeHome, int offset, byte value) => WriteByte(nativeHome, offset, value));
545         }
546
547         public static void WriteByte(IntPtr ptr, byte val) => WriteByte(ptr, 0, val);
548
549         public static unsafe void WriteInt16(IntPtr ptr, int ofs, short val)
550         {
551             try
552             {
553                 byte* addr = (byte*)ptr + ofs;
554                 if ((unchecked((int)addr) & 0x1) == 0)
555                 {
556                     // aligned write
557                     *((short*)addr) = val;
558                 }
559                 else
560                 {
561                     // unaligned write
562                     byte* valPtr = (byte*)&val;
563                     addr[0] = valPtr[0];
564                     addr[1] = valPtr[1];
565                 }
566             }
567             catch (NullReferenceException)
568             {
569                 // this method is documented to throw AccessViolationException on any AV
570                 throw new AccessViolationException();
571             }
572         }
573
574         public static void WriteInt16(object ptr, int ofs, short val)
575         {
576             WriteValueSlow(ptr, ofs, val, (IntPtr nativeHome, int offset, short value) => Marshal.WriteInt16(nativeHome, offset, value));
577         }
578
579         public static void WriteInt16(IntPtr ptr, short val) => WriteInt16(ptr, 0, val);
580
581         public static void WriteInt16(IntPtr ptr, int ofs, char val) => WriteInt16(ptr, ofs, (short)val);
582
583         public static void WriteInt16([In, Out]object ptr, int ofs, char val) => WriteInt16(ptr, ofs, (short)val);
584
585         public static void WriteInt16(IntPtr ptr, char val) => WriteInt16(ptr, 0, (short)val);
586
587         public static unsafe void WriteInt32(IntPtr ptr, int ofs, int val)
588         {
589             try
590             {
591                 byte* addr = (byte*)ptr + ofs;
592                 if ((unchecked((int)addr) & 0x3) == 0)
593                 {
594                     // aligned write
595                     *((int*)addr) = val;
596                 }
597                 else
598                 {
599                     // unaligned write
600                     byte* valPtr = (byte*)&val;
601                     addr[0] = valPtr[0];
602                     addr[1] = valPtr[1];
603                     addr[2] = valPtr[2];
604                     addr[3] = valPtr[3];
605                 }
606             }
607             catch (NullReferenceException)
608             {
609                 // this method is documented to throw AccessViolationException on any AV
610                 throw new AccessViolationException();
611             }
612         }
613
614         public static void WriteInt32(object ptr, int ofs, int val)
615         {
616             WriteValueSlow(ptr, ofs, val, (IntPtr nativeHome, int offset, int value) => Marshal.WriteInt32(nativeHome, offset, value));
617         }
618
619         public static void WriteInt32(IntPtr ptr, int val) => WriteInt32(ptr, 0, val);
620
621         public static void WriteIntPtr(IntPtr ptr, int ofs, IntPtr val)
622         {
623 #if BIT64
624             WriteInt64(ptr, ofs, (long)val);
625 #else // 32
626             WriteInt32(ptr, ofs, (int)val);
627 #endif
628         }
629
630         public static void WriteIntPtr(object ptr, int ofs, IntPtr val)
631         {
632 #if BIT64
633             WriteInt64(ptr, ofs, (long)val);
634 #else // 32
635             WriteInt32(ptr, ofs, (int)val);
636 #endif
637         }
638
639         public static void WriteIntPtr(IntPtr ptr, IntPtr val) => WriteIntPtr(ptr, 0, val);
640
641         public static unsafe void WriteInt64(IntPtr ptr, int ofs, long val)
642         {
643             try
644             {
645                 byte* addr = (byte*)ptr + ofs;
646                 if ((unchecked((int)addr) & 0x7) == 0)
647                 {
648                     // aligned write
649                     *((long*)addr) = val;
650                 }
651                 else
652                 {
653                     // unaligned write
654                     byte* valPtr = (byte*)&val;
655                     addr[0] = valPtr[0];
656                     addr[1] = valPtr[1];
657                     addr[2] = valPtr[2];
658                     addr[3] = valPtr[3];
659                     addr[4] = valPtr[4];
660                     addr[5] = valPtr[5];
661                     addr[6] = valPtr[6];
662                     addr[7] = valPtr[7];
663                 }
664             }
665             catch (NullReferenceException)
666             {
667                 // this method is documented to throw AccessViolationException on any AV
668                 throw new AccessViolationException();
669             }
670         }
671
672         public static void WriteInt64(object ptr, int ofs, long val)
673         {
674             WriteValueSlow(ptr, ofs, val, (IntPtr nativeHome, int offset, long value) => Marshal.WriteInt64(nativeHome, offset, value));
675         }
676
677         public static void WriteInt64(IntPtr ptr, long val) => WriteInt64(ptr, 0, val);
678
679         /// <summary>
680         /// Write value into marshaled object (marshaled using AsAny) and propagate the
681         /// value back. This is quite slow and can return back dangling pointers. It is
682         /// only here for backcompat. People should instead use the IntPtr overloads.
683         /// </summary>
684         private static unsafe void WriteValueSlow<T>(object ptr, int ofs, T val, Action<IntPtr, int, T> writeValueHelper)
685         {
686             // Consumers of this method are documented to throw AccessViolationException on any AV
687             if (ptr == null)
688             {
689                 throw new AccessViolationException();
690             }
691
692             const int Flags = 
693                 (int)AsAnyMarshaler.AsAnyFlags.In | 
694                 (int)AsAnyMarshaler.AsAnyFlags.Out | 
695                 (int)AsAnyMarshaler.AsAnyFlags.IsAnsi | 
696                 (int)AsAnyMarshaler.AsAnyFlags.IsBestFit;
697
698             MngdNativeArrayMarshaler.MarshalerState nativeArrayMarshalerState = new MngdNativeArrayMarshaler.MarshalerState();
699             AsAnyMarshaler marshaler = new AsAnyMarshaler(new IntPtr(&nativeArrayMarshalerState));
700
701             IntPtr pNativeHome = IntPtr.Zero;
702
703             try
704             {
705                 pNativeHome = marshaler.ConvertToNative(ptr, Flags);
706                 writeValueHelper(pNativeHome, ofs, val);
707                 marshaler.ConvertToManaged(ptr, pNativeHome);
708             }
709             finally
710             {
711                 marshaler.ClearNative(pNativeHome);
712             }
713         }
714
715         [MethodImpl(MethodImplOptions.InternalCall)]
716         public static extern int GetLastWin32Error();
717
718         [MethodImpl(MethodImplOptions.InternalCall)]
719         internal static extern void SetLastWin32Error(int error);
720
721         public static int GetHRForLastWin32Error()
722         {
723             int dwLastError = GetLastWin32Error();
724             if ((dwLastError & 0x80000000) == 0x80000000)
725             {
726                 return dwLastError;
727             }
728             
729             return (dwLastError & 0x0000FFFF) | unchecked((int)0x80070000);
730         }
731
732         public static void Prelink(MethodInfo m)
733         {
734             if (m == null)
735             {
736                 throw new ArgumentNullException(nameof(m));
737             }
738             if (!(m is RuntimeMethodInfo rmi))
739             {
740                 throw new ArgumentException(SR.Argument_MustBeRuntimeMethodInfo, nameof(m));
741             }
742
743             InternalPrelink(rmi);
744         }
745
746         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
747         private static extern void InternalPrelink(IRuntimeMethodInfo m);
748
749         public static void PrelinkAll(Type c)
750         {
751             if (c == null)
752             {
753                 throw new ArgumentNullException(nameof(c));
754             }
755
756             MethodInfo[] mi = c.GetMethods();
757             if (mi != null)
758             {
759                 for (int i = 0; i < mi.Length; i++)
760                 {
761                     Prelink(mi[i]);
762                 }
763             }
764         }
765
766         [MethodImpl(MethodImplOptions.InternalCall)]
767         public static extern /* struct _EXCEPTION_POINTERS* */ IntPtr GetExceptionPointers();
768         
769         [MethodImpl(MethodImplOptions.InternalCall)]
770         public static extern int GetExceptionCode();
771
772         /// <summary>
773         /// Marshals data from a structure class to a native memory block. If the
774         /// structure contains pointers to allocated blocks and "fDeleteOld" is
775         /// true, this routine will call DestroyStructure() first. 
776         /// </summary>
777         [MethodImpl(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
778         public static extern void StructureToPtr(object structure, IntPtr ptr, bool fDeleteOld);
779
780         public static void StructureToPtr<T>(T structure, IntPtr ptr, bool fDeleteOld)
781         {
782             StructureToPtr((object)structure, ptr, fDeleteOld);
783         }
784
785         /// <summary>
786         /// Marshals data from a native memory block to a preallocated structure class.
787         /// </summary>
788         public static void PtrToStructure(IntPtr ptr, object structure)
789         {
790             PtrToStructureHelper(ptr, structure, allowValueClasses: false);
791         }
792
793         public static void PtrToStructure<T>(IntPtr ptr, T structure)
794         {
795             PtrToStructure(ptr, (object)structure);
796         }
797
798         /// <summary>
799         /// Creates a new instance of "structuretype" and marshals data from a
800         /// native memory block to it.
801         /// </summary>
802         public static object PtrToStructure(IntPtr ptr, Type structureType)
803         {
804             if (ptr == IntPtr.Zero)
805             {
806                 return null;
807             }
808
809             if (structureType == null)
810             {
811                 throw new ArgumentNullException(nameof(structureType));
812             }
813             if (structureType.IsGenericType)
814             {
815                 throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(structureType));
816             }
817             if (!(structureType.UnderlyingSystemType is RuntimeType rt))
818             {
819                 throw new ArgumentException(SR.Arg_MustBeType, nameof(structureType));
820             }
821
822             object structure = rt.CreateInstanceDefaultCtor(publicOnly: false, skipCheckThis: false, fillCache: false, wrapExceptions: true);
823             PtrToStructureHelper(ptr, structure, allowValueClasses: true);
824             return structure;
825         }
826
827         public static T PtrToStructure<T>(IntPtr ptr) => (T)PtrToStructure(ptr, typeof(T));
828
829         /// <summary>
830         /// Helper function to copy a pointer into a preallocated structure.
831         /// </summary>
832         [MethodImpl(MethodImplOptions.InternalCall)]
833         private static extern void PtrToStructureHelper(IntPtr ptr, object structure, bool allowValueClasses);
834
835         /// <summary>
836         /// Frees all substructures pointed to by the native memory block.
837         /// "structuretype" is used to provide layout information.
838         /// </summary>
839         [MethodImpl(MethodImplOptions.InternalCall)]
840         public static extern void DestroyStructure(IntPtr ptr, Type structuretype);
841
842         public static void DestroyStructure<T>(IntPtr ptr) => DestroyStructure(ptr, typeof(T));
843
844 #if FEATURE_COMINTEROP
845         /// <summary>
846         /// Returns the HInstance for this module.  Returns -1 if the module doesn't have
847         /// an HInstance.  In Memory (Dynamic) Modules won't have an HInstance.
848         /// </summary>
849         public static IntPtr GetHINSTANCE(Module m)
850         {
851             if (m == null)
852             {
853                 throw new ArgumentNullException(nameof(m));
854             }
855
856             RuntimeModule rtModule = m as RuntimeModule;
857             if (rtModule == null && m is ModuleBuilder mb)
858             {
859                 rtModule = mb.InternalModule;
860             }
861
862             if (rtModule == null)
863             {
864                 throw new ArgumentNullException(nameof(m), SR.Argument_MustBeRuntimeModule);
865             }
866
867             return GetHINSTANCE(rtModule.GetNativeHandle());
868         }
869
870         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
871         private static extern IntPtr GetHINSTANCE(RuntimeModule m);
872
873 #endif // FEATURE_COMINTEROP
874
875         /// <summary>
876         /// Throws a CLR exception based on the HRESULT.
877         /// </summary>
878         public static void ThrowExceptionForHR(int errorCode)
879         {
880             if (errorCode < 0)
881             {
882                 ThrowExceptionForHRInternal(errorCode, IntPtr.Zero);
883             }
884         }
885
886         public static void ThrowExceptionForHR(int errorCode, IntPtr errorInfo)
887         {
888             if (errorCode < 0)
889             {
890                 ThrowExceptionForHRInternal(errorCode, errorInfo);
891             }
892         }
893
894         [MethodImpl(MethodImplOptions.InternalCall)]
895         internal static extern void ThrowExceptionForHRInternal(int errorCode, IntPtr errorInfo);
896
897         /// <summary>
898         /// Converts the HRESULT to a CLR exception.
899         /// </summary>
900         public static Exception GetExceptionForHR(int errorCode)
901         {
902             if (errorCode >= 0)
903             {
904                 return null;
905             }
906
907             return GetExceptionForHRInternal(errorCode, IntPtr.Zero);
908         }
909         public static Exception GetExceptionForHR(int errorCode, IntPtr errorInfo)
910         {
911             if (errorCode >= 0)
912             {
913                 return null;
914             }
915
916             return GetExceptionForHRInternal(errorCode, errorInfo);
917         }
918
919         [MethodImpl(MethodImplOptions.InternalCall)]
920         internal static extern Exception GetExceptionForHRInternal(int errorCode, IntPtr errorInfo);
921
922         public static IntPtr AllocHGlobal(IntPtr cb)
923         {
924             // For backwards compatibility on 32 bit platforms, ensure we pass values between 
925             // int.MaxValue and uint.MaxValue to Windows.  If the binary has had the 
926             // LARGEADDRESSAWARE bit set in the PE header, it may get 3 or 4 GB of user mode
927             // address space.  It is remotely that those allocations could have succeeded,
928             // though I couldn't reproduce that.  In either case, that means we should continue
929             // throwing an OOM instead of an ArgumentOutOfRangeException for "negative" amounts of memory.
930             UIntPtr numBytes;
931 #if BIT64
932             numBytes = new UIntPtr(unchecked((ulong)cb.ToInt64()));
933 #else // 32
934             numBytes = new UIntPtr(unchecked((uint)cb.ToInt32()));
935 #endif
936
937             IntPtr pNewMem = Win32Native.LocalAlloc_NoSafeHandle(LMEM_FIXED, unchecked(numBytes));
938             if (pNewMem == IntPtr.Zero)
939             {
940                 throw new OutOfMemoryException();
941             }
942
943             return pNewMem;
944         }
945
946         public static IntPtr AllocHGlobal(int cb) => AllocHGlobal((IntPtr)cb);
947
948         public static void FreeHGlobal(IntPtr hglobal)
949         {
950             if (!IsWin32Atom(hglobal))
951             {
952                 if (IntPtr.Zero != Win32Native.LocalFree(hglobal))
953                 {
954                     ThrowExceptionForHR(GetHRForLastWin32Error());
955                 }
956             }
957         }
958
959         public static IntPtr ReAllocHGlobal(IntPtr pv, IntPtr cb)
960         {
961             IntPtr pNewMem = Win32Native.LocalReAlloc(pv, cb, LMEM_MOVEABLE);
962             if (pNewMem == IntPtr.Zero)
963             {
964                 throw new OutOfMemoryException();
965             }
966
967             return pNewMem;
968         }
969     
970         public static unsafe IntPtr StringToHGlobalAnsi(string s)
971         {
972             if (s == null)
973             {
974                 return IntPtr.Zero;
975             }
976
977             int nb = (s.Length + 1) * SystemMaxDBCSCharSize;
978
979             // Overflow checking
980             if (nb < s.Length)
981             {
982                 throw new ArgumentOutOfRangeException(nameof(s));
983             }
984
985             UIntPtr len = new UIntPtr((uint)nb);
986             IntPtr hglobal = Win32Native.LocalAlloc_NoSafeHandle(LMEM_FIXED, len);
987             if (hglobal == IntPtr.Zero)
988             {
989                 throw new OutOfMemoryException();
990             }
991
992             s.ConvertToAnsi((byte*)hglobal, nb, false, false);
993             return hglobal;
994         }
995
996         public static unsafe IntPtr StringToHGlobalUni(string s)
997         {
998             if (s == null)
999             {
1000                 return IntPtr.Zero;
1001             }
1002
1003             int nb = (s.Length + 1) * 2;
1004
1005             // Overflow checking
1006             if (nb < s.Length)
1007             {
1008                 throw new ArgumentOutOfRangeException(nameof(s));
1009             }
1010
1011             UIntPtr len = new UIntPtr((uint)nb);
1012             IntPtr hglobal = Win32Native.LocalAlloc_NoSafeHandle(LMEM_FIXED, len);
1013             if (hglobal == IntPtr.Zero)
1014             {
1015                 throw new OutOfMemoryException();
1016             }
1017
1018             fixed (char* firstChar = s)
1019             {
1020                 string.wstrcpy((char*)hglobal, firstChar, s.Length + 1);
1021             }
1022             return hglobal;
1023         }
1024
1025         public static IntPtr StringToHGlobalAuto(string s)
1026         {
1027             // Ansi platforms are no longer supported
1028             return StringToHGlobalUni(s);
1029         }
1030
1031 #if FEATURE_COMINTEROP
1032         /// <summary>
1033         /// Converts the CLR exception to an HRESULT. This function also sets
1034         /// up an IErrorInfo for the exception.
1035         /// </summary>
1036         [MethodImpl(MethodImplOptions.InternalCall)]
1037         public static extern int GetHRForException(Exception e);
1038
1039         /// <summary>
1040         /// Converts the CLR exception to an HRESULT. This function also sets
1041         /// up an IErrorInfo for the exception.
1042         /// This function is only used in WinRT and converts ObjectDisposedException
1043         /// to RO_E_CLOSED
1044         /// </summary>
1045         [MethodImpl(MethodImplOptions.InternalCall)]
1046         internal static extern int GetHRForException_WinRT(Exception e);
1047
1048         /// <summary>
1049         /// Given a managed object that wraps an ITypeInfo, return its name.
1050         /// </summary>
1051         public static string GetTypeInfoName(ITypeInfo typeInfo)
1052         {
1053             if (typeInfo == null)
1054             {
1055                 throw new ArgumentNullException(nameof(typeInfo));
1056             }
1057
1058             typeInfo.GetDocumentation(-1, out string strTypeLibName, out _, out _, out _);
1059             return strTypeLibName;
1060         }
1061
1062         // This method is identical to Type.GetTypeFromCLSID. Since it's interop specific, we expose it
1063         // on Marshal for more consistent API surface.
1064         public static Type GetTypeFromCLSID(Guid clsid) => RuntimeType.GetTypeFromCLSIDImpl(clsid, null, throwOnError: false);
1065
1066         /// <summary>
1067         /// Return the IUnknown* for an Object if the current context is the one
1068         /// where the RCW was first seen. Will return null otherwise.
1069         /// </summary>
1070         public static IntPtr /* IUnknown* */ GetIUnknownForObject(object o)
1071         {
1072             return GetIUnknownForObjectNative(o, false);
1073         }
1074
1075         [MethodImpl(MethodImplOptions.InternalCall)]
1076         private static extern IntPtr /* IUnknown* */ GetIUnknownForObjectNative(object o, bool onlyInContext);
1077
1078         /// <summary>
1079         /// Return the raw IUnknown* for a COM Object not related to current.
1080         /// Does not call AddRef.
1081         /// </summary>
1082         [MethodImpl(MethodImplOptions.InternalCall)]
1083         internal static extern IntPtr /* IUnknown* */ GetRawIUnknownForComObjectNoAddRef(object o);
1084 #endif // FEATURE_COMINTEROP
1085
1086         public static IntPtr /* IDispatch */ GetIDispatchForObject(object o) => throw new PlatformNotSupportedException();
1087
1088 #if FEATURE_COMINTEROP
1089         /// <summary>
1090         /// Return the IUnknown* representing the interface for the Object.
1091         /// Object o should support Type T
1092         /// </summary>
1093         public static IntPtr /* IUnknown* */ GetComInterfaceForObject(object o, Type T)
1094         {
1095             return GetComInterfaceForObjectNative(o, T, false, true);
1096         }
1097
1098         public static IntPtr GetComInterfaceForObject<T, TInterface>(T o) => GetComInterfaceForObject(o, typeof(TInterface));
1099
1100         /// <summary>
1101         /// Return the IUnknown* representing the interface for the Object.
1102         /// Object o should support Type T, it refer the value of mode to
1103         /// invoke customized QueryInterface or not.
1104         /// </summary>
1105         public static IntPtr /* IUnknown* */ GetComInterfaceForObject(object o, Type T, CustomQueryInterfaceMode mode)
1106         {
1107             bool bEnableCustomizedQueryInterface = ((mode == CustomQueryInterfaceMode.Allow) ? true : false);
1108             return GetComInterfaceForObjectNative(o, T, false, bEnableCustomizedQueryInterface);
1109         }
1110
1111         [MethodImpl(MethodImplOptions.InternalCall)]
1112         private static extern IntPtr /* IUnknown* */ GetComInterfaceForObjectNative(object o, Type t, bool onlyInContext, bool fEnalbeCustomizedQueryInterface);
1113
1114         [MethodImpl(MethodImplOptions.InternalCall)]
1115         public static extern object GetObjectForIUnknown(IntPtr /* IUnknown* */ pUnk);
1116
1117         /// <summary>
1118         /// Return a unique Object given an IUnknown.  This ensures that you receive a fresh
1119         /// object (we will not look in the cache to match up this IUnknown to an already
1120         /// existing object). This is useful in cases where you want to be able to call
1121         /// ReleaseComObject on a RCW and not worry about other active uses ofsaid RCW.
1122         /// </summary>
1123         [MethodImpl(MethodImplOptions.InternalCall)]
1124         public static extern object GetUniqueObjectForIUnknown(IntPtr unknown);
1125
1126         /// <summary>
1127         /// Return an Object for IUnknown, using the Type T.
1128         /// Type T should be either a COM imported Type or a sub-type of COM imported Type
1129         /// </summary>
1130         [MethodImpl(MethodImplOptions.InternalCall)]
1131         public static extern object GetTypedObjectForIUnknown(IntPtr /* IUnknown* */ pUnk, Type t);
1132
1133         [MethodImpl(MethodImplOptions.InternalCall)]
1134         public static extern IntPtr CreateAggregatedObject(IntPtr pOuter, object o);
1135
1136         public static IntPtr CreateAggregatedObject<T>(IntPtr pOuter, T o)
1137         {
1138             return CreateAggregatedObject(pOuter, (object)o);
1139         }
1140
1141         [MethodImpl(MethodImplOptions.InternalCall)]
1142         public static extern void CleanupUnusedObjectsInCurrentContext();
1143
1144         [MethodImpl(MethodImplOptions.InternalCall)]
1145         public static extern bool AreComObjectsAvailableForCleanup();
1146
1147         /// <summary>
1148         /// Checks if the object is classic COM component.
1149         /// </summary>
1150         [MethodImpl(MethodImplOptions.InternalCall)]
1151         public static extern bool IsComObject(object o);
1152
1153 #endif // FEATURE_COMINTEROP
1154
1155         public static IntPtr AllocCoTaskMem(int cb)
1156         {
1157             IntPtr pNewMem = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)cb));
1158             if (pNewMem == IntPtr.Zero)
1159             {
1160                 throw new OutOfMemoryException();
1161             }
1162
1163             return pNewMem;
1164         }
1165
1166         public static unsafe IntPtr StringToCoTaskMemUni(string s)
1167         {
1168             if (s == null)
1169             {
1170                 return IntPtr.Zero;
1171             }
1172
1173             int nb = (s.Length + 1) * 2;
1174
1175             // Overflow checking
1176             if (nb < s.Length)
1177             {
1178                 throw new ArgumentOutOfRangeException(nameof(s));
1179             }
1180
1181             IntPtr hglobal = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)nb));
1182             if (hglobal == IntPtr.Zero)
1183             {
1184                 throw new OutOfMemoryException();
1185             }
1186
1187             fixed (char* firstChar = s)
1188             {
1189                 string.wstrcpy((char*)hglobal, firstChar, s.Length + 1);
1190             }
1191             return hglobal;
1192         }
1193
1194         public static unsafe IntPtr StringToCoTaskMemUTF8(string s)
1195         {
1196             if (s == null)
1197             {
1198                 return IntPtr.Zero;
1199             }
1200
1201             int nb = Encoding.UTF8.GetMaxByteCount(s.Length);
1202             IntPtr pMem = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)nb + 1));
1203             if (pMem == IntPtr.Zero)
1204             {
1205                 throw new OutOfMemoryException();
1206             }
1207
1208             fixed (char* firstChar = s)
1209             {
1210                 byte* pbMem = (byte*)pMem;
1211                 int nbWritten = Encoding.UTF8.GetBytes(firstChar, s.Length, pbMem, nb);
1212                 pbMem[nbWritten] = 0;
1213             }
1214             return pMem;
1215         }
1216
1217         public static IntPtr StringToCoTaskMemAuto(string s)
1218         {
1219             // Ansi platforms are no longer supported
1220             return StringToCoTaskMemUni(s);
1221         }
1222
1223         public static unsafe IntPtr StringToCoTaskMemAnsi(string s)
1224         {
1225             if (s == null)
1226             {
1227                 return IntPtr.Zero;
1228             }
1229
1230             int nb = (s.Length + 1) * SystemMaxDBCSCharSize;
1231
1232             // Overflow checking
1233             if (nb < s.Length)
1234             {
1235                 throw new ArgumentOutOfRangeException(nameof(s));
1236             }
1237
1238             IntPtr hglobal = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)nb));
1239             if (hglobal == IntPtr.Zero)
1240             {
1241                 throw new OutOfMemoryException();
1242             }
1243
1244             s.ConvertToAnsi((byte*)hglobal, nb, false, false);
1245             return hglobal;
1246         }
1247
1248         public static void FreeCoTaskMem(IntPtr ptr)
1249         {
1250             if (!IsWin32Atom(ptr))
1251             {
1252                 Win32Native.CoTaskMemFree(ptr);
1253             }
1254         }
1255
1256         public static IntPtr ReAllocCoTaskMem(IntPtr pv, int cb)
1257         {
1258             IntPtr pNewMem = Win32Native.CoTaskMemRealloc(pv, new UIntPtr((uint)cb));
1259             if (pNewMem == IntPtr.Zero && cb != 0)
1260             {
1261                 throw new OutOfMemoryException();
1262             }
1263
1264             return pNewMem;
1265         }
1266
1267         public static void FreeBSTR(IntPtr ptr)
1268         {
1269             if (!IsWin32Atom(ptr))
1270             {
1271                 Win32Native.SysFreeString(ptr);
1272             }
1273         }
1274
1275         public static IntPtr StringToBSTR(string s)
1276         {
1277             if (s == null)
1278             {
1279                 return IntPtr.Zero;
1280             }
1281
1282             // Overflow checking
1283             if (s.Length + 1 < s.Length)
1284             {
1285                 throw new ArgumentOutOfRangeException(nameof(s));
1286             }
1287
1288             IntPtr bstr = Win32Native.SysAllocStringLen(s, s.Length);
1289             if (bstr == IntPtr.Zero)
1290             {
1291                 throw new OutOfMemoryException();
1292             }
1293
1294             return bstr;
1295         }
1296
1297         public static string PtrToStringBSTR(IntPtr ptr)
1298         {
1299             return PtrToStringUni(ptr, (int)Win32Native.SysStringLen(ptr));
1300         }
1301
1302 #if FEATURE_COMINTEROP
1303         /// <summary>
1304         /// Release the COM component and if the reference hits 0 zombie this object.
1305         /// Further usage of this Object might throw an exception
1306         /// </summary>
1307         public static int ReleaseComObject(object o)
1308         {
1309             if (!(o is __ComObject co))
1310             {
1311                 throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(o));
1312             }
1313
1314             return co.ReleaseSelf();
1315         }
1316
1317         [MethodImpl(MethodImplOptions.InternalCall)]
1318         internal static extern int InternalReleaseComObject(object o);
1319
1320         /// <summary>
1321         /// Release the COM component and zombie this object.
1322         /// Further usage of this Object might throw an exception
1323         /// </summary>
1324         public static int FinalReleaseComObject(object o)
1325         {
1326             if (o == null)
1327             {
1328                 throw new ArgumentNullException(nameof(o));
1329             }
1330             if (!(o is __ComObject co))
1331             {
1332                 throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(o));
1333             }
1334
1335             co.FinalReleaseSelf();
1336             return 0;
1337         }
1338
1339         [MethodImpl(MethodImplOptions.InternalCall)]
1340         internal static extern void InternalFinalReleaseComObject(object o);
1341
1342         public static object GetComObjectData(object obj, object key)
1343         {
1344             if (obj == null)
1345             {
1346                 throw new ArgumentNullException(nameof(obj));
1347             }
1348             if (key == null)
1349             {
1350                 throw new ArgumentNullException(nameof(key));
1351             }
1352             if (!(obj is __ComObject co))
1353             {
1354                 throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(obj));
1355             }
1356             if (obj.GetType().IsWindowsRuntimeObject)
1357             {
1358                 throw new ArgumentException(SR.Argument_ObjIsWinRTObject, nameof(obj));
1359             }
1360
1361             // Retrieve the data from the __ComObject.
1362             return co.GetData(key);
1363         }
1364
1365         /// <summary>
1366         /// Sets data on the COM object. The data can only be set once for a given key
1367         /// and cannot be removed. This function returns true if the data has been added,
1368         /// false if the data could not be added because there already was data for the
1369         /// specified key.
1370         /// </summary>
1371         public static bool SetComObjectData(object obj, object key, object data)
1372         {
1373             if (obj == null)
1374             {
1375                 throw new ArgumentNullException(nameof(obj));
1376             }
1377             if (key == null)
1378             {
1379                 throw new ArgumentNullException(nameof(key));
1380             }
1381             if (!(obj is __ComObject co))
1382             {
1383                 throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(obj));
1384             }
1385             if (obj.GetType().IsWindowsRuntimeObject)
1386             {
1387                 throw new ArgumentException(SR.Argument_ObjIsWinRTObject, nameof(obj));
1388             }
1389
1390             // Retrieve the data from the __ComObject.
1391             return co.SetData(key, data);
1392         }
1393
1394         /// <summary>
1395         /// This method takes the given COM object and wraps it in an object
1396         /// of the specified type. The type must be derived from __ComObject.
1397         /// </summary>
1398         public static object CreateWrapperOfType(object o, Type t)
1399         {
1400             if (t == null)
1401             {
1402                 throw new ArgumentNullException(nameof(t));
1403             }
1404             if (!t.IsCOMObject)
1405             {
1406                 throw new ArgumentException(SR.Argument_TypeNotComObject, nameof(t));
1407             }
1408             if (t.IsGenericType)
1409             {
1410                 throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(t));
1411             }
1412             if (t.IsWindowsRuntimeObject)
1413             {
1414                 throw new ArgumentException(SR.Argument_TypeIsWinRTType, nameof(t));
1415             }
1416
1417             if (o == null)
1418             {
1419                 return null;
1420             }
1421
1422             if (!o.GetType().IsCOMObject)
1423             {
1424                 throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(o));
1425             }
1426             if (o.GetType().IsWindowsRuntimeObject)
1427             {
1428                 throw new ArgumentException(SR.Argument_ObjIsWinRTObject, nameof(o));
1429             }
1430
1431             // Check to see if we have nothing to do.
1432             if (o.GetType() == t)
1433             {
1434                 return o;
1435             }
1436
1437             // Check to see if we already have a cached wrapper for this type.
1438             object Wrapper = GetComObjectData(o, t);
1439             if (Wrapper == null)
1440             {
1441                 // Create the wrapper for the specified type.
1442                 Wrapper = InternalCreateWrapperOfType(o, t);
1443
1444                 // Attempt to cache the wrapper on the object.
1445                 if (!SetComObjectData(o, t, Wrapper))
1446                 {
1447                     // Another thead already cached the wrapper so use that one instead.
1448                     Wrapper = GetComObjectData(o, t);
1449                 }
1450             }
1451
1452             return Wrapper;
1453         }
1454
1455         public static TWrapper CreateWrapperOfType<T, TWrapper>(T o)
1456         {
1457             return (TWrapper)CreateWrapperOfType(o, typeof(TWrapper));
1458         }
1459
1460         [MethodImpl(MethodImplOptions.InternalCall)]
1461         private static extern object InternalCreateWrapperOfType(object o, Type t);
1462
1463         /// <summary>
1464         /// check if the type is visible from COM.
1465         /// </summary>
1466         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1467         public static extern bool IsTypeVisibleFromCom(Type t);
1468
1469         [MethodImpl(MethodImplOptions.InternalCall)]
1470         public static extern int /* HRESULT */ QueryInterface(IntPtr /* IUnknown */ pUnk, ref Guid iid, out IntPtr ppv);
1471
1472         [MethodImpl(MethodImplOptions.InternalCall)]
1473         public static extern int /* ULONG */ AddRef(IntPtr /* IUnknown */ pUnk);
1474
1475         [MethodImpl(MethodImplOptions.InternalCall)]
1476         public static extern int /* ULONG */ Release(IntPtr /* IUnknown */ pUnk);
1477
1478         [MethodImpl(MethodImplOptions.InternalCall)]
1479         public static extern void GetNativeVariantForObject(object obj, /* VARIANT * */ IntPtr pDstNativeVariant);
1480
1481         public static void GetNativeVariantForObject<T>(T obj, IntPtr pDstNativeVariant)
1482         {
1483             GetNativeVariantForObject((object)obj, pDstNativeVariant);
1484         }
1485
1486         [MethodImpl(MethodImplOptions.InternalCall)]
1487         public static extern object GetObjectForNativeVariant(/* VARIANT * */ IntPtr pSrcNativeVariant);
1488
1489         public static T GetObjectForNativeVariant<T>(IntPtr pSrcNativeVariant)
1490         {
1491             return (T)GetObjectForNativeVariant(pSrcNativeVariant);
1492         }
1493
1494         [MethodImpl(MethodImplOptions.InternalCall)]
1495         public static extern object[] GetObjectsForNativeVariants(/* VARIANT * */ IntPtr aSrcNativeVariant, int cVars);
1496
1497         public static T[] GetObjectsForNativeVariants<T>(IntPtr aSrcNativeVariant, int cVars)
1498         {
1499             object[] objects = GetObjectsForNativeVariants(aSrcNativeVariant, cVars);
1500             T[] result = null;
1501
1502             if (objects != null)
1503             {
1504                 result = new T[objects.Length];
1505                 Array.Copy(objects, result, objects.Length);
1506             }
1507
1508             return result;
1509         }
1510
1511         /// <summary>
1512         /// <para>Returns the first valid COM slot that GetMethodInfoForSlot will work on
1513         /// This will be 3 for IUnknown based interfaces and 7 for IDispatch based interfaces. </para>
1514         /// </summary>
1515         [MethodImpl(MethodImplOptions.InternalCall)]
1516         public static extern int GetStartComSlot(Type t);
1517
1518         /// <summary>
1519         /// <para>Returns the last valid COM slot that GetMethodInfoForSlot will work on. </para>
1520         /// </summary>
1521         [MethodImpl(MethodImplOptions.InternalCall)]
1522         public static extern int GetEndComSlot(Type t);
1523 #endif // FEATURE_COMINTEROP
1524
1525         /// <summary>
1526         /// Generates a GUID for the specified type. If the type has a GUID in the
1527         /// metadata then it is returned otherwise a stable guid is generated based
1528         /// on the fully qualified name of the type.
1529         /// </summary>
1530         public static Guid GenerateGuidForType(Type type) => type.GUID;
1531
1532         /// <summary>
1533         /// This method generates a PROGID for the specified type. If the type has
1534         /// a PROGID in the metadata then it is returned otherwise a stable PROGID
1535         /// is generated based on the fully qualified name of the type.
1536         /// </summary>
1537         public static string GenerateProgIdForType(Type type)
1538         {
1539             if (type == null)
1540             {
1541                 throw new ArgumentNullException(nameof(type));
1542             }
1543             if (type.IsImport)
1544             {
1545                 throw new ArgumentException(SR.Argument_TypeMustNotBeComImport, nameof(type));
1546             }
1547             if (type.IsGenericType)
1548             {
1549                 throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(type));
1550             }
1551
1552             IList<CustomAttributeData> cas = CustomAttributeData.GetCustomAttributes(type);
1553             for (int i = 0; i < cas.Count; i++)
1554             {
1555                 if (cas[i].Constructor.DeclaringType == typeof(ProgIdAttribute))
1556                 {
1557                     // Retrieve the PROGID string from the ProgIdAttribute.
1558                     IList<CustomAttributeTypedArgument> caConstructorArgs = cas[i].ConstructorArguments;
1559                     Debug.Assert(caConstructorArgs.Count == 1, "caConstructorArgs.Count == 1");
1560
1561                     CustomAttributeTypedArgument progIdConstructorArg = caConstructorArgs[0];
1562                     Debug.Assert(progIdConstructorArg.ArgumentType == typeof(string), "progIdConstructorArg.ArgumentType == typeof(String)");
1563
1564                     string strProgId = (string)progIdConstructorArg.Value;
1565
1566                     if (strProgId == null)
1567                         strProgId = string.Empty;
1568
1569                     return strProgId;
1570                 }
1571             }
1572
1573             // If there is no prog ID attribute then use the full name of the type as the prog id.
1574             return type.FullName;
1575         }
1576
1577 #if FEATURE_COMINTEROP
1578         public static object BindToMoniker(string monikerName)
1579         {
1580             CreateBindCtx(0, out IBindCtx bindctx);
1581
1582             MkParseDisplayName(bindctx, monikerName, out _, out IMoniker pmoniker);
1583             BindMoniker(pmoniker, 0, ref IID_IUnknown, out object obj);
1584
1585             return obj;
1586         }
1587
1588         [DllImport(Interop.Libraries.Ole32, PreserveSig = false)]
1589         private static extern void CreateBindCtx(uint reserved, out IBindCtx ppbc);
1590
1591         [DllImport(Interop.Libraries.Ole32, PreserveSig = false)]
1592         private static extern void MkParseDisplayName(IBindCtx pbc, [MarshalAs(UnmanagedType.LPWStr)] string szUserName, out uint pchEaten, out IMoniker ppmk);
1593
1594         [DllImport(Interop.Libraries.Ole32, PreserveSig = false)]
1595         private static extern void BindMoniker(IMoniker pmk, uint grfOpt, ref Guid iidResult, [MarshalAs(UnmanagedType.Interface)] out object ppvResult);
1596
1597         /// <summary>
1598         /// Private method called from EE upon use of license/ICF2 marshaling.
1599         /// </summary>
1600         private static IntPtr LoadLicenseManager()
1601         {
1602             Type t = Type.GetType("System.ComponentModel.LicenseManager, System", throwOnError: true);
1603             return t.TypeHandle.Value;
1604         }
1605
1606         [MethodImpl(MethodImplOptions.InternalCall)]
1607         public static extern void ChangeWrapperHandleStrength(object otp, bool fIsWeak);
1608
1609         [MethodImpl(MethodImplOptions.InternalCall)]
1610         internal static extern void InitializeWrapperForWinRT(object o, ref IntPtr pUnk);
1611
1612 #if FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION
1613         [MethodImpl(MethodImplOptions.InternalCall)]
1614         internal static extern void InitializeManagedWinRTFactoryObject(object o, RuntimeType runtimeClassType);
1615 #endif
1616
1617         /// <summary>
1618         /// Create activation factory and wraps it with a unique RCW.
1619         /// </summary>
1620         [MethodImpl(MethodImplOptions.InternalCall)]
1621         internal static extern object GetNativeActivationFactory(Type type);
1622
1623 #endif // FEATURE_COMINTEROP
1624
1625         public static Delegate GetDelegateForFunctionPointer(IntPtr ptr, Type t)
1626         {
1627             if (ptr == IntPtr.Zero)
1628             {
1629                 throw new ArgumentNullException(nameof(ptr));
1630             }
1631             if (t == null)
1632             {
1633                 throw new ArgumentNullException(nameof(t));
1634             }
1635             if (!(t is RuntimeType))
1636             {
1637                 throw new ArgumentException(SR.Argument_MustBeRuntimeType, nameof(t));
1638             }
1639             if (t.IsGenericType)
1640             {
1641                 throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(t));
1642             }
1643
1644             Type c = t.BaseType;
1645             if (c == null || (c != typeof(Delegate) && c != typeof(MulticastDelegate)))
1646             {
1647                 throw new ArgumentException(SR.Arg_MustBeDelegate, nameof(t));
1648             }
1649
1650             return GetDelegateForFunctionPointerInternal(ptr, t);
1651         }
1652
1653         public static TDelegate GetDelegateForFunctionPointer<TDelegate>(IntPtr ptr)
1654         {
1655             return (TDelegate)(object)GetDelegateForFunctionPointer(ptr, typeof(TDelegate));
1656         }
1657
1658         [MethodImpl(MethodImplOptions.InternalCall)]
1659         internal static extern Delegate GetDelegateForFunctionPointerInternal(IntPtr ptr, Type t);
1660
1661         public static IntPtr GetFunctionPointerForDelegate(Delegate d)
1662         {
1663             if (d == null)
1664             {
1665                 throw new ArgumentNullException(nameof(d));
1666             }
1667
1668             return GetFunctionPointerForDelegateInternal(d);
1669         }
1670
1671         public static IntPtr GetFunctionPointerForDelegate<TDelegate>(TDelegate d)
1672         {
1673             return GetFunctionPointerForDelegate((Delegate)(object)d);
1674         }
1675
1676         [MethodImpl(MethodImplOptions.InternalCall)]
1677         internal static extern IntPtr GetFunctionPointerForDelegateInternal(Delegate d);
1678
1679         public static IntPtr SecureStringToBSTR(SecureString s)
1680         {
1681             if (s == null)
1682             {
1683                 throw new ArgumentNullException(nameof(s));
1684             }
1685
1686             return s.MarshalToBSTR();
1687         }
1688
1689         public static IntPtr SecureStringToCoTaskMemAnsi(SecureString s)
1690         {
1691             if (s == null)
1692             {
1693                 throw new ArgumentNullException(nameof(s));
1694             }
1695
1696             return s.MarshalToString(globalAlloc: false, unicode: false);
1697         }
1698
1699         public static IntPtr SecureStringToCoTaskMemUnicode(SecureString s)
1700         {
1701             if (s == null)
1702             {
1703                 throw new ArgumentNullException(nameof(s));
1704             }
1705
1706             return s.MarshalToString(globalAlloc: false, unicode: true);
1707         }
1708         
1709         public static void ZeroFreeBSTR(IntPtr s)
1710         {
1711             RuntimeImports.RhZeroMemory(s, (UIntPtr)(Win32Native.SysStringLen(s) * 2));
1712             FreeBSTR(s);
1713         }
1714
1715         public static void ZeroFreeCoTaskMemAnsi(IntPtr s)
1716         {
1717             RuntimeImports.RhZeroMemory(s, (UIntPtr)(Win32Native.lstrlenA(s)));
1718             FreeCoTaskMem(s);
1719         }
1720
1721         public static void ZeroFreeCoTaskMemUnicode(IntPtr s)
1722         {
1723             RuntimeImports.RhZeroMemory(s, (UIntPtr)(Win32Native.lstrlenW(s) * 2));
1724             FreeCoTaskMem(s);
1725         }
1726
1727         public static unsafe void ZeroFreeCoTaskMemUTF8(IntPtr s)
1728         {
1729             RuntimeImports.RhZeroMemory(s, (UIntPtr)System.StubHelpers.StubHelpers.strlen((sbyte*)s));
1730             FreeCoTaskMem(s);
1731         }
1732
1733         public static IntPtr SecureStringToGlobalAllocAnsi(SecureString s)
1734         {
1735             if (s == null)
1736             {
1737                 throw new ArgumentNullException(nameof(s));
1738             }
1739
1740             return s.MarshalToString(globalAlloc: true, unicode: false);
1741         }
1742
1743         public static IntPtr SecureStringToGlobalAllocUnicode(SecureString s)
1744         {
1745             if (s == null)
1746             {
1747                 throw new ArgumentNullException(nameof(s));
1748             }
1749
1750             return s.MarshalToString(globalAlloc: true, unicode: true); ;
1751         }
1752
1753         public static void ZeroFreeGlobalAllocAnsi(IntPtr s)
1754         {
1755             RuntimeImports.RhZeroMemory(s, (UIntPtr)(Win32Native.lstrlenA(s)));
1756             FreeHGlobal(s);
1757         }
1758
1759         public static void ZeroFreeGlobalAllocUnicode(IntPtr s)
1760         {
1761             RuntimeImports.RhZeroMemory(s, (UIntPtr)(Win32Native.lstrlenW(s) * 2));
1762             FreeHGlobal(s);
1763         }
1764     }
1765 }