1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 // File: FieldMarshaler.cpp
16 #include "fieldmarshaler.h"
19 #include "dllimport.h"
20 #include "comdelegate.h"
22 #include "comdatetime.h"
23 #include "olevariant.h"
27 #include "sigformat.h"
28 #include "marshalnative.h"
29 #include "typeparse.h"
30 #ifdef FEATURE_COMINTEROP
31 #include <winstring.h>
32 #endif // FEATURE_COMINTEROP
34 // forward declaration
35 BOOL CheckForPrimitiveType(CorElementType elemType, CQuickArray<WCHAR> *pStrPrimitiveType);
36 TypeHandle ArraySubTypeLoadWorker(const SString &strUserDefTypeName, Assembly* pAssembly);
37 TypeHandle GetFieldTypeHandleWorker(MetaSig *pFieldSig);
40 //=======================================================================
41 // A database of NFT types.
42 //=======================================================================
43 struct NFTDataBaseEntry
45 UINT32 m_cbNativeSize; // native size of field (0 if not constant)
46 bool m_fWinRTSupported; // true if the field marshaler is supported for WinRT
49 static const NFTDataBaseEntry NFTDataBase[] =
52 #define DEFINE_NFT(name, nativesize, fWinRTSupported) { nativesize, fWinRTSupported },
57 //=======================================================================
58 // This is invoked from the class loader while building the internal structures for a type
59 // This function should check if explicit layout metadata exists.
62 // TRUE - yes, there's layout metadata
63 // FALSE - no, there's no layout.
64 // fail - throws a typeload exception
67 // *pNLType gets set to nltAnsi or nltUnicode
68 // *pPackingSize declared packing size
69 // *pfExplicitoffsets offsets explicit in metadata or computed?
70 //=======================================================================
71 BOOL HasLayoutMetadata(Assembly* pAssembly, IMDInternalImport *pInternalImport, mdTypeDef cl, MethodTable*pParentMT, BYTE *pPackingSize, BYTE *pNLTType, BOOL *pfExplicitOffsets)
78 PRECONDITION(CheckPointer(pInternalImport));
79 PRECONDITION(CheckPointer(pPackingSize));
80 PRECONDITION(CheckPointer(pNLTType));
81 PRECONDITION(CheckPointer(pfExplicitOffsets));
91 if (FAILED(pInternalImport->GetTypeDefProps(cl, &clFlags, NULL)))
93 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
96 if (IsTdAutoLayout(clFlags))
98 // <BUGNUM>workaround for B#104780 - VC fails to set SequentialLayout on some classes
99 // with ClassSize. Too late to fix compiler for V1.
101 // To compensate, we treat AutoLayout classes as Sequential if they
102 // meet all of the following criteria:
104 // - ClassSize present and nonzero.
105 // - No instance fields declared
106 // - Base class is System.ValueType.
108 ULONG cbTotalSize = 0;
109 if (SUCCEEDED(pInternalImport->GetClassTotalSize(cl, &cbTotalSize)) && cbTotalSize != 0)
111 if (pParentMT && pParentMT->IsValueTypeClass())
113 MDEnumHolder hEnumField(pInternalImport);
114 if (SUCCEEDED(pInternalImport->EnumInit(mdtFieldDef, cl, &hEnumField)))
116 ULONG numFields = pInternalImport->EnumGetCount(&hEnumField);
119 *pfExplicitOffsets = FALSE;
130 else if (IsTdSequentialLayout(clFlags))
132 *pfExplicitOffsets = FALSE;
134 else if (IsTdExplicitLayout(clFlags))
136 *pfExplicitOffsets = TRUE;
140 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
143 // We now know this class has seq. or explicit layout. Ensure the parent does too.
144 if (pParentMT && !(pParentMT->IsObjectClass() || pParentMT->IsValueTypeClass()) && !(pParentMT->HasLayout()))
145 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
147 if (IsTdAnsiClass(clFlags))
151 else if (IsTdUnicodeClass(clFlags))
153 *pNLTType = nltUnicode;
155 else if (IsTdAutoClass(clFlags))
157 // We no longer support Win9x so TdAuto always maps to Unicode.
158 *pNLTType = nltUnicode;
162 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
166 hr = pInternalImport->GetClassPackSize(cl, &dwPackSize);
167 if (FAILED(hr) || dwPackSize == 0)
168 dwPackSize = DEFAULT_PACKING_SIZE;
170 // This has to be reduced to a BYTE value, so we had better make sure it fits. If
171 // not, we'll throw an exception instead of trying to munge the value to what we
172 // think the user might want.
173 if (!FitsInU1((UINT64)(dwPackSize)))
175 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
178 *pPackingSize = (BYTE)dwPackSize;
185 ParseNativeTypeFlag_None = 0x00,
186 ParseNativeTypeFlag_IsAnsi = 0x01,
188 #ifdef FEATURE_COMINTEROP
189 ParseNativeTypeFlag_IsWinRT = 0x02,
190 #endif // FEATURE_COMINTEROP
192 ParseNativeTypeFlags;
194 inline ParseNativeTypeFlags operator|=(ParseNativeTypeFlags& lhs, ParseNativeTypeFlags rhs)
196 LIMITED_METHOD_CONTRACT;
197 lhs = static_cast<ParseNativeTypeFlags>(lhs | rhs);
202 #pragma warning(push)
203 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
205 VOID ParseNativeType(Module* pModule,
206 PCCOR_SIGNATURE pCOMSignature,
207 DWORD cbCOMSignature,
208 ParseNativeTypeFlags flags,
209 LayoutRawFieldInfo* pfwalk,
210 PCCOR_SIGNATURE pNativeType,
212 IMDInternalImport* pInternalImport,
214 const SigTypeContext * pTypeContext,
215 BOOL *pfDisqualifyFromManagedSequential // set to TRUE if needed (never set to FALSE, it may come in as TRUE!)
227 PRECONDITION(CheckPointer(pfwalk));
231 // Make sure that there is no junk in the unused part of the field marshaler space (ngen image determinism)
232 ZeroMemory(&pfwalk->m_FieldMarshaler, MAXFIELDMARSHALERSIZE);
234 #define INITFIELDMARSHALER(nfttype, fmtype, args) \
237 static_assert_no_msg(sizeof(fmtype) <= MAXFIELDMARSHALERSIZE); \
238 pfwalk->m_nft = (nfttype); \
239 new ( &(pfwalk->m_FieldMarshaler) ) fmtype args; \
240 ((FieldMarshaler*)&(pfwalk->m_FieldMarshaler))->SetNStructFieldType(nfttype); \
243 BOOL fAnsi = (flags & ParseNativeTypeFlag_IsAnsi);
244 #ifdef FEATURE_COMINTEROP
245 BOOL fIsWinRT = (flags & ParseNativeTypeFlag_IsWinRT);
246 #endif // FEATURE_COMINTEROP
247 CorElementType corElemType = ELEMENT_TYPE_END;
248 PCCOR_SIGNATURE pNativeTypeStart = pNativeType;
249 ULONG cbNativeTypeStart = cbNativeType;
253 BOOL ThrowOnUnmappableChar;
255 pfwalk->m_nft = NFT_NONE;
257 if (cbNativeType == 0)
259 ntype = NATIVE_TYPE_DEFAULT;
264 ntype = (CorNativeType) *( ((BYTE*&)pNativeType)++ );
266 fDefault = (ntype == NATIVE_TYPE_DEFAULT);
269 #ifdef FEATURE_COMINTEROP
270 if (fIsWinRT && !fDefault)
272 // Do not allow any MarshalAs in WinRT scenarios - marshaling is fully described by the field type.
273 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_MARSHAL_AS));
275 #endif // FEATURE_COMINTEROP
277 // Setup the signature and normalize
278 MetaSig fsig(pCOMSignature, cbCOMSignature, pModule, pTypeContext, MetaSig::sigField);
279 corElemType = fsig.NextArgNormalized();
282 if (!(*pfDisqualifyFromManagedSequential))
284 // This type may qualify for ManagedSequential. Collect managed size and alignment info.
285 if (CorTypeInfo::IsPrimitiveType(corElemType))
287 pfwalk->m_managedSize = ((UINT32)CorTypeInfo::Size(corElemType)); // Safe cast - no primitive type is larger than 4gb!
288 pfwalk->m_managedAlignmentReq = pfwalk->m_managedSize;
290 else if (corElemType == ELEMENT_TYPE_PTR)
292 pfwalk->m_managedSize = TARGET_POINTER_SIZE;
293 pfwalk->m_managedAlignmentReq = TARGET_POINTER_SIZE;
295 else if (corElemType == ELEMENT_TYPE_VALUETYPE)
297 TypeHandle pNestedType = fsig.GetLastTypeHandleThrowing(ClassLoader::LoadTypes,
298 CLASS_LOAD_APPROXPARENTS,
300 if (pNestedType.GetMethodTable()->IsManagedSequential())
302 pfwalk->m_managedSize = (pNestedType.GetMethodTable()->GetNumInstanceFieldBytes());
304 _ASSERTE(pNestedType.GetMethodTable()->HasLayout()); // If it is ManagedSequential(), it also has Layout but doesn't hurt to check before we do a cast!
305 pfwalk->m_managedAlignmentReq = pNestedType.GetMethodTable()->GetLayoutInfo()->m_ManagedLargestAlignmentRequirementOfAllMembers;
309 *pfDisqualifyFromManagedSequential = TRUE;
314 // No other type permitted for ManagedSequential.
315 *pfDisqualifyFromManagedSequential = TRUE;
320 // Normalization might have put corElementType and ntype out of sync which can
321 // result in problems with non-default ntype being validated against the
322 // normalized primitive corElemType.
324 VerifyAndAdjustNormalizedType(pModule, fsig.GetArgProps(), fsig.GetSigTypeContext(), &corElemType, &ntype);
326 fDefault = (ntype == NATIVE_TYPE_DEFAULT);
327 #endif // _TARGET_X86_
329 CorElementType sigElemType;
330 IfFailThrow(fsig.GetArgProps().PeekElemType(&sigElemType));
331 if ((sigElemType == ELEMENT_TYPE_GENERICINST || sigElemType == ELEMENT_TYPE_VAR) && corElemType == ELEMENT_TYPE_CLASS)
333 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_GENERICS_RESTRICTION));
335 else switch (corElemType)
337 case ELEMENT_TYPE_CHAR:
342 ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
343 INITFIELDMARSHALER(NFT_ANSICHAR, FieldMarshaler_Ansi, (BestFit, ThrowOnUnmappableChar));
347 INITFIELDMARSHALER(NFT_COPY2, FieldMarshaler_Copy2, ());
350 else if (ntype == NATIVE_TYPE_I1 || ntype == NATIVE_TYPE_U1)
352 ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
353 INITFIELDMARSHALER(NFT_ANSICHAR, FieldMarshaler_Ansi, (BestFit, ThrowOnUnmappableChar));
355 else if (ntype == NATIVE_TYPE_I2 || ntype == NATIVE_TYPE_U2)
357 INITFIELDMARSHALER(NFT_COPY2, FieldMarshaler_Copy2, ());
361 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_CHAR));
365 case ELEMENT_TYPE_BOOLEAN:
368 #ifdef FEATURE_COMINTEROP
371 INITFIELDMARSHALER(NFT_CBOOL, FieldMarshaler_CBool, ());
374 #endif // FEATURE_COMINTEROP
376 INITFIELDMARSHALER(NFT_WINBOOL, FieldMarshaler_WinBool, ());
379 else if (ntype == NATIVE_TYPE_BOOLEAN)
381 INITFIELDMARSHALER(NFT_WINBOOL, FieldMarshaler_WinBool, ());
383 #ifdef FEATURE_COMINTEROP
384 else if (ntype == NATIVE_TYPE_VARIANTBOOL)
386 INITFIELDMARSHALER(NFT_VARIANTBOOL, FieldMarshaler_VariantBool, ());
388 #endif // FEATURE_COMINTEROP
389 else if (ntype == NATIVE_TYPE_U1 || ntype == NATIVE_TYPE_I1)
391 INITFIELDMARSHALER(NFT_CBOOL, FieldMarshaler_CBool, ());
395 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_BOOLEAN));
400 case ELEMENT_TYPE_I1:
401 if (fDefault || ntype == NATIVE_TYPE_I1 || ntype == NATIVE_TYPE_U1)
403 INITFIELDMARSHALER(NFT_COPY1, FieldMarshaler_Copy1, ());
407 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I1));
411 case ELEMENT_TYPE_U1:
412 if (fDefault || ntype == NATIVE_TYPE_U1 || ntype == NATIVE_TYPE_I1)
414 INITFIELDMARSHALER(NFT_COPY1, FieldMarshaler_Copy1, ());
418 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I1));
422 case ELEMENT_TYPE_I2:
423 if (fDefault || ntype == NATIVE_TYPE_I2 || ntype == NATIVE_TYPE_U2)
425 INITFIELDMARSHALER(NFT_COPY2, FieldMarshaler_Copy2, ());
429 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I2));
433 case ELEMENT_TYPE_U2:
434 if (fDefault || ntype == NATIVE_TYPE_U2 || ntype == NATIVE_TYPE_I2)
436 INITFIELDMARSHALER(NFT_COPY2, FieldMarshaler_Copy2, ());
440 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I2));
444 case ELEMENT_TYPE_I4:
445 if (fDefault || ntype == NATIVE_TYPE_I4 || ntype == NATIVE_TYPE_U4 || ntype == NATIVE_TYPE_ERROR)
447 INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ());
451 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I4));
455 case ELEMENT_TYPE_U4:
456 if (fDefault || ntype == NATIVE_TYPE_U4 || ntype == NATIVE_TYPE_I4 || ntype == NATIVE_TYPE_ERROR)
458 INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ());
462 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I4));
466 case ELEMENT_TYPE_I8:
467 if (fDefault || ntype == NATIVE_TYPE_I8 || ntype == NATIVE_TYPE_U8)
469 INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ());
473 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I8));
477 case ELEMENT_TYPE_U8:
478 if (fDefault || ntype == NATIVE_TYPE_U8 || ntype == NATIVE_TYPE_I8)
480 INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ());
484 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I8));
488 case ELEMENT_TYPE_I: //fallthru
490 #ifdef FEATURE_COMINTEROP
493 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
496 #endif // FEATURE_COMINTEROP
497 if (fDefault || ntype == NATIVE_TYPE_INT || ntype == NATIVE_TYPE_UINT)
499 if (sizeof(LPVOID)==4)
501 INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ());
505 INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ());
510 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I));
514 case ELEMENT_TYPE_R4:
515 if (fDefault || ntype == NATIVE_TYPE_R4)
517 INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ());
521 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_R4));
525 case ELEMENT_TYPE_R8:
526 if (fDefault || ntype == NATIVE_TYPE_R8)
528 INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ());
532 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_R8));
536 case ELEMENT_TYPE_PTR:
537 #ifdef FEATURE_COMINTEROP
540 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
543 #endif // FEATURE_COMINTEROP
546 switch (sizeof(LPVOID))
549 INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ());
553 INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ());
557 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_BADMANAGED));
563 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_PTR));
567 case ELEMENT_TYPE_VALUETYPE:
569 // This may cause a TypeLoadException, which we currently seem to have to swallow.
570 // This happens with structs that contain fields of class type where the class itself
571 // refers to the struct in a field.
572 TypeHandle thNestedType = GetFieldTypeHandleWorker(&fsig);
573 if (!thNestedType.GetMethodTable())
575 #ifdef FEATURE_COMINTEROP
576 if (fIsWinRT && sigElemType == ELEMENT_TYPE_GENERICINST)
578 // If this is a generic value type, lets see whether it is a Nullable<T>
579 TypeHandle genType = fsig.GetLastTypeHandleThrowing();
580 if(genType != NULL && genType.GetMethodTable()->HasSameTypeDefAs(g_pNullableClass))
582 // The generic type is System.Nullable<T>.
583 // Lets extract the typeArg and check if the typeArg is valid.
584 // typeArg is invalid if
585 // 1. It is not a value type.
587 // 3. We have an open type with us.
588 Instantiation inst = genType.GetMethodTable()->GetInstantiation();
589 MethodTable* typeArgMT = inst[0].GetMethodTable();
590 if (!typeArgMT->IsLegalNonArrayWinRTType())
592 // Type is not a valid WinRT value type.
593 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_NULLABLE_RESTRICTION));
597 INITFIELDMARSHALER(NFT_WINDOWSFOUNDATIONIREFERENCE, FieldMarshaler_Nullable, (genType.GetMethodTable()));
603 if (fsig.IsClass(g_DateClassName))
605 if (fDefault || ntype == NATIVE_TYPE_STRUCT)
607 INITFIELDMARSHALER(NFT_DATE, FieldMarshaler_Date, ());
611 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_DATETIME));
614 else if (fsig.IsClass(g_DecimalClassName))
616 if (fDefault || ntype == NATIVE_TYPE_STRUCT)
618 INITFIELDMARSHALER(NFT_DECIMAL, FieldMarshaler_Decimal, ());
620 #ifdef FEATURE_COMINTEROP
621 else if (ntype == NATIVE_TYPE_CURRENCY)
623 INITFIELDMARSHALER(NFT_CURRENCY, FieldMarshaler_Currency, ());
625 #endif // FEATURE_COMINTEROP
628 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_DECIMAL));
631 #ifdef FEATURE_COMINTEROP
632 else if (fsig.IsClass(g_DateTimeOffsetClassName))
634 if (fDefault || ntype == NATIVE_TYPE_STRUCT)
636 INITFIELDMARSHALER(NFT_DATETIMEOFFSET, FieldMarshaler_DateTimeOffset, ());
640 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_DATETIMEOFFSET));
643 else if (fIsWinRT && !thNestedType.GetMethodTable()->IsLegalNonArrayWinRTType())
645 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
647 #endif // FEATURE_COMINTEROP
648 else if (thNestedType.GetMethodTable()->HasLayout())
650 if (fDefault || ntype == NATIVE_TYPE_STRUCT)
652 if (IsStructMarshalable(thNestedType))
654 INITFIELDMARSHALER(NFT_NESTEDVALUECLASS, FieldMarshaler_NestedValueClass, (thNestedType.GetMethodTable()));
658 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_NOTMARSHALABLE));
663 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_VALUETYPE));
668 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_NOTMARSHALABLE));
673 case ELEMENT_TYPE_CLASS:
675 // This may cause a TypeLoadException, which we currently seem to have to swallow.
676 // This happens with structs that contain fields of class type where the class itself
677 // refers to the struct in a field.
678 TypeHandle thNestedType = GetFieldTypeHandleWorker(&fsig);
679 if (!thNestedType.GetMethodTable())
682 if (thNestedType.GetMethodTable()->IsObjectClass())
684 #ifdef FEATURE_COMINTEROP
685 if (fDefault || ntype == NATIVE_TYPE_IUNKNOWN || ntype == NATIVE_TYPE_IDISPATCH || ntype == NATIVE_TYPE_INTF)
687 // Only NATIVE_TYPE_IDISPATCH maps to an IDispatch based interface pointer.
688 DWORD dwFlags = ItfMarshalInfo::ITF_MARSHAL_USE_BASIC_ITF;
689 if (ntype == NATIVE_TYPE_IDISPATCH)
691 dwFlags |= ItfMarshalInfo::ITF_MARSHAL_DISP_ITF;
693 INITFIELDMARSHALER(NFT_INTERFACE, FieldMarshaler_Interface, (NULL, NULL, dwFlags));
695 else if (ntype == NATIVE_TYPE_STRUCT)
697 INITFIELDMARSHALER(NFT_VARIANT, FieldMarshaler_Variant, ());
699 #else // FEATURE_COMINTEROP
700 if (fDefault || ntype == NATIVE_TYPE_IUNKNOWN || ntype == NATIVE_TYPE_IDISPATCH || ntype == NATIVE_TYPE_INTF)
702 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_OBJECT_TO_ITF_NOT_SUPPORTED));
704 else if (ntype == NATIVE_TYPE_STRUCT)
706 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_OBJECT_TO_VARIANT_NOT_SUPPORTED));
708 #endif // FEATURE_COMINTEROP
711 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_OBJECT));
714 #ifdef FEATURE_COMINTEROP
715 else if (ntype == NATIVE_TYPE_INTF || thNestedType.IsInterface())
717 if (fIsWinRT && !thNestedType.GetMethodTable()->IsLegalNonArrayWinRTType())
719 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
723 ItfMarshalInfo itfInfo;
724 if (FAILED(MarshalInfo::TryGetItfMarshalInfo(thNestedType, FALSE, FALSE, &itfInfo)))
727 INITFIELDMARSHALER(NFT_INTERFACE, FieldMarshaler_Interface, (itfInfo.thClass.GetMethodTable(), itfInfo.thItf.GetMethodTable(), itfInfo.dwFlags));
730 #else // FEATURE_COMINTEROP
731 else if (ntype == NATIVE_TYPE_INTF || thNestedType.IsInterface())
733 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_OBJECT_TO_ITF_NOT_SUPPORTED));
735 #endif // FEATURE_COMINTEROP
736 else if (ntype == NATIVE_TYPE_CUSTOMMARSHALER)
738 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_NOCUSTOMMARSH));
740 else if (thNestedType == TypeHandle(g_pStringClass))
744 #ifdef FEATURE_COMINTEROP
747 INITFIELDMARSHALER(NFT_HSTRING, FieldMarshaler_HSTRING, ());
750 #endif // FEATURE_COMINTEROP
753 ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
754 INITFIELDMARSHALER(NFT_STRINGANSI, FieldMarshaler_StringAnsi, (BestFit, ThrowOnUnmappableChar));
758 INITFIELDMARSHALER(NFT_STRINGUNI, FieldMarshaler_StringUni, ());
765 case NATIVE_TYPE_LPSTR:
766 ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
767 INITFIELDMARSHALER(NFT_STRINGANSI, FieldMarshaler_StringAnsi, (BestFit, ThrowOnUnmappableChar));
770 case NATIVE_TYPE_LPWSTR:
771 INITFIELDMARSHALER(NFT_STRINGUNI, FieldMarshaler_StringUni, ());
774 case NATIVE_TYPE_LPUTF8STR:
775 INITFIELDMARSHALER(NFT_STRINGUTF8, FieldMarshaler_StringUtf8, ());
778 case NATIVE_TYPE_LPTSTR:
779 // We no longer support Win9x so LPTSTR always maps to a Unicode string.
780 INITFIELDMARSHALER(NFT_STRINGUNI, FieldMarshaler_StringUni, ());
782 #ifdef FEATURE_COMINTEROP
783 case NATIVE_TYPE_BSTR:
784 INITFIELDMARSHALER(NFT_BSTR, FieldMarshaler_BSTR, ());
787 case NATIVE_TYPE_HSTRING:
788 INITFIELDMARSHALER(NFT_HSTRING, FieldMarshaler_HSTRING, ());
790 #endif // FEATURE_COMINTEROP
791 case NATIVE_TYPE_FIXEDSYSSTRING:
794 ULONG udatasize = CorSigUncompressedDataSize(pNativeType);
796 if (cbNativeType < udatasize)
799 nchars = CorSigUncompressData(pNativeType);
800 cbNativeType -= udatasize;
804 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_ZEROLENGTHFIXEDSTRING));
810 ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
811 INITFIELDMARSHALER(NFT_FIXEDSTRINGANSI, FieldMarshaler_FixedStringAnsi, (nchars, BestFit, ThrowOnUnmappableChar));
815 INITFIELDMARSHALER(NFT_FIXEDSTRINGUNI, FieldMarshaler_FixedStringUni, (nchars));
821 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_STRING));
826 #ifdef FEATURE_COMINTEROP
827 else if (fIsWinRT && fsig.IsClass(g_TypeClassName))
828 { // Note: If the System.Type field is in non-WinRT struct, do not change the previously shipped behavior
829 INITFIELDMARSHALER(NFT_SYSTEMTYPE, FieldMarshaler_SystemType, ());
831 else if (fIsWinRT && fsig.IsClass(g_ExceptionClassName)) // Marshal Windows.Foundation.HResult as System.Exception for WinRT.
833 INITFIELDMARSHALER(NFT_WINDOWSFOUNDATIONHRESULT, FieldMarshaler_Exception, ());
835 #endif //FEATURE_COMINTEROP
836 #ifdef FEATURE_CLASSIC_COMINTEROP
837 else if (thNestedType.GetMethodTable() == g_pArrayClass)
839 if (ntype == NATIVE_TYPE_SAFEARRAY)
841 NativeTypeParamInfo ParamInfo;
842 CorElementType etyp = ELEMENT_TYPE_OBJECT;
843 MethodTable* pMT = NULL;
844 VARTYPE vtElement = VT_EMPTY;
846 // Compat: If no safe array used def subtype was specified, we assume TypeOf(Object).
847 TypeHandle thElement = TypeHandle(g_pObjectClass);
849 // If we have no native type data, assume default behavior
850 if (S_OK != CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
852 INITFIELDMARSHALER(NFT_SAFEARRAY, FieldMarshaler_SafeArray, (VT_EMPTY, NULL));
856 vtElement = (VARTYPE) (CorSigUncompressData(/*modifies*/pNativeType));
858 // Extract the name of the record type's.
859 if (S_OK == CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
862 if (FAILED(CPackedLen::SafeGetData(pNativeType, pNativeTypeStart + cbNativeTypeStart, &strLen, &pNativeType)))
864 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_BADMETADATA));
869 // Load the type. Use a SString for the string since we need to NULL terminate the string
870 // that comes from the metadata.
871 StackSString safeArrayUserDefTypeName(SString::Utf8, (LPCUTF8)pNativeType, strLen);
872 _ASSERTE((ULONG)(pNativeType + strLen - pNativeTypeStart) == cbNativeTypeStart);
874 // Sadly this may cause a TypeLoadException, which we currently have to swallow.
875 // This happens with structs that contain fields of class type where the class itself
876 // refers to the struct in a field.
877 thElement = ArraySubTypeLoadWorker(safeArrayUserDefTypeName, pModule->GetAssembly());
878 if (thElement.IsNull())
883 ArrayMarshalInfo arrayMarshalInfo(amiRuntime);
884 arrayMarshalInfo.InitForSafeArray(MarshalInfo::MARSHAL_SCENARIO_FIELD, thElement, vtElement, fAnsi);
886 if (!arrayMarshalInfo.IsValid())
888 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (arrayMarshalInfo.GetErrorResourceId()));
892 INITFIELDMARSHALER(NFT_SAFEARRAY, FieldMarshaler_SafeArray, (arrayMarshalInfo.GetElementVT(), arrayMarshalInfo.GetElementTypeHandle().GetMethodTable()));
894 else if (ntype == NATIVE_TYPE_FIXEDARRAY)
896 // Check for the number of elements. This is required, if not present fail.
897 if (S_OK != CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
899 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_FIXEDARRAY_NOSIZE));
903 ULONG numElements = CorSigUncompressData(/*modifies*/pNativeType);
905 if (numElements == 0)
907 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_FIXEDARRAY_ZEROSIZE));
911 // Since these always export to arrays of BSTRs, we don't need to fetch the native type.
913 // Compat: FixedArrays of System.Arrays map to fixed arrays of BSTRs.
914 INITFIELDMARSHALER(NFT_FIXEDARRAY, FieldMarshaler_FixedArray, (pInternalImport, cl, numElements, VT_BSTR, g_pStringClass));
917 #endif // FEATURE_CLASSIC_COMINTEROP
918 else if (COMDelegate::IsDelegate(thNestedType.GetMethodTable()))
920 if (fDefault || ntype == NATIVE_TYPE_FUNC)
922 INITFIELDMARSHALER(NFT_DELEGATE, FieldMarshaler_Delegate, (thNestedType.GetMethodTable()));
926 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_DELEGATE));
929 else if (thNestedType.CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__SAFE_HANDLE))))
933 INITFIELDMARSHALER(NFT_SAFEHANDLE, FieldMarshaler_SafeHandle, ());
937 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_SAFEHANDLE));
940 else if (thNestedType.CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__CRITICAL_HANDLE))))
944 INITFIELDMARSHALER(NFT_CRITICALHANDLE, FieldMarshaler_CriticalHandle, ());
948 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_CRITICALHANDLE));
951 else if (fsig.IsClass(g_StringBufferClassName))
953 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_NOSTRINGBUILDER));
955 else if (IsStructMarshalable(thNestedType))
957 if (fDefault || ntype == NATIVE_TYPE_STRUCT)
959 INITFIELDMARSHALER(NFT_NESTEDLAYOUTCLASS, FieldMarshaler_NestedLayoutClass, (thNestedType.GetMethodTable()));
963 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_LAYOUTCLASS));
966 #ifdef FEATURE_COMINTEROP
969 // no other reference types are allowed as field types in WinRT
970 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
974 ItfMarshalInfo itfInfo;
975 if (FAILED(MarshalInfo::TryGetItfMarshalInfo(thNestedType, FALSE, FALSE, &itfInfo)))
977 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_BADMANAGED));
981 INITFIELDMARSHALER(NFT_INTERFACE, FieldMarshaler_Interface, (itfInfo.thClass.GetMethodTable(), itfInfo.thItf.GetMethodTable(), itfInfo.dwFlags));
984 #endif // FEATURE_COMINTEROP
988 case ELEMENT_TYPE_SZARRAY:
989 case ELEMENT_TYPE_ARRAY:
991 #ifdef FEATURE_COMINTEROP
994 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
997 #endif // FEATURE_COMINTEROP
999 // This may cause a TypeLoadException, which we currently seem to have to swallow.
1000 // This happens with structs that contain fields of class type where the class itself
1001 // refers to the struct in a field.
1002 TypeHandle thArray = GetFieldTypeHandleWorker(&fsig);
1003 if (thArray.IsNull() || !thArray.IsArray())
1006 TypeHandle thElement = thArray.AsArray()->GetArrayElementTypeHandle();
1007 if (thElement.IsNull())
1010 if (ntype == NATIVE_TYPE_FIXEDARRAY)
1012 CorNativeType elementNativeType = NATIVE_TYPE_DEFAULT;
1014 // The size constant must be specified, if it isn't then the struct can't be marshalled.
1015 if (S_OK != CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
1017 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_FIXEDARRAY_NOSIZE));
1021 // Read the size const, if it's 0, then the struct can't be marshalled.
1022 ULONG numElements = CorSigUncompressData(pNativeType);
1023 if (numElements == 0)
1025 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_FIXEDARRAY_ZEROSIZE));
1029 // The array sub type is optional so extract it if specified.
1030 if (S_OK == CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
1031 elementNativeType = (CorNativeType)CorSigUncompressData(pNativeType);
1033 ArrayMarshalInfo arrayMarshalInfo(amiRuntime);
1034 arrayMarshalInfo.InitForFixedArray(thElement, elementNativeType, fAnsi);
1036 if (!arrayMarshalInfo.IsValid())
1038 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (arrayMarshalInfo.GetErrorResourceId()));
1042 if (arrayMarshalInfo.GetElementVT() == VTHACK_ANSICHAR)
1044 // We need to special case fixed sized arrays of ANSI chars since the OleVariant code
1045 // that is used by the generic fixed size array marshaller doesn't support them
1047 ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
1048 INITFIELDMARSHALER(NFT_FIXEDCHARARRAYANSI, FieldMarshaler_FixedCharArrayAnsi, (numElements, BestFit, ThrowOnUnmappableChar));
1053 VARTYPE elementVT = arrayMarshalInfo.GetElementVT();
1055 INITFIELDMARSHALER(NFT_FIXEDARRAY, FieldMarshaler_FixedArray, (pInternalImport, cl, numElements, elementVT, arrayMarshalInfo.GetElementTypeHandle().GetMethodTable()));
1059 #ifdef FEATURE_CLASSIC_COMINTEROP
1060 else if (fDefault || ntype == NATIVE_TYPE_SAFEARRAY)
1062 VARTYPE vtElement = VT_EMPTY;
1064 // Check for data remaining in the signature before we attempt to grab some.
1065 if (S_OK == CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
1066 vtElement = (VARTYPE) (CorSigUncompressData(/*modifies*/pNativeType));
1068 ArrayMarshalInfo arrayMarshalInfo(amiRuntime);
1069 arrayMarshalInfo.InitForSafeArray(MarshalInfo::MARSHAL_SCENARIO_FIELD, thElement, vtElement, fAnsi);
1071 if (!arrayMarshalInfo.IsValid())
1073 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (arrayMarshalInfo.GetErrorResourceId()));
1077 INITFIELDMARSHALER(NFT_SAFEARRAY, FieldMarshaler_SafeArray, (arrayMarshalInfo.GetElementVT(), arrayMarshalInfo.GetElementTypeHandle().GetMethodTable()));
1079 #endif //FEATURE_CLASSIC_COMINTEROP
1082 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_ARRAY));
1087 case ELEMENT_TYPE_OBJECT:
1088 case ELEMENT_TYPE_STRING:
1092 // let it fall thru as NFT_NONE
1096 if (pfwalk->m_nft == NFT_NONE)
1098 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_BADMANAGED));
1100 #ifdef FEATURE_COMINTEROP
1101 else if (fIsWinRT && !NFTDataBase[pfwalk->m_nft].m_fWinRTSupported)
1103 // the field marshaler we came up with is not supported in WinRT scenarios
1104 ZeroMemory(&pfwalk->m_FieldMarshaler, MAXFIELDMARSHALERSIZE);
1105 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
1107 #endif // FEATURE_COMINTEROP
1108 #undef INITFIELDMARSHALER
1111 #pragma warning(pop)
1115 TypeHandle ArraySubTypeLoadWorker(const SString &strUserDefTypeName, Assembly* pAssembly)
1122 PRECONDITION(CheckPointer(pAssembly));
1130 // Load the user defined type.
1131 StackScratchBuffer utf8Name;
1132 th = TypeName::GetTypeUsingCASearchRules(strUserDefTypeName.GetUTF8(utf8Name), pAssembly);
1137 EX_END_CATCH(RethrowTerminalExceptions)
1143 TypeHandle GetFieldTypeHandleWorker(MetaSig *pFieldSig)
1150 PRECONDITION(CheckPointer(pFieldSig));
1158 // Load the user defined type.
1159 th = pFieldSig->GetLastTypeHandleThrowing(ClassLoader::LoadTypes,
1160 CLASS_LOAD_APPROXPARENTS,
1161 TRUE /*dropGenericArgumentLevel*/);
1166 EX_END_CATCH(RethrowTerminalExceptions)
1172 //=======================================================================
1173 // This function returns TRUE if the type passed in is either a value class or a class and if it has layout information
1174 // and is marshalable. In all other cases it will return FALSE.
1175 //=======================================================================
1176 BOOL IsStructMarshalable(TypeHandle th)
1184 PRECONDITION(!th.IsNull());
1188 if (th.IsBlittable())
1190 // th.IsBlittable will return true for arrays of blittable types, however since IsStructMarshalable
1191 // is only supposed to return true for value classes or classes with layout that are marshallable
1192 // we need to return false if the type is an array.
1199 // Check to see if the type has layout.
1200 if (!th.HasLayout())
1203 MethodTable *pMT= th.GetMethodTable();
1204 PREFIX_ASSUME(pMT != NULL);
1206 if (pMT->IsStructMarshalable())
1209 const FieldMarshaler *pFieldMarshaler = pMT->GetLayoutInfo()->GetFieldMarshalers();
1210 UINT numReferenceFields = pMT->GetLayoutInfo()->GetNumCTMFields();
1212 while (numReferenceFields--)
1214 if (pFieldMarshaler->GetNStructFieldType() == NFT_ILLEGAL)
1217 ((BYTE*&)pFieldMarshaler) += MAXFIELDMARSHALERSIZE;
1224 //=======================================================================
1225 // Called from the clsloader to load up and summarize the field metadata
1226 // for layout classes.
1228 // Warning: This function can load other classes (esp. for nested structs.)
1229 //=======================================================================
1231 #pragma warning(push)
1232 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
1234 VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing(
1235 mdTypeDef cl, // cl of the NStruct being loaded
1236 BYTE packingSize, // packing size (from @dll.struct)
1237 BYTE nlType, // nltype (from @dll.struct)
1238 #ifdef FEATURE_COMINTEROP
1239 BOOL isWinRT, // Is the type a WinRT type
1240 #endif // FEATURE_COMINTEROP
1241 BOOL fExplicitOffsets, // explicit offsets?
1242 MethodTable *pParentMT, // the loaded superclass
1243 ULONG cMembers, // total number of members (methods + fields)
1244 HENUMInternal *phEnumField, // enumerator for field
1245 Module *pModule, // Module that defines the scope, loader and heap (for allocate FieldMarshalers)
1246 const SigTypeContext *pTypeContext, // Type parameters for NStruct being loaded
1247 EEClassLayoutInfo *pEEClassLayoutInfoOut, // caller-allocated structure to fill in.
1248 LayoutRawFieldInfo *pInfoArrayOut, // caller-allocated array to fill in. Needs room for cMember+1 elements
1249 LoaderAllocator *pAllocator,
1250 AllocMemTracker *pamTracker
1258 INJECT_FAULT(COMPlusThrowOM());
1259 PRECONDITION(CheckPointer(pModule));
1264 MD_CLASS_LAYOUT classlayout;
1269 // Running tote - if anything in this type disqualifies it from being ManagedSequential, somebody will set this to TRUE by the the time
1271 BOOL fDisqualifyFromManagedSequential = FALSE;
1273 // Internal interface for the NStruct being loaded.
1274 IMDInternalImport *pInternalImport = pModule->GetMDImport();
1279 LPCUTF8 szNamespace;
1280 if (FAILED(pInternalImport->GetNameOfTypeDef(cl, &szName, &szNamespace)))
1282 szName = szNamespace = "Invalid TypeDef record";
1285 if (g_pConfig->ShouldBreakOnStructMarshalSetup(szName))
1286 CONSISTENCY_CHECK_MSGF(false, ("BreakOnStructMarshalSetup: '%s' ", szName));
1290 // Check if this type might be ManagedSequential. Only valuetypes marked Sequential can be
1291 // ManagedSequential. Other issues checked below might also disqualify the type.
1292 if ( (!fExplicitOffsets) && // Is it marked sequential?
1293 (pParentMT && (pParentMT->IsValueTypeClass() || pParentMT->IsManagedSequential())) // Is it a valuetype or derived from a qualifying valuetype?
1296 // Type qualifies so far... need do nothing.
1300 fDisqualifyFromManagedSequential = TRUE;
1304 BOOL fHasNonTrivialParent = pParentMT &&
1305 !pParentMT->IsObjectClass() &&
1306 !pParentMT->IsValueTypeClass();
1309 //====================================================================
1310 // First, some validation checks.
1311 //====================================================================
1312 _ASSERTE(!(fHasNonTrivialParent && !(pParentMT->HasLayout())));
1314 hr = pInternalImport->GetClassLayoutInit(cl, &classlayout);
1317 COMPlusThrowHR(hr, BFA_CANT_GET_CLASSLAYOUT);
1320 pEEClassLayoutInfoOut->m_numCTMFields = fHasNonTrivialParent ? pParentMT->GetLayoutInfo()->m_numCTMFields : 0;
1321 pEEClassLayoutInfoOut->SetFieldMarshalers(NULL);
1322 pEEClassLayoutInfoOut->SetIsBlittable(TRUE);
1323 if (fHasNonTrivialParent)
1324 pEEClassLayoutInfoOut->SetIsBlittable(pParentMT->IsBlittable());
1325 pEEClassLayoutInfoOut->SetIsZeroSized(FALSE);
1326 pEEClassLayoutInfoOut->SetHasExplicitSize(FALSE);
1327 pEEClassLayoutInfoOut->m_cbPackingSize = packingSize;
1329 LayoutRawFieldInfo *pfwalk = pInfoArrayOut;
1331 S_UINT32 cbSortArraySize = S_UINT32(cMembers) * S_UINT32(sizeof(LayoutRawFieldInfo *));
1332 if (cbSortArraySize.IsOverflow())
1334 ThrowHR(COR_E_TYPELOAD);
1336 LayoutRawFieldInfo **pSortArray = (LayoutRawFieldInfo **)_alloca(cbSortArraySize.Value());
1337 LayoutRawFieldInfo **pSortArrayEnd = pSortArray;
1339 ULONG maxRid = pInternalImport->GetCountWithTokenKind(mdtFieldDef);
1342 //=====================================================================
1343 // Phase 1: Figure out the NFT of each field based on both the CLR
1344 // signature of the field and the FieldMarshaler metadata.
1345 //=====================================================================
1346 BOOL fParentHasLayout = pParentMT && pParentMT->HasLayout();
1347 UINT32 cbAdjustedParentLayoutNativeSize = 0;
1348 EEClassLayoutInfo *pParentLayoutInfo = NULL;;
1349 if (fParentHasLayout)
1351 pParentLayoutInfo = pParentMT->GetLayoutInfo();
1352 // Treat base class as an initial member.
1353 cbAdjustedParentLayoutNativeSize = pParentLayoutInfo->GetNativeSize();
1354 // If the parent was originally a zero-sized explicit type but
1355 // got bumped up to a size of 1 for compatibility reasons, then
1356 // we need to remove the padding, but ONLY for inheritance situations.
1357 if (pParentLayoutInfo->IsZeroSized()) {
1358 CONSISTENCY_CHECK(cbAdjustedParentLayoutNativeSize == 1);
1359 cbAdjustedParentLayoutNativeSize = 0;
1364 for (i = 0; pInternalImport->EnumNext(phEnumField, &fd); i++)
1367 ULONG rid = RidFromToken(fd);
1369 if((rid == 0)||(rid > maxRid))
1371 COMPlusThrowHR(COR_E_TYPELOAD, BFA_BAD_FIELD_TOKEN);
1374 IfFailThrow(pInternalImport->GetFieldDefProps(fd, &dwFieldAttrs));
1376 PCCOR_SIGNATURE pNativeType = NULL;
1378 // We ignore marshaling data attached to statics and literals,
1379 // since these do not contribute to instance data.
1380 if (!IsFdStatic(dwFieldAttrs) && !IsFdLiteral(dwFieldAttrs))
1382 PCCOR_SIGNATURE pCOMSignature;
1383 ULONG cbCOMSignature;
1385 if (IsFdHasFieldMarshal(dwFieldAttrs))
1387 hr = pInternalImport->GetFieldMarshal(fd, &pNativeType, &cbNativeType);
1394 IfFailThrow(pInternalImport->GetSigOfFieldDef(fd,&cbCOMSignature, &pCOMSignature));
1396 IfFailThrow(::validateTokenSig(fd,pCOMSignature,cbCOMSignature,dwFieldAttrs,pInternalImport));
1398 // fill the appropriate entry in pInfoArrayOut
1400 pfwalk->m_nft = NULL;
1401 pfwalk->m_offset = (UINT32) -1;
1402 pfwalk->m_sequence = 0;
1405 LPCUTF8 szFieldName;
1406 if (FAILED(pInternalImport->GetNameOfFieldDef(fd, &szFieldName)))
1408 szFieldName = "Invalid FieldDef record";
1412 ParseNativeTypeFlags flags = ParseNativeTypeFlag_None;
1413 #ifdef FEATURE_COMINTEROP
1415 flags |= ParseNativeTypeFlag_IsWinRT;
1416 else // WinRT types have nlType == nltAnsi but should be treated as Unicode
1417 #endif // FEATURE_COMINTEROP
1418 if (nlType == nltAnsi)
1419 flags |= ParseNativeTypeFlag_IsAnsi;
1421 ParseNativeType(pModule,
1431 &fDisqualifyFromManagedSequential
1441 //<TODO>@nice: This is obviously not the place to bury this logic.
1442 // We're replacing NFT's with MARSHAL_TYPES_* in the near future
1443 // so this isn't worth perfecting.</TODO>
1445 BOOL resetBlittable = TRUE;
1447 // if it's a simple copy...
1448 if (pfwalk->m_nft == NFT_COPY1 ||
1449 pfwalk->m_nft == NFT_COPY2 ||
1450 pfwalk->m_nft == NFT_COPY4 ||
1451 pfwalk->m_nft == NFT_COPY8)
1453 resetBlittable = FALSE;
1456 // Or if it's a nested value class that is itself blittable...
1457 if (pfwalk->m_nft == NFT_NESTEDVALUECLASS)
1459 FieldMarshaler *pFM = (FieldMarshaler*)&(pfwalk->m_FieldMarshaler);
1460 _ASSERTE(pFM->IsNestedValueClassMarshaler());
1462 if (((FieldMarshaler_NestedValueClass *) pFM)->IsBlittable())
1463 resetBlittable = FALSE;
1466 // ...Otherwise, this field prevents blitting
1468 pEEClassLayoutInfoOut->SetIsBlittable(FALSE);
1475 _ASSERTE(i == cMembers);
1477 // NULL out the last entry
1478 pfwalk->m_MD = mdFieldDefNil;
1482 // fill in the layout information
1485 // pfwalk points to the beginging of the array
1486 pfwalk = pInfoArrayOut;
1488 while (SUCCEEDED(hr = pInternalImport->GetClassLayoutNext(
1492 fd != mdFieldDefNil)
1494 // watch for the last entry: must be mdFieldDefNil
1495 while ((mdFieldDefNil != pfwalk->m_MD)&&(pfwalk->m_MD < fd))
1498 // if we haven't found a matching token, it must be a static field with layout -- ignore it
1499 if(pfwalk->m_MD != fd) continue;
1501 if (!fExplicitOffsets)
1503 // ulOffset is the sequence
1504 pfwalk->m_sequence = ulOffset;
1508 // ulOffset is the explicit offset
1509 pfwalk->m_offset = ulOffset;
1510 pfwalk->m_sequence = (ULONG) -1;
1512 // Treat base class as an initial member.
1513 if (!SafeAddUINT32(&(pfwalk->m_offset), cbAdjustedParentLayoutNativeSize))
1519 // now sort the array
1520 if (!fExplicitOffsets)
1522 // sort sequential by ascending sequence
1523 for (i = 0; i < cFields; i++)
1525 LayoutRawFieldInfo**pSortWalk = pSortArrayEnd;
1526 while (pSortWalk != pSortArray)
1528 if (pInfoArrayOut[i].m_sequence >= (*(pSortWalk-1))->m_sequence)
1534 // pSortWalk now points to the target location for new FieldInfo.
1535 MoveMemory(pSortWalk + 1, pSortWalk, (pSortArrayEnd - pSortWalk) * sizeof(LayoutRawFieldInfo*));
1536 *pSortWalk = &pInfoArrayOut[i];
1540 else // no sorting for explicit layout
1542 for (i = 0; i < cFields; i++)
1544 if(pInfoArrayOut[i].m_MD != mdFieldDefNil)
1546 if (pInfoArrayOut[i].m_offset == (UINT32)-1)
1548 LPCUTF8 szFieldName;
1549 if (FAILED(pInternalImport->GetNameOfFieldDef(pInfoArrayOut[i].m_MD, &szFieldName)))
1551 szFieldName = "Invalid FieldDef record";
1553 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport,
1556 IDS_CLASSLOAD_NSTRUCT_EXPLICIT_OFFSET);
1558 else if ((INT)pInfoArrayOut[i].m_offset < 0)
1560 LPCUTF8 szFieldName;
1561 if (FAILED(pInternalImport->GetNameOfFieldDef(pInfoArrayOut[i].m_MD, &szFieldName)))
1563 szFieldName = "Invalid FieldDef record";
1565 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport,
1568 IDS_CLASSLOAD_NSTRUCT_NEGATIVE_OFFSET);
1572 *pSortArrayEnd = &pInfoArrayOut[i];
1577 //=====================================================================
1578 // Phase 2: Compute the native size (in bytes) of each field.
1579 // Store this in pInfoArrayOut[].cbNativeSize;
1580 //=====================================================================
1582 // Now compute the native size of each field
1583 for (pfwalk = pInfoArrayOut; pfwalk->m_MD != mdFieldDefNil; pfwalk++)
1585 UINT8 nft = pfwalk->m_nft;
1586 pEEClassLayoutInfoOut->m_numCTMFields++;
1588 // If the NFT's size never changes, it is stored in the database.
1589 UINT32 cbNativeSize = NFTDataBase[nft].m_cbNativeSize;
1591 if (cbNativeSize == 0)
1593 // Size of 0 means NFT's size is variable, so we have to figure it
1594 // out case by case.
1595 cbNativeSize = ((FieldMarshaler*)&(pfwalk->m_FieldMarshaler))->NativeSize();
1597 pfwalk->m_cbNativeSize = cbNativeSize;
1600 if (pEEClassLayoutInfoOut->m_numCTMFields)
1602 pEEClassLayoutInfoOut->SetFieldMarshalers((FieldMarshaler*)(pamTracker->Track(pAllocator->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(MAXFIELDMARSHALERSIZE) * S_SIZE_T(pEEClassLayoutInfoOut->m_numCTMFields)))));
1604 // Bring in the parent's fieldmarshalers
1605 if (fHasNonTrivialParent)
1607 CONSISTENCY_CHECK(fParentHasLayout);
1608 PREFAST_ASSUME(pParentLayoutInfo != NULL); // See if (fParentHasLayout) branch above
1610 UINT numChildCTMFields = pEEClassLayoutInfoOut->m_numCTMFields - pParentLayoutInfo->m_numCTMFields;
1612 BYTE *pParentCTMFieldSrcArray = (BYTE*)pParentLayoutInfo->GetFieldMarshalers();
1613 BYTE *pParentCTMFieldDestArray = ((BYTE*)pEEClassLayoutInfoOut->GetFieldMarshalers()) + MAXFIELDMARSHALERSIZE*numChildCTMFields;
1615 for (UINT parentCTMFieldIndex = 0; parentCTMFieldIndex < pParentLayoutInfo->m_numCTMFields; parentCTMFieldIndex++)
1617 FieldMarshaler *pParentCTMFieldSrc = (FieldMarshaler *)(pParentCTMFieldSrcArray + MAXFIELDMARSHALERSIZE*parentCTMFieldIndex);
1618 FieldMarshaler *pParentCTMFieldDest = (FieldMarshaler *)(pParentCTMFieldDestArray + MAXFIELDMARSHALERSIZE*parentCTMFieldIndex);
1620 pParentCTMFieldSrc->CopyTo(pParentCTMFieldDest, MAXFIELDMARSHALERSIZE);
1627 //=====================================================================
1628 // Phase 3: If FieldMarshaler requires autooffsetting, compute the offset
1629 // of each field and the size of the total structure. We do the layout
1630 // according to standard VC layout rules:
1632 // Each field has an alignment requirement. The alignment-requirement
1633 // of a scalar field is the smaller of its size and the declared packsize.
1634 // The alighnment-requirement of a struct field is the smaller of the
1635 // declared packsize and the largest of the alignment-requirement
1636 // of its fields. The alignment requirement of an array is that
1637 // of one of its elements.
1639 // In addition, each struct gets padding at the end to ensure
1640 // that an array of such structs contain no unused space between
1642 //=====================================================================
1644 BYTE LargestAlignmentRequirement = 1;
1645 UINT32 cbCurOffset = 0;
1647 // Treat base class as an initial member.
1648 if (!SafeAddUINT32(&cbCurOffset, cbAdjustedParentLayoutNativeSize))
1651 if (fParentHasLayout)
1653 BYTE alignmentRequirement;
1655 alignmentRequirement = min(packingSize, pParentLayoutInfo->GetLargestAlignmentRequirementOfAllMembers());
1657 LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);
1660 // Start with the size inherited from the parent (if any).
1661 unsigned calcTotalSize = cbAdjustedParentLayoutNativeSize;
1663 LayoutRawFieldInfo **pSortWalk;
1664 for (pSortWalk = pSortArray, i=cFields; i; i--, pSortWalk++)
1666 pfwalk = *pSortWalk;
1668 BYTE alignmentRequirement = static_cast<BYTE>(((FieldMarshaler*)&(pfwalk->m_FieldMarshaler))->AlignmentRequirement());
1669 if (!(alignmentRequirement == 1 ||
1670 alignmentRequirement == 2 ||
1671 alignmentRequirement == 4 ||
1672 alignmentRequirement == 8 ||
1673 alignmentRequirement == 16 ||
1674 alignmentRequirement == 32))
1676 COMPlusThrowHR(COR_E_INVALIDPROGRAM, BFA_METADATA_CORRUPT);
1679 alignmentRequirement = min(alignmentRequirement, packingSize);
1681 LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);
1683 // This assert means I forgot to special-case some NFT in the
1685 _ASSERTE(alignmentRequirement <= 32);
1687 // Check if this field is overlapped with other(s)
1688 pfwalk->m_fIsOverlapped = FALSE;
1689 if (fExplicitOffsets) {
1690 LayoutRawFieldInfo *pfwalk1;
1691 DWORD dwBegin = pfwalk->m_offset;
1692 DWORD dwEnd = dwBegin+pfwalk->m_cbNativeSize;
1693 for (pfwalk1 = pInfoArrayOut; pfwalk1 < pfwalk; pfwalk1++)
1695 if((pfwalk1->m_offset >= dwEnd) || (pfwalk1->m_offset+pfwalk1->m_cbNativeSize <= dwBegin)) continue;
1696 pfwalk->m_fIsOverlapped = TRUE;
1697 pfwalk1->m_fIsOverlapped = TRUE;
1702 // Insert enough padding to align the current data member.
1703 while (cbCurOffset % alignmentRequirement)
1705 if (!SafeAddUINT32(&cbCurOffset, 1))
1709 // Insert current data member.
1710 pfwalk->m_offset = cbCurOffset;
1712 // if we overflow we will catch it below
1713 cbCurOffset += pfwalk->m_cbNativeSize;
1716 unsigned fieldEnd = pfwalk->m_offset + pfwalk->m_cbNativeSize;
1717 if (fieldEnd < pfwalk->m_offset)
1720 // size of the structure is the size of the last field.
1721 if (fieldEnd > calcTotalSize)
1722 calcTotalSize = fieldEnd;
1725 ULONG clstotalsize = 0;
1726 if (FAILED(pInternalImport->GetClassTotalSize(cl, &clstotalsize)))
1731 if (clstotalsize != 0)
1733 if (!SafeAddULONG(&clstotalsize, (ULONG)cbAdjustedParentLayoutNativeSize))
1736 // size must be large enough to accomodate layout. If not, we use the layout size instead.
1737 if (clstotalsize < calcTotalSize)
1739 clstotalsize = calcTotalSize;
1741 calcTotalSize = clstotalsize; // use the size they told us
1745 // The did not give us an explict size, so lets round up to a good size (for arrays)
1746 while (calcTotalSize % LargestAlignmentRequirement != 0)
1748 if (!SafeAddUINT32(&calcTotalSize, 1))
1753 // We'll cap the total native size at a (somewhat) arbitrary limit to ensure
1754 // that we don't expose some overflow bug later on.
1755 if (calcTotalSize >= MAX_SIZE_FOR_INTEROP)
1758 // This is a zero-sized struct - need to record the fact and bump it up to 1.
1759 if (calcTotalSize == 0)
1761 pEEClassLayoutInfoOut->SetIsZeroSized(TRUE);
1765 pEEClassLayoutInfoOut->m_cbNativeSize = calcTotalSize;
1767 // The packingSize acts as a ceiling on all individual alignment
1768 // requirements so it follows that the largest alignment requirement
1770 _ASSERTE(LargestAlignmentRequirement <= packingSize);
1771 pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers = LargestAlignmentRequirement;
1776 //=====================================================================
1777 // Phase 4: Now we do the same thing again for managedsequential layout.
1778 //=====================================================================
1779 if (!fDisqualifyFromManagedSequential)
1781 BYTE LargestAlignmentRequirement = 1;
1782 UINT32 cbCurOffset = 0;
1784 if (pParentMT && pParentMT->IsManagedSequential())
1786 // Treat base class as an initial member.
1787 if (!SafeAddUINT32(&cbCurOffset, pParentMT->GetNumInstanceFieldBytes()))
1790 BYTE alignmentRequirement = 0;
1792 alignmentRequirement = min(packingSize, pParentLayoutInfo->m_ManagedLargestAlignmentRequirementOfAllMembers);
1794 LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);
1797 // The current size of the structure as a whole, we start at 1, because we disallow 0 sized structures.
1798 // NOTE: We do not need to do the same checking for zero-sized types as phase 3 because only ValueTypes
1799 // can be ManagedSequential and ValueTypes can not be inherited from.
1800 unsigned calcTotalSize = 1;
1802 LayoutRawFieldInfo **pSortWalk;
1803 for (pSortWalk = pSortArray, i=cFields; i; i--, pSortWalk++)
1805 pfwalk = *pSortWalk;
1807 BYTE alignmentRequirement = ((BYTE)(pfwalk->m_managedAlignmentReq));
1808 if (!(alignmentRequirement == 1 ||
1809 alignmentRequirement == 2 ||
1810 alignmentRequirement == 4 ||
1811 alignmentRequirement == 8 ||
1812 alignmentRequirement == 16 ||
1813 alignmentRequirement == 32))
1815 COMPlusThrowHR(COR_E_INVALIDPROGRAM, BFA_METADATA_CORRUPT);
1818 alignmentRequirement = min(alignmentRequirement, packingSize);
1820 LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);
1822 _ASSERTE(alignmentRequirement <= 32);
1824 // Insert enough padding to align the current data member.
1825 while (cbCurOffset % alignmentRequirement)
1827 if (!SafeAddUINT32(&cbCurOffset, 1))
1831 // Insert current data member.
1832 pfwalk->m_managedOffset = cbCurOffset;
1834 // if we overflow we will catch it below
1835 cbCurOffset += pfwalk->m_managedSize;
1837 unsigned fieldEnd = pfwalk->m_managedOffset + pfwalk->m_managedSize;
1838 if (fieldEnd < pfwalk->m_managedOffset)
1841 // size of the structure is the size of the last field.
1842 if (fieldEnd > calcTotalSize)
1843 calcTotalSize = fieldEnd;
1846 // @perf: If the type is blittable, the managed and native layouts have to be identical
1847 // so they really shouldn't be calculated twice. Until this code has been well tested and
1848 // stabilized, however, it is useful to compute both and assert that they are equal in the blittable
1850 if (pEEClassLayoutInfoOut->IsBlittable())
1852 _ASSERTE(pfwalk->m_managedOffset == pfwalk->m_offset);
1853 _ASSERTE(pfwalk->m_managedSize == pfwalk->m_cbNativeSize);
1858 ULONG clstotalsize = 0;
1859 if (FAILED(pInternalImport->GetClassTotalSize(cl, &clstotalsize)))
1864 if (clstotalsize != 0)
1866 pEEClassLayoutInfoOut->SetHasExplicitSize(TRUE);
1868 if (pParentMT && pParentMT->IsManagedSequential())
1870 // Treat base class as an initial member.
1871 UINT32 parentSize = pParentMT->GetNumInstanceFieldBytes();
1872 if (!SafeAddULONG(&clstotalsize, parentSize))
1876 // size must be large enough to accomodate layout. If not, we use the layout size instead.
1877 if (clstotalsize < calcTotalSize)
1879 clstotalsize = calcTotalSize;
1881 calcTotalSize = clstotalsize; // use the size they told us
1885 // The did not give us an explict size, so lets round up to a good size (for arrays)
1886 while (calcTotalSize % LargestAlignmentRequirement != 0)
1888 if (!SafeAddUINT32(&calcTotalSize, 1))
1893 pEEClassLayoutInfoOut->m_cbManagedSize = calcTotalSize;
1895 // The packingSize acts as a ceiling on all individual alignment
1896 // requirements so it follows that the largest alignment requirement
1898 _ASSERTE(LargestAlignmentRequirement <= packingSize);
1899 pEEClassLayoutInfoOut->m_ManagedLargestAlignmentRequirementOfAllMembers = LargestAlignmentRequirement;
1902 // @perf: If the type is blittable, the managed and native layouts have to be identical
1903 // so they really shouldn't be calculated twice. Until this code has been well tested and
1904 // stabilized, however, it is useful to compute both and assert that they are equal in the blittable
1906 if (pEEClassLayoutInfoOut->IsBlittable())
1908 _ASSERTE(pEEClassLayoutInfoOut->m_cbManagedSize == pEEClassLayoutInfoOut->m_cbNativeSize);
1909 _ASSERTE(pEEClassLayoutInfoOut->m_ManagedLargestAlignmentRequirementOfAllMembers == pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers);
1914 pEEClassLayoutInfoOut->SetIsManagedSequential(!fDisqualifyFromManagedSequential);
1918 BOOL illegalMarshaler = FALSE;
1920 LOG((LF_INTEROP, LL_INFO100000, "\n\n"));
1921 LOG((LF_INTEROP, LL_INFO100000, "%s.%s\n", szNamespace, szName));
1922 LOG((LF_INTEROP, LL_INFO100000, "Packsize = %lu\n", (ULONG)packingSize));
1923 LOG((LF_INTEROP, LL_INFO100000, "Max align req = %lu\n", (ULONG)(pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers)));
1924 LOG((LF_INTEROP, LL_INFO100000, "----------------------------\n"));
1925 for (pfwalk = pInfoArrayOut; pfwalk->m_MD != mdFieldDefNil; pfwalk++)
1928 if (FAILED(pInternalImport->GetNameOfFieldDef(pfwalk->m_MD, &fieldname)))
1932 LOG((LF_INTEROP, LL_INFO100000, "+%-5lu ", (ULONG)(pfwalk->m_offset)));
1933 LOG((LF_INTEROP, LL_INFO100000, "%s", fieldname));
1934 LOG((LF_INTEROP, LL_INFO100000, "\n"));
1936 if (((FieldMarshaler*)&pfwalk->m_FieldMarshaler)->GetNStructFieldType() == NFT_ILLEGAL)
1937 illegalMarshaler = TRUE;
1940 // If we are dealing with a non trivial parent, determine if it has any illegal marshallers.
1941 if (fHasNonTrivialParent)
1943 FieldMarshaler *pParentFM = pParentMT->GetLayoutInfo()->GetFieldMarshalers();
1944 for (i = 0; i < pParentMT->GetLayoutInfo()->m_numCTMFields; i++)
1946 if (pParentFM->GetNStructFieldType() == NFT_ILLEGAL)
1947 illegalMarshaler = TRUE;
1948 ((BYTE*&)pParentFM) += MAXFIELDMARSHALERSIZE;
1952 LOG((LF_INTEROP, LL_INFO100000, "+%-5lu EOS\n", (ULONG)(pEEClassLayoutInfoOut->m_cbNativeSize)));
1953 LOG((LF_INTEROP, LL_INFO100000, "Allocated %d %s field marshallers for %s.%s\n", pEEClassLayoutInfoOut->m_numCTMFields, (illegalMarshaler ? "pointless" : "usable"), szNamespace, szName));
1959 #pragma warning(pop)
1963 #ifndef CROSSGEN_COMPILE
1965 //=======================================================================
1966 // For each reference-typed FieldMarshaler field, marshals the current CLR value
1967 // to a new native instance and stores it in the fixed portion of the FieldMarshaler.
1969 // This function does not attempt to delete the native value that it overwrites.
1971 // If there is a SafeHandle field, ppCleanupWorkListOnStack must be non-null, otherwise
1972 // InvalidOperationException is thrown.
1973 //=======================================================================
1974 VOID LayoutUpdateNative(LPVOID *ppProtectedManagedData, SIZE_T offsetbias, MethodTable *pMT, BYTE* pNativeData, OBJECTREF *ppCleanupWorkListOnStack)
1981 PRECONDITION(CheckPointer(pMT));
1985 FieldMarshaler* pFM = pMT->GetLayoutInfo()->GetFieldMarshalers();
1986 UINT numReferenceFields = pMT->GetLayoutInfo()->GetNumCTMFields();
1988 OBJECTREF pCLRValue = NULL;
1989 LPVOID scalar = NULL;
1991 GCPROTECT_BEGIN(pCLRValue)
1992 GCPROTECT_BEGININTERIOR(scalar)
1994 g_IBCLogger.LogFieldMarshalersReadAccess(pMT);
1996 while (numReferenceFields--)
2000 DWORD internalOffset = pFM->GetFieldDesc()->GetOffset();
2002 if (pFM->IsScalarMarshaler())
2004 scalar = (LPVOID)(internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData));
2005 // Note this will throw for FieldMarshaler_Illegal
2006 pFM->ScalarUpdateNative(scalar, pNativeData + pFM->GetExternalOffset() );
2009 else if (pFM->IsNestedValueClassMarshaler())
2011 pFM->NestedValueClassUpdateNative((const VOID **)ppProtectedManagedData, internalOffset + offsetbias, pNativeData + pFM->GetExternalOffset(),
2012 ppCleanupWorkListOnStack);
2016 pCLRValue = *(OBJECTREF*)(internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData));
2017 pFM->UpdateNative(&pCLRValue, pNativeData + pFM->GetExternalOffset(), ppCleanupWorkListOnStack);
2018 SetObjectReferenceUnchecked( (OBJECTREF*) (internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData)), pCLRValue);
2021 // The cleanup work list is not used to clean up the native contents. It is used
2022 // to handle cleanup of any additionnal resources the FieldMarshalers allocate.
2024 ((BYTE*&)pFM) += MAXFIELDMARSHALERSIZE;
2032 VOID FmtClassUpdateNative(OBJECTREF *ppProtectedManagedData, BYTE *pNativeData, OBJECTREF *ppCleanupWorkListOnStack)
2039 PRECONDITION(CheckPointer(ppProtectedManagedData));
2043 MethodTable *pMT = (*ppProtectedManagedData)->GetMethodTable();
2044 _ASSERTE(pMT->IsBlittable() || pMT->HasLayout());
2045 UINT32 cbsize = pMT->GetNativeSize();
2047 if (pMT->IsBlittable())
2049 memcpyNoGCRefs(pNativeData, (*ppProtectedManagedData)->GetData(), cbsize);
2053 // This allows us to do a partial LayoutDestroyNative in the case of
2054 // a marshaling error on one of the fields.
2055 FillMemory(pNativeData, cbsize, 0);
2056 NativeLayoutDestroyer nld(pNativeData, pMT, cbsize);
2058 LayoutUpdateNative( (VOID**)ppProtectedManagedData,
2059 Object::GetOffsetOfFirstField(),
2062 ppCleanupWorkListOnStack);
2064 nld.SuppressRelease();
2070 VOID FmtClassUpdateCLR(OBJECTREF *ppProtectedManagedData, BYTE *pNativeData)
2080 MethodTable *pMT = (*ppProtectedManagedData)->GetMethodTable();
2081 _ASSERTE(pMT->IsBlittable() || pMT->HasLayout());
2082 UINT32 cbsize = pMT->GetNativeSize();
2084 if (pMT->IsBlittable())
2086 memcpyNoGCRefs((*ppProtectedManagedData)->GetData(), pNativeData, cbsize);
2090 LayoutUpdateCLR((VOID**)ppProtectedManagedData,
2091 Object::GetOffsetOfFirstField(),
2100 //=======================================================================
2101 // For each reference-typed FieldMarshaler field, marshals the current CLR value
2102 // to a new CLR instance and stores it in the GC portion of the FieldMarshaler.
2104 // If fDeleteNativeCopies is true, it will also destroy the native version.
2106 // NOTE: To avoid error-path leaks, this function attempts to destroy
2107 // all of the native fields even if one or more of the conversions fail.
2108 //=======================================================================
2109 VOID LayoutUpdateCLR(LPVOID *ppProtectedManagedData, SIZE_T offsetbias, MethodTable *pMT, BYTE *pNativeData)
2116 PRECONDITION(CheckPointer(pMT));
2120 // Don't try to destroy/free native the structure on exception, we may not own it. If we do own it and
2121 // are supposed to destroy/free it, we do it upstack (e.g. in a helper called from the marshaling stub).
2123 FieldMarshaler* pFM = pMT->GetLayoutInfo()->GetFieldMarshalers();
2124 UINT numReferenceFields = pMT->GetLayoutInfo()->GetNumCTMFields();
2128 OBJECTREF pCLRValue;
2129 OBJECTREF pOldCLRValue;
2132 gc.pCLRValue = NULL;
2133 gc.pOldCLRValue = NULL;
2134 LPVOID scalar = NULL;
2137 GCPROTECT_BEGININTERIOR(scalar)
2139 g_IBCLogger.LogFieldMarshalersReadAccess(pMT);
2141 while (numReferenceFields--)
2145 DWORD internalOffset = pFM->GetFieldDesc()->GetOffset();
2147 if (pFM->IsScalarMarshaler())
2149 scalar = (LPVOID)(internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData));
2150 // Note this will throw for FieldMarshaler_Illegal
2151 pFM->ScalarUpdateCLR( pNativeData + pFM->GetExternalOffset(), scalar);
2153 else if (pFM->IsNestedValueClassMarshaler())
2155 pFM->NestedValueClassUpdateCLR(pNativeData + pFM->GetExternalOffset(), ppProtectedManagedData, internalOffset + offsetbias);
2159 gc.pOldCLRValue = *(OBJECTREF*)(internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData));
2160 pFM->UpdateCLR( pNativeData + pFM->GetExternalOffset(), &gc.pCLRValue, &gc.pOldCLRValue );
2161 SetObjectReferenceUnchecked( (OBJECTREF*) (internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData)), gc.pCLRValue );
2164 ((BYTE*&)pFM) += MAXFIELDMARSHALERSIZE;
2172 VOID LayoutDestroyNative(LPVOID pNative, MethodTable *pMT)
2179 PRECONDITION(CheckPointer(pMT));
2183 FieldMarshaler *pFM = pMT->GetLayoutInfo()->GetFieldMarshalers();
2184 UINT numReferenceFields = pMT->GetLayoutInfo()->GetNumCTMFields();
2185 BYTE *pNativeData = (BYTE*)pNative;
2187 while (numReferenceFields--)
2189 pFM->DestroyNative( pNativeData + pFM->GetExternalOffset() );
2190 ((BYTE*&)pFM) += MAXFIELDMARSHALERSIZE;
2194 VOID FmtClassDestroyNative(LPVOID pNative, MethodTable *pMT)
2201 PRECONDITION(CheckPointer(pMT));
2207 if (!(pMT->IsBlittable()))
2209 _ASSERTE(pMT->HasLayout());
2210 LayoutDestroyNative(pNative, pMT);
2215 VOID FmtValueTypeUpdateNative(LPVOID pProtectedManagedData, MethodTable *pMT, BYTE *pNativeData, OBJECTREF *ppCleanupWorkListOnStack)
2222 PRECONDITION(CheckPointer(pMT));
2226 _ASSERTE(pMT->IsValueType() && (pMT->IsBlittable() || pMT->HasLayout()));
2227 UINT32 cbsize = pMT->GetNativeSize();
2229 if (pMT->IsBlittable())
2231 memcpyNoGCRefs(pNativeData, pProtectedManagedData, cbsize);
2235 // This allows us to do a partial LayoutDestroyNative in the case of
2236 // a marshaling error on one of the fields.
2237 FillMemory(pNativeData, cbsize, 0);
2239 NativeLayoutDestroyer nld(pNativeData, pMT, cbsize);
2241 LayoutUpdateNative( (VOID**)pProtectedManagedData,
2245 ppCleanupWorkListOnStack);
2247 nld.SuppressRelease();
2251 VOID FmtValueTypeUpdateCLR(LPVOID pProtectedManagedData, MethodTable *pMT, BYTE *pNativeData)
2258 PRECONDITION(CheckPointer(pMT));
2262 _ASSERTE(pMT->IsValueType() && (pMT->IsBlittable() || pMT->HasLayout()));
2263 UINT32 cbsize = pMT->GetNativeSize();
2265 if (pMT->IsBlittable())
2267 memcpyNoGCRefs(pProtectedManagedData, pNativeData, cbsize);
2271 LayoutUpdateCLR((VOID**)pProtectedManagedData,
2274 (BYTE*)pNativeData);
2279 #ifdef FEATURE_COMINTEROP
2281 //=======================================================================
2282 // BSTR <--> System.String
2283 // See FieldMarshaler for details.
2284 //=======================================================================
2285 VOID FieldMarshaler_BSTR::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
2292 INJECT_FAULT(COMPlusThrowOM());
2293 PRECONDITION(CheckPointer(pNativeValue));
2298 *((OBJECTREF*)&pString) = *pCLRValue;
2300 if (pString == NULL)
2301 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
2304 BSTR pBSTR = SysAllocStringLen(pString->GetBuffer(), pString->GetStringLength());
2308 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, pBSTR);
2313 //=======================================================================
2314 // BSTR <--> System.String
2315 // See FieldMarshaler for details.
2316 //=======================================================================
2317 VOID FieldMarshaler_BSTR::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
2319 STATIC_CONTRACT_THROWS;
2320 STATIC_CONTRACT_GC_TRIGGERS;
2321 STATIC_CONTRACT_MODE_COOPERATIVE;
2323 _ASSERTE(NULL != pNativeValue);
2324 _ASSERTE(NULL != ppProtectedCLRValue);
2327 BSTR pBSTR = (BSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
2333 struct Param : CallOutFilterParam {
2338 param.OneShot = TRUE;
2340 param.pBSTR = pBSTR;
2342 PAL_TRY(Param *, pParam, ¶m)
2344 pParam->length = SysStringLen(pParam->pBSTR);
2346 PAL_EXCEPT_FILTER(CallOutFilter)
2348 _ASSERTE(!"CallOutFilter returned EXECUTE_HANDLER.");
2352 pString = StringObject::NewString(pBSTR, param.length);
2355 *((STRINGREF*)ppProtectedCLRValue) = pString;
2359 //=======================================================================
2360 // BSTR <--> System.String
2361 // See FieldMarshaler for details.
2362 //=======================================================================
2363 VOID FieldMarshaler_BSTR::DestroyNativeImpl(LPVOID pNativeValue) const
2370 PRECONDITION(CheckPointer(pNativeValue));
2374 BSTR pBSTR = (BSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
2375 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
2379 _ASSERTE (GetModuleHandleA("oleaut32.dll") != NULL);
2380 // BSTR has been created, which means oleaut32 should have been loaded.
2381 // Delay load will not fail.
2382 CONTRACT_VIOLATION(ThrowsViolation);
2383 SysFreeString(pBSTR);
2387 //===========================================================================================
2388 // Windows.Foundation.IReference'1<-- System.Nullable'1
2390 VOID FieldMarshaler_Nullable::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const
2397 INJECT_FAULT(COMPlusThrowOM());
2398 PRECONDITION(CheckPointer(pNative));
2399 PRECONDITION(CheckPointer(pCLR));
2403 IUnknown *pUnk = NULL;
2405 // ConvertToNative<T>(ref Nullable<T> pManaged) where T : struct
2406 MethodDescCallSite convertToNative(GetMethodDescForGenericInstantiation(MscorlibBinder::GetMethod(METHOD__NULLABLEMARSHALER__CONVERT_TO_NATIVE)));
2412 pUnk = (IUnknown*) convertToNative.Call_RetLPVOID(args);
2414 MAYBE_UNALIGNED_WRITE(pNative, _PTR, pUnk);
2417 //===========================================================================================
2418 // Windows.Foundation.IReference'1--> System.Nullable'1
2420 VOID FieldMarshaler_Nullable::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const
2427 PRECONDITION(CheckPointer(pNative));
2428 PRECONDITION(CheckPointer(pCLR));
2432 IUnknown *pUnk = (IUnknown*)MAYBE_UNALIGNED_READ(pNative, _PTR);
2434 MethodDescCallSite convertToManaged(GetMethodDescForGenericInstantiation(MscorlibBinder::GetMethod(METHOD__NULLABLEMARSHALER__CONVERT_TO_MANAGED_RET_VOID)));
2442 //ConvertToManaged<T>(Intptr pNative, ref Nullable<T> retObj) where T : struct;
2443 convertToManaged.Call(args);
2446 //===========================================================================================
2447 // Windows.Foundation.IReference'1<--> System.Nullable'1
2449 VOID FieldMarshaler_Nullable::DestroyNativeImpl(const VOID* pNative) const
2456 PRECONDITION(CheckPointer(pNative));
2460 IUnknown *pUnk = (IUnknown*)MAYBE_UNALIGNED_READ(pNative, _PTR);
2461 MAYBE_UNALIGNED_WRITE(pNative, _PTR, NULL);
2465 ULONG cbRef = SafeRelease(pUnk);
2466 LogInteropRelease(pUnk, cbRef, "Field marshaler destroy native");
2470 //=======================================================================
2471 // HSTRING <--> System.String
2472 // See FieldMarshaler for details.
2473 //=======================================================================
2474 VOID FieldMarshaler_HSTRING::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
2481 PRECONDITION(CheckPointer(pCLRValue));
2482 PRECONDITION(CheckPointer(pNativeValue));
2486 if (!WinRTSupported())
2488 COMPlusThrow(kPlatformNotSupportedException, W("PlatformNotSupported_WinRT"));
2491 STRINGREF stringref = (STRINGREF)(*pCLRValue);
2493 if (stringref == NULL)
2495 DefineFullyQualifiedNameForClassW();
2496 StackSString ssFieldName(SString::Utf8, GetFieldDesc()->GetName());
2498 SString errorString;
2499 errorString.LoadResource(CCompRC::Error, IDS_EE_BADMARSHALFIELD_NULL_HSTRING);
2501 COMPlusThrow(kMarshalDirectiveException,
2502 IDS_EE_BADMARSHALFIELD_ERROR_MSG,
2503 GetFullyQualifiedNameForClassW(GetFieldDesc()->GetEnclosingMethodTable()),
2504 ssFieldName.GetUnicode(),
2505 errorString.GetUnicode());
2509 IfFailThrow(WindowsCreateString(stringref->GetBuffer(), stringref->GetStringLength(), &hstring));
2511 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, hstring);
2514 //=======================================================================
2515 // HSTRING <--> System.String
2516 // See FieldMarshaler for details.
2517 //=======================================================================
2518 VOID FieldMarshaler_HSTRING::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
2525 PRECONDITION(CheckPointer(pNativeValue));
2526 PRECONDITION(CheckPointer(ppProtectedCLRValue));
2530 if (!WinRTSupported())
2532 COMPlusThrow(kPlatformNotSupportedException, W("PlatformNotSupported_WinRT"));
2535 // NULL HSTRINGS are equivilent to empty strings
2536 UINT32 cchString = 0;
2537 LPCWSTR pwszString = W("");
2539 HSTRING hstring = (HSTRING)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
2540 if (hstring != NULL)
2542 pwszString = WindowsGetStringRawBuffer(hstring, &cchString);
2545 STRINGREF stringref = StringObject::NewString(pwszString, cchString);
2546 *((STRINGREF *)ppProtectedCLRValue) = stringref;
2549 //=======================================================================
2550 // HSTRING <--> System.String
2551 // See FieldMarshaler for details.
2552 //=======================================================================
2553 VOID FieldMarshaler_HSTRING::DestroyNativeImpl(LPVOID pNativeValue) const
2560 PRECONDITION(CheckPointer(pNativeValue));
2564 HSTRING hstring = (HSTRING)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
2565 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
2567 if (hstring != NULL)
2569 // We need this for code:System.Runtime.InteropServices.Marshal.DestroyStructure (user can explicitly call it)
2570 if (WinRTSupported())
2572 // If WinRT is supported we've already loaded combase.dll, which means
2573 // this delay load will succeed
2574 CONTRACT_VIOLATION(ThrowsViolation);
2575 WindowsDeleteString(hstring);
2580 //=======================================================================================
2581 // Windows.UI.Xaml.Interop.TypeName <--> System.Type
2583 VOID FieldMarshaler_SystemType::UpdateNativeImpl(OBJECTREF * pCLRValue, LPVOID pNativeValue, OBJECTREF * ppCleanupWorkListOnStack) const
2590 PRECONDITION(CheckPointer(pCLRValue));
2591 PRECONDITION(CheckPointer(pNativeValue));
2595 // ConvertToNative(System.Type managedType, TypeName *pTypeName)
2596 MethodDescCallSite convertToNative(METHOD__SYSTEMTYPEMARSHALER__CONVERT_TO_NATIVE);
2599 ObjToArgSlot(*pCLRValue),
2600 PtrToArgSlot(pNativeValue)
2602 convertToNative.Call(args);
2605 //=======================================================================================
2606 // Windows.UI.Xaml.Interop.TypeName <--> System.Type
2608 VOID FieldMarshaler_SystemType::UpdateCLRImpl(const VOID * pNativeValue, OBJECTREF * ppProtectedCLRValue, OBJECTREF * ppProtectedOldCLRValue) const
2615 PRECONDITION(CheckPointer(pNativeValue));
2616 PRECONDITION(CheckPointer(ppProtectedCLRValue));
2620 // ConvertToManaged(TypeName *pTypeName, out System.Type)
2621 MethodDescCallSite convertToManaged(METHOD__SYSTEMTYPEMARSHALER__CONVERT_TO_MANAGED);
2624 PtrToArgSlot(pNativeValue),
2625 PtrToArgSlot(ppProtectedCLRValue)
2628 convertToManaged.Call(args);
2631 //=======================================================================================
2632 // Windows.UI.Xaml.Interop.TypeName <--> System.Type
2633 // Clear the HSTRING field
2635 VOID FieldMarshaler_SystemType::DestroyNativeImpl(LPVOID pNativeValue) const
2642 PRECONDITION(CheckPointer(pNativeValue));
2643 PRECONDITION(WinRTSupported());
2648 // Call WindowsDeleteString instead of SystemTypeMarshaler.ClearNative
2649 // because WindowsDeleteString does not throw and is much faster
2651 size_t offset = offsetof(TypeNameNative, typeName);
2652 HSTRING hstring = (HSTRING)MAYBE_UNALIGNED_READ((LPBYTE) pNativeValue + offset , _PTR);
2653 MAYBE_UNALIGNED_WRITE((LPBYTE) pNativeValue + offset, _PTR, NULL);
2655 if (hstring != NULL)
2657 // Note: we've already loaded combase.dll, which means this delay load will succeed
2658 CONTRACT_VIOLATION(ThrowsViolation);
2659 WindowsDeleteString(hstring);
2663 //=======================================================================================
2664 // Windows.Foundation.HResult <--> System.Exception
2665 // Note: The WinRT struct has exactly 1 field, Value (an HRESULT)
2667 VOID FieldMarshaler_Exception::UpdateNativeImpl(OBJECTREF * pCLRValue, LPVOID pNativeValue, OBJECTREF * ppCleanupWorkListOnStack) const
2674 PRECONDITION(CheckPointer(pCLRValue));
2675 PRECONDITION(CheckPointer(pNativeValue));
2679 // int ConvertToNative(Exception ex)
2680 MethodDescCallSite convertToNative(METHOD__HRESULTEXCEPTIONMARSHALER__CONVERT_TO_NATIVE);
2683 ObjToArgSlot(*pCLRValue)
2685 int iReturnedValue = convertToNative.Call_RetI4(args);
2686 MAYBE_UNALIGNED_WRITE(pNativeValue, 32, iReturnedValue);
2689 //=======================================================================================
2690 // Windows.Foundation.HResult <--> System.Exception
2691 // Note: The WinRT struct has exactly 1 field, Value (an HRESULT)
2693 VOID FieldMarshaler_Exception::UpdateCLRImpl(const VOID * pNativeValue, OBJECTREF * ppProtectedCLRValue, OBJECTREF * ppProtectedOldCLRValue) const
2700 PRECONDITION(CheckPointer(pNativeValue));
2701 PRECONDITION(CheckPointer(ppProtectedCLRValue));
2705 // Exception ConvertToManaged(int hr)
2706 MethodDescCallSite convertToManaged(METHOD__HRESULTEXCEPTIONMARSHALER__CONVERT_TO_MANAGED);
2709 (ARG_SLOT)MAYBE_UNALIGNED_READ(pNativeValue, 32)
2711 *ppProtectedCLRValue = convertToManaged.Call_RetOBJECTREF(args);
2714 #endif // FEATURE_COMINTEROP
2717 //=======================================================================
2718 // Nested structure conversion
2719 // See FieldMarshaler for details.
2720 //=======================================================================
2721 VOID FieldMarshaler_NestedLayoutClass::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
2728 INJECT_FAULT(COMPlusThrowOM());
2729 PRECONDITION(CheckPointer(pNativeValue));
2733 UINT32 cbNativeSize = GetMethodTable()->GetNativeSize();
2735 if (*pCLRValue == NULL)
2737 ZeroMemoryInGCHeap(pNativeValue, cbNativeSize);
2741 LayoutUpdateNative((LPVOID*)pCLRValue, Object::GetOffsetOfFirstField(),
2742 GetMethodTable(), (BYTE*)pNativeValue, ppCleanupWorkListOnStack);
2748 //=======================================================================
2749 // Nested structure conversion
2750 // See FieldMarshaler for details.
2751 //=======================================================================
2752 VOID FieldMarshaler_NestedLayoutClass::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
2759 INJECT_FAULT(COMPlusThrowOM());
2760 PRECONDITION(CheckPointer(pNativeValue));
2761 PRECONDITION(CheckPointer(ppProtectedCLRValue));
2765 *ppProtectedCLRValue = GetMethodTable()->Allocate();
2767 LayoutUpdateCLR( (LPVOID*)ppProtectedCLRValue,
2768 Object::GetOffsetOfFirstField(),
2770 (BYTE *)pNativeValue);
2775 //=======================================================================
2776 // Nested structure conversion
2777 // See FieldMarshaler for details.
2778 //=======================================================================
2779 VOID FieldMarshaler_NestedLayoutClass::DestroyNativeImpl(LPVOID pNativeValue) const
2786 PRECONDITION(CheckPointer(pNativeValue));
2790 LayoutDestroyNative(pNativeValue, GetMethodTable());
2793 #endif // CROSSGEN_COMPILE
2796 //=======================================================================
2797 // Nested structure conversion
2798 // See FieldMarshaler for details.
2799 //=======================================================================
2800 UINT32 FieldMarshaler_NestedLayoutClass::NativeSizeImpl() const
2810 return GetMethodTable()->GetLayoutInfo()->GetNativeSize();
2813 //=======================================================================
2814 // Nested structure conversion
2815 // See FieldMarshaler for details.
2816 //=======================================================================
2817 UINT32 FieldMarshaler_NestedLayoutClass::AlignmentRequirementImpl() const
2827 return GetMethodTable()->GetLayoutInfo()->GetLargestAlignmentRequirementOfAllMembers();
2830 #if FEATURE_COMINTEROP
2831 MethodDesc* FieldMarshaler_Nullable::GetMethodDescForGenericInstantiation(MethodDesc* pMD) const
2833 MethodDesc *pMethodInstantiation;
2835 pMethodInstantiation = MethodDesc::FindOrCreateAssociatedMethodDesc(
2837 pMD->GetMethodTable(),
2839 GetMethodTable()->GetInstantiation(),
2843 _ASSERTE(pMethodInstantiation != NULL);
2845 return pMethodInstantiation;
2847 #endif //FEATURE_COMINTEROP
2849 #ifndef CROSSGEN_COMPILE
2851 //=======================================================================
2852 // Nested structure conversion
2853 // See FieldMarshaler for details.
2854 //=======================================================================
2855 VOID FieldMarshaler_NestedValueClass::NestedValueClassUpdateNativeImpl(const VOID **ppProtectedCLR, SIZE_T startoffset, LPVOID pNative, OBJECTREF *ppCleanupWorkListOnStack) const
2862 INJECT_FAULT(COMPlusThrowOM());
2863 PRECONDITION(CheckPointer(ppProtectedCLR));
2864 PRECONDITION(CheckPointer(pNative));
2868 // would be better to detect this at class load time (that have a nested value
2869 // class with no layout) but don't have a way to know
2870 if (! GetMethodTable()->GetLayoutInfo())
2871 COMPlusThrow(kArgumentException, IDS_NOLAYOUT_IN_EMBEDDED_VALUECLASS);
2873 LayoutUpdateNative((LPVOID*)ppProtectedCLR, startoffset, GetMethodTable(), (BYTE*)pNative, ppCleanupWorkListOnStack);
2877 //=======================================================================
2878 // Nested structure conversion
2879 // See FieldMarshaler for details.
2880 //=======================================================================
2881 VOID FieldMarshaler_NestedValueClass::NestedValueClassUpdateCLRImpl(const VOID *pNative, LPVOID *ppProtectedCLR, SIZE_T startoffset) const
2888 PRECONDITION(CheckPointer(pNative));
2889 PRECONDITION(CheckPointer(ppProtectedCLR));
2893 // would be better to detect this at class load time (that have a nested value
2894 // class with no layout) but don't have a way to know
2895 if (! GetMethodTable()->GetLayoutInfo())
2896 COMPlusThrow(kArgumentException, IDS_NOLAYOUT_IN_EMBEDDED_VALUECLASS);
2898 LayoutUpdateCLR( (LPVOID*)ppProtectedCLR,
2907 //=======================================================================
2908 // Nested structure conversion
2909 // See FieldMarshaler for details.
2910 //=======================================================================
2911 VOID FieldMarshaler_NestedValueClass::DestroyNativeImpl(LPVOID pNativeValue) const
2918 PRECONDITION(CheckPointer(pNativeValue));
2922 LayoutDestroyNative(pNativeValue, GetMethodTable());
2925 #endif // CROSSGEN_COMPILE
2928 //=======================================================================
2929 // Nested structure conversion
2930 // See FieldMarshaler for details.
2931 //=======================================================================
2932 UINT32 FieldMarshaler_NestedValueClass::NativeSizeImpl() const
2942 // this can't be marshalled as native type if no layout, so we allow the
2943 // native size info to be created if available, but the size will only
2944 // be valid for native, not unions. Marshaller will throw exception if
2945 // try to marshall a value class with no layout
2946 if (GetMethodTable()->HasLayout())
2947 return GetMethodTable()->GetLayoutInfo()->GetNativeSize();
2953 //=======================================================================
2954 // Nested structure conversion
2955 // See FieldMarshaler for details.
2956 //=======================================================================
2957 UINT32 FieldMarshaler_NestedValueClass::AlignmentRequirementImpl() const
2967 // this can't be marshalled as native type if no layout, so we allow the
2968 // native size info to be created if available, but the alignment will only
2969 // be valid for native, not unions. Marshaller will throw exception if
2970 // try to marshall a value class with no layout
2971 if (GetMethodTable()->HasLayout())
2973 UINT32 uAlignmentReq = GetMethodTable()->GetLayoutInfo()->GetLargestAlignmentRequirementOfAllMembers();
2974 return uAlignmentReq;
2980 #ifndef CROSSGEN_COMPILE
2982 //=======================================================================
2983 // CoTask Uni <--> System.String
2984 // See FieldMarshaler for details.
2985 //=======================================================================
2986 VOID FieldMarshaler_StringUni::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
2993 INJECT_FAULT(COMPlusThrowOM());
2994 PRECONDITION(CheckPointer(pNativeValue));
2999 *((OBJECTREF*)&pString) = *pCLRValue;
3001 if (pString == NULL)
3003 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3007 DWORD nc = pString->GetStringLength();
3008 if (nc > MAX_SIZE_FOR_INTEROP)
3009 COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG);
3011 LPWSTR wsz = (LPWSTR)CoTaskMemAlloc( (nc + 1) * sizeof(WCHAR) );
3015 memcpyNoGCRefs(wsz, pString->GetBuffer(), nc*sizeof(WCHAR));
3017 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, wsz);
3022 //=======================================================================
3023 // CoTask Uni <--> System.String
3024 // See FieldMarshaler for details.
3025 //=======================================================================
3026 VOID FieldMarshaler_StringUni::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3033 PRECONDITION(CheckPointer(pNativeValue));
3034 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3039 LPCWSTR wsz = (LPCWSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3045 SIZE_T length = wcslen(wsz);
3046 if (length > MAX_SIZE_FOR_INTEROP)
3047 COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG);
3049 pString = StringObject::NewString(wsz, (DWORD)length);
3052 *((STRINGREF*)ppProtectedCLRValue) = pString;
3056 //=======================================================================
3057 // CoTask Uni <--> System.String
3058 // See FieldMarshaler for details.
3059 //=======================================================================
3060 VOID FieldMarshaler_StringUni::DestroyNativeImpl(LPVOID pNativeValue) const
3067 PRECONDITION(CheckPointer(pNativeValue));
3071 LPWSTR wsz = (LPWSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3072 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3079 //=======================================================================
3080 // CoTask Ansi <--> System.String
3081 // See FieldMarshaler for details.
3082 //=======================================================================
3083 VOID FieldMarshaler_StringAnsi::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3090 INJECT_FAULT(COMPlusThrowOM());
3091 PRECONDITION(CheckPointer(pNativeValue));
3096 *((OBJECTREF*)&pString) = *pCLRValue;
3098 if (pString == NULL)
3100 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3104 DWORD nc = pString->GetStringLength();
3105 if (nc > MAX_SIZE_FOR_INTEROP)
3106 COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG);
3108 LPSTR sz = (LPSTR)CoTaskMemAlloc( (nc + 1) * 2 /* 2 for MBCS */ );
3112 int nbytes = InternalWideToAnsi(pString->GetBuffer(),
3117 m_ThrowOnUnmappableChar);
3120 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, sz);
3125 //=======================================================================
3126 // CoTask Ansi <--> System.String
3127 // See FieldMarshaler for details.
3128 //=======================================================================
3129 VOID FieldMarshaler_StringAnsi::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3136 INJECT_FAULT(COMPlusThrowOM());
3137 PRECONDITION(CheckPointer(pNativeValue));
3138 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3142 STRINGREF pString = NULL;
3143 LPCSTR sz = (LPCSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3148 MAKE_WIDEPTR_FROMANSI(wsztemp, sz);
3149 pString = StringObject::NewString(wsztemp, __lwsztemp - 1);
3152 *((STRINGREF*)ppProtectedCLRValue) = pString;
3156 //=======================================================================
3157 // CoTask Ansi <--> System.String
3158 // See FieldMarshaler for details.
3159 //=======================================================================
3160 VOID FieldMarshaler_StringAnsi::DestroyNativeImpl(LPVOID pNativeValue) const
3167 PRECONDITION(CheckPointer(pNativeValue));
3171 LPSTR sz = (LPSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3172 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3177 //=======================================================================
3178 // CoTask Utf8 <--> System.String
3179 // See FieldMarshaler for details.
3180 //=======================================================================
3181 VOID FieldMarshaler_StringUtf8::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3188 INJECT_FAULT(COMPlusThrowOM());
3189 PRECONDITION(CheckPointer(pNativeValue));
3193 STRINGREF pString = (STRINGREF)(*pCLRValue);
3194 if (pString == NULL)
3196 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3200 DWORD nc = pString->GetStringLength();
3201 if (nc > MAX_SIZE_FOR_INTEROP)
3202 COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG);
3204 // Characters would be # of characters + 1 in case left over high surrogate is ?
3205 // Max 3 bytes per char for basic multi-lingual plane.
3206 nc = (nc + 1) * MAX_UTF8_CHAR_SIZE;
3208 LPUTF8 lpBuffer = (LPUTF8)CoTaskMemAlloc(nc + 1);
3214 // UTF8Marshaler.ConvertToNative
3215 MethodDescCallSite convertToNative(METHOD__CUTF8MARSHALER__CONVERT_TO_NATIVE);
3219 ((ARG_SLOT)(CLR_I4)0),
3220 ObjToArgSlot(*pCLRValue),
3221 PtrToArgSlot(lpBuffer)
3223 convertToNative.Call(args);
3224 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, lpBuffer);
3229 //=======================================================================
3230 // CoTask Utf8 <--> System.String
3231 // See FieldMarshaler for details.
3232 //=======================================================================
3233 VOID FieldMarshaler_StringUtf8::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3240 INJECT_FAULT(COMPlusThrowOM());
3241 PRECONDITION(CheckPointer(pNativeValue));
3242 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3246 STRINGREF pString = NULL;
3247 LPCUTF8 sz = (LPCUTF8)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3254 MethodDescCallSite convertToManaged(METHOD__CUTF8MARSHALER__CONVERT_TO_MANAGED);
3257 PtrToArgSlot(pNativeValue),
3259 pString = convertToManaged.Call_RetSTRINGREF(args);
3261 *((STRINGREF*)ppProtectedCLRValue) = pString;
3264 //=======================================================================
3265 // CoTask Utf8 <--> System.String
3266 // See FieldMarshaler for details.
3267 //=======================================================================
3268 VOID FieldMarshaler_StringUtf8::DestroyNativeImpl(LPVOID pNativeValue) const
3275 PRECONDITION(CheckPointer(pNativeValue));
3279 LPCUTF8 lpBuffer = (LPCUTF8)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3280 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3282 CoTaskMemFree((LPVOID)lpBuffer);
3285 //=======================================================================
3286 // FixedString <--> System.String
3287 // See FieldMarshaler for details.
3288 //=======================================================================
3289 VOID FieldMarshaler_FixedStringUni::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3296 PRECONDITION(CheckPointer(pNativeValue));
3301 *((OBJECTREF*)&pString) = *pCLRValue;
3303 if (pString == NULL)
3305 MAYBE_UNALIGNED_WRITE(pNativeValue, 16, W('\0'));
3309 DWORD nc = pString->GetStringLength();
3310 if (nc >= m_numchar)
3313 memcpyNoGCRefs(pNativeValue, pString->GetBuffer(), nc*sizeof(WCHAR));
3314 MAYBE_UNALIGNED_WRITE(&(((WCHAR*)pNativeValue)[nc]), 16, W('\0'));
3320 //=======================================================================
3321 // FixedString <--> System.String
3322 // See FieldMarshaler for details.
3323 //=======================================================================
3324 VOID FieldMarshaler_FixedStringUni::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3331 PRECONDITION(CheckPointer(pNativeValue));
3332 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3337 SIZE_T ncActual = wcsnlen((const WCHAR *)pNativeValue, m_numchar);
3339 if (!FitsIn<int>(ncActual))
3340 COMPlusThrowHR(COR_E_OVERFLOW);
3342 pString = StringObject::NewString((const WCHAR *)pNativeValue, (int)ncActual);
3343 *((STRINGREF*)ppProtectedCLRValue) = pString;
3352 //=======================================================================
3353 // FixedString <--> System.String
3354 // See FieldMarshaler for details.
3355 //=======================================================================
3356 VOID FieldMarshaler_FixedStringAnsi::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3363 PRECONDITION(CheckPointer(pNativeValue));
3368 *((OBJECTREF*)&pString) = *pCLRValue;
3370 if (pString == NULL)
3371 *((CHAR*)pNativeValue) = W('\0');
3374 DWORD nc = pString->GetStringLength();
3375 if (nc >= m_numchar)
3378 int cbwritten = InternalWideToAnsi(pString->GetBuffer(),
3380 (CHAR*)pNativeValue,
3383 m_ThrowOnUnmappableChar);
3385 // Handle the case where SizeConst == Number of bytes.For single byte chars
3386 // this will never be the case since nc >= m_numchar check will truncate the last
3387 // character, but for multibyte chars nc>= m_numchar check won't truncate since GetStringLength
3388 // gives number of characters but not the actual number of bytes. For such cases need to make
3389 // sure that we dont write one past the buffer.
3390 if (cbwritten == (int) m_numchar)
3393 ((CHAR*)pNativeValue)[cbwritten] = '\0';
3398 //=======================================================================
3399 // FixedString <--> System.String
3400 // See FieldMarshaler for details.
3401 //=======================================================================
3402 VOID FieldMarshaler_FixedStringAnsi::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3409 INJECT_FAULT(COMPlusThrowOM());
3410 PRECONDITION(CheckPointer(pNativeValue));
3411 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3413 // should not have slipped past the metadata
3414 PRECONDITION(m_numchar != 0);
3421 // but if it does, better to throw an exception tardily rather than
3422 // allow a memory corrupt.
3423 COMPlusThrow(kMarshalDirectiveException);
3426 UINT32 allocSize = m_numchar + 2;
3427 if (allocSize < m_numchar)
3430 LPSTR tempbuf = (LPSTR)(_alloca((size_t)allocSize));
3434 memcpyNoGCRefs(tempbuf, pNativeValue, m_numchar);
3435 tempbuf[m_numchar-1] = '\0';
3436 tempbuf[m_numchar] = '\0';
3437 tempbuf[m_numchar+1] = '\0';
3439 allocSize = m_numchar * sizeof(WCHAR);
3440 if (allocSize < m_numchar)
3443 LPWSTR wsztemp = (LPWSTR)_alloca( (size_t)allocSize );
3444 int ncwritten = MultiByteToWideChar(CP_ACP,
3447 -1, // # of CHAR's in inbuffer
3449 m_numchar // size (in WCHAR) of outbuffer
3454 // intentionally not throwing for MB2WC failure. We don't always know
3455 // whether to expect a valid string in the buffer and we don't want
3456 // to throw exceptions randomly.
3460 pString = StringObject::NewString((const WCHAR *)wsztemp, ncwritten-1);
3461 *((STRINGREF*)ppProtectedCLRValue) = pString;
3465 //=======================================================================
3466 // CHAR[] <--> char[]
3467 // See FieldMarshaler for details.
3468 //=======================================================================
3469 VOID FieldMarshaler_FixedCharArrayAnsi::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3476 INJECT_FAULT(COMPlusThrowOM());
3477 PRECONDITION(CheckPointer(pNativeValue));
3482 *((OBJECTREF*)&pArray) = *pCLRValue;
3485 FillMemory(pNativeValue, m_numElems * sizeof(CHAR), 0);
3488 if (pArray->GetNumComponents() < m_numElems)
3489 COMPlusThrow(kArgumentException, IDS_WRONGSIZEARRAY_IN_NSTRUCT);
3492 InternalWideToAnsi((const WCHAR*) pArray->GetDataPtr(),
3494 (CHAR*)pNativeValue,
3495 m_numElems * sizeof(CHAR),
3497 m_ThrowOnUnmappableChar);
3503 //=======================================================================
3504 // CHAR[] <--> char[]
3505 // See FieldMarshaler for details.
3506 //=======================================================================
3507 VOID FieldMarshaler_FixedCharArrayAnsi::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3514 INJECT_FAULT(COMPlusThrowOM());
3515 PRECONDITION(CheckPointer(pNativeValue));
3516 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3520 *ppProtectedCLRValue = AllocatePrimitiveArray(ELEMENT_TYPE_CHAR, m_numElems);
3522 MultiByteToWideChar(CP_ACP,
3524 (const CHAR *)pNativeValue,
3525 m_numElems * sizeof(CHAR), // size, in bytes, of in buffer
3526 (WCHAR*) ((*((I2ARRAYREF*)ppProtectedCLRValue))->GetDirectPointerToNonObjectElements()),
3527 m_numElems); // size, in WCHAR's of outbuffer
3530 #endif // CROSSGEN_COMPILE
3533 //=======================================================================
3535 // See FieldMarshaler for details.
3536 //=======================================================================
3537 FieldMarshaler_FixedArray::FieldMarshaler_FixedArray(IMDInternalImport *pMDImport, mdTypeDef cl, UINT32 numElems, VARTYPE vt, MethodTable* pElementMT)
3538 : m_numElems(numElems)
3540 , m_BestFitMap(FALSE)
3541 , m_ThrowOnUnmappableChar(FALSE)
3548 PRECONDITION(CheckPointer(pElementMT));
3549 PRECONDITION(vt != VTHACK_ANSICHAR); // This must be handled by the FixedCharArrayAnsi marshaler.
3553 // Only attempt to read the best fit mapping attribute if required to minimize
3554 // custom attribute accesses.
3555 if (vt == VT_LPSTR || vt == VT_RECORD)
3557 BOOL BestFitMap = FALSE;
3558 BOOL ThrowOnUnmappableChar = FALSE;
3559 ReadBestFitCustomAttribute(pMDImport, cl, &BestFitMap, &ThrowOnUnmappableChar);
3560 m_BestFitMap = !!BestFitMap;
3561 m_ThrowOnUnmappableChar = !!ThrowOnUnmappableChar;
3564 m_arrayType.SetValue(ClassLoader::LoadArrayTypeThrowing(TypeHandle(pElementMT),
3565 ELEMENT_TYPE_SZARRAY,
3567 ClassLoader::LoadTypes,
3568 pElementMT->GetLoadLevel()));
3572 #ifndef CROSSGEN_COMPILE
3574 //=======================================================================
3576 // See FieldMarshaler for details.
3577 //=======================================================================
3578 VOID FieldMarshaler_FixedArray::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3585 PRECONDITION(CheckPointer(pNativeValue));
3589 if (*pCLRValue == NULL)
3591 FillMemory(pNativeValue, NativeSize(), 0);
3595 // Make sure the size of the array is >= as specified in the MarshalAs attribute (via the SizeConst field).
3596 if ((*pCLRValue)->GetNumComponents() < m_numElems)
3597 COMPlusThrow(kArgumentException, IDS_WRONGSIZEARRAY_IN_NSTRUCT);
3599 // Marshal the contents from the managed array to the native array.
3600 const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(m_vt, TRUE);
3601 if (pMarshaler == NULL || pMarshaler->ComToOleArray == NULL)
3603 memcpyNoGCRefs(pNativeValue, (*(BASEARRAYREF*)pCLRValue)->GetDataPtr(), NativeSize());
3607 MethodTable *pElementMT = m_arrayType.GetValue().AsArray()->GetArrayElementTypeHandle().GetMethodTable();
3609 // We never operate on an uninitialized native layout here, we have zero'ed it if needed.
3610 // Therefore fOleArrayIsValid is always TRUE.
3611 pMarshaler->ComToOleArray((BASEARRAYREF*)pCLRValue, pNativeValue, pElementMT, m_BestFitMap, m_ThrowOnUnmappableChar, TRUE, m_numElems);
3617 //=======================================================================
3619 // See FieldMarshaler for details.
3620 //=======================================================================
3621 VOID FieldMarshaler_FixedArray::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3628 INJECT_FAULT(COMPlusThrowOM());
3629 PRECONDITION(CheckPointer(pNativeValue));
3630 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3634 // Allocate the value class array.
3635 *ppProtectedCLRValue = AllocateArrayEx(m_arrayType.GetValue(), (INT32*)&m_numElems, 1);
3637 // Marshal the contents from the native array to the managed array.
3638 const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(m_vt, TRUE);
3639 if (pMarshaler == NULL || pMarshaler->OleToComArray == NULL)
3641 memcpyNoGCRefs((*(BASEARRAYREF*)ppProtectedCLRValue)->GetDataPtr(), pNativeValue, NativeSize());
3645 MethodTable *pElementMT = m_arrayType.GetValue().AsArray()->GetArrayElementTypeHandle().GetMethodTable();
3646 pMarshaler->OleToComArray((VOID *)pNativeValue, (BASEARRAYREF*)ppProtectedCLRValue, pElementMT);
3650 //=======================================================================
3652 // See FieldMarshaler for details.
3653 //=======================================================================
3654 VOID FieldMarshaler_FixedArray::DestroyNativeImpl(LPVOID pNativeValue) const
3661 INJECT_FAULT(COMPlusThrowOM());
3662 PRECONDITION(CheckPointer(pNativeValue));
3666 const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(m_vt, FALSE);
3668 if (pMarshaler != NULL && pMarshaler->ClearOleArray != NULL)
3670 MethodTable *pElementMT = m_arrayType.GetValue().AsArray()->GetArrayElementTypeHandle().GetMethodTable();
3671 pMarshaler->ClearOleArray(pNativeValue, m_numElems, pElementMT);
3675 #endif // CROSSGEN_COMPILE
3678 //=======================================================================
3680 // See FieldMarshaler for details.
3681 //=======================================================================
3682 UINT32 FieldMarshaler_FixedArray::AlignmentRequirementImpl() const
3684 WRAPPER_NO_CONTRACT;
3686 UINT32 alignment = 0;
3687 TypeHandle elementType = m_arrayType.GetValue().AsArray()->GetArrayElementTypeHandle();
3700 alignment = elementType.GetMethodTable()->GetLayoutInfo()->GetLargestAlignmentRequirementOfAllMembers();
3704 alignment = OleVariant::GetElementSizeForVarType(m_vt, elementType.GetMethodTable());
3711 #ifndef CROSSGEN_COMPILE
3713 #ifdef FEATURE_CLASSIC_COMINTEROP
3714 //=======================================================================
3716 // See FieldMarshaler for details.
3717 //=======================================================================
3718 VOID FieldMarshaler_SafeArray::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3725 PRECONDITION(CheckPointer(pNativeValue));
3729 BASEARRAYREF pArray;
3730 *((OBJECTREF*)&pArray) = *pCLRValue;
3731 if ((pArray == NULL) || (OBJECTREFToObject(pArray) == NULL))
3733 FillMemory(pNativeValue, sizeof(LPSAFEARRAY*), 0);
3737 LPSAFEARRAY* pSafeArray;
3738 pSafeArray = (LPSAFEARRAY*)pNativeValue;
3741 MethodTable* pMT = m_pMT.GetValueMaybeNull();
3743 GCPROTECT_BEGIN(pArray)
3746 vt = OleVariant::GetElementVarTypeForArrayRef(pArray);
3749 pMT = OleVariant::GetArrayElementTypeWrapperAware(&pArray).GetMethodTable();
3751 // OleVariant calls throw on error.
3752 *pSafeArray = OleVariant::CreateSafeArrayForArrayRef(&pArray, vt, pMT);
3753 OleVariant::MarshalSafeArrayForArrayRef(&pArray, *pSafeArray, vt, pMT);
3759 //=======================================================================
3761 // See FieldMarshaler for details.
3762 //=======================================================================
3763 VOID FieldMarshaler_SafeArray::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3770 INJECT_FAULT(COMPlusThrowOM());
3771 PRECONDITION(CheckPointer(pNativeValue));
3772 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3776 LPSAFEARRAY* pSafeArray;
3777 pSafeArray = (LPSAFEARRAY*)pNativeValue;
3779 if ((pSafeArray == NULL) || (*pSafeArray == NULL))
3781 *ppProtectedCLRValue = NULL;
3786 MethodTable* pMT = m_pMT.GetValueMaybeNull();
3788 // If we have an empty vartype, get it from the safearray vartype
3791 if (FAILED(ClrSafeArrayGetVartype(*pSafeArray, &vt)))
3792 COMPlusThrow(kArgumentException, IDS_EE_INVALID_SAFEARRAY);
3795 // Get the method table if we need to.
3796 if ((vt == VT_RECORD) && (!pMT))
3797 pMT = OleVariant::GetElementTypeForRecordSafeArray(*pSafeArray).GetMethodTable();
3799 // If we have a single dimension safearray, it will be converted into a SZArray.
3800 // SZArray must have a lower bound of zero.
3801 LONG LowerBound = -1;
3802 UINT Dimensions = SafeArrayGetDim( (SAFEARRAY*)*pSafeArray );
3804 if (Dimensions == 1)
3806 HRESULT hr = SafeArrayGetLBound((SAFEARRAY*)*pSafeArray, 1, &LowerBound);
3807 if ( FAILED(hr) || LowerBound != 0)
3808 COMPlusThrow(kSafeArrayRankMismatchException, IDS_EE_SAFEARRAYSZARRAYMISMATCH);
3811 // OleVariant calls throw on error.
3812 *ppProtectedCLRValue = OleVariant::CreateArrayRefForSafeArray(*pSafeArray, vt, pMT);
3813 OleVariant::MarshalArrayRefForSafeArray(*pSafeArray, (BASEARRAYREF*)ppProtectedCLRValue, vt, pMT);
3817 //=======================================================================
3819 // See FieldMarshaler for details.
3820 //=======================================================================
3821 VOID FieldMarshaler_SafeArray::DestroyNativeImpl(LPVOID pNativeValue) const
3828 PRECONDITION(CheckPointer(pNativeValue));
3835 LPSAFEARRAY psa = (LPSAFEARRAY)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3836 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3840 _ASSERTE (GetModuleHandleA("oleaut32.dll") != NULL);
3841 // SafeArray has been created, which means oleaut32 should have been loaded.
3842 // Delay load will not fail.
3843 CONTRACT_VIOLATION(ThrowsViolation);
3844 hr = SafeArrayDestroy(psa);
3845 _ASSERTE(!FAILED(hr));
3848 #endif //FEATURE_CLASSIC_COMINTEROP
3851 //=======================================================================
3852 // function ptr <--> Delegate
3853 // See FieldMarshaler for details.
3854 //=======================================================================
3855 VOID FieldMarshaler_Delegate::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3862 PRECONDITION(CheckPointer(pNativeValue));
3866 LPVOID fnPtr = COMDelegate::ConvertToCallback(*pCLRValue);
3867 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, fnPtr);
3871 //=======================================================================
3872 // function ptr <--> Delegate
3873 // See FieldMarshaler for details.
3874 //=======================================================================
3875 VOID FieldMarshaler_Delegate::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3882 PRECONDITION(CheckPointer(pNativeValue));
3883 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3887 *ppProtectedCLRValue = COMDelegate::ConvertToDelegate((LPVOID)MAYBE_UNALIGNED_READ(pNativeValue, _PTR), GetMethodTable());
3891 //=======================================================================
3892 // SafeHandle <--> Handle
3893 // See FieldMarshaler for details.
3894 //=======================================================================
3895 VOID FieldMarshaler_SafeHandle::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3902 PRECONDITION(CheckPointer(pNativeValue));
3903 PRECONDITION(CheckPointer(ppCleanupWorkListOnStack, NULL_OK));
3907 SAFEHANDLE *pSafeHandleObj = ((SAFEHANDLE *)pCLRValue);
3909 // A cleanup list MUST be specified in order for us to be able to marshal
3911 if (ppCleanupWorkListOnStack == NULL)
3912 COMPlusThrow(kInvalidOperationException, IDS_EE_SH_FIELD_INVALID_OPERATION);
3914 if (*pSafeHandleObj == NULL)
3915 COMPlusThrow(kArgumentNullException, W("ArgumentNull_SafeHandle"));
3917 // Call StubHelpers.AddToCleanupList to AddRef and schedule Release on this SafeHandle
3918 // This is realiable, i.e. the cleanup will happen if and only if the SH was actually AddRef'ed.
3919 MethodDescCallSite AddToCleanupList(METHOD__STUBHELPERS__ADD_TO_CLEANUP_LIST);
3923 (ARG_SLOT)ppCleanupWorkListOnStack,
3924 ObjToArgSlot(*pSafeHandleObj)
3927 LPVOID handle = AddToCleanupList.Call_RetLPVOID(args);
3929 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, handle);
3933 //=======================================================================
3934 // SafeHandle <--> Handle
3935 // See FieldMarshaler for details.
3936 //=======================================================================
3937 VOID FieldMarshaler_SafeHandle::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3944 PRECONDITION(CheckPointer(pNativeValue));
3945 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3946 PRECONDITION(CheckPointer(ppProtectedOldCLRValue));
3950 // Since we dissallow marshaling SafeHandle fields from unmanaged to managed, check
3951 // to see if this handle was obtained from a SafeHandle and if it was that the
3952 // handle value hasn't changed.
3953 SAFEHANDLE *pSafeHandleObj = (SAFEHANDLE *)ppProtectedOldCLRValue;
3954 if (!*pSafeHandleObj || (*pSafeHandleObj)->GetHandle() != (LPVOID)MAYBE_UNALIGNED_READ(pNativeValue, _PTR))
3955 COMPlusThrow(kNotSupportedException, IDS_EE_CANNOT_CREATE_SAFEHANDLE_FIELD);
3957 // Now that we know the handle hasn't changed we just copy set the new SafeHandle
3959 *ppProtectedCLRValue = *ppProtectedOldCLRValue;
3963 //=======================================================================
3964 // CriticalHandle <--> Handle
3965 // See FieldMarshaler for details.
3966 //=======================================================================
3967 VOID FieldMarshaler_CriticalHandle::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3974 PRECONDITION(CheckPointer(pNativeValue));
3978 LPVOID handle = ((CRITICALHANDLE)*pCLRValue)->GetHandle();
3979 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, handle);
3983 //=======================================================================
3984 // CriticalHandle <--> Handle
3985 // See FieldMarshaler for details.
3986 //=======================================================================
3987 VOID FieldMarshaler_CriticalHandle::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3994 PRECONDITION(CheckPointer(pNativeValue));
3995 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3996 PRECONDITION(CheckPointer(ppProtectedOldCLRValue));
4000 // Since we dissallow marshaling CriticalHandle fields from unmanaged to managed, check
4001 // to see if this handle was obtained from a CriticalHandle and if it was that the
4002 // handle value hasn't changed.
4003 CRITICALHANDLE *pCriticalHandleObj = (CRITICALHANDLE *)ppProtectedOldCLRValue;
4004 if (!*pCriticalHandleObj || (*pCriticalHandleObj)->GetHandle() != (LPVOID)MAYBE_UNALIGNED_READ(pNativeValue, _PTR))
4005 COMPlusThrow(kNotSupportedException, IDS_EE_CANNOT_CREATE_CRITICALHANDLE_FIELD);
4007 // Now that we know the handle hasn't changed we just copy set the new CriticalHandle
4009 *ppProtectedCLRValue = *ppProtectedOldCLRValue;
4012 #ifdef FEATURE_COMINTEROP
4014 //=======================================================================
4015 // COM IP <--> interface
4016 // See FieldMarshaler for details.
4017 //=======================================================================
4018 VOID FieldMarshaler_Interface::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
4025 PRECONDITION(CheckPointer(pNativeValue));
4029 IUnknown *pUnk = NULL;
4031 if (!m_pItfMT.IsNull())
4033 pUnk = GetComIPFromObjectRef(pCLRValue, GetInterfaceMethodTable());
4035 else if (!(m_dwFlags & ItfMarshalInfo::ITF_MARSHAL_USE_BASIC_ITF))
4037 pUnk = GetComIPFromObjectRef(pCLRValue, GetMethodTable());
4041 ComIpType ReqIpType = !!(m_dwFlags & ItfMarshalInfo::ITF_MARSHAL_DISP_ITF) ? ComIpType_Dispatch : ComIpType_Unknown;
4042 pUnk = GetComIPFromObjectRef(pCLRValue, ReqIpType, NULL);
4045 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, pUnk);
4049 //=======================================================================
4050 // COM IP <--> interface
4051 // See FieldMarshaler for details.
4052 //=======================================================================
4053 VOID FieldMarshaler_Interface::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
4060 PRECONDITION(CheckPointer(pNativeValue));
4061 PRECONDITION(CheckPointer(ppProtectedCLRValue));
4062 PRECONDITION(IsProtectedByGCFrame(ppProtectedCLRValue));
4066 IUnknown *pUnk = (IUnknown*)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
4068 MethodTable *pItfMT = GetInterfaceMethodTable();
4069 if (pItfMT != NULL && !pItfMT->IsInterface())
4072 GetObjectRefFromComIP(
4073 ppProtectedCLRValue, // Created object
4074 pUnk, // Interface pointer
4075 GetMethodTable(), // Class MT
4076 pItfMT, // Interface MT
4077 (m_dwFlags & ItfMarshalInfo::ITF_MARSHAL_CLASS_IS_HINT) // Flags
4082 //=======================================================================
4083 // COM IP <--> interface
4084 // See FieldMarshaler for details.
4085 //=======================================================================
4086 VOID FieldMarshaler_Interface::DestroyNativeImpl(LPVOID pNativeValue) const
4093 PRECONDITION(CheckPointer(pNativeValue));
4097 IUnknown *pUnk = (IUnknown*)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
4098 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
4102 ULONG cbRef = SafeRelease(pUnk);
4103 LogInteropRelease(pUnk, cbRef, "Field marshaler destroy native");
4107 #endif // FEATURE_COMINTEROP
4110 //=======================================================================
4111 // See FieldMarshaler for details.
4112 //=======================================================================
4113 VOID FieldMarshaler_Date::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const
4120 PRECONDITION(CheckPointer(pCLR));
4121 PRECONDITION(CheckPointer(pNative));
4125 // <TODO> Handle unaligned native fields </TODO>
4126 *((DATE*)pNative) = COMDateTime::TicksToDoubleDate(*((INT64*)pCLR));
4130 //=======================================================================
4131 // See FieldMarshaler for details.
4132 //=======================================================================
4133 VOID FieldMarshaler_Date::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const
4140 PRECONDITION(CheckPointer(pNative));
4141 PRECONDITION(CheckPointer(pCLR));
4145 // <TODO> Handle unaligned native fields </TODO>
4146 *((INT64*)pCLR) = COMDateTime::DoubleDateToTicks(*((DATE*)pNative));
4150 #ifdef FEATURE_COMINTEROP
4152 //=======================================================================
4153 // See FieldMarshaler for details.
4154 //=======================================================================
4155 VOID FieldMarshaler_Currency::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const
4162 PRECONDITION(CheckPointer(pCLR));
4163 PRECONDITION(CheckPointer(pNative));
4167 // no need to switch to preemptive mode because it's very primitive operaion, doesn't take
4168 // long and is guaranteed not to call 3rd party code.
4169 // But if we do need to switch to preemptive mode, we can't pass the managed pointer to native code directly
4170 HRESULT hr = VarCyFromDec( (DECIMAL *)pCLR, (CURRENCY*)pNative);
4177 //=======================================================================
4178 // See FieldMarshaler for details.
4179 //=======================================================================
4180 VOID FieldMarshaler_Currency::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const
4187 PRECONDITION(CheckPointer(pNative));
4188 PRECONDITION(CheckPointer(pCLR));
4192 // no need to switch to preemptive mode because it's very primitive operaion, doesn't take
4193 // long and is guaranteed not to call 3rd party code.
4194 // But if we do need to switch to preemptive mode, we can't pass the managed pointer to native code directly
4195 HRESULT hr = VarDecFromCy( *(CURRENCY*)pNative, (DECIMAL *)pCLR );
4199 if (FAILED(DecimalCanonicalize((DECIMAL*)pCLR)))
4200 COMPlusThrow(kOverflowException, W("Overflow_Currency"));
4203 VOID FieldMarshaler_DateTimeOffset::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const
4210 PRECONDITION(CheckPointer(pCLR));
4211 PRECONDITION(CheckPointer(pNative));
4215 MethodDescCallSite convertToNative(METHOD__DATETIMEOFFSETMARSHALER__CONVERT_TO_NATIVE);
4219 PtrToArgSlot(pNative)
4221 convertToNative.Call(args);
4224 VOID FieldMarshaler_DateTimeOffset::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const
4231 PRECONDITION(CheckPointer(pNative));
4232 PRECONDITION(CheckPointer(pCLR));
4236 MethodDescCallSite convertToManaged(METHOD__DATETIMEOFFSETMARSHALER__CONVERT_TO_MANAGED);
4240 PtrToArgSlot(pNative)
4242 convertToManaged.Call(args);
4245 #endif // FEATURE_COMINTEROP
4248 //=======================================================================
4249 // See FieldMarshaler for details.
4250 //=======================================================================
4251 VOID FieldMarshaler_Illegal::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const
4258 PRECONDITION(CheckPointer(pCLR));
4259 PRECONDITION(CheckPointer(pNative));
4263 DefineFullyQualifiedNameForClassW();
4265 StackSString ssFieldName(SString::Utf8, GetFieldDesc()->GetName());
4267 StackSString errorString(W("Unknown error."));
4268 errorString.LoadResource(CCompRC::Error, m_resIDWhy);
4270 COMPlusThrow(kTypeLoadException, IDS_EE_BADMARSHALFIELD_ERROR_MSG,
4271 GetFullyQualifiedNameForClassW(GetFieldDesc()->GetEnclosingMethodTable()),
4272 ssFieldName.GetUnicode(), errorString.GetUnicode());
4276 //=======================================================================
4277 // See FieldMarshaler for details.
4278 //=======================================================================
4279 VOID FieldMarshaler_Illegal::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const
4286 PRECONDITION(CheckPointer(pNative));
4287 PRECONDITION(CheckPointer(pCLR));
4291 DefineFullyQualifiedNameForClassW();
4293 StackSString ssFieldName(SString::Utf8, GetFieldDesc()->GetName());
4295 StackSString errorString(W("Unknown error."));
4296 errorString.LoadResource(CCompRC::Error,m_resIDWhy);
4298 COMPlusThrow(kTypeLoadException, IDS_EE_BADMARSHALFIELD_ERROR_MSG,
4299 GetFullyQualifiedNameForClassW(GetFieldDesc()->GetEnclosingMethodTable()),
4300 ssFieldName.GetUnicode(), errorString.GetUnicode());
4303 #ifdef FEATURE_COMINTEROP
4306 //=======================================================================
4307 // See FieldMarshaler for details.
4308 //=======================================================================
4309 VOID FieldMarshaler_Variant::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
4316 PRECONDITION(CheckPointer(pNativeValue));
4320 OleVariant::MarshalOleVariantForObject(pCLRValue, (VARIANT*)pNativeValue);
4325 //=======================================================================
4326 // See FieldMarshaler for details.
4327 //=======================================================================
4328 VOID FieldMarshaler_Variant::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
4335 PRECONDITION(CheckPointer(pNativeValue));
4336 PRECONDITION(CheckPointer(ppProtectedCLRValue));
4340 OleVariant::MarshalObjectForOleVariant((VARIANT*)pNativeValue, ppProtectedCLRValue);
4344 //=======================================================================
4345 // See FieldMarshaler for details.
4346 //=======================================================================
4347 VOID FieldMarshaler_Variant::DestroyNativeImpl(LPVOID pNativeValue) const
4354 PRECONDITION(CheckPointer(pNativeValue));
4358 SafeVariantClear( (VARIANT*)pNativeValue );
4361 #endif // FEATURE_COMINTEROP
4365 #pragma warning(push)
4366 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
4368 VOID NStructFieldTypeToString(FieldMarshaler* pFM, SString& strNStructFieldType)
4375 INJECT_FAULT(COMPlusThrowOM());
4376 PRECONDITION(CheckPointer(pFM));
4380 NStructFieldType cls = pFM->GetNStructFieldType();
4382 CorElementType elemType = pFM->GetFieldDesc()->GetFieldType();
4384 // Some NStruct Field Types have extra information and require special handling.
4385 if (cls == NFT_FIXEDCHARARRAYANSI)
4387 strNStructFieldType.Printf(W("fixed array of ANSI char (size = %i bytes)"), pFM->NativeSize());
4390 else if (cls == NFT_FIXEDARRAY)
4392 VARTYPE vtElement = ((FieldMarshaler_FixedArray*)pFM)->GetElementVT();
4393 TypeHandle thElement = ((FieldMarshaler_FixedArray*)pFM)->GetElementTypeHandle();
4394 BOOL fElementTypeUserDefined = FALSE;
4396 // Determine if the array type is a user defined type.
4397 if (vtElement == VT_RECORD)
4399 fElementTypeUserDefined = TRUE;
4401 else if (vtElement == VT_UNKNOWN || vtElement == VT_DISPATCH)
4403 fElementTypeUserDefined = !thElement.IsObjectType();
4406 // Retrieve the string representation for the VARTYPE.
4407 StackSString strVarType;
4408 MarshalInfo::VarTypeToString(vtElement, strVarType);
4410 MethodTable *pMT = ((FieldMarshaler_FixedArray*)pFM)->GetElementTypeHandle().GetMethodTable();
4411 DefineFullyQualifiedNameForClassW();
4412 WCHAR* szClassName = (WCHAR*)GetFullyQualifiedNameForClassW(pMT);
4414 if (fElementTypeUserDefined)
4416 strNStructFieldType.Printf(W("fixed array of %s exposed as %s elements (array size = %i bytes)"),
4418 strVarType.GetUnicode(), pFM->NativeSize());
4422 strNStructFieldType.Printf(W("fixed array of %s (array size = %i bytes)"),
4423 szClassName, pFM->NativeSize());
4428 #ifdef FEATURE_COMINTEROP
4429 else if (cls == NFT_INTERFACE)
4431 MethodTable *pItfMT = NULL;
4434 ((FieldMarshaler_Interface*)pFM)->GetInterfaceInfo(&pItfMT, &dwFlags);
4436 if (dwFlags & ItfMarshalInfo::ITF_MARSHAL_DISP_ITF)
4438 strNStructFieldType.Set(W("IDispatch "));
4442 strNStructFieldType.Set(W("IUnknown "));
4445 if (dwFlags & ItfMarshalInfo::ITF_MARSHAL_USE_BASIC_ITF)
4447 strNStructFieldType.Append(W("(basic) "));
4453 DefineFullyQualifiedNameForClassW();
4454 GetFullyQualifiedNameForClassW(pItfMT);
4456 strNStructFieldType.Append(GetFullyQualifiedNameForClassW(pItfMT));
4461 #ifdef FEATURE_CLASSIC_COMINTEROP
4462 else if (cls == NFT_SAFEARRAY)
4464 VARTYPE vtElement = ((FieldMarshaler_SafeArray*)pFM)->GetElementVT();
4465 TypeHandle thElement = ((FieldMarshaler_SafeArray*)pFM)->GetElementTypeHandle();
4466 BOOL fElementTypeUserDefined = FALSE;
4468 // Determine if the array type is a user defined type.
4469 if (vtElement == VT_RECORD)
4471 fElementTypeUserDefined = TRUE;
4473 else if (vtElement == VT_UNKNOWN || vtElement == VT_DISPATCH)
4475 fElementTypeUserDefined = !thElement.IsObjectType();
4478 // Retrieve the string representation for the VARTYPE.
4479 StackSString strVarType;
4480 MarshalInfo::VarTypeToString(vtElement, strVarType);
4483 StackSString strClassName;
4484 if (!thElement.IsNull())
4486 DefineFullyQualifiedNameForClassW();
4487 MethodTable *pMT = ((FieldMarshaler_SafeArray*)pFM)->GetElementTypeHandle().GetMethodTable();
4488 strClassName.Set((WCHAR*)GetFullyQualifiedNameForClassW(pMT));
4492 strClassName.Set(W("object"));
4495 if (fElementTypeUserDefined)
4497 strNStructFieldType.Printf(W("safe array of %s exposed as %s elements (array size = %i bytes)"),
4498 strClassName.GetUnicode(),
4499 strVarType.GetUnicode(), pFM->NativeSize());
4503 strNStructFieldType.Printf(W("safearray of %s (array size = %i bytes)"),
4504 strClassName.GetUnicode(), pFM->NativeSize());
4509 #endif // FEATURE_CLASSIC_COMINTEROP
4510 #endif // FEATURE_COMINTEROP
4511 else if (cls == NFT_NESTEDLAYOUTCLASS)
4513 MethodTable *pMT = ((FieldMarshaler_NestedLayoutClass*)pFM)->GetMethodTable();
4514 DefineFullyQualifiedNameForClassW();
4515 strNStructFieldType.Printf(W("nested layout class %s"),
4516 GetFullyQualifiedNameForClassW(pMT));
4519 else if (cls == NFT_NESTEDVALUECLASS)
4521 MethodTable *pMT = ((FieldMarshaler_NestedValueClass*)pFM)->GetMethodTable();
4522 DefineFullyQualifiedNameForClassW();
4523 strNStructFieldType.Printf(W("nested value class %s"),
4524 GetFullyQualifiedNameForClassW(pMT));
4527 else if (cls == NFT_COPY1)
4529 // The following CorElementTypes are the only ones handled with FieldMarshaler_Copy1.
4532 case ELEMENT_TYPE_I1:
4533 strRetVal = W("SByte");
4536 case ELEMENT_TYPE_U1:
4537 strRetVal = W("Byte");
4541 strRetVal = W("Unknown");
4545 else if (cls == NFT_COPY2)
4547 // The following CorElementTypes are the only ones handled with FieldMarshaler_Copy2.
4550 case ELEMENT_TYPE_CHAR:
4551 strRetVal = W("Unicode char");
4554 case ELEMENT_TYPE_I2:
4555 strRetVal = W("Int16");
4558 case ELEMENT_TYPE_U2:
4559 strRetVal = W("UInt16");
4563 strRetVal = W("Unknown");
4567 else if (cls == NFT_COPY4)
4569 // The following CorElementTypes are the only ones handled with FieldMarshaler_Copy4.
4572 // At this point, ELEMENT_TYPE_I must be 4 bytes long. Same for ELEMENT_TYPE_U.
4573 case ELEMENT_TYPE_I:
4574 case ELEMENT_TYPE_I4:
4575 strRetVal = W("Int32");
4578 case ELEMENT_TYPE_U:
4579 case ELEMENT_TYPE_U4:
4580 strRetVal = W("UInt32");
4583 case ELEMENT_TYPE_R4:
4584 strRetVal = W("Single");
4587 case ELEMENT_TYPE_PTR:
4588 strRetVal = W("4-byte pointer");
4592 strRetVal = W("Unknown");
4596 else if (cls == NFT_COPY8)
4598 // The following CorElementTypes are the only ones handled with FieldMarshaler_Copy8.
4601 // At this point, ELEMENT_TYPE_I must be 8 bytes long. Same for ELEMENT_TYPE_U.
4602 case ELEMENT_TYPE_I:
4603 case ELEMENT_TYPE_I8:
4604 strRetVal = W("Int64");
4607 case ELEMENT_TYPE_U:
4608 case ELEMENT_TYPE_U8:
4609 strRetVal = W("UInt64");
4612 case ELEMENT_TYPE_R8:
4613 strRetVal = W("Double");
4616 case ELEMENT_TYPE_PTR:
4617 strRetVal = W("8-byte pointer");
4621 strRetVal = W("Unknown");
4625 else if (cls == NFT_FIXEDSTRINGUNI)
4627 int nativeSize = pFM->NativeSize();
4628 int strLength = nativeSize / sizeof(WCHAR);
4630 strNStructFieldType.Printf(W("embedded LPWSTR (length %d)"), strLength);
4634 else if (cls == NFT_FIXEDSTRINGANSI)
4636 int nativeSize = pFM->NativeSize();
4637 int strLength = nativeSize / sizeof(CHAR);
4639 strNStructFieldType.Printf(W("embedded LPSTR (length %d)"), strLength);
4645 // All other NStruct Field Types which do not require special handling.
4648 #ifdef FEATURE_COMINTEROP
4650 strRetVal = W("BSTR");
4653 strRetVal = W("HSTRING");
4655 #endif // FEATURE_COMINTEROP
4657 strRetVal = W("LPWSTR");
4659 case NFT_STRINGANSI:
4660 strRetVal = W("LPSTR");
4663 strRetVal = W("Delegate");
4665 #ifdef FEATURE_COMINTEROP
4667 strRetVal = W("VARIANT");
4669 #endif // FEATURE_COMINTEROP
4671 strRetVal = W("ANSI char");
4674 strRetVal = W("Windows Bool");
4677 strRetVal = W("CBool");
4680 strRetVal = W("DECIMAL");
4683 strRetVal = W("DATE");
4685 #ifdef FEATURE_COMINTEROP
4686 case NFT_VARIANTBOOL:
4687 strRetVal = W("VARIANT Bool");
4690 strRetVal = W("CURRENCY");
4692 #endif // FEATURE_COMINTEROP
4694 strRetVal = W("illegal type");
4696 case NFT_SAFEHANDLE:
4697 strRetVal = W("SafeHandle");
4699 case NFT_CRITICALHANDLE:
4700 strRetVal = W("CriticalHandle");
4703 strRetVal = W("<UNKNOWN>");
4708 strNStructFieldType.Set(strRetVal);
4713 #pragma warning(pop)
4716 #endif // CROSSGEN_COMPILE
4720 // Implementation of the virtual functions using switch statements.
4722 // We are not able bake pointers to the FieldMarshaller vtables into NGen images. We store
4723 // the field marshaller id instead, and implement the virtualization by switch based on the id.
4726 #ifdef FEATURE_CLASSIC_COMINTEROP
4727 #define FieldMarshaler_SafeArray_Case(rettype, name, args) case NFT_SAFEARRAY: rettype ((FieldMarshaler_SafeArray*)this)->name##Impl args; break;
4729 #define FieldMarshaler_SafeArray_Case(rettype, name, args)
4732 #ifdef FEATURE_COMINTEROP
4734 #define IMPLEMENT_FieldMarshaler_METHOD(ret, name, argsdecl, rettype, args) \
4735 ret FieldMarshaler::name argsdecl { \
4736 WRAPPER_NO_CONTRACT; \
4737 switch (GetNStructFieldType()) { \
4738 case NFT_STRINGUNI: rettype ((FieldMarshaler_StringUni*)this)->name##Impl args; break; \
4739 case NFT_STRINGANSI: rettype ((FieldMarshaler_StringAnsi*)this)->name##Impl args; break; \
4740 case NFT_STRINGUTF8: rettype ((FieldMarshaler_StringUtf8*)this)->name##Impl args; break; \
4741 case NFT_FIXEDSTRINGUNI: rettype ((FieldMarshaler_FixedStringUni*)this)->name##Impl args; break; \
4742 case NFT_FIXEDSTRINGANSI: rettype ((FieldMarshaler_FixedStringAnsi*)this)->name##Impl args; break; \
4743 case NFT_FIXEDCHARARRAYANSI: rettype ((FieldMarshaler_FixedCharArrayAnsi*)this)->name##Impl args; break; \
4744 case NFT_FIXEDARRAY: rettype ((FieldMarshaler_FixedArray*)this)->name##Impl args; break; \
4745 case NFT_DELEGATE: rettype ((FieldMarshaler_Delegate*)this)->name##Impl args; break; \
4746 case NFT_COPY1: rettype ((FieldMarshaler_Copy1*)this)->name##Impl args; break; \
4747 case NFT_COPY2: rettype ((FieldMarshaler_Copy2*)this)->name##Impl args; break; \
4748 case NFT_COPY4: rettype ((FieldMarshaler_Copy4*)this)->name##Impl args; break; \
4749 case NFT_COPY8: rettype ((FieldMarshaler_Copy8*)this)->name##Impl args; break; \
4750 case NFT_ANSICHAR: rettype ((FieldMarshaler_Ansi*)this)->name##Impl args; break; \
4751 case NFT_WINBOOL: rettype ((FieldMarshaler_WinBool*)this)->name##Impl args; break; \
4752 case NFT_NESTEDLAYOUTCLASS: rettype ((FieldMarshaler_NestedLayoutClass*)this)->name##Impl args; break; \
4753 case NFT_NESTEDVALUECLASS: rettype ((FieldMarshaler_NestedValueClass*)this)->name##Impl args; break; \
4754 case NFT_CBOOL: rettype ((FieldMarshaler_CBool*)this)->name##Impl args; break; \
4755 case NFT_DATE: rettype ((FieldMarshaler_Date*)this)->name##Impl args; break; \
4756 case NFT_DECIMAL: rettype ((FieldMarshaler_Decimal*)this)->name##Impl args; break; \
4757 case NFT_INTERFACE: rettype ((FieldMarshaler_Interface*)this)->name##Impl args; break; \
4758 case NFT_SAFEHANDLE: rettype ((FieldMarshaler_SafeHandle*)this)->name##Impl args; break; \
4759 case NFT_CRITICALHANDLE: rettype ((FieldMarshaler_CriticalHandle*)this)->name##Impl args; break; \
4760 FieldMarshaler_SafeArray_Case(rettype, name, args) \
4761 case NFT_BSTR: rettype ((FieldMarshaler_BSTR*)this)->name##Impl args; break; \
4762 case NFT_HSTRING: rettype ((FieldMarshaler_HSTRING*)this)->name##Impl args; break; \
4763 case NFT_VARIANT: rettype ((FieldMarshaler_Variant*)this)->name##Impl args; break; \
4764 case NFT_VARIANTBOOL: rettype ((FieldMarshaler_VariantBool*)this)->name##Impl args; break; \
4765 case NFT_CURRENCY: rettype ((FieldMarshaler_Currency*)this)->name##Impl args; break; \
4766 case NFT_DATETIMEOFFSET: rettype ((FieldMarshaler_DateTimeOffset*)this)->name##Impl args; break; \
4767 case NFT_SYSTEMTYPE: rettype ((FieldMarshaler_SystemType *)this)->name##Impl args; break; \
4768 case NFT_WINDOWSFOUNDATIONHRESULT: rettype ((FieldMarshaler_Exception*)this)->name##Impl args; break; \
4769 case NFT_WINDOWSFOUNDATIONIREFERENCE: rettype ((FieldMarshaler_Nullable*)this)->name##Impl args; break; \
4770 case NFT_ILLEGAL: rettype ((FieldMarshaler_Illegal*)this)->name##Impl args; break; \
4771 default: UNREACHABLE_MSG("unexpected type of FieldMarshaler"); break; \
4775 #else // FEATURE_COMINTEROP
4777 #define IMPLEMENT_FieldMarshaler_METHOD(ret, name, argsdecl, rettype, args) \
4778 ret FieldMarshaler::name argsdecl { \
4779 WRAPPER_NO_CONTRACT; \
4780 switch (GetNStructFieldType()) { \
4781 case NFT_STRINGUNI: rettype ((FieldMarshaler_StringUni*)this)->name##Impl args; break; \
4782 case NFT_STRINGANSI: rettype ((FieldMarshaler_StringAnsi*)this)->name##Impl args; break; \
4783 case NFT_STRINGUTF8: rettype ((FieldMarshaler_StringUtf8*)this)->name##Impl args; break; \
4784 case NFT_FIXEDSTRINGUNI: rettype ((FieldMarshaler_FixedStringUni*)this)->name##Impl args; break; \
4785 case NFT_FIXEDSTRINGANSI: rettype ((FieldMarshaler_FixedStringAnsi*)this)->name##Impl args; break; \
4786 case NFT_FIXEDCHARARRAYANSI: rettype ((FieldMarshaler_FixedCharArrayAnsi*)this)->name##Impl args; break; \
4787 case NFT_FIXEDARRAY: rettype ((FieldMarshaler_FixedArray*)this)->name##Impl args; break; \
4788 case NFT_DELEGATE: rettype ((FieldMarshaler_Delegate*)this)->name##Impl args; break; \
4789 case NFT_COPY1: rettype ((FieldMarshaler_Copy1*)this)->name##Impl args; break; \
4790 case NFT_COPY2: rettype ((FieldMarshaler_Copy2*)this)->name##Impl args; break; \
4791 case NFT_COPY4: rettype ((FieldMarshaler_Copy4*)this)->name##Impl args; break; \
4792 case NFT_COPY8: rettype ((FieldMarshaler_Copy8*)this)->name##Impl args; break; \
4793 case NFT_ANSICHAR: rettype ((FieldMarshaler_Ansi*)this)->name##Impl args; break; \
4794 case NFT_WINBOOL: rettype ((FieldMarshaler_WinBool*)this)->name##Impl args; break; \
4795 case NFT_NESTEDLAYOUTCLASS: rettype ((FieldMarshaler_NestedLayoutClass*)this)->name##Impl args; break; \
4796 case NFT_NESTEDVALUECLASS: rettype ((FieldMarshaler_NestedValueClass*)this)->name##Impl args; break; \
4797 case NFT_CBOOL: rettype ((FieldMarshaler_CBool*)this)->name##Impl args; break; \
4798 case NFT_DATE: rettype ((FieldMarshaler_Date*)this)->name##Impl args; break; \
4799 case NFT_DECIMAL: rettype ((FieldMarshaler_Decimal*)this)->name##Impl args; break; \
4800 case NFT_SAFEHANDLE: rettype ((FieldMarshaler_SafeHandle*)this)->name##Impl args; break; \
4801 case NFT_CRITICALHANDLE: rettype ((FieldMarshaler_CriticalHandle*)this)->name##Impl args; break; \
4802 case NFT_ILLEGAL: rettype ((FieldMarshaler_Illegal*)this)->name##Impl args; break; \
4803 default: UNREACHABLE_MSG("unexpected type of FieldMarshaler"); break; \
4807 #endif // FEATURE_COMINTEROP
4810 IMPLEMENT_FieldMarshaler_METHOD(UINT32, NativeSize,
4815 IMPLEMENT_FieldMarshaler_METHOD(UINT32, AlignmentRequirement,
4820 IMPLEMENT_FieldMarshaler_METHOD(BOOL, IsScalarMarshaler,
4825 IMPLEMENT_FieldMarshaler_METHOD(BOOL, IsNestedValueClassMarshaler,
4830 #ifndef CROSSGEN_COMPILE
4831 IMPLEMENT_FieldMarshaler_METHOD(VOID, UpdateNative,
4832 (OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const,
4834 (pCLRValue, pNativeValue, ppCleanupWorkListOnStack))
4836 IMPLEMENT_FieldMarshaler_METHOD(VOID, UpdateCLR,
4837 (const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const,
4839 (pNativeValue, ppProtectedCLRValue, ppProtectedOldCLRValue))
4841 IMPLEMENT_FieldMarshaler_METHOD(VOID, DestroyNative,
4842 (LPVOID pNativeValue) const,
4846 IMPLEMENT_FieldMarshaler_METHOD(VOID, ScalarUpdateNative,
4847 (LPVOID pCLR, LPVOID pNative) const,
4851 IMPLEMENT_FieldMarshaler_METHOD(VOID, ScalarUpdateCLR,
4852 (const VOID *pNative, LPVOID pCLR) const,
4856 IMPLEMENT_FieldMarshaler_METHOD(VOID, NestedValueClassUpdateNative,
4857 (const VOID **ppProtectedCLR, SIZE_T startoffset, LPVOID pNative, OBJECTREF *ppCleanupWorkListOnStack) const,
4859 (ppProtectedCLR, startoffset, pNative, ppCleanupWorkListOnStack))
4861 IMPLEMENT_FieldMarshaler_METHOD(VOID, NestedValueClassUpdateCLR,
4862 (const VOID *pNative, LPVOID *ppProtectedCLR, SIZE_T startoffset) const,
4864 (pNative, ppProtectedCLR, startoffset))
4865 #endif // CROSSGEN_COMPILE
4867 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
4868 IMPLEMENT_FieldMarshaler_METHOD(void, Save,
4873 IMPLEMENT_FieldMarshaler_METHOD(void, Fixup,
4877 #endif // FEATURE_NATIVE_IMAGE_GENERATION
4879 IMPLEMENT_FieldMarshaler_METHOD(void, Restore,
4884 #ifndef DACCESS_COMPILE
4885 IMPLEMENT_FieldMarshaler_METHOD(VOID, CopyTo,
4886 (VOID *pDest, SIZE_T destSize) const,
4889 #endif // !DACCESS_COMPILE