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 if (m is RuntimeModule rtModule)
858 return GetHINSTANCE(rtModule.GetNativeHandle());
864 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
865 private static extern IntPtr GetHINSTANCE(RuntimeModule m);
867 #endif // FEATURE_COMINTEROP
870 /// Throws a CLR exception based on the HRESULT.
872 public static void ThrowExceptionForHR(int errorCode)
876 ThrowExceptionForHRInternal(errorCode, IntPtr.Zero);
880 public static void ThrowExceptionForHR(int errorCode, IntPtr errorInfo)
884 ThrowExceptionForHRInternal(errorCode, errorInfo);
888 [MethodImpl(MethodImplOptions.InternalCall)]
889 internal static extern void ThrowExceptionForHRInternal(int errorCode, IntPtr errorInfo);
892 /// Converts the HRESULT to a CLR exception.
894 public static Exception GetExceptionForHR(int errorCode)
901 return GetExceptionForHRInternal(errorCode, IntPtr.Zero);
903 public static Exception GetExceptionForHR(int errorCode, IntPtr errorInfo)
910 return GetExceptionForHRInternal(errorCode, errorInfo);
913 [MethodImpl(MethodImplOptions.InternalCall)]
914 internal static extern Exception GetExceptionForHRInternal(int errorCode, IntPtr errorInfo);
916 public static IntPtr AllocHGlobal(IntPtr cb)
918 // For backwards compatibility on 32 bit platforms, ensure we pass values between
919 // int.MaxValue and uint.MaxValue to Windows. If the binary has had the
920 // LARGEADDRESSAWARE bit set in the PE header, it may get 3 or 4 GB of user mode
921 // address space. It is remotely that those allocations could have succeeded,
922 // though I couldn't reproduce that. In either case, that means we should continue
923 // throwing an OOM instead of an ArgumentOutOfRangeException for "negative" amounts of memory.
926 numBytes = new UIntPtr(unchecked((ulong)cb.ToInt64()));
928 numBytes = new UIntPtr(unchecked((uint)cb.ToInt32()));
931 IntPtr pNewMem = Win32Native.LocalAlloc_NoSafeHandle(LMEM_FIXED, unchecked(numBytes));
932 if (pNewMem == IntPtr.Zero)
934 throw new OutOfMemoryException();
940 public static IntPtr AllocHGlobal(int cb) => AllocHGlobal((IntPtr)cb);
942 public static void FreeHGlobal(IntPtr hglobal)
944 if (!IsWin32Atom(hglobal))
946 if (IntPtr.Zero != Win32Native.LocalFree(hglobal))
948 ThrowExceptionForHR(GetHRForLastWin32Error());
953 public static IntPtr ReAllocHGlobal(IntPtr pv, IntPtr cb)
955 IntPtr pNewMem = Win32Native.LocalReAlloc(pv, cb, LMEM_MOVEABLE);
956 if (pNewMem == IntPtr.Zero)
958 throw new OutOfMemoryException();
964 public static unsafe IntPtr StringToHGlobalAnsi(string s)
971 int nb = (s.Length + 1) * SystemMaxDBCSCharSize;
976 throw new ArgumentOutOfRangeException(nameof(s));
979 UIntPtr len = new UIntPtr((uint)nb);
980 IntPtr hglobal = Win32Native.LocalAlloc_NoSafeHandle(LMEM_FIXED, len);
981 if (hglobal == IntPtr.Zero)
983 throw new OutOfMemoryException();
986 s.ConvertToAnsi((byte*)hglobal, nb, false, false);
990 public static unsafe IntPtr StringToHGlobalUni(string s)
997 int nb = (s.Length + 1) * 2;
1002 throw new ArgumentOutOfRangeException(nameof(s));
1005 UIntPtr len = new UIntPtr((uint)nb);
1006 IntPtr hglobal = Win32Native.LocalAlloc_NoSafeHandle(LMEM_FIXED, len);
1007 if (hglobal == IntPtr.Zero)
1009 throw new OutOfMemoryException();
1012 fixed (char* firstChar = s)
1014 string.wstrcpy((char*)hglobal, firstChar, s.Length + 1);
1019 public static IntPtr StringToHGlobalAuto(string s)
1021 // Ansi platforms are no longer supported
1022 return StringToHGlobalUni(s);
1025 #if FEATURE_COMINTEROP
1027 /// Converts the CLR exception to an HRESULT. This function also sets
1028 /// up an IErrorInfo for the exception.
1030 [MethodImpl(MethodImplOptions.InternalCall)]
1031 public static extern int GetHRForException(Exception e);
1034 /// Converts the CLR exception to an HRESULT. This function also sets
1035 /// up an IErrorInfo for the exception.
1036 /// This function is only used in WinRT and converts ObjectDisposedException
1039 [MethodImpl(MethodImplOptions.InternalCall)]
1040 internal static extern int GetHRForException_WinRT(Exception e);
1043 /// Given a managed object that wraps an ITypeInfo, return its name.
1045 public static string GetTypeInfoName(ITypeInfo typeInfo)
1047 if (typeInfo == null)
1049 throw new ArgumentNullException(nameof(typeInfo));
1052 typeInfo.GetDocumentation(-1, out string strTypeLibName, out _, out _, out _);
1053 return strTypeLibName;
1056 // This method is identical to Type.GetTypeFromCLSID. Since it's interop specific, we expose it
1057 // on Marshal for more consistent API surface.
1058 public static Type GetTypeFromCLSID(Guid clsid) => RuntimeType.GetTypeFromCLSIDImpl(clsid, null, throwOnError: false);
1061 /// Return the IUnknown* for an Object if the current context is the one
1062 /// where the RCW was first seen. Will return null otherwise.
1064 public static IntPtr /* IUnknown* */ GetIUnknownForObject(object o)
1066 return GetIUnknownForObjectNative(o, false);
1069 [MethodImpl(MethodImplOptions.InternalCall)]
1070 private static extern IntPtr /* IUnknown* */ GetIUnknownForObjectNative(object o, bool onlyInContext);
1073 /// Return the raw IUnknown* for a COM Object not related to current.
1074 /// Does not call AddRef.
1076 [MethodImpl(MethodImplOptions.InternalCall)]
1077 internal static extern IntPtr /* IUnknown* */ GetRawIUnknownForComObjectNoAddRef(object o);
1078 #endif // FEATURE_COMINTEROP
1080 public static IntPtr /* IDispatch */ GetIDispatchForObject(object o) => throw new PlatformNotSupportedException();
1082 #if FEATURE_COMINTEROP
1084 /// Return the IUnknown* representing the interface for the Object.
1085 /// Object o should support Type T
1087 public static IntPtr /* IUnknown* */ GetComInterfaceForObject(object o, Type T)
1089 return GetComInterfaceForObjectNative(o, T, false, true);
1092 public static IntPtr GetComInterfaceForObject<T, TInterface>(T o) => GetComInterfaceForObject(o, typeof(TInterface));
1095 /// Return the IUnknown* representing the interface for the Object.
1096 /// Object o should support Type T, it refer the value of mode to
1097 /// invoke customized QueryInterface or not.
1099 public static IntPtr /* IUnknown* */ GetComInterfaceForObject(object o, Type T, CustomQueryInterfaceMode mode)
1101 bool bEnableCustomizedQueryInterface = ((mode == CustomQueryInterfaceMode.Allow) ? true : false);
1102 return GetComInterfaceForObjectNative(o, T, false, bEnableCustomizedQueryInterface);
1105 [MethodImpl(MethodImplOptions.InternalCall)]
1106 private static extern IntPtr /* IUnknown* */ GetComInterfaceForObjectNative(object o, Type t, bool onlyInContext, bool fEnalbeCustomizedQueryInterface);
1108 [MethodImpl(MethodImplOptions.InternalCall)]
1109 public static extern object GetObjectForIUnknown(IntPtr /* IUnknown* */ pUnk);
1112 /// Return a unique Object given an IUnknown. This ensures that you receive a fresh
1113 /// object (we will not look in the cache to match up this IUnknown to an already
1114 /// existing object). This is useful in cases where you want to be able to call
1115 /// ReleaseComObject on a RCW and not worry about other active uses ofsaid RCW.
1117 [MethodImpl(MethodImplOptions.InternalCall)]
1118 public static extern object GetUniqueObjectForIUnknown(IntPtr unknown);
1121 /// Return an Object for IUnknown, using the Type T.
1122 /// Type T should be either a COM imported Type or a sub-type of COM imported Type
1124 [MethodImpl(MethodImplOptions.InternalCall)]
1125 public static extern object GetTypedObjectForIUnknown(IntPtr /* IUnknown* */ pUnk, Type t);
1127 [MethodImpl(MethodImplOptions.InternalCall)]
1128 public static extern IntPtr CreateAggregatedObject(IntPtr pOuter, object o);
1130 public static IntPtr CreateAggregatedObject<T>(IntPtr pOuter, T o)
1132 return CreateAggregatedObject(pOuter, (object)o);
1135 [MethodImpl(MethodImplOptions.InternalCall)]
1136 public static extern void CleanupUnusedObjectsInCurrentContext();
1138 [MethodImpl(MethodImplOptions.InternalCall)]
1139 public static extern bool AreComObjectsAvailableForCleanup();
1142 /// Checks if the object is classic COM component.
1144 [MethodImpl(MethodImplOptions.InternalCall)]
1145 public static extern bool IsComObject(object o);
1147 #endif // FEATURE_COMINTEROP
1149 public static IntPtr AllocCoTaskMem(int cb)
1151 IntPtr pNewMem = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)cb));
1152 if (pNewMem == IntPtr.Zero)
1154 throw new OutOfMemoryException();
1160 public static unsafe IntPtr StringToCoTaskMemUni(string s)
1167 int nb = (s.Length + 1) * 2;
1169 // Overflow checking
1172 throw new ArgumentOutOfRangeException(nameof(s));
1175 IntPtr hglobal = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)nb));
1176 if (hglobal == IntPtr.Zero)
1178 throw new OutOfMemoryException();
1181 fixed (char* firstChar = s)
1183 string.wstrcpy((char*)hglobal, firstChar, s.Length + 1);
1188 public static unsafe IntPtr StringToCoTaskMemUTF8(string s)
1195 int nb = Encoding.UTF8.GetMaxByteCount(s.Length);
1196 IntPtr pMem = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)nb + 1));
1197 if (pMem == IntPtr.Zero)
1199 throw new OutOfMemoryException();
1202 fixed (char* firstChar = s)
1204 byte* pbMem = (byte*)pMem;
1205 int nbWritten = Encoding.UTF8.GetBytes(firstChar, s.Length, pbMem, nb);
1206 pbMem[nbWritten] = 0;
1211 public static IntPtr StringToCoTaskMemAuto(string s)
1213 // Ansi platforms are no longer supported
1214 return StringToCoTaskMemUni(s);
1217 public static unsafe IntPtr StringToCoTaskMemAnsi(string s)
1224 int nb = (s.Length + 1) * SystemMaxDBCSCharSize;
1226 // Overflow checking
1229 throw new ArgumentOutOfRangeException(nameof(s));
1232 IntPtr hglobal = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)nb));
1233 if (hglobal == IntPtr.Zero)
1235 throw new OutOfMemoryException();
1238 s.ConvertToAnsi((byte*)hglobal, nb, false, false);
1242 public static void FreeCoTaskMem(IntPtr ptr)
1244 if (!IsWin32Atom(ptr))
1246 Win32Native.CoTaskMemFree(ptr);
1250 public static IntPtr ReAllocCoTaskMem(IntPtr pv, int cb)
1252 IntPtr pNewMem = Win32Native.CoTaskMemRealloc(pv, new UIntPtr((uint)cb));
1253 if (pNewMem == IntPtr.Zero && cb != 0)
1255 throw new OutOfMemoryException();
1261 public static void FreeBSTR(IntPtr ptr)
1263 if (!IsWin32Atom(ptr))
1265 Win32Native.SysFreeString(ptr);
1269 public static IntPtr StringToBSTR(string s)
1276 // Overflow checking
1277 if (s.Length + 1 < s.Length)
1279 throw new ArgumentOutOfRangeException(nameof(s));
1282 IntPtr bstr = Win32Native.SysAllocStringLen(s, s.Length);
1283 if (bstr == IntPtr.Zero)
1285 throw new OutOfMemoryException();
1291 public static string PtrToStringBSTR(IntPtr ptr)
1293 return PtrToStringUni(ptr, (int)Win32Native.SysStringLen(ptr));
1296 #if FEATURE_COMINTEROP
1298 /// Release the COM component and if the reference hits 0 zombie this object.
1299 /// Further usage of this Object might throw an exception
1301 public static int ReleaseComObject(object o)
1303 if (!(o is __ComObject co))
1305 throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(o));
1308 return co.ReleaseSelf();
1311 [MethodImpl(MethodImplOptions.InternalCall)]
1312 internal static extern int InternalReleaseComObject(object o);
1315 /// Release the COM component and zombie this object.
1316 /// Further usage of this Object might throw an exception
1318 public static int FinalReleaseComObject(object o)
1322 throw new ArgumentNullException(nameof(o));
1324 if (!(o is __ComObject co))
1326 throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(o));
1329 co.FinalReleaseSelf();
1333 [MethodImpl(MethodImplOptions.InternalCall)]
1334 internal static extern void InternalFinalReleaseComObject(object o);
1336 public static object GetComObjectData(object obj, object key)
1340 throw new ArgumentNullException(nameof(obj));
1344 throw new ArgumentNullException(nameof(key));
1346 if (!(obj is __ComObject co))
1348 throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(obj));
1350 if (obj.GetType().IsWindowsRuntimeObject)
1352 throw new ArgumentException(SR.Argument_ObjIsWinRTObject, nameof(obj));
1355 // Retrieve the data from the __ComObject.
1356 return co.GetData(key);
1360 /// Sets data on the COM object. The data can only be set once for a given key
1361 /// and cannot be removed. This function returns true if the data has been added,
1362 /// false if the data could not be added because there already was data for the
1365 public static bool SetComObjectData(object obj, object key, object data)
1369 throw new ArgumentNullException(nameof(obj));
1373 throw new ArgumentNullException(nameof(key));
1375 if (!(obj is __ComObject co))
1377 throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(obj));
1379 if (obj.GetType().IsWindowsRuntimeObject)
1381 throw new ArgumentException(SR.Argument_ObjIsWinRTObject, nameof(obj));
1384 // Retrieve the data from the __ComObject.
1385 return co.SetData(key, data);
1389 /// This method takes the given COM object and wraps it in an object
1390 /// of the specified type. The type must be derived from __ComObject.
1392 public static object CreateWrapperOfType(object o, Type t)
1396 throw new ArgumentNullException(nameof(t));
1400 throw new ArgumentException(SR.Argument_TypeNotComObject, nameof(t));
1402 if (t.IsGenericType)
1404 throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(t));
1406 if (t.IsWindowsRuntimeObject)
1408 throw new ArgumentException(SR.Argument_TypeIsWinRTType, nameof(t));
1416 if (!o.GetType().IsCOMObject)
1418 throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(o));
1420 if (o.GetType().IsWindowsRuntimeObject)
1422 throw new ArgumentException(SR.Argument_ObjIsWinRTObject, nameof(o));
1425 // Check to see if we have nothing to do.
1426 if (o.GetType() == t)
1431 // Check to see if we already have a cached wrapper for this type.
1432 object Wrapper = GetComObjectData(o, t);
1433 if (Wrapper == null)
1435 // Create the wrapper for the specified type.
1436 Wrapper = InternalCreateWrapperOfType(o, t);
1438 // Attempt to cache the wrapper on the object.
1439 if (!SetComObjectData(o, t, Wrapper))
1441 // Another thead already cached the wrapper so use that one instead.
1442 Wrapper = GetComObjectData(o, t);
1449 public static TWrapper CreateWrapperOfType<T, TWrapper>(T o)
1451 return (TWrapper)CreateWrapperOfType(o, typeof(TWrapper));
1454 [MethodImpl(MethodImplOptions.InternalCall)]
1455 private static extern object InternalCreateWrapperOfType(object o, Type t);
1458 /// check if the type is visible from COM.
1460 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1461 public static extern bool IsTypeVisibleFromCom(Type t);
1463 [MethodImpl(MethodImplOptions.InternalCall)]
1464 public static extern int /* HRESULT */ QueryInterface(IntPtr /* IUnknown */ pUnk, ref Guid iid, out IntPtr ppv);
1466 [MethodImpl(MethodImplOptions.InternalCall)]
1467 public static extern int /* ULONG */ AddRef(IntPtr /* IUnknown */ pUnk);
1469 [MethodImpl(MethodImplOptions.InternalCall)]
1470 public static extern int /* ULONG */ Release(IntPtr /* IUnknown */ pUnk);
1472 [MethodImpl(MethodImplOptions.InternalCall)]
1473 public static extern void GetNativeVariantForObject(object obj, /* VARIANT * */ IntPtr pDstNativeVariant);
1475 public static void GetNativeVariantForObject<T>(T obj, IntPtr pDstNativeVariant)
1477 GetNativeVariantForObject((object)obj, pDstNativeVariant);
1480 [MethodImpl(MethodImplOptions.InternalCall)]
1481 public static extern object GetObjectForNativeVariant(/* VARIANT * */ IntPtr pSrcNativeVariant);
1483 public static T GetObjectForNativeVariant<T>(IntPtr pSrcNativeVariant)
1485 return (T)GetObjectForNativeVariant(pSrcNativeVariant);
1488 [MethodImpl(MethodImplOptions.InternalCall)]
1489 public static extern object[] GetObjectsForNativeVariants(/* VARIANT * */ IntPtr aSrcNativeVariant, int cVars);
1491 public static T[] GetObjectsForNativeVariants<T>(IntPtr aSrcNativeVariant, int cVars)
1493 object[] objects = GetObjectsForNativeVariants(aSrcNativeVariant, cVars);
1496 if (objects != null)
1498 result = new T[objects.Length];
1499 Array.Copy(objects, result, objects.Length);
1506 /// <para>Returns the first valid COM slot that GetMethodInfoForSlot will work on
1507 /// This will be 3 for IUnknown based interfaces and 7 for IDispatch based interfaces. </para>
1509 [MethodImpl(MethodImplOptions.InternalCall)]
1510 public static extern int GetStartComSlot(Type t);
1513 /// <para>Returns the last valid COM slot that GetMethodInfoForSlot will work on. </para>
1515 [MethodImpl(MethodImplOptions.InternalCall)]
1516 public static extern int GetEndComSlot(Type t);
1517 #endif // FEATURE_COMINTEROP
1520 /// Generates a GUID for the specified type. If the type has a GUID in the
1521 /// metadata then it is returned otherwise a stable guid is generated based
1522 /// on the fully qualified name of the type.
1524 public static Guid GenerateGuidForType(Type type) => type.GUID;
1527 /// This method generates a PROGID for the specified type. If the type has
1528 /// a PROGID in the metadata then it is returned otherwise a stable PROGID
1529 /// is generated based on the fully qualified name of the type.
1531 public static string GenerateProgIdForType(Type type)
1535 throw new ArgumentNullException(nameof(type));
1539 throw new ArgumentException(SR.Argument_TypeMustNotBeComImport, nameof(type));
1541 if (type.IsGenericType)
1543 throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(type));
1546 IList<CustomAttributeData> cas = CustomAttributeData.GetCustomAttributes(type);
1547 for (int i = 0; i < cas.Count; i++)
1549 if (cas[i].Constructor.DeclaringType == typeof(ProgIdAttribute))
1551 // Retrieve the PROGID string from the ProgIdAttribute.
1552 IList<CustomAttributeTypedArgument> caConstructorArgs = cas[i].ConstructorArguments;
1553 Debug.Assert(caConstructorArgs.Count == 1, "caConstructorArgs.Count == 1");
1555 CustomAttributeTypedArgument progIdConstructorArg = caConstructorArgs[0];
1556 Debug.Assert(progIdConstructorArg.ArgumentType == typeof(string), "progIdConstructorArg.ArgumentType == typeof(String)");
1558 string strProgId = (string)progIdConstructorArg.Value;
1560 if (strProgId == null)
1561 strProgId = string.Empty;
1567 // If there is no prog ID attribute then use the full name of the type as the prog id.
1568 return type.FullName;
1571 #if FEATURE_COMINTEROP
1572 public static object BindToMoniker(string monikerName)
1574 CreateBindCtx(0, out IBindCtx bindctx);
1576 MkParseDisplayName(bindctx, monikerName, out _, out IMoniker pmoniker);
1577 BindMoniker(pmoniker, 0, ref IID_IUnknown, out object obj);
1582 [DllImport(Interop.Libraries.Ole32, PreserveSig = false)]
1583 private static extern void CreateBindCtx(uint reserved, out IBindCtx ppbc);
1585 [DllImport(Interop.Libraries.Ole32, PreserveSig = false)]
1586 private static extern void MkParseDisplayName(IBindCtx pbc, [MarshalAs(UnmanagedType.LPWStr)] string szUserName, out uint pchEaten, out IMoniker ppmk);
1588 [DllImport(Interop.Libraries.Ole32, PreserveSig = false)]
1589 private static extern void BindMoniker(IMoniker pmk, uint grfOpt, ref Guid iidResult, [MarshalAs(UnmanagedType.Interface)] out object ppvResult);
1592 /// Private method called from EE upon use of license/ICF2 marshaling.
1594 private static IntPtr LoadLicenseManager()
1596 Type t = Type.GetType("System.ComponentModel.LicenseManager, System", throwOnError: true);
1597 return t.TypeHandle.Value;
1600 [MethodImpl(MethodImplOptions.InternalCall)]
1601 public static extern void ChangeWrapperHandleStrength(object otp, bool fIsWeak);
1603 [MethodImpl(MethodImplOptions.InternalCall)]
1604 internal static extern void InitializeWrapperForWinRT(object o, ref IntPtr pUnk);
1606 #if FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION
1607 [MethodImpl(MethodImplOptions.InternalCall)]
1608 internal static extern void InitializeManagedWinRTFactoryObject(object o, RuntimeType runtimeClassType);
1612 /// Create activation factory and wraps it with a unique RCW.
1614 [MethodImpl(MethodImplOptions.InternalCall)]
1615 internal static extern object GetNativeActivationFactory(Type type);
1617 #endif // FEATURE_COMINTEROP
1619 public static Delegate GetDelegateForFunctionPointer(IntPtr ptr, Type t)
1621 if (ptr == IntPtr.Zero)
1623 throw new ArgumentNullException(nameof(ptr));
1627 throw new ArgumentNullException(nameof(t));
1629 if (!(t is RuntimeType))
1631 throw new ArgumentException(SR.Argument_MustBeRuntimeType, nameof(t));
1633 if (t.IsGenericType)
1635 throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(t));
1638 Type c = t.BaseType;
1639 if (c == null || (c != typeof(Delegate) && c != typeof(MulticastDelegate)))
1641 throw new ArgumentException(SR.Arg_MustBeDelegate, nameof(t));
1644 return GetDelegateForFunctionPointerInternal(ptr, t);
1647 public static TDelegate GetDelegateForFunctionPointer<TDelegate>(IntPtr ptr)
1649 return (TDelegate)(object)GetDelegateForFunctionPointer(ptr, typeof(TDelegate));
1652 [MethodImpl(MethodImplOptions.InternalCall)]
1653 internal static extern Delegate GetDelegateForFunctionPointerInternal(IntPtr ptr, Type t);
1655 public static IntPtr GetFunctionPointerForDelegate(Delegate d)
1659 throw new ArgumentNullException(nameof(d));
1662 return GetFunctionPointerForDelegateInternal(d);
1665 public static IntPtr GetFunctionPointerForDelegate<TDelegate>(TDelegate d)
1667 return GetFunctionPointerForDelegate((Delegate)(object)d);
1670 [MethodImpl(MethodImplOptions.InternalCall)]
1671 internal static extern IntPtr GetFunctionPointerForDelegateInternal(Delegate d);
1673 public static IntPtr SecureStringToBSTR(SecureString s)
1677 throw new ArgumentNullException(nameof(s));
1680 return s.MarshalToBSTR();
1683 public static IntPtr SecureStringToCoTaskMemAnsi(SecureString s)
1687 throw new ArgumentNullException(nameof(s));
1690 return s.MarshalToString(globalAlloc: false, unicode: false);
1693 public static IntPtr SecureStringToCoTaskMemUnicode(SecureString s)
1697 throw new ArgumentNullException(nameof(s));
1700 return s.MarshalToString(globalAlloc: false, unicode: true);
1703 public static void ZeroFreeBSTR(IntPtr s)
1705 RuntimeImports.RhZeroMemory(s, (UIntPtr)(Win32Native.SysStringLen(s) * 2));
1709 public static void ZeroFreeCoTaskMemAnsi(IntPtr s)
1711 RuntimeImports.RhZeroMemory(s, (UIntPtr)(Win32Native.lstrlenA(s)));
1715 public static void ZeroFreeCoTaskMemUnicode(IntPtr s)
1717 RuntimeImports.RhZeroMemory(s, (UIntPtr)(Win32Native.lstrlenW(s) * 2));
1721 public static unsafe void ZeroFreeCoTaskMemUTF8(IntPtr s)
1723 RuntimeImports.RhZeroMemory(s, (UIntPtr)System.StubHelpers.StubHelpers.strlen((sbyte*)s));
1727 public static IntPtr SecureStringToGlobalAllocAnsi(SecureString s)
1731 throw new ArgumentNullException(nameof(s));
1734 return s.MarshalToString(globalAlloc: true, unicode: false);
1737 public static IntPtr SecureStringToGlobalAllocUnicode(SecureString s)
1741 throw new ArgumentNullException(nameof(s));
1744 return s.MarshalToString(globalAlloc: true, unicode: true); ;
1747 public static void ZeroFreeGlobalAllocAnsi(IntPtr s)
1749 RuntimeImports.RhZeroMemory(s, (UIntPtr)(Win32Native.lstrlenA(s)));
1753 public static void ZeroFreeGlobalAllocUnicode(IntPtr s)
1755 RuntimeImports.RhZeroMemory(s, (UIntPtr)(Win32Native.lstrlenW(s) * 2));