// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Security;
using System.Text;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using Win32Native = Microsoft.Win32.Win32Native;
using System.Diagnostics;
using System.Runtime.InteropServices.ComTypes;
using System.StubHelpers;
namespace System.Runtime.InteropServices
{
///
/// This class contains methods that are mainly used to marshal between unmanaged
/// and managed types.
///
public static partial class Marshal
{
#if FEATURE_COMINTEROP
///
/// IUnknown is {00000000-0000-0000-C000-000000000046}
///
internal static Guid IID_IUnknown = new Guid(0, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);
#endif //FEATURE_COMINTEROP
private const int LMEM_FIXED = 0;
private const int LMEM_MOVEABLE = 2;
#if !FEATURE_PAL
private const long HiWordMask = unchecked((long)0xffffffffffff0000L);
#endif //!FEATURE_PAL
// Win32 has the concept of Atoms, where a pointer can either be a pointer
// or an int. If it's less than 64K, this is guaranteed to NOT be a
// pointer since the bottom 64K bytes are reserved in a process' page table.
// We should be careful about deallocating this stuff. Extracted to
// a function to avoid C# problems with lack of support for IntPtr.
// We have 2 of these methods for slightly different semantics for NULL.
private static bool IsWin32Atom(IntPtr ptr)
{
#if FEATURE_PAL
return false;
#else
long lPtr = (long)ptr;
return 0 == (lPtr & HiWordMask);
#endif
}
///
/// The default character size for the system. This is always 2 because
/// the framework only runs on UTF-16 systems.
///
public static readonly int SystemDefaultCharSize = 2;
///
/// The max DBCS character size for the system.
///
public static readonly int SystemMaxDBCSCharSize = GetSystemMaxDBCSCharSize();
///
/// Helper method to retrieve the system's maximum DBCS character size.
///
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern int GetSystemMaxDBCSCharSize();
public static unsafe string PtrToStringAnsi(IntPtr ptr)
{
if (IntPtr.Zero == ptr)
{
return null;
}
else if (IsWin32Atom(ptr))
{
return null;
}
int nb = string.strlen((byte*)ptr);
if (nb == 0)
{
return string.Empty;
}
return new string((sbyte*)ptr);
}
public static unsafe string PtrToStringAnsi(IntPtr ptr, int len)
{
if (ptr == IntPtr.Zero)
{
throw new ArgumentNullException(nameof(ptr));
}
if (len < 0)
{
throw new ArgumentException(null, nameof(len));
}
return new string((sbyte*)ptr, 0, len);
}
public static unsafe string PtrToStringUni(IntPtr ptr, int len)
{
if (ptr == IntPtr.Zero)
{
throw new ArgumentNullException(nameof(ptr));
}
if (len < 0)
{
throw new ArgumentException(SR.ArgumentOutOfRange_NeedNonNegNum, nameof(len));
}
return new string((char*)ptr, 0, len);
}
public static string PtrToStringAuto(IntPtr ptr, int len)
{
// Ansi platforms are no longer supported
return PtrToStringUni(ptr, len);
}
public static unsafe string PtrToStringUni(IntPtr ptr)
{
if (IntPtr.Zero == ptr)
{
return null;
}
else if (IsWin32Atom(ptr))
{
return null;
}
return new string((char*)ptr);
}
public static string PtrToStringAuto(IntPtr ptr)
{
// Ansi platforms are no longer supported
return PtrToStringUni(ptr);
}
public static unsafe string PtrToStringUTF8(IntPtr ptr)
{
if (IntPtr.Zero == ptr)
{
return null;
}
int nbBytes = string.strlen((byte*)ptr);
return PtrToStringUTF8(ptr, nbBytes);
}
public static unsafe string PtrToStringUTF8(IntPtr ptr, int byteLen)
{
if (byteLen < 0)
{
throw new ArgumentOutOfRangeException(nameof(byteLen), SR.ArgumentOutOfRange_NeedNonNegNum);
}
else if (IntPtr.Zero == ptr)
{
return null;
}
else if (IsWin32Atom(ptr))
{
return null;
}
else if (byteLen == 0)
{
return string.Empty;
}
return Encoding.UTF8.GetString((byte*)ptr, byteLen);
}
public static int SizeOf(object structure)
{
if (structure == null)
{
throw new ArgumentNullException(nameof(structure));
}
return SizeOfHelper(structure.GetType(), true);
}
public static int SizeOf(T structure) => SizeOf((object)structure);
public static int SizeOf(Type t)
{
if (t == null)
{
throw new ArgumentNullException(nameof(t));
}
if (!(t is RuntimeType))
{
throw new ArgumentException(SR.Argument_MustBeRuntimeType, nameof(t));
}
if (t.IsGenericType)
{
throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(t));
}
return SizeOfHelper(t, throwIfNotMarshalable: true);
}
public static int SizeOf() => SizeOf(typeof(T));
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern int SizeOfHelper(Type t, bool throwIfNotMarshalable);
public static IntPtr OffsetOf(Type t, string fieldName)
{
if (t == null)
{
throw new ArgumentNullException(nameof(t));
}
FieldInfo f = t.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (f == null)
{
throw new ArgumentException(SR.Format(SR.Argument_OffsetOfFieldNotFound, t.FullName), nameof(fieldName));
}
if (!(f is RtFieldInfo rtField))
{
throw new ArgumentException(SR.Argument_MustBeRuntimeFieldInfo, nameof(fieldName));
}
return OffsetOfHelper(rtField);
}
public static IntPtr OffsetOf(string fieldName) => OffsetOf(typeof(T), fieldName);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern IntPtr OffsetOfHelper(IRuntimeFieldInfo f);
///
/// IMPORTANT NOTICE: This method does not do any verification on the array.
/// It must be used with EXTREME CAUTION since passing in an array that is
/// not pinned or in the fixed heap can cause unexpected results.
///
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern IntPtr UnsafeAddrOfPinnedArrayElement(Array arr, int index);
public static IntPtr UnsafeAddrOfPinnedArrayElement(T[] arr, int index)
{
return UnsafeAddrOfPinnedArrayElement((Array)arr, index);
}
public static void Copy(int[] source, int startIndex, IntPtr destination, int length)
{
CopyToNative(source, startIndex, destination, length);
}
public static void Copy(char[] source, int startIndex, IntPtr destination, int length)
{
CopyToNative(source, startIndex, destination, length);
}
public static void Copy(short[] source, int startIndex, IntPtr destination, int length)
{
CopyToNative(source, startIndex, destination, length);
}
public static void Copy(long[] source, int startIndex, IntPtr destination, int length)
{
CopyToNative(source, startIndex, destination, length);
}
public static void Copy(float[] source, int startIndex, IntPtr destination, int length)
{
CopyToNative(source, startIndex, destination, length);
}
public static void Copy(double[] source, int startIndex, IntPtr destination, int length)
{
CopyToNative(source, startIndex, destination, length);
}
public static void Copy(byte[] source, int startIndex, IntPtr destination, int length)
{
CopyToNative(source, startIndex, destination, length);
}
public static void Copy(IntPtr[] source, int startIndex, IntPtr destination, int length)
{
CopyToNative(source, startIndex, destination, length);
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void CopyToNative(object source, int startIndex, IntPtr destination, int length);
public static void Copy(IntPtr source, int[] destination, int startIndex, int length)
{
CopyToManaged(source, destination, startIndex, length);
}
public static void Copy(IntPtr source, char[] destination, int startIndex, int length)
{
CopyToManaged(source, destination, startIndex, length);
}
public static void Copy(IntPtr source, short[] destination, int startIndex, int length)
{
CopyToManaged(source, destination, startIndex, length);
}
public static void Copy(IntPtr source, long[] destination, int startIndex, int length)
{
CopyToManaged(source, destination, startIndex, length);
}
public static void Copy(IntPtr source, float[] destination, int startIndex, int length)
{
CopyToManaged(source, destination, startIndex, length);
}
public static void Copy(IntPtr source, double[] destination, int startIndex, int length)
{
CopyToManaged(source, destination, startIndex, length);
}
public static void Copy(IntPtr source, byte[] destination, int startIndex, int length)
{
CopyToManaged(source, destination, startIndex, length);
}
public static void Copy(IntPtr source, IntPtr[] destination, int startIndex, int length)
{
CopyToManaged(source, destination, startIndex, length);
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void CopyToManaged(IntPtr source, object destination, int startIndex, int length);
public static byte ReadByte(object ptr, int ofs)
{
return ReadValueSlow(ptr, ofs, (IntPtr nativeHome, int offset) => ReadByte(nativeHome, offset));
}
public static unsafe byte ReadByte(IntPtr ptr, int ofs)
{
try
{
byte* addr = (byte*)ptr + ofs;
return *addr;
}
catch (NullReferenceException)
{
// this method is documented to throw AccessViolationException on any AV
throw new AccessViolationException();
}
}
public static byte ReadByte(IntPtr ptr) => ReadByte(ptr, 0);
public static short ReadInt16(object ptr, int ofs)
{
return ReadValueSlow(ptr, ofs, (IntPtr nativeHome, int offset) => ReadInt16(nativeHome, offset));
}
public static unsafe short ReadInt16(IntPtr ptr, int ofs)
{
try
{
byte* addr = (byte*)ptr + ofs;
if ((unchecked((int)addr) & 0x1) == 0)
{
// aligned read
return *((short*)addr);
}
else
{
// unaligned read
short val;
byte* valPtr = (byte*)&val;
valPtr[0] = addr[0];
valPtr[1] = addr[1];
return val;
}
}
catch (NullReferenceException)
{
// this method is documented to throw AccessViolationException on any AV
throw new AccessViolationException();
}
}
public static short ReadInt16(IntPtr ptr) => ReadInt16(ptr, 0);
public static int ReadInt32(object ptr, int ofs)
{
return ReadValueSlow(ptr, ofs, (IntPtr nativeHome, int offset) => ReadInt32(nativeHome, offset));
}
public static unsafe int ReadInt32(IntPtr ptr, int ofs)
{
try
{
byte* addr = (byte*)ptr + ofs;
if ((unchecked((int)addr) & 0x3) == 0)
{
// aligned read
return *((int*)addr);
}
else
{
// unaligned read
int val;
byte* valPtr = (byte*)&val;
valPtr[0] = addr[0];
valPtr[1] = addr[1];
valPtr[2] = addr[2];
valPtr[3] = addr[3];
return val;
}
}
catch (NullReferenceException)
{
// this method is documented to throw AccessViolationException on any AV
throw new AccessViolationException();
}
}
public static int ReadInt32(IntPtr ptr) => ReadInt32(ptr, 0);
public static IntPtr ReadIntPtr(object ptr, int ofs)
{
#if BIT64
return (IntPtr)ReadInt64(ptr, ofs);
#else // 32
return (IntPtr)ReadInt32(ptr, ofs);
#endif
}
public static IntPtr ReadIntPtr(IntPtr ptr, int ofs)
{
#if BIT64
return (IntPtr)ReadInt64(ptr, ofs);
#else // 32
return (IntPtr)ReadInt32(ptr, ofs);
#endif
}
public static IntPtr ReadIntPtr(IntPtr ptr) => ReadIntPtr(ptr, 0);
public static long ReadInt64([MarshalAs(UnmanagedType.AsAny), In] object ptr, int ofs)
{
return ReadValueSlow(ptr, ofs, (IntPtr nativeHome, int offset) => ReadInt64(nativeHome, offset));
}
public static unsafe long ReadInt64(IntPtr ptr, int ofs)
{
try
{
byte* addr = (byte*)ptr + ofs;
if ((unchecked((int)addr) & 0x7) == 0)
{
// aligned read
return *((long*)addr);
}
else
{
// unaligned read
long val;
byte* valPtr = (byte*)&val;
valPtr[0] = addr[0];
valPtr[1] = addr[1];
valPtr[2] = addr[2];
valPtr[3] = addr[3];
valPtr[4] = addr[4];
valPtr[5] = addr[5];
valPtr[6] = addr[6];
valPtr[7] = addr[7];
return val;
}
}
catch (NullReferenceException)
{
// this method is documented to throw AccessViolationException on any AV
throw new AccessViolationException();
}
}
public static long ReadInt64(IntPtr ptr) => ReadInt64(ptr, 0);
//====================================================================
// Read value from marshaled object (marshaled using AsAny)
// It's quite slow and can return back dangling pointers
// It's only there for backcompact
// People should instead use the IntPtr overloads
//====================================================================
private static unsafe T ReadValueSlow(object ptr, int ofs, Func readValueHelper)
{
// Consumers of this method are documented to throw AccessViolationException on any AV
if (ptr == null)
{
throw new AccessViolationException();
}
const int Flags =
(int)AsAnyMarshaler.AsAnyFlags.In |
(int)AsAnyMarshaler.AsAnyFlags.IsAnsi |
(int)AsAnyMarshaler.AsAnyFlags.IsBestFit;
MngdNativeArrayMarshaler.MarshalerState nativeArrayMarshalerState = new MngdNativeArrayMarshaler.MarshalerState();
AsAnyMarshaler marshaler = new AsAnyMarshaler(new IntPtr(&nativeArrayMarshalerState));
IntPtr pNativeHome = IntPtr.Zero;
try
{
pNativeHome = marshaler.ConvertToNative(ptr, Flags);
return readValueHelper(pNativeHome, ofs);
}
finally
{
marshaler.ClearNative(pNativeHome);
}
}
public static unsafe void WriteByte(IntPtr ptr, int ofs, byte val)
{
try
{
byte* addr = (byte*)ptr + ofs;
*addr = val;
}
catch (NullReferenceException)
{
// this method is documented to throw AccessViolationException on any AV
throw new AccessViolationException();
}
}
public static void WriteByte(object ptr, int ofs, byte val)
{
WriteValueSlow(ptr, ofs, val, (IntPtr nativeHome, int offset, byte value) => WriteByte(nativeHome, offset, value));
}
public static void WriteByte(IntPtr ptr, byte val) => WriteByte(ptr, 0, val);
public static unsafe void WriteInt16(IntPtr ptr, int ofs, short val)
{
try
{
byte* addr = (byte*)ptr + ofs;
if ((unchecked((int)addr) & 0x1) == 0)
{
// aligned write
*((short*)addr) = val;
}
else
{
// unaligned write
byte* valPtr = (byte*)&val;
addr[0] = valPtr[0];
addr[1] = valPtr[1];
}
}
catch (NullReferenceException)
{
// this method is documented to throw AccessViolationException on any AV
throw new AccessViolationException();
}
}
public static void WriteInt16(object ptr, int ofs, short val)
{
WriteValueSlow(ptr, ofs, val, (IntPtr nativeHome, int offset, short value) => Marshal.WriteInt16(nativeHome, offset, value));
}
public static void WriteInt16(IntPtr ptr, short val) => WriteInt16(ptr, 0, val);
public static void WriteInt16(IntPtr ptr, int ofs, char val) => WriteInt16(ptr, ofs, (short)val);
public static void WriteInt16([In, Out]object ptr, int ofs, char val) => WriteInt16(ptr, ofs, (short)val);
public static void WriteInt16(IntPtr ptr, char val) => WriteInt16(ptr, 0, (short)val);
public static unsafe void WriteInt32(IntPtr ptr, int ofs, int val)
{
try
{
byte* addr = (byte*)ptr + ofs;
if ((unchecked((int)addr) & 0x3) == 0)
{
// aligned write
*((int*)addr) = val;
}
else
{
// unaligned write
byte* valPtr = (byte*)&val;
addr[0] = valPtr[0];
addr[1] = valPtr[1];
addr[2] = valPtr[2];
addr[3] = valPtr[3];
}
}
catch (NullReferenceException)
{
// this method is documented to throw AccessViolationException on any AV
throw new AccessViolationException();
}
}
public static void WriteInt32(object ptr, int ofs, int val)
{
WriteValueSlow(ptr, ofs, val, (IntPtr nativeHome, int offset, int value) => Marshal.WriteInt32(nativeHome, offset, value));
}
public static void WriteInt32(IntPtr ptr, int val) => WriteInt32(ptr, 0, val);
public static void WriteIntPtr(IntPtr ptr, int ofs, IntPtr val)
{
#if BIT64
WriteInt64(ptr, ofs, (long)val);
#else // 32
WriteInt32(ptr, ofs, (int)val);
#endif
}
public static void WriteIntPtr(object ptr, int ofs, IntPtr val)
{
#if BIT64
WriteInt64(ptr, ofs, (long)val);
#else // 32
WriteInt32(ptr, ofs, (int)val);
#endif
}
public static void WriteIntPtr(IntPtr ptr, IntPtr val) => WriteIntPtr(ptr, 0, val);
public static unsafe void WriteInt64(IntPtr ptr, int ofs, long val)
{
try
{
byte* addr = (byte*)ptr + ofs;
if ((unchecked((int)addr) & 0x7) == 0)
{
// aligned write
*((long*)addr) = val;
}
else
{
// unaligned write
byte* valPtr = (byte*)&val;
addr[0] = valPtr[0];
addr[1] = valPtr[1];
addr[2] = valPtr[2];
addr[3] = valPtr[3];
addr[4] = valPtr[4];
addr[5] = valPtr[5];
addr[6] = valPtr[6];
addr[7] = valPtr[7];
}
}
catch (NullReferenceException)
{
// this method is documented to throw AccessViolationException on any AV
throw new AccessViolationException();
}
}
public static void WriteInt64(object ptr, int ofs, long val)
{
WriteValueSlow(ptr, ofs, val, (IntPtr nativeHome, int offset, long value) => Marshal.WriteInt64(nativeHome, offset, value));
}
public static void WriteInt64(IntPtr ptr, long val) => WriteInt64(ptr, 0, val);
///
/// Write value into marshaled object (marshaled using AsAny) and propagate the
/// value back. This is quite slow and can return back dangling pointers. It is
/// only here for backcompat. People should instead use the IntPtr overloads.
///
private static unsafe void WriteValueSlow(object ptr, int ofs, T val, Action writeValueHelper)
{
// Consumers of this method are documented to throw AccessViolationException on any AV
if (ptr == null)
{
throw new AccessViolationException();
}
const int Flags =
(int)AsAnyMarshaler.AsAnyFlags.In |
(int)AsAnyMarshaler.AsAnyFlags.Out |
(int)AsAnyMarshaler.AsAnyFlags.IsAnsi |
(int)AsAnyMarshaler.AsAnyFlags.IsBestFit;
MngdNativeArrayMarshaler.MarshalerState nativeArrayMarshalerState = new MngdNativeArrayMarshaler.MarshalerState();
AsAnyMarshaler marshaler = new AsAnyMarshaler(new IntPtr(&nativeArrayMarshalerState));
IntPtr pNativeHome = IntPtr.Zero;
try
{
pNativeHome = marshaler.ConvertToNative(ptr, Flags);
writeValueHelper(pNativeHome, ofs, val);
marshaler.ConvertToManaged(ptr, pNativeHome);
}
finally
{
marshaler.ClearNative(pNativeHome);
}
}
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern int GetLastWin32Error();
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern void SetLastWin32Error(int error);
public static int GetHRForLastWin32Error()
{
int dwLastError = GetLastWin32Error();
if ((dwLastError & 0x80000000) == 0x80000000)
{
return dwLastError;
}
return (dwLastError & 0x0000FFFF) | unchecked((int)0x80070000);
}
public static void Prelink(MethodInfo m)
{
if (m == null)
{
throw new ArgumentNullException(nameof(m));
}
if (!(m is RuntimeMethodInfo rmi))
{
throw new ArgumentException(SR.Argument_MustBeRuntimeMethodInfo, nameof(m));
}
InternalPrelink(rmi);
}
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
private static extern void InternalPrelink(IRuntimeMethodInfo m);
public static void PrelinkAll(Type c)
{
if (c == null)
{
throw new ArgumentNullException(nameof(c));
}
MethodInfo[] mi = c.GetMethods();
if (mi != null)
{
for (int i = 0; i < mi.Length; i++)
{
Prelink(mi[i]);
}
}
}
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern /* struct _EXCEPTION_POINTERS* */ IntPtr GetExceptionPointers();
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern int GetExceptionCode();
///
/// Marshals data from a structure class to a native memory block. If the
/// structure contains pointers to allocated blocks and "fDeleteOld" is
/// true, this routine will call DestroyStructure() first.
///
[MethodImpl(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public static extern void StructureToPtr(object structure, IntPtr ptr, bool fDeleteOld);
public static void StructureToPtr(T structure, IntPtr ptr, bool fDeleteOld)
{
StructureToPtr((object)structure, ptr, fDeleteOld);
}
///
/// Marshals data from a native memory block to a preallocated structure class.
///
public static void PtrToStructure(IntPtr ptr, object structure)
{
PtrToStructureHelper(ptr, structure, allowValueClasses: false);
}
public static void PtrToStructure(IntPtr ptr, T structure)
{
PtrToStructure(ptr, (object)structure);
}
///
/// Creates a new instance of "structuretype" and marshals data from a
/// native memory block to it.
///
public static object PtrToStructure(IntPtr ptr, Type structureType)
{
if (ptr == IntPtr.Zero)
{
return null;
}
if (structureType == null)
{
throw new ArgumentNullException(nameof(structureType));
}
if (structureType.IsGenericType)
{
throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(structureType));
}
if (!(structureType.UnderlyingSystemType is RuntimeType rt))
{
throw new ArgumentException(SR.Arg_MustBeType, nameof(structureType));
}
object structure = rt.CreateInstanceDefaultCtor(publicOnly: false, skipCheckThis: false, fillCache: false, wrapExceptions: true);
PtrToStructureHelper(ptr, structure, allowValueClasses: true);
return structure;
}
public static T PtrToStructure(IntPtr ptr) => (T)PtrToStructure(ptr, typeof(T));
///
/// Helper function to copy a pointer into a preallocated structure.
///
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void PtrToStructureHelper(IntPtr ptr, object structure, bool allowValueClasses);
///
/// Frees all substructures pointed to by the native memory block.
/// "structuretype" is used to provide layout information.
///
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern void DestroyStructure(IntPtr ptr, Type structuretype);
public static void DestroyStructure(IntPtr ptr) => DestroyStructure(ptr, typeof(T));
#if FEATURE_COMINTEROP
///
/// Returns the HInstance for this module. Returns -1 if the module doesn't have
/// an HInstance. In Memory (Dynamic) Modules won't have an HInstance.
///
public static IntPtr GetHINSTANCE(Module m)
{
if (m == null)
{
throw new ArgumentNullException(nameof(m));
}
if (m is RuntimeModule rtModule)
{
return GetHINSTANCE(rtModule.GetNativeHandle());
}
return (IntPtr)(-1);
}
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
private static extern IntPtr GetHINSTANCE(RuntimeModule m);
#endif // FEATURE_COMINTEROP
///
/// Throws a CLR exception based on the HRESULT.
///
public static void ThrowExceptionForHR(int errorCode)
{
if (errorCode < 0)
{
ThrowExceptionForHRInternal(errorCode, IntPtr.Zero);
}
}
public static void ThrowExceptionForHR(int errorCode, IntPtr errorInfo)
{
if (errorCode < 0)
{
ThrowExceptionForHRInternal(errorCode, errorInfo);
}
}
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern void ThrowExceptionForHRInternal(int errorCode, IntPtr errorInfo);
///
/// Converts the HRESULT to a CLR exception.
///
public static Exception GetExceptionForHR(int errorCode)
{
if (errorCode >= 0)
{
return null;
}
return GetExceptionForHRInternal(errorCode, IntPtr.Zero);
}
public static Exception GetExceptionForHR(int errorCode, IntPtr errorInfo)
{
if (errorCode >= 0)
{
return null;
}
return GetExceptionForHRInternal(errorCode, errorInfo);
}
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern Exception GetExceptionForHRInternal(int errorCode, IntPtr errorInfo);
public static IntPtr AllocHGlobal(IntPtr cb)
{
// For backwards compatibility on 32 bit platforms, ensure we pass values between
// int.MaxValue and uint.MaxValue to Windows. If the binary has had the
// LARGEADDRESSAWARE bit set in the PE header, it may get 3 or 4 GB of user mode
// address space. It is remotely that those allocations could have succeeded,
// though I couldn't reproduce that. In either case, that means we should continue
// throwing an OOM instead of an ArgumentOutOfRangeException for "negative" amounts of memory.
UIntPtr numBytes;
#if BIT64
numBytes = new UIntPtr(unchecked((ulong)cb.ToInt64()));
#else // 32
numBytes = new UIntPtr(unchecked((uint)cb.ToInt32()));
#endif
IntPtr pNewMem = Win32Native.LocalAlloc_NoSafeHandle(LMEM_FIXED, unchecked(numBytes));
if (pNewMem == IntPtr.Zero)
{
throw new OutOfMemoryException();
}
return pNewMem;
}
public static IntPtr AllocHGlobal(int cb) => AllocHGlobal((IntPtr)cb);
public static void FreeHGlobal(IntPtr hglobal)
{
if (!IsWin32Atom(hglobal))
{
if (IntPtr.Zero != Win32Native.LocalFree(hglobal))
{
ThrowExceptionForHR(GetHRForLastWin32Error());
}
}
}
public static IntPtr ReAllocHGlobal(IntPtr pv, IntPtr cb)
{
IntPtr pNewMem = Win32Native.LocalReAlloc(pv, cb, LMEM_MOVEABLE);
if (pNewMem == IntPtr.Zero)
{
throw new OutOfMemoryException();
}
return pNewMem;
}
public static unsafe IntPtr StringToHGlobalAnsi(string s)
{
if (s == null)
{
return IntPtr.Zero;
}
long lnb = (s.Length + 1) * (long)SystemMaxDBCSCharSize;
int nb = (int)lnb;
// Overflow checking
if (nb != lnb)
{
throw new ArgumentOutOfRangeException(nameof(s));
}
UIntPtr len = new UIntPtr((uint)nb);
IntPtr hglobal = Win32Native.LocalAlloc_NoSafeHandle(LMEM_FIXED, len);
if (hglobal == IntPtr.Zero)
{
throw new OutOfMemoryException();
}
s.ConvertToAnsi((byte*)hglobal, nb, false, false);
return hglobal;
}
public static unsafe IntPtr StringToHGlobalUni(string s)
{
if (s == null)
{
return IntPtr.Zero;
}
int nb = (s.Length + 1) * 2;
// Overflow checking
if (nb < s.Length)
{
throw new ArgumentOutOfRangeException(nameof(s));
}
UIntPtr len = new UIntPtr((uint)nb);
IntPtr hglobal = Win32Native.LocalAlloc_NoSafeHandle(LMEM_FIXED, len);
if (hglobal == IntPtr.Zero)
{
throw new OutOfMemoryException();
}
fixed (char* firstChar = s)
{
string.wstrcpy((char*)hglobal, firstChar, s.Length + 1);
}
return hglobal;
}
public static IntPtr StringToHGlobalAuto(string s)
{
// Ansi platforms are no longer supported
return StringToHGlobalUni(s);
}
#if FEATURE_COMINTEROP
///
/// Converts the CLR exception to an HRESULT. This function also sets
/// up an IErrorInfo for the exception.
///
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern int GetHRForException(Exception e);
///
/// Converts the CLR exception to an HRESULT. This function also sets
/// up an IErrorInfo for the exception.
/// This function is only used in WinRT and converts ObjectDisposedException
/// to RO_E_CLOSED
///
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern int GetHRForException_WinRT(Exception e);
///
/// Given a managed object that wraps an ITypeInfo, return its name.
///
public static string GetTypeInfoName(ITypeInfo typeInfo)
{
if (typeInfo == null)
{
throw new ArgumentNullException(nameof(typeInfo));
}
typeInfo.GetDocumentation(-1, out string strTypeLibName, out _, out _, out _);
return strTypeLibName;
}
// This method is identical to Type.GetTypeFromCLSID. Since it's interop specific, we expose it
// on Marshal for more consistent API surface.
public static Type GetTypeFromCLSID(Guid clsid) => RuntimeType.GetTypeFromCLSIDImpl(clsid, null, throwOnError: false);
///
/// Return the IUnknown* for an Object if the current context is the one
/// where the RCW was first seen. Will return null otherwise.
///
public static IntPtr /* IUnknown* */ GetIUnknownForObject(object o)
{
return GetIUnknownForObjectNative(o, false);
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern IntPtr /* IUnknown* */ GetIUnknownForObjectNative(object o, bool onlyInContext);
///
/// Return the raw IUnknown* for a COM Object not related to current.
/// Does not call AddRef.
///
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern IntPtr /* IUnknown* */ GetRawIUnknownForComObjectNoAddRef(object o);
#endif // FEATURE_COMINTEROP
public static IntPtr /* IDispatch */ GetIDispatchForObject(object o) => throw new PlatformNotSupportedException();
#if FEATURE_COMINTEROP
///
/// Return the IUnknown* representing the interface for the Object.
/// Object o should support Type T
///
public static IntPtr /* IUnknown* */ GetComInterfaceForObject(object o, Type T)
{
return GetComInterfaceForObjectNative(o, T, false, true);
}
public static IntPtr GetComInterfaceForObject(T o) => GetComInterfaceForObject(o, typeof(TInterface));
///
/// Return the IUnknown* representing the interface for the Object.
/// Object o should support Type T, it refer the value of mode to
/// invoke customized QueryInterface or not.
///
public static IntPtr /* IUnknown* */ GetComInterfaceForObject(object o, Type T, CustomQueryInterfaceMode mode)
{
bool bEnableCustomizedQueryInterface = ((mode == CustomQueryInterfaceMode.Allow) ? true : false);
return GetComInterfaceForObjectNative(o, T, false, bEnableCustomizedQueryInterface);
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern IntPtr /* IUnknown* */ GetComInterfaceForObjectNative(object o, Type t, bool onlyInContext, bool fEnalbeCustomizedQueryInterface);
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern object GetObjectForIUnknown(IntPtr /* IUnknown* */ pUnk);
///
/// Return a unique Object given an IUnknown. This ensures that you receive a fresh
/// object (we will not look in the cache to match up this IUnknown to an already
/// existing object). This is useful in cases where you want to be able to call
/// ReleaseComObject on a RCW and not worry about other active uses ofsaid RCW.
///
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern object GetUniqueObjectForIUnknown(IntPtr unknown);
///
/// Return an Object for IUnknown, using the Type T.
/// Type T should be either a COM imported Type or a sub-type of COM imported Type
///
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern object GetTypedObjectForIUnknown(IntPtr /* IUnknown* */ pUnk, Type t);
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern IntPtr CreateAggregatedObject(IntPtr pOuter, object o);
public static IntPtr CreateAggregatedObject(IntPtr pOuter, T o)
{
return CreateAggregatedObject(pOuter, (object)o);
}
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern void CleanupUnusedObjectsInCurrentContext();
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern bool AreComObjectsAvailableForCleanup();
///
/// Checks if the object is classic COM component.
///
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern bool IsComObject(object o);
#endif // FEATURE_COMINTEROP
public static IntPtr AllocCoTaskMem(int cb)
{
IntPtr pNewMem = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)cb));
if (pNewMem == IntPtr.Zero)
{
throw new OutOfMemoryException();
}
return pNewMem;
}
public static unsafe IntPtr StringToCoTaskMemUni(string s)
{
if (s == null)
{
return IntPtr.Zero;
}
int nb = (s.Length + 1) * 2;
// Overflow checking
if (nb < s.Length)
{
throw new ArgumentOutOfRangeException(nameof(s));
}
IntPtr hglobal = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)nb));
if (hglobal == IntPtr.Zero)
{
throw new OutOfMemoryException();
}
fixed (char* firstChar = s)
{
string.wstrcpy((char*)hglobal, firstChar, s.Length + 1);
}
return hglobal;
}
public static unsafe IntPtr StringToCoTaskMemUTF8(string s)
{
if (s == null)
{
return IntPtr.Zero;
}
int nb = Encoding.UTF8.GetMaxByteCount(s.Length);
IntPtr pMem = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)nb + 1));
if (pMem == IntPtr.Zero)
{
throw new OutOfMemoryException();
}
fixed (char* firstChar = s)
{
byte* pbMem = (byte*)pMem;
int nbWritten = Encoding.UTF8.GetBytes(firstChar, s.Length, pbMem, nb);
pbMem[nbWritten] = 0;
}
return pMem;
}
public static IntPtr StringToCoTaskMemAuto(string s)
{
// Ansi platforms are no longer supported
return StringToCoTaskMemUni(s);
}
public static unsafe IntPtr StringToCoTaskMemAnsi(string s)
{
if (s == null)
{
return IntPtr.Zero;
}
long lnb = (s.Length + 1) * (long)SystemMaxDBCSCharSize;
int nb = (int)lnb;
// Overflow checking
if (nb != lnb)
{
throw new ArgumentOutOfRangeException(nameof(s));
}
IntPtr hglobal = Win32Native.CoTaskMemAlloc(new UIntPtr((uint)nb));
if (hglobal == IntPtr.Zero)
{
throw new OutOfMemoryException();
}
s.ConvertToAnsi((byte*)hglobal, nb, false, false);
return hglobal;
}
public static void FreeCoTaskMem(IntPtr ptr)
{
if (!IsWin32Atom(ptr))
{
Win32Native.CoTaskMemFree(ptr);
}
}
public static IntPtr ReAllocCoTaskMem(IntPtr pv, int cb)
{
IntPtr pNewMem = Win32Native.CoTaskMemRealloc(pv, new UIntPtr((uint)cb));
if (pNewMem == IntPtr.Zero && cb != 0)
{
throw new OutOfMemoryException();
}
return pNewMem;
}
internal static IntPtr AllocBSTR(int length)
{
IntPtr bstr = Win32Native.SysAllocStringLen(null, length);
if (bstr == IntPtr.Zero)
{
throw new OutOfMemoryException();
}
return bstr;
}
public static void FreeBSTR(IntPtr ptr)
{
if (!IsWin32Atom(ptr))
{
Win32Native.SysFreeString(ptr);
}
}
public static IntPtr StringToBSTR(string s)
{
if (s == null)
{
return IntPtr.Zero;
}
// Overflow checking
if (s.Length + 1 < s.Length)
{
throw new ArgumentOutOfRangeException(nameof(s));
}
IntPtr bstr = Win32Native.SysAllocStringLen(s, s.Length);
if (bstr == IntPtr.Zero)
{
throw new OutOfMemoryException();
}
return bstr;
}
public static string PtrToStringBSTR(IntPtr ptr)
{
return PtrToStringUni(ptr, (int)Win32Native.SysStringLen(ptr));
}
#if FEATURE_COMINTEROP
///
/// Release the COM component and if the reference hits 0 zombie this object.
/// Further usage of this Object might throw an exception
///
public static int ReleaseComObject(object o)
{
if (o == null)
{
// Match .NET Framework behaviour.
throw new NullReferenceException();
}
if (!(o is __ComObject co))
{
throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(o));
}
return co.ReleaseSelf();
}
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern int InternalReleaseComObject(object o);
///
/// Release the COM component and zombie this object.
/// Further usage of this Object might throw an exception
///
public static int FinalReleaseComObject(object o)
{
if (o == null)
{
throw new ArgumentNullException(nameof(o));
}
if (!(o is __ComObject co))
{
throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(o));
}
co.FinalReleaseSelf();
return 0;
}
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern void InternalFinalReleaseComObject(object o);
public static object GetComObjectData(object obj, object key)
{
if (obj == null)
{
throw new ArgumentNullException(nameof(obj));
}
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
if (!(obj is __ComObject co))
{
throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(obj));
}
if (obj.GetType().IsWindowsRuntimeObject)
{
throw new ArgumentException(SR.Argument_ObjIsWinRTObject, nameof(obj));
}
// Retrieve the data from the __ComObject.
return co.GetData(key);
}
///
/// Sets data on the COM object. The data can only be set once for a given key
/// and cannot be removed. This function returns true if the data has been added,
/// false if the data could not be added because there already was data for the
/// specified key.
///
public static bool SetComObjectData(object obj, object key, object data)
{
if (obj == null)
{
throw new ArgumentNullException(nameof(obj));
}
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
if (!(obj is __ComObject co))
{
throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(obj));
}
if (obj.GetType().IsWindowsRuntimeObject)
{
throw new ArgumentException(SR.Argument_ObjIsWinRTObject, nameof(obj));
}
// Retrieve the data from the __ComObject.
return co.SetData(key, data);
}
///
/// This method takes the given COM object and wraps it in an object
/// of the specified type. The type must be derived from __ComObject.
///
public static object CreateWrapperOfType(object o, Type t)
{
if (t == null)
{
throw new ArgumentNullException(nameof(t));
}
if (!t.IsCOMObject)
{
throw new ArgumentException(SR.Argument_TypeNotComObject, nameof(t));
}
if (t.IsGenericType)
{
throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(t));
}
if (t.IsWindowsRuntimeObject)
{
throw new ArgumentException(SR.Argument_TypeIsWinRTType, nameof(t));
}
if (o == null)
{
return null;
}
if (!o.GetType().IsCOMObject)
{
throw new ArgumentException(SR.Argument_ObjNotComObject, nameof(o));
}
if (o.GetType().IsWindowsRuntimeObject)
{
throw new ArgumentException(SR.Argument_ObjIsWinRTObject, nameof(o));
}
// Check to see if we have nothing to do.
if (o.GetType() == t)
{
return o;
}
// Check to see if we already have a cached wrapper for this type.
object Wrapper = GetComObjectData(o, t);
if (Wrapper == null)
{
// Create the wrapper for the specified type.
Wrapper = InternalCreateWrapperOfType(o, t);
// Attempt to cache the wrapper on the object.
if (!SetComObjectData(o, t, Wrapper))
{
// Another thead already cached the wrapper so use that one instead.
Wrapper = GetComObjectData(o, t);
}
}
return Wrapper;
}
public static TWrapper CreateWrapperOfType(T o)
{
return (TWrapper)CreateWrapperOfType(o, typeof(TWrapper));
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern object InternalCreateWrapperOfType(object o, Type t);
///
/// check if the type is visible from COM.
///
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public static extern bool IsTypeVisibleFromCom(Type t);
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern int /* HRESULT */ QueryInterface(IntPtr /* IUnknown */ pUnk, ref Guid iid, out IntPtr ppv);
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern int /* ULONG */ AddRef(IntPtr /* IUnknown */ pUnk);
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern int /* ULONG */ Release(IntPtr /* IUnknown */ pUnk);
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern void GetNativeVariantForObject(object obj, /* VARIANT * */ IntPtr pDstNativeVariant);
public static void GetNativeVariantForObject(T obj, IntPtr pDstNativeVariant)
{
GetNativeVariantForObject((object)obj, pDstNativeVariant);
}
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern object GetObjectForNativeVariant(/* VARIANT * */ IntPtr pSrcNativeVariant);
public static T GetObjectForNativeVariant(IntPtr pSrcNativeVariant)
{
return (T)GetObjectForNativeVariant(pSrcNativeVariant);
}
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern object[] GetObjectsForNativeVariants(/* VARIANT * */ IntPtr aSrcNativeVariant, int cVars);
public static T[] GetObjectsForNativeVariants(IntPtr aSrcNativeVariant, int cVars)
{
object[] objects = GetObjectsForNativeVariants(aSrcNativeVariant, cVars);
T[] result = null;
if (objects != null)
{
result = new T[objects.Length];
Array.Copy(objects, 0, result, 0, objects.Length);
}
return result;
}
///
/// Returns the first valid COM slot that GetMethodInfoForSlot will work on
/// This will be 3 for IUnknown based interfaces and 7 for IDispatch based interfaces.
///
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern int GetStartComSlot(Type t);
///
/// Returns the last valid COM slot that GetMethodInfoForSlot will work on.
///
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern int GetEndComSlot(Type t);
#endif // FEATURE_COMINTEROP
///
/// Generates a GUID for the specified type. If the type has a GUID in the
/// metadata then it is returned otherwise a stable guid is generated based
/// on the fully qualified name of the type.
///
public static Guid GenerateGuidForType(Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
if (!(type is RuntimeType))
{
throw new ArgumentException(SR.Argument_MustBeRuntimeType, nameof(type));
}
return type.GUID;
}
///
/// This method generates a PROGID for the specified type. If the type has
/// a PROGID in the metadata then it is returned otherwise a stable PROGID
/// is generated based on the fully qualified name of the type.
///
public static string GenerateProgIdForType(Type type)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
if (type.IsImport)
{
throw new ArgumentException(SR.Argument_TypeMustNotBeComImport, nameof(type));
}
if (type.IsGenericType)
{
throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(type));
}
IList cas = CustomAttributeData.GetCustomAttributes(type);
for (int i = 0; i < cas.Count; i++)
{
if (cas[i].Constructor.DeclaringType == typeof(ProgIdAttribute))
{
// Retrieve the PROGID string from the ProgIdAttribute.
IList caConstructorArgs = cas[i].ConstructorArguments;
Debug.Assert(caConstructorArgs.Count == 1, "caConstructorArgs.Count == 1");
CustomAttributeTypedArgument progIdConstructorArg = caConstructorArgs[0];
Debug.Assert(progIdConstructorArg.ArgumentType == typeof(string), "progIdConstructorArg.ArgumentType == typeof(String)");
string strProgId = (string)progIdConstructorArg.Value;
if (strProgId == null)
strProgId = string.Empty;
return strProgId;
}
}
// If there is no prog ID attribute then use the full name of the type as the prog id.
return type.FullName;
}
#if FEATURE_COMINTEROP
public static object BindToMoniker(string monikerName)
{
CreateBindCtx(0, out IBindCtx bindctx);
MkParseDisplayName(bindctx, monikerName, out _, out IMoniker pmoniker);
BindMoniker(pmoniker, 0, ref IID_IUnknown, out object obj);
return obj;
}
[DllImport(Interop.Libraries.Ole32, PreserveSig = false)]
private static extern void CreateBindCtx(uint reserved, out IBindCtx ppbc);
[DllImport(Interop.Libraries.Ole32, PreserveSig = false)]
private static extern void MkParseDisplayName(IBindCtx pbc, [MarshalAs(UnmanagedType.LPWStr)] string szUserName, out uint pchEaten, out IMoniker ppmk);
[DllImport(Interop.Libraries.Ole32, PreserveSig = false)]
private static extern void BindMoniker(IMoniker pmk, uint grfOpt, ref Guid iidResult, [MarshalAs(UnmanagedType.Interface)] out object ppvResult);
///
/// Private method called from EE upon use of license/ICF2 marshaling.
///
private static IntPtr LoadLicenseManager()
{
Type t = Type.GetType("System.ComponentModel.LicenseManager, System", throwOnError: true);
return t.TypeHandle.Value;
}
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern void ChangeWrapperHandleStrength(object otp, bool fIsWeak);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern void InitializeWrapperForWinRT(object o, ref IntPtr pUnk);
#if FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern void InitializeManagedWinRTFactoryObject(object o, RuntimeType runtimeClassType);
#endif
///
/// Create activation factory and wraps it with a unique RCW.
///
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern object GetNativeActivationFactory(Type type);
#endif // FEATURE_COMINTEROP
public static Delegate GetDelegateForFunctionPointer(IntPtr ptr, Type t)
{
if (ptr == IntPtr.Zero)
{
throw new ArgumentNullException(nameof(ptr));
}
if (t == null)
{
throw new ArgumentNullException(nameof(t));
}
if (!(t is RuntimeType))
{
throw new ArgumentException(SR.Argument_MustBeRuntimeType, nameof(t));
}
if (t.IsGenericType)
{
throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(t));
}
Type c = t.BaseType;
if (c == null || (c != typeof(Delegate) && c != typeof(MulticastDelegate)))
{
throw new ArgumentException(SR.Arg_MustBeDelegate, nameof(t));
}
return GetDelegateForFunctionPointerInternal(ptr, t);
}
public static TDelegate GetDelegateForFunctionPointer(IntPtr ptr)
{
return (TDelegate)(object)GetDelegateForFunctionPointer(ptr, typeof(TDelegate));
}
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern Delegate GetDelegateForFunctionPointerInternal(IntPtr ptr, Type t);
public static IntPtr GetFunctionPointerForDelegate(Delegate d)
{
if (d == null)
{
throw new ArgumentNullException(nameof(d));
}
return GetFunctionPointerForDelegateInternal(d);
}
public static IntPtr GetFunctionPointerForDelegate(TDelegate d)
{
return GetFunctionPointerForDelegate((Delegate)(object)d);
}
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern IntPtr GetFunctionPointerForDelegateInternal(Delegate d);
public static IntPtr SecureStringToBSTR(SecureString s)
{
if (s == null)
{
throw new ArgumentNullException(nameof(s));
}
return s.MarshalToBSTR();
}
public static IntPtr SecureStringToCoTaskMemAnsi(SecureString s)
{
if (s == null)
{
throw new ArgumentNullException(nameof(s));
}
return s.MarshalToString(globalAlloc: false, unicode: false);
}
public static IntPtr SecureStringToCoTaskMemUnicode(SecureString s)
{
if (s == null)
{
throw new ArgumentNullException(nameof(s));
}
return s.MarshalToString(globalAlloc: false, unicode: true);
}
public static void ZeroFreeBSTR(IntPtr s)
{
if (s == IntPtr.Zero)
{
return;
}
RuntimeImports.RhZeroMemory(s, (UIntPtr)(Win32Native.SysStringLen(s) * 2));
FreeBSTR(s);
}
public unsafe static void ZeroFreeCoTaskMemAnsi(IntPtr s)
{
if (s == IntPtr.Zero)
{
return;
}
RuntimeImports.RhZeroMemory(s, (UIntPtr)string.strlen((byte*)s));
FreeCoTaskMem(s);
}
public static unsafe void ZeroFreeCoTaskMemUnicode(IntPtr s)
{
if (s == IntPtr.Zero)
{
return;
}
RuntimeImports.RhZeroMemory(s, (UIntPtr)(string.wcslen((char*)s) * 2));
FreeCoTaskMem(s);
}
public static unsafe void ZeroFreeCoTaskMemUTF8(IntPtr s)
{
if (s == IntPtr.Zero)
{
return;
}
RuntimeImports.RhZeroMemory(s, (UIntPtr)string.strlen((byte*)s));
FreeCoTaskMem(s);
}
public static IntPtr SecureStringToGlobalAllocAnsi(SecureString s)
{
if (s == null)
{
throw new ArgumentNullException(nameof(s));
}
return s.MarshalToString(globalAlloc: true, unicode: false);
}
public static IntPtr SecureStringToGlobalAllocUnicode(SecureString s)
{
if (s == null)
{
throw new ArgumentNullException(nameof(s));
}
return s.MarshalToString(globalAlloc: true, unicode: true); ;
}
public unsafe static void ZeroFreeGlobalAllocAnsi(IntPtr s)
{
if (s == IntPtr.Zero)
{
return;
}
RuntimeImports.RhZeroMemory(s, (UIntPtr)string.strlen((byte*)s));
FreeHGlobal(s);
}
public static unsafe void ZeroFreeGlobalAllocUnicode(IntPtr s)
{
if (s == IntPtr.Zero)
{
return;
}
RuntimeImports.RhZeroMemory(s, (UIntPtr)(string.wcslen((char*)s) * 2));
FreeHGlobal(s);
}
}
}