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 private const int LMEM_FIXED = 0;
32 private const int LMEM_MOVEABLE = 2;
34 private const long HiWordMask = unchecked((long)0xffffffffffff0000L);
36 #if FEATURE_COMINTEROP
37 private static Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");
38 #endif //FEATURE_COMINTEROP
40 // Win32 has the concept of Atoms, where a pointer can either be a pointer
41 // or an int. If it's less than 64K, this is guaranteed to NOT be a
42 // pointer since the bottom 64K bytes are reserved in a process' page table.
43 // We should be careful about deallocating this stuff. Extracted to
44 // a function to avoid C# problems with lack of support for IntPtr.
45 // We have 2 of these methods for slightly different semantics for NULL.
46 private static bool IsWin32Atom(IntPtr ptr)
51 long lPtr = (long)ptr;
52 return 0 == (lPtr & HiWordMask);
57 /// The default character size for the system. This is always 2 because
58 /// the framework only runs on UTF-16 systems.
60 public static readonly int SystemDefaultCharSize = 2;
63 /// The max DBCS character size for the system.
65 public static readonly int SystemMaxDBCSCharSize = GetSystemMaxDBCSCharSize();
68 /// Helper method to retrieve the system's maximum DBCS character size.
70 [MethodImpl(MethodImplOptions.InternalCall)]
71 private static extern int GetSystemMaxDBCSCharSize();
73 public static unsafe string PtrToStringAnsi(IntPtr ptr)
75 if (IntPtr.Zero == ptr)
79 else if (IsWin32Atom(ptr))
84 int nb = Win32Native.lstrlenA(ptr);
90 return new string((sbyte*)ptr);
93 public static unsafe string PtrToStringAnsi(IntPtr ptr, int len)
95 if (ptr == IntPtr.Zero)
97 throw new ArgumentNullException(nameof(ptr));
101 throw new ArgumentException(null, nameof(len));
104 return new string((sbyte*)ptr, 0, len);
107 public static unsafe string PtrToStringUni(IntPtr ptr, int len)
109 if (ptr == IntPtr.Zero)
111 throw new ArgumentNullException(nameof(ptr));
115 throw new ArgumentException(SR.ArgumentOutOfRange_NeedNonNegNum, nameof(len));
118 return new string((char*)ptr, 0, len);
121 public static string PtrToStringAuto(IntPtr ptr, int len)
123 // Ansi platforms are no longer supported
124 return PtrToStringUni(ptr, len);
127 public static unsafe string PtrToStringUni(IntPtr ptr)
129 if (IntPtr.Zero == ptr)
133 else if (IsWin32Atom(ptr))
138 return new string((char*)ptr);
141 public static string PtrToStringAuto(IntPtr ptr)
143 // Ansi platforms are no longer supported
144 return PtrToStringUni(ptr);
147 public static unsafe string PtrToStringUTF8(IntPtr ptr)
149 if (IntPtr.Zero == ptr)
154 int nbBytes = StubHelpers.StubHelpers.strlen((sbyte*)ptr.ToPointer());
155 return PtrToStringUTF8(ptr, nbBytes);
158 public static unsafe string PtrToStringUTF8(IntPtr ptr, int byteLen)
162 throw new ArgumentOutOfRangeException(nameof(byteLen), SR.ArgumentOutOfRange_NeedNonNegNum);
164 else if (IntPtr.Zero == ptr)
168 else if (IsWin32Atom(ptr))
172 else if (byteLen == 0)
177 byte* pByte = (byte*)ptr.ToPointer();
178 return Encoding.UTF8.GetString(pByte, byteLen);
181 public static int SizeOf(object structure)
183 if (structure == null)
185 throw new ArgumentNullException(nameof(structure));
188 return SizeOfHelper(structure.GetType(), true);
191 public static int SizeOf<T>(T structure) => SizeOf((object)structure);
193 public static int SizeOf(Type t)
197 throw new ArgumentNullException(nameof(t));
199 if (!(t is RuntimeType))
201 throw new ArgumentException(SR.Argument_MustBeRuntimeType, nameof(t));
205 throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(t));
208 return SizeOfHelper(t, throwIfNotMarshalable: true);
211 public static int SizeOf<T>() => SizeOf(typeof(T));
213 [MethodImpl(MethodImplOptions.InternalCall)]
214 internal static extern int SizeOfHelper(Type t, bool throwIfNotMarshalable);
216 public static IntPtr OffsetOf(Type t, string fieldName)
220 throw new ArgumentNullException(nameof(t));
223 FieldInfo f = t.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
226 throw new ArgumentException(SR.Format(SR.Argument_OffsetOfFieldNotFound, t.FullName), nameof(fieldName));
229 if (!(f is RtFieldInfo rtField))
231 throw new ArgumentException(SR.Argument_MustBeRuntimeFieldInfo, nameof(fieldName));
234 return OffsetOfHelper(rtField);
237 public static IntPtr OffsetOf<T>(string fieldName) => OffsetOf(typeof(T), fieldName);
239 [MethodImpl(MethodImplOptions.InternalCall)]
240 private static extern IntPtr OffsetOfHelper(IRuntimeFieldInfo f);
243 /// IMPORTANT NOTICE: This method does not do any verification on the array.
244 /// It must be used with EXTREME CAUTION since passing in an array that is
245 /// not pinned or in the fixed heap can cause unexpected results.
247 [MethodImpl(MethodImplOptions.InternalCall)]
248 public static extern IntPtr UnsafeAddrOfPinnedArrayElement(Array arr, int index);
250 public static IntPtr UnsafeAddrOfPinnedArrayElement<T>(T[] arr, int index)
252 return UnsafeAddrOfPinnedArrayElement((Array)arr, index);
255 public static void Copy(int[] source, int startIndex, IntPtr destination, int length)
257 CopyToNative(source, startIndex, destination, length);
260 public static void Copy(char[] source, int startIndex, IntPtr destination, int length)
262 CopyToNative(source, startIndex, destination, length);
265 public static void Copy(short[] source, int startIndex, IntPtr destination, int length)
267 CopyToNative(source, startIndex, destination, length);
270 public static void Copy(long[] source, int startIndex, IntPtr destination, int length)
272 CopyToNative(source, startIndex, destination, length);
275 public static void Copy(float[] source, int startIndex, IntPtr destination, int length)
277 CopyToNative(source, startIndex, destination, length);
280 public static void Copy(double[] source, int startIndex, IntPtr destination, int length)
282 CopyToNative(source, startIndex, destination, length);
285 public static void Copy(byte[] source, int startIndex, IntPtr destination, int length)
287 CopyToNative(source, startIndex, destination, length);
290 public static void Copy(IntPtr[] source, int startIndex, IntPtr destination, int length)
292 CopyToNative(source, startIndex, destination, length);
295 [MethodImpl(MethodImplOptions.InternalCall)]
296 private static extern void CopyToNative(object source, int startIndex, IntPtr destination, int length);
298 public static void Copy(IntPtr source, int[] destination, int startIndex, int length)
300 CopyToManaged(source, destination, startIndex, length);
303 public static void Copy(IntPtr source, char[] destination, int startIndex, int length)
305 CopyToManaged(source, destination, startIndex, length);
308 public static void Copy(IntPtr source, short[] destination, int startIndex, int length)
310 CopyToManaged(source, destination, startIndex, length);
313 public static void Copy(IntPtr source, long[] destination, int startIndex, int length)
315 CopyToManaged(source, destination, startIndex, length);
318 public static void Copy(IntPtr source, float[] destination, int startIndex, int length)
320 CopyToManaged(source, destination, startIndex, length);
323 public static void Copy(IntPtr source, double[] destination, int startIndex, int length)
325 CopyToManaged(source, destination, startIndex, length);
328 public static void Copy(IntPtr source, byte[] destination, int startIndex, int length)
330 CopyToManaged(source, destination, startIndex, length);
333 public static void Copy(IntPtr source, IntPtr[] destination, int startIndex, int length)
335 CopyToManaged(source, destination, startIndex, length);
338 [MethodImpl(MethodImplOptions.InternalCall)]
339 private static extern void CopyToManaged(IntPtr source, object destination, int startIndex, int length);
341 public static byte ReadByte(object ptr, int ofs)
343 return ReadValueSlow(ptr, ofs, (IntPtr nativeHome, int offset) => ReadByte(nativeHome, offset));
346 public static unsafe byte ReadByte(IntPtr ptr, int ofs)
350 byte* addr = (byte*)ptr + ofs;
353 catch (NullReferenceException)
355 // this method is documented to throw AccessViolationException on any AV
356 throw new AccessViolationException();
360 public static byte ReadByte(IntPtr ptr) => ReadByte(ptr, 0);
362 public static short ReadInt16(object ptr, int ofs)
364 return ReadValueSlow(ptr, ofs, (IntPtr nativeHome, int offset) => ReadInt16(nativeHome, offset));
367 public static unsafe short ReadInt16(IntPtr ptr, int ofs)
371 byte* addr = (byte*)ptr + ofs;
372 if ((unchecked((int)addr) & 0x1) == 0)
375 return *((short*)addr);
381 byte* valPtr = (byte*)&val;
387 catch (NullReferenceException)
389 // this method is documented to throw AccessViolationException on any AV
390 throw new AccessViolationException();
394 public static short ReadInt16(IntPtr ptr) => ReadInt16(ptr, 0);
396 public static int ReadInt32(object ptr, int ofs)
398 return ReadValueSlow(ptr, ofs, (IntPtr nativeHome, int offset) => ReadInt32(nativeHome, offset));
401 public static unsafe int ReadInt32(IntPtr ptr, int ofs)
405 byte* addr = (byte*)ptr + ofs;
406 if ((unchecked((int)addr) & 0x3) == 0)
409 return *((int*)addr);
415 byte* valPtr = (byte*)&val;
423 catch (NullReferenceException)
425 // this method is documented to throw AccessViolationException on any AV
426 throw new AccessViolationException();
430 public static int ReadInt32(IntPtr ptr) => ReadInt32(ptr, 0);
432 public static IntPtr ReadIntPtr(object ptr, int ofs)
435 return (IntPtr)ReadInt64(ptr, ofs);
437 return (IntPtr)ReadInt32(ptr, ofs);
441 public static IntPtr ReadIntPtr(IntPtr ptr, int ofs)
444 return (IntPtr)ReadInt64(ptr, ofs);
446 return (IntPtr)ReadInt32(ptr, ofs);
450 public static IntPtr ReadIntPtr(IntPtr ptr) => ReadIntPtr(ptr, 0);
452 public static long ReadInt64([MarshalAs(UnmanagedType.AsAny), In] object ptr, int ofs)
454 return ReadValueSlow(ptr, ofs, (IntPtr nativeHome, int offset) => ReadInt64(nativeHome, offset));
457 public static unsafe long ReadInt64(IntPtr ptr, int ofs)
461 byte* addr = (byte*)ptr + ofs;
462 if ((unchecked((int)addr) & 0x7) == 0)
465 return *((long*)addr);
471 byte* valPtr = (byte*)&val;
483 catch (NullReferenceException)
485 // this method is documented to throw AccessViolationException on any AV
486 throw new AccessViolationException();
490 public static long ReadInt64(IntPtr ptr) => ReadInt64(ptr, 0);
492 //====================================================================
493 // Read value from marshaled object (marshaled using AsAny)
494 // It's quite slow and can return back dangling pointers
495 // It's only there for backcompact
496 // People should instead use the IntPtr overloads
497 //====================================================================
498 private static unsafe T ReadValueSlow<T>(object ptr, int ofs, Func<IntPtr, int, T> readValueHelper)
500 // Consumers of this method are documented to throw AccessViolationException on any AV
503 throw new AccessViolationException();
507 (int)AsAnyMarshaler.AsAnyFlags.In |
508 (int)AsAnyMarshaler.AsAnyFlags.IsAnsi |
509 (int)AsAnyMarshaler.AsAnyFlags.IsBestFit;
511 MngdNativeArrayMarshaler.MarshalerState nativeArrayMarshalerState = new MngdNativeArrayMarshaler.MarshalerState();
512 AsAnyMarshaler marshaler = new AsAnyMarshaler(new IntPtr(&nativeArrayMarshalerState));
514 IntPtr pNativeHome = IntPtr.Zero;
518 pNativeHome = marshaler.ConvertToNative(ptr, Flags);
519 return readValueHelper(pNativeHome, ofs);
523 marshaler.ClearNative(pNativeHome);
527 public static unsafe void WriteByte(IntPtr ptr, int ofs, byte val)
531 byte* addr = (byte*)ptr + ofs;
534 catch (NullReferenceException)
536 // this method is documented to throw AccessViolationException on any AV
537 throw new AccessViolationException();
541 public static void WriteByte(object ptr, int ofs, byte val)
543 WriteValueSlow(ptr, ofs, val, (IntPtr nativeHome, int offset, byte value) => WriteByte(nativeHome, offset, value));
546 public static void WriteByte(IntPtr ptr, byte val) => WriteByte(ptr, 0, val);
548 public static unsafe void WriteInt16(IntPtr ptr, int ofs, short val)
552 byte* addr = (byte*)ptr + ofs;
553 if ((unchecked((int)addr) & 0x1) == 0)
556 *((short*)addr) = val;
561 byte* valPtr = (byte*)&val;
566 catch (NullReferenceException)
568 // this method is documented to throw AccessViolationException on any AV
569 throw new AccessViolationException();
573 public static void WriteInt16(object ptr, int ofs, short val)
575 WriteValueSlow(ptr, ofs, val, (IntPtr nativeHome, int offset, short value) => Marshal.WriteInt16(nativeHome, offset, value));
578 public static void WriteInt16(IntPtr ptr, short val) => WriteInt16(ptr, 0, val);
580 public static void WriteInt16(IntPtr ptr, int ofs, char val) => WriteInt16(ptr, ofs, (short)val);
582 public static void WriteInt16([In, Out]object ptr, int ofs, char val) => WriteInt16(ptr, ofs, (short)val);
584 public static void WriteInt16(IntPtr ptr, char val) => WriteInt16(ptr, 0, (short)val);
586 public static unsafe void WriteInt32(IntPtr ptr, int ofs, int val)
590 byte* addr = (byte*)ptr + ofs;
591 if ((unchecked((int)addr) & 0x3) == 0)
599 byte* valPtr = (byte*)&val;
606 catch (NullReferenceException)
608 // this method is documented to throw AccessViolationException on any AV
609 throw new AccessViolationException();
613 public static void WriteInt32(object ptr, int ofs, int val)
615 WriteValueSlow(ptr, ofs, val, (IntPtr nativeHome, int offset, int value) => Marshal.WriteInt32(nativeHome, offset, value));
618 public static void WriteInt32(IntPtr ptr, int val) => WriteInt32(ptr, 0, val);
620 public static void WriteIntPtr(IntPtr ptr, int ofs, IntPtr val)
623 WriteInt64(ptr, ofs, (long)val);
625 WriteInt32(ptr, ofs, (int)val);
629 public static void WriteIntPtr(object ptr, int ofs, IntPtr val)
632 WriteInt64(ptr, ofs, (long)val);
634 WriteInt32(ptr, ofs, (int)val);
638 public static void WriteIntPtr(IntPtr ptr, IntPtr val) => WriteIntPtr(ptr, 0, val);
640 public static unsafe void WriteInt64(IntPtr ptr, int ofs, long val)
644 byte* addr = (byte*)ptr + ofs;
645 if ((unchecked((int)addr) & 0x7) == 0)
648 *((long*)addr) = val;
653 byte* valPtr = (byte*)&val;
664 catch (NullReferenceException)
666 // this method is documented to throw AccessViolationException on any AV
667 throw new AccessViolationException();
671 public static void WriteInt64(object ptr, int ofs, long val)
673 WriteValueSlow(ptr, ofs, val, (IntPtr nativeHome, int offset, long value) => Marshal.WriteInt64(nativeHome, offset, value));
676 public static void WriteInt64(IntPtr ptr, long val) => WriteInt64(ptr, 0, val);
679 /// Write value into marshaled object (marshaled using AsAny) and propagate the
680 /// value back. This is quite slow and can return back dangling pointers. It is
681 /// only here for backcompat. People should instead use the IntPtr overloads.
683 private static unsafe void WriteValueSlow<T>(object ptr, int ofs, T val, Action<IntPtr, int, T> writeValueHelper)
685 // Consumers of this method are documented to throw AccessViolationException on any AV
688 throw new AccessViolationException();
692 (int)AsAnyMarshaler.AsAnyFlags.In |
693 (int)AsAnyMarshaler.AsAnyFlags.Out |
694 (int)AsAnyMarshaler.AsAnyFlags.IsAnsi |
695 (int)AsAnyMarshaler.AsAnyFlags.IsBestFit;
697 MngdNativeArrayMarshaler.MarshalerState nativeArrayMarshalerState = new MngdNativeArrayMarshaler.MarshalerState();
698 AsAnyMarshaler marshaler = new AsAnyMarshaler(new IntPtr(&nativeArrayMarshalerState));
700 IntPtr pNativeHome = IntPtr.Zero;
704 pNativeHome = marshaler.ConvertToNative(ptr, Flags);
705 writeValueHelper(pNativeHome, ofs, val);
706 marshaler.ConvertToManaged(ptr, pNativeHome);
710 marshaler.ClearNative(pNativeHome);
714 [MethodImpl(MethodImplOptions.InternalCall)]
715 public static extern int GetLastWin32Error();
717 [MethodImpl(MethodImplOptions.InternalCall)]
718 internal static extern void SetLastWin32Error(int error);
720 public static int GetHRForLastWin32Error()
722 int dwLastError = GetLastWin32Error();
723 if ((dwLastError & 0x80000000) == 0x80000000)
728 return (dwLastError & 0x0000FFFF) | unchecked((int)0x80070000);
731 public static void Prelink(MethodInfo m)
735 throw new ArgumentNullException(nameof(m));
737 if (!(m is RuntimeMethodInfo rmi))
739 throw new ArgumentException(SR.Argument_MustBeRuntimeMethodInfo, nameof(m));
742 InternalPrelink(rmi);
745 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
746 private static extern void InternalPrelink(IRuntimeMethodInfo m);
748 public static void PrelinkAll(Type c)
752 throw new ArgumentNullException(nameof(c));
755 MethodInfo[] mi = c.GetMethods();
758 for (int i = 0; i < mi.Length; i++)
765 [MethodImpl(MethodImplOptions.InternalCall)]
766 public static extern /* struct _EXCEPTION_POINTERS* */ IntPtr GetExceptionPointers();
768 [MethodImpl(MethodImplOptions.InternalCall)]
769 public static extern int GetExceptionCode();
772 /// Marshals data from a structure class to a native memory block. If the
773 /// structure contains pointers to allocated blocks and "fDeleteOld" is
774 /// true, this routine will call DestroyStructure() first.
776 [MethodImpl(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
777 public static extern void StructureToPtr(object structure, IntPtr ptr, bool fDeleteOld);
779 public static void StructureToPtr<T>(T structure, IntPtr ptr, bool fDeleteOld)
781 StructureToPtr((object)structure, ptr, fDeleteOld);
785 /// Marshals data from a native memory block to a preallocated structure class.
787 public static void PtrToStructure(IntPtr ptr, object structure)
789 PtrToStructureHelper(ptr, structure, allowValueClasses: false);
792 public static void PtrToStructure<T>(IntPtr ptr, T structure)
794 PtrToStructure(ptr, (object)structure);
798 /// Creates a new instance of "structuretype" and marshals data from a
799 /// native memory block to it.
801 public static object PtrToStructure(IntPtr ptr, Type structureType)
803 if (ptr == IntPtr.Zero)
808 if (structureType == null)
810 throw new ArgumentNullException(nameof(structureType));
812 if (structureType.IsGenericType)
814 throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(structureType));
816 if (!(structureType.UnderlyingSystemType is RuntimeType rt))
818 throw new ArgumentException(SR.Arg_MustBeType, nameof(structureType));
821 object structure = rt.CreateInstanceDefaultCtor(publicOnly: false, skipCheckThis: false, fillCache: false, wrapExceptions: true);
822 PtrToStructureHelper(ptr, structure, allowValueClasses: true);
826 public static T PtrToStructure<T>(IntPtr ptr) => (T)PtrToStructure(ptr, typeof(T));
829 /// Helper function to copy a pointer into a preallocated structure.
831 [MethodImpl(MethodImplOptions.InternalCall)]
832 private static extern void PtrToStructureHelper(IntPtr ptr, object structure, bool allowValueClasses);
835 /// Frees all substructures pointed to by the native memory block.
836 /// "structuretype" is used to provide layout information.
838 [MethodImpl(MethodImplOptions.InternalCall)]
839 public static extern void DestroyStructure(IntPtr ptr, Type structuretype);
841 public static void DestroyStructure<T>(IntPtr ptr) => DestroyStructure(ptr, typeof(T));
843 #if FEATURE_COMINTEROP
845 /// Returns the HInstance for this module. Returns -1 if the module doesn't have
846 /// an HInstance. In Memory (Dynamic) Modules won't have an HInstance.
848 public static IntPtr GetHINSTANCE(Module m)
852 throw new ArgumentNullException(nameof(m));
855 RuntimeModule rtModule = m as RuntimeModule;
856 if (rtModule == null && m is ModuleBuilder mb)
858 rtModule = mb.InternalModule;
861 if (rtModule == null)
863 throw new ArgumentNullException(nameof(m), SR.Argument_MustBeRuntimeModule);
866 return GetHINSTANCE(rtModule.GetNativeHandle());
869 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
870 private static extern IntPtr GetHINSTANCE(RuntimeModule m);
872 #endif // FEATURE_COMINTEROP
875 /// Throws a CLR exception based on the HRESULT.
877 public static void ThrowExceptionForHR(int errorCode)
881 ThrowExceptionForHRInternal(errorCode, IntPtr.Zero);
885 public static void ThrowExceptionForHR(int errorCode, IntPtr errorInfo)
889 ThrowExceptionForHRInternal(errorCode, errorInfo);
893 [MethodImpl(MethodImplOptions.InternalCall)]
894 internal static extern void ThrowExceptionForHRInternal(int errorCode, IntPtr errorInfo);
897 /// Converts the HRESULT to a CLR exception.
899 public static Exception GetExceptionForHR(int errorCode)
906 return GetExceptionForHRInternal(errorCode, IntPtr.Zero);
908 public static Exception GetExceptionForHR(int errorCode, IntPtr errorInfo)
915 return GetExceptionForHRInternal(errorCode, errorInfo);
918 [MethodImpl(MethodImplOptions.InternalCall)]
919 internal static extern Exception GetExceptionForHRInternal(int errorCode, IntPtr errorInfo);
921 public static IntPtr AllocHGlobal(IntPtr cb)
923 // For backwards compatibility on 32 bit platforms, ensure we pass values between
924 // int.MaxValue and uint.MaxValue to Windows. If the binary has had the
925 // LARGEADDRESSAWARE bit set in the PE header, it may get 3 or 4 GB of user mode
926 // address space. It is remotely that those allocations could have succeeded,
927 // though I couldn't reproduce that. In either case, that means we should continue
928 // throwing an OOM instead of an ArgumentOutOfRangeException for "negative" amounts of memory.
931 numBytes = new UIntPtr(unchecked((ulong)cb.ToInt64()));
933 numBytes = new UIntPtr(unchecked((uint)cb.ToInt32()));
936 IntPtr pNewMem = Win32Native.LocalAlloc_NoSafeHandle(LMEM_FIXED, unchecked(numBytes));
937 if (pNewMem == IntPtr.Zero)
939 throw new OutOfMemoryException();
945 public static IntPtr AllocHGlobal(int cb) => AllocHGlobal((IntPtr)cb);
947 public static void FreeHGlobal(IntPtr hglobal)
949 if (!IsWin32Atom(hglobal))
951 if (IntPtr.Zero != Win32Native.LocalFree(hglobal))
953 ThrowExceptionForHR(GetHRForLastWin32Error());
958 public static IntPtr ReAllocHGlobal(IntPtr pv, IntPtr cb)
960 IntPtr pNewMem = Win32Native.LocalReAlloc(pv, cb, LMEM_MOVEABLE);
961 if (pNewMem == IntPtr.Zero)
963 throw new OutOfMemoryException();
969 public static unsafe IntPtr StringToHGlobalAnsi(string s)
976 int nb = (s.Length + 1) * SystemMaxDBCSCharSize;
981 throw new ArgumentOutOfRangeException(nameof(s));
984 UIntPtr len = new UIntPtr((uint)nb);
985 IntPtr hglobal = Win32Native.LocalAlloc_NoSafeHandle(LMEM_FIXED, len);
986 if (hglobal == IntPtr.Zero)
988 throw new OutOfMemoryException();
991 s.ConvertToAnsi((byte*)hglobal, nb, false, false);
995 public static unsafe IntPtr StringToHGlobalUni(string s)
1002 int nb = (s.Length + 1) * 2;
1004 // Overflow checking
1007 throw new ArgumentOutOfRangeException(nameof(s));
1010 UIntPtr len = new UIntPtr((uint)nb);
1011 IntPtr hglobal = Win32Native.LocalAlloc_NoSafeHandle(LMEM_FIXED, len);
1012 if (hglobal == IntPtr.Zero)
1014 throw new OutOfMemoryException();
1017 fixed (char* firstChar = s)
1019 string.wstrcpy((char*)hglobal, firstChar, s.Length + 1);
1024 public static IntPtr StringToHGlobalAuto(string s)
1026 // Ansi platforms are no longer supported
1027 return StringToHGlobalUni(s);
1030 #if FEATURE_COMINTEROP
1032 /// Converts the CLR exception to an HRESULT. This function also sets
1033 /// up an IErrorInfo for the exception.
1035 [MethodImpl(MethodImplOptions.InternalCall)]
1036 public static extern int GetHRForException(Exception e);
1039 /// Converts the CLR exception to an HRESULT. This function also sets
1040 /// up an IErrorInfo for the exception.
1041 /// This function is only used in WinRT and converts ObjectDisposedException
1044 [MethodImpl(MethodImplOptions.InternalCall)]
1045 internal static extern int GetHRForException_WinRT(Exception e);
1048 /// Given a managed object that wraps an ITypeInfo, return its name.
1050 public static string GetTypeInfoName(ITypeInfo typeInfo)
1052 if (typeInfo == null)
1054 throw new ArgumentNullException(nameof(typeInfo));
1057 typeInfo.GetDocumentation(-1, out string strTypeLibName, out _, out _, out _);
1058 return strTypeLibName;
1061 // This method is identical to Type.GetTypeFromCLSID. Since it's interop specific, we expose it
1062 // on Marshal for more consistent API surface.
1063 public static Type GetTypeFromCLSID(Guid clsid) => RuntimeType.GetTypeFromCLSIDImpl(clsid, null, throwOnError: false);
1066 /// Return the IUnknown* for an Object if the current context is the one
1067 /// where the RCW was first seen. Will return null otherwise.
1069 public static IntPtr /* IUnknown* */ GetIUnknownForObject(object o)
1071 return GetIUnknownForObjectNative(o, false);
1074 [MethodImpl(MethodImplOptions.InternalCall)]
1075 private static extern IntPtr /* IUnknown* */ GetIUnknownForObjectNative(object o, bool onlyInContext);
1078 /// Return the raw IUnknown* for a COM Object not related to current.
1079 /// Does not call AddRef.
1081 [MethodImpl(MethodImplOptions.InternalCall)]
1082 internal static extern IntPtr /* IUnknown* */ GetRawIUnknownForComObjectNoAddRef(object o);
1083 #endif // FEATURE_COMINTEROP
1085 public static IntPtr /* IDispatch */ GetIDispatchForObject(object o) => throw new PlatformNotSupportedException();
1087 #if FEATURE_COMINTEROP
1089 /// Return the IUnknown* representing the interface for the Object.
1090 /// Object o should support Type T
1092 public static IntPtr /* IUnknown* */ GetComInterfaceForObject(object o, Type T)
1094 return GetComInterfaceForObjectNative(o, T, false, true);
1097 public static IntPtr GetComInterfaceForObject<T, TInterface>(T o) => GetComInterfaceForObject(o, typeof(TInterface));
1100 /// Return the IUnknown* representing the interface for the Object.
1101 /// Object o should support Type T, it refer the value of mode to
1102 /// invoke customized QueryInterface or not.
1104 public static IntPtr /* IUnknown* */ GetComInterfaceForObject(object o, Type T, CustomQueryInterfaceMode mode)
1106 bool bEnableCustomizedQueryInterface = ((mode == CustomQueryInterfaceMode.Allow) ? true : false);
1107 return GetComInterfaceForObjectNative(o, T, false, bEnableCustomizedQueryInterface);
1110 [MethodImpl(MethodImplOptions.InternalCall)]
1111 private static extern IntPtr /* IUnknown* */ GetComInterfaceForObjectNative(object o, Type t, bool onlyInContext, bool fEnalbeCustomizedQueryInterface);
1113 [MethodImpl(MethodImplOptions.InternalCall)]
1114 public static extern object GetObjectForIUnknown(IntPtr /* IUnknown* */ pUnk);
1117 /// Return a unique Object given an IUnknown. This ensures that you receive a fresh
1118 /// object (we will not look in the cache to match up this IUnknown to an already
1119 /// existing object). This is useful in cases where you want to be able to call
1120 /// ReleaseComObject on a RCW and not worry about other active uses ofsaid RCW.
1122 [MethodImpl(MethodImplOptions.InternalCall)]
1123 public static extern object GetUniqueObjectForIUnknown(IntPtr unknown);
1126 /// Return an Object for IUnknown, using the Type T.
1127 /// Type T should be either a COM imported Type or a sub-type of COM imported Type
1129 [MethodImpl(MethodImplOptions.InternalCall)]
1130 public static extern object GetTypedObjectForIUnknown(IntPtr /* IUnknown* */ pUnk, Type t);
1132 [MethodImpl(MethodImplOptions.InternalCall)]
1133 public static extern IntPtr CreateAggregatedObject(IntPtr pOuter, object o);
1135 public static IntPtr CreateAggregatedObject<T>(IntPtr pOuter, T o)
1137 return CreateAggregatedObject(pOuter, (object)o);
1140 [MethodImpl(MethodImplOptions.InternalCall)]
1141 public static extern void CleanupUnusedObjectsInCurrentContext();
1143 [MethodImpl(MethodImplOptions.InternalCall)]
1144 public static extern bool AreComObjectsAvailableForCleanup();
1147 /// Checks if the object is classic COM component.
1149 [MethodImpl(MethodImplOptions.InternalCall)]
1150 public static extern bool IsComObject(object o);
1152 #endif // FEATURE_COMINTEROP
1154 public static IntPtr AllocCoTaskMem(int cb)
1156 IntPtr pNewMem = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)cb));
1157 if (pNewMem == IntPtr.Zero)
1159 throw new OutOfMemoryException();
1165 public static unsafe IntPtr StringToCoTaskMemUni(string s)
1172 int nb = (s.Length + 1) * 2;
1174 // Overflow checking
1177 throw new ArgumentOutOfRangeException(nameof(s));
1180 IntPtr hglobal = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)nb));
1181 if (hglobal == IntPtr.Zero)
1183 throw new OutOfMemoryException();
1186 fixed (char* firstChar = s)
1188 string.wstrcpy((char*)hglobal, firstChar, s.Length + 1);
1193 public static unsafe IntPtr StringToCoTaskMemUTF8(string s)
1200 int nb = Encoding.UTF8.GetMaxByteCount(s.Length);
1201 IntPtr pMem = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)nb + 1));
1202 if (pMem == IntPtr.Zero)
1204 throw new OutOfMemoryException();
1207 fixed (char* firstChar = s)
1209 byte* pbMem = (byte*)pMem;
1210 int nbWritten = Encoding.UTF8.GetBytes(firstChar, s.Length, pbMem, nb);
1211 pbMem[nbWritten] = 0;
1216 public static IntPtr StringToCoTaskMemAuto(string s)
1218 // Ansi platforms are no longer supported
1219 return StringToCoTaskMemUni(s);
1222 public static unsafe IntPtr StringToCoTaskMemAnsi(string s)
1229 int nb = (s.Length + 1) * SystemMaxDBCSCharSize;
1231 // Overflow checking
1234 throw new ArgumentOutOfRangeException(nameof(s));
1237 IntPtr hglobal = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)nb));
1238 if (hglobal == IntPtr.Zero)
1240 throw new OutOfMemoryException();
1243 s.ConvertToAnsi((byte*)hglobal, nb, false, false);
1247 public static void FreeCoTaskMem(IntPtr ptr)
1249 if (!IsWin32Atom(ptr))
1251 Win32Native.CoTaskMemFree(ptr);
1255 public static IntPtr ReAllocCoTaskMem(IntPtr pv, int cb)
1257 IntPtr pNewMem = Win32Native.CoTaskMemRealloc(pv, new UIntPtr((uint)cb));
1258 if (pNewMem == IntPtr.Zero && cb != 0)
1260 throw new OutOfMemoryException();
1266 public static void FreeBSTR(IntPtr ptr)
1268 if (!IsWin32Atom(ptr))
1270 Win32Native.SysFreeString(ptr);
1274 public static IntPtr StringToBSTR(string s)
1281 // Overflow checking
1282 if (s.Length + 1 < s.Length)
1284 throw new ArgumentOutOfRangeException(nameof(s));
1287 IntPtr bstr = Win32Native.SysAllocStringLen(s, s.Length);
1288 if (bstr == IntPtr.Zero)
1290 throw new OutOfMemoryException();
1296 public static string PtrToStringBSTR(IntPtr ptr)
1298 return PtrToStringUni(ptr, (int)Win32Native.SysStringLen(ptr));
1301 #if FEATURE_COMINTEROP
1303 /// Release the COM component and if the reference hits 0 zombie this object.
1304 /// Further usage of this Object might throw an exception
1306 public static int ReleaseComObject(object o)
1308 if (!(o is __ComObject co))
1310 throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(o));
1313 return co.ReleaseSelf();
1316 [MethodImpl(MethodImplOptions.InternalCall)]
1317 internal static extern int InternalReleaseComObject(object o);
1320 /// Release the COM component and zombie this object.
1321 /// Further usage of this Object might throw an exception
1323 public static int FinalReleaseComObject(object o)
1327 throw new ArgumentNullException(nameof(o));
1329 if (!(o is __ComObject co))
1331 throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(o));
1334 co.FinalReleaseSelf();
1338 [MethodImpl(MethodImplOptions.InternalCall)]
1339 internal static extern void InternalFinalReleaseComObject(object o);
1341 public static object GetComObjectData(object obj, object key)
1345 throw new ArgumentNullException(nameof(obj));
1349 throw new ArgumentNullException(nameof(key));
1351 if (!(obj is __ComObject co))
1353 throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(obj));
1355 if (obj.GetType().IsWindowsRuntimeObject)
1357 throw new ArgumentException(SR.Argument_ObjIsWinRTObject, nameof(obj));
1360 // Retrieve the data from the __ComObject.
1361 return co.GetData(key);
1365 /// Sets data on the COM object. The data can only be set once for a given key
1366 /// and cannot be removed. This function returns true if the data has been added,
1367 /// false if the data could not be added because there already was data for the
1370 public static bool SetComObjectData(object obj, object key, object data)
1374 throw new ArgumentNullException(nameof(obj));
1378 throw new ArgumentNullException(nameof(key));
1380 if (!(obj is __ComObject co))
1382 throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(obj));
1384 if (obj.GetType().IsWindowsRuntimeObject)
1386 throw new ArgumentException(SR.Argument_ObjIsWinRTObject, nameof(obj));
1389 // Retrieve the data from the __ComObject.
1390 return co.SetData(key, data);
1394 /// This method takes the given COM object and wraps it in an object
1395 /// of the specified type. The type must be derived from __ComObject.
1397 public static object CreateWrapperOfType(object o, Type t)
1401 throw new ArgumentNullException(nameof(t));
1405 throw new ArgumentException(SR.Argument_TypeNotComObject, nameof(t));
1407 if (t.IsGenericType)
1409 throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(t));
1411 if (t.IsWindowsRuntimeObject)
1413 throw new ArgumentException(SR.Argument_TypeIsWinRTType, nameof(t));
1421 if (!o.GetType().IsCOMObject)
1423 throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(o));
1425 if (o.GetType().IsWindowsRuntimeObject)
1427 throw new ArgumentException(SR.Argument_ObjIsWinRTObject, nameof(o));
1430 // Check to see if we have nothing to do.
1431 if (o.GetType() == t)
1436 // Check to see if we already have a cached wrapper for this type.
1437 object Wrapper = GetComObjectData(o, t);
1438 if (Wrapper == null)
1440 // Create the wrapper for the specified type.
1441 Wrapper = InternalCreateWrapperOfType(o, t);
1443 // Attempt to cache the wrapper on the object.
1444 if (!SetComObjectData(o, t, Wrapper))
1446 // Another thead already cached the wrapper so use that one instead.
1447 Wrapper = GetComObjectData(o, t);
1454 public static TWrapper CreateWrapperOfType<T, TWrapper>(T o)
1456 return (TWrapper)CreateWrapperOfType(o, typeof(TWrapper));
1459 [MethodImpl(MethodImplOptions.InternalCall)]
1460 private static extern object InternalCreateWrapperOfType(object o, Type t);
1463 /// check if the type is visible from COM.
1465 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1466 public static extern bool IsTypeVisibleFromCom(Type t);
1468 [MethodImpl(MethodImplOptions.InternalCall)]
1469 public static extern int /* HRESULT */ QueryInterface(IntPtr /* IUnknown */ pUnk, ref Guid iid, out IntPtr ppv);
1471 [MethodImpl(MethodImplOptions.InternalCall)]
1472 public static extern int /* ULONG */ AddRef(IntPtr /* IUnknown */ pUnk);
1474 [MethodImpl(MethodImplOptions.InternalCall)]
1475 public static extern int /* ULONG */ Release(IntPtr /* IUnknown */ pUnk);
1477 [MethodImpl(MethodImplOptions.InternalCall)]
1478 public static extern void GetNativeVariantForObject(object obj, /* VARIANT * */ IntPtr pDstNativeVariant);
1480 public static void GetNativeVariantForObject<T>(T obj, IntPtr pDstNativeVariant)
1482 GetNativeVariantForObject((object)obj, pDstNativeVariant);
1485 [MethodImpl(MethodImplOptions.InternalCall)]
1486 public static extern object GetObjectForNativeVariant(/* VARIANT * */ IntPtr pSrcNativeVariant);
1488 public static T GetObjectForNativeVariant<T>(IntPtr pSrcNativeVariant)
1490 return (T)GetObjectForNativeVariant(pSrcNativeVariant);
1493 [MethodImpl(MethodImplOptions.InternalCall)]
1494 public static extern object[] GetObjectsForNativeVariants(/* VARIANT * */ IntPtr aSrcNativeVariant, int cVars);
1496 public static T[] GetObjectsForNativeVariants<T>(IntPtr aSrcNativeVariant, int cVars)
1498 object[] objects = GetObjectsForNativeVariants(aSrcNativeVariant, cVars);
1501 if (objects != null)
1503 result = new T[objects.Length];
1504 Array.Copy(objects, result, objects.Length);
1511 /// <para>Returns the first valid COM slot that GetMethodInfoForSlot will work on
1512 /// This will be 3 for IUnknown based interfaces and 7 for IDispatch based interfaces. </para>
1514 [MethodImpl(MethodImplOptions.InternalCall)]
1515 public static extern int GetStartComSlot(Type t);
1518 /// <para>Returns the last valid COM slot that GetMethodInfoForSlot will work on. </para>
1520 [MethodImpl(MethodImplOptions.InternalCall)]
1521 public static extern int GetEndComSlot(Type t);
1522 #endif // FEATURE_COMINTEROP
1525 /// Generates a GUID for the specified type. If the type has a GUID in the
1526 /// metadata then it is returned otherwise a stable guid is generated based
1527 /// on the fully qualified name of the type.
1529 public static Guid GenerateGuidForType(Type type) => type.GUID;
1532 /// This method generates a PROGID for the specified type. If the type has
1533 /// a PROGID in the metadata then it is returned otherwise a stable PROGID
1534 /// is generated based on the fully qualified name of the type.
1536 public static string GenerateProgIdForType(Type type)
1540 throw new ArgumentNullException(nameof(type));
1544 throw new ArgumentException(SR.Argument_TypeMustNotBeComImport, nameof(type));
1546 if (type.IsGenericType)
1548 throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(type));
1551 IList<CustomAttributeData> cas = CustomAttributeData.GetCustomAttributes(type);
1552 for (int i = 0; i < cas.Count; i++)
1554 if (cas[i].Constructor.DeclaringType == typeof(ProgIdAttribute))
1556 // Retrieve the PROGID string from the ProgIdAttribute.
1557 IList<CustomAttributeTypedArgument> caConstructorArgs = cas[i].ConstructorArguments;
1558 Debug.Assert(caConstructorArgs.Count == 1, "caConstructorArgs.Count == 1");
1560 CustomAttributeTypedArgument progIdConstructorArg = caConstructorArgs[0];
1561 Debug.Assert(progIdConstructorArg.ArgumentType == typeof(string), "progIdConstructorArg.ArgumentType == typeof(String)");
1563 string strProgId = (string)progIdConstructorArg.Value;
1565 if (strProgId == null)
1566 strProgId = string.Empty;
1572 // If there is no prog ID attribute then use the full name of the type as the prog id.
1573 return type.FullName;
1576 #if FEATURE_COMINTEROP
1577 public static object BindToMoniker(string monikerName)
1579 CreateBindCtx(0, out IBindCtx bindctx);
1581 MkParseDisplayName(bindctx, monikerName, out _, out IMoniker pmoniker);
1582 BindMoniker(pmoniker, 0, ref IID_IUnknown, out object obj);
1587 [DllImport(Interop.Libraries.Ole32, PreserveSig = false)]
1588 private static extern void CreateBindCtx(uint reserved, out IBindCtx ppbc);
1590 [DllImport(Interop.Libraries.Ole32, PreserveSig = false)]
1591 private static extern void MkParseDisplayName(IBindCtx pbc, [MarshalAs(UnmanagedType.LPWStr)] string szUserName, out uint pchEaten, out IMoniker ppmk);
1593 [DllImport(Interop.Libraries.Ole32, PreserveSig = false)]
1594 private static extern void BindMoniker(IMoniker pmk, uint grfOpt, ref Guid iidResult, [MarshalAs(UnmanagedType.Interface)] out object ppvResult);
1597 /// Private method called from EE upon use of license/ICF2 marshaling.
1599 private static IntPtr LoadLicenseManager()
1601 Type t = Type.GetType("System.ComponentModel.LicenseManager, System", throwOnError: true);
1602 return t.TypeHandle.Value;
1605 [MethodImpl(MethodImplOptions.InternalCall)]
1606 public static extern void ChangeWrapperHandleStrength(object otp, bool fIsWeak);
1608 [MethodImpl(MethodImplOptions.InternalCall)]
1609 internal static extern void InitializeWrapperForWinRT(object o, ref IntPtr pUnk);
1611 #if FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION
1612 [MethodImpl(MethodImplOptions.InternalCall)]
1613 internal static extern void InitializeManagedWinRTFactoryObject(object o, RuntimeType runtimeClassType);
1617 /// Create activation factory and wraps it with a unique RCW.
1619 [MethodImpl(MethodImplOptions.InternalCall)]
1620 internal static extern object GetNativeActivationFactory(Type type);
1622 #endif // FEATURE_COMINTEROP
1624 public static Delegate GetDelegateForFunctionPointer(IntPtr ptr, Type t)
1626 if (ptr == IntPtr.Zero)
1628 throw new ArgumentNullException(nameof(ptr));
1632 throw new ArgumentNullException(nameof(t));
1634 if (!(t is RuntimeType))
1636 throw new ArgumentException(SR.Argument_MustBeRuntimeType, nameof(t));
1638 if (t.IsGenericType)
1640 throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(t));
1643 Type c = t.BaseType;
1644 if (c == null || (c != typeof(Delegate) && c != typeof(MulticastDelegate)))
1646 throw new ArgumentException(SR.Arg_MustBeDelegate, nameof(t));
1649 return GetDelegateForFunctionPointerInternal(ptr, t);
1652 public static TDelegate GetDelegateForFunctionPointer<TDelegate>(IntPtr ptr)
1654 return (TDelegate)(object)GetDelegateForFunctionPointer(ptr, typeof(TDelegate));
1657 [MethodImpl(MethodImplOptions.InternalCall)]
1658 internal static extern Delegate GetDelegateForFunctionPointerInternal(IntPtr ptr, Type t);
1660 public static IntPtr GetFunctionPointerForDelegate(Delegate d)
1664 throw new ArgumentNullException(nameof(d));
1667 return GetFunctionPointerForDelegateInternal(d);
1670 public static IntPtr GetFunctionPointerForDelegate<TDelegate>(TDelegate d)
1672 return GetFunctionPointerForDelegate((Delegate)(object)d);
1675 [MethodImpl(MethodImplOptions.InternalCall)]
1676 internal static extern IntPtr GetFunctionPointerForDelegateInternal(Delegate d);
1678 public static IntPtr SecureStringToBSTR(SecureString s)
1682 throw new ArgumentNullException(nameof(s));
1685 return s.MarshalToBSTR();
1688 public static IntPtr SecureStringToCoTaskMemAnsi(SecureString s)
1692 throw new ArgumentNullException(nameof(s));
1695 return s.MarshalToString(globalAlloc: false, unicode: false);
1698 public static IntPtr SecureStringToCoTaskMemUnicode(SecureString s)
1702 throw new ArgumentNullException(nameof(s));
1705 return s.MarshalToString(globalAlloc: false, unicode: true);
1708 public static void ZeroFreeBSTR(IntPtr s)
1710 RuntimeImports.RhZeroMemory(s, (UIntPtr)(Win32Native.SysStringLen(s) * 2));
1714 public static void ZeroFreeCoTaskMemAnsi(IntPtr s)
1716 RuntimeImports.RhZeroMemory(s, (UIntPtr)(Win32Native.lstrlenA(s)));
1720 public static void ZeroFreeCoTaskMemUnicode(IntPtr s)
1722 RuntimeImports.RhZeroMemory(s, (UIntPtr)(Win32Native.lstrlenW(s) * 2));
1726 public static unsafe void ZeroFreeCoTaskMemUTF8(IntPtr s)
1728 RuntimeImports.RhZeroMemory(s, (UIntPtr)System.StubHelpers.StubHelpers.strlen((sbyte*)s));
1732 public static IntPtr SecureStringToGlobalAllocAnsi(SecureString s)
1736 throw new ArgumentNullException(nameof(s));
1739 return s.MarshalToString(globalAlloc: true, unicode: false);
1742 public static IntPtr SecureStringToGlobalAllocUnicode(SecureString s)
1746 throw new ArgumentNullException(nameof(s));
1749 return s.MarshalToString(globalAlloc: true, unicode: true); ;
1752 public static void ZeroFreeGlobalAllocAnsi(IntPtr s)
1754 RuntimeImports.RhZeroMemory(s, (UIntPtr)(Win32Native.lstrlenA(s)));
1758 public static void ZeroFreeGlobalAllocUnicode(IntPtr s)
1760 RuntimeImports.RhZeroMemory(s, (UIntPtr)(Win32Native.lstrlenW(s) * 2));