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.
6 using System
.Reflection
;
7 using System
.Runtime
.CompilerServices
;
10 using Internal
.Runtime
.CompilerServices
;
11 using System
.Diagnostics
.CodeAnalysis
;
13 #pragma warning disable SA1121 // explicitly using type aliases instead of built-in types
15 using nuint
= System
.UInt64
;
17 using nuint
= System
.UInt32
;
20 namespace System
.Runtime
.InteropServices
23 /// This class contains methods that are mainly used to marshal between unmanaged
24 /// and managed types.
26 public static partial class Marshal
29 /// The default character size for the system. This is always 2 because
30 /// the framework only runs on UTF-16 systems.
32 public static readonly int SystemDefaultCharSize
= 2;
35 /// The max DBCS character size for the system.
37 public static readonly int SystemMaxDBCSCharSize
= GetSystemMaxDBCSCharSize();
39 public static IntPtr
AllocHGlobal(int cb
) => AllocHGlobal((IntPtr
)cb
);
41 public static unsafe string? PtrToStringAnsi(IntPtr ptr
)
43 if (ptr
== IntPtr
.Zero
|| IsWin32Atom(ptr
))
48 return new string((sbyte*)ptr
);
51 public static unsafe string PtrToStringAnsi(IntPtr ptr
, int len
)
53 if (ptr
== IntPtr
.Zero
)
55 throw new ArgumentNullException(nameof(ptr
));
59 throw new ArgumentOutOfRangeException(nameof(len
), len
, SR
.ArgumentOutOfRange_NeedNonNegNum
);
62 return new string((sbyte*)ptr
, 0, len
);
65 public static unsafe string? PtrToStringUni(IntPtr ptr
)
67 if (ptr
== IntPtr
.Zero
|| IsWin32Atom(ptr
))
72 return new string((char*)ptr
);
75 public static unsafe string PtrToStringUni(IntPtr ptr
, int len
)
77 if (ptr
== IntPtr
.Zero
)
79 throw new ArgumentNullException(nameof(ptr
));
83 throw new ArgumentOutOfRangeException(nameof(len
), len
, SR
.ArgumentOutOfRange_NeedNonNegNum
);
86 return new string((char*)ptr
, 0, len
);
89 public static unsafe string? PtrToStringUTF8(IntPtr ptr
)
91 if (ptr
== IntPtr
.Zero
|| IsWin32Atom(ptr
))
96 int nbBytes
= string.strlen((byte*)ptr
);
97 return string.CreateStringFromEncoding((byte*)ptr
, nbBytes
, Encoding
.UTF8
);
100 public static unsafe string PtrToStringUTF8(IntPtr ptr
, int byteLen
)
102 if (ptr
== IntPtr
.Zero
)
104 throw new ArgumentNullException(nameof(ptr
));
108 throw new ArgumentOutOfRangeException(nameof(byteLen
), byteLen
, SR
.ArgumentOutOfRange_NeedNonNegNum
);
111 return string.CreateStringFromEncoding((byte*)ptr
, byteLen
, Encoding
.UTF8
);
114 public static int SizeOf(object structure
)
116 if (structure
is null)
118 throw new ArgumentNullException(nameof(structure
));
121 return SizeOfHelper(structure
.GetType(), throwIfNotMarshalable
: true);
124 public static int SizeOf
<T
>(T structure
)
126 if (structure
is null)
128 throw new ArgumentNullException(nameof(structure
));
131 return SizeOfHelper(structure
.GetType(), throwIfNotMarshalable
: true);
134 public static int SizeOf(Type t
)
138 throw new ArgumentNullException(nameof(t
));
140 if (!t
.IsRuntimeImplemented())
142 throw new ArgumentException(SR
.Argument_MustBeRuntimeType
, nameof(t
));
146 throw new ArgumentException(SR
.Argument_NeedNonGenericType
, nameof(t
));
149 return SizeOfHelper(t
, throwIfNotMarshalable
: true);
152 public static int SizeOf
<T
>() => SizeOf(typeof(T
));
155 /// IMPORTANT NOTICE: This method does not do any verification on the array.
156 /// It must be used with EXTREME CAUTION since passing in invalid index or
157 /// an array that is not pinned can cause unexpected results.
159 public static unsafe IntPtr
UnsafeAddrOfPinnedArrayElement(Array arr
, int index
)
162 throw new ArgumentNullException(nameof(arr
));
164 void* pRawData
= Unsafe
.AsPointer(ref arr
.GetRawArrayData());
165 return (IntPtr
)((byte*)pRawData
+ (uint)index
* (nuint
)arr
.GetElementSize());
168 public static unsafe IntPtr UnsafeAddrOfPinnedArrayElement
<T
>(T
[] arr
, int index
)
171 throw new ArgumentNullException(nameof(arr
));
173 void* pRawData
= Unsafe
.AsPointer(ref arr
.GetRawSzArrayData());
174 return (IntPtr
)((byte*)pRawData
+ (uint)index
* (nuint
)Unsafe
.SizeOf
<T
>());
177 public static IntPtr OffsetOf
<T
>(string fieldName
) => OffsetOf(typeof(T
), fieldName
);
179 public static void Copy(int[] source
, int startIndex
, IntPtr destination
, int length
)
181 CopyToNative(source
, startIndex
, destination
, length
);
184 public static void Copy(char[] source
, int startIndex
, IntPtr destination
, int length
)
186 CopyToNative(source
, startIndex
, destination
, length
);
189 public static void Copy(short[] source
, int startIndex
, IntPtr destination
, int length
)
191 CopyToNative(source
, startIndex
, destination
, length
);
194 public static void Copy(long[] source
, int startIndex
, IntPtr destination
, int length
)
196 CopyToNative(source
, startIndex
, destination
, length
);
199 public static void Copy(float[] source
, int startIndex
, IntPtr destination
, int length
)
201 CopyToNative(source
, startIndex
, destination
, length
);
204 public static void Copy(double[] source
, int startIndex
, IntPtr destination
, int length
)
206 CopyToNative(source
, startIndex
, destination
, length
);
209 public static void Copy(byte[] source
, int startIndex
, IntPtr destination
, int length
)
211 CopyToNative(source
, startIndex
, destination
, length
);
214 public static void Copy(IntPtr
[] source
, int startIndex
, IntPtr destination
, int length
)
216 CopyToNative(source
, startIndex
, destination
, length
);
219 private static unsafe void CopyToNative
<T
>(T
[] source
, int startIndex
, IntPtr destination
, int length
)
222 throw new ArgumentNullException(nameof(source
));
223 if (destination
== IntPtr
.Zero
)
224 throw new ArgumentNullException(nameof(destination
));
226 // The rest of the argument validation is done by CopyTo
228 new Span
<T
>(source
, startIndex
, length
).CopyTo(new Span
<T
>((void*)destination
, length
));
231 public static void Copy(IntPtr source
, int[] destination
, int startIndex
, int length
)
233 CopyToManaged(source
, destination
, startIndex
, length
);
236 public static void Copy(IntPtr source
, char[] destination
, int startIndex
, int length
)
238 CopyToManaged(source
, destination
, startIndex
, length
);
241 public static void Copy(IntPtr source
, short[] destination
, int startIndex
, int length
)
243 CopyToManaged(source
, destination
, startIndex
, length
);
246 public static void Copy(IntPtr source
, long[] destination
, int startIndex
, int length
)
248 CopyToManaged(source
, destination
, startIndex
, length
);
251 public static void Copy(IntPtr source
, float[] destination
, int startIndex
, int length
)
253 CopyToManaged(source
, destination
, startIndex
, length
);
256 public static void Copy(IntPtr source
, double[] destination
, int startIndex
, int length
)
258 CopyToManaged(source
, destination
, startIndex
, length
);
261 public static void Copy(IntPtr source
, byte[] destination
, int startIndex
, int length
)
263 CopyToManaged(source
, destination
, startIndex
, length
);
266 public static void Copy(IntPtr source
, IntPtr
[] destination
, int startIndex
, int length
)
268 CopyToManaged(source
, destination
, startIndex
, length
);
271 private static unsafe void CopyToManaged
<T
>(IntPtr source
, T
[] destination
, int startIndex
, int length
)
273 if (source
== IntPtr
.Zero
)
274 throw new ArgumentNullException(nameof(source
));
275 if (destination
is null)
276 throw new ArgumentNullException(nameof(destination
));
278 throw new ArgumentOutOfRangeException(nameof(startIndex
), SR
.ArgumentOutOfRange_StartIndex
);
280 throw new ArgumentOutOfRangeException(nameof(length
), SR
.ArgumentOutOfRange_NeedNonNegNum
);
282 // The rest of the argument validation is done by CopyTo
284 new Span
<T
>((void*)source
, length
).CopyTo(new Span
<T
>(destination
, startIndex
, length
));
287 public static unsafe byte ReadByte(IntPtr ptr
, int ofs
)
291 byte* addr
= (byte*)ptr
+ ofs
;
294 catch (NullReferenceException
)
296 // this method is documented to throw AccessViolationException on any AV
297 throw new AccessViolationException();
301 public static byte ReadByte(IntPtr ptr
) => ReadByte(ptr
, 0);
303 public static unsafe short ReadInt16(IntPtr ptr
, int ofs
)
307 byte* addr
= (byte*)ptr
+ ofs
;
308 if ((unchecked((int)addr
) & 0x1) == 0)
311 return *((short*)addr
);
315 return Unsafe
.ReadUnaligned
<short>(addr
);
318 catch (NullReferenceException
)
320 // this method is documented to throw AccessViolationException on any AV
321 throw new AccessViolationException();
325 public static short ReadInt16(IntPtr ptr
) => ReadInt16(ptr
, 0);
327 public static unsafe int ReadInt32(IntPtr ptr
, int ofs
)
331 byte* addr
= (byte*)ptr
+ ofs
;
332 if ((unchecked((int)addr
) & 0x3) == 0)
335 return *((int*)addr
);
339 return Unsafe
.ReadUnaligned
<int>(addr
);
342 catch (NullReferenceException
)
344 // this method is documented to throw AccessViolationException on any AV
345 throw new AccessViolationException();
349 public static int ReadInt32(IntPtr ptr
) => ReadInt32(ptr
, 0);
351 public static IntPtr
ReadIntPtr(object ptr
, int ofs
)
354 return (IntPtr
)ReadInt64(ptr
, ofs
);
356 return (IntPtr
)ReadInt32(ptr
, ofs
);
360 public static IntPtr
ReadIntPtr(IntPtr ptr
, int ofs
)
363 return (IntPtr
)ReadInt64(ptr
, ofs
);
365 return (IntPtr
)ReadInt32(ptr
, ofs
);
369 public static IntPtr
ReadIntPtr(IntPtr ptr
) => ReadIntPtr(ptr
, 0);
371 public static unsafe long ReadInt64(IntPtr ptr
, int ofs
)
375 byte* addr
= (byte*)ptr
+ ofs
;
376 if ((unchecked((int)addr
) & 0x7) == 0)
379 return *((long*)addr
);
383 return Unsafe
.ReadUnaligned
<long>(addr
);
386 catch (NullReferenceException
)
388 // this method is documented to throw AccessViolationException on any AV
389 throw new AccessViolationException();
393 public static long ReadInt64(IntPtr ptr
) => ReadInt64(ptr
, 0);
395 public static unsafe void WriteByte(IntPtr ptr
, int ofs
, byte val
)
399 byte* addr
= (byte*)ptr
+ ofs
;
402 catch (NullReferenceException
)
404 // this method is documented to throw AccessViolationException on any AV
405 throw new AccessViolationException();
409 public static void WriteByte(IntPtr ptr
, byte val
) => WriteByte(ptr
, 0, val
);
411 public static unsafe void WriteInt16(IntPtr ptr
, int ofs
, short val
)
415 byte* addr
= (byte*)ptr
+ ofs
;
416 if ((unchecked((int)addr
) & 0x1) == 0)
419 *((short*)addr
) = val
;
423 Unsafe
.WriteUnaligned(addr
, val
);
426 catch (NullReferenceException
)
428 // this method is documented to throw AccessViolationException on any AV
429 throw new AccessViolationException();
433 public static void WriteInt16(IntPtr ptr
, short val
) => WriteInt16(ptr
, 0, val
);
435 public static void WriteInt16(IntPtr ptr
, int ofs
, char val
) => WriteInt16(ptr
, ofs
, (short)val
);
437 public static void WriteInt16([In
, Out
]object ptr
, int ofs
, char val
) => WriteInt16(ptr
, ofs
, (short)val
);
439 public static void WriteInt16(IntPtr ptr
, char val
) => WriteInt16(ptr
, 0, (short)val
);
441 public static unsafe void WriteInt32(IntPtr ptr
, int ofs
, int val
)
445 byte* addr
= (byte*)ptr
+ ofs
;
446 if ((unchecked((int)addr
) & 0x3) == 0)
453 Unsafe
.WriteUnaligned(addr
, val
);
456 catch (NullReferenceException
)
458 // this method is documented to throw AccessViolationException on any AV
459 throw new AccessViolationException();
463 public static void WriteInt32(IntPtr ptr
, int val
) => WriteInt32(ptr
, 0, val
);
465 public static void WriteIntPtr(IntPtr ptr
, int ofs
, IntPtr val
)
468 WriteInt64(ptr
, ofs
, (long)val
);
470 WriteInt32(ptr
, ofs
, (int)val
);
474 public static void WriteIntPtr(object ptr
, int ofs
, IntPtr val
)
477 WriteInt64(ptr
, ofs
, (long)val
);
479 WriteInt32(ptr
, ofs
, (int)val
);
483 public static void WriteIntPtr(IntPtr ptr
, IntPtr val
) => WriteIntPtr(ptr
, 0, val
);
485 public static unsafe void WriteInt64(IntPtr ptr
, int ofs
, long val
)
489 byte* addr
= (byte*)ptr
+ ofs
;
490 if ((unchecked((int)addr
) & 0x7) == 0)
493 *((long*)addr
) = val
;
497 Unsafe
.WriteUnaligned(addr
, val
);
500 catch (NullReferenceException
)
502 // this method is documented to throw AccessViolationException on any AV
503 throw new AccessViolationException();
507 public static void WriteInt64(IntPtr ptr
, long val
) => WriteInt64(ptr
, 0, val
);
509 public static void Prelink(MethodInfo m
)
513 throw new ArgumentNullException(nameof(m
));
519 public static void PrelinkAll(Type c
)
523 throw new ArgumentNullException(nameof(c
));
526 MethodInfo
[] mi
= c
.GetMethods();
528 for (int i
= 0; i
< mi
.Length
; i
++)
534 public static void StructureToPtr
<T
>([DisallowNull
] T structure
, IntPtr ptr
, bool fDeleteOld
)
536 StructureToPtr((object)structure
!, ptr
, fDeleteOld
);
540 /// Creates a new instance of "structuretype" and marshals data from a
541 /// native memory block to it.
543 public static object? PtrToStructure(IntPtr ptr
, Type structureType
)
545 if (ptr
== IntPtr
.Zero
)
550 if (structureType
is null)
552 throw new ArgumentNullException(nameof(structureType
));
554 if (structureType
.IsGenericType
)
556 throw new ArgumentException(SR
.Argument_NeedNonGenericType
, nameof(structureType
));
558 if (!structureType
.IsRuntimeImplemented())
560 throw new ArgumentException(SR
.Argument_MustBeRuntimeType
, nameof(structureType
));
563 return PtrToStructureHelper(ptr
, structureType
);
567 /// Marshals data from a native memory block to a preallocated structure class.
569 public static void PtrToStructure(IntPtr ptr
, object structure
)
571 PtrToStructureHelper(ptr
, structure
, allowValueClasses
: false);
574 public static void PtrToStructure
<T
>(IntPtr ptr
, [DisallowNull
] T structure
)
576 PtrToStructure(ptr
, (object)structure
!);
580 public static T PtrToStructure
<T
>(IntPtr ptr
) => (T
)PtrToStructure(ptr
, typeof(T
))!;
582 public static void DestroyStructure
<T
>(IntPtr ptr
) => DestroyStructure(ptr
, typeof(T
));
585 /// Converts the HRESULT to a CLR exception.
587 public static Exception
? GetExceptionForHR(int errorCode
) => GetExceptionForHR(errorCode
, IntPtr
.Zero
);
589 public static Exception
? GetExceptionForHR(int errorCode
, IntPtr errorInfo
)
596 return GetExceptionForHRInternal(errorCode
, errorInfo
);
600 /// Throws a CLR exception based on the HRESULT.
602 public static void ThrowExceptionForHR(int errorCode
)
606 throw GetExceptionForHR(errorCode
, IntPtr
.Zero
)!;
610 public static void ThrowExceptionForHR(int errorCode
, IntPtr errorInfo
)
614 throw GetExceptionForHR(errorCode
, errorInfo
)!;
618 public static IntPtr
SecureStringToBSTR(SecureString s
)
622 throw new ArgumentNullException(nameof(s
));
625 return s
.MarshalToBSTR();
628 public static IntPtr
SecureStringToCoTaskMemAnsi(SecureString s
)
632 throw new ArgumentNullException(nameof(s
));
635 return s
.MarshalToString(globalAlloc
: false, unicode
: false);
638 public static IntPtr
SecureStringToCoTaskMemUnicode(SecureString s
)
642 throw new ArgumentNullException(nameof(s
));
645 return s
.MarshalToString(globalAlloc
: false, unicode
: true);
648 public static IntPtr
SecureStringToGlobalAllocAnsi(SecureString s
)
652 throw new ArgumentNullException(nameof(s
));
655 return s
.MarshalToString(globalAlloc
: true, unicode
: false);
658 public static IntPtr
SecureStringToGlobalAllocUnicode(SecureString s
)
662 throw new ArgumentNullException(nameof(s
));
665 return s
.MarshalToString(globalAlloc
: true, unicode
: true); ;
668 public static unsafe IntPtr
StringToHGlobalAnsi(string? s
)
675 long lnb
= (s
.Length
+ 1) * (long)SystemMaxDBCSCharSize
;
681 throw new ArgumentOutOfRangeException(nameof(s
));
684 IntPtr hglobal
= AllocHGlobal((IntPtr
)nb
);
686 StringToAnsiString(s
, (byte*)hglobal
, nb
);
690 public static unsafe IntPtr
StringToHGlobalUni(string? s
)
697 int nb
= (s
.Length
+ 1) * 2;
702 throw new ArgumentOutOfRangeException(nameof(s
));
705 IntPtr hglobal
= AllocHGlobal((IntPtr
)nb
);
707 fixed (char* firstChar
= s
)
709 string.wstrcpy((char*)hglobal
, firstChar
, s
.Length
+ 1);
714 private static unsafe IntPtr
StringToHGlobalUTF8(string? s
)
721 int nb
= Encoding
.UTF8
.GetMaxByteCount(s
.Length
);
723 IntPtr pMem
= AllocHGlobal(nb
+ 1);
726 byte* pbMem
= (byte*)pMem
;
728 fixed (char* firstChar
= s
)
730 nbWritten
= Encoding
.UTF8
.GetBytes(firstChar
, s
.Length
, pbMem
, nb
);
733 pbMem
[nbWritten
] = 0;
738 public static unsafe IntPtr
StringToCoTaskMemUni(string? s
)
745 int nb
= (s
.Length
+ 1) * 2;
750 throw new ArgumentOutOfRangeException(nameof(s
));
753 IntPtr hglobal
= AllocCoTaskMem(nb
);
755 fixed (char* firstChar
= s
)
757 string.wstrcpy((char*)hglobal
, firstChar
, s
.Length
+ 1);
762 public static unsafe IntPtr
StringToCoTaskMemUTF8(string? s
)
769 int nb
= Encoding
.UTF8
.GetMaxByteCount(s
.Length
);
771 IntPtr pMem
= AllocCoTaskMem(nb
+ 1);
774 byte* pbMem
= (byte*)pMem
;
776 fixed (char* firstChar
= s
)
778 nbWritten
= Encoding
.UTF8
.GetBytes(firstChar
, s
.Length
, pbMem
, nb
);
781 pbMem
[nbWritten
] = 0;
786 public static unsafe IntPtr
StringToCoTaskMemAnsi(string? s
)
793 long lnb
= (s
.Length
+ 1) * (long)SystemMaxDBCSCharSize
;
799 throw new ArgumentOutOfRangeException(nameof(s
));
802 IntPtr hglobal
= AllocCoTaskMem(nb
);
804 StringToAnsiString(s
, (byte*)hglobal
, nb
);
809 /// Generates a GUID for the specified type. If the type has a GUID in the
810 /// metadata then it is returned otherwise a stable guid is generated based
811 /// on the fully qualified name of the type.
813 public static Guid
GenerateGuidForType(Type type
)
817 throw new ArgumentNullException(nameof(type
));
819 if (!type
.IsRuntimeImplemented())
821 throw new ArgumentException(SR
.Argument_MustBeRuntimeType
, nameof(type
));
828 /// This method generates a PROGID for the specified type. If the type has
829 /// a PROGID in the metadata then it is returned otherwise a stable PROGID
830 /// is generated based on the fully qualified name of the type.
832 public static string? GenerateProgIdForType(Type type
)
836 throw new ArgumentNullException(nameof(type
));
840 throw new ArgumentException(SR
.Argument_TypeMustNotBeComImport
, nameof(type
));
842 if (type
.IsGenericType
)
844 throw new ArgumentException(SR
.Argument_NeedNonGenericType
, nameof(type
));
847 ProgIdAttribute
? progIdAttribute
= type
.GetCustomAttribute
<ProgIdAttribute
>();
848 if (progIdAttribute
!= null)
850 return progIdAttribute
.Value
?? string.Empty
;
853 // If there is no prog ID attribute then use the full name of the type as the prog id.
854 return type
.FullName
;
857 public static Delegate
GetDelegateForFunctionPointer(IntPtr ptr
, Type t
)
859 if (ptr
== IntPtr
.Zero
)
861 throw new ArgumentNullException(nameof(ptr
));
865 throw new ArgumentNullException(nameof(t
));
867 if (!t
.IsRuntimeImplemented())
869 throw new ArgumentException(SR
.Argument_MustBeRuntimeType
, nameof(t
));
873 throw new ArgumentException(SR
.Argument_NeedNonGenericType
, nameof(t
));
876 Type
? c
= t
.BaseType
;
877 if (c
!= typeof(Delegate
) && c
!= typeof(MulticastDelegate
))
879 throw new ArgumentException(SR
.Arg_MustBeDelegate
, nameof(t
));
882 return GetDelegateForFunctionPointerInternal(ptr
, t
);
885 public static TDelegate GetDelegateForFunctionPointer
<TDelegate
>(IntPtr ptr
)
887 return (TDelegate
)(object)GetDelegateForFunctionPointer(ptr
, typeof(TDelegate
));
890 public static IntPtr
GetFunctionPointerForDelegate(Delegate d
)
894 throw new ArgumentNullException(nameof(d
));
897 return GetFunctionPointerForDelegateInternal(d
);
900 public static IntPtr GetFunctionPointerForDelegate
<TDelegate
>(TDelegate d
) where TDelegate
: notnull
902 return GetFunctionPointerForDelegate((Delegate
)(object)d
);
905 public static int GetHRForLastWin32Error()
907 int dwLastError
= GetLastWin32Error();
908 if ((dwLastError
& 0x80000000) == 0x80000000)
913 return (dwLastError
& 0x0000FFFF) | unchecked((int)0x80070000);
916 public static IntPtr
/* IDispatch */ GetIDispatchForObject(object o
) => throw new PlatformNotSupportedException();
918 public static void ZeroFreeBSTR(IntPtr s
)
920 if (s
== IntPtr
.Zero
)
924 RuntimeImports
.RhZeroMemory(s
, (UIntPtr
)SysStringByteLen(s
));
928 public static unsafe void ZeroFreeCoTaskMemAnsi(IntPtr s
)
930 ZeroFreeCoTaskMemUTF8(s
);
933 public static unsafe void ZeroFreeCoTaskMemUnicode(IntPtr s
)
935 if (s
== IntPtr
.Zero
)
939 RuntimeImports
.RhZeroMemory(s
, (UIntPtr
)(string.wcslen((char*)s
) * 2));
943 public static unsafe void ZeroFreeCoTaskMemUTF8(IntPtr s
)
945 if (s
== IntPtr
.Zero
)
949 RuntimeImports
.RhZeroMemory(s
, (UIntPtr
)string.strlen((byte*)s
));
953 public static unsafe void ZeroFreeGlobalAllocAnsi(IntPtr s
)
955 if (s
== IntPtr
.Zero
)
959 RuntimeImports
.RhZeroMemory(s
, (UIntPtr
)string.strlen((byte*)s
));
963 public static unsafe void ZeroFreeGlobalAllocUnicode(IntPtr s
)
965 if (s
== IntPtr
.Zero
)
969 RuntimeImports
.RhZeroMemory(s
, (UIntPtr
)(string.wcslen((char*)s
) * 2));
973 internal static unsafe uint SysStringByteLen(IntPtr s
)
975 return *(((uint*)s
) - 1);