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 namespace System.StubHelpers
10 using System.Security;
11 using System.Collections.Generic;
13 using System.Runtime.InteropServices;
14 #if FEATURE_COMINTEROP
15 using System.Runtime.InteropServices.WindowsRuntime;
16 #endif // FEATURE_COMINTEROP
17 using System.Runtime.CompilerServices;
18 using System.Runtime.ConstrainedExecution;
19 using System.Diagnostics;
21 internal static class AnsiCharMarshaler
23 // The length of the returned array is an approximation based on the length of the input string and the system
24 // character set. It is only guaranteed to be larger or equal to cbLength, don't depend on the exact value.
25 unsafe static internal byte[] DoAnsiConversion(string str, bool fBestFit, bool fThrowOnUnmappableChar, out int cbLength)
27 byte[] buffer = new byte[(str.Length + 1) * Marshal.SystemMaxDBCSCharSize];
28 Debug.Assert(buffer.Length != 0);
29 fixed (byte* bufferPtr = &buffer[0])
31 cbLength = str.ConvertToAnsi(bufferPtr, buffer.Length, fBestFit, fThrowOnUnmappableChar);
36 unsafe static internal byte ConvertToNative(char managedChar, bool fBestFit, bool fThrowOnUnmappableChar)
38 int cbAllocLength = (1 + 1) * Marshal.SystemMaxDBCSCharSize;
39 byte* bufferPtr = stackalloc byte[cbAllocLength];
41 int cbLength = managedChar.ToString().ConvertToAnsi(bufferPtr, cbAllocLength, fBestFit, fThrowOnUnmappableChar);
43 Debug.Assert(cbLength > 0, "Zero bytes returned from DoAnsiConversion in AnsiCharMarshaler.ConvertToNative");
47 static internal char ConvertToManaged(byte nativeChar)
49 byte[] bytes = new byte[1] { nativeChar };
50 string str = Encoding.Default.GetString(bytes);
53 } // class AnsiCharMarshaler
55 internal static class CSTRMarshaler
57 static internal unsafe IntPtr ConvertToNative(int flags, string strManaged, IntPtr pNativeBuffer)
59 if (null == strManaged)
64 StubHelpers.CheckStringLength(strManaged.Length);
67 byte* pbNativeBuffer = (byte*)pNativeBuffer;
69 if (pbNativeBuffer != null || Marshal.SystemMaxDBCSCharSize == 1)
71 // If we are marshaling into a stack buffer or we can accurately estimate the size of the required heap
72 // space, we will use a "1-pass" mode where we convert the string directly into the unmanaged buffer.
74 // + 1 for the null character from the user
75 nb = (strManaged.Length + 1) * Marshal.SystemMaxDBCSCharSize;
77 // Use the pre-allocated buffer (allocated by localloc IL instruction) if not NULL,
78 // otherwise fallback to AllocCoTaskMem
79 if (pbNativeBuffer == null)
81 // + 1 for the null character we put in
82 pbNativeBuffer = (byte*)Marshal.AllocCoTaskMem(nb + 1);
85 nb = strManaged.ConvertToAnsi(pbNativeBuffer, nb + 1, 0 != (flags & 0xFF), 0 != (flags >> 8));
89 // Otherwise we use a slower "2-pass" mode where we first marshal the string into an intermediate buffer
90 // (managed byte array) and then allocate exactly the right amount of unmanaged memory. This is to avoid
91 // wasting memory on systems with multibyte character sets where the buffer we end up with is often much
92 // smaller than the upper bound for the given managed string.
94 byte[] bytes = AnsiCharMarshaler.DoAnsiConversion(strManaged, 0 != (flags & 0xFF), 0 != (flags >> 8), out nb);
96 // + 1 for the null character from the user. + 1 for the null character we put in.
97 pbNativeBuffer = (byte*)Marshal.AllocCoTaskMem(nb + 2);
99 Buffer.Memcpy(pbNativeBuffer, 0, bytes, 0, nb);
102 pbNativeBuffer[nb] = 0x00;
103 pbNativeBuffer[nb + 1] = 0x00;
105 return (IntPtr)pbNativeBuffer;
108 static internal unsafe string ConvertToManaged(IntPtr cstr)
110 if (IntPtr.Zero == cstr)
113 return new String((sbyte*)cstr);
116 static internal void ClearNative(IntPtr pNative)
118 Win32Native.CoTaskMemFree(pNative);
120 } // class CSTRMarshaler
122 internal static class UTF8Marshaler
124 private const int MAX_UTF8_CHAR_SIZE = 3;
125 static internal unsafe IntPtr ConvertToNative(int flags, string strManaged, IntPtr pNativeBuffer)
127 if (null == strManaged)
131 StubHelpers.CheckStringLength(strManaged.Length);
134 byte* pbNativeBuffer = (byte*)pNativeBuffer;
136 // If we are marshaling into a stack buffer allocated by the ILStub
137 // we will use a "1-pass" mode where we convert the string directly into the unmanaged buffer.
138 // else we will allocate the precise native heap memory.
139 if (pbNativeBuffer != null)
141 // this is the number of bytes allocated by the ILStub.
142 nb = (strManaged.Length + 1) * MAX_UTF8_CHAR_SIZE;
144 // nb is the actual number of bytes written by Encoding.GetBytes.
145 // use nb to de-limit the string since we are allocating more than
147 nb = strManaged.GetBytesFromEncoding(pbNativeBuffer, nb, Encoding.UTF8);
149 // required bytes > 260 , allocate required bytes on heap
152 nb = Encoding.UTF8.GetByteCount(strManaged);
153 // + 1 for the null character.
154 pbNativeBuffer = (byte*)Marshal.AllocCoTaskMem(nb + 1);
155 strManaged.GetBytesFromEncoding(pbNativeBuffer, nb, Encoding.UTF8);
157 pbNativeBuffer[nb] = 0x0;
158 return (IntPtr)pbNativeBuffer;
161 static internal unsafe string ConvertToManaged(IntPtr cstr)
163 if (IntPtr.Zero == cstr)
165 int nbBytes = StubHelpers.strlen((sbyte*)cstr);
166 return String.CreateStringFromEncoding((byte*)cstr, nbBytes, Encoding.UTF8);
169 static internal void ClearNative(IntPtr pNative)
171 if (pNative != IntPtr.Zero)
173 Win32Native.CoTaskMemFree(pNative);
178 internal static class UTF8BufferMarshaler
180 static internal unsafe IntPtr ConvertToNative(StringBuilder sb, IntPtr pNativeBuffer, int flags)
187 // Convert to string first
188 string strManaged = sb.ToString();
191 int nb = Encoding.UTF8.GetByteCount(strManaged);
193 // EmitConvertSpaceCLRToNative allocates memory
194 byte* pbNativeBuffer = (byte*)pNativeBuffer;
195 nb = strManaged.GetBytesFromEncoding(pbNativeBuffer, nb, Encoding.UTF8);
197 pbNativeBuffer[nb] = 0x0;
198 return (IntPtr)pbNativeBuffer;
201 static internal unsafe void ConvertToManaged(StringBuilder sb, IntPtr pNative)
206 int nbBytes = StubHelpers.strlen((sbyte*)pNative);
207 int numChar = Encoding.UTF8.GetCharCount((byte*)pNative, nbBytes);
209 // +1 GetCharCount return 0 if the pNative points to a
210 // an empty buffer.We still need to allocate an empty
211 // buffer with a '\0' to distingiush it from null.
212 // Note that pinning on (char *pinned = new char[0])
213 // return null and Encoding.UTF8.GetChars do not like
215 char[] cCharBuffer = new char[numChar + 1];
216 cCharBuffer[numChar] = '\0';
217 fixed (char* pBuffer = &cCharBuffer[0])
219 numChar = Encoding.UTF8.GetChars((byte*)pNative, nbBytes, pBuffer, numChar);
220 // replace string builder internal buffer
221 sb.ReplaceBufferInternal(pBuffer, numChar);
226 #if FEATURE_COMINTEROP
228 internal static class BSTRMarshaler
230 static internal unsafe IntPtr ConvertToNative(string strManaged, IntPtr pNativeBuffer)
232 if (null == strManaged)
238 StubHelpers.CheckStringLength(strManaged.Length);
241 bool hasTrailByte = strManaged.TryGetTrailByte(out trailByte);
243 uint lengthInBytes = (uint)strManaged.Length * 2;
247 // this is an odd-sized string with a trailing byte stored in its sync block
251 byte* ptrToFirstChar;
253 if (pNativeBuffer != IntPtr.Zero)
255 // If caller provided a buffer, construct the BSTR manually. The size
256 // of the buffer must be at least (lengthInBytes + 6) bytes.
258 uint length = *((uint*)pNativeBuffer.ToPointer());
259 Debug.Assert(length >= lengthInBytes + 6, "BSTR localloc'ed buffer is too small");
263 *((uint*)pNativeBuffer.ToPointer()) = lengthInBytes;
265 ptrToFirstChar = (byte*)pNativeBuffer.ToPointer() + 4;
269 // If not provided, allocate the buffer using SysAllocStringByteLen so
270 // that odd-sized strings will be handled as well.
271 ptrToFirstChar = (byte*)Win32Native.SysAllocStringByteLen(null, lengthInBytes).ToPointer();
273 if (ptrToFirstChar == null)
275 throw new OutOfMemoryException();
279 // copy characters from the managed string
280 fixed (char* ch = strManaged)
285 (strManaged.Length + 1) * 2);
288 // copy the trail byte if present
291 ptrToFirstChar[lengthInBytes - 1] = trailByte;
294 // return ptr to first character
295 return (IntPtr)ptrToFirstChar;
299 static internal unsafe string ConvertToManaged(IntPtr bstr)
301 if (IntPtr.Zero == bstr)
307 uint length = Win32Native.SysStringByteLen(bstr);
309 // Intentionally checking the number of bytes not characters to match the behavior
310 // of ML marshalers. This prevents roundtripping of very large strings as the check
311 // in the managed->native direction is done on String length but considering that
312 // it's completely moot on 32-bit and not expected to be important on 64-bit either,
313 // the ability to catch random garbage in the BSTR's length field outweighs this
314 // restriction. If an ordinary null-terminated string is passed instead of a BSTR,
315 // chances are that the length field - possibly being unallocated memory - contains
316 // a heap fill pattern that will have the highest bit set, caught by the check.
317 StubHelpers.CheckStringLength(length);
322 // In the empty string case, we need to use FastAllocateString rather than the
323 // String .ctor, since newing up a 0 sized string will always return String.Emtpy.
324 // When we marshal that out as a bstr, it can wind up getting modified which
325 // corrupts String.Empty.
326 ret = String.FastAllocateString(0);
330 ret = new String((char*)bstr, 0, (int)(length / 2));
333 if ((length & 1) == 1)
335 // odd-sized strings need to have the trailing byte saved in their sync block
336 ret.SetTrailByte(((byte*)bstr.ToPointer())[length - 1]);
343 static internal void ClearNative(IntPtr pNative)
345 if (IntPtr.Zero != pNative)
347 Win32Native.SysFreeString(pNative);
350 } // class BSTRMarshaler
352 #endif // FEATURE_COMINTEROP
355 internal static class VBByValStrMarshaler
357 static internal unsafe IntPtr ConvertToNative(string strManaged, bool fBestFit, bool fThrowOnUnmappableChar, ref int cch)
359 if (null == strManaged)
366 cch = strManaged.Length;
368 StubHelpers.CheckStringLength(cch);
370 // length field at negative offset + (# of characters incl. the terminator) * max ANSI char size
371 int nbytes = sizeof(uint) + ((cch + 1) * Marshal.SystemMaxDBCSCharSize);
373 pNative = (byte*)Marshal.AllocCoTaskMem(nbytes);
374 int* pLength = (int*)pNative;
376 pNative = pNative + sizeof(uint);
386 byte[] bytes = AnsiCharMarshaler.DoAnsiConversion(strManaged, fBestFit, fThrowOnUnmappableChar, out nbytesused);
388 Debug.Assert(nbytesused < nbytes, "Insufficient buffer allocated in VBByValStrMarshaler.ConvertToNative");
389 Buffer.Memcpy(pNative, 0, bytes, 0, nbytesused);
391 pNative[nbytesused] = 0;
392 *pLength = nbytesused;
395 return new IntPtr(pNative);
398 static internal unsafe string ConvertToManaged(IntPtr pNative, int cch)
400 if (IntPtr.Zero == pNative)
405 return new String((sbyte*)pNative, 0, cch);
408 static internal unsafe void ClearNative(IntPtr pNative)
410 if (IntPtr.Zero != pNative)
412 Win32Native.CoTaskMemFree((IntPtr)(((long)pNative) - sizeof(uint)));
415 } // class VBByValStrMarshaler
418 #if FEATURE_COMINTEROP
420 internal static class AnsiBSTRMarshaler
422 static internal unsafe IntPtr ConvertToNative(int flags, string strManaged)
424 if (null == strManaged)
429 int length = strManaged.Length;
431 StubHelpers.CheckStringLength(length);
438 bytes = AnsiCharMarshaler.DoAnsiConversion(strManaged, 0 != (flags & 0xFF), 0 != (flags >> 8), out nb);
441 return Win32Native.SysAllocStringByteLen(bytes, (uint)nb);
444 static internal unsafe string ConvertToManaged(IntPtr bstr)
446 if (IntPtr.Zero == bstr)
452 // We intentionally ignore the length field of the BSTR for back compat reasons.
453 // Unfortunately VB.NET uses Ansi BSTR marshaling when a string is passed ByRef
454 // and we cannot afford to break this common scenario.
455 return new String((sbyte*)bstr);
459 static internal unsafe void ClearNative(IntPtr pNative)
461 if (IntPtr.Zero != pNative)
463 Win32Native.SysFreeString(pNative);
466 } // class AnsiBSTRMarshaler
468 #endif // FEATURE_COMINTEROP
471 internal static class WSTRBufferMarshaler
473 static internal IntPtr ConvertToNative(string strManaged)
479 static internal unsafe string ConvertToManaged(IntPtr bstr)
485 static internal void ClearNative(IntPtr pNative)
489 } // class WSTRBufferMarshaler
492 #if FEATURE_COMINTEROP
495 [StructLayout(LayoutKind.Sequential)]
496 internal struct DateTimeNative
498 public Int64 UniversalTime;
501 internal static class DateTimeOffsetMarshaler
503 // Numer of ticks counted between 0001-01-01, 00:00:00 and 1601-01-01, 00:00:00.
504 // You can get this through: (new DateTimeOffset(1601, 1, 1, 0, 0, 1, TimeSpan.Zero)).Ticks;
505 private const Int64 ManagedUtcTicksAtNativeZero = 504911232000000000;
507 internal static void ConvertToNative(ref DateTimeOffset managedDTO, out DateTimeNative dateTime)
509 Int64 managedUtcTicks = managedDTO.UtcTicks;
510 dateTime.UniversalTime = managedUtcTicks - ManagedUtcTicksAtNativeZero;
513 internal static void ConvertToManaged(out DateTimeOffset managedLocalDTO, ref DateTimeNative nativeTicks)
515 Int64 managedUtcTicks = ManagedUtcTicksAtNativeZero + nativeTicks.UniversalTime;
516 DateTimeOffset managedUtcDTO = new DateTimeOffset(managedUtcTicks, TimeSpan.Zero);
518 // Some Utc times cannot be represented in local time in certain timezones. E.g. 0001-01-01 12:00:00 AM cannot
519 // be represented in any timezones with a negative offset from Utc. We throw an ArgumentException in that case.
520 managedLocalDTO = managedUtcDTO.ToLocalTime(true);
522 } // class DateTimeOffsetMarshaler
524 #endif // FEATURE_COMINTEROP
527 #if FEATURE_COMINTEROP
528 internal static class HStringMarshaler
530 // Slow-path, which requires making a copy of the managed string into the resulting HSTRING
531 internal static unsafe IntPtr ConvertToNative(string managed)
533 if (!Environment.IsWinRTSupported)
534 throw new PlatformNotSupportedException(SR.PlatformNotSupported_WinRT);
536 throw new ArgumentNullException(); // We don't have enough information to get the argument name
539 int hrCreate = System.Runtime.InteropServices.WindowsRuntime.UnsafeNativeMethods.WindowsCreateString(managed, managed.Length, &hstring);
540 Marshal.ThrowExceptionForHR(hrCreate, new IntPtr(-1));
544 // Fast-path, which creates a reference over a pinned managed string. This may only be used if the
545 // pinned string and HSTRING_HEADER will outlive the HSTRING produced (for instance, as an in parameter).
547 // Note that the managed string input to this method MUST be pinned, and stay pinned for the lifetime of
548 // the returned HSTRING object. If the string is not pinned, or becomes unpinned before the HSTRING's
549 // lifetime ends, the HSTRING instance will be corrupted.
550 internal static unsafe IntPtr ConvertToNativeReference(string managed,
551 [Out] HSTRING_HEADER* hstringHeader)
553 if (!Environment.IsWinRTSupported)
554 throw new PlatformNotSupportedException(SR.PlatformNotSupported_WinRT);
556 throw new ArgumentNullException(); // We don't have enough information to get the argument name
558 // The string must also be pinned by the caller to ConvertToNativeReference, which also owns
559 // the HSTRING_HEADER.
560 fixed (char* pManaged = managed)
563 int hrCreate = System.Runtime.InteropServices.WindowsRuntime.UnsafeNativeMethods.WindowsCreateStringReference(pManaged, managed.Length, hstringHeader, &hstring);
564 Marshal.ThrowExceptionForHR(hrCreate, new IntPtr(-1));
569 internal static string ConvertToManaged(IntPtr hstring)
571 if (!Environment.IsWinRTSupported)
573 throw new PlatformNotSupportedException(SR.PlatformNotSupported_WinRT);
576 return WindowsRuntimeMarshal.HStringToString(hstring);
579 internal static void ClearNative(IntPtr hstring)
581 Debug.Assert(Environment.IsWinRTSupported);
583 if (hstring != IntPtr.Zero)
585 System.Runtime.InteropServices.WindowsRuntime.UnsafeNativeMethods.WindowsDeleteString(hstring);
588 } // class HStringMarshaler
590 internal static class ObjectMarshaler
592 [MethodImplAttribute(MethodImplOptions.InternalCall)]
593 static internal extern void ConvertToNative(object objSrc, IntPtr pDstVariant);
595 [MethodImplAttribute(MethodImplOptions.InternalCall)]
596 static internal extern object ConvertToManaged(IntPtr pSrcVariant);
598 [MethodImplAttribute(MethodImplOptions.InternalCall)]
599 static internal extern void ClearNative(IntPtr pVariant);
600 } // class ObjectMarshaler
602 #endif // FEATURE_COMINTEROP
604 internal static class ValueClassMarshaler
606 [MethodImplAttribute(MethodImplOptions.InternalCall)]
607 static internal extern void ConvertToNative(IntPtr dst, IntPtr src, IntPtr pMT, ref CleanupWorkList pCleanupWorkList);
609 [MethodImplAttribute(MethodImplOptions.InternalCall)]
610 static internal extern void ConvertToManaged(IntPtr dst, IntPtr src, IntPtr pMT);
612 [MethodImplAttribute(MethodImplOptions.InternalCall)]
613 static internal extern void ClearNative(IntPtr dst, IntPtr pMT);
614 } // class ValueClassMarshaler
616 internal static class DateMarshaler
618 [MethodImplAttribute(MethodImplOptions.InternalCall)]
619 static internal extern double ConvertToNative(DateTime managedDate);
621 // The return type is really DateTime but we use long to avoid the pain associated with returning structures.
622 [MethodImplAttribute(MethodImplOptions.InternalCall)]
623 static internal extern long ConvertToManaged(double nativeDate);
624 } // class DateMarshaler
626 #if FEATURE_COMINTEROP
627 // [FriendAccessAllowed]
628 internal static class InterfaceMarshaler
630 [MethodImplAttribute(MethodImplOptions.InternalCall)]
631 static internal extern IntPtr ConvertToNative(object objSrc, IntPtr itfMT, IntPtr classMT, int flags);
633 [MethodImplAttribute(MethodImplOptions.InternalCall)]
634 static internal extern object ConvertToManaged(IntPtr pUnk, IntPtr itfMT, IntPtr classMT, int flags);
636 [DllImport(JitHelpers.QCall)]
637 static internal extern void ClearNative(IntPtr pUnk);
639 // [FriendAccessAllowed]
640 [MethodImplAttribute(MethodImplOptions.InternalCall)]
641 static internal extern object ConvertToManagedWithoutUnboxing(IntPtr pNative);
642 } // class InterfaceMarshaler
643 #endif // FEATURE_COMINTEROP
645 #if FEATURE_COMINTEROP
646 internal static class UriMarshaler
648 [MethodImplAttribute(MethodImplOptions.InternalCall)]
649 static internal extern string GetRawUriFromNative(IntPtr pUri);
651 [MethodImplAttribute(MethodImplOptions.InternalCall)]
652 static unsafe internal extern IntPtr CreateNativeUriInstanceHelper(char* rawUri, int strLen);
654 static unsafe internal IntPtr CreateNativeUriInstance(string rawUri)
656 fixed (char* pManaged = rawUri)
658 return CreateNativeUriInstanceHelper(pManaged, rawUri.Length);
661 } // class InterfaceMarshaler
663 // [FriendAccessAllowed]
664 internal static class EventArgsMarshaler
666 // [FriendAccessAllowed]
667 static internal IntPtr CreateNativeNCCEventArgsInstance(int action, object newItems, object oldItems, int newIndex, int oldIndex)
669 IntPtr newItemsIP = IntPtr.Zero;
670 IntPtr oldItemsIP = IntPtr.Zero;
672 RuntimeHelpers.PrepareConstrainedRegions();
675 if (newItems != null)
676 newItemsIP = Marshal.GetComInterfaceForObject(newItems, typeof(IBindableVector));
677 if (oldItems != null)
678 oldItemsIP = Marshal.GetComInterfaceForObject(oldItems, typeof(IBindableVector));
680 return CreateNativeNCCEventArgsInstanceHelper(action, newItemsIP, oldItemsIP, newIndex, oldIndex);
684 if (!oldItemsIP.IsNull())
685 Marshal.Release(oldItemsIP);
686 if (!newItemsIP.IsNull())
687 Marshal.Release(newItemsIP);
691 // [FriendAccessAllowed]
692 [DllImport(JitHelpers.QCall)]
693 static extern internal IntPtr CreateNativePCEventArgsInstance([MarshalAs(UnmanagedType.HString)]string name);
695 [DllImport(JitHelpers.QCall)]
696 static extern internal IntPtr CreateNativeNCCEventArgsInstanceHelper(int action, IntPtr newItem, IntPtr oldItem, int newIndex, int oldIndex);
698 #endif // FEATURE_COMINTEROP
700 internal static class MngdNativeArrayMarshaler
702 // Needs to match exactly with MngdNativeArrayMarshaler in ilmarshalers.h
703 internal struct MarshalerState
707 int m_NativeDataValid;
709 int m_ThrowOnUnmappableChar;
713 [MethodImplAttribute(MethodImplOptions.InternalCall)]
714 static internal extern void CreateMarshaler(IntPtr pMarshalState, IntPtr pMT, int dwFlags);
716 [MethodImplAttribute(MethodImplOptions.InternalCall)]
717 static internal extern void ConvertSpaceToNative(IntPtr pMarshalState, ref object pManagedHome, IntPtr pNativeHome);
719 [MethodImplAttribute(MethodImplOptions.InternalCall)]
720 static internal extern void ConvertContentsToNative(IntPtr pMarshalState, ref object pManagedHome, IntPtr pNativeHome);
722 [MethodImplAttribute(MethodImplOptions.InternalCall)]
723 static internal extern void ConvertSpaceToManaged(IntPtr pMarshalState, ref object pManagedHome, IntPtr pNativeHome,
726 [MethodImplAttribute(MethodImplOptions.InternalCall)]
727 static internal extern void ConvertContentsToManaged(IntPtr pMarshalState, ref object pManagedHome, IntPtr pNativeHome);
729 [MethodImplAttribute(MethodImplOptions.InternalCall)]
730 static internal extern void ClearNative(IntPtr pMarshalState, IntPtr pNativeHome, int cElements);
732 [MethodImplAttribute(MethodImplOptions.InternalCall)]
733 static internal extern void ClearNativeContents(IntPtr pMarshalState, IntPtr pNativeHome, int cElements);
734 } // class MngdNativeArrayMarshaler
736 #if FEATURE_COMINTEROP
737 internal static class MngdSafeArrayMarshaler
739 [MethodImplAttribute(MethodImplOptions.InternalCall)]
740 static internal extern void CreateMarshaler(IntPtr pMarshalState, IntPtr pMT, int iRank, int dwFlags);
742 [MethodImplAttribute(MethodImplOptions.InternalCall)]
743 static internal extern void ConvertSpaceToNative(IntPtr pMarshalState, ref object pManagedHome, IntPtr pNativeHome);
745 [MethodImplAttribute(MethodImplOptions.InternalCall)]
746 static internal extern void ConvertContentsToNative(IntPtr pMarshalState, ref object pManagedHome, IntPtr pNativeHome, object pOriginalManaged);
748 [MethodImplAttribute(MethodImplOptions.InternalCall)]
749 static internal extern void ConvertSpaceToManaged(IntPtr pMarshalState, ref object pManagedHome, IntPtr pNativeHome);
751 [MethodImplAttribute(MethodImplOptions.InternalCall)]
752 static internal extern void ConvertContentsToManaged(IntPtr pMarshalState, ref object pManagedHome, IntPtr pNativeHome);
754 [MethodImplAttribute(MethodImplOptions.InternalCall)]
755 static internal extern void ClearNative(IntPtr pMarshalState, ref object pManagedHome, IntPtr pNativeHome);
756 } // class MngdSafeArrayMarshaler
758 internal static class MngdHiddenLengthArrayMarshaler
760 [MethodImplAttribute(MethodImplOptions.InternalCall)]
761 static internal extern void CreateMarshaler(IntPtr pMarshalState, IntPtr pMT, IntPtr cbElementSize, ushort vt);
763 [MethodImplAttribute(MethodImplOptions.InternalCall)]
764 internal static extern void ConvertSpaceToNative(IntPtr pMarshalState, ref object pManagedHome, IntPtr pNativeHome);
766 [MethodImplAttribute(MethodImplOptions.InternalCall)]
767 internal static extern void ConvertContentsToNative(IntPtr pMarshalState, ref object pManagedHome, IntPtr pNativeHome);
769 internal static unsafe void ConvertContentsToNative_DateTime(ref DateTimeOffset[] managedArray, IntPtr pNativeHome)
771 if (managedArray != null)
773 DateTimeNative* nativeBuffer = *(DateTimeNative**)pNativeHome;
774 for (int i = 0; i < managedArray.Length; i++)
776 DateTimeOffsetMarshaler.ConvertToNative(ref managedArray[i], out nativeBuffer[i]);
781 internal static unsafe void ConvertContentsToNative_Type(ref System.Type[] managedArray, IntPtr pNativeHome)
783 if (managedArray != null)
785 TypeNameNative* nativeBuffer = *(TypeNameNative**)pNativeHome;
786 for (int i = 0; i < managedArray.Length; i++)
788 SystemTypeMarshaler.ConvertToNative(managedArray[i], &nativeBuffer[i]);
793 internal static unsafe void ConvertContentsToNative_Exception(ref Exception[] managedArray, IntPtr pNativeHome)
795 if (managedArray != null)
797 Int32* nativeBuffer = *(Int32**)pNativeHome;
798 for (int i = 0; i < managedArray.Length; i++)
800 nativeBuffer[i] = HResultExceptionMarshaler.ConvertToNative(managedArray[i]);
805 internal static unsafe void ConvertContentsToNative_Nullable<T>(ref Nullable<T>[] managedArray, IntPtr pNativeHome)
808 if (managedArray != null)
810 IntPtr* nativeBuffer = *(IntPtr**)pNativeHome;
811 for (int i = 0; i < managedArray.Length; i++)
813 nativeBuffer[i] = NullableMarshaler.ConvertToNative<T>(ref managedArray[i]);
818 internal static unsafe void ConvertContentsToNative_KeyValuePair<K, V>(ref KeyValuePair<K, V>[] managedArray, IntPtr pNativeHome)
820 if (managedArray != null)
822 IntPtr* nativeBuffer = *(IntPtr**)pNativeHome;
823 for (int i = 0; i < managedArray.Length; i++)
825 nativeBuffer[i] = KeyValuePairMarshaler.ConvertToNative<K, V>(ref managedArray[i]);
830 [MethodImplAttribute(MethodImplOptions.InternalCall)]
831 internal static extern void ConvertSpaceToManaged(IntPtr pMarshalState, ref object pManagedHome, IntPtr pNativeHome, int elementCount);
833 [MethodImplAttribute(MethodImplOptions.InternalCall)]
834 internal static extern void ConvertContentsToManaged(IntPtr pMarshalState, ref object pManagedHome, IntPtr pNativeHome);
836 internal static unsafe void ConvertContentsToManaged_DateTime(ref DateTimeOffset[] managedArray, IntPtr pNativeHome)
838 if (managedArray != null)
840 DateTimeNative* nativeBuffer = *(DateTimeNative**)pNativeHome;
841 for (int i = 0; i < managedArray.Length; i++)
843 DateTimeOffsetMarshaler.ConvertToManaged(out managedArray[i], ref nativeBuffer[i]);
848 internal static unsafe void ConvertContentsToManaged_Type(ref System.Type[] managedArray, IntPtr pNativeHome)
850 if (managedArray != null)
852 TypeNameNative* nativeBuffer = *(TypeNameNative**)pNativeHome;
853 for (int i = 0; i < managedArray.Length; i++)
855 SystemTypeMarshaler.ConvertToManaged(&nativeBuffer[i], ref managedArray[i]);
860 internal static unsafe void ConvertContentsToManaged_Exception(ref Exception[] managedArray, IntPtr pNativeHome)
862 if (managedArray != null)
864 Int32* nativeBuffer = *(Int32**)pNativeHome;
865 for (int i = 0; i < managedArray.Length; i++)
867 managedArray[i] = HResultExceptionMarshaler.ConvertToManaged(nativeBuffer[i]);
872 internal static unsafe void ConvertContentsToManaged_Nullable<T>(ref Nullable<T>[] managedArray, IntPtr pNativeHome)
875 if (managedArray != null)
877 IntPtr* nativeBuffer = *(IntPtr**)pNativeHome;
878 for (int i = 0; i < managedArray.Length; i++)
880 managedArray[i] = NullableMarshaler.ConvertToManaged<T>(nativeBuffer[i]);
885 internal static unsafe void ConvertContentsToManaged_KeyValuePair<K, V>(ref KeyValuePair<K, V>[] managedArray, IntPtr pNativeHome)
887 if (managedArray != null)
889 IntPtr* nativeBuffer = *(IntPtr**)pNativeHome;
890 for (int i = 0; i < managedArray.Length; i++)
892 managedArray[i] = KeyValuePairMarshaler.ConvertToManaged<K, V>(nativeBuffer[i]);
897 [MethodImplAttribute(MethodImplOptions.InternalCall)]
898 internal static extern void ClearNativeContents(IntPtr pMarshalState, IntPtr pNativeHome, int cElements);
900 internal static unsafe void ClearNativeContents_Type(IntPtr pNativeHome, int cElements)
902 Debug.Assert(Environment.IsWinRTSupported);
904 TypeNameNative* pNativeTypeArray = *(TypeNameNative**)pNativeHome;
905 if (pNativeTypeArray != null)
907 for (int i = 0; i < cElements; ++i)
909 SystemTypeMarshaler.ClearNative(pNativeTypeArray);
914 } // class MngdHiddenLengthArrayMarshaler
916 #endif // FEATURE_COMINTEROP
918 internal static class MngdRefCustomMarshaler
920 [MethodImplAttribute(MethodImplOptions.InternalCall)]
921 static internal extern void CreateMarshaler(IntPtr pMarshalState, IntPtr pCMHelper);
923 [MethodImplAttribute(MethodImplOptions.InternalCall)]
924 static internal extern void ConvertContentsToNative(IntPtr pMarshalState, ref object pManagedHome, IntPtr pNativeHome);
926 [MethodImplAttribute(MethodImplOptions.InternalCall)]
927 static internal extern void ConvertContentsToManaged(IntPtr pMarshalState, ref object pManagedHome, IntPtr pNativeHome);
929 [MethodImplAttribute(MethodImplOptions.InternalCall)]
930 static internal extern void ClearNative(IntPtr pMarshalState, ref object pManagedHome, IntPtr pNativeHome);
932 [MethodImplAttribute(MethodImplOptions.InternalCall)]
933 static internal extern void ClearManaged(IntPtr pMarshalState, ref object pManagedHome, IntPtr pNativeHome);
934 } // class MngdRefCustomMarshaler
936 internal struct AsAnyMarshaler
938 private const ushort VTHACK_ANSICHAR = 253;
939 private const ushort VTHACK_WINBOOL = 254;
941 private enum BackPropAction
950 // Pointer to MngdNativeArrayMarshaler, ownership not assumed.
951 private IntPtr pvArrayMarshaler;
953 // Type of action to perform after the CLR-to-unmanaged call.
954 private BackPropAction backPropAction;
956 // The managed layout type for BackPropAction.Layout.
957 private Type layoutType;
959 // Cleanup list to be destroyed when clearing the native view (for layouts with SafeHandles).
960 private CleanupWorkList cleanupWorkList;
963 internal enum AsAnyFlags
968 IsThrowOn = 0x0000FF00,
969 IsBestFit = 0x000000FF
972 private static bool IsIn(int dwFlags) { return ((dwFlags & (int)AsAnyFlags.In) != 0); }
973 private static bool IsOut(int dwFlags) { return ((dwFlags & (int)AsAnyFlags.Out) != 0); }
974 private static bool IsAnsi(int dwFlags) { return ((dwFlags & (int)AsAnyFlags.IsAnsi) != 0); }
975 private static bool IsThrowOn(int dwFlags) { return ((dwFlags & (int)AsAnyFlags.IsThrowOn) != 0); }
976 private static bool IsBestFit(int dwFlags) { return ((dwFlags & (int)AsAnyFlags.IsBestFit) != 0); }
978 internal AsAnyMarshaler(IntPtr pvArrayMarshaler)
980 // we need this in case the value being marshaled turns out to be array
981 Debug.Assert(pvArrayMarshaler != IntPtr.Zero, "pvArrayMarshaler must not be null");
983 this.pvArrayMarshaler = pvArrayMarshaler;
984 backPropAction = BackPropAction.None;
986 cleanupWorkList = null;
989 #region ConvertToNative helpers
991 private unsafe IntPtr ConvertArrayToNative(object pManagedHome, int dwFlags)
993 Type elementType = pManagedHome.GetType().GetElementType();
994 VarEnum vt = VarEnum.VT_EMPTY;
996 switch (Type.GetTypeCode(elementType))
998 case TypeCode.SByte: vt = VarEnum.VT_I1; break;
999 case TypeCode.Byte: vt = VarEnum.VT_UI1; break;
1000 case TypeCode.Int16: vt = VarEnum.VT_I2; break;
1001 case TypeCode.UInt16: vt = VarEnum.VT_UI2; break;
1002 case TypeCode.Int32: vt = VarEnum.VT_I4; break;
1003 case TypeCode.UInt32: vt = VarEnum.VT_UI4; break;
1004 case TypeCode.Int64: vt = VarEnum.VT_I8; break;
1005 case TypeCode.UInt64: vt = VarEnum.VT_UI8; break;
1006 case TypeCode.Single: vt = VarEnum.VT_R4; break;
1007 case TypeCode.Double: vt = VarEnum.VT_R8; break;
1008 case TypeCode.Char: vt = (IsAnsi(dwFlags) ? (VarEnum)VTHACK_ANSICHAR : VarEnum.VT_UI2); break;
1009 case TypeCode.Boolean: vt = (VarEnum)VTHACK_WINBOOL; break;
1011 case TypeCode.Object:
1013 if (elementType == typeof(IntPtr))
1015 vt = (IntPtr.Size == 4 ? VarEnum.VT_I4 : VarEnum.VT_I8);
1017 else if (elementType == typeof(UIntPtr))
1019 vt = (IntPtr.Size == 4 ? VarEnum.VT_UI4 : VarEnum.VT_UI8);
1026 throw new ArgumentException(SR.Arg_NDirectBadObject);
1029 // marshal the object as C-style array (UnmanagedType.LPArray)
1030 int dwArrayMarshalerFlags = (int)vt;
1031 if (IsBestFit(dwFlags)) dwArrayMarshalerFlags |= (1 << 16);
1032 if (IsThrowOn(dwFlags)) dwArrayMarshalerFlags |= (1 << 24);
1034 MngdNativeArrayMarshaler.CreateMarshaler(
1036 IntPtr.Zero, // not needed as we marshal primitive VTs only
1037 dwArrayMarshalerFlags);
1040 IntPtr pNativeHomeAddr = new IntPtr(&pNativeHome);
1042 MngdNativeArrayMarshaler.ConvertSpaceToNative(
1049 MngdNativeArrayMarshaler.ConvertContentsToNative(
1056 backPropAction = BackPropAction.Array;
1062 private static IntPtr ConvertStringToNative(string pManagedHome, int dwFlags)
1066 // IsIn, IsOut are ignored for strings - they're always in-only
1067 if (IsAnsi(dwFlags))
1069 // marshal the object as Ansi string (UnmanagedType.LPStr)
1070 pNativeHome = CSTRMarshaler.ConvertToNative(
1071 dwFlags & 0xFFFF, // (throw on unmappable char << 8 | best fit)
1073 IntPtr.Zero); // unmanaged buffer will be allocated
1077 // marshal the object as Unicode string (UnmanagedType.LPWStr)
1078 StubHelpers.CheckStringLength(pManagedHome.Length);
1080 int allocSize = (pManagedHome.Length + 1) * 2;
1081 pNativeHome = Marshal.AllocCoTaskMem(allocSize);
1083 String.InternalCopy(pManagedHome, pNativeHome, allocSize);
1089 private unsafe IntPtr ConvertStringBuilderToNative(StringBuilder pManagedHome, int dwFlags)
1093 // P/Invoke can be used to call Win32 apis that don't strictly follow CLR in/out semantics and thus may
1094 // leave garbage in the buffer in circumstances that we can't detect. To prevent us from crashing when
1095 // converting the contents back to managed, put a hidden NULL terminator past the end of the official buffer.
1097 // Unmanaged layout:
1098 // +====================================+
1099 // | Extra hidden NULL |
1100 // +====================================+ \
1102 // | [Converted] NULL-terminated string | |- buffer that the target may change
1104 // +====================================+ / <-- native home
1106 // Note that StringBuilder.Capacity is the number of characters NOT including any terminators.
1108 if (IsAnsi(dwFlags))
1110 StubHelpers.CheckStringLength(pManagedHome.Capacity);
1112 // marshal the object as Ansi string (UnmanagedType.LPStr)
1113 int allocSize = (pManagedHome.Capacity * Marshal.SystemMaxDBCSCharSize) + 4;
1114 pNativeHome = Marshal.AllocCoTaskMem(allocSize);
1116 byte* ptr = (byte*)pNativeHome;
1117 *(ptr + allocSize - 3) = 0;
1118 *(ptr + allocSize - 2) = 0;
1119 *(ptr + allocSize - 1) = 0;
1123 int length = pManagedHome.ToString().ConvertToAnsi(
1126 IsThrowOn(dwFlags));
1127 Debug.Assert(length < allocSize, "Expected a length less than the allocated size");
1131 backPropAction = BackPropAction.StringBuilderAnsi;
1136 // marshal the object as Unicode string (UnmanagedType.LPWStr)
1137 int allocSize = (pManagedHome.Capacity * 2) + 4;
1138 pNativeHome = Marshal.AllocCoTaskMem(allocSize);
1140 byte* ptr = (byte*)pNativeHome;
1141 *(ptr + allocSize - 1) = 0;
1142 *(ptr + allocSize - 2) = 0;
1146 int length = pManagedHome.Length * 2;
1147 pManagedHome.InternalCopy(pNativeHome, length);
1149 // null-terminate the native string
1150 *(ptr + length + 0) = 0;
1151 *(ptr + length + 1) = 0;
1155 backPropAction = BackPropAction.StringBuilderUnicode;
1162 private unsafe IntPtr ConvertLayoutToNative(object pManagedHome, int dwFlags)
1164 // Note that the following call will not throw exception if the type
1165 // of pManagedHome is not marshalable. That's intentional because we
1166 // want to maintain the original behavior where this was indicated
1167 // by TypeLoadException during the actual field marshaling.
1168 int allocSize = Marshal.SizeOfHelper(pManagedHome.GetType(), false);
1169 IntPtr pNativeHome = Marshal.AllocCoTaskMem(allocSize);
1171 // marshal the object as class with layout (UnmanagedType.LPStruct)
1174 StubHelpers.FmtClassUpdateNativeInternal(pManagedHome, (byte*)pNativeHome.ToPointer(), ref cleanupWorkList);
1178 backPropAction = BackPropAction.Layout;
1180 layoutType = pManagedHome.GetType();
1187 internal IntPtr ConvertToNative(object pManagedHome, int dwFlags)
1189 if (pManagedHome == null)
1192 if (pManagedHome is ArrayWithOffset)
1193 throw new ArgumentException(SR.Arg_MarshalAsAnyRestriction);
1197 if (pManagedHome.GetType().IsArray)
1200 pNativeHome = ConvertArrayToNative(pManagedHome, dwFlags);
1205 StringBuilder sbValue;
1207 if ((strValue = pManagedHome as string) != null)
1209 // string (LPStr or LPWStr)
1210 pNativeHome = ConvertStringToNative(strValue, dwFlags);
1212 else if ((sbValue = pManagedHome as StringBuilder) != null)
1214 // StringBuilder (LPStr or LPWStr)
1215 pNativeHome = ConvertStringBuilderToNative(sbValue, dwFlags);
1217 else if (pManagedHome.GetType().IsLayoutSequential || pManagedHome.GetType().IsExplicitLayout)
1219 // layout (LPStruct)
1220 pNativeHome = ConvertLayoutToNative(pManagedHome, dwFlags);
1224 // this type is not supported for AsAny marshaling
1225 throw new ArgumentException(SR.Arg_NDirectBadObject);
1232 internal unsafe void ConvertToManaged(object pManagedHome, IntPtr pNativeHome)
1234 switch (backPropAction)
1236 case BackPropAction.Array:
1238 MngdNativeArrayMarshaler.ConvertContentsToManaged(
1241 new IntPtr(&pNativeHome));
1245 case BackPropAction.Layout:
1247 StubHelpers.FmtClassUpdateCLRInternal(pManagedHome, (byte*)pNativeHome.ToPointer());
1251 case BackPropAction.StringBuilderAnsi:
1253 sbyte* ptr = (sbyte*)pNativeHome.ToPointer();
1254 ((StringBuilder)pManagedHome).ReplaceBufferAnsiInternal(ptr, Win32Native.lstrlenA(pNativeHome));
1258 case BackPropAction.StringBuilderUnicode:
1260 char* ptr = (char*)pNativeHome.ToPointer();
1261 ((StringBuilder)pManagedHome).ReplaceBufferInternal(ptr, Win32Native.lstrlenW(pNativeHome));
1265 // nothing to do for BackPropAction.None
1269 internal void ClearNative(IntPtr pNativeHome)
1271 if (pNativeHome != IntPtr.Zero)
1273 if (layoutType != null)
1275 // this must happen regardless of BackPropAction
1276 Marshal.DestroyStructure(pNativeHome, layoutType);
1278 Win32Native.CoTaskMemFree(pNativeHome);
1280 StubHelpers.DestroyCleanupList(ref cleanupWorkList);
1282 } // struct AsAnyMarshaler
1284 #if FEATURE_COMINTEROP
1285 internal static class NullableMarshaler
1287 static internal IntPtr ConvertToNative<T>(ref Nullable<T> pManaged) where T : struct
1289 if (pManaged.HasValue)
1291 object impl = IReferenceFactory.CreateIReference(pManaged);
1292 return Marshal.GetComInterfaceForObject(impl, typeof(IReference<T>));
1300 static internal void ConvertToManagedRetVoid<T>(IntPtr pNative, ref Nullable<T> retObj) where T : struct
1302 retObj = ConvertToManaged<T>(pNative);
1306 static internal Nullable<T> ConvertToManaged<T>(IntPtr pNative) where T : struct
1308 if (pNative != IntPtr.Zero)
1310 object wrapper = InterfaceMarshaler.ConvertToManagedWithoutUnboxing(pNative);
1311 return (Nullable<T>)CLRIReferenceImpl<T>.UnboxHelper(wrapper);
1315 return new Nullable<T>();
1318 } // class NullableMarshaler
1320 // Corresponds to Windows.UI.Xaml.Interop.TypeName
1321 [StructLayout(LayoutKind.Sequential)]
1322 internal struct TypeNameNative
1324 internal IntPtr typeName; // HSTRING
1325 internal TypeKind typeKind; // TypeKind enum
1328 // Corresponds to Windows.UI.Xaml.TypeSource
1329 internal enum TypeKind
1336 internal static class WinRTTypeNameConverter
1338 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1339 internal static extern string ConvertToWinRTTypeName(System.Type managedType, out bool isPrimitive);
1341 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1342 internal static extern System.Type GetTypeFromWinRTTypeName(string typeName, out bool isPrimitive);
1345 internal static class SystemTypeMarshaler
1347 internal static unsafe void ConvertToNative(System.Type managedType, TypeNameNative* pNativeType)
1349 if (!Environment.IsWinRTSupported)
1351 throw new PlatformNotSupportedException(SR.PlatformNotSupported_WinRT);
1355 if (managedType != null)
1357 if (managedType.GetType() != typeof(System.RuntimeType))
1358 { // The type should be exactly System.RuntimeType (and not its child System.ReflectionOnlyType, or other System.Type children)
1359 throw new ArgumentException(SR.Format(SR.Argument_WinRTSystemRuntimeType, managedType.GetType().ToString()));
1363 string winrtTypeName = WinRTTypeNameConverter.ConvertToWinRTTypeName(managedType, out isPrimitive);
1364 if (winrtTypeName != null)
1366 // Must be a WinRT type, either in a WinMD or a Primitive
1367 typeName = winrtTypeName;
1369 pNativeType->typeKind = TypeKind.Primitive;
1371 pNativeType->typeKind = TypeKind.Metadata;
1376 typeName = managedType.AssemblyQualifiedName;
1377 pNativeType->typeKind = TypeKind.Projection;
1381 { // Marshal null as empty string + Projection
1383 pNativeType->typeKind = TypeKind.Projection;
1386 int hrCreate = System.Runtime.InteropServices.WindowsRuntime.UnsafeNativeMethods.WindowsCreateString(typeName, typeName.Length, &pNativeType->typeName);
1387 Marshal.ThrowExceptionForHR(hrCreate, new IntPtr(-1));
1390 internal static unsafe void ConvertToManaged(TypeNameNative* pNativeType, ref System.Type managedType)
1392 if (!Environment.IsWinRTSupported)
1394 throw new PlatformNotSupportedException(SR.PlatformNotSupported_WinRT);
1397 string typeName = WindowsRuntimeMarshal.HStringToString(pNativeType->typeName);
1398 if (String.IsNullOrEmpty(typeName))
1404 if (pNativeType->typeKind == TypeKind.Projection)
1406 managedType = Type.GetType(typeName, /* throwOnError = */ true);
1411 managedType = WinRTTypeNameConverter.GetTypeFromWinRTTypeName(typeName, out isPrimitive);
1413 // TypeSource must match
1414 if (isPrimitive != (pNativeType->typeKind == TypeKind.Primitive))
1415 throw new ArgumentException(SR.Argument_Unexpected_TypeSource);
1419 internal static unsafe void ClearNative(TypeNameNative* pNativeType)
1421 Debug.Assert(Environment.IsWinRTSupported);
1423 if (pNativeType->typeName != IntPtr.Zero)
1425 System.Runtime.InteropServices.WindowsRuntime.UnsafeNativeMethods.WindowsDeleteString(pNativeType->typeName);
1428 } // class SystemTypeMarshaler
1430 // For converting WinRT's Windows.Foundation.HResult into System.Exception and vice versa.
1431 internal static class HResultExceptionMarshaler
1433 static internal unsafe int ConvertToNative(Exception ex)
1435 if (!Environment.IsWinRTSupported)
1437 throw new PlatformNotSupportedException(SR.PlatformNotSupported_WinRT);
1446 static internal unsafe Exception ConvertToManaged(int hr)
1448 if (!Environment.IsWinRTSupported)
1450 throw new PlatformNotSupportedException(SR.PlatformNotSupported_WinRT);
1456 e = StubHelpers.InternalGetCOMHRExceptionObject(hr, IntPtr.Zero, null, /* fForWinRT */ true);
1459 // S_OK should be marshaled as null. WinRT API's should not return S_FALSE by convention.
1460 // We've chosen to treat S_FALSE as success and return null.
1461 Debug.Assert(e != null || hr == 0 || hr == 1, "Unexpected HRESULT - it is a success HRESULT (without the high bit set) other than S_OK & S_FALSE.");
1464 } // class HResultExceptionMarshaler
1466 internal static class KeyValuePairMarshaler
1468 internal static IntPtr ConvertToNative<K, V>([In] ref KeyValuePair<K, V> pair)
1470 IKeyValuePair<K, V> impl = new CLRIKeyValuePairImpl<K, V>(ref pair);
1471 return Marshal.GetComInterfaceForObject(impl, typeof(IKeyValuePair<K, V>));
1474 internal static KeyValuePair<K, V> ConvertToManaged<K, V>(IntPtr pInsp)
1476 object obj = InterfaceMarshaler.ConvertToManagedWithoutUnboxing(pInsp);
1478 IKeyValuePair<K, V> pair = (IKeyValuePair<K, V>)obj;
1479 return new KeyValuePair<K, V>(pair.Key, pair.Value);
1482 // Called from COMInterfaceMarshaler
1483 internal static object ConvertToManagedBox<K, V>(IntPtr pInsp)
1485 return (object)ConvertToManaged<K, V>(pInsp);
1487 } // class KeyValuePairMarshaler
1489 #endif // FEATURE_COMINTEROP
1491 [StructLayout(LayoutKind.Sequential)]
1492 internal struct NativeVariant
1495 private ushort wReserved1;
1496 private ushort wReserved2;
1497 private ushort wReserved3;
1499 // The union portion of the structure contains at least one 64-bit type that on some 32-bit platforms
1500 // (notably ARM) requires 64-bit alignment. So on 32-bit platforms we'll actually size the variant
1501 // portion of the struct with an Int64 so the type loader notices this requirement (a no-op on x86,
1502 // but on ARM it will allow us to correctly determine the layout of native argument lists containing
1503 // VARIANTs). Note that the field names here don't matter: none of the code refers to these fields,
1504 // the structure just exists to provide size information to the IL marshaler.
1506 private IntPtr data1;
1507 private IntPtr data2;
1511 } // struct NativeVariant
1513 // Aggregates SafeHandle and the "owned" bit which indicates whether the SafeHandle
1514 // has been successfully AddRef'ed. This allows us to do realiable cleanup (Release)
1515 // if and only if it is needed.
1516 internal sealed class CleanupWorkListElement
1518 public CleanupWorkListElement(SafeHandle handle)
1523 public SafeHandle m_handle;
1525 // This field is passed by-ref to SafeHandle.DangerousAddRef.
1526 // CleanupWorkList.Destroy ignores this element if m_owned is not set to true.
1527 public bool m_owned;
1528 } // class CleanupWorkListElement
1530 internal sealed class CleanupWorkList
1532 private List<CleanupWorkListElement> m_list = new List<CleanupWorkListElement>();
1534 public void Add(CleanupWorkListElement elem)
1536 Debug.Assert(elem.m_owned == false, "m_owned is supposed to be false and set later by DangerousAddRef");
1540 public void Destroy()
1542 for (int i = m_list.Count - 1; i >= 0; i--)
1544 if (m_list[i].m_owned)
1545 StubHelpers.SafeHandleRelease(m_list[i].m_handle);
1548 } // class CleanupWorkList
1550 internal static class StubHelpers
1552 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1553 static internal extern bool IsQCall(IntPtr pMD);
1555 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1556 static internal extern void InitDeclaringType(IntPtr pMD);
1558 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1559 static internal extern IntPtr GetNDirectTarget(IntPtr pMD);
1561 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1562 static internal extern IntPtr GetDelegateTarget(Delegate pThis, ref IntPtr pStubArg);
1564 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1565 static internal extern void ClearLastError();
1567 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1568 static internal extern void SetLastError();
1570 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1571 static internal extern void ThrowInteropParamException(int resID, int paramIdx);
1573 static internal IntPtr AddToCleanupList(ref CleanupWorkList pCleanupWorkList, SafeHandle handle)
1575 if (pCleanupWorkList == null)
1576 pCleanupWorkList = new CleanupWorkList();
1578 CleanupWorkListElement element = new CleanupWorkListElement(handle);
1579 pCleanupWorkList.Add(element);
1581 // element.m_owned will be true iff the AddRef succeeded
1582 return SafeHandleAddRef(handle, ref element.m_owned);
1585 static internal void DestroyCleanupList(ref CleanupWorkList pCleanupWorkList)
1587 if (pCleanupWorkList != null)
1589 pCleanupWorkList.Destroy();
1590 pCleanupWorkList = null;
1594 static internal Exception GetHRExceptionObject(int hr)
1596 Exception ex = InternalGetHRExceptionObject(hr);
1597 ex.InternalPreserveStackTrace();
1601 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1602 static internal extern Exception InternalGetHRExceptionObject(int hr);
1604 #if FEATURE_COMINTEROP
1605 static internal Exception GetCOMHRExceptionObject(int hr, IntPtr pCPCMD, object pThis)
1607 Exception ex = InternalGetCOMHRExceptionObject(hr, pCPCMD, pThis, false);
1608 ex.InternalPreserveStackTrace();
1612 static internal Exception GetCOMHRExceptionObject_WinRT(int hr, IntPtr pCPCMD, object pThis)
1614 Exception ex = InternalGetCOMHRExceptionObject(hr, pCPCMD, pThis, true);
1615 ex.InternalPreserveStackTrace();
1619 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1620 static internal extern Exception InternalGetCOMHRExceptionObject(int hr, IntPtr pCPCMD, object pThis, bool fForWinRT);
1622 #endif // FEATURE_COMINTEROP
1624 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1625 static internal extern IntPtr CreateCustomMarshalerHelper(IntPtr pMD, int paramToken, IntPtr hndManagedType);
1627 //-------------------------------------------------------
1628 // SafeHandle Helpers
1629 //-------------------------------------------------------
1631 // AddRefs the SH and returns the underlying unmanaged handle.
1632 static internal IntPtr SafeHandleAddRef(SafeHandle pHandle, ref bool success)
1634 if (pHandle == null)
1636 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.pHandle, ExceptionResource.ArgumentNull_SafeHandle);
1639 pHandle.DangerousAddRef(ref success);
1640 return pHandle.DangerousGetHandle();
1643 // Releases the SH (to be called from finally block).
1644 static internal void SafeHandleRelease(SafeHandle pHandle)
1646 if (pHandle == null)
1648 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.pHandle, ExceptionResource.ArgumentNull_SafeHandle);
1653 pHandle.DangerousRelease();
1656 catch (Exception ex)
1658 Mda.ReportErrorSafeHandleRelease(ex);
1660 #else // MDA_SUPPORTED
1663 #endif // MDA_SUPPORTED
1666 #if FEATURE_COMINTEROP
1667 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1668 static internal extern IntPtr GetCOMIPFromRCW(object objSrc, IntPtr pCPCMD, out IntPtr ppTarget, out bool pfNeedsRelease);
1670 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1671 static internal extern IntPtr GetCOMIPFromRCW_WinRT(object objSrc, IntPtr pCPCMD, out IntPtr ppTarget);
1673 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1674 static internal extern IntPtr GetCOMIPFromRCW_WinRTSharedGeneric(object objSrc, IntPtr pCPCMD, out IntPtr ppTarget);
1676 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1677 static internal extern IntPtr GetCOMIPFromRCW_WinRTDelegate(object objSrc, IntPtr pCPCMD, out IntPtr ppTarget);
1679 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1680 static internal extern bool ShouldCallWinRTInterface(object objSrc, IntPtr pCPCMD);
1682 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1683 static internal extern Delegate GetTargetForAmbiguousVariantCall(object objSrc, IntPtr pMT, out bool fUseString);
1685 //-------------------------------------------------------
1686 // Helper for the MDA RaceOnRCWCleanup
1687 //-------------------------------------------------------
1689 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1690 static internal extern void StubRegisterRCW(object pThis);
1692 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1693 static internal extern void StubUnregisterRCW(object pThis);
1695 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1696 static internal extern IntPtr GetDelegateInvokeMethod(Delegate pThis);
1698 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1699 static internal extern object GetWinRTFactoryObject(IntPtr pCPCMD);
1701 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1702 static internal extern IntPtr GetWinRTFactoryReturnValue(object pThis, IntPtr pCtorEntry);
1704 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1705 static internal extern IntPtr GetOuterInspectable(object pThis, IntPtr pCtorMD);
1708 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1709 static internal extern Exception TriggerExceptionSwallowedMDA(Exception ex, IntPtr pManagedTarget);
1710 #endif // MDA_SUPPORTED
1712 #endif // FEATURE_COMINTEROP
1715 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1716 static internal extern void CheckCollectedDelegateMDA(IntPtr pEntryThunk);
1717 #endif // MDA_SUPPORTED
1719 //-------------------------------------------------------
1721 //-------------------------------------------------------
1722 #if PROFILING_SUPPORTED
1723 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1724 static internal extern IntPtr ProfilerBeginTransitionCallback(IntPtr pSecretParam, IntPtr pThread, object pThis);
1726 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1727 static internal extern void ProfilerEndTransitionCallback(IntPtr pMD, IntPtr pThread);
1728 #endif // PROFILING_SUPPORTED
1730 //------------------------------------------------------
1732 //------------------------------------------------------
1733 static internal void CheckStringLength(int length)
1735 CheckStringLength((uint)length);
1738 static internal void CheckStringLength(uint length)
1740 if (length > 0x7ffffff0)
1742 throw new MarshalDirectiveException(SR.Marshaler_StringTooLong);
1746 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1747 static internal unsafe extern int strlen(sbyte* ptr);
1749 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1750 static internal extern void DecimalCanonicalizeInternal(ref Decimal dec);
1752 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1753 static internal unsafe extern void FmtClassUpdateNativeInternal(object obj, byte* pNative, ref CleanupWorkList pCleanupWorkList);
1754 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1755 static internal unsafe extern void FmtClassUpdateCLRInternal(object obj, byte* pNative);
1756 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1757 static internal unsafe extern void LayoutDestroyNativeInternal(byte* pNative, IntPtr pMT);
1758 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1759 static internal extern object AllocateInternal(IntPtr typeHandle);
1761 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1762 static internal extern void MarshalToUnmanagedVaListInternal(IntPtr va_list, uint vaListSize, IntPtr pArgIterator);
1764 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1765 static internal extern void MarshalToManagedVaListInternal(IntPtr va_list, IntPtr pArgIterator);
1767 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1768 static internal extern uint CalcVaListSize(IntPtr va_list);
1770 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1771 static internal extern void ValidateObject(object obj, IntPtr pMD, object pThis);
1773 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1774 static internal extern void LogPinnedArgument(IntPtr localDesc, IntPtr nativeArg);
1776 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1777 static internal extern void ValidateByref(IntPtr byref, IntPtr pMD, object pThis); // the byref is pinned so we can safely "cast" it to IntPtr
1779 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1780 static internal extern IntPtr GetStubContext();
1783 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1784 static internal extern IntPtr GetStubContextAddr();
1788 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1789 static internal extern void TriggerGCForMDA();
1790 #endif // MDA_SUPPORTED
1792 #if FEATURE_ARRAYSTUB_AS_IL
1793 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1794 internal static extern void ArrayTypeCheck(object o, Object[] arr);
1797 #if FEATURE_MULTICASTSTUB_AS_IL
1798 [MethodImplAttribute(MethodImplOptions.InternalCall)]
1799 internal static extern void MulticastDebuggerTraceHelper(object o, Int32 count);
1801 } // class StubHelpers