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.
5 using System.Collections.Generic;
6 using System.Reflection;
7 using System.Reflection.Emit;
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;
17 namespace System.Runtime.InteropServices
19 public enum CustomQueryInterfaceMode
26 /// This class contains methods that are mainly used to marshal between unmanaged
27 /// and managed types.
29 public static partial class Marshal
31 #if FEATURE_COMINTEROP
32 internal static Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");
33 #endif //FEATURE_COMINTEROP
35 private const int LMEM_FIXED = 0;
36 private const int LMEM_MOVEABLE = 2;
38 private const long HiWordMask = unchecked((long)0xffffffffffff0000L);
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)
52 long lPtr = (long)ptr;
53 return 0 == (lPtr & HiWordMask);
58 /// The default character size for the system. This is always 2 because
59 /// the framework only runs on UTF-16 systems.
61 public static readonly int SystemDefaultCharSize = 2;
64 /// The max DBCS character size for the system.
66 public static readonly int SystemMaxDBCSCharSize = GetSystemMaxDBCSCharSize();
69 /// Helper method to retrieve the system's maximum DBCS character size.
71 [MethodImpl(MethodImplOptions.InternalCall)]
72 private static extern int GetSystemMaxDBCSCharSize();
74 public static unsafe string PtrToStringAnsi(IntPtr ptr)
76 if (IntPtr.Zero == ptr)
80 else if (IsWin32Atom(ptr))
85 int nb = Win32Native.lstrlenA(ptr);
91 return new string((sbyte*)ptr);
94 public static unsafe string PtrToStringAnsi(IntPtr ptr, int len)
96 if (ptr == IntPtr.Zero)
98 throw new ArgumentNullException(nameof(ptr));
102 throw new ArgumentException(null, nameof(len));
105 return new string((sbyte*)ptr, 0, len);
108 public static unsafe string PtrToStringUni(IntPtr ptr, int len)
110 if (ptr == IntPtr.Zero)
112 throw new ArgumentNullException(nameof(ptr));
116 throw new ArgumentException(SR.ArgumentOutOfRange_NeedNonNegNum, nameof(len));
119 return new string((char*)ptr, 0, len);
122 public static string PtrToStringAuto(IntPtr ptr, int len)
124 // Ansi platforms are no longer supported
125 return PtrToStringUni(ptr, len);
128 public static unsafe string PtrToStringUni(IntPtr ptr)
130 if (IntPtr.Zero == ptr)
134 else if (IsWin32Atom(ptr))
139 return new string((char*)ptr);
142 public static string PtrToStringAuto(IntPtr ptr)
144 // Ansi platforms are no longer supported
145 return PtrToStringUni(ptr);
148 public static unsafe string PtrToStringUTF8(IntPtr ptr)
150 if (IntPtr.Zero == ptr)
155 int nbBytes = StubHelpers.StubHelpers.strlen((sbyte*)ptr.ToPointer());
156 return PtrToStringUTF8(ptr, nbBytes);
159 public static unsafe string PtrToStringUTF8(IntPtr ptr, int byteLen)
163 throw new ArgumentOutOfRangeException(nameof(byteLen), SR.ArgumentOutOfRange_NeedNonNegNum);
165 else if (IntPtr.Zero == ptr)
169 else if (IsWin32Atom(ptr))
173 else if (byteLen == 0)
178 byte* pByte = (byte*)ptr.ToPointer();
179 return Encoding.UTF8.GetString(pByte, byteLen);
182 public static int SizeOf(object structure)
184 if (structure == null)
186 throw new ArgumentNullException(nameof(structure));
189 return SizeOfHelper(structure.GetType(), true);
192 public static int SizeOf<T>(T structure) => SizeOf((object)structure);
194 public static int SizeOf(Type t)
198 throw new ArgumentNullException(nameof(t));
200 if (!(t is RuntimeType))
202 throw new ArgumentException(SR.Argument_MustBeRuntimeType, nameof(t));
206 throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(t));
209 return SizeOfHelper(t, throwIfNotMarshalable: true);
212 public static int SizeOf<T>() => SizeOf(typeof(T));
214 [MethodImpl(MethodImplOptions.InternalCall)]
215 internal static extern int SizeOfHelper(Type t, bool throwIfNotMarshalable);
217 public static IntPtr OffsetOf(Type t, string fieldName)
221 throw new ArgumentNullException(nameof(t));
224 FieldInfo f = t.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
227 throw new ArgumentException(SR.Format(SR.Argument_OffsetOfFieldNotFound, t.FullName), nameof(fieldName));
230 if (!(f is RtFieldInfo rtField))
232 throw new ArgumentException(SR.Argument_MustBeRuntimeFieldInfo, nameof(fieldName));
235 return OffsetOfHelper(rtField);
238 public static IntPtr OffsetOf<T>(string fieldName) => OffsetOf(typeof(T), fieldName);
240 [MethodImpl(MethodImplOptions.InternalCall)]
241 private static extern IntPtr OffsetOfHelper(IRuntimeFieldInfo f);
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.
248 [MethodImpl(MethodImplOptions.InternalCall)]
249 public static extern IntPtr UnsafeAddrOfPinnedArrayElement(Array arr, int index);
251 public static IntPtr UnsafeAddrOfPinnedArrayElement<T>(T[] arr, int index)
253 return UnsafeAddrOfPinnedArrayElement((Array)arr, index);
256 public static void Copy(int[] source, int startIndex, IntPtr destination, int length)
258 CopyToNative(source, startIndex, destination, length);
261 public static void Copy(char[] source, int startIndex, IntPtr destination, int length)
263 CopyToNative(source, startIndex, destination, length);
266 public static void Copy(short[] source, int startIndex, IntPtr destination, int length)
268 CopyToNative(source, startIndex, destination, length);
271 public static void Copy(long[] source, int startIndex, IntPtr destination, int length)
273 CopyToNative(source, startIndex, destination, length);
276 public static void Copy(float[] source, int startIndex, IntPtr destination, int length)
278 CopyToNative(source, startIndex, destination, length);
281 public static void Copy(double[] source, int startIndex, IntPtr destination, int length)
283 CopyToNative(source, startIndex, destination, length);
286 public static void Copy(byte[] source, int startIndex, IntPtr destination, int length)
288 CopyToNative(source, startIndex, destination, length);
291 public static void Copy(IntPtr[] source, int startIndex, IntPtr destination, int length)
293 CopyToNative(source, startIndex, destination, length);
296 [MethodImpl(MethodImplOptions.InternalCall)]
297 private static extern void CopyToNative(object source, int startIndex, IntPtr destination, int length);
299 public static void Copy(IntPtr source, int[] destination, int startIndex, int length)
301 CopyToManaged(source, destination, startIndex, length);
304 public static void Copy(IntPtr source, char[] destination, int startIndex, int length)
306 CopyToManaged(source, destination, startIndex, length);
309 public static void Copy(IntPtr source, short[] destination, int startIndex, int length)
311 CopyToManaged(source, destination, startIndex, length);
314 public static void Copy(IntPtr source, long[] destination, int startIndex, int length)
316 CopyToManaged(source, destination, startIndex, length);
319 public static void Copy(IntPtr source, float[] destination, int startIndex, int length)
321 CopyToManaged(source, destination, startIndex, length);
324 public static void Copy(IntPtr source, double[] destination, int startIndex, int length)
326 CopyToManaged(source, destination, startIndex, length);
329 public static void Copy(IntPtr source, byte[] destination, int startIndex, int length)
331 CopyToManaged(source, destination, startIndex, length);
334 public static void Copy(IntPtr source, IntPtr[] destination, int startIndex, int length)
336 CopyToManaged(source, destination, startIndex, length);
339 [MethodImpl(MethodImplOptions.InternalCall)]
340 private static extern void CopyToManaged(IntPtr source, object destination, int startIndex, int length);
342 public static byte ReadByte(object ptr, int ofs)
344 return ReadValueSlow(ptr, ofs, (IntPtr nativeHome, int offset) => ReadByte(nativeHome, offset));
347 public static unsafe byte ReadByte(IntPtr ptr, int ofs)
351 byte* addr = (byte*)ptr + ofs;
354 catch (NullReferenceException)
356 // this method is documented to throw AccessViolationException on any AV
357 throw new AccessViolationException();
361 public static byte ReadByte(IntPtr ptr) => ReadByte(ptr, 0);
363 public static short ReadInt16(object ptr, int ofs)
365 return ReadValueSlow(ptr, ofs, (IntPtr nativeHome, int offset) => ReadInt16(nativeHome, offset));
368 public static unsafe short ReadInt16(IntPtr ptr, int ofs)
372 byte* addr = (byte*)ptr + ofs;
373 if ((unchecked((int)addr) & 0x1) == 0)
376 return *((short*)addr);
382 byte* valPtr = (byte*)&val;
388 catch (NullReferenceException)
390 // this method is documented to throw AccessViolationException on any AV
391 throw new AccessViolationException();
395 public static short ReadInt16(IntPtr ptr) => ReadInt16(ptr, 0);
397 public static int ReadInt32(object ptr, int ofs)
399 return ReadValueSlow(ptr, ofs, (IntPtr nativeHome, int offset) => ReadInt32(nativeHome, offset));
402 public static unsafe int ReadInt32(IntPtr ptr, int ofs)
406 byte* addr = (byte*)ptr + ofs;
407 if ((unchecked((int)addr) & 0x3) == 0)
410 return *((int*)addr);
416 byte* valPtr = (byte*)&val;
424 catch (NullReferenceException)
426 // this method is documented to throw AccessViolationException on any AV
427 throw new AccessViolationException();
431 public static int ReadInt32(IntPtr ptr) => ReadInt32(ptr, 0);
433 public static IntPtr ReadIntPtr(object ptr, int ofs)
436 return (IntPtr)ReadInt64(ptr, ofs);
438 return (IntPtr)ReadInt32(ptr, ofs);
442 public static IntPtr ReadIntPtr(IntPtr ptr, int ofs)
445 return (IntPtr)ReadInt64(ptr, ofs);
447 return (IntPtr)ReadInt32(ptr, ofs);
451 public static IntPtr ReadIntPtr(IntPtr ptr) => ReadIntPtr(ptr, 0);
453 public static long ReadInt64([MarshalAs(UnmanagedType.AsAny), In] object ptr, int ofs)
455 return ReadValueSlow(ptr, ofs, (IntPtr nativeHome, int offset) => ReadInt64(nativeHome, offset));
458 public static unsafe long ReadInt64(IntPtr ptr, int ofs)
462 byte* addr = (byte*)ptr + ofs;
463 if ((unchecked((int)addr) & 0x7) == 0)
466 return *((long*)addr);
472 byte* valPtr = (byte*)&val;
484 catch (NullReferenceException)
486 // this method is documented to throw AccessViolationException on any AV
487 throw new AccessViolationException();
491 public static long ReadInt64(IntPtr ptr) => ReadInt64(ptr, 0);
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)
501 // Consumers of this method are documented to throw AccessViolationException on any AV
504 throw new AccessViolationException();
508 (int)AsAnyMarshaler.AsAnyFlags.In |
509 (int)AsAnyMarshaler.AsAnyFlags.IsAnsi |
510 (int)AsAnyMarshaler.AsAnyFlags.IsBestFit;
512 MngdNativeArrayMarshaler.MarshalerState nativeArrayMarshalerState = new MngdNativeArrayMarshaler.MarshalerState();
513 AsAnyMarshaler marshaler = new AsAnyMarshaler(new IntPtr(&nativeArrayMarshalerState));
515 IntPtr pNativeHome = IntPtr.Zero;
519 pNativeHome = marshaler.ConvertToNative(ptr, Flags);
520 return readValueHelper(pNativeHome, ofs);
524 marshaler.ClearNative(pNativeHome);
528 public static unsafe void WriteByte(IntPtr ptr, int ofs, byte val)
532 byte* addr = (byte*)ptr + ofs;
535 catch (NullReferenceException)
537 // this method is documented to throw AccessViolationException on any AV
538 throw new AccessViolationException();
542 public static void WriteByte(object ptr, int ofs, byte val)
544 WriteValueSlow(ptr, ofs, val, (IntPtr nativeHome, int offset, byte value) => WriteByte(nativeHome, offset, value));
547 public static void WriteByte(IntPtr ptr, byte val) => WriteByte(ptr, 0, val);
549 public static unsafe void WriteInt16(IntPtr ptr, int ofs, short val)
553 byte* addr = (byte*)ptr + ofs;
554 if ((unchecked((int)addr) & 0x1) == 0)
557 *((short*)addr) = val;
562 byte* valPtr = (byte*)&val;
567 catch (NullReferenceException)
569 // this method is documented to throw AccessViolationException on any AV
570 throw new AccessViolationException();
574 public static void WriteInt16(object ptr, int ofs, short val)
576 WriteValueSlow(ptr, ofs, val, (IntPtr nativeHome, int offset, short value) => Marshal.WriteInt16(nativeHome, offset, value));
579 public static void WriteInt16(IntPtr ptr, short val) => WriteInt16(ptr, 0, val);
581 public static void WriteInt16(IntPtr ptr, int ofs, char val) => WriteInt16(ptr, ofs, (short)val);
583 public static void WriteInt16([In, Out]object ptr, int ofs, char val) => WriteInt16(ptr, ofs, (short)val);
585 public static void WriteInt16(IntPtr ptr, char val) => WriteInt16(ptr, 0, (short)val);
587 public static unsafe void WriteInt32(IntPtr ptr, int ofs, int val)
591 byte* addr = (byte*)ptr + ofs;
592 if ((unchecked((int)addr) & 0x3) == 0)
600 byte* valPtr = (byte*)&val;
607 catch (NullReferenceException)
609 // this method is documented to throw AccessViolationException on any AV
610 throw new AccessViolationException();
614 public static void WriteInt32(object ptr, int ofs, int val)
616 WriteValueSlow(ptr, ofs, val, (IntPtr nativeHome, int offset, int value) => Marshal.WriteInt32(nativeHome, offset, value));
619 public static void WriteInt32(IntPtr ptr, int val) => WriteInt32(ptr, 0, val);
621 public static void WriteIntPtr(IntPtr ptr, int ofs, IntPtr val)
624 WriteInt64(ptr, ofs, (long)val);
626 WriteInt32(ptr, ofs, (int)val);
630 public static void WriteIntPtr(object ptr, int ofs, IntPtr val)
633 WriteInt64(ptr, ofs, (long)val);
635 WriteInt32(ptr, ofs, (int)val);
639 public static void WriteIntPtr(IntPtr ptr, IntPtr val) => WriteIntPtr(ptr, 0, val);
641 public static unsafe void WriteInt64(IntPtr ptr, int ofs, long val)
645 byte* addr = (byte*)ptr + ofs;
646 if ((unchecked((int)addr) & 0x7) == 0)
649 *((long*)addr) = val;
654 byte* valPtr = (byte*)&val;
665 catch (NullReferenceException)
667 // this method is documented to throw AccessViolationException on any AV
668 throw new AccessViolationException();
672 public static void WriteInt64(object ptr, int ofs, long val)
674 WriteValueSlow(ptr, ofs, val, (IntPtr nativeHome, int offset, long value) => Marshal.WriteInt64(nativeHome, offset, value));
677 public static void WriteInt64(IntPtr ptr, long val) => WriteInt64(ptr, 0, val);
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.
684 private static unsafe void WriteValueSlow<T>(object ptr, int ofs, T val, Action<IntPtr, int, T> writeValueHelper)
686 // Consumers of this method are documented to throw AccessViolationException on any AV
689 throw new AccessViolationException();
693 (int)AsAnyMarshaler.AsAnyFlags.In |
694 (int)AsAnyMarshaler.AsAnyFlags.Out |
695 (int)AsAnyMarshaler.AsAnyFlags.IsAnsi |
696 (int)AsAnyMarshaler.AsAnyFlags.IsBestFit;
698 MngdNativeArrayMarshaler.MarshalerState nativeArrayMarshalerState = new MngdNativeArrayMarshaler.MarshalerState();
699 AsAnyMarshaler marshaler = new AsAnyMarshaler(new IntPtr(&nativeArrayMarshalerState));
701 IntPtr pNativeHome = IntPtr.Zero;
705 pNativeHome = marshaler.ConvertToNative(ptr, Flags);
706 writeValueHelper(pNativeHome, ofs, val);
707 marshaler.ConvertToManaged(ptr, pNativeHome);
711 marshaler.ClearNative(pNativeHome);
715 [MethodImpl(MethodImplOptions.InternalCall)]
716 public static extern int GetLastWin32Error();
718 [MethodImpl(MethodImplOptions.InternalCall)]
719 internal static extern void SetLastWin32Error(int error);
721 public static int GetHRForLastWin32Error()
723 int dwLastError = GetLastWin32Error();
724 if ((dwLastError & 0x80000000) == 0x80000000)
729 return (dwLastError & 0x0000FFFF) | unchecked((int)0x80070000);
732 public static void Prelink(MethodInfo m)
736 throw new ArgumentNullException(nameof(m));
738 if (!(m is RuntimeMethodInfo rmi))
740 throw new ArgumentException(SR.Argument_MustBeRuntimeMethodInfo, nameof(m));
743 InternalPrelink(rmi);
746 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
747 private static extern void InternalPrelink(IRuntimeMethodInfo m);
749 public static void PrelinkAll(Type c)
753 throw new ArgumentNullException(nameof(c));
756 MethodInfo[] mi = c.GetMethods();
759 for (int i = 0; i < mi.Length; i++)
766 [MethodImpl(MethodImplOptions.InternalCall)]
767 public static extern /* struct _EXCEPTION_POINTERS* */ IntPtr GetExceptionPointers();
769 [MethodImpl(MethodImplOptions.InternalCall)]
770 public static extern int GetExceptionCode();
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.
777 [MethodImpl(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
778 public static extern void StructureToPtr(object structure, IntPtr ptr, bool fDeleteOld);
780 public static void StructureToPtr<T>(T structure, IntPtr ptr, bool fDeleteOld)
782 StructureToPtr((object)structure, ptr, fDeleteOld);
786 /// Marshals data from a native memory block to a preallocated structure class.
788 public static void PtrToStructure(IntPtr ptr, object structure)
790 PtrToStructureHelper(ptr, structure, allowValueClasses: false);
793 public static void PtrToStructure<T>(IntPtr ptr, T structure)
795 PtrToStructure(ptr, (object)structure);
799 /// Creates a new instance of "structuretype" and marshals data from a
800 /// native memory block to it.
802 public static object PtrToStructure(IntPtr ptr, Type structureType)
804 if (ptr == IntPtr.Zero)
809 if (structureType == null)
811 throw new ArgumentNullException(nameof(structureType));
813 if (structureType.IsGenericType)
815 throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(structureType));
817 if (!(structureType.UnderlyingSystemType is RuntimeType rt))
819 throw new ArgumentException(SR.Arg_MustBeType, nameof(structureType));
822 object structure = rt.CreateInstanceDefaultCtor(publicOnly: false, skipCheckThis: false, fillCache: false, wrapExceptions: true);
823 PtrToStructureHelper(ptr, structure, allowValueClasses: true);
827 public static T PtrToStructure<T>(IntPtr ptr) => (T)PtrToStructure(ptr, typeof(T));
830 /// Helper function to copy a pointer into a preallocated structure.
832 [MethodImpl(MethodImplOptions.InternalCall)]
833 private static extern void PtrToStructureHelper(IntPtr ptr, object structure, bool allowValueClasses);
836 /// Frees all substructures pointed to by the native memory block.
837 /// "structuretype" is used to provide layout information.
839 [MethodImpl(MethodImplOptions.InternalCall)]
840 public static extern void DestroyStructure(IntPtr ptr, Type structuretype);
842 public static void DestroyStructure<T>(IntPtr ptr) => DestroyStructure(ptr, typeof(T));
844 #if FEATURE_COMINTEROP
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.
849 public static IntPtr GetHINSTANCE(Module m)
853 throw new ArgumentNullException(nameof(m));
856 RuntimeModule rtModule = m as RuntimeModule;
857 if (rtModule == null && m is ModuleBuilder mb)
859 rtModule = mb.InternalModule;
862 if (rtModule == null)
864 throw new ArgumentNullException(nameof(m), SR.Argument_MustBeRuntimeModule);
867 return GetHINSTANCE(rtModule.GetNativeHandle());
870 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
871 private static extern IntPtr GetHINSTANCE(RuntimeModule m);
873 #endif // FEATURE_COMINTEROP
876 /// Throws a CLR exception based on the HRESULT.
878 public static void ThrowExceptionForHR(int errorCode)
882 ThrowExceptionForHRInternal(errorCode, IntPtr.Zero);
886 public static void ThrowExceptionForHR(int errorCode, IntPtr errorInfo)
890 ThrowExceptionForHRInternal(errorCode, errorInfo);
894 [MethodImpl(MethodImplOptions.InternalCall)]
895 internal static extern void ThrowExceptionForHRInternal(int errorCode, IntPtr errorInfo);
898 /// Converts the HRESULT to a CLR exception.
900 public static Exception GetExceptionForHR(int errorCode)
907 return GetExceptionForHRInternal(errorCode, IntPtr.Zero);
909 public static Exception GetExceptionForHR(int errorCode, IntPtr errorInfo)
916 return GetExceptionForHRInternal(errorCode, errorInfo);
919 [MethodImpl(MethodImplOptions.InternalCall)]
920 internal static extern Exception GetExceptionForHRInternal(int errorCode, IntPtr errorInfo);
922 public static IntPtr AllocHGlobal(IntPtr cb)
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.
932 numBytes = new UIntPtr(unchecked((ulong)cb.ToInt64()));
934 numBytes = new UIntPtr(unchecked((uint)cb.ToInt32()));
937 IntPtr pNewMem = Win32Native.LocalAlloc_NoSafeHandle(LMEM_FIXED, unchecked(numBytes));
938 if (pNewMem == IntPtr.Zero)
940 throw new OutOfMemoryException();
946 public static IntPtr AllocHGlobal(int cb) => AllocHGlobal((IntPtr)cb);
948 public static void FreeHGlobal(IntPtr hglobal)
950 if (!IsWin32Atom(hglobal))
952 if (IntPtr.Zero != Win32Native.LocalFree(hglobal))
954 ThrowExceptionForHR(GetHRForLastWin32Error());
959 public static IntPtr ReAllocHGlobal(IntPtr pv, IntPtr cb)
961 IntPtr pNewMem = Win32Native.LocalReAlloc(pv, cb, LMEM_MOVEABLE);
962 if (pNewMem == IntPtr.Zero)
964 throw new OutOfMemoryException();
970 public static unsafe IntPtr StringToHGlobalAnsi(string s)
977 int nb = (s.Length + 1) * SystemMaxDBCSCharSize;
982 throw new ArgumentOutOfRangeException(nameof(s));
985 UIntPtr len = new UIntPtr((uint)nb);
986 IntPtr hglobal = Win32Native.LocalAlloc_NoSafeHandle(LMEM_FIXED, len);
987 if (hglobal == IntPtr.Zero)
989 throw new OutOfMemoryException();
992 s.ConvertToAnsi((byte*)hglobal, nb, false, false);
996 public static unsafe IntPtr StringToHGlobalUni(string s)
1003 int nb = (s.Length + 1) * 2;
1005 // Overflow checking
1008 throw new ArgumentOutOfRangeException(nameof(s));
1011 UIntPtr len = new UIntPtr((uint)nb);
1012 IntPtr hglobal = Win32Native.LocalAlloc_NoSafeHandle(LMEM_FIXED, len);
1013 if (hglobal == IntPtr.Zero)
1015 throw new OutOfMemoryException();
1018 fixed (char* firstChar = s)
1020 string.wstrcpy((char*)hglobal, firstChar, s.Length + 1);
1025 public static IntPtr StringToHGlobalAuto(string s)
1027 // Ansi platforms are no longer supported
1028 return StringToHGlobalUni(s);
1031 #if FEATURE_COMINTEROP
1033 /// Converts the CLR exception to an HRESULT. This function also sets
1034 /// up an IErrorInfo for the exception.
1036 [MethodImpl(MethodImplOptions.InternalCall)]
1037 public static extern int GetHRForException(Exception e);
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
1045 [MethodImpl(MethodImplOptions.InternalCall)]
1046 internal static extern int GetHRForException_WinRT(Exception e);
1049 /// Given a managed object that wraps an ITypeInfo, return its name.
1051 public static string GetTypeInfoName(ITypeInfo typeInfo)
1053 if (typeInfo == null)
1055 throw new ArgumentNullException(nameof(typeInfo));
1058 typeInfo.GetDocumentation(-1, out string strTypeLibName, out _, out _, out _);
1059 return strTypeLibName;
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);
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.
1070 public static IntPtr /* IUnknown* */ GetIUnknownForObject(object o)
1072 return GetIUnknownForObjectNative(o, false);
1075 [MethodImpl(MethodImplOptions.InternalCall)]
1076 private static extern IntPtr /* IUnknown* */ GetIUnknownForObjectNative(object o, bool onlyInContext);
1079 /// Return the raw IUnknown* for a COM Object not related to current.
1080 /// Does not call AddRef.
1082 [MethodImpl(MethodImplOptions.InternalCall)]
1083 internal static extern IntPtr /* IUnknown* */ GetRawIUnknownForComObjectNoAddRef(object o);
1084 #endif // FEATURE_COMINTEROP
1086 public static IntPtr /* IDispatch */ GetIDispatchForObject(object o) => throw new PlatformNotSupportedException();
1088 #if FEATURE_COMINTEROP
1090 /// Return the IUnknown* representing the interface for the Object.
1091 /// Object o should support Type T
1093 public static IntPtr /* IUnknown* */ GetComInterfaceForObject(object o, Type T)
1095 return GetComInterfaceForObjectNative(o, T, false, true);
1098 public static IntPtr GetComInterfaceForObject<T, TInterface>(T o) => GetComInterfaceForObject(o, typeof(TInterface));
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.
1105 public static IntPtr /* IUnknown* */ GetComInterfaceForObject(object o, Type T, CustomQueryInterfaceMode mode)
1107 bool bEnableCustomizedQueryInterface = ((mode == CustomQueryInterfaceMode.Allow) ? true : false);
1108 return GetComInterfaceForObjectNative(o, T, false, bEnableCustomizedQueryInterface);
1111 [MethodImpl(MethodImplOptions.InternalCall)]
1112 private static extern IntPtr /* IUnknown* */ GetComInterfaceForObjectNative(object o, Type t, bool onlyInContext, bool fEnalbeCustomizedQueryInterface);
1114 [MethodImpl(MethodImplOptions.InternalCall)]
1115 public static extern object GetObjectForIUnknown(IntPtr /* IUnknown* */ pUnk);
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.
1123 [MethodImpl(MethodImplOptions.InternalCall)]
1124 public static extern object GetUniqueObjectForIUnknown(IntPtr unknown);
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
1130 [MethodImpl(MethodImplOptions.InternalCall)]
1131 public static extern object GetTypedObjectForIUnknown(IntPtr /* IUnknown* */ pUnk, Type t);
1133 [MethodImpl(MethodImplOptions.InternalCall)]
1134 public static extern IntPtr CreateAggregatedObject(IntPtr pOuter, object o);
1136 public static IntPtr CreateAggregatedObject<T>(IntPtr pOuter, T o)
1138 return CreateAggregatedObject(pOuter, (object)o);
1141 [MethodImpl(MethodImplOptions.InternalCall)]
1142 public static extern void CleanupUnusedObjectsInCurrentContext();
1144 [MethodImpl(MethodImplOptions.InternalCall)]
1145 public static extern bool AreComObjectsAvailableForCleanup();
1148 /// Checks if the object is classic COM component.
1150 [MethodImpl(MethodImplOptions.InternalCall)]
1151 public static extern bool IsComObject(object o);
1153 #endif // FEATURE_COMINTEROP
1155 public static IntPtr AllocCoTaskMem(int cb)
1157 IntPtr pNewMem = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)cb));
1158 if (pNewMem == IntPtr.Zero)
1160 throw new OutOfMemoryException();
1166 public static unsafe IntPtr StringToCoTaskMemUni(string s)
1173 int nb = (s.Length + 1) * 2;
1175 // Overflow checking
1178 throw new ArgumentOutOfRangeException(nameof(s));
1181 IntPtr hglobal = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)nb));
1182 if (hglobal == IntPtr.Zero)
1184 throw new OutOfMemoryException();
1187 fixed (char* firstChar = s)
1189 string.wstrcpy((char*)hglobal, firstChar, s.Length + 1);
1194 public static unsafe IntPtr StringToCoTaskMemUTF8(string s)
1201 int nb = Encoding.UTF8.GetMaxByteCount(s.Length);
1202 IntPtr pMem = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)nb + 1));
1203 if (pMem == IntPtr.Zero)
1205 throw new OutOfMemoryException();
1208 fixed (char* firstChar = s)
1210 byte* pbMem = (byte*)pMem;
1211 int nbWritten = Encoding.UTF8.GetBytes(firstChar, s.Length, pbMem, nb);
1212 pbMem[nbWritten] = 0;
1217 public static IntPtr StringToCoTaskMemAuto(string s)
1219 // Ansi platforms are no longer supported
1220 return StringToCoTaskMemUni(s);
1223 public static unsafe IntPtr StringToCoTaskMemAnsi(string s)
1230 int nb = (s.Length + 1) * SystemMaxDBCSCharSize;
1232 // Overflow checking
1235 throw new ArgumentOutOfRangeException(nameof(s));
1238 IntPtr hglobal = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)nb));
1239 if (hglobal == IntPtr.Zero)
1241 throw new OutOfMemoryException();
1244 s.ConvertToAnsi((byte*)hglobal, nb, false, false);
1248 public static void FreeCoTaskMem(IntPtr ptr)
1250 if (!IsWin32Atom(ptr))
1252 Win32Native.CoTaskMemFree(ptr);
1256 public static IntPtr ReAllocCoTaskMem(IntPtr pv, int cb)
1258 IntPtr pNewMem = Win32Native.CoTaskMemRealloc(pv, new UIntPtr((uint)cb));
1259 if (pNewMem == IntPtr.Zero && cb != 0)
1261 throw new OutOfMemoryException();
1267 public static void FreeBSTR(IntPtr ptr)
1269 if (!IsWin32Atom(ptr))
1271 Win32Native.SysFreeString(ptr);
1275 public static IntPtr StringToBSTR(string s)
1282 // Overflow checking
1283 if (s.Length + 1 < s.Length)
1285 throw new ArgumentOutOfRangeException(nameof(s));
1288 IntPtr bstr = Win32Native.SysAllocStringLen(s, s.Length);
1289 if (bstr == IntPtr.Zero)
1291 throw new OutOfMemoryException();
1297 public static string PtrToStringBSTR(IntPtr ptr)
1299 return PtrToStringUni(ptr, (int)Win32Native.SysStringLen(ptr));
1302 #if FEATURE_COMINTEROP
1304 /// Release the COM component and if the reference hits 0 zombie this object.
1305 /// Further usage of this Object might throw an exception
1307 public static int ReleaseComObject(object o)
1309 if (!(o is __ComObject co))
1311 throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(o));
1314 return co.ReleaseSelf();
1317 [MethodImpl(MethodImplOptions.InternalCall)]
1318 internal static extern int InternalReleaseComObject(object o);
1321 /// Release the COM component and zombie this object.
1322 /// Further usage of this Object might throw an exception
1324 public static int FinalReleaseComObject(object o)
1328 throw new ArgumentNullException(nameof(o));
1330 if (!(o is __ComObject co))
1332 throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(o));
1335 co.FinalReleaseSelf();
1339 [MethodImpl(MethodImplOptions.InternalCall)]
1340 internal static extern void InternalFinalReleaseComObject(object o);
1342 public static object GetComObjectData(object obj, object key)
1346 throw new ArgumentNullException(nameof(obj));
1350 throw new ArgumentNullException(nameof(key));
1352 if (!(obj is __ComObject co))
1354 throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(obj));
1356 if (obj.GetType().IsWindowsRuntimeObject)
1358 throw new ArgumentException(SR.Argument_ObjIsWinRTObject, nameof(obj));
1361 // Retrieve the data from the __ComObject.
1362 return co.GetData(key);
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
1371 public static bool SetComObjectData(object obj, object key, object data)
1375 throw new ArgumentNullException(nameof(obj));
1379 throw new ArgumentNullException(nameof(key));
1381 if (!(obj is __ComObject co))
1383 throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(obj));
1385 if (obj.GetType().IsWindowsRuntimeObject)
1387 throw new ArgumentException(SR.Argument_ObjIsWinRTObject, nameof(obj));
1390 // Retrieve the data from the __ComObject.
1391 return co.SetData(key, data);
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.
1398 public static object CreateWrapperOfType(object o, Type t)
1402 throw new ArgumentNullException(nameof(t));
1406 throw new ArgumentException(SR.Argument_TypeNotComObject, nameof(t));
1408 if (t.IsGenericType)
1410 throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(t));
1412 if (t.IsWindowsRuntimeObject)
1414 throw new ArgumentException(SR.Argument_TypeIsWinRTType, nameof(t));
1422 if (!o.GetType().IsCOMObject)
1424 throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(o));
1426 if (o.GetType().IsWindowsRuntimeObject)
1428 throw new ArgumentException(SR.Argument_ObjIsWinRTObject, nameof(o));
1431 // Check to see if we have nothing to do.
1432 if (o.GetType() == t)
1437 // Check to see if we already have a cached wrapper for this type.
1438 object Wrapper = GetComObjectData(o, t);
1439 if (Wrapper == null)
1441 // Create the wrapper for the specified type.
1442 Wrapper = InternalCreateWrapperOfType(o, t);
1444 // Attempt to cache the wrapper on the object.
1445 if (!SetComObjectData(o, t, Wrapper))
1447 // Another thead already cached the wrapper so use that one instead.
1448 Wrapper = GetComObjectData(o, t);
1455 public static TWrapper CreateWrapperOfType<T, TWrapper>(T o)
1457 return (TWrapper)CreateWrapperOfType(o, typeof(TWrapper));
1460 [MethodImpl(MethodImplOptions.InternalCall)]
1461 private static extern object InternalCreateWrapperOfType(object o, Type t);
1464 /// check if the type is visible from COM.
1466 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1467 public static extern bool IsTypeVisibleFromCom(Type t);
1469 [MethodImpl(MethodImplOptions.InternalCall)]
1470 public static extern int /* HRESULT */ QueryInterface(IntPtr /* IUnknown */ pUnk, ref Guid iid, out IntPtr ppv);
1472 [MethodImpl(MethodImplOptions.InternalCall)]
1473 public static extern int /* ULONG */ AddRef(IntPtr /* IUnknown */ pUnk);
1475 [MethodImpl(MethodImplOptions.InternalCall)]
1476 public static extern int /* ULONG */ Release(IntPtr /* IUnknown */ pUnk);
1478 [MethodImpl(MethodImplOptions.InternalCall)]
1479 public static extern void GetNativeVariantForObject(object obj, /* VARIANT * */ IntPtr pDstNativeVariant);
1481 public static void GetNativeVariantForObject<T>(T obj, IntPtr pDstNativeVariant)
1483 GetNativeVariantForObject((object)obj, pDstNativeVariant);
1486 [MethodImpl(MethodImplOptions.InternalCall)]
1487 public static extern object GetObjectForNativeVariant(/* VARIANT * */ IntPtr pSrcNativeVariant);
1489 public static T GetObjectForNativeVariant<T>(IntPtr pSrcNativeVariant)
1491 return (T)GetObjectForNativeVariant(pSrcNativeVariant);
1494 [MethodImpl(MethodImplOptions.InternalCall)]
1495 public static extern object[] GetObjectsForNativeVariants(/* VARIANT * */ IntPtr aSrcNativeVariant, int cVars);
1497 public static T[] GetObjectsForNativeVariants<T>(IntPtr aSrcNativeVariant, int cVars)
1499 object[] objects = GetObjectsForNativeVariants(aSrcNativeVariant, cVars);
1502 if (objects != null)
1504 result = new T[objects.Length];
1505 Array.Copy(objects, result, objects.Length);
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>
1515 [MethodImpl(MethodImplOptions.InternalCall)]
1516 public static extern int GetStartComSlot(Type t);
1519 /// <para>Returns the last valid COM slot that GetMethodInfoForSlot will work on. </para>
1521 [MethodImpl(MethodImplOptions.InternalCall)]
1522 public static extern int GetEndComSlot(Type t);
1523 #endif // FEATURE_COMINTEROP
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.
1530 public static Guid GenerateGuidForType(Type type) => type.GUID;
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.
1537 public static string GenerateProgIdForType(Type type)
1541 throw new ArgumentNullException(nameof(type));
1545 throw new ArgumentException(SR.Argument_TypeMustNotBeComImport, nameof(type));
1547 if (type.IsGenericType)
1549 throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(type));
1552 IList<CustomAttributeData> cas = CustomAttributeData.GetCustomAttributes(type);
1553 for (int i = 0; i < cas.Count; i++)
1555 if (cas[i].Constructor.DeclaringType == typeof(ProgIdAttribute))
1557 // Retrieve the PROGID string from the ProgIdAttribute.
1558 IList<CustomAttributeTypedArgument> caConstructorArgs = cas[i].ConstructorArguments;
1559 Debug.Assert(caConstructorArgs.Count == 1, "caConstructorArgs.Count == 1");
1561 CustomAttributeTypedArgument progIdConstructorArg = caConstructorArgs[0];
1562 Debug.Assert(progIdConstructorArg.ArgumentType == typeof(string), "progIdConstructorArg.ArgumentType == typeof(String)");
1564 string strProgId = (string)progIdConstructorArg.Value;
1566 if (strProgId == null)
1567 strProgId = string.Empty;
1573 // If there is no prog ID attribute then use the full name of the type as the prog id.
1574 return type.FullName;
1577 #if FEATURE_COMINTEROP
1578 public static object BindToMoniker(string monikerName)
1580 CreateBindCtx(0, out IBindCtx bindctx);
1582 MkParseDisplayName(bindctx, monikerName, out _, out IMoniker pmoniker);
1583 BindMoniker(pmoniker, 0, ref IID_IUnknown, out object obj);
1588 [DllImport(Interop.Libraries.Ole32, PreserveSig = false)]
1589 private static extern void CreateBindCtx(uint reserved, out IBindCtx ppbc);
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);
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);
1598 /// Private method called from EE upon use of license/ICF2 marshaling.
1600 private static IntPtr LoadLicenseManager()
1602 Type t = Type.GetType("System.ComponentModel.LicenseManager, System", throwOnError: true);
1603 return t.TypeHandle.Value;
1606 [MethodImpl(MethodImplOptions.InternalCall)]
1607 public static extern void ChangeWrapperHandleStrength(object otp, bool fIsWeak);
1609 [MethodImpl(MethodImplOptions.InternalCall)]
1610 internal static extern void InitializeWrapperForWinRT(object o, ref IntPtr pUnk);
1612 #if FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION
1613 [MethodImpl(MethodImplOptions.InternalCall)]
1614 internal static extern void InitializeManagedWinRTFactoryObject(object o, RuntimeType runtimeClassType);
1618 /// Create activation factory and wraps it with a unique RCW.
1620 [MethodImpl(MethodImplOptions.InternalCall)]
1621 internal static extern object GetNativeActivationFactory(Type type);
1623 #endif // FEATURE_COMINTEROP
1625 public static Delegate GetDelegateForFunctionPointer(IntPtr ptr, Type t)
1627 if (ptr == IntPtr.Zero)
1629 throw new ArgumentNullException(nameof(ptr));
1633 throw new ArgumentNullException(nameof(t));
1635 if (!(t is RuntimeType))
1637 throw new ArgumentException(SR.Argument_MustBeRuntimeType, nameof(t));
1639 if (t.IsGenericType)
1641 throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(t));
1644 Type c = t.BaseType;
1645 if (c == null || (c != typeof(Delegate) && c != typeof(MulticastDelegate)))
1647 throw new ArgumentException(SR.Arg_MustBeDelegate, nameof(t));
1650 return GetDelegateForFunctionPointerInternal(ptr, t);
1653 public static TDelegate GetDelegateForFunctionPointer<TDelegate>(IntPtr ptr)
1655 return (TDelegate)(object)GetDelegateForFunctionPointer(ptr, typeof(TDelegate));
1658 [MethodImpl(MethodImplOptions.InternalCall)]
1659 internal static extern Delegate GetDelegateForFunctionPointerInternal(IntPtr ptr, Type t);
1661 public static IntPtr GetFunctionPointerForDelegate(Delegate d)
1665 throw new ArgumentNullException(nameof(d));
1668 return GetFunctionPointerForDelegateInternal(d);
1671 public static IntPtr GetFunctionPointerForDelegate<TDelegate>(TDelegate d)
1673 return GetFunctionPointerForDelegate((Delegate)(object)d);
1676 [MethodImpl(MethodImplOptions.InternalCall)]
1677 internal static extern IntPtr GetFunctionPointerForDelegateInternal(Delegate d);
1679 public static IntPtr SecureStringToBSTR(SecureString s)
1683 throw new ArgumentNullException(nameof(s));
1686 return s.MarshalToBSTR();
1689 public static IntPtr SecureStringToCoTaskMemAnsi(SecureString s)
1693 throw new ArgumentNullException(nameof(s));
1696 return s.MarshalToString(globalAlloc: false, unicode: false);
1699 public static IntPtr SecureStringToCoTaskMemUnicode(SecureString s)
1703 throw new ArgumentNullException(nameof(s));
1706 return s.MarshalToString(globalAlloc: false, unicode: true);
1709 public static void ZeroFreeBSTR(IntPtr s)
1711 RuntimeImports.RhZeroMemory(s, (UIntPtr)(Win32Native.SysStringLen(s) * 2));
1715 public static void ZeroFreeCoTaskMemAnsi(IntPtr s)
1717 RuntimeImports.RhZeroMemory(s, (UIntPtr)(Win32Native.lstrlenA(s)));
1721 public static void ZeroFreeCoTaskMemUnicode(IntPtr s)
1723 RuntimeImports.RhZeroMemory(s, (UIntPtr)(Win32Native.lstrlenW(s) * 2));
1727 public static unsafe void ZeroFreeCoTaskMemUTF8(IntPtr s)
1729 RuntimeImports.RhZeroMemory(s, (UIntPtr)System.StubHelpers.StubHelpers.strlen((sbyte*)s));
1733 public static IntPtr SecureStringToGlobalAllocAnsi(SecureString s)
1737 throw new ArgumentNullException(nameof(s));
1740 return s.MarshalToString(globalAlloc: true, unicode: false);
1743 public static IntPtr SecureStringToGlobalAllocUnicode(SecureString s)
1747 throw new ArgumentNullException(nameof(s));
1750 return s.MarshalToString(globalAlloc: true, unicode: true); ;
1753 public static void ZeroFreeGlobalAllocAnsi(IntPtr s)
1755 RuntimeImports.RhZeroMemory(s, (UIntPtr)(Win32Native.lstrlenA(s)));
1759 public static void ZeroFreeGlobalAllocUnicode(IntPtr s)
1761 RuntimeImports.RhZeroMemory(s, (UIntPtr)(Win32Native.lstrlenW(s) * 2));