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 #ifdef _TARGET_64BIT_
500 INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ());
501 #else // !_TARGET_64BIT_
502 INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ());
503 #endif // !_TARGET_64BIT_
507 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I));
511 case ELEMENT_TYPE_R4:
512 if (fDefault || ntype == NATIVE_TYPE_R4)
514 INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ());
518 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_R4));
522 case ELEMENT_TYPE_R8:
523 if (fDefault || ntype == NATIVE_TYPE_R8)
525 INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ());
529 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_R8));
533 case ELEMENT_TYPE_PTR:
534 #ifdef FEATURE_COMINTEROP
537 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
540 #endif // FEATURE_COMINTEROP
543 #ifdef _TARGET_64BIT_
544 INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ());
545 #else // !_TARGET_64BIT_
546 INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ());
547 #endif // !_TARGET_64BIT_
551 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_PTR));
555 case ELEMENT_TYPE_VALUETYPE:
557 // This may cause a TypeLoadException, which we currently seem to have to swallow.
558 // This happens with structs that contain fields of class type where the class itself
559 // refers to the struct in a field.
560 TypeHandle thNestedType = GetFieldTypeHandleWorker(&fsig);
561 if (!thNestedType.GetMethodTable())
563 #ifdef FEATURE_COMINTEROP
564 if (fIsWinRT && sigElemType == ELEMENT_TYPE_GENERICINST)
566 // If this is a generic value type, lets see whether it is a Nullable<T>
567 TypeHandle genType = fsig.GetLastTypeHandleThrowing();
568 if(genType != NULL && genType.GetMethodTable()->HasSameTypeDefAs(g_pNullableClass))
570 // The generic type is System.Nullable<T>.
571 // Lets extract the typeArg and check if the typeArg is valid.
572 // typeArg is invalid if
573 // 1. It is not a value type.
575 // 3. We have an open type with us.
576 Instantiation inst = genType.GetMethodTable()->GetInstantiation();
577 MethodTable* typeArgMT = inst[0].GetMethodTable();
578 if (!typeArgMT->IsLegalNonArrayWinRTType())
580 // Type is not a valid WinRT value type.
581 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_NULLABLE_RESTRICTION));
585 INITFIELDMARSHALER(NFT_WINDOWSFOUNDATIONIREFERENCE, FieldMarshaler_Nullable, (genType.GetMethodTable()));
591 if (fsig.IsClass(g_DateClassName))
593 if (fDefault || ntype == NATIVE_TYPE_STRUCT)
595 INITFIELDMARSHALER(NFT_DATE, FieldMarshaler_Date, ());
599 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_DATETIME));
602 else if (fsig.IsClass(g_DecimalClassName))
604 if (fDefault || ntype == NATIVE_TYPE_STRUCT)
606 INITFIELDMARSHALER(NFT_DECIMAL, FieldMarshaler_Decimal, ());
608 #ifdef FEATURE_COMINTEROP
609 else if (ntype == NATIVE_TYPE_CURRENCY)
611 INITFIELDMARSHALER(NFT_CURRENCY, FieldMarshaler_Currency, ());
613 #endif // FEATURE_COMINTEROP
616 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_DECIMAL));
619 #ifdef FEATURE_COMINTEROP
620 else if (fsig.IsClass(g_DateTimeOffsetClassName))
622 if (fDefault || ntype == NATIVE_TYPE_STRUCT)
624 INITFIELDMARSHALER(NFT_DATETIMEOFFSET, FieldMarshaler_DateTimeOffset, ());
628 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_DATETIMEOFFSET));
631 else if (fIsWinRT && !thNestedType.GetMethodTable()->IsLegalNonArrayWinRTType())
633 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
635 #endif // FEATURE_COMINTEROP
636 else if (thNestedType.GetMethodTable()->HasLayout())
638 if (fDefault || ntype == NATIVE_TYPE_STRUCT)
640 if (IsStructMarshalable(thNestedType))
642 INITFIELDMARSHALER(NFT_NESTEDVALUECLASS, FieldMarshaler_NestedValueClass, (thNestedType.GetMethodTable()));
646 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_NOTMARSHALABLE));
651 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_VALUETYPE));
656 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_NOTMARSHALABLE));
661 case ELEMENT_TYPE_CLASS:
663 // This may cause a TypeLoadException, which we currently seem to have to swallow.
664 // This happens with structs that contain fields of class type where the class itself
665 // refers to the struct in a field.
666 TypeHandle thNestedType = GetFieldTypeHandleWorker(&fsig);
667 if (!thNestedType.GetMethodTable())
670 if (thNestedType.GetMethodTable()->IsObjectClass())
672 #ifdef FEATURE_COMINTEROP
673 if (fDefault || ntype == NATIVE_TYPE_IUNKNOWN || ntype == NATIVE_TYPE_IDISPATCH || ntype == NATIVE_TYPE_INTF)
675 // Only NATIVE_TYPE_IDISPATCH maps to an IDispatch based interface pointer.
676 DWORD dwFlags = ItfMarshalInfo::ITF_MARSHAL_USE_BASIC_ITF;
677 if (ntype == NATIVE_TYPE_IDISPATCH)
679 dwFlags |= ItfMarshalInfo::ITF_MARSHAL_DISP_ITF;
681 INITFIELDMARSHALER(NFT_INTERFACE, FieldMarshaler_Interface, (NULL, NULL, dwFlags));
683 else if (ntype == NATIVE_TYPE_STRUCT)
685 INITFIELDMARSHALER(NFT_VARIANT, FieldMarshaler_Variant, ());
687 #else // FEATURE_COMINTEROP
688 if (fDefault || ntype == NATIVE_TYPE_IUNKNOWN || ntype == NATIVE_TYPE_IDISPATCH || ntype == NATIVE_TYPE_INTF)
690 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_OBJECT_TO_ITF_NOT_SUPPORTED));
692 else if (ntype == NATIVE_TYPE_STRUCT)
694 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_OBJECT_TO_VARIANT_NOT_SUPPORTED));
696 #endif // FEATURE_COMINTEROP
699 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_OBJECT));
702 #ifdef FEATURE_COMINTEROP
703 else if (ntype == NATIVE_TYPE_INTF || thNestedType.IsInterface())
705 if (fIsWinRT && !thNestedType.GetMethodTable()->IsLegalNonArrayWinRTType())
707 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
711 ItfMarshalInfo itfInfo;
712 if (FAILED(MarshalInfo::TryGetItfMarshalInfo(thNestedType, FALSE, FALSE, &itfInfo)))
715 INITFIELDMARSHALER(NFT_INTERFACE, FieldMarshaler_Interface, (itfInfo.thClass.GetMethodTable(), itfInfo.thItf.GetMethodTable(), itfInfo.dwFlags));
718 #else // FEATURE_COMINTEROP
719 else if (ntype == NATIVE_TYPE_INTF || thNestedType.IsInterface())
721 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_OBJECT_TO_ITF_NOT_SUPPORTED));
723 #endif // FEATURE_COMINTEROP
724 else if (ntype == NATIVE_TYPE_CUSTOMMARSHALER)
726 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_NOCUSTOMMARSH));
728 else if (thNestedType == TypeHandle(g_pStringClass))
732 #ifdef FEATURE_COMINTEROP
735 INITFIELDMARSHALER(NFT_HSTRING, FieldMarshaler_HSTRING, ());
738 #endif // FEATURE_COMINTEROP
741 ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
742 INITFIELDMARSHALER(NFT_STRINGANSI, FieldMarshaler_StringAnsi, (BestFit, ThrowOnUnmappableChar));
746 INITFIELDMARSHALER(NFT_STRINGUNI, FieldMarshaler_StringUni, ());
753 case NATIVE_TYPE_LPSTR:
754 ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
755 INITFIELDMARSHALER(NFT_STRINGANSI, FieldMarshaler_StringAnsi, (BestFit, ThrowOnUnmappableChar));
758 case NATIVE_TYPE_LPWSTR:
759 INITFIELDMARSHALER(NFT_STRINGUNI, FieldMarshaler_StringUni, ());
762 case NATIVE_TYPE_LPUTF8STR:
763 INITFIELDMARSHALER(NFT_STRINGUTF8, FieldMarshaler_StringUtf8, ());
766 case NATIVE_TYPE_LPTSTR:
767 // We no longer support Win9x so LPTSTR always maps to a Unicode string.
768 INITFIELDMARSHALER(NFT_STRINGUNI, FieldMarshaler_StringUni, ());
770 #ifdef FEATURE_COMINTEROP
771 case NATIVE_TYPE_BSTR:
772 INITFIELDMARSHALER(NFT_BSTR, FieldMarshaler_BSTR, ());
775 case NATIVE_TYPE_HSTRING:
776 INITFIELDMARSHALER(NFT_HSTRING, FieldMarshaler_HSTRING, ());
778 #endif // FEATURE_COMINTEROP
779 case NATIVE_TYPE_FIXEDSYSSTRING:
782 ULONG udatasize = CorSigUncompressedDataSize(pNativeType);
784 if (cbNativeType < udatasize)
787 nchars = CorSigUncompressData(pNativeType);
788 cbNativeType -= udatasize;
792 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_ZEROLENGTHFIXEDSTRING));
798 ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
799 INITFIELDMARSHALER(NFT_FIXEDSTRINGANSI, FieldMarshaler_FixedStringAnsi, (nchars, BestFit, ThrowOnUnmappableChar));
803 INITFIELDMARSHALER(NFT_FIXEDSTRINGUNI, FieldMarshaler_FixedStringUni, (nchars));
809 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_STRING));
814 #ifdef FEATURE_COMINTEROP
815 else if (fIsWinRT && fsig.IsClass(g_TypeClassName))
816 { // Note: If the System.Type field is in non-WinRT struct, do not change the previously shipped behavior
817 INITFIELDMARSHALER(NFT_SYSTEMTYPE, FieldMarshaler_SystemType, ());
819 else if (fIsWinRT && fsig.IsClass(g_ExceptionClassName)) // Marshal Windows.Foundation.HResult as System.Exception for WinRT.
821 INITFIELDMARSHALER(NFT_WINDOWSFOUNDATIONHRESULT, FieldMarshaler_Exception, ());
823 #endif //FEATURE_COMINTEROP
824 #ifdef FEATURE_CLASSIC_COMINTEROP
825 else if (thNestedType.GetMethodTable() == g_pArrayClass)
827 if (ntype == NATIVE_TYPE_SAFEARRAY)
829 NativeTypeParamInfo ParamInfo;
830 CorElementType etyp = ELEMENT_TYPE_OBJECT;
831 MethodTable* pMT = NULL;
832 VARTYPE vtElement = VT_EMPTY;
834 // Compat: If no safe array used def subtype was specified, we assume TypeOf(Object).
835 TypeHandle thElement = TypeHandle(g_pObjectClass);
837 // If we have no native type data, assume default behavior
838 if (S_OK != CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
840 INITFIELDMARSHALER(NFT_SAFEARRAY, FieldMarshaler_SafeArray, (VT_EMPTY, NULL));
844 vtElement = (VARTYPE) (CorSigUncompressData(/*modifies*/pNativeType));
846 // Extract the name of the record type's.
847 if (S_OK == CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
850 if (FAILED(CPackedLen::SafeGetData(pNativeType, pNativeTypeStart + cbNativeTypeStart, &strLen, &pNativeType)))
852 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_BADMETADATA));
857 // Load the type. Use a SString for the string since we need to NULL terminate the string
858 // that comes from the metadata.
859 StackSString safeArrayUserDefTypeName(SString::Utf8, (LPCUTF8)pNativeType, strLen);
860 _ASSERTE((ULONG)(pNativeType + strLen - pNativeTypeStart) == cbNativeTypeStart);
862 // Sadly this may cause a TypeLoadException, which we currently have to swallow.
863 // This happens with structs that contain fields of class type where the class itself
864 // refers to the struct in a field.
865 thElement = ArraySubTypeLoadWorker(safeArrayUserDefTypeName, pModule->GetAssembly());
866 if (thElement.IsNull())
871 ArrayMarshalInfo arrayMarshalInfo(amiRuntime);
872 arrayMarshalInfo.InitForSafeArray(MarshalInfo::MARSHAL_SCENARIO_FIELD, thElement, vtElement, fAnsi);
874 if (!arrayMarshalInfo.IsValid())
876 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (arrayMarshalInfo.GetErrorResourceId()));
880 INITFIELDMARSHALER(NFT_SAFEARRAY, FieldMarshaler_SafeArray, (arrayMarshalInfo.GetElementVT(), arrayMarshalInfo.GetElementTypeHandle().GetMethodTable()));
882 else if (ntype == NATIVE_TYPE_FIXEDARRAY)
884 // Check for the number of elements. This is required, if not present fail.
885 if (S_OK != CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
887 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_FIXEDARRAY_NOSIZE));
891 ULONG numElements = CorSigUncompressData(/*modifies*/pNativeType);
893 if (numElements == 0)
895 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_FIXEDARRAY_ZEROSIZE));
899 // Since these always export to arrays of BSTRs, we don't need to fetch the native type.
901 // Compat: FixedArrays of System.Arrays map to fixed arrays of BSTRs.
902 INITFIELDMARSHALER(NFT_FIXEDARRAY, FieldMarshaler_FixedArray, (pInternalImport, cl, numElements, VT_BSTR, g_pStringClass));
905 #endif // FEATURE_CLASSIC_COMINTEROP
906 else if (COMDelegate::IsDelegate(thNestedType.GetMethodTable()))
908 if (fDefault || ntype == NATIVE_TYPE_FUNC)
910 INITFIELDMARSHALER(NFT_DELEGATE, FieldMarshaler_Delegate, (thNestedType.GetMethodTable()));
914 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_DELEGATE));
917 else if (thNestedType.CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__SAFE_HANDLE))))
921 INITFIELDMARSHALER(NFT_SAFEHANDLE, FieldMarshaler_SafeHandle, ());
925 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_SAFEHANDLE));
928 else if (thNestedType.CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__CRITICAL_HANDLE))))
932 INITFIELDMARSHALER(NFT_CRITICALHANDLE, FieldMarshaler_CriticalHandle, ());
936 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_CRITICALHANDLE));
939 else if (fsig.IsClass(g_StringBufferClassName))
941 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_NOSTRINGBUILDER));
943 else if (IsStructMarshalable(thNestedType))
945 if (fDefault || ntype == NATIVE_TYPE_STRUCT)
947 INITFIELDMARSHALER(NFT_NESTEDLAYOUTCLASS, FieldMarshaler_NestedLayoutClass, (thNestedType.GetMethodTable()));
951 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_LAYOUTCLASS));
954 #ifdef FEATURE_COMINTEROP
957 // no other reference types are allowed as field types in WinRT
958 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
962 ItfMarshalInfo itfInfo;
963 if (FAILED(MarshalInfo::TryGetItfMarshalInfo(thNestedType, FALSE, FALSE, &itfInfo)))
965 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_BADMANAGED));
969 INITFIELDMARSHALER(NFT_INTERFACE, FieldMarshaler_Interface, (itfInfo.thClass.GetMethodTable(), itfInfo.thItf.GetMethodTable(), itfInfo.dwFlags));
972 #endif // FEATURE_COMINTEROP
976 case ELEMENT_TYPE_SZARRAY:
977 case ELEMENT_TYPE_ARRAY:
979 #ifdef FEATURE_COMINTEROP
982 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
985 #endif // FEATURE_COMINTEROP
987 // This may cause a TypeLoadException, which we currently seem to have to swallow.
988 // This happens with structs that contain fields of class type where the class itself
989 // refers to the struct in a field.
990 TypeHandle thArray = GetFieldTypeHandleWorker(&fsig);
991 if (thArray.IsNull() || !thArray.IsArray())
994 TypeHandle thElement = thArray.AsArray()->GetArrayElementTypeHandle();
995 if (thElement.IsNull())
998 if (ntype == NATIVE_TYPE_FIXEDARRAY)
1000 CorNativeType elementNativeType = NATIVE_TYPE_DEFAULT;
1002 // The size constant must be specified, if it isn't then the struct can't be marshalled.
1003 if (S_OK != CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
1005 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_FIXEDARRAY_NOSIZE));
1009 // Read the size const, if it's 0, then the struct can't be marshalled.
1010 ULONG numElements = CorSigUncompressData(pNativeType);
1011 if (numElements == 0)
1013 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_FIXEDARRAY_ZEROSIZE));
1017 // The array sub type is optional so extract it if specified.
1018 if (S_OK == CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
1019 elementNativeType = (CorNativeType)CorSigUncompressData(pNativeType);
1021 ArrayMarshalInfo arrayMarshalInfo(amiRuntime);
1022 arrayMarshalInfo.InitForFixedArray(thElement, elementNativeType, fAnsi);
1024 if (!arrayMarshalInfo.IsValid())
1026 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (arrayMarshalInfo.GetErrorResourceId()));
1030 if (arrayMarshalInfo.GetElementVT() == VTHACK_ANSICHAR)
1032 // We need to special case fixed sized arrays of ANSI chars since the OleVariant code
1033 // that is used by the generic fixed size array marshaller doesn't support them
1035 ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
1036 INITFIELDMARSHALER(NFT_FIXEDCHARARRAYANSI, FieldMarshaler_FixedCharArrayAnsi, (numElements, BestFit, ThrowOnUnmappableChar));
1041 VARTYPE elementVT = arrayMarshalInfo.GetElementVT();
1043 INITFIELDMARSHALER(NFT_FIXEDARRAY, FieldMarshaler_FixedArray, (pInternalImport, cl, numElements, elementVT, arrayMarshalInfo.GetElementTypeHandle().GetMethodTable()));
1047 #ifdef FEATURE_CLASSIC_COMINTEROP
1048 else if (fDefault || ntype == NATIVE_TYPE_SAFEARRAY)
1050 VARTYPE vtElement = VT_EMPTY;
1052 // Check for data remaining in the signature before we attempt to grab some.
1053 if (S_OK == CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
1054 vtElement = (VARTYPE) (CorSigUncompressData(/*modifies*/pNativeType));
1056 ArrayMarshalInfo arrayMarshalInfo(amiRuntime);
1057 arrayMarshalInfo.InitForSafeArray(MarshalInfo::MARSHAL_SCENARIO_FIELD, thElement, vtElement, fAnsi);
1059 if (!arrayMarshalInfo.IsValid())
1061 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (arrayMarshalInfo.GetErrorResourceId()));
1065 INITFIELDMARSHALER(NFT_SAFEARRAY, FieldMarshaler_SafeArray, (arrayMarshalInfo.GetElementVT(), arrayMarshalInfo.GetElementTypeHandle().GetMethodTable()));
1067 #endif //FEATURE_CLASSIC_COMINTEROP
1070 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_ARRAY));
1075 case ELEMENT_TYPE_OBJECT:
1076 case ELEMENT_TYPE_STRING:
1080 // let it fall thru as NFT_NONE
1084 if (pfwalk->m_nft == NFT_NONE)
1086 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_BADMANAGED));
1088 #ifdef FEATURE_COMINTEROP
1089 else if (fIsWinRT && !NFTDataBase[pfwalk->m_nft].m_fWinRTSupported)
1091 // the field marshaler we came up with is not supported in WinRT scenarios
1092 ZeroMemory(&pfwalk->m_FieldMarshaler, MAXFIELDMARSHALERSIZE);
1093 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
1095 #endif // FEATURE_COMINTEROP
1096 #undef INITFIELDMARSHALER
1099 #pragma warning(pop)
1103 TypeHandle ArraySubTypeLoadWorker(const SString &strUserDefTypeName, Assembly* pAssembly)
1110 PRECONDITION(CheckPointer(pAssembly));
1118 // Load the user defined type.
1119 StackScratchBuffer utf8Name;
1120 th = TypeName::GetTypeUsingCASearchRules(strUserDefTypeName.GetUTF8(utf8Name), pAssembly);
1125 EX_END_CATCH(RethrowTerminalExceptions)
1131 TypeHandle GetFieldTypeHandleWorker(MetaSig *pFieldSig)
1138 PRECONDITION(CheckPointer(pFieldSig));
1146 // Load the user defined type.
1147 th = pFieldSig->GetLastTypeHandleThrowing(ClassLoader::LoadTypes,
1148 CLASS_LOAD_APPROXPARENTS,
1149 TRUE /*dropGenericArgumentLevel*/);
1154 EX_END_CATCH(RethrowTerminalExceptions)
1160 //=======================================================================
1161 // This function returns TRUE if the type passed in is either a value class or a class and if it has layout information
1162 // and is marshalable. In all other cases it will return FALSE.
1163 //=======================================================================
1164 BOOL IsStructMarshalable(TypeHandle th)
1172 PRECONDITION(!th.IsNull());
1176 if (th.IsBlittable())
1178 // th.IsBlittable will return true for arrays of blittable types, however since IsStructMarshalable
1179 // is only supposed to return true for value classes or classes with layout that are marshallable
1180 // we need to return false if the type is an array.
1187 // Check to see if the type has layout.
1188 if (!th.HasLayout())
1191 MethodTable *pMT= th.GetMethodTable();
1192 PREFIX_ASSUME(pMT != NULL);
1194 if (pMT->IsStructMarshalable())
1197 const FieldMarshaler *pFieldMarshaler = pMT->GetLayoutInfo()->GetFieldMarshalers();
1198 UINT numReferenceFields = pMT->GetLayoutInfo()->GetNumCTMFields();
1200 while (numReferenceFields--)
1202 if (pFieldMarshaler->GetNStructFieldType() == NFT_ILLEGAL)
1205 ((BYTE*&)pFieldMarshaler) += MAXFIELDMARSHALERSIZE;
1212 //=======================================================================
1213 // Called from the clsloader to load up and summarize the field metadata
1214 // for layout classes.
1216 // Warning: This function can load other classes (esp. for nested structs.)
1217 //=======================================================================
1219 #pragma warning(push)
1220 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
1222 VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing(
1223 mdTypeDef cl, // cl of the NStruct being loaded
1224 BYTE packingSize, // packing size (from @dll.struct)
1225 BYTE nlType, // nltype (from @dll.struct)
1226 #ifdef FEATURE_COMINTEROP
1227 BOOL isWinRT, // Is the type a WinRT type
1228 #endif // FEATURE_COMINTEROP
1229 BOOL fExplicitOffsets, // explicit offsets?
1230 MethodTable *pParentMT, // the loaded superclass
1231 ULONG cMembers, // total number of members (methods + fields)
1232 HENUMInternal *phEnumField, // enumerator for field
1233 Module *pModule, // Module that defines the scope, loader and heap (for allocate FieldMarshalers)
1234 const SigTypeContext *pTypeContext, // Type parameters for NStruct being loaded
1235 EEClassLayoutInfo *pEEClassLayoutInfoOut, // caller-allocated structure to fill in.
1236 LayoutRawFieldInfo *pInfoArrayOut, // caller-allocated array to fill in. Needs room for cMember+1 elements
1237 LoaderAllocator *pAllocator,
1238 AllocMemTracker *pamTracker
1246 INJECT_FAULT(COMPlusThrowOM());
1247 PRECONDITION(CheckPointer(pModule));
1252 MD_CLASS_LAYOUT classlayout;
1257 // Running tote - if anything in this type disqualifies it from being ManagedSequential, somebody will set this to TRUE by the the time
1259 BOOL fDisqualifyFromManagedSequential = FALSE;
1261 // Internal interface for the NStruct being loaded.
1262 IMDInternalImport *pInternalImport = pModule->GetMDImport();
1267 LPCUTF8 szNamespace;
1268 if (FAILED(pInternalImport->GetNameOfTypeDef(cl, &szName, &szNamespace)))
1270 szName = szNamespace = "Invalid TypeDef record";
1273 if (g_pConfig->ShouldBreakOnStructMarshalSetup(szName))
1274 CONSISTENCY_CHECK_MSGF(false, ("BreakOnStructMarshalSetup: '%s' ", szName));
1278 // Check if this type might be ManagedSequential. Only valuetypes marked Sequential can be
1279 // ManagedSequential. Other issues checked below might also disqualify the type.
1280 if ( (!fExplicitOffsets) && // Is it marked sequential?
1281 (pParentMT && (pParentMT->IsValueTypeClass() || pParentMT->IsManagedSequential())) // Is it a valuetype or derived from a qualifying valuetype?
1284 // Type qualifies so far... need do nothing.
1288 fDisqualifyFromManagedSequential = TRUE;
1292 BOOL fHasNonTrivialParent = pParentMT &&
1293 !pParentMT->IsObjectClass() &&
1294 !pParentMT->IsValueTypeClass();
1297 //====================================================================
1298 // First, some validation checks.
1299 //====================================================================
1300 _ASSERTE(!(fHasNonTrivialParent && !(pParentMT->HasLayout())));
1302 hr = pInternalImport->GetClassLayoutInit(cl, &classlayout);
1305 COMPlusThrowHR(hr, BFA_CANT_GET_CLASSLAYOUT);
1308 pEEClassLayoutInfoOut->m_numCTMFields = fHasNonTrivialParent ? pParentMT->GetLayoutInfo()->m_numCTMFields : 0;
1309 pEEClassLayoutInfoOut->SetFieldMarshalers(NULL);
1310 pEEClassLayoutInfoOut->SetIsBlittable(TRUE);
1311 if (fHasNonTrivialParent)
1312 pEEClassLayoutInfoOut->SetIsBlittable(pParentMT->IsBlittable());
1313 pEEClassLayoutInfoOut->SetIsZeroSized(FALSE);
1314 pEEClassLayoutInfoOut->SetHasExplicitSize(FALSE);
1315 pEEClassLayoutInfoOut->m_cbPackingSize = packingSize;
1317 LayoutRawFieldInfo *pfwalk = pInfoArrayOut;
1319 S_UINT32 cbSortArraySize = S_UINT32(cMembers) * S_UINT32(sizeof(LayoutRawFieldInfo *));
1320 if (cbSortArraySize.IsOverflow())
1322 ThrowHR(COR_E_TYPELOAD);
1324 LayoutRawFieldInfo **pSortArray = (LayoutRawFieldInfo **)_alloca(cbSortArraySize.Value());
1325 LayoutRawFieldInfo **pSortArrayEnd = pSortArray;
1327 ULONG maxRid = pInternalImport->GetCountWithTokenKind(mdtFieldDef);
1330 //=====================================================================
1331 // Phase 1: Figure out the NFT of each field based on both the CLR
1332 // signature of the field and the FieldMarshaler metadata.
1333 //=====================================================================
1334 BOOL fParentHasLayout = pParentMT && pParentMT->HasLayout();
1335 UINT32 cbAdjustedParentLayoutNativeSize = 0;
1336 EEClassLayoutInfo *pParentLayoutInfo = NULL;;
1337 if (fParentHasLayout)
1339 pParentLayoutInfo = pParentMT->GetLayoutInfo();
1340 // Treat base class as an initial member.
1341 cbAdjustedParentLayoutNativeSize = pParentLayoutInfo->GetNativeSize();
1342 // If the parent was originally a zero-sized explicit type but
1343 // got bumped up to a size of 1 for compatibility reasons, then
1344 // we need to remove the padding, but ONLY for inheritance situations.
1345 if (pParentLayoutInfo->IsZeroSized()) {
1346 CONSISTENCY_CHECK(cbAdjustedParentLayoutNativeSize == 1);
1347 cbAdjustedParentLayoutNativeSize = 0;
1352 for (i = 0; pInternalImport->EnumNext(phEnumField, &fd); i++)
1355 ULONG rid = RidFromToken(fd);
1357 if((rid == 0)||(rid > maxRid))
1359 COMPlusThrowHR(COR_E_TYPELOAD, BFA_BAD_FIELD_TOKEN);
1362 IfFailThrow(pInternalImport->GetFieldDefProps(fd, &dwFieldAttrs));
1364 PCCOR_SIGNATURE pNativeType = NULL;
1366 // We ignore marshaling data attached to statics and literals,
1367 // since these do not contribute to instance data.
1368 if (!IsFdStatic(dwFieldAttrs) && !IsFdLiteral(dwFieldAttrs))
1370 PCCOR_SIGNATURE pCOMSignature;
1371 ULONG cbCOMSignature;
1373 if (IsFdHasFieldMarshal(dwFieldAttrs))
1375 hr = pInternalImport->GetFieldMarshal(fd, &pNativeType, &cbNativeType);
1382 IfFailThrow(pInternalImport->GetSigOfFieldDef(fd,&cbCOMSignature, &pCOMSignature));
1384 IfFailThrow(::validateTokenSig(fd,pCOMSignature,cbCOMSignature,dwFieldAttrs,pInternalImport));
1386 // fill the appropriate entry in pInfoArrayOut
1388 pfwalk->m_nft = NULL;
1389 pfwalk->m_offset = (UINT32) -1;
1390 pfwalk->m_sequence = 0;
1393 LPCUTF8 szFieldName;
1394 if (FAILED(pInternalImport->GetNameOfFieldDef(fd, &szFieldName)))
1396 szFieldName = "Invalid FieldDef record";
1400 ParseNativeTypeFlags flags = ParseNativeTypeFlag_None;
1401 #ifdef FEATURE_COMINTEROP
1403 flags |= ParseNativeTypeFlag_IsWinRT;
1404 else // WinRT types have nlType == nltAnsi but should be treated as Unicode
1405 #endif // FEATURE_COMINTEROP
1406 if (nlType == nltAnsi)
1407 flags |= ParseNativeTypeFlag_IsAnsi;
1409 ParseNativeType(pModule,
1419 &fDisqualifyFromManagedSequential
1429 //<TODO>@nice: This is obviously not the place to bury this logic.
1430 // We're replacing NFT's with MARSHAL_TYPES_* in the near future
1431 // so this isn't worth perfecting.</TODO>
1433 BOOL resetBlittable = TRUE;
1435 // if it's a simple copy...
1436 if (pfwalk->m_nft == NFT_COPY1 ||
1437 pfwalk->m_nft == NFT_COPY2 ||
1438 pfwalk->m_nft == NFT_COPY4 ||
1439 pfwalk->m_nft == NFT_COPY8)
1441 resetBlittable = FALSE;
1444 // Or if it's a nested value class that is itself blittable...
1445 if (pfwalk->m_nft == NFT_NESTEDVALUECLASS)
1447 FieldMarshaler *pFM = (FieldMarshaler*)&(pfwalk->m_FieldMarshaler);
1448 _ASSERTE(pFM->IsNestedValueClassMarshaler());
1450 if (((FieldMarshaler_NestedValueClass *) pFM)->IsBlittable())
1451 resetBlittable = FALSE;
1454 // ...Otherwise, this field prevents blitting
1456 pEEClassLayoutInfoOut->SetIsBlittable(FALSE);
1463 _ASSERTE(i == cMembers);
1465 // NULL out the last entry
1466 pfwalk->m_MD = mdFieldDefNil;
1470 // fill in the layout information
1473 // pfwalk points to the beginging of the array
1474 pfwalk = pInfoArrayOut;
1476 while (SUCCEEDED(hr = pInternalImport->GetClassLayoutNext(
1480 fd != mdFieldDefNil)
1482 // watch for the last entry: must be mdFieldDefNil
1483 while ((mdFieldDefNil != pfwalk->m_MD)&&(pfwalk->m_MD < fd))
1486 // if we haven't found a matching token, it must be a static field with layout -- ignore it
1487 if(pfwalk->m_MD != fd) continue;
1489 if (!fExplicitOffsets)
1491 // ulOffset is the sequence
1492 pfwalk->m_sequence = ulOffset;
1496 // ulOffset is the explicit offset
1497 pfwalk->m_offset = ulOffset;
1498 pfwalk->m_sequence = (ULONG) -1;
1500 // Treat base class as an initial member.
1501 if (!SafeAddUINT32(&(pfwalk->m_offset), cbAdjustedParentLayoutNativeSize))
1507 // now sort the array
1508 if (!fExplicitOffsets)
1510 // sort sequential by ascending sequence
1511 for (i = 0; i < cFields; i++)
1513 LayoutRawFieldInfo**pSortWalk = pSortArrayEnd;
1514 while (pSortWalk != pSortArray)
1516 if (pInfoArrayOut[i].m_sequence >= (*(pSortWalk-1))->m_sequence)
1522 // pSortWalk now points to the target location for new FieldInfo.
1523 MoveMemory(pSortWalk + 1, pSortWalk, (pSortArrayEnd - pSortWalk) * sizeof(LayoutRawFieldInfo*));
1524 *pSortWalk = &pInfoArrayOut[i];
1528 else // no sorting for explicit layout
1530 for (i = 0; i < cFields; i++)
1532 if(pInfoArrayOut[i].m_MD != mdFieldDefNil)
1534 if (pInfoArrayOut[i].m_offset == (UINT32)-1)
1536 LPCUTF8 szFieldName;
1537 if (FAILED(pInternalImport->GetNameOfFieldDef(pInfoArrayOut[i].m_MD, &szFieldName)))
1539 szFieldName = "Invalid FieldDef record";
1541 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport,
1544 IDS_CLASSLOAD_NSTRUCT_EXPLICIT_OFFSET);
1546 else if ((INT)pInfoArrayOut[i].m_offset < 0)
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_NEGATIVE_OFFSET);
1560 *pSortArrayEnd = &pInfoArrayOut[i];
1565 //=====================================================================
1566 // Phase 2: Compute the native size (in bytes) of each field.
1567 // Store this in pInfoArrayOut[].cbNativeSize;
1568 //=====================================================================
1570 // Now compute the native size of each field
1571 for (pfwalk = pInfoArrayOut; pfwalk->m_MD != mdFieldDefNil; pfwalk++)
1573 UINT8 nft = pfwalk->m_nft;
1574 pEEClassLayoutInfoOut->m_numCTMFields++;
1576 // If the NFT's size never changes, it is stored in the database.
1577 UINT32 cbNativeSize = NFTDataBase[nft].m_cbNativeSize;
1579 if (cbNativeSize == 0)
1581 // Size of 0 means NFT's size is variable, so we have to figure it
1582 // out case by case.
1583 cbNativeSize = ((FieldMarshaler*)&(pfwalk->m_FieldMarshaler))->NativeSize();
1585 pfwalk->m_cbNativeSize = cbNativeSize;
1588 if (pEEClassLayoutInfoOut->m_numCTMFields)
1590 pEEClassLayoutInfoOut->SetFieldMarshalers((FieldMarshaler*)(pamTracker->Track(pAllocator->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(MAXFIELDMARSHALERSIZE) * S_SIZE_T(pEEClassLayoutInfoOut->m_numCTMFields)))));
1592 // Bring in the parent's fieldmarshalers
1593 if (fHasNonTrivialParent)
1595 CONSISTENCY_CHECK(fParentHasLayout);
1596 PREFAST_ASSUME(pParentLayoutInfo != NULL); // See if (fParentHasLayout) branch above
1598 UINT numChildCTMFields = pEEClassLayoutInfoOut->m_numCTMFields - pParentLayoutInfo->m_numCTMFields;
1600 BYTE *pParentCTMFieldSrcArray = (BYTE*)pParentLayoutInfo->GetFieldMarshalers();
1601 BYTE *pParentCTMFieldDestArray = ((BYTE*)pEEClassLayoutInfoOut->GetFieldMarshalers()) + MAXFIELDMARSHALERSIZE*numChildCTMFields;
1603 for (UINT parentCTMFieldIndex = 0; parentCTMFieldIndex < pParentLayoutInfo->m_numCTMFields; parentCTMFieldIndex++)
1605 FieldMarshaler *pParentCTMFieldSrc = (FieldMarshaler *)(pParentCTMFieldSrcArray + MAXFIELDMARSHALERSIZE*parentCTMFieldIndex);
1606 FieldMarshaler *pParentCTMFieldDest = (FieldMarshaler *)(pParentCTMFieldDestArray + MAXFIELDMARSHALERSIZE*parentCTMFieldIndex);
1608 pParentCTMFieldSrc->CopyTo(pParentCTMFieldDest, MAXFIELDMARSHALERSIZE);
1615 //=====================================================================
1616 // Phase 3: If FieldMarshaler requires autooffsetting, compute the offset
1617 // of each field and the size of the total structure. We do the layout
1618 // according to standard VC layout rules:
1620 // Each field has an alignment requirement. The alignment-requirement
1621 // of a scalar field is the smaller of its size and the declared packsize.
1622 // The alighnment-requirement of a struct field is the smaller of the
1623 // declared packsize and the largest of the alignment-requirement
1624 // of its fields. The alignment requirement of an array is that
1625 // of one of its elements.
1627 // In addition, each struct gets padding at the end to ensure
1628 // that an array of such structs contain no unused space between
1630 //=====================================================================
1632 BYTE LargestAlignmentRequirement = 1;
1633 UINT32 cbCurOffset = 0;
1635 // Treat base class as an initial member.
1636 if (!SafeAddUINT32(&cbCurOffset, cbAdjustedParentLayoutNativeSize))
1639 if (fParentHasLayout)
1641 BYTE alignmentRequirement;
1643 alignmentRequirement = min(packingSize, pParentLayoutInfo->GetLargestAlignmentRequirementOfAllMembers());
1645 LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);
1648 // Start with the size inherited from the parent (if any).
1649 unsigned calcTotalSize = cbAdjustedParentLayoutNativeSize;
1651 LayoutRawFieldInfo **pSortWalk;
1652 for (pSortWalk = pSortArray, i=cFields; i; i--, pSortWalk++)
1654 pfwalk = *pSortWalk;
1656 BYTE alignmentRequirement = static_cast<BYTE>(((FieldMarshaler*)&(pfwalk->m_FieldMarshaler))->AlignmentRequirement());
1657 if (!(alignmentRequirement == 1 ||
1658 alignmentRequirement == 2 ||
1659 alignmentRequirement == 4 ||
1660 alignmentRequirement == 8 ||
1661 alignmentRequirement == 16 ||
1662 alignmentRequirement == 32))
1664 COMPlusThrowHR(COR_E_INVALIDPROGRAM, BFA_METADATA_CORRUPT);
1667 alignmentRequirement = min(alignmentRequirement, packingSize);
1669 LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);
1671 // This assert means I forgot to special-case some NFT in the
1673 _ASSERTE(alignmentRequirement <= 32);
1675 // Check if this field is overlapped with other(s)
1676 pfwalk->m_fIsOverlapped = FALSE;
1677 if (fExplicitOffsets) {
1678 LayoutRawFieldInfo *pfwalk1;
1679 DWORD dwBegin = pfwalk->m_offset;
1680 DWORD dwEnd = dwBegin+pfwalk->m_cbNativeSize;
1681 for (pfwalk1 = pInfoArrayOut; pfwalk1 < pfwalk; pfwalk1++)
1683 if((pfwalk1->m_offset >= dwEnd) || (pfwalk1->m_offset+pfwalk1->m_cbNativeSize <= dwBegin)) continue;
1684 pfwalk->m_fIsOverlapped = TRUE;
1685 pfwalk1->m_fIsOverlapped = TRUE;
1690 // Insert enough padding to align the current data member.
1691 while (cbCurOffset % alignmentRequirement)
1693 if (!SafeAddUINT32(&cbCurOffset, 1))
1697 // Insert current data member.
1698 pfwalk->m_offset = cbCurOffset;
1700 // if we overflow we will catch it below
1701 cbCurOffset += pfwalk->m_cbNativeSize;
1704 unsigned fieldEnd = pfwalk->m_offset + pfwalk->m_cbNativeSize;
1705 if (fieldEnd < pfwalk->m_offset)
1708 // size of the structure is the size of the last field.
1709 if (fieldEnd > calcTotalSize)
1710 calcTotalSize = fieldEnd;
1713 ULONG clstotalsize = 0;
1714 if (FAILED(pInternalImport->GetClassTotalSize(cl, &clstotalsize)))
1719 if (clstotalsize != 0)
1721 if (!SafeAddULONG(&clstotalsize, (ULONG)cbAdjustedParentLayoutNativeSize))
1724 // size must be large enough to accomodate layout. If not, we use the layout size instead.
1725 if (clstotalsize < calcTotalSize)
1727 clstotalsize = calcTotalSize;
1729 calcTotalSize = clstotalsize; // use the size they told us
1733 // The did not give us an explict size, so lets round up to a good size (for arrays)
1734 while (calcTotalSize % LargestAlignmentRequirement != 0)
1736 if (!SafeAddUINT32(&calcTotalSize, 1))
1741 // We'll cap the total native size at a (somewhat) arbitrary limit to ensure
1742 // that we don't expose some overflow bug later on.
1743 if (calcTotalSize >= MAX_SIZE_FOR_INTEROP)
1746 // This is a zero-sized struct - need to record the fact and bump it up to 1.
1747 if (calcTotalSize == 0)
1749 pEEClassLayoutInfoOut->SetIsZeroSized(TRUE);
1753 pEEClassLayoutInfoOut->m_cbNativeSize = calcTotalSize;
1755 // The packingSize acts as a ceiling on all individual alignment
1756 // requirements so it follows that the largest alignment requirement
1758 _ASSERTE(LargestAlignmentRequirement <= packingSize);
1759 pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers = LargestAlignmentRequirement;
1764 //=====================================================================
1765 // Phase 4: Now we do the same thing again for managedsequential layout.
1766 //=====================================================================
1767 if (!fDisqualifyFromManagedSequential)
1769 BYTE LargestAlignmentRequirement = 1;
1770 UINT32 cbCurOffset = 0;
1772 if (pParentMT && pParentMT->IsManagedSequential())
1774 // Treat base class as an initial member.
1775 if (!SafeAddUINT32(&cbCurOffset, pParentMT->GetNumInstanceFieldBytes()))
1778 BYTE alignmentRequirement = 0;
1780 alignmentRequirement = min(packingSize, pParentLayoutInfo->m_ManagedLargestAlignmentRequirementOfAllMembers);
1782 LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);
1785 // The current size of the structure as a whole, we start at 1, because we disallow 0 sized structures.
1786 // NOTE: We do not need to do the same checking for zero-sized types as phase 3 because only ValueTypes
1787 // can be ManagedSequential and ValueTypes can not be inherited from.
1788 unsigned calcTotalSize = 1;
1790 LayoutRawFieldInfo **pSortWalk;
1791 for (pSortWalk = pSortArray, i=cFields; i; i--, pSortWalk++)
1793 pfwalk = *pSortWalk;
1795 BYTE alignmentRequirement = ((BYTE)(pfwalk->m_managedAlignmentReq));
1796 if (!(alignmentRequirement == 1 ||
1797 alignmentRequirement == 2 ||
1798 alignmentRequirement == 4 ||
1799 alignmentRequirement == 8 ||
1800 alignmentRequirement == 16 ||
1801 alignmentRequirement == 32))
1803 COMPlusThrowHR(COR_E_INVALIDPROGRAM, BFA_METADATA_CORRUPT);
1806 alignmentRequirement = min(alignmentRequirement, packingSize);
1808 LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);
1810 _ASSERTE(alignmentRequirement <= 32);
1812 // Insert enough padding to align the current data member.
1813 while (cbCurOffset % alignmentRequirement)
1815 if (!SafeAddUINT32(&cbCurOffset, 1))
1819 // Insert current data member.
1820 pfwalk->m_managedOffset = cbCurOffset;
1822 // if we overflow we will catch it below
1823 cbCurOffset += pfwalk->m_managedSize;
1825 unsigned fieldEnd = pfwalk->m_managedOffset + pfwalk->m_managedSize;
1826 if (fieldEnd < pfwalk->m_managedOffset)
1829 // size of the structure is the size of the last field.
1830 if (fieldEnd > calcTotalSize)
1831 calcTotalSize = fieldEnd;
1834 // @perf: If the type is blittable, the managed and native layouts have to be identical
1835 // so they really shouldn't be calculated twice. Until this code has been well tested and
1836 // stabilized, however, it is useful to compute both and assert that they are equal in the blittable
1838 if (pEEClassLayoutInfoOut->IsBlittable())
1840 _ASSERTE(pfwalk->m_managedOffset == pfwalk->m_offset);
1841 _ASSERTE(pfwalk->m_managedSize == pfwalk->m_cbNativeSize);
1846 ULONG clstotalsize = 0;
1847 if (FAILED(pInternalImport->GetClassTotalSize(cl, &clstotalsize)))
1852 if (clstotalsize != 0)
1854 pEEClassLayoutInfoOut->SetHasExplicitSize(TRUE);
1856 if (pParentMT && pParentMT->IsManagedSequential())
1858 // Treat base class as an initial member.
1859 UINT32 parentSize = pParentMT->GetNumInstanceFieldBytes();
1860 if (!SafeAddULONG(&clstotalsize, parentSize))
1864 // size must be large enough to accomodate layout. If not, we use the layout size instead.
1865 if (clstotalsize < calcTotalSize)
1867 clstotalsize = calcTotalSize;
1869 calcTotalSize = clstotalsize; // use the size they told us
1873 // The did not give us an explict size, so lets round up to a good size (for arrays)
1874 while (calcTotalSize % LargestAlignmentRequirement != 0)
1876 if (!SafeAddUINT32(&calcTotalSize, 1))
1881 pEEClassLayoutInfoOut->m_cbManagedSize = calcTotalSize;
1883 // The packingSize acts as a ceiling on all individual alignment
1884 // requirements so it follows that the largest alignment requirement
1886 _ASSERTE(LargestAlignmentRequirement <= packingSize);
1887 pEEClassLayoutInfoOut->m_ManagedLargestAlignmentRequirementOfAllMembers = LargestAlignmentRequirement;
1890 // @perf: If the type is blittable, the managed and native layouts have to be identical
1891 // so they really shouldn't be calculated twice. Until this code has been well tested and
1892 // stabilized, however, it is useful to compute both and assert that they are equal in the blittable
1894 if (pEEClassLayoutInfoOut->IsBlittable())
1896 _ASSERTE(pEEClassLayoutInfoOut->m_cbManagedSize == pEEClassLayoutInfoOut->m_cbNativeSize);
1897 _ASSERTE(pEEClassLayoutInfoOut->m_ManagedLargestAlignmentRequirementOfAllMembers == pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers);
1902 pEEClassLayoutInfoOut->SetIsManagedSequential(!fDisqualifyFromManagedSequential);
1906 BOOL illegalMarshaler = FALSE;
1908 LOG((LF_INTEROP, LL_INFO100000, "\n\n"));
1909 LOG((LF_INTEROP, LL_INFO100000, "%s.%s\n", szNamespace, szName));
1910 LOG((LF_INTEROP, LL_INFO100000, "Packsize = %lu\n", (ULONG)packingSize));
1911 LOG((LF_INTEROP, LL_INFO100000, "Max align req = %lu\n", (ULONG)(pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers)));
1912 LOG((LF_INTEROP, LL_INFO100000, "----------------------------\n"));
1913 for (pfwalk = pInfoArrayOut; pfwalk->m_MD != mdFieldDefNil; pfwalk++)
1916 if (FAILED(pInternalImport->GetNameOfFieldDef(pfwalk->m_MD, &fieldname)))
1920 LOG((LF_INTEROP, LL_INFO100000, "+%-5lu ", (ULONG)(pfwalk->m_offset)));
1921 LOG((LF_INTEROP, LL_INFO100000, "%s", fieldname));
1922 LOG((LF_INTEROP, LL_INFO100000, "\n"));
1924 if (((FieldMarshaler*)&pfwalk->m_FieldMarshaler)->GetNStructFieldType() == NFT_ILLEGAL)
1925 illegalMarshaler = TRUE;
1928 // If we are dealing with a non trivial parent, determine if it has any illegal marshallers.
1929 if (fHasNonTrivialParent)
1931 FieldMarshaler *pParentFM = pParentMT->GetLayoutInfo()->GetFieldMarshalers();
1932 for (i = 0; i < pParentMT->GetLayoutInfo()->m_numCTMFields; i++)
1934 if (pParentFM->GetNStructFieldType() == NFT_ILLEGAL)
1935 illegalMarshaler = TRUE;
1936 ((BYTE*&)pParentFM) += MAXFIELDMARSHALERSIZE;
1940 LOG((LF_INTEROP, LL_INFO100000, "+%-5lu EOS\n", (ULONG)(pEEClassLayoutInfoOut->m_cbNativeSize)));
1941 LOG((LF_INTEROP, LL_INFO100000, "Allocated %d %s field marshallers for %s.%s\n", pEEClassLayoutInfoOut->m_numCTMFields, (illegalMarshaler ? "pointless" : "usable"), szNamespace, szName));
1947 #pragma warning(pop)
1951 #ifndef CROSSGEN_COMPILE
1953 //=======================================================================
1954 // For each reference-typed FieldMarshaler field, marshals the current CLR value
1955 // to a new native instance and stores it in the fixed portion of the FieldMarshaler.
1957 // This function does not attempt to delete the native value that it overwrites.
1959 // If there is a SafeHandle field, ppCleanupWorkListOnStack must be non-null, otherwise
1960 // InvalidOperationException is thrown.
1961 //=======================================================================
1962 VOID LayoutUpdateNative(LPVOID *ppProtectedManagedData, SIZE_T offsetbias, MethodTable *pMT, BYTE* pNativeData, OBJECTREF *ppCleanupWorkListOnStack)
1969 PRECONDITION(CheckPointer(pMT));
1973 FieldMarshaler* pFM = pMT->GetLayoutInfo()->GetFieldMarshalers();
1974 UINT numReferenceFields = pMT->GetLayoutInfo()->GetNumCTMFields();
1976 OBJECTREF pCLRValue = NULL;
1977 LPVOID scalar = NULL;
1979 GCPROTECT_BEGIN(pCLRValue)
1980 GCPROTECT_BEGININTERIOR(scalar)
1982 g_IBCLogger.LogFieldMarshalersReadAccess(pMT);
1984 while (numReferenceFields--)
1988 DWORD internalOffset = pFM->GetFieldDesc()->GetOffset();
1990 if (pFM->IsScalarMarshaler())
1992 scalar = (LPVOID)(internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData));
1993 // Note this will throw for FieldMarshaler_Illegal
1994 pFM->ScalarUpdateNative(scalar, pNativeData + pFM->GetExternalOffset() );
1997 else if (pFM->IsNestedValueClassMarshaler())
1999 pFM->NestedValueClassUpdateNative((const VOID **)ppProtectedManagedData, internalOffset + offsetbias, pNativeData + pFM->GetExternalOffset(),
2000 ppCleanupWorkListOnStack);
2004 pCLRValue = *(OBJECTREF*)(internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData));
2005 pFM->UpdateNative(&pCLRValue, pNativeData + pFM->GetExternalOffset(), ppCleanupWorkListOnStack);
2006 SetObjectReferenceUnchecked( (OBJECTREF*) (internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData)), pCLRValue);
2009 // The cleanup work list is not used to clean up the native contents. It is used
2010 // to handle cleanup of any additionnal resources the FieldMarshalers allocate.
2012 ((BYTE*&)pFM) += MAXFIELDMARSHALERSIZE;
2020 VOID FmtClassUpdateNative(OBJECTREF *ppProtectedManagedData, BYTE *pNativeData, OBJECTREF *ppCleanupWorkListOnStack)
2027 PRECONDITION(CheckPointer(ppProtectedManagedData));
2031 MethodTable *pMT = (*ppProtectedManagedData)->GetMethodTable();
2032 _ASSERTE(pMT->IsBlittable() || pMT->HasLayout());
2033 UINT32 cbsize = pMT->GetNativeSize();
2035 if (pMT->IsBlittable())
2037 memcpyNoGCRefs(pNativeData, (*ppProtectedManagedData)->GetData(), cbsize);
2041 // This allows us to do a partial LayoutDestroyNative in the case of
2042 // a marshaling error on one of the fields.
2043 FillMemory(pNativeData, cbsize, 0);
2044 NativeLayoutDestroyer nld(pNativeData, pMT, cbsize);
2046 LayoutUpdateNative( (VOID**)ppProtectedManagedData,
2047 Object::GetOffsetOfFirstField(),
2050 ppCleanupWorkListOnStack);
2052 nld.SuppressRelease();
2058 VOID FmtClassUpdateCLR(OBJECTREF *ppProtectedManagedData, BYTE *pNativeData)
2068 MethodTable *pMT = (*ppProtectedManagedData)->GetMethodTable();
2069 _ASSERTE(pMT->IsBlittable() || pMT->HasLayout());
2070 UINT32 cbsize = pMT->GetNativeSize();
2072 if (pMT->IsBlittable())
2074 memcpyNoGCRefs((*ppProtectedManagedData)->GetData(), pNativeData, cbsize);
2078 LayoutUpdateCLR((VOID**)ppProtectedManagedData,
2079 Object::GetOffsetOfFirstField(),
2088 //=======================================================================
2089 // For each reference-typed FieldMarshaler field, marshals the current CLR value
2090 // to a new CLR instance and stores it in the GC portion of the FieldMarshaler.
2092 // If fDeleteNativeCopies is true, it will also destroy the native version.
2094 // NOTE: To avoid error-path leaks, this function attempts to destroy
2095 // all of the native fields even if one or more of the conversions fail.
2096 //=======================================================================
2097 VOID LayoutUpdateCLR(LPVOID *ppProtectedManagedData, SIZE_T offsetbias, MethodTable *pMT, BYTE *pNativeData)
2104 PRECONDITION(CheckPointer(pMT));
2108 // Don't try to destroy/free native the structure on exception, we may not own it. If we do own it and
2109 // are supposed to destroy/free it, we do it upstack (e.g. in a helper called from the marshaling stub).
2111 FieldMarshaler* pFM = pMT->GetLayoutInfo()->GetFieldMarshalers();
2112 UINT numReferenceFields = pMT->GetLayoutInfo()->GetNumCTMFields();
2116 OBJECTREF pCLRValue;
2117 OBJECTREF pOldCLRValue;
2120 gc.pCLRValue = NULL;
2121 gc.pOldCLRValue = NULL;
2122 LPVOID scalar = NULL;
2125 GCPROTECT_BEGININTERIOR(scalar)
2127 g_IBCLogger.LogFieldMarshalersReadAccess(pMT);
2129 while (numReferenceFields--)
2133 DWORD internalOffset = pFM->GetFieldDesc()->GetOffset();
2135 if (pFM->IsScalarMarshaler())
2137 scalar = (LPVOID)(internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData));
2138 // Note this will throw for FieldMarshaler_Illegal
2139 pFM->ScalarUpdateCLR( pNativeData + pFM->GetExternalOffset(), scalar);
2141 else if (pFM->IsNestedValueClassMarshaler())
2143 pFM->NestedValueClassUpdateCLR(pNativeData + pFM->GetExternalOffset(), ppProtectedManagedData, internalOffset + offsetbias);
2147 gc.pOldCLRValue = *(OBJECTREF*)(internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData));
2148 pFM->UpdateCLR( pNativeData + pFM->GetExternalOffset(), &gc.pCLRValue, &gc.pOldCLRValue );
2149 SetObjectReferenceUnchecked( (OBJECTREF*) (internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData)), gc.pCLRValue );
2152 ((BYTE*&)pFM) += MAXFIELDMARSHALERSIZE;
2160 VOID LayoutDestroyNative(LPVOID pNative, MethodTable *pMT)
2167 PRECONDITION(CheckPointer(pMT));
2171 FieldMarshaler *pFM = pMT->GetLayoutInfo()->GetFieldMarshalers();
2172 UINT numReferenceFields = pMT->GetLayoutInfo()->GetNumCTMFields();
2173 BYTE *pNativeData = (BYTE*)pNative;
2175 while (numReferenceFields--)
2177 pFM->DestroyNative( pNativeData + pFM->GetExternalOffset() );
2178 ((BYTE*&)pFM) += MAXFIELDMARSHALERSIZE;
2182 VOID FmtClassDestroyNative(LPVOID pNative, MethodTable *pMT)
2189 PRECONDITION(CheckPointer(pMT));
2195 if (!(pMT->IsBlittable()))
2197 _ASSERTE(pMT->HasLayout());
2198 LayoutDestroyNative(pNative, pMT);
2203 VOID FmtValueTypeUpdateNative(LPVOID pProtectedManagedData, MethodTable *pMT, BYTE *pNativeData, OBJECTREF *ppCleanupWorkListOnStack)
2210 PRECONDITION(CheckPointer(pMT));
2214 _ASSERTE(pMT->IsValueType() && (pMT->IsBlittable() || pMT->HasLayout()));
2215 UINT32 cbsize = pMT->GetNativeSize();
2217 if (pMT->IsBlittable())
2219 memcpyNoGCRefs(pNativeData, pProtectedManagedData, cbsize);
2223 // This allows us to do a partial LayoutDestroyNative in the case of
2224 // a marshaling error on one of the fields.
2225 FillMemory(pNativeData, cbsize, 0);
2227 NativeLayoutDestroyer nld(pNativeData, pMT, cbsize);
2229 LayoutUpdateNative( (VOID**)pProtectedManagedData,
2233 ppCleanupWorkListOnStack);
2235 nld.SuppressRelease();
2239 VOID FmtValueTypeUpdateCLR(LPVOID pProtectedManagedData, MethodTable *pMT, BYTE *pNativeData)
2246 PRECONDITION(CheckPointer(pMT));
2250 _ASSERTE(pMT->IsValueType() && (pMT->IsBlittable() || pMT->HasLayout()));
2251 UINT32 cbsize = pMT->GetNativeSize();
2253 if (pMT->IsBlittable())
2255 memcpyNoGCRefs(pProtectedManagedData, pNativeData, cbsize);
2259 LayoutUpdateCLR((VOID**)pProtectedManagedData,
2262 (BYTE*)pNativeData);
2267 #ifdef FEATURE_COMINTEROP
2269 //=======================================================================
2270 // BSTR <--> System.String
2271 // See FieldMarshaler for details.
2272 //=======================================================================
2273 VOID FieldMarshaler_BSTR::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
2280 INJECT_FAULT(COMPlusThrowOM());
2281 PRECONDITION(CheckPointer(pNativeValue));
2286 *((OBJECTREF*)&pString) = *pCLRValue;
2288 if (pString == NULL)
2289 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
2292 BSTR pBSTR = SysAllocStringLen(pString->GetBuffer(), pString->GetStringLength());
2296 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, pBSTR);
2301 //=======================================================================
2302 // BSTR <--> System.String
2303 // See FieldMarshaler for details.
2304 //=======================================================================
2305 VOID FieldMarshaler_BSTR::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
2307 STATIC_CONTRACT_THROWS;
2308 STATIC_CONTRACT_GC_TRIGGERS;
2309 STATIC_CONTRACT_MODE_COOPERATIVE;
2311 _ASSERTE(NULL != pNativeValue);
2312 _ASSERTE(NULL != ppProtectedCLRValue);
2315 BSTR pBSTR = (BSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
2321 struct Param : CallOutFilterParam {
2326 param.OneShot = TRUE;
2328 param.pBSTR = pBSTR;
2330 PAL_TRY(Param *, pParam, ¶m)
2332 pParam->length = SysStringLen(pParam->pBSTR);
2334 PAL_EXCEPT_FILTER(CallOutFilter)
2336 _ASSERTE(!"CallOutFilter returned EXECUTE_HANDLER.");
2340 pString = StringObject::NewString(pBSTR, param.length);
2343 *((STRINGREF*)ppProtectedCLRValue) = pString;
2347 //=======================================================================
2348 // BSTR <--> System.String
2349 // See FieldMarshaler for details.
2350 //=======================================================================
2351 VOID FieldMarshaler_BSTR::DestroyNativeImpl(LPVOID pNativeValue) const
2358 PRECONDITION(CheckPointer(pNativeValue));
2362 BSTR pBSTR = (BSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
2363 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
2367 _ASSERTE (GetModuleHandleA("oleaut32.dll") != NULL);
2368 // BSTR has been created, which means oleaut32 should have been loaded.
2369 // Delay load will not fail.
2370 CONTRACT_VIOLATION(ThrowsViolation);
2371 SysFreeString(pBSTR);
2375 //===========================================================================================
2376 // Windows.Foundation.IReference'1<-- System.Nullable'1
2378 VOID FieldMarshaler_Nullable::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const
2385 INJECT_FAULT(COMPlusThrowOM());
2386 PRECONDITION(CheckPointer(pNative));
2387 PRECONDITION(CheckPointer(pCLR));
2391 IUnknown *pUnk = NULL;
2393 // ConvertToNative<T>(ref Nullable<T> pManaged) where T : struct
2394 MethodDescCallSite convertToNative(GetMethodDescForGenericInstantiation(MscorlibBinder::GetMethod(METHOD__NULLABLEMARSHALER__CONVERT_TO_NATIVE)));
2400 pUnk = (IUnknown*) convertToNative.Call_RetLPVOID(args);
2402 MAYBE_UNALIGNED_WRITE(pNative, _PTR, pUnk);
2405 //===========================================================================================
2406 // Windows.Foundation.IReference'1--> System.Nullable'1
2408 VOID FieldMarshaler_Nullable::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const
2415 PRECONDITION(CheckPointer(pNative));
2416 PRECONDITION(CheckPointer(pCLR));
2420 IUnknown *pUnk = (IUnknown*)MAYBE_UNALIGNED_READ(pNative, _PTR);
2422 MethodDescCallSite convertToManaged(GetMethodDescForGenericInstantiation(MscorlibBinder::GetMethod(METHOD__NULLABLEMARSHALER__CONVERT_TO_MANAGED_RET_VOID)));
2430 //ConvertToManaged<T>(Intptr pNative, ref Nullable<T> retObj) where T : struct;
2431 convertToManaged.Call(args);
2434 //===========================================================================================
2435 // Windows.Foundation.IReference'1<--> System.Nullable'1
2437 VOID FieldMarshaler_Nullable::DestroyNativeImpl(const VOID* pNative) const
2444 PRECONDITION(CheckPointer(pNative));
2448 IUnknown *pUnk = (IUnknown*)MAYBE_UNALIGNED_READ(pNative, _PTR);
2449 MAYBE_UNALIGNED_WRITE(pNative, _PTR, NULL);
2453 ULONG cbRef = SafeRelease(pUnk);
2454 LogInteropRelease(pUnk, cbRef, "Field marshaler destroy native");
2458 //=======================================================================
2459 // HSTRING <--> System.String
2460 // See FieldMarshaler for details.
2461 //=======================================================================
2462 VOID FieldMarshaler_HSTRING::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
2469 PRECONDITION(CheckPointer(pCLRValue));
2470 PRECONDITION(CheckPointer(pNativeValue));
2474 if (!WinRTSupported())
2476 COMPlusThrow(kPlatformNotSupportedException, W("PlatformNotSupported_WinRT"));
2479 STRINGREF stringref = (STRINGREF)(*pCLRValue);
2481 if (stringref == NULL)
2483 DefineFullyQualifiedNameForClassW();
2484 StackSString ssFieldName(SString::Utf8, GetFieldDesc()->GetName());
2486 SString errorString;
2487 errorString.LoadResource(CCompRC::Error, IDS_EE_BADMARSHALFIELD_NULL_HSTRING);
2489 COMPlusThrow(kMarshalDirectiveException,
2490 IDS_EE_BADMARSHALFIELD_ERROR_MSG,
2491 GetFullyQualifiedNameForClassW(GetFieldDesc()->GetEnclosingMethodTable()),
2492 ssFieldName.GetUnicode(),
2493 errorString.GetUnicode());
2497 IfFailThrow(WindowsCreateString(stringref->GetBuffer(), stringref->GetStringLength(), &hstring));
2499 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, hstring);
2502 //=======================================================================
2503 // HSTRING <--> System.String
2504 // See FieldMarshaler for details.
2505 //=======================================================================
2506 VOID FieldMarshaler_HSTRING::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
2513 PRECONDITION(CheckPointer(pNativeValue));
2514 PRECONDITION(CheckPointer(ppProtectedCLRValue));
2518 if (!WinRTSupported())
2520 COMPlusThrow(kPlatformNotSupportedException, W("PlatformNotSupported_WinRT"));
2523 // NULL HSTRINGS are equivilent to empty strings
2524 UINT32 cchString = 0;
2525 LPCWSTR pwszString = W("");
2527 HSTRING hstring = (HSTRING)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
2528 if (hstring != NULL)
2530 pwszString = WindowsGetStringRawBuffer(hstring, &cchString);
2533 STRINGREF stringref = StringObject::NewString(pwszString, cchString);
2534 *((STRINGREF *)ppProtectedCLRValue) = stringref;
2537 //=======================================================================
2538 // HSTRING <--> System.String
2539 // See FieldMarshaler for details.
2540 //=======================================================================
2541 VOID FieldMarshaler_HSTRING::DestroyNativeImpl(LPVOID pNativeValue) const
2548 PRECONDITION(CheckPointer(pNativeValue));
2552 HSTRING hstring = (HSTRING)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
2553 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
2555 if (hstring != NULL)
2557 // We need this for code:System.Runtime.InteropServices.Marshal.DestroyStructure (user can explicitly call it)
2558 if (WinRTSupported())
2560 // If WinRT is supported we've already loaded combase.dll, which means
2561 // this delay load will succeed
2562 CONTRACT_VIOLATION(ThrowsViolation);
2563 WindowsDeleteString(hstring);
2568 //=======================================================================================
2569 // Windows.UI.Xaml.Interop.TypeName <--> System.Type
2571 VOID FieldMarshaler_SystemType::UpdateNativeImpl(OBJECTREF * pCLRValue, LPVOID pNativeValue, OBJECTREF * ppCleanupWorkListOnStack) const
2578 PRECONDITION(CheckPointer(pCLRValue));
2579 PRECONDITION(CheckPointer(pNativeValue));
2583 // ConvertToNative(System.Type managedType, TypeName *pTypeName)
2584 MethodDescCallSite convertToNative(METHOD__SYSTEMTYPEMARSHALER__CONVERT_TO_NATIVE);
2587 ObjToArgSlot(*pCLRValue),
2588 PtrToArgSlot(pNativeValue)
2590 convertToNative.Call(args);
2593 //=======================================================================================
2594 // Windows.UI.Xaml.Interop.TypeName <--> System.Type
2596 VOID FieldMarshaler_SystemType::UpdateCLRImpl(const VOID * pNativeValue, OBJECTREF * ppProtectedCLRValue, OBJECTREF * ppProtectedOldCLRValue) const
2603 PRECONDITION(CheckPointer(pNativeValue));
2604 PRECONDITION(CheckPointer(ppProtectedCLRValue));
2608 // ConvertToManaged(TypeName *pTypeName, out System.Type)
2609 MethodDescCallSite convertToManaged(METHOD__SYSTEMTYPEMARSHALER__CONVERT_TO_MANAGED);
2612 PtrToArgSlot(pNativeValue),
2613 PtrToArgSlot(ppProtectedCLRValue)
2616 convertToManaged.Call(args);
2619 //=======================================================================================
2620 // Windows.UI.Xaml.Interop.TypeName <--> System.Type
2621 // Clear the HSTRING field
2623 VOID FieldMarshaler_SystemType::DestroyNativeImpl(LPVOID pNativeValue) const
2630 PRECONDITION(CheckPointer(pNativeValue));
2631 PRECONDITION(WinRTSupported());
2636 // Call WindowsDeleteString instead of SystemTypeMarshaler.ClearNative
2637 // because WindowsDeleteString does not throw and is much faster
2639 size_t offset = offsetof(TypeNameNative, typeName);
2640 HSTRING hstring = (HSTRING)MAYBE_UNALIGNED_READ((LPBYTE) pNativeValue + offset , _PTR);
2641 MAYBE_UNALIGNED_WRITE((LPBYTE) pNativeValue + offset, _PTR, NULL);
2643 if (hstring != NULL)
2645 // Note: we've already loaded combase.dll, which means this delay load will succeed
2646 CONTRACT_VIOLATION(ThrowsViolation);
2647 WindowsDeleteString(hstring);
2651 //=======================================================================================
2652 // Windows.Foundation.HResult <--> System.Exception
2653 // Note: The WinRT struct has exactly 1 field, Value (an HRESULT)
2655 VOID FieldMarshaler_Exception::UpdateNativeImpl(OBJECTREF * pCLRValue, LPVOID pNativeValue, OBJECTREF * ppCleanupWorkListOnStack) const
2662 PRECONDITION(CheckPointer(pCLRValue));
2663 PRECONDITION(CheckPointer(pNativeValue));
2667 // int ConvertToNative(Exception ex)
2668 MethodDescCallSite convertToNative(METHOD__HRESULTEXCEPTIONMARSHALER__CONVERT_TO_NATIVE);
2671 ObjToArgSlot(*pCLRValue)
2673 int iReturnedValue = convertToNative.Call_RetI4(args);
2674 MAYBE_UNALIGNED_WRITE(pNativeValue, 32, iReturnedValue);
2677 //=======================================================================================
2678 // Windows.Foundation.HResult <--> System.Exception
2679 // Note: The WinRT struct has exactly 1 field, Value (an HRESULT)
2681 VOID FieldMarshaler_Exception::UpdateCLRImpl(const VOID * pNativeValue, OBJECTREF * ppProtectedCLRValue, OBJECTREF * ppProtectedOldCLRValue) const
2688 PRECONDITION(CheckPointer(pNativeValue));
2689 PRECONDITION(CheckPointer(ppProtectedCLRValue));
2693 // Exception ConvertToManaged(int hr)
2694 MethodDescCallSite convertToManaged(METHOD__HRESULTEXCEPTIONMARSHALER__CONVERT_TO_MANAGED);
2697 (ARG_SLOT)MAYBE_UNALIGNED_READ(pNativeValue, 32)
2699 *ppProtectedCLRValue = convertToManaged.Call_RetOBJECTREF(args);
2702 #endif // FEATURE_COMINTEROP
2705 //=======================================================================
2706 // Nested structure conversion
2707 // See FieldMarshaler for details.
2708 //=======================================================================
2709 VOID FieldMarshaler_NestedLayoutClass::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
2716 INJECT_FAULT(COMPlusThrowOM());
2717 PRECONDITION(CheckPointer(pNativeValue));
2721 UINT32 cbNativeSize = GetMethodTable()->GetNativeSize();
2723 if (*pCLRValue == NULL)
2725 ZeroMemoryInGCHeap(pNativeValue, cbNativeSize);
2729 LayoutUpdateNative((LPVOID*)pCLRValue, Object::GetOffsetOfFirstField(),
2730 GetMethodTable(), (BYTE*)pNativeValue, ppCleanupWorkListOnStack);
2736 //=======================================================================
2737 // Nested structure conversion
2738 // See FieldMarshaler for details.
2739 //=======================================================================
2740 VOID FieldMarshaler_NestedLayoutClass::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
2747 INJECT_FAULT(COMPlusThrowOM());
2748 PRECONDITION(CheckPointer(pNativeValue));
2749 PRECONDITION(CheckPointer(ppProtectedCLRValue));
2753 *ppProtectedCLRValue = GetMethodTable()->Allocate();
2755 LayoutUpdateCLR( (LPVOID*)ppProtectedCLRValue,
2756 Object::GetOffsetOfFirstField(),
2758 (BYTE *)pNativeValue);
2763 //=======================================================================
2764 // Nested structure conversion
2765 // See FieldMarshaler for details.
2766 //=======================================================================
2767 VOID FieldMarshaler_NestedLayoutClass::DestroyNativeImpl(LPVOID pNativeValue) const
2774 PRECONDITION(CheckPointer(pNativeValue));
2778 LayoutDestroyNative(pNativeValue, GetMethodTable());
2781 #endif // CROSSGEN_COMPILE
2784 //=======================================================================
2785 // Nested structure conversion
2786 // See FieldMarshaler for details.
2787 //=======================================================================
2788 UINT32 FieldMarshaler_NestedLayoutClass::NativeSizeImpl() const
2798 return GetMethodTable()->GetLayoutInfo()->GetNativeSize();
2801 //=======================================================================
2802 // Nested structure conversion
2803 // See FieldMarshaler for details.
2804 //=======================================================================
2805 UINT32 FieldMarshaler_NestedLayoutClass::AlignmentRequirementImpl() const
2815 return GetMethodTable()->GetLayoutInfo()->GetLargestAlignmentRequirementOfAllMembers();
2818 #if FEATURE_COMINTEROP
2819 MethodDesc* FieldMarshaler_Nullable::GetMethodDescForGenericInstantiation(MethodDesc* pMD) const
2821 MethodDesc *pMethodInstantiation;
2823 pMethodInstantiation = MethodDesc::FindOrCreateAssociatedMethodDesc(
2825 pMD->GetMethodTable(),
2827 GetMethodTable()->GetInstantiation(),
2831 _ASSERTE(pMethodInstantiation != NULL);
2833 return pMethodInstantiation;
2835 #endif //FEATURE_COMINTEROP
2837 #ifndef CROSSGEN_COMPILE
2839 //=======================================================================
2840 // Nested structure conversion
2841 // See FieldMarshaler for details.
2842 //=======================================================================
2843 VOID FieldMarshaler_NestedValueClass::NestedValueClassUpdateNativeImpl(const VOID **ppProtectedCLR, SIZE_T startoffset, LPVOID pNative, OBJECTREF *ppCleanupWorkListOnStack) const
2850 INJECT_FAULT(COMPlusThrowOM());
2851 PRECONDITION(CheckPointer(ppProtectedCLR));
2852 PRECONDITION(CheckPointer(pNative));
2856 // would be better to detect this at class load time (that have a nested value
2857 // class with no layout) but don't have a way to know
2858 if (! GetMethodTable()->GetLayoutInfo())
2859 COMPlusThrow(kArgumentException, IDS_NOLAYOUT_IN_EMBEDDED_VALUECLASS);
2861 LayoutUpdateNative((LPVOID*)ppProtectedCLR, startoffset, GetMethodTable(), (BYTE*)pNative, ppCleanupWorkListOnStack);
2865 //=======================================================================
2866 // Nested structure conversion
2867 // See FieldMarshaler for details.
2868 //=======================================================================
2869 VOID FieldMarshaler_NestedValueClass::NestedValueClassUpdateCLRImpl(const VOID *pNative, LPVOID *ppProtectedCLR, SIZE_T startoffset) const
2876 PRECONDITION(CheckPointer(pNative));
2877 PRECONDITION(CheckPointer(ppProtectedCLR));
2881 // would be better to detect this at class load time (that have a nested value
2882 // class with no layout) but don't have a way to know
2883 if (! GetMethodTable()->GetLayoutInfo())
2884 COMPlusThrow(kArgumentException, IDS_NOLAYOUT_IN_EMBEDDED_VALUECLASS);
2886 LayoutUpdateCLR( (LPVOID*)ppProtectedCLR,
2895 //=======================================================================
2896 // Nested structure conversion
2897 // See FieldMarshaler for details.
2898 //=======================================================================
2899 VOID FieldMarshaler_NestedValueClass::DestroyNativeImpl(LPVOID pNativeValue) const
2906 PRECONDITION(CheckPointer(pNativeValue));
2910 LayoutDestroyNative(pNativeValue, GetMethodTable());
2913 #endif // CROSSGEN_COMPILE
2916 //=======================================================================
2917 // Nested structure conversion
2918 // See FieldMarshaler for details.
2919 //=======================================================================
2920 UINT32 FieldMarshaler_NestedValueClass::NativeSizeImpl() const
2930 // this can't be marshalled as native type if no layout, so we allow the
2931 // native size info to be created if available, but the size will only
2932 // be valid for native, not unions. Marshaller will throw exception if
2933 // try to marshall a value class with no layout
2934 if (GetMethodTable()->HasLayout())
2935 return GetMethodTable()->GetLayoutInfo()->GetNativeSize();
2941 //=======================================================================
2942 // Nested structure conversion
2943 // See FieldMarshaler for details.
2944 //=======================================================================
2945 UINT32 FieldMarshaler_NestedValueClass::AlignmentRequirementImpl() const
2955 // this can't be marshalled as native type if no layout, so we allow the
2956 // native size info to be created if available, but the alignment will only
2957 // be valid for native, not unions. Marshaller will throw exception if
2958 // try to marshall a value class with no layout
2959 if (GetMethodTable()->HasLayout())
2961 UINT32 uAlignmentReq = GetMethodTable()->GetLayoutInfo()->GetLargestAlignmentRequirementOfAllMembers();
2962 return uAlignmentReq;
2968 #ifndef CROSSGEN_COMPILE
2970 //=======================================================================
2971 // CoTask Uni <--> System.String
2972 // See FieldMarshaler for details.
2973 //=======================================================================
2974 VOID FieldMarshaler_StringUni::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
2981 INJECT_FAULT(COMPlusThrowOM());
2982 PRECONDITION(CheckPointer(pNativeValue));
2987 *((OBJECTREF*)&pString) = *pCLRValue;
2989 if (pString == NULL)
2991 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
2995 DWORD nc = pString->GetStringLength();
2996 if (nc > MAX_SIZE_FOR_INTEROP)
2997 COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG);
2999 LPWSTR wsz = (LPWSTR)CoTaskMemAlloc( (nc + 1) * sizeof(WCHAR) );
3003 memcpyNoGCRefs(wsz, pString->GetBuffer(), nc*sizeof(WCHAR));
3005 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, wsz);
3010 //=======================================================================
3011 // CoTask Uni <--> System.String
3012 // See FieldMarshaler for details.
3013 //=======================================================================
3014 VOID FieldMarshaler_StringUni::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3021 PRECONDITION(CheckPointer(pNativeValue));
3022 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3027 LPCWSTR wsz = (LPCWSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3033 SIZE_T length = wcslen(wsz);
3034 if (length > MAX_SIZE_FOR_INTEROP)
3035 COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG);
3037 pString = StringObject::NewString(wsz, (DWORD)length);
3040 *((STRINGREF*)ppProtectedCLRValue) = pString;
3044 //=======================================================================
3045 // CoTask Uni <--> System.String
3046 // See FieldMarshaler for details.
3047 //=======================================================================
3048 VOID FieldMarshaler_StringUni::DestroyNativeImpl(LPVOID pNativeValue) const
3055 PRECONDITION(CheckPointer(pNativeValue));
3059 LPWSTR wsz = (LPWSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3060 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3067 //=======================================================================
3068 // CoTask Ansi <--> System.String
3069 // See FieldMarshaler for details.
3070 //=======================================================================
3071 VOID FieldMarshaler_StringAnsi::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3078 INJECT_FAULT(COMPlusThrowOM());
3079 PRECONDITION(CheckPointer(pNativeValue));
3084 *((OBJECTREF*)&pString) = *pCLRValue;
3086 if (pString == NULL)
3088 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3092 DWORD nc = pString->GetStringLength();
3093 if (nc > MAX_SIZE_FOR_INTEROP)
3094 COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG);
3096 LPSTR sz = (LPSTR)CoTaskMemAlloc( (nc + 1) * 2 /* 2 for MBCS */ );
3100 int nbytes = InternalWideToAnsi(pString->GetBuffer(),
3105 m_ThrowOnUnmappableChar);
3108 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, sz);
3113 //=======================================================================
3114 // CoTask Ansi <--> System.String
3115 // See FieldMarshaler for details.
3116 //=======================================================================
3117 VOID FieldMarshaler_StringAnsi::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3124 INJECT_FAULT(COMPlusThrowOM());
3125 PRECONDITION(CheckPointer(pNativeValue));
3126 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3130 STRINGREF pString = NULL;
3131 LPCSTR sz = (LPCSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3136 MAKE_WIDEPTR_FROMANSI(wsztemp, sz);
3137 pString = StringObject::NewString(wsztemp, __lwsztemp - 1);
3140 *((STRINGREF*)ppProtectedCLRValue) = pString;
3144 //=======================================================================
3145 // CoTask Ansi <--> System.String
3146 // See FieldMarshaler for details.
3147 //=======================================================================
3148 VOID FieldMarshaler_StringAnsi::DestroyNativeImpl(LPVOID pNativeValue) const
3155 PRECONDITION(CheckPointer(pNativeValue));
3159 LPSTR sz = (LPSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3160 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3165 //=======================================================================
3166 // CoTask Utf8 <--> System.String
3167 // See FieldMarshaler for details.
3168 //=======================================================================
3169 VOID FieldMarshaler_StringUtf8::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3176 INJECT_FAULT(COMPlusThrowOM());
3177 PRECONDITION(CheckPointer(pNativeValue));
3181 STRINGREF pString = (STRINGREF)(*pCLRValue);
3182 if (pString == NULL)
3184 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3188 DWORD nc = pString->GetStringLength();
3189 if (nc > MAX_SIZE_FOR_INTEROP)
3190 COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG);
3192 // Characters would be # of characters + 1 in case left over high surrogate is ?
3193 // Max 3 bytes per char for basic multi-lingual plane.
3194 nc = (nc + 1) * MAX_UTF8_CHAR_SIZE;
3196 LPUTF8 lpBuffer = (LPUTF8)CoTaskMemAlloc(nc + 1);
3202 // UTF8Marshaler.ConvertToNative
3203 MethodDescCallSite convertToNative(METHOD__CUTF8MARSHALER__CONVERT_TO_NATIVE);
3207 ((ARG_SLOT)(CLR_I4)0),
3208 ObjToArgSlot(*pCLRValue),
3209 PtrToArgSlot(lpBuffer)
3211 convertToNative.Call(args);
3212 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, lpBuffer);
3217 //=======================================================================
3218 // CoTask Utf8 <--> System.String
3219 // See FieldMarshaler for details.
3220 //=======================================================================
3221 VOID FieldMarshaler_StringUtf8::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3228 INJECT_FAULT(COMPlusThrowOM());
3229 PRECONDITION(CheckPointer(pNativeValue));
3230 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3234 STRINGREF pString = NULL;
3235 LPCUTF8 sz = (LPCUTF8)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3242 MethodDescCallSite convertToManaged(METHOD__CUTF8MARSHALER__CONVERT_TO_MANAGED);
3245 PtrToArgSlot(pNativeValue),
3247 pString = convertToManaged.Call_RetSTRINGREF(args);
3249 *((STRINGREF*)ppProtectedCLRValue) = pString;
3252 //=======================================================================
3253 // CoTask Utf8 <--> System.String
3254 // See FieldMarshaler for details.
3255 //=======================================================================
3256 VOID FieldMarshaler_StringUtf8::DestroyNativeImpl(LPVOID pNativeValue) const
3263 PRECONDITION(CheckPointer(pNativeValue));
3267 LPCUTF8 lpBuffer = (LPCUTF8)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3268 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3270 CoTaskMemFree((LPVOID)lpBuffer);
3273 //=======================================================================
3274 // FixedString <--> System.String
3275 // See FieldMarshaler for details.
3276 //=======================================================================
3277 VOID FieldMarshaler_FixedStringUni::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3284 PRECONDITION(CheckPointer(pNativeValue));
3289 *((OBJECTREF*)&pString) = *pCLRValue;
3291 if (pString == NULL)
3293 MAYBE_UNALIGNED_WRITE(pNativeValue, 16, W('\0'));
3297 DWORD nc = pString->GetStringLength();
3298 if (nc >= m_numchar)
3301 memcpyNoGCRefs(pNativeValue, pString->GetBuffer(), nc*sizeof(WCHAR));
3302 MAYBE_UNALIGNED_WRITE(&(((WCHAR*)pNativeValue)[nc]), 16, W('\0'));
3308 //=======================================================================
3309 // FixedString <--> System.String
3310 // See FieldMarshaler for details.
3311 //=======================================================================
3312 VOID FieldMarshaler_FixedStringUni::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3319 PRECONDITION(CheckPointer(pNativeValue));
3320 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3325 SIZE_T ncActual = wcsnlen((const WCHAR *)pNativeValue, m_numchar);
3327 if (!FitsIn<int>(ncActual))
3328 COMPlusThrowHR(COR_E_OVERFLOW);
3330 pString = StringObject::NewString((const WCHAR *)pNativeValue, (int)ncActual);
3331 *((STRINGREF*)ppProtectedCLRValue) = pString;
3340 //=======================================================================
3341 // FixedString <--> System.String
3342 // See FieldMarshaler for details.
3343 //=======================================================================
3344 VOID FieldMarshaler_FixedStringAnsi::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3351 PRECONDITION(CheckPointer(pNativeValue));
3356 *((OBJECTREF*)&pString) = *pCLRValue;
3358 if (pString == NULL)
3359 *((CHAR*)pNativeValue) = W('\0');
3362 DWORD nc = pString->GetStringLength();
3363 if (nc >= m_numchar)
3366 int cbwritten = InternalWideToAnsi(pString->GetBuffer(),
3368 (CHAR*)pNativeValue,
3371 m_ThrowOnUnmappableChar);
3373 // Handle the case where SizeConst == Number of bytes.For single byte chars
3374 // this will never be the case since nc >= m_numchar check will truncate the last
3375 // character, but for multibyte chars nc>= m_numchar check won't truncate since GetStringLength
3376 // gives number of characters but not the actual number of bytes. For such cases need to make
3377 // sure that we dont write one past the buffer.
3378 if (cbwritten == (int) m_numchar)
3381 ((CHAR*)pNativeValue)[cbwritten] = '\0';
3386 //=======================================================================
3387 // FixedString <--> System.String
3388 // See FieldMarshaler for details.
3389 //=======================================================================
3390 VOID FieldMarshaler_FixedStringAnsi::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3397 INJECT_FAULT(COMPlusThrowOM());
3398 PRECONDITION(CheckPointer(pNativeValue));
3399 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3401 // should not have slipped past the metadata
3402 PRECONDITION(m_numchar != 0);
3409 // but if it does, better to throw an exception tardily rather than
3410 // allow a memory corrupt.
3411 COMPlusThrow(kMarshalDirectiveException);
3414 UINT32 allocSize = m_numchar + 2;
3415 if (allocSize < m_numchar)
3418 LPSTR tempbuf = (LPSTR)(_alloca((size_t)allocSize));
3422 memcpyNoGCRefs(tempbuf, pNativeValue, m_numchar);
3423 tempbuf[m_numchar-1] = '\0';
3424 tempbuf[m_numchar] = '\0';
3425 tempbuf[m_numchar+1] = '\0';
3427 allocSize = m_numchar * sizeof(WCHAR);
3428 if (allocSize < m_numchar)
3431 LPWSTR wsztemp = (LPWSTR)_alloca( (size_t)allocSize );
3432 int ncwritten = MultiByteToWideChar(CP_ACP,
3435 -1, // # of CHAR's in inbuffer
3437 m_numchar // size (in WCHAR) of outbuffer
3442 // intentionally not throwing for MB2WC failure. We don't always know
3443 // whether to expect a valid string in the buffer and we don't want
3444 // to throw exceptions randomly.
3448 pString = StringObject::NewString((const WCHAR *)wsztemp, ncwritten-1);
3449 *((STRINGREF*)ppProtectedCLRValue) = pString;
3453 //=======================================================================
3454 // CHAR[] <--> char[]
3455 // See FieldMarshaler for details.
3456 //=======================================================================
3457 VOID FieldMarshaler_FixedCharArrayAnsi::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3464 INJECT_FAULT(COMPlusThrowOM());
3465 PRECONDITION(CheckPointer(pNativeValue));
3470 *((OBJECTREF*)&pArray) = *pCLRValue;
3473 FillMemory(pNativeValue, m_numElems * sizeof(CHAR), 0);
3476 if (pArray->GetNumComponents() < m_numElems)
3477 COMPlusThrow(kArgumentException, IDS_WRONGSIZEARRAY_IN_NSTRUCT);
3480 InternalWideToAnsi((const WCHAR*) pArray->GetDataPtr(),
3482 (CHAR*)pNativeValue,
3483 m_numElems * sizeof(CHAR),
3485 m_ThrowOnUnmappableChar);
3491 //=======================================================================
3492 // CHAR[] <--> char[]
3493 // See FieldMarshaler for details.
3494 //=======================================================================
3495 VOID FieldMarshaler_FixedCharArrayAnsi::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3502 INJECT_FAULT(COMPlusThrowOM());
3503 PRECONDITION(CheckPointer(pNativeValue));
3504 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3508 *ppProtectedCLRValue = AllocatePrimitiveArray(ELEMENT_TYPE_CHAR, m_numElems);
3510 MultiByteToWideChar(CP_ACP,
3512 (const CHAR *)pNativeValue,
3513 m_numElems * sizeof(CHAR), // size, in bytes, of in buffer
3514 (WCHAR*) ((*((I2ARRAYREF*)ppProtectedCLRValue))->GetDirectPointerToNonObjectElements()),
3515 m_numElems); // size, in WCHAR's of outbuffer
3518 #endif // CROSSGEN_COMPILE
3521 //=======================================================================
3523 // See FieldMarshaler for details.
3524 //=======================================================================
3525 FieldMarshaler_FixedArray::FieldMarshaler_FixedArray(IMDInternalImport *pMDImport, mdTypeDef cl, UINT32 numElems, VARTYPE vt, MethodTable* pElementMT)
3526 : m_numElems(numElems)
3528 , m_BestFitMap(FALSE)
3529 , m_ThrowOnUnmappableChar(FALSE)
3536 PRECONDITION(CheckPointer(pElementMT));
3537 PRECONDITION(vt != VTHACK_ANSICHAR); // This must be handled by the FixedCharArrayAnsi marshaler.
3541 // Only attempt to read the best fit mapping attribute if required to minimize
3542 // custom attribute accesses.
3543 if (vt == VT_LPSTR || vt == VT_RECORD)
3545 BOOL BestFitMap = FALSE;
3546 BOOL ThrowOnUnmappableChar = FALSE;
3547 ReadBestFitCustomAttribute(pMDImport, cl, &BestFitMap, &ThrowOnUnmappableChar);
3548 m_BestFitMap = !!BestFitMap;
3549 m_ThrowOnUnmappableChar = !!ThrowOnUnmappableChar;
3552 m_arrayType.SetValue(ClassLoader::LoadArrayTypeThrowing(TypeHandle(pElementMT),
3553 ELEMENT_TYPE_SZARRAY,
3555 ClassLoader::LoadTypes,
3556 pElementMT->GetLoadLevel()));
3560 #ifndef CROSSGEN_COMPILE
3562 //=======================================================================
3564 // See FieldMarshaler for details.
3565 //=======================================================================
3566 VOID FieldMarshaler_FixedArray::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3573 PRECONDITION(CheckPointer(pNativeValue));
3577 if (*pCLRValue == NULL)
3579 FillMemory(pNativeValue, NativeSize(), 0);
3583 // Make sure the size of the array is >= as specified in the MarshalAs attribute (via the SizeConst field).
3584 if ((*pCLRValue)->GetNumComponents() < m_numElems)
3585 COMPlusThrow(kArgumentException, IDS_WRONGSIZEARRAY_IN_NSTRUCT);
3587 // Marshal the contents from the managed array to the native array.
3588 const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(m_vt, TRUE);
3589 if (pMarshaler == NULL || pMarshaler->ComToOleArray == NULL)
3591 memcpyNoGCRefs(pNativeValue, (*(BASEARRAYREF*)pCLRValue)->GetDataPtr(), NativeSize());
3595 MethodTable *pElementMT = m_arrayType.GetValue().AsArray()->GetArrayElementTypeHandle().GetMethodTable();
3597 // We never operate on an uninitialized native layout here, we have zero'ed it if needed.
3598 // Therefore fOleArrayIsValid is always TRUE.
3599 pMarshaler->ComToOleArray((BASEARRAYREF*)pCLRValue, pNativeValue, pElementMT, m_BestFitMap, m_ThrowOnUnmappableChar, TRUE, m_numElems);
3605 //=======================================================================
3607 // See FieldMarshaler for details.
3608 //=======================================================================
3609 VOID FieldMarshaler_FixedArray::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3616 INJECT_FAULT(COMPlusThrowOM());
3617 PRECONDITION(CheckPointer(pNativeValue));
3618 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3622 // Allocate the value class array.
3623 *ppProtectedCLRValue = AllocateArrayEx(m_arrayType.GetValue(), (INT32*)&m_numElems, 1);
3625 // Marshal the contents from the native array to the managed array.
3626 const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(m_vt, TRUE);
3627 if (pMarshaler == NULL || pMarshaler->OleToComArray == NULL)
3629 memcpyNoGCRefs((*(BASEARRAYREF*)ppProtectedCLRValue)->GetDataPtr(), pNativeValue, NativeSize());
3633 MethodTable *pElementMT = m_arrayType.GetValue().AsArray()->GetArrayElementTypeHandle().GetMethodTable();
3634 pMarshaler->OleToComArray((VOID *)pNativeValue, (BASEARRAYREF*)ppProtectedCLRValue, pElementMT);
3638 //=======================================================================
3640 // See FieldMarshaler for details.
3641 //=======================================================================
3642 VOID FieldMarshaler_FixedArray::DestroyNativeImpl(LPVOID pNativeValue) const
3649 INJECT_FAULT(COMPlusThrowOM());
3650 PRECONDITION(CheckPointer(pNativeValue));
3654 const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(m_vt, FALSE);
3656 if (pMarshaler != NULL && pMarshaler->ClearOleArray != NULL)
3658 MethodTable *pElementMT = m_arrayType.GetValue().AsArray()->GetArrayElementTypeHandle().GetMethodTable();
3659 pMarshaler->ClearOleArray(pNativeValue, m_numElems, pElementMT);
3663 #endif // CROSSGEN_COMPILE
3666 //=======================================================================
3668 // See FieldMarshaler for details.
3669 //=======================================================================
3670 UINT32 FieldMarshaler_FixedArray::AlignmentRequirementImpl() const
3672 WRAPPER_NO_CONTRACT;
3674 UINT32 alignment = 0;
3675 TypeHandle elementType = m_arrayType.GetValue().AsArray()->GetArrayElementTypeHandle();
3688 alignment = elementType.GetMethodTable()->GetLayoutInfo()->GetLargestAlignmentRequirementOfAllMembers();
3692 alignment = OleVariant::GetElementSizeForVarType(m_vt, elementType.GetMethodTable());
3699 #ifndef CROSSGEN_COMPILE
3701 #ifdef FEATURE_CLASSIC_COMINTEROP
3702 //=======================================================================
3704 // See FieldMarshaler for details.
3705 //=======================================================================
3706 VOID FieldMarshaler_SafeArray::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3713 PRECONDITION(CheckPointer(pNativeValue));
3717 BASEARRAYREF pArray;
3718 *((OBJECTREF*)&pArray) = *pCLRValue;
3719 if ((pArray == NULL) || (OBJECTREFToObject(pArray) == NULL))
3721 FillMemory(pNativeValue, sizeof(LPSAFEARRAY*), 0);
3725 LPSAFEARRAY* pSafeArray;
3726 pSafeArray = (LPSAFEARRAY*)pNativeValue;
3729 MethodTable* pMT = m_pMT.GetValueMaybeNull();
3731 GCPROTECT_BEGIN(pArray)
3734 vt = OleVariant::GetElementVarTypeForArrayRef(pArray);
3737 pMT = OleVariant::GetArrayElementTypeWrapperAware(&pArray).GetMethodTable();
3739 // OleVariant calls throw on error.
3740 *pSafeArray = OleVariant::CreateSafeArrayForArrayRef(&pArray, vt, pMT);
3741 OleVariant::MarshalSafeArrayForArrayRef(&pArray, *pSafeArray, vt, pMT);
3747 //=======================================================================
3749 // See FieldMarshaler for details.
3750 //=======================================================================
3751 VOID FieldMarshaler_SafeArray::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3758 INJECT_FAULT(COMPlusThrowOM());
3759 PRECONDITION(CheckPointer(pNativeValue));
3760 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3764 LPSAFEARRAY* pSafeArray;
3765 pSafeArray = (LPSAFEARRAY*)pNativeValue;
3767 if ((pSafeArray == NULL) || (*pSafeArray == NULL))
3769 *ppProtectedCLRValue = NULL;
3774 MethodTable* pMT = m_pMT.GetValueMaybeNull();
3776 // If we have an empty vartype, get it from the safearray vartype
3779 if (FAILED(ClrSafeArrayGetVartype(*pSafeArray, &vt)))
3780 COMPlusThrow(kArgumentException, IDS_EE_INVALID_SAFEARRAY);
3783 // Get the method table if we need to.
3784 if ((vt == VT_RECORD) && (!pMT))
3785 pMT = OleVariant::GetElementTypeForRecordSafeArray(*pSafeArray).GetMethodTable();
3787 // If we have a single dimension safearray, it will be converted into a SZArray.
3788 // SZArray must have a lower bound of zero.
3789 LONG LowerBound = -1;
3790 UINT Dimensions = SafeArrayGetDim( (SAFEARRAY*)*pSafeArray );
3792 if (Dimensions == 1)
3794 HRESULT hr = SafeArrayGetLBound((SAFEARRAY*)*pSafeArray, 1, &LowerBound);
3795 if ( FAILED(hr) || LowerBound != 0)
3796 COMPlusThrow(kSafeArrayRankMismatchException, IDS_EE_SAFEARRAYSZARRAYMISMATCH);
3799 // OleVariant calls throw on error.
3800 *ppProtectedCLRValue = OleVariant::CreateArrayRefForSafeArray(*pSafeArray, vt, pMT);
3801 OleVariant::MarshalArrayRefForSafeArray(*pSafeArray, (BASEARRAYREF*)ppProtectedCLRValue, vt, pMT);
3805 //=======================================================================
3807 // See FieldMarshaler for details.
3808 //=======================================================================
3809 VOID FieldMarshaler_SafeArray::DestroyNativeImpl(LPVOID pNativeValue) const
3816 PRECONDITION(CheckPointer(pNativeValue));
3823 LPSAFEARRAY psa = (LPSAFEARRAY)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3824 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3828 _ASSERTE (GetModuleHandleA("oleaut32.dll") != NULL);
3829 // SafeArray has been created, which means oleaut32 should have been loaded.
3830 // Delay load will not fail.
3831 CONTRACT_VIOLATION(ThrowsViolation);
3832 hr = SafeArrayDestroy(psa);
3833 _ASSERTE(!FAILED(hr));
3836 #endif //FEATURE_CLASSIC_COMINTEROP
3839 //=======================================================================
3840 // function ptr <--> Delegate
3841 // See FieldMarshaler for details.
3842 //=======================================================================
3843 VOID FieldMarshaler_Delegate::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3850 PRECONDITION(CheckPointer(pNativeValue));
3854 LPVOID fnPtr = COMDelegate::ConvertToCallback(*pCLRValue);
3855 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, fnPtr);
3859 //=======================================================================
3860 // function ptr <--> Delegate
3861 // See FieldMarshaler for details.
3862 //=======================================================================
3863 VOID FieldMarshaler_Delegate::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3870 PRECONDITION(CheckPointer(pNativeValue));
3871 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3875 *ppProtectedCLRValue = COMDelegate::ConvertToDelegate((LPVOID)MAYBE_UNALIGNED_READ(pNativeValue, _PTR), GetMethodTable());
3879 //=======================================================================
3880 // SafeHandle <--> Handle
3881 // See FieldMarshaler for details.
3882 //=======================================================================
3883 VOID FieldMarshaler_SafeHandle::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3890 PRECONDITION(CheckPointer(pNativeValue));
3891 PRECONDITION(CheckPointer(ppCleanupWorkListOnStack, NULL_OK));
3895 SAFEHANDLE *pSafeHandleObj = ((SAFEHANDLE *)pCLRValue);
3897 // A cleanup list MUST be specified in order for us to be able to marshal
3899 if (ppCleanupWorkListOnStack == NULL)
3900 COMPlusThrow(kInvalidOperationException, IDS_EE_SH_FIELD_INVALID_OPERATION);
3902 if (*pSafeHandleObj == NULL)
3903 COMPlusThrow(kArgumentNullException, W("ArgumentNull_SafeHandle"));
3905 // Call StubHelpers.AddToCleanupList to AddRef and schedule Release on this SafeHandle
3906 // This is realiable, i.e. the cleanup will happen if and only if the SH was actually AddRef'ed.
3907 MethodDescCallSite AddToCleanupList(METHOD__STUBHELPERS__ADD_TO_CLEANUP_LIST);
3911 (ARG_SLOT)ppCleanupWorkListOnStack,
3912 ObjToArgSlot(*pSafeHandleObj)
3915 LPVOID handle = AddToCleanupList.Call_RetLPVOID(args);
3917 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, handle);
3921 //=======================================================================
3922 // SafeHandle <--> Handle
3923 // See FieldMarshaler for details.
3924 //=======================================================================
3925 VOID FieldMarshaler_SafeHandle::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3932 PRECONDITION(CheckPointer(pNativeValue));
3933 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3934 PRECONDITION(CheckPointer(ppProtectedOldCLRValue));
3938 // Since we dissallow marshaling SafeHandle fields from unmanaged to managed, check
3939 // to see if this handle was obtained from a SafeHandle and if it was that the
3940 // handle value hasn't changed.
3941 SAFEHANDLE *pSafeHandleObj = (SAFEHANDLE *)ppProtectedOldCLRValue;
3942 if (!*pSafeHandleObj || (*pSafeHandleObj)->GetHandle() != (LPVOID)MAYBE_UNALIGNED_READ(pNativeValue, _PTR))
3943 COMPlusThrow(kNotSupportedException, IDS_EE_CANNOT_CREATE_SAFEHANDLE_FIELD);
3945 // Now that we know the handle hasn't changed we just copy set the new SafeHandle
3947 *ppProtectedCLRValue = *ppProtectedOldCLRValue;
3951 //=======================================================================
3952 // CriticalHandle <--> Handle
3953 // See FieldMarshaler for details.
3954 //=======================================================================
3955 VOID FieldMarshaler_CriticalHandle::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3962 PRECONDITION(CheckPointer(pNativeValue));
3966 LPVOID handle = ((CRITICALHANDLE)*pCLRValue)->GetHandle();
3967 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, handle);
3971 //=======================================================================
3972 // CriticalHandle <--> Handle
3973 // See FieldMarshaler for details.
3974 //=======================================================================
3975 VOID FieldMarshaler_CriticalHandle::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3982 PRECONDITION(CheckPointer(pNativeValue));
3983 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3984 PRECONDITION(CheckPointer(ppProtectedOldCLRValue));
3988 // Since we dissallow marshaling CriticalHandle fields from unmanaged to managed, check
3989 // to see if this handle was obtained from a CriticalHandle and if it was that the
3990 // handle value hasn't changed.
3991 CRITICALHANDLE *pCriticalHandleObj = (CRITICALHANDLE *)ppProtectedOldCLRValue;
3992 if (!*pCriticalHandleObj || (*pCriticalHandleObj)->GetHandle() != (LPVOID)MAYBE_UNALIGNED_READ(pNativeValue, _PTR))
3993 COMPlusThrow(kNotSupportedException, IDS_EE_CANNOT_CREATE_CRITICALHANDLE_FIELD);
3995 // Now that we know the handle hasn't changed we just copy set the new CriticalHandle
3997 *ppProtectedCLRValue = *ppProtectedOldCLRValue;
4000 #ifdef FEATURE_COMINTEROP
4002 //=======================================================================
4003 // COM IP <--> interface
4004 // See FieldMarshaler for details.
4005 //=======================================================================
4006 VOID FieldMarshaler_Interface::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
4013 PRECONDITION(CheckPointer(pNativeValue));
4017 IUnknown *pUnk = NULL;
4019 if (!m_pItfMT.IsNull())
4021 pUnk = GetComIPFromObjectRef(pCLRValue, GetInterfaceMethodTable());
4023 else if (!(m_dwFlags & ItfMarshalInfo::ITF_MARSHAL_USE_BASIC_ITF))
4025 pUnk = GetComIPFromObjectRef(pCLRValue, GetMethodTable());
4029 ComIpType ReqIpType = !!(m_dwFlags & ItfMarshalInfo::ITF_MARSHAL_DISP_ITF) ? ComIpType_Dispatch : ComIpType_Unknown;
4030 pUnk = GetComIPFromObjectRef(pCLRValue, ReqIpType, NULL);
4033 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, pUnk);
4037 //=======================================================================
4038 // COM IP <--> interface
4039 // See FieldMarshaler for details.
4040 //=======================================================================
4041 VOID FieldMarshaler_Interface::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
4048 PRECONDITION(CheckPointer(pNativeValue));
4049 PRECONDITION(CheckPointer(ppProtectedCLRValue));
4050 PRECONDITION(IsProtectedByGCFrame(ppProtectedCLRValue));
4054 IUnknown *pUnk = (IUnknown*)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
4056 MethodTable *pItfMT = GetInterfaceMethodTable();
4057 if (pItfMT != NULL && !pItfMT->IsInterface())
4060 GetObjectRefFromComIP(
4061 ppProtectedCLRValue, // Created object
4062 pUnk, // Interface pointer
4063 GetMethodTable(), // Class MT
4064 pItfMT, // Interface MT
4065 (m_dwFlags & ItfMarshalInfo::ITF_MARSHAL_CLASS_IS_HINT) // Flags
4070 //=======================================================================
4071 // COM IP <--> interface
4072 // See FieldMarshaler for details.
4073 //=======================================================================
4074 VOID FieldMarshaler_Interface::DestroyNativeImpl(LPVOID pNativeValue) const
4081 PRECONDITION(CheckPointer(pNativeValue));
4085 IUnknown *pUnk = (IUnknown*)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
4086 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
4090 ULONG cbRef = SafeRelease(pUnk);
4091 LogInteropRelease(pUnk, cbRef, "Field marshaler destroy native");
4095 #endif // FEATURE_COMINTEROP
4098 //=======================================================================
4099 // See FieldMarshaler for details.
4100 //=======================================================================
4101 VOID FieldMarshaler_Date::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const
4108 PRECONDITION(CheckPointer(pCLR));
4109 PRECONDITION(CheckPointer(pNative));
4113 // <TODO> Handle unaligned native fields </TODO>
4114 *((DATE*)pNative) = COMDateTime::TicksToDoubleDate(*((INT64*)pCLR));
4118 //=======================================================================
4119 // See FieldMarshaler for details.
4120 //=======================================================================
4121 VOID FieldMarshaler_Date::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const
4128 PRECONDITION(CheckPointer(pNative));
4129 PRECONDITION(CheckPointer(pCLR));
4133 // <TODO> Handle unaligned native fields </TODO>
4134 *((INT64*)pCLR) = COMDateTime::DoubleDateToTicks(*((DATE*)pNative));
4138 #ifdef FEATURE_COMINTEROP
4140 //=======================================================================
4141 // See FieldMarshaler for details.
4142 //=======================================================================
4143 VOID FieldMarshaler_Currency::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const
4150 PRECONDITION(CheckPointer(pCLR));
4151 PRECONDITION(CheckPointer(pNative));
4155 // no need to switch to preemptive mode because it's very primitive operaion, doesn't take
4156 // long and is guaranteed not to call 3rd party code.
4157 // But if we do need to switch to preemptive mode, we can't pass the managed pointer to native code directly
4158 HRESULT hr = VarCyFromDec( (DECIMAL *)pCLR, (CURRENCY*)pNative);
4165 //=======================================================================
4166 // See FieldMarshaler for details.
4167 //=======================================================================
4168 VOID FieldMarshaler_Currency::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const
4175 PRECONDITION(CheckPointer(pNative));
4176 PRECONDITION(CheckPointer(pCLR));
4180 // no need to switch to preemptive mode because it's very primitive operaion, doesn't take
4181 // long and is guaranteed not to call 3rd party code.
4182 // But if we do need to switch to preemptive mode, we can't pass the managed pointer to native code directly
4183 HRESULT hr = VarDecFromCy( *(CURRENCY*)pNative, (DECIMAL *)pCLR );
4187 if (FAILED(DecimalCanonicalize((DECIMAL*)pCLR)))
4188 COMPlusThrow(kOverflowException, W("Overflow_Currency"));
4191 VOID FieldMarshaler_DateTimeOffset::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const
4198 PRECONDITION(CheckPointer(pCLR));
4199 PRECONDITION(CheckPointer(pNative));
4203 MethodDescCallSite convertToNative(METHOD__DATETIMEOFFSETMARSHALER__CONVERT_TO_NATIVE);
4207 PtrToArgSlot(pNative)
4209 convertToNative.Call(args);
4212 VOID FieldMarshaler_DateTimeOffset::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const
4219 PRECONDITION(CheckPointer(pNative));
4220 PRECONDITION(CheckPointer(pCLR));
4224 MethodDescCallSite convertToManaged(METHOD__DATETIMEOFFSETMARSHALER__CONVERT_TO_MANAGED);
4228 PtrToArgSlot(pNative)
4230 convertToManaged.Call(args);
4233 #endif // FEATURE_COMINTEROP
4236 //=======================================================================
4237 // See FieldMarshaler for details.
4238 //=======================================================================
4239 VOID FieldMarshaler_Illegal::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const
4246 PRECONDITION(CheckPointer(pCLR));
4247 PRECONDITION(CheckPointer(pNative));
4251 DefineFullyQualifiedNameForClassW();
4253 StackSString ssFieldName(SString::Utf8, GetFieldDesc()->GetName());
4255 StackSString errorString(W("Unknown error."));
4256 errorString.LoadResource(CCompRC::Error, m_resIDWhy);
4258 COMPlusThrow(kTypeLoadException, IDS_EE_BADMARSHALFIELD_ERROR_MSG,
4259 GetFullyQualifiedNameForClassW(GetFieldDesc()->GetEnclosingMethodTable()),
4260 ssFieldName.GetUnicode(), errorString.GetUnicode());
4264 //=======================================================================
4265 // See FieldMarshaler for details.
4266 //=======================================================================
4267 VOID FieldMarshaler_Illegal::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const
4274 PRECONDITION(CheckPointer(pNative));
4275 PRECONDITION(CheckPointer(pCLR));
4279 DefineFullyQualifiedNameForClassW();
4281 StackSString ssFieldName(SString::Utf8, GetFieldDesc()->GetName());
4283 StackSString errorString(W("Unknown error."));
4284 errorString.LoadResource(CCompRC::Error,m_resIDWhy);
4286 COMPlusThrow(kTypeLoadException, IDS_EE_BADMARSHALFIELD_ERROR_MSG,
4287 GetFullyQualifiedNameForClassW(GetFieldDesc()->GetEnclosingMethodTable()),
4288 ssFieldName.GetUnicode(), errorString.GetUnicode());
4291 #ifdef FEATURE_COMINTEROP
4294 //=======================================================================
4295 // See FieldMarshaler for details.
4296 //=======================================================================
4297 VOID FieldMarshaler_Variant::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
4304 PRECONDITION(CheckPointer(pNativeValue));
4308 OleVariant::MarshalOleVariantForObject(pCLRValue, (VARIANT*)pNativeValue);
4313 //=======================================================================
4314 // See FieldMarshaler for details.
4315 //=======================================================================
4316 VOID FieldMarshaler_Variant::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
4323 PRECONDITION(CheckPointer(pNativeValue));
4324 PRECONDITION(CheckPointer(ppProtectedCLRValue));
4328 OleVariant::MarshalObjectForOleVariant((VARIANT*)pNativeValue, ppProtectedCLRValue);
4332 //=======================================================================
4333 // See FieldMarshaler for details.
4334 //=======================================================================
4335 VOID FieldMarshaler_Variant::DestroyNativeImpl(LPVOID pNativeValue) const
4342 PRECONDITION(CheckPointer(pNativeValue));
4346 SafeVariantClear( (VARIANT*)pNativeValue );
4349 #endif // FEATURE_COMINTEROP
4353 #pragma warning(push)
4354 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
4356 VOID NStructFieldTypeToString(FieldMarshaler* pFM, SString& strNStructFieldType)
4363 INJECT_FAULT(COMPlusThrowOM());
4364 PRECONDITION(CheckPointer(pFM));
4368 NStructFieldType cls = pFM->GetNStructFieldType();
4370 CorElementType elemType = pFM->GetFieldDesc()->GetFieldType();
4372 // Some NStruct Field Types have extra information and require special handling.
4373 if (cls == NFT_FIXEDCHARARRAYANSI)
4375 strNStructFieldType.Printf(W("fixed array of ANSI char (size = %i bytes)"), pFM->NativeSize());
4378 else if (cls == NFT_FIXEDARRAY)
4380 VARTYPE vtElement = ((FieldMarshaler_FixedArray*)pFM)->GetElementVT();
4381 TypeHandle thElement = ((FieldMarshaler_FixedArray*)pFM)->GetElementTypeHandle();
4382 BOOL fElementTypeUserDefined = FALSE;
4384 // Determine if the array type is a user defined type.
4385 if (vtElement == VT_RECORD)
4387 fElementTypeUserDefined = TRUE;
4389 else if (vtElement == VT_UNKNOWN || vtElement == VT_DISPATCH)
4391 fElementTypeUserDefined = !thElement.IsObjectType();
4394 // Retrieve the string representation for the VARTYPE.
4395 StackSString strVarType;
4396 MarshalInfo::VarTypeToString(vtElement, strVarType);
4398 MethodTable *pMT = ((FieldMarshaler_FixedArray*)pFM)->GetElementTypeHandle().GetMethodTable();
4399 DefineFullyQualifiedNameForClassW();
4400 WCHAR* szClassName = (WCHAR*)GetFullyQualifiedNameForClassW(pMT);
4402 if (fElementTypeUserDefined)
4404 strNStructFieldType.Printf(W("fixed array of %s exposed as %s elements (array size = %i bytes)"),
4406 strVarType.GetUnicode(), pFM->NativeSize());
4410 strNStructFieldType.Printf(W("fixed array of %s (array size = %i bytes)"),
4411 szClassName, pFM->NativeSize());
4416 #ifdef FEATURE_COMINTEROP
4417 else if (cls == NFT_INTERFACE)
4419 MethodTable *pItfMT = NULL;
4422 ((FieldMarshaler_Interface*)pFM)->GetInterfaceInfo(&pItfMT, &dwFlags);
4424 if (dwFlags & ItfMarshalInfo::ITF_MARSHAL_DISP_ITF)
4426 strNStructFieldType.Set(W("IDispatch "));
4430 strNStructFieldType.Set(W("IUnknown "));
4433 if (dwFlags & ItfMarshalInfo::ITF_MARSHAL_USE_BASIC_ITF)
4435 strNStructFieldType.Append(W("(basic) "));
4441 DefineFullyQualifiedNameForClassW();
4442 GetFullyQualifiedNameForClassW(pItfMT);
4444 strNStructFieldType.Append(GetFullyQualifiedNameForClassW(pItfMT));
4449 #ifdef FEATURE_CLASSIC_COMINTEROP
4450 else if (cls == NFT_SAFEARRAY)
4452 VARTYPE vtElement = ((FieldMarshaler_SafeArray*)pFM)->GetElementVT();
4453 TypeHandle thElement = ((FieldMarshaler_SafeArray*)pFM)->GetElementTypeHandle();
4454 BOOL fElementTypeUserDefined = FALSE;
4456 // Determine if the array type is a user defined type.
4457 if (vtElement == VT_RECORD)
4459 fElementTypeUserDefined = TRUE;
4461 else if (vtElement == VT_UNKNOWN || vtElement == VT_DISPATCH)
4463 fElementTypeUserDefined = !thElement.IsObjectType();
4466 // Retrieve the string representation for the VARTYPE.
4467 StackSString strVarType;
4468 MarshalInfo::VarTypeToString(vtElement, strVarType);
4471 StackSString strClassName;
4472 if (!thElement.IsNull())
4474 DefineFullyQualifiedNameForClassW();
4475 MethodTable *pMT = ((FieldMarshaler_SafeArray*)pFM)->GetElementTypeHandle().GetMethodTable();
4476 strClassName.Set((WCHAR*)GetFullyQualifiedNameForClassW(pMT));
4480 strClassName.Set(W("object"));
4483 if (fElementTypeUserDefined)
4485 strNStructFieldType.Printf(W("safe array of %s exposed as %s elements (array size = %i bytes)"),
4486 strClassName.GetUnicode(),
4487 strVarType.GetUnicode(), pFM->NativeSize());
4491 strNStructFieldType.Printf(W("safearray of %s (array size = %i bytes)"),
4492 strClassName.GetUnicode(), pFM->NativeSize());
4497 #endif // FEATURE_CLASSIC_COMINTEROP
4498 #endif // FEATURE_COMINTEROP
4499 else if (cls == NFT_NESTEDLAYOUTCLASS)
4501 MethodTable *pMT = ((FieldMarshaler_NestedLayoutClass*)pFM)->GetMethodTable();
4502 DefineFullyQualifiedNameForClassW();
4503 strNStructFieldType.Printf(W("nested layout class %s"),
4504 GetFullyQualifiedNameForClassW(pMT));
4507 else if (cls == NFT_NESTEDVALUECLASS)
4509 MethodTable *pMT = ((FieldMarshaler_NestedValueClass*)pFM)->GetMethodTable();
4510 DefineFullyQualifiedNameForClassW();
4511 strNStructFieldType.Printf(W("nested value class %s"),
4512 GetFullyQualifiedNameForClassW(pMT));
4515 else if (cls == NFT_COPY1)
4517 // The following CorElementTypes are the only ones handled with FieldMarshaler_Copy1.
4520 case ELEMENT_TYPE_I1:
4521 strRetVal = W("SByte");
4524 case ELEMENT_TYPE_U1:
4525 strRetVal = W("Byte");
4529 strRetVal = W("Unknown");
4533 else if (cls == NFT_COPY2)
4535 // The following CorElementTypes are the only ones handled with FieldMarshaler_Copy2.
4538 case ELEMENT_TYPE_CHAR:
4539 strRetVal = W("Unicode char");
4542 case ELEMENT_TYPE_I2:
4543 strRetVal = W("Int16");
4546 case ELEMENT_TYPE_U2:
4547 strRetVal = W("UInt16");
4551 strRetVal = W("Unknown");
4555 else if (cls == NFT_COPY4)
4557 // The following CorElementTypes are the only ones handled with FieldMarshaler_Copy4.
4560 // At this point, ELEMENT_TYPE_I must be 4 bytes long. Same for ELEMENT_TYPE_U.
4561 case ELEMENT_TYPE_I:
4562 case ELEMENT_TYPE_I4:
4563 strRetVal = W("Int32");
4566 case ELEMENT_TYPE_U:
4567 case ELEMENT_TYPE_U4:
4568 strRetVal = W("UInt32");
4571 case ELEMENT_TYPE_R4:
4572 strRetVal = W("Single");
4575 case ELEMENT_TYPE_PTR:
4576 strRetVal = W("4-byte pointer");
4580 strRetVal = W("Unknown");
4584 else if (cls == NFT_COPY8)
4586 // The following CorElementTypes are the only ones handled with FieldMarshaler_Copy8.
4589 // At this point, ELEMENT_TYPE_I must be 8 bytes long. Same for ELEMENT_TYPE_U.
4590 case ELEMENT_TYPE_I:
4591 case ELEMENT_TYPE_I8:
4592 strRetVal = W("Int64");
4595 case ELEMENT_TYPE_U:
4596 case ELEMENT_TYPE_U8:
4597 strRetVal = W("UInt64");
4600 case ELEMENT_TYPE_R8:
4601 strRetVal = W("Double");
4604 case ELEMENT_TYPE_PTR:
4605 strRetVal = W("8-byte pointer");
4609 strRetVal = W("Unknown");
4613 else if (cls == NFT_FIXEDSTRINGUNI)
4615 int nativeSize = pFM->NativeSize();
4616 int strLength = nativeSize / sizeof(WCHAR);
4618 strNStructFieldType.Printf(W("embedded LPWSTR (length %d)"), strLength);
4622 else if (cls == NFT_FIXEDSTRINGANSI)
4624 int nativeSize = pFM->NativeSize();
4625 int strLength = nativeSize / sizeof(CHAR);
4627 strNStructFieldType.Printf(W("embedded LPSTR (length %d)"), strLength);
4633 // All other NStruct Field Types which do not require special handling.
4636 #ifdef FEATURE_COMINTEROP
4638 strRetVal = W("BSTR");
4641 strRetVal = W("HSTRING");
4643 #endif // FEATURE_COMINTEROP
4645 strRetVal = W("LPWSTR");
4647 case NFT_STRINGANSI:
4648 strRetVal = W("LPSTR");
4651 strRetVal = W("Delegate");
4653 #ifdef FEATURE_COMINTEROP
4655 strRetVal = W("VARIANT");
4657 #endif // FEATURE_COMINTEROP
4659 strRetVal = W("ANSI char");
4662 strRetVal = W("Windows Bool");
4665 strRetVal = W("CBool");
4668 strRetVal = W("DECIMAL");
4671 strRetVal = W("DATE");
4673 #ifdef FEATURE_COMINTEROP
4674 case NFT_VARIANTBOOL:
4675 strRetVal = W("VARIANT Bool");
4678 strRetVal = W("CURRENCY");
4680 #endif // FEATURE_COMINTEROP
4682 strRetVal = W("illegal type");
4684 case NFT_SAFEHANDLE:
4685 strRetVal = W("SafeHandle");
4687 case NFT_CRITICALHANDLE:
4688 strRetVal = W("CriticalHandle");
4691 strRetVal = W("<UNKNOWN>");
4696 strNStructFieldType.Set(strRetVal);
4701 #pragma warning(pop)
4704 #endif // CROSSGEN_COMPILE
4708 // Implementation of the virtual functions using switch statements.
4710 // We are not able bake pointers to the FieldMarshaller vtables into NGen images. We store
4711 // the field marshaller id instead, and implement the virtualization by switch based on the id.
4714 #ifdef FEATURE_CLASSIC_COMINTEROP
4715 #define FieldMarshaler_SafeArray_Case(rettype, name, args) case NFT_SAFEARRAY: rettype ((FieldMarshaler_SafeArray*)this)->name##Impl args; break;
4717 #define FieldMarshaler_SafeArray_Case(rettype, name, args)
4720 #ifdef FEATURE_COMINTEROP
4722 #define IMPLEMENT_FieldMarshaler_METHOD(ret, name, argsdecl, rettype, args) \
4723 ret FieldMarshaler::name argsdecl { \
4724 WRAPPER_NO_CONTRACT; \
4725 switch (GetNStructFieldType()) { \
4726 case NFT_STRINGUNI: rettype ((FieldMarshaler_StringUni*)this)->name##Impl args; break; \
4727 case NFT_STRINGANSI: rettype ((FieldMarshaler_StringAnsi*)this)->name##Impl args; break; \
4728 case NFT_STRINGUTF8: rettype ((FieldMarshaler_StringUtf8*)this)->name##Impl args; break; \
4729 case NFT_FIXEDSTRINGUNI: rettype ((FieldMarshaler_FixedStringUni*)this)->name##Impl args; break; \
4730 case NFT_FIXEDSTRINGANSI: rettype ((FieldMarshaler_FixedStringAnsi*)this)->name##Impl args; break; \
4731 case NFT_FIXEDCHARARRAYANSI: rettype ((FieldMarshaler_FixedCharArrayAnsi*)this)->name##Impl args; break; \
4732 case NFT_FIXEDARRAY: rettype ((FieldMarshaler_FixedArray*)this)->name##Impl args; break; \
4733 case NFT_DELEGATE: rettype ((FieldMarshaler_Delegate*)this)->name##Impl args; break; \
4734 case NFT_COPY1: rettype ((FieldMarshaler_Copy1*)this)->name##Impl args; break; \
4735 case NFT_COPY2: rettype ((FieldMarshaler_Copy2*)this)->name##Impl args; break; \
4736 case NFT_COPY4: rettype ((FieldMarshaler_Copy4*)this)->name##Impl args; break; \
4737 case NFT_COPY8: rettype ((FieldMarshaler_Copy8*)this)->name##Impl args; break; \
4738 case NFT_ANSICHAR: rettype ((FieldMarshaler_Ansi*)this)->name##Impl args; break; \
4739 case NFT_WINBOOL: rettype ((FieldMarshaler_WinBool*)this)->name##Impl args; break; \
4740 case NFT_NESTEDLAYOUTCLASS: rettype ((FieldMarshaler_NestedLayoutClass*)this)->name##Impl args; break; \
4741 case NFT_NESTEDVALUECLASS: rettype ((FieldMarshaler_NestedValueClass*)this)->name##Impl args; break; \
4742 case NFT_CBOOL: rettype ((FieldMarshaler_CBool*)this)->name##Impl args; break; \
4743 case NFT_DATE: rettype ((FieldMarshaler_Date*)this)->name##Impl args; break; \
4744 case NFT_DECIMAL: rettype ((FieldMarshaler_Decimal*)this)->name##Impl args; break; \
4745 case NFT_INTERFACE: rettype ((FieldMarshaler_Interface*)this)->name##Impl args; break; \
4746 case NFT_SAFEHANDLE: rettype ((FieldMarshaler_SafeHandle*)this)->name##Impl args; break; \
4747 case NFT_CRITICALHANDLE: rettype ((FieldMarshaler_CriticalHandle*)this)->name##Impl args; break; \
4748 FieldMarshaler_SafeArray_Case(rettype, name, args) \
4749 case NFT_BSTR: rettype ((FieldMarshaler_BSTR*)this)->name##Impl args; break; \
4750 case NFT_HSTRING: rettype ((FieldMarshaler_HSTRING*)this)->name##Impl args; break; \
4751 case NFT_VARIANT: rettype ((FieldMarshaler_Variant*)this)->name##Impl args; break; \
4752 case NFT_VARIANTBOOL: rettype ((FieldMarshaler_VariantBool*)this)->name##Impl args; break; \
4753 case NFT_CURRENCY: rettype ((FieldMarshaler_Currency*)this)->name##Impl args; break; \
4754 case NFT_DATETIMEOFFSET: rettype ((FieldMarshaler_DateTimeOffset*)this)->name##Impl args; break; \
4755 case NFT_SYSTEMTYPE: rettype ((FieldMarshaler_SystemType *)this)->name##Impl args; break; \
4756 case NFT_WINDOWSFOUNDATIONHRESULT: rettype ((FieldMarshaler_Exception*)this)->name##Impl args; break; \
4757 case NFT_WINDOWSFOUNDATIONIREFERENCE: rettype ((FieldMarshaler_Nullable*)this)->name##Impl args; break; \
4758 case NFT_ILLEGAL: rettype ((FieldMarshaler_Illegal*)this)->name##Impl args; break; \
4759 default: UNREACHABLE_MSG("unexpected type of FieldMarshaler"); break; \
4763 #else // FEATURE_COMINTEROP
4765 #define IMPLEMENT_FieldMarshaler_METHOD(ret, name, argsdecl, rettype, args) \
4766 ret FieldMarshaler::name argsdecl { \
4767 WRAPPER_NO_CONTRACT; \
4768 switch (GetNStructFieldType()) { \
4769 case NFT_STRINGUNI: rettype ((FieldMarshaler_StringUni*)this)->name##Impl args; break; \
4770 case NFT_STRINGANSI: rettype ((FieldMarshaler_StringAnsi*)this)->name##Impl args; break; \
4771 case NFT_STRINGUTF8: rettype ((FieldMarshaler_StringUtf8*)this)->name##Impl args; break; \
4772 case NFT_FIXEDSTRINGUNI: rettype ((FieldMarshaler_FixedStringUni*)this)->name##Impl args; break; \
4773 case NFT_FIXEDSTRINGANSI: rettype ((FieldMarshaler_FixedStringAnsi*)this)->name##Impl args; break; \
4774 case NFT_FIXEDCHARARRAYANSI: rettype ((FieldMarshaler_FixedCharArrayAnsi*)this)->name##Impl args; break; \
4775 case NFT_FIXEDARRAY: rettype ((FieldMarshaler_FixedArray*)this)->name##Impl args; break; \
4776 case NFT_DELEGATE: rettype ((FieldMarshaler_Delegate*)this)->name##Impl args; break; \
4777 case NFT_COPY1: rettype ((FieldMarshaler_Copy1*)this)->name##Impl args; break; \
4778 case NFT_COPY2: rettype ((FieldMarshaler_Copy2*)this)->name##Impl args; break; \
4779 case NFT_COPY4: rettype ((FieldMarshaler_Copy4*)this)->name##Impl args; break; \
4780 case NFT_COPY8: rettype ((FieldMarshaler_Copy8*)this)->name##Impl args; break; \
4781 case NFT_ANSICHAR: rettype ((FieldMarshaler_Ansi*)this)->name##Impl args; break; \
4782 case NFT_WINBOOL: rettype ((FieldMarshaler_WinBool*)this)->name##Impl args; break; \
4783 case NFT_NESTEDLAYOUTCLASS: rettype ((FieldMarshaler_NestedLayoutClass*)this)->name##Impl args; break; \
4784 case NFT_NESTEDVALUECLASS: rettype ((FieldMarshaler_NestedValueClass*)this)->name##Impl args; break; \
4785 case NFT_CBOOL: rettype ((FieldMarshaler_CBool*)this)->name##Impl args; break; \
4786 case NFT_DATE: rettype ((FieldMarshaler_Date*)this)->name##Impl args; break; \
4787 case NFT_DECIMAL: rettype ((FieldMarshaler_Decimal*)this)->name##Impl args; break; \
4788 case NFT_SAFEHANDLE: rettype ((FieldMarshaler_SafeHandle*)this)->name##Impl args; break; \
4789 case NFT_CRITICALHANDLE: rettype ((FieldMarshaler_CriticalHandle*)this)->name##Impl args; break; \
4790 case NFT_ILLEGAL: rettype ((FieldMarshaler_Illegal*)this)->name##Impl args; break; \
4791 default: UNREACHABLE_MSG("unexpected type of FieldMarshaler"); break; \
4795 #endif // FEATURE_COMINTEROP
4798 IMPLEMENT_FieldMarshaler_METHOD(UINT32, NativeSize,
4803 IMPLEMENT_FieldMarshaler_METHOD(UINT32, AlignmentRequirement,
4808 IMPLEMENT_FieldMarshaler_METHOD(BOOL, IsScalarMarshaler,
4813 IMPLEMENT_FieldMarshaler_METHOD(BOOL, IsNestedValueClassMarshaler,
4818 #ifndef CROSSGEN_COMPILE
4819 IMPLEMENT_FieldMarshaler_METHOD(VOID, UpdateNative,
4820 (OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const,
4822 (pCLRValue, pNativeValue, ppCleanupWorkListOnStack))
4824 IMPLEMENT_FieldMarshaler_METHOD(VOID, UpdateCLR,
4825 (const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const,
4827 (pNativeValue, ppProtectedCLRValue, ppProtectedOldCLRValue))
4829 IMPLEMENT_FieldMarshaler_METHOD(VOID, DestroyNative,
4830 (LPVOID pNativeValue) const,
4834 IMPLEMENT_FieldMarshaler_METHOD(VOID, ScalarUpdateNative,
4835 (LPVOID pCLR, LPVOID pNative) const,
4839 IMPLEMENT_FieldMarshaler_METHOD(VOID, ScalarUpdateCLR,
4840 (const VOID *pNative, LPVOID pCLR) const,
4844 IMPLEMENT_FieldMarshaler_METHOD(VOID, NestedValueClassUpdateNative,
4845 (const VOID **ppProtectedCLR, SIZE_T startoffset, LPVOID pNative, OBJECTREF *ppCleanupWorkListOnStack) const,
4847 (ppProtectedCLR, startoffset, pNative, ppCleanupWorkListOnStack))
4849 IMPLEMENT_FieldMarshaler_METHOD(VOID, NestedValueClassUpdateCLR,
4850 (const VOID *pNative, LPVOID *ppProtectedCLR, SIZE_T startoffset) const,
4852 (pNative, ppProtectedCLR, startoffset))
4853 #endif // CROSSGEN_COMPILE
4855 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
4856 IMPLEMENT_FieldMarshaler_METHOD(void, Save,
4861 IMPLEMENT_FieldMarshaler_METHOD(void, Fixup,
4865 #endif // FEATURE_NATIVE_IMAGE_GENERATION
4867 IMPLEMENT_FieldMarshaler_METHOD(void, Restore,
4872 #ifndef DACCESS_COMPILE
4873 IMPLEMENT_FieldMarshaler_METHOD(VOID, CopyTo,
4874 (VOID *pDest, SIZE_T destSize) const,
4877 #endif // !DACCESS_COMPILE