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);
39 BOOL IsFixedBuffer(mdFieldDef field, IMDInternalImport *pInternalImport);
43 //=======================================================================
44 // A database of NFT types.
45 //=======================================================================
46 struct NFTDataBaseEntry
48 UINT32 m_cbNativeSize; // native size of field (0 if not constant)
49 bool m_fWinRTSupported; // true if the field marshaler is supported for WinRT
52 static const NFTDataBaseEntry NFTDataBase[] =
55 #define DEFINE_NFT(name, nativesize, fWinRTSupported) { nativesize, fWinRTSupported },
60 //=======================================================================
61 // This is invoked from the class loader while building the internal structures for a type
62 // This function should check if explicit layout metadata exists.
65 // TRUE - yes, there's layout metadata
66 // FALSE - no, there's no layout.
67 // fail - throws a typeload exception
70 // *pNLType gets set to nltAnsi or nltUnicode
71 // *pPackingSize declared packing size
72 // *pfExplicitoffsets offsets explicit in metadata or computed?
73 //=======================================================================
74 BOOL HasLayoutMetadata(Assembly* pAssembly, IMDInternalImport *pInternalImport, mdTypeDef cl, MethodTable*pParentMT, BYTE *pPackingSize, BYTE *pNLTType, BOOL *pfExplicitOffsets)
81 PRECONDITION(CheckPointer(pInternalImport));
82 PRECONDITION(CheckPointer(pPackingSize));
83 PRECONDITION(CheckPointer(pNLTType));
84 PRECONDITION(CheckPointer(pfExplicitOffsets));
94 if (FAILED(pInternalImport->GetTypeDefProps(cl, &clFlags, NULL)))
96 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
99 if (IsTdAutoLayout(clFlags))
101 // <BUGNUM>workaround for B#104780 - VC fails to set SequentialLayout on some classes
102 // with ClassSize. Too late to fix compiler for V1.
104 // To compensate, we treat AutoLayout classes as Sequential if they
105 // meet all of the following criteria:
107 // - ClassSize present and nonzero.
108 // - No instance fields declared
109 // - Base class is System.ValueType.
111 ULONG cbTotalSize = 0;
112 if (SUCCEEDED(pInternalImport->GetClassTotalSize(cl, &cbTotalSize)) && cbTotalSize != 0)
114 if (pParentMT && pParentMT->IsValueTypeClass())
116 MDEnumHolder hEnumField(pInternalImport);
117 if (SUCCEEDED(pInternalImport->EnumInit(mdtFieldDef, cl, &hEnumField)))
119 ULONG numFields = pInternalImport->EnumGetCount(&hEnumField);
122 *pfExplicitOffsets = FALSE;
133 else if (IsTdSequentialLayout(clFlags))
135 *pfExplicitOffsets = FALSE;
137 else if (IsTdExplicitLayout(clFlags))
139 *pfExplicitOffsets = TRUE;
143 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
146 // We now know this class has seq. or explicit layout. Ensure the parent does too.
147 if (pParentMT && !(pParentMT->IsObjectClass() || pParentMT->IsValueTypeClass()) && !(pParentMT->HasLayout()))
148 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
150 if (IsTdAnsiClass(clFlags))
154 else if (IsTdUnicodeClass(clFlags))
156 *pNLTType = nltUnicode;
158 else if (IsTdAutoClass(clFlags))
160 // We no longer support Win9x so TdAuto always maps to Unicode.
161 *pNLTType = nltUnicode;
165 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
169 hr = pInternalImport->GetClassPackSize(cl, &dwPackSize);
170 if (FAILED(hr) || dwPackSize == 0)
171 dwPackSize = DEFAULT_PACKING_SIZE;
173 // This has to be reduced to a BYTE value, so we had better make sure it fits. If
174 // not, we'll throw an exception instead of trying to munge the value to what we
175 // think the user might want.
176 if (!FitsInU1((UINT64)(dwPackSize)))
178 pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT);
181 *pPackingSize = (BYTE)dwPackSize;
188 ParseNativeTypeFlag_None = 0x00,
189 ParseNativeTypeFlag_IsAnsi = 0x01,
191 #ifdef FEATURE_COMINTEROP
192 ParseNativeTypeFlag_IsWinRT = 0x02,
193 #endif // FEATURE_COMINTEROP
195 ParseNativeTypeFlags;
197 inline ParseNativeTypeFlags operator|=(ParseNativeTypeFlags& lhs, ParseNativeTypeFlags rhs)
199 LIMITED_METHOD_CONTRACT;
200 lhs = static_cast<ParseNativeTypeFlags>(lhs | rhs);
205 #pragma warning(push)
206 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
208 VOID ParseNativeType(Module* pModule,
209 PCCOR_SIGNATURE pCOMSignature,
210 DWORD cbCOMSignature,
211 ParseNativeTypeFlags flags,
212 LayoutRawFieldInfo* pfwalk,
213 PCCOR_SIGNATURE pNativeType,
215 IMDInternalImport* pInternalImport,
217 const SigTypeContext * pTypeContext,
218 BOOL *pfDisqualifyFromManagedSequential // set to TRUE if needed (never set to FALSE, it may come in as TRUE!)
230 PRECONDITION(CheckPointer(pfwalk));
234 // Make sure that there is no junk in the unused part of the field marshaler space (ngen image determinism)
235 ZeroMemory(&pfwalk->m_FieldMarshaler, MAXFIELDMARSHALERSIZE);
237 #define INITFIELDMARSHALER(nfttype, fmtype, args) \
240 static_assert_no_msg(sizeof(fmtype) <= MAXFIELDMARSHALERSIZE); \
241 pfwalk->m_nft = (nfttype); \
242 new ( &(pfwalk->m_FieldMarshaler) ) fmtype args; \
243 ((FieldMarshaler*)&(pfwalk->m_FieldMarshaler))->SetNStructFieldType(nfttype); \
246 BOOL fAnsi = (flags & ParseNativeTypeFlag_IsAnsi);
247 #ifdef FEATURE_COMINTEROP
248 BOOL fIsWinRT = (flags & ParseNativeTypeFlag_IsWinRT);
249 #endif // FEATURE_COMINTEROP
250 CorElementType corElemType = ELEMENT_TYPE_END;
251 PCCOR_SIGNATURE pNativeTypeStart = pNativeType;
252 ULONG cbNativeTypeStart = cbNativeType;
256 BOOL ThrowOnUnmappableChar;
258 pfwalk->m_nft = NFT_NONE;
260 if (cbNativeType == 0)
262 ntype = NATIVE_TYPE_DEFAULT;
267 ntype = (CorNativeType) *( ((BYTE*&)pNativeType)++ );
269 fDefault = (ntype == NATIVE_TYPE_DEFAULT);
272 #ifdef FEATURE_COMINTEROP
273 if (fIsWinRT && !fDefault)
275 // Do not allow any MarshalAs in WinRT scenarios - marshaling is fully described by the field type.
276 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_MARSHAL_AS));
278 #endif // FEATURE_COMINTEROP
280 // Setup the signature and normalize
281 MetaSig fsig(pCOMSignature, cbCOMSignature, pModule, pTypeContext, MetaSig::sigField);
282 corElemType = fsig.NextArgNormalized();
285 if (!(*pfDisqualifyFromManagedSequential))
287 // This type may qualify for ManagedSequential. Collect managed size and alignment info.
288 if (CorTypeInfo::IsPrimitiveType(corElemType))
290 pfwalk->m_managedSize = ((UINT32)CorTypeInfo::Size(corElemType)); // Safe cast - no primitive type is larger than 4gb!
291 #if defined(_TARGET_X86_) && defined(UNIX_X86_ABI)
294 // The System V ABI for i386 defines different packing for these types.
295 case ELEMENT_TYPE_I8:
296 case ELEMENT_TYPE_U8:
297 case ELEMENT_TYPE_R8:
299 pfwalk->m_managedAlignmentReq = 4;
305 pfwalk->m_managedAlignmentReq = pfwalk->m_managedSize;
309 #else // _TARGET_X86_ && UNIX_X86_ABI
310 pfwalk->m_managedAlignmentReq = pfwalk->m_managedSize;
313 else if (corElemType == ELEMENT_TYPE_PTR)
315 pfwalk->m_managedSize = TARGET_POINTER_SIZE;
316 pfwalk->m_managedAlignmentReq = TARGET_POINTER_SIZE;
318 else if (corElemType == ELEMENT_TYPE_VALUETYPE)
320 TypeHandle pNestedType = fsig.GetLastTypeHandleThrowing(ClassLoader::LoadTypes,
321 CLASS_LOAD_APPROXPARENTS,
323 if (pNestedType.GetMethodTable()->IsManagedSequential())
325 pfwalk->m_managedSize = (pNestedType.GetMethodTable()->GetNumInstanceFieldBytes());
327 _ASSERTE(pNestedType.GetMethodTable()->HasLayout()); // If it is ManagedSequential(), it also has Layout but doesn't hurt to check before we do a cast!
328 pfwalk->m_managedAlignmentReq = pNestedType.GetMethodTable()->GetLayoutInfo()->m_ManagedLargestAlignmentRequirementOfAllMembers;
332 *pfDisqualifyFromManagedSequential = TRUE;
337 // No other type permitted for ManagedSequential.
338 *pfDisqualifyFromManagedSequential = TRUE;
343 // Normalization might have put corElementType and ntype out of sync which can
344 // result in problems with non-default ntype being validated against the
345 // normalized primitive corElemType.
347 VerifyAndAdjustNormalizedType(pModule, fsig.GetArgProps(), fsig.GetSigTypeContext(), &corElemType, &ntype);
349 fDefault = (ntype == NATIVE_TYPE_DEFAULT);
350 #endif // _TARGET_X86_
352 CorElementType sigElemType;
353 IfFailThrow(fsig.GetArgProps().PeekElemType(&sigElemType));
354 if ((sigElemType == ELEMENT_TYPE_GENERICINST || sigElemType == ELEMENT_TYPE_VAR) && corElemType == ELEMENT_TYPE_CLASS)
356 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_GENERICS_RESTRICTION));
358 else switch (corElemType)
360 case ELEMENT_TYPE_CHAR:
365 ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
366 INITFIELDMARSHALER(NFT_ANSICHAR, FieldMarshaler_Ansi, (BestFit, ThrowOnUnmappableChar));
370 INITFIELDMARSHALER(NFT_COPY2, FieldMarshaler_Copy2, ());
373 else if (ntype == NATIVE_TYPE_I1 || ntype == NATIVE_TYPE_U1)
375 ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
376 INITFIELDMARSHALER(NFT_ANSICHAR, FieldMarshaler_Ansi, (BestFit, ThrowOnUnmappableChar));
378 else if (ntype == NATIVE_TYPE_I2 || ntype == NATIVE_TYPE_U2)
380 INITFIELDMARSHALER(NFT_COPY2, FieldMarshaler_Copy2, ());
384 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_CHAR));
388 case ELEMENT_TYPE_BOOLEAN:
391 #ifdef FEATURE_COMINTEROP
394 INITFIELDMARSHALER(NFT_CBOOL, FieldMarshaler_CBool, ());
397 #endif // FEATURE_COMINTEROP
399 INITFIELDMARSHALER(NFT_WINBOOL, FieldMarshaler_WinBool, ());
402 else if (ntype == NATIVE_TYPE_BOOLEAN)
404 INITFIELDMARSHALER(NFT_WINBOOL, FieldMarshaler_WinBool, ());
406 #ifdef FEATURE_COMINTEROP
407 else if (ntype == NATIVE_TYPE_VARIANTBOOL)
409 INITFIELDMARSHALER(NFT_VARIANTBOOL, FieldMarshaler_VariantBool, ());
411 #endif // FEATURE_COMINTEROP
412 else if (ntype == NATIVE_TYPE_U1 || ntype == NATIVE_TYPE_I1)
414 INITFIELDMARSHALER(NFT_CBOOL, FieldMarshaler_CBool, ());
418 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_BOOLEAN));
423 case ELEMENT_TYPE_I1:
424 if (fDefault || ntype == NATIVE_TYPE_I1 || ntype == NATIVE_TYPE_U1)
426 INITFIELDMARSHALER(NFT_COPY1, FieldMarshaler_Copy1, ());
430 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I1));
434 case ELEMENT_TYPE_U1:
435 if (fDefault || ntype == NATIVE_TYPE_U1 || ntype == NATIVE_TYPE_I1)
437 INITFIELDMARSHALER(NFT_COPY1, FieldMarshaler_Copy1, ());
441 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I1));
445 case ELEMENT_TYPE_I2:
446 if (fDefault || ntype == NATIVE_TYPE_I2 || ntype == NATIVE_TYPE_U2)
448 INITFIELDMARSHALER(NFT_COPY2, FieldMarshaler_Copy2, ());
452 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I2));
456 case ELEMENT_TYPE_U2:
457 if (fDefault || ntype == NATIVE_TYPE_U2 || ntype == NATIVE_TYPE_I2)
459 INITFIELDMARSHALER(NFT_COPY2, FieldMarshaler_Copy2, ());
463 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I2));
467 case ELEMENT_TYPE_I4:
468 if (fDefault || ntype == NATIVE_TYPE_I4 || ntype == NATIVE_TYPE_U4 || ntype == NATIVE_TYPE_ERROR)
470 INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ());
474 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I4));
478 case ELEMENT_TYPE_U4:
479 if (fDefault || ntype == NATIVE_TYPE_U4 || ntype == NATIVE_TYPE_I4 || ntype == NATIVE_TYPE_ERROR)
481 INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ());
485 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I4));
489 case ELEMENT_TYPE_I8:
490 if (fDefault || ntype == NATIVE_TYPE_I8 || ntype == NATIVE_TYPE_U8)
492 INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ());
496 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I8));
500 case ELEMENT_TYPE_U8:
501 if (fDefault || ntype == NATIVE_TYPE_U8 || ntype == NATIVE_TYPE_I8)
503 INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ());
507 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I8));
511 case ELEMENT_TYPE_I: //fallthru
513 #ifdef FEATURE_COMINTEROP
516 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
519 #endif // FEATURE_COMINTEROP
520 if (fDefault || ntype == NATIVE_TYPE_INT || ntype == NATIVE_TYPE_UINT)
522 #ifdef _TARGET_64BIT_
523 INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ());
524 #else // !_TARGET_64BIT_
525 INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ());
526 #endif // !_TARGET_64BIT_
530 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I));
534 case ELEMENT_TYPE_R4:
535 if (fDefault || ntype == NATIVE_TYPE_R4)
537 INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ());
541 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_R4));
545 case ELEMENT_TYPE_R8:
546 if (fDefault || ntype == NATIVE_TYPE_R8)
548 INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ());
552 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_R8));
556 case ELEMENT_TYPE_PTR:
557 #ifdef FEATURE_COMINTEROP
560 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
563 #endif // FEATURE_COMINTEROP
566 #ifdef _TARGET_64BIT_
567 INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ());
568 #else // !_TARGET_64BIT_
569 INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ());
570 #endif // !_TARGET_64BIT_
574 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_PTR));
578 case ELEMENT_TYPE_VALUETYPE:
580 // This may cause a TypeLoadException, which we currently seem to have to swallow.
581 // This happens with structs that contain fields of class type where the class itself
582 // refers to the struct in a field.
583 TypeHandle thNestedType = GetFieldTypeHandleWorker(&fsig);
584 if (!thNestedType.GetMethodTable())
586 #ifdef FEATURE_COMINTEROP
587 if (fIsWinRT && sigElemType == ELEMENT_TYPE_GENERICINST)
589 // If this is a generic value type, lets see whether it is a Nullable<T>
590 TypeHandle genType = fsig.GetLastTypeHandleThrowing();
591 if(genType != NULL && genType.GetMethodTable()->HasSameTypeDefAs(g_pNullableClass))
593 // The generic type is System.Nullable<T>.
594 // Lets extract the typeArg and check if the typeArg is valid.
595 // typeArg is invalid if
596 // 1. It is not a value type.
598 // 3. We have an open type with us.
599 Instantiation inst = genType.GetMethodTable()->GetInstantiation();
600 MethodTable* typeArgMT = inst[0].GetMethodTable();
601 if (!typeArgMT->IsLegalNonArrayWinRTType())
603 // Type is not a valid WinRT value type.
604 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_NULLABLE_RESTRICTION));
608 INITFIELDMARSHALER(NFT_WINDOWSFOUNDATIONIREFERENCE, FieldMarshaler_Nullable, (genType.GetMethodTable()));
614 if (fsig.IsClass(g_DateClassName))
616 if (fDefault || ntype == NATIVE_TYPE_STRUCT)
618 INITFIELDMARSHALER(NFT_DATE, FieldMarshaler_Date, ());
622 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_DATETIME));
625 else if (fsig.IsClass(g_DecimalClassName))
627 if (fDefault || ntype == NATIVE_TYPE_STRUCT)
629 INITFIELDMARSHALER(NFT_DECIMAL, FieldMarshaler_Decimal, ());
631 #ifdef FEATURE_COMINTEROP
632 else if (ntype == NATIVE_TYPE_CURRENCY)
634 INITFIELDMARSHALER(NFT_CURRENCY, FieldMarshaler_Currency, ());
636 #endif // FEATURE_COMINTEROP
639 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_DECIMAL));
642 #ifdef FEATURE_COMINTEROP
643 else if (fsig.IsClass(g_DateTimeOffsetClassName))
645 if (fDefault || ntype == NATIVE_TYPE_STRUCT)
647 INITFIELDMARSHALER(NFT_DATETIMEOFFSET, FieldMarshaler_DateTimeOffset, ());
651 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_DATETIMEOFFSET));
654 else if (fIsWinRT && !thNestedType.GetMethodTable()->IsLegalNonArrayWinRTType())
656 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
658 #endif // FEATURE_COMINTEROP
659 else if (thNestedType.GetMethodTable()->HasLayout())
661 if (fDefault || ntype == NATIVE_TYPE_STRUCT)
663 if (IsStructMarshalable(thNestedType))
666 INITFIELDMARSHALER(NFT_NESTEDVALUECLASS, FieldMarshaler_NestedValueClass, (thNestedType.GetMethodTable(), IsFixedBuffer(pfwalk->m_MD, pInternalImport)));
668 INITFIELDMARSHALER(NFT_NESTEDVALUECLASS, FieldMarshaler_NestedValueClass, (thNestedType.GetMethodTable()));
673 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_NOTMARSHALABLE));
678 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_VALUETYPE));
683 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_NOTMARSHALABLE));
688 case ELEMENT_TYPE_CLASS:
690 // This may cause a TypeLoadException, which we currently seem to have to swallow.
691 // This happens with structs that contain fields of class type where the class itself
692 // refers to the struct in a field.
693 TypeHandle thNestedType = GetFieldTypeHandleWorker(&fsig);
694 if (!thNestedType.GetMethodTable())
697 if (thNestedType.GetMethodTable()->IsObjectClass())
699 #ifdef FEATURE_COMINTEROP
700 if (fDefault || ntype == NATIVE_TYPE_IUNKNOWN || ntype == NATIVE_TYPE_IDISPATCH || ntype == NATIVE_TYPE_INTF)
702 // Only NATIVE_TYPE_IDISPATCH maps to an IDispatch based interface pointer.
703 DWORD dwFlags = ItfMarshalInfo::ITF_MARSHAL_USE_BASIC_ITF;
704 if (ntype == NATIVE_TYPE_IDISPATCH)
706 dwFlags |= ItfMarshalInfo::ITF_MARSHAL_DISP_ITF;
708 INITFIELDMARSHALER(NFT_INTERFACE, FieldMarshaler_Interface, (NULL, NULL, dwFlags));
710 else if (ntype == NATIVE_TYPE_STRUCT)
712 INITFIELDMARSHALER(NFT_VARIANT, FieldMarshaler_Variant, ());
714 #else // FEATURE_COMINTEROP
715 if (fDefault || ntype == NATIVE_TYPE_IUNKNOWN || ntype == NATIVE_TYPE_IDISPATCH || ntype == NATIVE_TYPE_INTF)
717 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_OBJECT_TO_ITF_NOT_SUPPORTED));
719 else if (ntype == NATIVE_TYPE_STRUCT)
721 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_OBJECT_TO_VARIANT_NOT_SUPPORTED));
723 #endif // FEATURE_COMINTEROP
726 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_OBJECT));
729 #ifdef FEATURE_COMINTEROP
730 else if (ntype == NATIVE_TYPE_INTF || thNestedType.IsInterface())
732 if (fIsWinRT && !thNestedType.GetMethodTable()->IsLegalNonArrayWinRTType())
734 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
738 ItfMarshalInfo itfInfo;
739 if (FAILED(MarshalInfo::TryGetItfMarshalInfo(thNestedType, FALSE, FALSE, &itfInfo)))
742 INITFIELDMARSHALER(NFT_INTERFACE, FieldMarshaler_Interface, (itfInfo.thClass.GetMethodTable(), itfInfo.thItf.GetMethodTable(), itfInfo.dwFlags));
745 #else // FEATURE_COMINTEROP
746 else if (ntype == NATIVE_TYPE_INTF || thNestedType.IsInterface())
748 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_OBJECT_TO_ITF_NOT_SUPPORTED));
750 #endif // FEATURE_COMINTEROP
751 else if (ntype == NATIVE_TYPE_CUSTOMMARSHALER)
753 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_NOCUSTOMMARSH));
755 else if (thNestedType == TypeHandle(g_pStringClass))
759 #ifdef FEATURE_COMINTEROP
762 INITFIELDMARSHALER(NFT_HSTRING, FieldMarshaler_HSTRING, ());
765 #endif // FEATURE_COMINTEROP
768 ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
769 INITFIELDMARSHALER(NFT_STRINGANSI, FieldMarshaler_StringAnsi, (BestFit, ThrowOnUnmappableChar));
773 INITFIELDMARSHALER(NFT_STRINGUNI, FieldMarshaler_StringUni, ());
780 case NATIVE_TYPE_LPSTR:
781 ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
782 INITFIELDMARSHALER(NFT_STRINGANSI, FieldMarshaler_StringAnsi, (BestFit, ThrowOnUnmappableChar));
785 case NATIVE_TYPE_LPWSTR:
786 INITFIELDMARSHALER(NFT_STRINGUNI, FieldMarshaler_StringUni, ());
789 case NATIVE_TYPE_LPUTF8STR:
790 INITFIELDMARSHALER(NFT_STRINGUTF8, FieldMarshaler_StringUtf8, ());
793 case NATIVE_TYPE_LPTSTR:
794 // We no longer support Win9x so LPTSTR always maps to a Unicode string.
795 INITFIELDMARSHALER(NFT_STRINGUNI, FieldMarshaler_StringUni, ());
798 case NATIVE_TYPE_BSTR:
799 INITFIELDMARSHALER(NFT_BSTR, FieldMarshaler_BSTR, ());
802 #ifdef FEATURE_COMINTEROP
803 case NATIVE_TYPE_HSTRING:
804 INITFIELDMARSHALER(NFT_HSTRING, FieldMarshaler_HSTRING, ());
806 #endif // FEATURE_COMINTEROP
807 case NATIVE_TYPE_FIXEDSYSSTRING:
810 ULONG udatasize = CorSigUncompressedDataSize(pNativeType);
812 if (cbNativeType < udatasize)
815 nchars = CorSigUncompressData(pNativeType);
816 cbNativeType -= udatasize;
820 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_ZEROLENGTHFIXEDSTRING));
826 ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
827 INITFIELDMARSHALER(NFT_FIXEDSTRINGANSI, FieldMarshaler_FixedStringAnsi, (nchars, BestFit, ThrowOnUnmappableChar));
831 INITFIELDMARSHALER(NFT_FIXEDSTRINGUNI, FieldMarshaler_FixedStringUni, (nchars));
837 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_STRING));
842 #ifdef FEATURE_COMINTEROP
843 else if (fIsWinRT && fsig.IsClass(g_TypeClassName))
844 { // Note: If the System.Type field is in non-WinRT struct, do not change the previously shipped behavior
845 INITFIELDMARSHALER(NFT_SYSTEMTYPE, FieldMarshaler_SystemType, ());
847 else if (fIsWinRT && fsig.IsClass(g_ExceptionClassName)) // Marshal Windows.Foundation.HResult as System.Exception for WinRT.
849 INITFIELDMARSHALER(NFT_WINDOWSFOUNDATIONHRESULT, FieldMarshaler_Exception, ());
851 #endif //FEATURE_COMINTEROP
852 #ifdef FEATURE_CLASSIC_COMINTEROP
853 else if (thNestedType.GetMethodTable() == g_pArrayClass)
855 if (ntype == NATIVE_TYPE_SAFEARRAY)
857 NativeTypeParamInfo ParamInfo;
858 CorElementType etyp = ELEMENT_TYPE_OBJECT;
859 MethodTable* pMT = NULL;
860 VARTYPE vtElement = VT_EMPTY;
862 // Compat: If no safe array used def subtype was specified, we assume TypeOf(Object).
863 TypeHandle thElement = TypeHandle(g_pObjectClass);
865 // If we have no native type data, assume default behavior
866 if (S_OK != CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
868 INITFIELDMARSHALER(NFT_SAFEARRAY, FieldMarshaler_SafeArray, (VT_EMPTY, NULL));
872 vtElement = (VARTYPE) (CorSigUncompressData(/*modifies*/pNativeType));
874 // Extract the name of the record type's.
875 if (S_OK == CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
878 if (FAILED(CPackedLen::SafeGetData(pNativeType, pNativeTypeStart + cbNativeTypeStart, &strLen, &pNativeType)))
880 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_BADMETADATA));
885 // Load the type. Use a SString for the string since we need to NULL terminate the string
886 // that comes from the metadata.
887 StackSString safeArrayUserDefTypeName(SString::Utf8, (LPCUTF8)pNativeType, strLen);
888 _ASSERTE((ULONG)(pNativeType + strLen - pNativeTypeStart) == cbNativeTypeStart);
890 // Sadly this may cause a TypeLoadException, which we currently have to swallow.
891 // This happens with structs that contain fields of class type where the class itself
892 // refers to the struct in a field.
893 thElement = ArraySubTypeLoadWorker(safeArrayUserDefTypeName, pModule->GetAssembly());
894 if (thElement.IsNull())
899 ArrayMarshalInfo arrayMarshalInfo(amiRuntime);
900 arrayMarshalInfo.InitForSafeArray(MarshalInfo::MARSHAL_SCENARIO_FIELD, thElement, vtElement, fAnsi);
902 if (!arrayMarshalInfo.IsValid())
904 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (arrayMarshalInfo.GetErrorResourceId()));
908 INITFIELDMARSHALER(NFT_SAFEARRAY, FieldMarshaler_SafeArray, (arrayMarshalInfo.GetElementVT(), arrayMarshalInfo.GetElementTypeHandle().GetMethodTable()));
910 else if (ntype == NATIVE_TYPE_FIXEDARRAY)
912 // Check for the number of elements. This is required, if not present fail.
913 if (S_OK != CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
915 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_FIXEDARRAY_NOSIZE));
919 ULONG numElements = CorSigUncompressData(/*modifies*/pNativeType);
921 if (numElements == 0)
923 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_FIXEDARRAY_ZEROSIZE));
927 // Since these always export to arrays of BSTRs, we don't need to fetch the native type.
929 // Compat: FixedArrays of System.Arrays map to fixed arrays of BSTRs.
930 INITFIELDMARSHALER(NFT_FIXEDARRAY, FieldMarshaler_FixedArray, (pInternalImport, cl, numElements, VT_BSTR, g_pStringClass));
933 #endif // FEATURE_CLASSIC_COMINTEROP
934 else if (COMDelegate::IsDelegate(thNestedType.GetMethodTable()))
936 if (fDefault || ntype == NATIVE_TYPE_FUNC)
938 INITFIELDMARSHALER(NFT_DELEGATE, FieldMarshaler_Delegate, (thNestedType.GetMethodTable()));
942 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_DELEGATE));
945 else if (thNestedType.CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__SAFE_HANDLE))))
949 INITFIELDMARSHALER(NFT_SAFEHANDLE, FieldMarshaler_SafeHandle, ());
953 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_SAFEHANDLE));
956 else if (thNestedType.CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__CRITICAL_HANDLE))))
960 INITFIELDMARSHALER(NFT_CRITICALHANDLE, FieldMarshaler_CriticalHandle, ());
964 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_CRITICALHANDLE));
967 else if (fsig.IsClass(g_StringBufferClassName))
969 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_NOSTRINGBUILDER));
971 else if (IsStructMarshalable(thNestedType))
973 if (fDefault || ntype == NATIVE_TYPE_STRUCT)
975 INITFIELDMARSHALER(NFT_NESTEDLAYOUTCLASS, FieldMarshaler_NestedLayoutClass, (thNestedType.GetMethodTable()));
979 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_LAYOUTCLASS));
982 #ifdef FEATURE_COMINTEROP
985 // no other reference types are allowed as field types in WinRT
986 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
990 ItfMarshalInfo itfInfo;
991 if (FAILED(MarshalInfo::TryGetItfMarshalInfo(thNestedType, FALSE, FALSE, &itfInfo)))
993 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_BADMANAGED));
997 INITFIELDMARSHALER(NFT_INTERFACE, FieldMarshaler_Interface, (itfInfo.thClass.GetMethodTable(), itfInfo.thItf.GetMethodTable(), itfInfo.dwFlags));
1000 #endif // FEATURE_COMINTEROP
1004 case ELEMENT_TYPE_SZARRAY:
1005 case ELEMENT_TYPE_ARRAY:
1007 #ifdef FEATURE_COMINTEROP
1010 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
1013 #endif // FEATURE_COMINTEROP
1015 // This may cause a TypeLoadException, which we currently seem to have to swallow.
1016 // This happens with structs that contain fields of class type where the class itself
1017 // refers to the struct in a field.
1018 TypeHandle thArray = GetFieldTypeHandleWorker(&fsig);
1019 if (thArray.IsNull() || !thArray.IsArray())
1022 TypeHandle thElement = thArray.AsArray()->GetArrayElementTypeHandle();
1023 if (thElement.IsNull())
1026 if (ntype == NATIVE_TYPE_FIXEDARRAY)
1028 CorNativeType elementNativeType = NATIVE_TYPE_DEFAULT;
1030 // The size constant must be specified, if it isn't then the struct can't be marshalled.
1031 if (S_OK != CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
1033 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_FIXEDARRAY_NOSIZE));
1037 // Read the size const, if it's 0, then the struct can't be marshalled.
1038 ULONG numElements = CorSigUncompressData(pNativeType);
1039 if (numElements == 0)
1041 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_FIXEDARRAY_ZEROSIZE));
1045 // The array sub type is optional so extract it if specified.
1046 if (S_OK == CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
1047 elementNativeType = (CorNativeType)CorSigUncompressData(pNativeType);
1049 ArrayMarshalInfo arrayMarshalInfo(amiRuntime);
1050 arrayMarshalInfo.InitForFixedArray(thElement, elementNativeType, fAnsi);
1052 if (!arrayMarshalInfo.IsValid())
1054 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (arrayMarshalInfo.GetErrorResourceId()));
1058 if (arrayMarshalInfo.GetElementVT() == VTHACK_ANSICHAR)
1060 // We need to special case fixed sized arrays of ANSI chars since the OleVariant code
1061 // that is used by the generic fixed size array marshaller doesn't support them
1063 ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar);
1064 INITFIELDMARSHALER(NFT_FIXEDCHARARRAYANSI, FieldMarshaler_FixedCharArrayAnsi, (numElements, BestFit, ThrowOnUnmappableChar));
1069 VARTYPE elementVT = arrayMarshalInfo.GetElementVT();
1071 INITFIELDMARSHALER(NFT_FIXEDARRAY, FieldMarshaler_FixedArray, (pInternalImport, cl, numElements, elementVT, arrayMarshalInfo.GetElementTypeHandle().GetMethodTable()));
1075 #ifdef FEATURE_CLASSIC_COMINTEROP
1076 else if (fDefault || ntype == NATIVE_TYPE_SAFEARRAY)
1078 VARTYPE vtElement = VT_EMPTY;
1080 // Check for data remaining in the signature before we attempt to grab some.
1081 if (S_OK == CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart))
1082 vtElement = (VARTYPE) (CorSigUncompressData(/*modifies*/pNativeType));
1084 ArrayMarshalInfo arrayMarshalInfo(amiRuntime);
1085 arrayMarshalInfo.InitForSafeArray(MarshalInfo::MARSHAL_SCENARIO_FIELD, thElement, vtElement, fAnsi);
1087 if (!arrayMarshalInfo.IsValid())
1089 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (arrayMarshalInfo.GetErrorResourceId()));
1093 INITFIELDMARSHALER(NFT_SAFEARRAY, FieldMarshaler_SafeArray, (arrayMarshalInfo.GetElementVT(), arrayMarshalInfo.GetElementTypeHandle().GetMethodTable()));
1095 #endif //FEATURE_CLASSIC_COMINTEROP
1098 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_ARRAY));
1103 case ELEMENT_TYPE_OBJECT:
1104 case ELEMENT_TYPE_STRING:
1108 // let it fall thru as NFT_NONE
1112 if (pfwalk->m_nft == NFT_NONE)
1114 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_BADMANAGED));
1116 #ifdef FEATURE_COMINTEROP
1117 else if (fIsWinRT && !NFTDataBase[pfwalk->m_nft].m_fWinRTSupported)
1119 // the field marshaler we came up with is not supported in WinRT scenarios
1120 ZeroMemory(&pfwalk->m_FieldMarshaler, MAXFIELDMARSHALERSIZE);
1121 INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE));
1123 #endif // FEATURE_COMINTEROP
1124 #undef INITFIELDMARSHALER
1127 #pragma warning(pop)
1131 TypeHandle ArraySubTypeLoadWorker(const SString &strUserDefTypeName, Assembly* pAssembly)
1138 PRECONDITION(CheckPointer(pAssembly));
1146 // Load the user defined type.
1147 StackScratchBuffer utf8Name;
1148 th = TypeName::GetTypeUsingCASearchRules(strUserDefTypeName.GetUTF8(utf8Name), pAssembly);
1153 EX_END_CATCH(RethrowTerminalExceptions)
1159 TypeHandle GetFieldTypeHandleWorker(MetaSig *pFieldSig)
1166 PRECONDITION(CheckPointer(pFieldSig));
1174 // Load the user defined type.
1175 th = pFieldSig->GetLastTypeHandleThrowing(ClassLoader::LoadTypes,
1176 CLASS_LOAD_APPROXPARENTS,
1177 TRUE /*dropGenericArgumentLevel*/);
1182 EX_END_CATCH(RethrowTerminalExceptions)
1188 //=======================================================================
1189 // This function returns TRUE if the type passed in is either a value class or a class and if it has layout information
1190 // and is marshalable. In all other cases it will return FALSE.
1191 //=======================================================================
1192 BOOL IsStructMarshalable(TypeHandle th)
1199 PRECONDITION(!th.IsNull());
1203 if (th.IsBlittable())
1205 // th.IsBlittable will return true for arrays of blittable types, however since IsStructMarshalable
1206 // is only supposed to return true for value classes or classes with layout that are marshallable
1207 // we need to return false if the type is an array.
1214 // Check to see if the type has layout.
1215 if (!th.HasLayout())
1218 MethodTable *pMT= th.GetMethodTable();
1219 PREFIX_ASSUME(pMT != NULL);
1221 if (pMT->IsStructMarshalable())
1224 const FieldMarshaler *pFieldMarshaler = pMT->GetLayoutInfo()->GetFieldMarshalers();
1225 UINT numReferenceFields = pMT->GetLayoutInfo()->GetNumCTMFields();
1227 while (numReferenceFields--)
1229 if (pFieldMarshaler->GetNStructFieldType() == NFT_ILLEGAL)
1232 ((BYTE*&)pFieldMarshaler) += MAXFIELDMARSHALERSIZE;
1239 BOOL IsFixedBuffer(mdFieldDef field, IMDInternalImport *pInternalImport)
1241 HRESULT hr = pInternalImport->GetCustomAttributeByName(field, g_FixedBufferAttribute, NULL, NULL);
1243 return hr == S_OK ? TRUE : FALSE;
1248 //=======================================================================
1249 // Called from the clsloader to load up and summarize the field metadata
1250 // for layout classes.
1252 // Warning: This function can load other classes (esp. for nested structs.)
1253 //=======================================================================
1255 #pragma warning(push)
1256 #pragma warning(disable:21000) // Suppress PREFast warning about overly large function
1258 VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing(
1259 mdTypeDef cl, // cl of the NStruct being loaded
1260 BYTE packingSize, // packing size (from @dll.struct)
1261 BYTE nlType, // nltype (from @dll.struct)
1262 #ifdef FEATURE_COMINTEROP
1263 BOOL isWinRT, // Is the type a WinRT type
1264 #endif // FEATURE_COMINTEROP
1265 BOOL fExplicitOffsets, // explicit offsets?
1266 MethodTable *pParentMT, // the loaded superclass
1267 ULONG cMembers, // total number of members (methods + fields)
1268 HENUMInternal *phEnumField, // enumerator for field
1269 Module *pModule, // Module that defines the scope, loader and heap (for allocate FieldMarshalers)
1270 const SigTypeContext *pTypeContext, // Type parameters for NStruct being loaded
1271 EEClassLayoutInfo *pEEClassLayoutInfoOut, // caller-allocated structure to fill in.
1272 LayoutRawFieldInfo *pInfoArrayOut, // caller-allocated array to fill in. Needs room for cMember+1 elements
1273 LoaderAllocator *pAllocator,
1274 AllocMemTracker *pamTracker
1282 INJECT_FAULT(COMPlusThrowOM());
1283 PRECONDITION(CheckPointer(pModule));
1288 MD_CLASS_LAYOUT classlayout;
1293 // Running tote - if anything in this type disqualifies it from being ManagedSequential, somebody will set this to TRUE by the the time
1295 BOOL fDisqualifyFromManagedSequential = FALSE;
1297 // Internal interface for the NStruct being loaded.
1298 IMDInternalImport *pInternalImport = pModule->GetMDImport();
1303 LPCUTF8 szNamespace;
1304 if (FAILED(pInternalImport->GetNameOfTypeDef(cl, &szName, &szNamespace)))
1306 szName = szNamespace = "Invalid TypeDef record";
1309 if (g_pConfig->ShouldBreakOnStructMarshalSetup(szName))
1310 CONSISTENCY_CHECK_MSGF(false, ("BreakOnStructMarshalSetup: '%s' ", szName));
1314 // Check if this type might be ManagedSequential. Only valuetypes marked Sequential can be
1315 // ManagedSequential. Other issues checked below might also disqualify the type.
1316 if ( (!fExplicitOffsets) && // Is it marked sequential?
1317 (pParentMT && (pParentMT->IsValueTypeClass() || pParentMT->IsManagedSequential())) // Is it a valuetype or derived from a qualifying valuetype?
1320 // Type qualifies so far... need do nothing.
1324 fDisqualifyFromManagedSequential = TRUE;
1328 BOOL fHasNonTrivialParent = pParentMT &&
1329 !pParentMT->IsObjectClass() &&
1330 !pParentMT->IsValueTypeClass();
1333 //====================================================================
1334 // First, some validation checks.
1335 //====================================================================
1336 _ASSERTE(!(fHasNonTrivialParent && !(pParentMT->HasLayout())));
1338 hr = pInternalImport->GetClassLayoutInit(cl, &classlayout);
1341 COMPlusThrowHR(hr, BFA_CANT_GET_CLASSLAYOUT);
1344 pEEClassLayoutInfoOut->m_numCTMFields = fHasNonTrivialParent ? pParentMT->GetLayoutInfo()->m_numCTMFields : 0;
1345 pEEClassLayoutInfoOut->SetFieldMarshalers(NULL);
1346 pEEClassLayoutInfoOut->SetIsBlittable(TRUE);
1347 if (fHasNonTrivialParent)
1348 pEEClassLayoutInfoOut->SetIsBlittable(pParentMT->IsBlittable());
1349 pEEClassLayoutInfoOut->SetIsZeroSized(FALSE);
1350 pEEClassLayoutInfoOut->SetHasExplicitSize(FALSE);
1351 pEEClassLayoutInfoOut->m_cbPackingSize = packingSize;
1353 LayoutRawFieldInfo *pfwalk = pInfoArrayOut;
1355 S_UINT32 cbSortArraySize = S_UINT32(cMembers) * S_UINT32(sizeof(LayoutRawFieldInfo *));
1356 if (cbSortArraySize.IsOverflow())
1358 ThrowHR(COR_E_TYPELOAD);
1360 LayoutRawFieldInfo **pSortArray = (LayoutRawFieldInfo **)_alloca(cbSortArraySize.Value());
1361 LayoutRawFieldInfo **pSortArrayEnd = pSortArray;
1363 ULONG maxRid = pInternalImport->GetCountWithTokenKind(mdtFieldDef);
1366 //=====================================================================
1367 // Phase 1: Figure out the NFT of each field based on both the CLR
1368 // signature of the field and the FieldMarshaler metadata.
1369 //=====================================================================
1370 BOOL fParentHasLayout = pParentMT && pParentMT->HasLayout();
1371 UINT32 cbAdjustedParentLayoutNativeSize = 0;
1372 EEClassLayoutInfo *pParentLayoutInfo = NULL;;
1373 if (fParentHasLayout)
1375 pParentLayoutInfo = pParentMT->GetLayoutInfo();
1376 // Treat base class as an initial member.
1377 cbAdjustedParentLayoutNativeSize = pParentLayoutInfo->GetNativeSize();
1378 // If the parent was originally a zero-sized explicit type but
1379 // got bumped up to a size of 1 for compatibility reasons, then
1380 // we need to remove the padding, but ONLY for inheritance situations.
1381 if (pParentLayoutInfo->IsZeroSized()) {
1382 CONSISTENCY_CHECK(cbAdjustedParentLayoutNativeSize == 1);
1383 cbAdjustedParentLayoutNativeSize = 0;
1388 for (i = 0; pInternalImport->EnumNext(phEnumField, &fd); i++)
1391 ULONG rid = RidFromToken(fd);
1393 if((rid == 0)||(rid > maxRid))
1395 COMPlusThrowHR(COR_E_TYPELOAD, BFA_BAD_FIELD_TOKEN);
1398 IfFailThrow(pInternalImport->GetFieldDefProps(fd, &dwFieldAttrs));
1400 PCCOR_SIGNATURE pNativeType = NULL;
1402 // We ignore marshaling data attached to statics and literals,
1403 // since these do not contribute to instance data.
1404 if (!IsFdStatic(dwFieldAttrs) && !IsFdLiteral(dwFieldAttrs))
1406 PCCOR_SIGNATURE pCOMSignature;
1407 ULONG cbCOMSignature;
1409 if (IsFdHasFieldMarshal(dwFieldAttrs))
1411 hr = pInternalImport->GetFieldMarshal(fd, &pNativeType, &cbNativeType);
1418 IfFailThrow(pInternalImport->GetSigOfFieldDef(fd,&cbCOMSignature, &pCOMSignature));
1420 IfFailThrow(::validateTokenSig(fd,pCOMSignature,cbCOMSignature,dwFieldAttrs,pInternalImport));
1422 // fill the appropriate entry in pInfoArrayOut
1424 pfwalk->m_nft = NULL;
1425 pfwalk->m_offset = (UINT32) -1;
1426 pfwalk->m_sequence = 0;
1429 LPCUTF8 szFieldName;
1430 if (FAILED(pInternalImport->GetNameOfFieldDef(fd, &szFieldName)))
1432 szFieldName = "Invalid FieldDef record";
1436 ParseNativeTypeFlags flags = ParseNativeTypeFlag_None;
1437 #ifdef FEATURE_COMINTEROP
1439 flags |= ParseNativeTypeFlag_IsWinRT;
1440 else // WinRT types have nlType == nltAnsi but should be treated as Unicode
1441 #endif // FEATURE_COMINTEROP
1442 if (nlType == nltAnsi)
1443 flags |= ParseNativeTypeFlag_IsAnsi;
1445 ParseNativeType(pModule,
1455 &fDisqualifyFromManagedSequential
1465 //<TODO>@nice: This is obviously not the place to bury this logic.
1466 // We're replacing NFT's with MARSHAL_TYPES_* in the near future
1467 // so this isn't worth perfecting.</TODO>
1469 BOOL resetBlittable = TRUE;
1471 // if it's a simple copy...
1472 if (pfwalk->m_nft == NFT_COPY1 ||
1473 pfwalk->m_nft == NFT_COPY2 ||
1474 pfwalk->m_nft == NFT_COPY4 ||
1475 pfwalk->m_nft == NFT_COPY8)
1477 resetBlittable = FALSE;
1480 // Or if it's a nested value class that is itself blittable...
1481 if (pfwalk->m_nft == NFT_NESTEDVALUECLASS)
1483 FieldMarshaler *pFM = (FieldMarshaler*)&(pfwalk->m_FieldMarshaler);
1484 _ASSERTE(pFM->IsNestedValueClassMarshaler());
1486 if (((FieldMarshaler_NestedValueClass *) pFM)->IsBlittable())
1487 resetBlittable = FALSE;
1490 // ...Otherwise, this field prevents blitting
1492 pEEClassLayoutInfoOut->SetIsBlittable(FALSE);
1499 _ASSERTE(i == cMembers);
1501 // NULL out the last entry
1502 pfwalk->m_MD = mdFieldDefNil;
1506 // fill in the layout information
1509 // pfwalk points to the beginging of the array
1510 pfwalk = pInfoArrayOut;
1512 while (SUCCEEDED(hr = pInternalImport->GetClassLayoutNext(
1516 fd != mdFieldDefNil)
1518 // watch for the last entry: must be mdFieldDefNil
1519 while ((mdFieldDefNil != pfwalk->m_MD)&&(pfwalk->m_MD < fd))
1522 // if we haven't found a matching token, it must be a static field with layout -- ignore it
1523 if(pfwalk->m_MD != fd) continue;
1525 if (!fExplicitOffsets)
1527 // ulOffset is the sequence
1528 pfwalk->m_sequence = ulOffset;
1532 // ulOffset is the explicit offset
1533 pfwalk->m_offset = ulOffset;
1534 pfwalk->m_sequence = (ULONG) -1;
1536 // Treat base class as an initial member.
1537 if (!SafeAddUINT32(&(pfwalk->m_offset), cbAdjustedParentLayoutNativeSize))
1543 // now sort the array
1544 if (!fExplicitOffsets)
1546 // sort sequential by ascending sequence
1547 for (i = 0; i < cFields; i++)
1549 LayoutRawFieldInfo**pSortWalk = pSortArrayEnd;
1550 while (pSortWalk != pSortArray)
1552 if (pInfoArrayOut[i].m_sequence >= (*(pSortWalk-1))->m_sequence)
1558 // pSortWalk now points to the target location for new FieldInfo.
1559 MoveMemory(pSortWalk + 1, pSortWalk, (pSortArrayEnd - pSortWalk) * sizeof(LayoutRawFieldInfo*));
1560 *pSortWalk = &pInfoArrayOut[i];
1564 else // no sorting for explicit layout
1566 for (i = 0; i < cFields; i++)
1568 if(pInfoArrayOut[i].m_MD != mdFieldDefNil)
1570 if (pInfoArrayOut[i].m_offset == (UINT32)-1)
1572 LPCUTF8 szFieldName;
1573 if (FAILED(pInternalImport->GetNameOfFieldDef(pInfoArrayOut[i].m_MD, &szFieldName)))
1575 szFieldName = "Invalid FieldDef record";
1577 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport,
1580 IDS_CLASSLOAD_NSTRUCT_EXPLICIT_OFFSET);
1582 else if ((INT)pInfoArrayOut[i].m_offset < 0)
1584 LPCUTF8 szFieldName;
1585 if (FAILED(pInternalImport->GetNameOfFieldDef(pInfoArrayOut[i].m_MD, &szFieldName)))
1587 szFieldName = "Invalid FieldDef record";
1589 pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport,
1592 IDS_CLASSLOAD_NSTRUCT_NEGATIVE_OFFSET);
1596 *pSortArrayEnd = &pInfoArrayOut[i];
1601 //=====================================================================
1602 // Phase 2: Compute the native size (in bytes) of each field.
1603 // Store this in pInfoArrayOut[].cbNativeSize;
1604 //=====================================================================
1606 // Now compute the native size of each field
1607 for (pfwalk = pInfoArrayOut; pfwalk->m_MD != mdFieldDefNil; pfwalk++)
1609 UINT8 nft = pfwalk->m_nft;
1610 pEEClassLayoutInfoOut->m_numCTMFields++;
1612 // If the NFT's size never changes, it is stored in the database.
1613 UINT32 cbNativeSize = NFTDataBase[nft].m_cbNativeSize;
1615 if (cbNativeSize == 0)
1617 // Size of 0 means NFT's size is variable, so we have to figure it
1618 // out case by case.
1619 cbNativeSize = ((FieldMarshaler*)&(pfwalk->m_FieldMarshaler))->NativeSize();
1621 pfwalk->m_cbNativeSize = cbNativeSize;
1624 if (pEEClassLayoutInfoOut->m_numCTMFields)
1626 pEEClassLayoutInfoOut->SetFieldMarshalers((FieldMarshaler*)(pamTracker->Track(pAllocator->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(MAXFIELDMARSHALERSIZE) * S_SIZE_T(pEEClassLayoutInfoOut->m_numCTMFields)))));
1628 // Bring in the parent's fieldmarshalers
1629 if (fHasNonTrivialParent)
1631 CONSISTENCY_CHECK(fParentHasLayout);
1632 PREFAST_ASSUME(pParentLayoutInfo != NULL); // See if (fParentHasLayout) branch above
1634 UINT numChildCTMFields = pEEClassLayoutInfoOut->m_numCTMFields - pParentLayoutInfo->m_numCTMFields;
1636 BYTE *pParentCTMFieldSrcArray = (BYTE*)pParentLayoutInfo->GetFieldMarshalers();
1637 BYTE *pParentCTMFieldDestArray = ((BYTE*)pEEClassLayoutInfoOut->GetFieldMarshalers()) + MAXFIELDMARSHALERSIZE*numChildCTMFields;
1639 for (UINT parentCTMFieldIndex = 0; parentCTMFieldIndex < pParentLayoutInfo->m_numCTMFields; parentCTMFieldIndex++)
1641 FieldMarshaler *pParentCTMFieldSrc = (FieldMarshaler *)(pParentCTMFieldSrcArray + MAXFIELDMARSHALERSIZE*parentCTMFieldIndex);
1642 FieldMarshaler *pParentCTMFieldDest = (FieldMarshaler *)(pParentCTMFieldDestArray + MAXFIELDMARSHALERSIZE*parentCTMFieldIndex);
1644 pParentCTMFieldSrc->CopyTo(pParentCTMFieldDest, MAXFIELDMARSHALERSIZE);
1651 //=====================================================================
1652 // Phase 3: If FieldMarshaler requires autooffsetting, compute the offset
1653 // of each field and the size of the total structure. We do the layout
1654 // according to standard VC layout rules:
1656 // Each field has an alignment requirement. The alignment-requirement
1657 // of a scalar field is the smaller of its size and the declared packsize.
1658 // The alignment-requirement of a struct field is the smaller of the
1659 // declared packsize and the largest of the alignment-requirement
1660 // of its fields. The alignment requirement of an array is that
1661 // of one of its elements.
1663 // In addition, each struct gets padding at the end to ensure
1664 // that an array of such structs contain no unused space between
1666 //=====================================================================
1668 BYTE LargestAlignmentRequirement = 1;
1669 UINT32 cbCurOffset = 0;
1671 // Treat base class as an initial member.
1672 if (!SafeAddUINT32(&cbCurOffset, cbAdjustedParentLayoutNativeSize))
1675 if (fParentHasLayout)
1677 BYTE alignmentRequirement;
1679 alignmentRequirement = min(packingSize, pParentLayoutInfo->GetLargestAlignmentRequirementOfAllMembers());
1681 LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);
1684 // Start with the size inherited from the parent (if any).
1685 unsigned calcTotalSize = cbAdjustedParentLayoutNativeSize;
1687 LayoutRawFieldInfo **pSortWalk;
1688 for (pSortWalk = pSortArray, i=cFields; i; i--, pSortWalk++)
1690 pfwalk = *pSortWalk;
1692 BYTE alignmentRequirement = static_cast<BYTE>(((FieldMarshaler*)&(pfwalk->m_FieldMarshaler))->AlignmentRequirement());
1693 if (!(alignmentRequirement == 1 ||
1694 alignmentRequirement == 2 ||
1695 alignmentRequirement == 4 ||
1696 alignmentRequirement == 8 ||
1697 alignmentRequirement == 16 ||
1698 alignmentRequirement == 32))
1700 COMPlusThrowHR(COR_E_INVALIDPROGRAM, BFA_METADATA_CORRUPT);
1703 alignmentRequirement = min(alignmentRequirement, packingSize);
1705 LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);
1707 // This assert means I forgot to special-case some NFT in the
1709 _ASSERTE(alignmentRequirement <= 32);
1711 // Check if this field is overlapped with other(s)
1712 pfwalk->m_fIsOverlapped = FALSE;
1713 if (fExplicitOffsets) {
1714 LayoutRawFieldInfo *pfwalk1;
1715 DWORD dwBegin = pfwalk->m_offset;
1716 DWORD dwEnd = dwBegin+pfwalk->m_cbNativeSize;
1717 for (pfwalk1 = pInfoArrayOut; pfwalk1 < pfwalk; pfwalk1++)
1719 if((pfwalk1->m_offset >= dwEnd) || (pfwalk1->m_offset+pfwalk1->m_cbNativeSize <= dwBegin)) continue;
1720 pfwalk->m_fIsOverlapped = TRUE;
1721 pfwalk1->m_fIsOverlapped = TRUE;
1726 // Insert enough padding to align the current data member.
1727 while (cbCurOffset % alignmentRequirement)
1729 if (!SafeAddUINT32(&cbCurOffset, 1))
1733 // Insert current data member.
1734 pfwalk->m_offset = cbCurOffset;
1736 // if we overflow we will catch it below
1737 cbCurOffset += pfwalk->m_cbNativeSize;
1740 unsigned fieldEnd = pfwalk->m_offset + pfwalk->m_cbNativeSize;
1741 if (fieldEnd < pfwalk->m_offset)
1744 // size of the structure is the size of the last field.
1745 if (fieldEnd > calcTotalSize)
1746 calcTotalSize = fieldEnd;
1749 ULONG clstotalsize = 0;
1750 if (FAILED(pInternalImport->GetClassTotalSize(cl, &clstotalsize)))
1755 if (clstotalsize != 0)
1757 if (!SafeAddULONG(&clstotalsize, (ULONG)cbAdjustedParentLayoutNativeSize))
1760 // size must be large enough to accomodate layout. If not, we use the layout size instead.
1761 if (clstotalsize < calcTotalSize)
1763 clstotalsize = calcTotalSize;
1765 calcTotalSize = clstotalsize; // use the size they told us
1769 // The did not give us an explict size, so lets round up to a good size (for arrays)
1770 while (calcTotalSize % LargestAlignmentRequirement != 0)
1772 if (!SafeAddUINT32(&calcTotalSize, 1))
1777 // We'll cap the total native size at a (somewhat) arbitrary limit to ensure
1778 // that we don't expose some overflow bug later on.
1779 if (calcTotalSize >= MAX_SIZE_FOR_INTEROP)
1782 // This is a zero-sized struct - need to record the fact and bump it up to 1.
1783 if (calcTotalSize == 0)
1785 pEEClassLayoutInfoOut->SetIsZeroSized(TRUE);
1789 pEEClassLayoutInfoOut->m_cbNativeSize = calcTotalSize;
1791 // The packingSize acts as a ceiling on all individual alignment
1792 // requirements so it follows that the largest alignment requirement
1794 _ASSERTE(LargestAlignmentRequirement <= packingSize);
1795 pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers = LargestAlignmentRequirement;
1800 //=====================================================================
1801 // Phase 4: Now we do the same thing again for managedsequential layout.
1802 //=====================================================================
1803 if (!fDisqualifyFromManagedSequential)
1805 BYTE LargestAlignmentRequirement = 1;
1806 UINT32 cbCurOffset = 0;
1808 if (pParentMT && pParentMT->IsManagedSequential())
1810 // Treat base class as an initial member.
1811 if (!SafeAddUINT32(&cbCurOffset, pParentMT->GetNumInstanceFieldBytes()))
1814 BYTE alignmentRequirement = 0;
1816 alignmentRequirement = min(packingSize, pParentLayoutInfo->m_ManagedLargestAlignmentRequirementOfAllMembers);
1818 LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);
1821 // The current size of the structure as a whole, we start at 1, because we disallow 0 sized structures.
1822 // NOTE: We do not need to do the same checking for zero-sized types as phase 3 because only ValueTypes
1823 // can be ManagedSequential and ValueTypes can not be inherited from.
1824 unsigned calcTotalSize = 1;
1826 LayoutRawFieldInfo **pSortWalk;
1827 for (pSortWalk = pSortArray, i=cFields; i; i--, pSortWalk++)
1829 pfwalk = *pSortWalk;
1831 BYTE alignmentRequirement = ((BYTE)(pfwalk->m_managedAlignmentReq));
1832 if (!(alignmentRequirement == 1 ||
1833 alignmentRequirement == 2 ||
1834 alignmentRequirement == 4 ||
1835 alignmentRequirement == 8 ||
1836 alignmentRequirement == 16 ||
1837 alignmentRequirement == 32))
1839 COMPlusThrowHR(COR_E_INVALIDPROGRAM, BFA_METADATA_CORRUPT);
1842 alignmentRequirement = min(alignmentRequirement, packingSize);
1844 LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement);
1846 _ASSERTE(alignmentRequirement <= 32);
1848 // Insert enough padding to align the current data member.
1849 while (cbCurOffset % alignmentRequirement)
1851 if (!SafeAddUINT32(&cbCurOffset, 1))
1855 // Insert current data member.
1856 pfwalk->m_managedOffset = cbCurOffset;
1858 // if we overflow we will catch it below
1859 cbCurOffset += pfwalk->m_managedSize;
1861 unsigned fieldEnd = pfwalk->m_managedOffset + pfwalk->m_managedSize;
1862 if (fieldEnd < pfwalk->m_managedOffset)
1865 // size of the structure is the size of the last field.
1866 if (fieldEnd > calcTotalSize)
1867 calcTotalSize = fieldEnd;
1870 // @perf: If the type is blittable, the managed and native layouts have to be identical
1871 // so they really shouldn't be calculated twice. Until this code has been well tested and
1872 // stabilized, however, it is useful to compute both and assert that they are equal in the blittable
1874 if (pEEClassLayoutInfoOut->IsBlittable())
1876 _ASSERTE(pfwalk->m_managedOffset == pfwalk->m_offset);
1877 _ASSERTE(pfwalk->m_managedSize == pfwalk->m_cbNativeSize);
1882 ULONG clstotalsize = 0;
1883 if (FAILED(pInternalImport->GetClassTotalSize(cl, &clstotalsize)))
1888 if (clstotalsize != 0)
1890 pEEClassLayoutInfoOut->SetHasExplicitSize(TRUE);
1892 if (pParentMT && pParentMT->IsManagedSequential())
1894 // Treat base class as an initial member.
1895 UINT32 parentSize = pParentMT->GetNumInstanceFieldBytes();
1896 if (!SafeAddULONG(&clstotalsize, parentSize))
1900 // size must be large enough to accomodate layout. If not, we use the layout size instead.
1901 if (clstotalsize < calcTotalSize)
1903 clstotalsize = calcTotalSize;
1905 calcTotalSize = clstotalsize; // use the size they told us
1909 // The did not give us an explict size, so lets round up to a good size (for arrays)
1910 while (calcTotalSize % LargestAlignmentRequirement != 0)
1912 if (!SafeAddUINT32(&calcTotalSize, 1))
1917 pEEClassLayoutInfoOut->m_cbManagedSize = calcTotalSize;
1919 // The packingSize acts as a ceiling on all individual alignment
1920 // requirements so it follows that the largest alignment requirement
1922 _ASSERTE(LargestAlignmentRequirement <= packingSize);
1923 pEEClassLayoutInfoOut->m_ManagedLargestAlignmentRequirementOfAllMembers = LargestAlignmentRequirement;
1926 // @perf: If the type is blittable, the managed and native layouts have to be identical
1927 // so they really shouldn't be calculated twice. Until this code has been well tested and
1928 // stabilized, however, it is useful to compute both and assert that they are equal in the blittable
1930 if (pEEClassLayoutInfoOut->IsBlittable())
1932 _ASSERTE(pEEClassLayoutInfoOut->m_cbManagedSize == pEEClassLayoutInfoOut->m_cbNativeSize);
1933 _ASSERTE(pEEClassLayoutInfoOut->m_ManagedLargestAlignmentRequirementOfAllMembers == pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers);
1938 pEEClassLayoutInfoOut->SetIsManagedSequential(!fDisqualifyFromManagedSequential);
1942 BOOL illegalMarshaler = FALSE;
1944 LOG((LF_INTEROP, LL_INFO100000, "\n\n"));
1945 LOG((LF_INTEROP, LL_INFO100000, "%s.%s\n", szNamespace, szName));
1946 LOG((LF_INTEROP, LL_INFO100000, "Packsize = %lu\n", (ULONG)packingSize));
1947 LOG((LF_INTEROP, LL_INFO100000, "Max align req = %lu\n", (ULONG)(pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers)));
1948 LOG((LF_INTEROP, LL_INFO100000, "----------------------------\n"));
1949 for (pfwalk = pInfoArrayOut; pfwalk->m_MD != mdFieldDefNil; pfwalk++)
1952 if (FAILED(pInternalImport->GetNameOfFieldDef(pfwalk->m_MD, &fieldname)))
1956 LOG((LF_INTEROP, LL_INFO100000, "+%-5lu ", (ULONG)(pfwalk->m_offset)));
1957 LOG((LF_INTEROP, LL_INFO100000, "%s", fieldname));
1958 LOG((LF_INTEROP, LL_INFO100000, "\n"));
1960 if (((FieldMarshaler*)&pfwalk->m_FieldMarshaler)->GetNStructFieldType() == NFT_ILLEGAL)
1961 illegalMarshaler = TRUE;
1964 // If we are dealing with a non trivial parent, determine if it has any illegal marshallers.
1965 if (fHasNonTrivialParent)
1967 FieldMarshaler *pParentFM = pParentMT->GetLayoutInfo()->GetFieldMarshalers();
1968 for (i = 0; i < pParentMT->GetLayoutInfo()->m_numCTMFields; i++)
1970 if (pParentFM->GetNStructFieldType() == NFT_ILLEGAL)
1971 illegalMarshaler = TRUE;
1972 ((BYTE*&)pParentFM) += MAXFIELDMARSHALERSIZE;
1976 LOG((LF_INTEROP, LL_INFO100000, "+%-5lu EOS\n", (ULONG)(pEEClassLayoutInfoOut->m_cbNativeSize)));
1977 LOG((LF_INTEROP, LL_INFO100000, "Allocated %d %s field marshallers for %s.%s\n", pEEClassLayoutInfoOut->m_numCTMFields, (illegalMarshaler ? "pointless" : "usable"), szNamespace, szName));
1983 #pragma warning(pop)
1987 #ifndef CROSSGEN_COMPILE
1989 //=======================================================================
1990 // For each reference-typed FieldMarshaler field, marshals the current CLR value
1991 // to a new native instance and stores it in the fixed portion of the FieldMarshaler.
1993 // This function does not attempt to delete the native value that it overwrites.
1995 // If there is a SafeHandle field, ppCleanupWorkListOnStack must be non-null, otherwise
1996 // InvalidOperationException is thrown.
1997 //=======================================================================
1998 VOID LayoutUpdateNative(LPVOID *ppProtectedManagedData, SIZE_T offsetbias, MethodTable *pMT, BYTE* pNativeData, OBJECTREF *ppCleanupWorkListOnStack)
2005 PRECONDITION(CheckPointer(pMT));
2009 FieldMarshaler* pFM = pMT->GetLayoutInfo()->GetFieldMarshalers();
2010 UINT numReferenceFields = pMT->GetLayoutInfo()->GetNumCTMFields();
2012 OBJECTREF pCLRValue = NULL;
2013 LPVOID scalar = NULL;
2015 GCPROTECT_BEGIN(pCLRValue)
2016 GCPROTECT_BEGININTERIOR(scalar)
2018 g_IBCLogger.LogFieldMarshalersReadAccess(pMT);
2020 while (numReferenceFields--)
2024 DWORD internalOffset = pFM->GetFieldDesc()->GetOffset();
2026 if (pFM->IsScalarMarshaler())
2028 scalar = (LPVOID)(internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData));
2029 // Note this will throw for FieldMarshaler_Illegal
2030 pFM->ScalarUpdateNative(scalar, pNativeData + pFM->GetExternalOffset() );
2033 else if (pFM->IsNestedValueClassMarshaler())
2035 pFM->NestedValueClassUpdateNative((const VOID **)ppProtectedManagedData, internalOffset + offsetbias, pNativeData + pFM->GetExternalOffset(),
2036 ppCleanupWorkListOnStack);
2040 pCLRValue = *(OBJECTREF*)(internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData));
2041 pFM->UpdateNative(&pCLRValue, pNativeData + pFM->GetExternalOffset(), ppCleanupWorkListOnStack);
2042 SetObjectReferenceUnchecked( (OBJECTREF*) (internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData)), pCLRValue);
2045 // The cleanup work list is not used to clean up the native contents. It is used
2046 // to handle cleanup of any additional resources the FieldMarshalers allocate.
2048 ((BYTE*&)pFM) += MAXFIELDMARSHALERSIZE;
2055 VOID FmtClassUpdateNative(OBJECTREF *ppProtectedManagedData, BYTE *pNativeData, OBJECTREF *ppCleanupWorkListOnStack)
2062 PRECONDITION(CheckPointer(ppProtectedManagedData));
2066 MethodTable *pMT = (*ppProtectedManagedData)->GetMethodTable();
2067 _ASSERTE(pMT->IsBlittable() || pMT->HasLayout());
2068 UINT32 cbsize = pMT->GetNativeSize();
2070 if (pMT->IsBlittable())
2072 memcpyNoGCRefs(pNativeData, (*ppProtectedManagedData)->GetData(), cbsize);
2076 // This allows us to do a partial LayoutDestroyNative in the case of
2077 // a marshaling error on one of the fields.
2078 FillMemory(pNativeData, cbsize, 0);
2079 NativeLayoutDestroyer nld(pNativeData, pMT, cbsize);
2081 LayoutUpdateNative( (VOID**)ppProtectedManagedData,
2082 Object::GetOffsetOfFirstField(),
2085 ppCleanupWorkListOnStack);
2087 nld.SuppressRelease();
2093 VOID FmtClassUpdateCLR(OBJECTREF *ppProtectedManagedData, BYTE *pNativeData)
2103 MethodTable *pMT = (*ppProtectedManagedData)->GetMethodTable();
2104 _ASSERTE(pMT->IsBlittable() || pMT->HasLayout());
2105 UINT32 cbsize = pMT->GetNativeSize();
2107 if (pMT->IsBlittable())
2109 memcpyNoGCRefs((*ppProtectedManagedData)->GetData(), pNativeData, cbsize);
2113 LayoutUpdateCLR((VOID**)ppProtectedManagedData,
2114 Object::GetOffsetOfFirstField(),
2123 //=======================================================================
2124 // For each reference-typed FieldMarshaler field, marshals the current CLR value
2125 // to a new CLR instance and stores it in the GC portion of the FieldMarshaler.
2127 // If fDeleteNativeCopies is true, it will also destroy the native version.
2129 // NOTE: To avoid error-path leaks, this function attempts to destroy
2130 // all of the native fields even if one or more of the conversions fail.
2131 //=======================================================================
2132 VOID LayoutUpdateCLR(LPVOID *ppProtectedManagedData, SIZE_T offsetbias, MethodTable *pMT, BYTE *pNativeData)
2139 PRECONDITION(CheckPointer(pMT));
2143 // Don't try to destroy/free native the structure on exception, we may not own it. If we do own it and
2144 // are supposed to destroy/free it, we do it upstack (e.g. in a helper called from the marshaling stub).
2146 FieldMarshaler* pFM = pMT->GetLayoutInfo()->GetFieldMarshalers();
2147 UINT numReferenceFields = pMT->GetLayoutInfo()->GetNumCTMFields();
2151 OBJECTREF pCLRValue;
2152 OBJECTREF pOldCLRValue;
2155 gc.pCLRValue = NULL;
2156 gc.pOldCLRValue = NULL;
2157 LPVOID scalar = NULL;
2160 GCPROTECT_BEGININTERIOR(scalar)
2162 g_IBCLogger.LogFieldMarshalersReadAccess(pMT);
2164 while (numReferenceFields--)
2168 DWORD internalOffset = pFM->GetFieldDesc()->GetOffset();
2170 if (pFM->IsScalarMarshaler())
2172 scalar = (LPVOID)(internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData));
2173 // Note this will throw for FieldMarshaler_Illegal
2174 pFM->ScalarUpdateCLR( pNativeData + pFM->GetExternalOffset(), scalar);
2176 else if (pFM->IsNestedValueClassMarshaler())
2178 pFM->NestedValueClassUpdateCLR(pNativeData + pFM->GetExternalOffset(), ppProtectedManagedData, internalOffset + offsetbias);
2182 gc.pOldCLRValue = *(OBJECTREF*)(internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData));
2183 pFM->UpdateCLR( pNativeData + pFM->GetExternalOffset(), &gc.pCLRValue, &gc.pOldCLRValue );
2184 SetObjectReferenceUnchecked( (OBJECTREF*) (internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData)), gc.pCLRValue );
2187 ((BYTE*&)pFM) += MAXFIELDMARSHALERSIZE;
2195 VOID LayoutDestroyNative(LPVOID pNative, MethodTable *pMT)
2202 PRECONDITION(CheckPointer(pMT));
2206 FieldMarshaler *pFM = pMT->GetLayoutInfo()->GetFieldMarshalers();
2207 UINT numReferenceFields = pMT->GetLayoutInfo()->GetNumCTMFields();
2208 BYTE *pNativeData = (BYTE*)pNative;
2210 while (numReferenceFields--)
2212 pFM->DestroyNative( pNativeData + pFM->GetExternalOffset() );
2213 ((BYTE*&)pFM) += MAXFIELDMARSHALERSIZE;
2217 VOID FmtClassDestroyNative(LPVOID pNative, MethodTable *pMT)
2224 PRECONDITION(CheckPointer(pMT));
2230 if (!(pMT->IsBlittable()))
2232 _ASSERTE(pMT->HasLayout());
2233 LayoutDestroyNative(pNative, pMT);
2238 VOID FmtValueTypeUpdateNative(LPVOID pProtectedManagedData, MethodTable *pMT, BYTE *pNativeData, OBJECTREF *ppCleanupWorkListOnStack)
2245 PRECONDITION(CheckPointer(pMT));
2249 _ASSERTE(pMT->IsValueType() && (pMT->IsBlittable() || pMT->HasLayout()));
2250 UINT32 cbsize = pMT->GetNativeSize();
2252 if (pMT->IsBlittable())
2254 memcpyNoGCRefs(pNativeData, pProtectedManagedData, cbsize);
2258 // This allows us to do a partial LayoutDestroyNative in the case of
2259 // a marshaling error on one of the fields.
2260 FillMemory(pNativeData, cbsize, 0);
2262 NativeLayoutDestroyer nld(pNativeData, pMT, cbsize);
2264 LayoutUpdateNative( (VOID**)pProtectedManagedData,
2268 ppCleanupWorkListOnStack);
2270 nld.SuppressRelease();
2274 VOID FmtValueTypeUpdateCLR(LPVOID pProtectedManagedData, MethodTable *pMT, BYTE *pNativeData)
2281 PRECONDITION(CheckPointer(pMT));
2285 _ASSERTE(pMT->IsValueType() && (pMT->IsBlittable() || pMT->HasLayout()));
2286 UINT32 cbsize = pMT->GetNativeSize();
2288 if (pMT->IsBlittable())
2290 memcpyNoGCRefs(pProtectedManagedData, pNativeData, cbsize);
2294 LayoutUpdateCLR((VOID**)pProtectedManagedData,
2297 (BYTE*)pNativeData);
2301 //=======================================================================
2302 // BSTR <--> System.String
2303 // See FieldMarshaler for details.
2304 //=======================================================================
2305 VOID FieldMarshaler_BSTR::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
2312 INJECT_FAULT(COMPlusThrowOM());
2313 PRECONDITION(CheckPointer(pNativeValue));
2318 *((OBJECTREF*)&pString) = *pCLRValue;
2320 if (pString == NULL)
2321 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
2324 BSTR pBSTR = SysAllocStringLen(pString->GetBuffer(), pString->GetStringLength());
2328 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, pBSTR);
2333 //=======================================================================
2334 // BSTR <--> System.String
2335 // See FieldMarshaler for details.
2336 //=======================================================================
2337 VOID FieldMarshaler_BSTR::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
2339 STATIC_CONTRACT_THROWS;
2340 STATIC_CONTRACT_GC_TRIGGERS;
2341 STATIC_CONTRACT_MODE_COOPERATIVE;
2343 _ASSERTE(NULL != pNativeValue);
2344 _ASSERTE(NULL != ppProtectedCLRValue);
2347 BSTR pBSTR = (BSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
2353 struct Param : CallOutFilterParam {
2358 param.OneShot = TRUE;
2360 param.pBSTR = pBSTR;
2362 PAL_TRY(Param *, pParam, ¶m)
2364 pParam->length = SysStringLen(pParam->pBSTR);
2366 PAL_EXCEPT_FILTER(CallOutFilter)
2368 _ASSERTE(!"CallOutFilter returned EXECUTE_HANDLER.");
2372 pString = StringObject::NewString(pBSTR, param.length);
2375 *((STRINGREF*)ppProtectedCLRValue) = pString;
2379 //=======================================================================
2380 // BSTR <--> System.String
2381 // See FieldMarshaler for details.
2382 //=======================================================================
2383 VOID FieldMarshaler_BSTR::DestroyNativeImpl(LPVOID pNativeValue) const
2390 PRECONDITION(CheckPointer(pNativeValue));
2394 BSTR pBSTR = (BSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
2395 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
2399 // BSTR has been created, Delay load will not fail.
2400 CONTRACT_VIOLATION(ThrowsViolation);
2401 SysFreeString(pBSTR);
2405 #ifdef FEATURE_COMINTEROP
2406 //===========================================================================================
2407 // Windows.Foundation.IReference'1<-- System.Nullable'1
2409 VOID FieldMarshaler_Nullable::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const
2416 INJECT_FAULT(COMPlusThrowOM());
2417 PRECONDITION(CheckPointer(pNative));
2418 PRECONDITION(CheckPointer(pCLR));
2422 IUnknown *pUnk = NULL;
2424 // ConvertToNative<T>(ref Nullable<T> pManaged) where T : struct
2425 MethodDescCallSite convertToNative(GetMethodDescForGenericInstantiation(MscorlibBinder::GetMethod(METHOD__NULLABLEMARSHALER__CONVERT_TO_NATIVE)));
2431 pUnk = (IUnknown*) convertToNative.Call_RetLPVOID(args);
2433 MAYBE_UNALIGNED_WRITE(pNative, _PTR, pUnk);
2436 //===========================================================================================
2437 // Windows.Foundation.IReference'1--> System.Nullable'1
2439 VOID FieldMarshaler_Nullable::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const
2446 PRECONDITION(CheckPointer(pNative));
2447 PRECONDITION(CheckPointer(pCLR));
2451 IUnknown *pUnk = (IUnknown*)MAYBE_UNALIGNED_READ(pNative, _PTR);
2453 MethodDescCallSite convertToManaged(GetMethodDescForGenericInstantiation(MscorlibBinder::GetMethod(METHOD__NULLABLEMARSHALER__CONVERT_TO_MANAGED_RET_VOID)));
2461 //ConvertToManaged<T>(Intptr pNative, ref Nullable<T> retObj) where T : struct;
2462 convertToManaged.Call(args);
2465 //===========================================================================================
2466 // Windows.Foundation.IReference'1<--> System.Nullable'1
2468 VOID FieldMarshaler_Nullable::DestroyNativeImpl(const VOID* pNative) const
2475 PRECONDITION(CheckPointer(pNative));
2479 IUnknown *pUnk = (IUnknown*)MAYBE_UNALIGNED_READ(pNative, _PTR);
2480 MAYBE_UNALIGNED_WRITE(pNative, _PTR, NULL);
2484 ULONG cbRef = SafeRelease(pUnk);
2485 LogInteropRelease(pUnk, cbRef, "Field marshaler destroy native");
2489 //=======================================================================
2490 // HSTRING <--> System.String
2491 // See FieldMarshaler for details.
2492 //=======================================================================
2493 VOID FieldMarshaler_HSTRING::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
2500 PRECONDITION(CheckPointer(pCLRValue));
2501 PRECONDITION(CheckPointer(pNativeValue));
2505 if (!WinRTSupported())
2507 COMPlusThrow(kPlatformNotSupportedException, W("PlatformNotSupported_WinRT"));
2510 STRINGREF stringref = (STRINGREF)(*pCLRValue);
2512 if (stringref == NULL)
2514 DefineFullyQualifiedNameForClassW();
2515 StackSString ssFieldName(SString::Utf8, GetFieldDesc()->GetName());
2517 SString errorString;
2518 errorString.LoadResource(CCompRC::Error, IDS_EE_BADMARSHALFIELD_NULL_HSTRING);
2520 COMPlusThrow(kMarshalDirectiveException,
2521 IDS_EE_BADMARSHALFIELD_ERROR_MSG,
2522 GetFullyQualifiedNameForClassW(GetFieldDesc()->GetEnclosingMethodTable()),
2523 ssFieldName.GetUnicode(),
2524 errorString.GetUnicode());
2528 IfFailThrow(WindowsCreateString(stringref->GetBuffer(), stringref->GetStringLength(), &hstring));
2530 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, hstring);
2533 //=======================================================================
2534 // HSTRING <--> System.String
2535 // See FieldMarshaler for details.
2536 //=======================================================================
2537 VOID FieldMarshaler_HSTRING::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
2544 PRECONDITION(CheckPointer(pNativeValue));
2545 PRECONDITION(CheckPointer(ppProtectedCLRValue));
2549 if (!WinRTSupported())
2551 COMPlusThrow(kPlatformNotSupportedException, W("PlatformNotSupported_WinRT"));
2554 // NULL HSTRINGS are equivilent to empty strings
2555 UINT32 cchString = 0;
2556 LPCWSTR pwszString = W("");
2558 HSTRING hstring = (HSTRING)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
2559 if (hstring != NULL)
2561 pwszString = WindowsGetStringRawBuffer(hstring, &cchString);
2564 STRINGREF stringref = StringObject::NewString(pwszString, cchString);
2565 *((STRINGREF *)ppProtectedCLRValue) = stringref;
2568 //=======================================================================
2569 // HSTRING <--> System.String
2570 // See FieldMarshaler for details.
2571 //=======================================================================
2572 VOID FieldMarshaler_HSTRING::DestroyNativeImpl(LPVOID pNativeValue) const
2579 PRECONDITION(CheckPointer(pNativeValue));
2583 HSTRING hstring = (HSTRING)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
2584 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
2586 if (hstring != NULL)
2588 // We need this for code:System.Runtime.InteropServices.Marshal.DestroyStructure (user can explicitly call it)
2589 if (WinRTSupported())
2591 // If WinRT is supported we've already loaded combase.dll, which means
2592 // this delay load will succeed
2593 CONTRACT_VIOLATION(ThrowsViolation);
2594 WindowsDeleteString(hstring);
2599 //=======================================================================================
2600 // Windows.UI.Xaml.Interop.TypeName <--> System.Type
2602 VOID FieldMarshaler_SystemType::UpdateNativeImpl(OBJECTREF * pCLRValue, LPVOID pNativeValue, OBJECTREF * ppCleanupWorkListOnStack) const
2609 PRECONDITION(CheckPointer(pCLRValue));
2610 PRECONDITION(CheckPointer(pNativeValue));
2614 // ConvertToNative(System.Type managedType, TypeName *pTypeName)
2615 MethodDescCallSite convertToNative(METHOD__SYSTEMTYPEMARSHALER__CONVERT_TO_NATIVE);
2618 ObjToArgSlot(*pCLRValue),
2619 PtrToArgSlot(pNativeValue)
2621 convertToNative.Call(args);
2624 //=======================================================================================
2625 // Windows.UI.Xaml.Interop.TypeName <--> System.Type
2627 VOID FieldMarshaler_SystemType::UpdateCLRImpl(const VOID * pNativeValue, OBJECTREF * ppProtectedCLRValue, OBJECTREF * ppProtectedOldCLRValue) const
2634 PRECONDITION(CheckPointer(pNativeValue));
2635 PRECONDITION(CheckPointer(ppProtectedCLRValue));
2639 // ConvertToManaged(TypeName *pTypeName, out System.Type)
2640 MethodDescCallSite convertToManaged(METHOD__SYSTEMTYPEMARSHALER__CONVERT_TO_MANAGED);
2643 PtrToArgSlot(pNativeValue),
2644 PtrToArgSlot(ppProtectedCLRValue)
2647 convertToManaged.Call(args);
2650 //=======================================================================================
2651 // Windows.UI.Xaml.Interop.TypeName <--> System.Type
2652 // Clear the HSTRING field
2654 VOID FieldMarshaler_SystemType::DestroyNativeImpl(LPVOID pNativeValue) const
2661 PRECONDITION(CheckPointer(pNativeValue));
2662 PRECONDITION(WinRTSupported());
2667 // Call WindowsDeleteString instead of SystemTypeMarshaler.ClearNative
2668 // because WindowsDeleteString does not throw and is much faster
2670 size_t offset = offsetof(TypeNameNative, typeName);
2671 HSTRING hstring = (HSTRING)MAYBE_UNALIGNED_READ((LPBYTE) pNativeValue + offset , _PTR);
2672 MAYBE_UNALIGNED_WRITE((LPBYTE) pNativeValue + offset, _PTR, NULL);
2674 if (hstring != NULL)
2676 // Note: we've already loaded combase.dll, which means this delay load will succeed
2677 CONTRACT_VIOLATION(ThrowsViolation);
2678 WindowsDeleteString(hstring);
2682 //=======================================================================================
2683 // Windows.Foundation.HResult <--> System.Exception
2684 // Note: The WinRT struct has exactly 1 field, Value (an HRESULT)
2686 VOID FieldMarshaler_Exception::UpdateNativeImpl(OBJECTREF * pCLRValue, LPVOID pNativeValue, OBJECTREF * ppCleanupWorkListOnStack) const
2693 PRECONDITION(CheckPointer(pCLRValue));
2694 PRECONDITION(CheckPointer(pNativeValue));
2698 // int ConvertToNative(Exception ex)
2699 MethodDescCallSite convertToNative(METHOD__HRESULTEXCEPTIONMARSHALER__CONVERT_TO_NATIVE);
2702 ObjToArgSlot(*pCLRValue)
2704 int iReturnedValue = convertToNative.Call_RetI4(args);
2705 MAYBE_UNALIGNED_WRITE(pNativeValue, 32, iReturnedValue);
2708 //=======================================================================================
2709 // Windows.Foundation.HResult <--> System.Exception
2710 // Note: The WinRT struct has exactly 1 field, Value (an HRESULT)
2712 VOID FieldMarshaler_Exception::UpdateCLRImpl(const VOID * pNativeValue, OBJECTREF * ppProtectedCLRValue, OBJECTREF * ppProtectedOldCLRValue) const
2719 PRECONDITION(CheckPointer(pNativeValue));
2720 PRECONDITION(CheckPointer(ppProtectedCLRValue));
2724 // Exception ConvertToManaged(int hr)
2725 MethodDescCallSite convertToManaged(METHOD__HRESULTEXCEPTIONMARSHALER__CONVERT_TO_MANAGED);
2728 (ARG_SLOT)MAYBE_UNALIGNED_READ(pNativeValue, 32)
2730 *ppProtectedCLRValue = convertToManaged.Call_RetOBJECTREF(args);
2733 #endif // FEATURE_COMINTEROP
2736 //=======================================================================
2737 // Nested structure conversion
2738 // See FieldMarshaler for details.
2739 //=======================================================================
2740 VOID FieldMarshaler_NestedLayoutClass::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
2747 INJECT_FAULT(COMPlusThrowOM());
2748 PRECONDITION(CheckPointer(pNativeValue));
2752 UINT32 cbNativeSize = GetMethodTable()->GetNativeSize();
2754 if (*pCLRValue == NULL)
2756 ZeroMemoryInGCHeap(pNativeValue, cbNativeSize);
2760 LayoutUpdateNative((LPVOID*)pCLRValue, Object::GetOffsetOfFirstField(),
2761 GetMethodTable(), (BYTE*)pNativeValue, ppCleanupWorkListOnStack);
2767 //=======================================================================
2768 // Nested structure conversion
2769 // See FieldMarshaler for details.
2770 //=======================================================================
2771 VOID FieldMarshaler_NestedLayoutClass::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
2778 INJECT_FAULT(COMPlusThrowOM());
2779 PRECONDITION(CheckPointer(pNativeValue));
2780 PRECONDITION(CheckPointer(ppProtectedCLRValue));
2784 *ppProtectedCLRValue = GetMethodTable()->Allocate();
2786 LayoutUpdateCLR( (LPVOID*)ppProtectedCLRValue,
2787 Object::GetOffsetOfFirstField(),
2789 (BYTE *)pNativeValue);
2794 //=======================================================================
2795 // Nested structure conversion
2796 // See FieldMarshaler for details.
2797 //=======================================================================
2798 VOID FieldMarshaler_NestedLayoutClass::DestroyNativeImpl(LPVOID pNativeValue) const
2805 PRECONDITION(CheckPointer(pNativeValue));
2809 LayoutDestroyNative(pNativeValue, GetMethodTable());
2812 #endif // CROSSGEN_COMPILE
2815 //=======================================================================
2816 // Nested structure conversion
2817 // See FieldMarshaler for details.
2818 //=======================================================================
2819 UINT32 FieldMarshaler_NestedLayoutClass::NativeSizeImpl() const
2829 return GetMethodTable()->GetLayoutInfo()->GetNativeSize();
2832 //=======================================================================
2833 // Nested structure conversion
2834 // See FieldMarshaler for details.
2835 //=======================================================================
2836 UINT32 FieldMarshaler_NestedLayoutClass::AlignmentRequirementImpl() const
2846 return GetMethodTable()->GetLayoutInfo()->GetLargestAlignmentRequirementOfAllMembers();
2849 #if FEATURE_COMINTEROP
2850 MethodDesc* FieldMarshaler_Nullable::GetMethodDescForGenericInstantiation(MethodDesc* pMD) const
2852 MethodDesc *pMethodInstantiation;
2854 pMethodInstantiation = MethodDesc::FindOrCreateAssociatedMethodDesc(
2856 pMD->GetMethodTable(),
2858 GetMethodTable()->GetInstantiation(),
2862 _ASSERTE(pMethodInstantiation != NULL);
2864 return pMethodInstantiation;
2866 #endif //FEATURE_COMINTEROP
2868 #ifndef CROSSGEN_COMPILE
2870 //=======================================================================
2871 // Nested structure conversion
2872 // See FieldMarshaler for details.
2873 //=======================================================================
2874 VOID FieldMarshaler_NestedValueClass::NestedValueClassUpdateNativeImpl(const VOID **ppProtectedCLR, SIZE_T startoffset, LPVOID pNative, OBJECTREF *ppCleanupWorkListOnStack) const
2881 INJECT_FAULT(COMPlusThrowOM());
2882 PRECONDITION(CheckPointer(ppProtectedCLR));
2883 PRECONDITION(CheckPointer(pNative));
2887 MethodTable* pMT = GetMethodTable();
2889 // would be better to detect this at class load time (that have a nested value
2890 // class with no layout) but don't have a way to know
2891 if (!pMT->GetLayoutInfo())
2892 COMPlusThrow(kArgumentException, IDS_NOLAYOUT_IN_EMBEDDED_VALUECLASS);
2894 if (pMT->IsBlittable())
2896 memcpyNoGCRefs(pNative, (BYTE*)(*ppProtectedCLR) + startoffset, pMT->GetNativeSize());
2901 _ASSERTE_MSG(!IsFixedBuffer(), "Cannot correctly marshal fixed buffers of non-blittable types");
2903 LayoutUpdateNative((LPVOID*)ppProtectedCLR, startoffset, pMT, (BYTE*)pNative, ppCleanupWorkListOnStack);
2908 //=======================================================================
2909 // Nested structure conversion
2910 // See FieldMarshaler for details.
2911 //=======================================================================
2912 VOID FieldMarshaler_NestedValueClass::NestedValueClassUpdateCLRImpl(const VOID *pNative, LPVOID *ppProtectedCLR, SIZE_T startoffset) const
2919 PRECONDITION(CheckPointer(pNative));
2920 PRECONDITION(CheckPointer(ppProtectedCLR));
2924 MethodTable* pMT = GetMethodTable();
2926 // would be better to detect this at class load time (that have a nested value
2927 // class with no layout) but don't have a way to know
2928 if (!pMT->GetLayoutInfo())
2929 COMPlusThrow(kArgumentException, IDS_NOLAYOUT_IN_EMBEDDED_VALUECLASS);
2931 if (pMT->IsBlittable())
2933 memcpyNoGCRefs((BYTE*)(*ppProtectedCLR) + startoffset, pNative, pMT->GetNativeSize());
2938 _ASSERTE_MSG(!IsFixedBuffer(), "Cannot correctly marshal fixed buffers of non-blittable types");
2940 LayoutUpdateCLR((LPVOID*)ppProtectedCLR,
2948 //=======================================================================
2949 // Nested structure conversion
2950 // See FieldMarshaler for details.
2951 //=======================================================================
2952 VOID FieldMarshaler_NestedValueClass::DestroyNativeImpl(LPVOID pNativeValue) const
2959 PRECONDITION(CheckPointer(pNativeValue));
2963 MethodTable* pMT = GetMethodTable();
2965 if (!pMT->IsBlittable())
2967 LayoutDestroyNative(pNativeValue, pMT);
2971 #endif // CROSSGEN_COMPILE
2974 //=======================================================================
2975 // Nested structure conversion
2976 // See FieldMarshaler for details.
2977 //=======================================================================
2978 UINT32 FieldMarshaler_NestedValueClass::NativeSizeImpl() const
2988 // this can't be marshalled as native type if no layout, so we allow the
2989 // native size info to be created if available, but the size will only
2990 // be valid for native, not unions. Marshaller will throw exception if
2991 // try to marshall a value class with no layout
2992 if (GetMethodTable()->HasLayout())
2993 return GetMethodTable()->GetLayoutInfo()->GetNativeSize();
2999 //=======================================================================
3000 // Nested structure conversion
3001 // See FieldMarshaler for details.
3002 //=======================================================================
3003 UINT32 FieldMarshaler_NestedValueClass::AlignmentRequirementImpl() const
3013 // this can't be marshalled as native type if no layout, so we allow the
3014 // native size info to be created if available, but the alignment will only
3015 // be valid for native, not unions. Marshaller will throw exception if
3016 // try to marshall a value class with no layout
3017 if (GetMethodTable()->HasLayout())
3019 UINT32 uAlignmentReq = GetMethodTable()->GetLayoutInfo()->GetLargestAlignmentRequirementOfAllMembers();
3020 return uAlignmentReq;
3026 #ifndef CROSSGEN_COMPILE
3028 //=======================================================================
3029 // CoTask Uni <--> System.String
3030 // See FieldMarshaler for details.
3031 //=======================================================================
3032 VOID FieldMarshaler_StringUni::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3039 INJECT_FAULT(COMPlusThrowOM());
3040 PRECONDITION(CheckPointer(pNativeValue));
3045 *((OBJECTREF*)&pString) = *pCLRValue;
3047 if (pString == NULL)
3049 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3053 DWORD nc = pString->GetStringLength();
3054 if (nc > MAX_SIZE_FOR_INTEROP)
3055 COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG);
3057 LPWSTR wsz = (LPWSTR)CoTaskMemAlloc( (nc + 1) * sizeof(WCHAR) );
3061 memcpyNoGCRefs(wsz, pString->GetBuffer(), nc*sizeof(WCHAR));
3063 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, wsz);
3068 //=======================================================================
3069 // CoTask Uni <--> System.String
3070 // See FieldMarshaler for details.
3071 //=======================================================================
3072 VOID FieldMarshaler_StringUni::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3079 PRECONDITION(CheckPointer(pNativeValue));
3080 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3085 LPCWSTR wsz = (LPCWSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3091 SIZE_T length = wcslen(wsz);
3092 if (length > MAX_SIZE_FOR_INTEROP)
3093 COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG);
3095 pString = StringObject::NewString(wsz, (DWORD)length);
3098 *((STRINGREF*)ppProtectedCLRValue) = pString;
3102 //=======================================================================
3103 // CoTask Uni <--> System.String
3104 // See FieldMarshaler for details.
3105 //=======================================================================
3106 VOID FieldMarshaler_StringUni::DestroyNativeImpl(LPVOID pNativeValue) const
3113 PRECONDITION(CheckPointer(pNativeValue));
3117 LPWSTR wsz = (LPWSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3118 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3125 //=======================================================================
3126 // CoTask Ansi <--> System.String
3127 // See FieldMarshaler for details.
3128 //=======================================================================
3129 VOID FieldMarshaler_StringAnsi::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3136 INJECT_FAULT(COMPlusThrowOM());
3137 PRECONDITION(CheckPointer(pNativeValue));
3142 *((OBJECTREF*)&pString) = *pCLRValue;
3144 if (pString == NULL)
3146 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3150 DWORD nc = pString->GetStringLength();
3151 if (nc > MAX_SIZE_FOR_INTEROP)
3152 COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG);
3154 LPSTR sz = (LPSTR)CoTaskMemAlloc( (nc + 1) * 2 /* 2 for MBCS */ );
3158 int nbytes = InternalWideToAnsi(pString->GetBuffer(),
3163 m_ThrowOnUnmappableChar);
3166 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, sz);
3171 //=======================================================================
3172 // CoTask Ansi <--> System.String
3173 // See FieldMarshaler for details.
3174 //=======================================================================
3175 VOID FieldMarshaler_StringAnsi::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3182 INJECT_FAULT(COMPlusThrowOM());
3183 PRECONDITION(CheckPointer(pNativeValue));
3184 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3188 STRINGREF pString = NULL;
3189 LPCSTR sz = (LPCSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3194 MAKE_WIDEPTR_FROMANSI(wsztemp, sz);
3195 pString = StringObject::NewString(wsztemp, __lwsztemp - 1);
3198 *((STRINGREF*)ppProtectedCLRValue) = pString;
3202 //=======================================================================
3203 // CoTask Ansi <--> System.String
3204 // See FieldMarshaler for details.
3205 //=======================================================================
3206 VOID FieldMarshaler_StringAnsi::DestroyNativeImpl(LPVOID pNativeValue) const
3213 PRECONDITION(CheckPointer(pNativeValue));
3217 LPSTR sz = (LPSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3218 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3223 //=======================================================================
3224 // CoTask Utf8 <--> System.String
3225 // See FieldMarshaler for details.
3226 //=======================================================================
3227 VOID FieldMarshaler_StringUtf8::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3234 INJECT_FAULT(COMPlusThrowOM());
3235 PRECONDITION(CheckPointer(pNativeValue));
3239 STRINGREF pString = (STRINGREF)(*pCLRValue);
3240 if (pString == NULL)
3242 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3246 DWORD nc = pString->GetStringLength();
3247 if (nc > MAX_SIZE_FOR_INTEROP)
3248 COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG);
3250 // Characters would be # of characters + 1 in case left over high surrogate is ?
3251 // Max 3 bytes per char for basic multi-lingual plane.
3252 nc = (nc + 1) * MAX_UTF8_CHAR_SIZE;
3254 LPUTF8 lpBuffer = (LPUTF8)CoTaskMemAlloc(nc + 1);
3260 // UTF8Marshaler.ConvertToNative
3261 MethodDescCallSite convertToNative(METHOD__CUTF8MARSHALER__CONVERT_TO_NATIVE);
3265 ((ARG_SLOT)(CLR_I4)0),
3266 ObjToArgSlot(*pCLRValue),
3267 PtrToArgSlot(lpBuffer)
3269 convertToNative.Call(args);
3270 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, lpBuffer);
3275 //=======================================================================
3276 // CoTask Utf8 <--> System.String
3277 // See FieldMarshaler for details.
3278 //=======================================================================
3279 VOID FieldMarshaler_StringUtf8::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3286 INJECT_FAULT(COMPlusThrowOM());
3287 PRECONDITION(CheckPointer(pNativeValue));
3288 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3292 STRINGREF pString = NULL;
3293 LPCUTF8 sz = (LPCUTF8)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3296 MethodDescCallSite convertToManaged(METHOD__CUTF8MARSHALER__CONVERT_TO_MANAGED);
3301 pString = convertToManaged.Call_RetSTRINGREF(args);
3303 *((STRINGREF*)ppProtectedCLRValue) = pString;
3306 //=======================================================================
3307 // CoTask Utf8 <--> System.String
3308 // See FieldMarshaler for details.
3309 //=======================================================================
3310 VOID FieldMarshaler_StringUtf8::DestroyNativeImpl(LPVOID pNativeValue) const
3317 PRECONDITION(CheckPointer(pNativeValue));
3321 LPCUTF8 lpBuffer = (LPCUTF8)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3322 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3324 CoTaskMemFree((LPVOID)lpBuffer);
3327 //=======================================================================
3328 // FixedString <--> System.String
3329 // See FieldMarshaler for details.
3330 //=======================================================================
3331 VOID FieldMarshaler_FixedStringUni::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3338 PRECONDITION(CheckPointer(pNativeValue));
3343 *((OBJECTREF*)&pString) = *pCLRValue;
3345 if (pString == NULL)
3347 MAYBE_UNALIGNED_WRITE(pNativeValue, 16, W('\0'));
3351 DWORD nc = pString->GetStringLength();
3352 if (nc >= m_numchar)
3355 memcpyNoGCRefs(pNativeValue, pString->GetBuffer(), nc*sizeof(WCHAR));
3356 MAYBE_UNALIGNED_WRITE(&(((WCHAR*)pNativeValue)[nc]), 16, W('\0'));
3362 //=======================================================================
3363 // FixedString <--> System.String
3364 // See FieldMarshaler for details.
3365 //=======================================================================
3366 VOID FieldMarshaler_FixedStringUni::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3373 PRECONDITION(CheckPointer(pNativeValue));
3374 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3379 SIZE_T ncActual = wcsnlen((const WCHAR *)pNativeValue, m_numchar);
3381 if (!FitsIn<int>(ncActual))
3382 COMPlusThrowHR(COR_E_OVERFLOW);
3384 pString = StringObject::NewString((const WCHAR *)pNativeValue, (int)ncActual);
3385 *((STRINGREF*)ppProtectedCLRValue) = pString;
3394 //=======================================================================
3395 // FixedString <--> System.String
3396 // See FieldMarshaler for details.
3397 //=======================================================================
3398 VOID FieldMarshaler_FixedStringAnsi::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3405 PRECONDITION(CheckPointer(pNativeValue));
3410 *((OBJECTREF*)&pString) = *pCLRValue;
3412 if (pString == NULL)
3413 *((CHAR*)pNativeValue) = W('\0');
3416 DWORD nc = pString->GetStringLength();
3417 if (nc >= m_numchar)
3420 int cbwritten = InternalWideToAnsi(pString->GetBuffer(),
3422 (CHAR*)pNativeValue,
3425 m_ThrowOnUnmappableChar);
3427 // Handle the case where SizeConst == Number of bytes.For single byte chars
3428 // this will never be the case since nc >= m_numchar check will truncate the last
3429 // character, but for multibyte chars nc>= m_numchar check won't truncate since GetStringLength
3430 // gives number of characters but not the actual number of bytes. For such cases need to make
3431 // sure that we dont write one past the buffer.
3432 if (cbwritten == (int) m_numchar)
3435 ((CHAR*)pNativeValue)[cbwritten] = '\0';
3440 //=======================================================================
3441 // FixedString <--> System.String
3442 // See FieldMarshaler for details.
3443 //=======================================================================
3444 VOID FieldMarshaler_FixedStringAnsi::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3451 INJECT_FAULT(COMPlusThrowOM());
3452 PRECONDITION(CheckPointer(pNativeValue));
3453 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3455 // should not have slipped past the metadata
3456 PRECONDITION(m_numchar != 0);
3463 // but if it does, better to throw an exception tardily rather than
3464 // allow a memory corrupt.
3465 COMPlusThrow(kMarshalDirectiveException);
3468 UINT32 allocSize = m_numchar + 2;
3469 if (allocSize < m_numchar)
3472 LPSTR tempbuf = (LPSTR)(_alloca((size_t)allocSize));
3476 memcpyNoGCRefs(tempbuf, pNativeValue, m_numchar);
3477 tempbuf[m_numchar-1] = '\0';
3478 tempbuf[m_numchar] = '\0';
3479 tempbuf[m_numchar+1] = '\0';
3481 allocSize = m_numchar * sizeof(WCHAR);
3482 if (allocSize < m_numchar)
3485 LPWSTR wsztemp = (LPWSTR)_alloca( (size_t)allocSize );
3486 int ncwritten = MultiByteToWideChar(CP_ACP,
3489 -1, // # of CHAR's in inbuffer
3491 m_numchar // size (in WCHAR) of outbuffer
3496 // intentionally not throwing for MB2WC failure. We don't always know
3497 // whether to expect a valid string in the buffer and we don't want
3498 // to throw exceptions randomly.
3502 pString = StringObject::NewString((const WCHAR *)wsztemp, ncwritten-1);
3503 *((STRINGREF*)ppProtectedCLRValue) = pString;
3507 //=======================================================================
3508 // CHAR[] <--> char[]
3509 // See FieldMarshaler for details.
3510 //=======================================================================
3511 VOID FieldMarshaler_FixedCharArrayAnsi::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3518 INJECT_FAULT(COMPlusThrowOM());
3519 PRECONDITION(CheckPointer(pNativeValue));
3524 *((OBJECTREF*)&pArray) = *pCLRValue;
3527 FillMemory(pNativeValue, m_numElems * sizeof(CHAR), 0);
3530 if (pArray->GetNumComponents() < m_numElems)
3531 COMPlusThrow(kArgumentException, IDS_WRONGSIZEARRAY_IN_NSTRUCT);
3534 InternalWideToAnsi((const WCHAR*) pArray->GetDataPtr(),
3536 (CHAR*)pNativeValue,
3537 m_numElems * sizeof(CHAR),
3539 m_ThrowOnUnmappableChar);
3545 //=======================================================================
3546 // CHAR[] <--> char[]
3547 // See FieldMarshaler for details.
3548 //=======================================================================
3549 VOID FieldMarshaler_FixedCharArrayAnsi::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3556 INJECT_FAULT(COMPlusThrowOM());
3557 PRECONDITION(CheckPointer(pNativeValue));
3558 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3562 *ppProtectedCLRValue = AllocatePrimitiveArray(ELEMENT_TYPE_CHAR, m_numElems);
3564 MultiByteToWideChar(CP_ACP,
3566 (const CHAR *)pNativeValue,
3567 m_numElems * sizeof(CHAR), // size, in bytes, of in buffer
3568 (WCHAR*) ((*((I2ARRAYREF*)ppProtectedCLRValue))->GetDirectPointerToNonObjectElements()),
3569 m_numElems); // size, in WCHAR's of outbuffer
3572 #endif // CROSSGEN_COMPILE
3575 //=======================================================================
3577 // See FieldMarshaler for details.
3578 //=======================================================================
3579 FieldMarshaler_FixedArray::FieldMarshaler_FixedArray(IMDInternalImport *pMDImport, mdTypeDef cl, UINT32 numElems, VARTYPE vt, MethodTable* pElementMT)
3580 : m_numElems(numElems)
3582 , m_BestFitMap(FALSE)
3583 , m_ThrowOnUnmappableChar(FALSE)
3590 PRECONDITION(CheckPointer(pElementMT));
3591 PRECONDITION(vt != VTHACK_ANSICHAR); // This must be handled by the FixedCharArrayAnsi marshaler.
3595 // Only attempt to read the best fit mapping attribute if required to minimize
3596 // custom attribute accesses.
3597 if (vt == VT_LPSTR || vt == VT_RECORD)
3599 BOOL BestFitMap = FALSE;
3600 BOOL ThrowOnUnmappableChar = FALSE;
3601 ReadBestFitCustomAttribute(pMDImport, cl, &BestFitMap, &ThrowOnUnmappableChar);
3602 m_BestFitMap = !!BestFitMap;
3603 m_ThrowOnUnmappableChar = !!ThrowOnUnmappableChar;
3606 m_arrayType.SetValue(ClassLoader::LoadArrayTypeThrowing(TypeHandle(pElementMT),
3607 ELEMENT_TYPE_SZARRAY,
3609 ClassLoader::LoadTypes,
3610 pElementMT->GetLoadLevel()));
3614 #ifndef CROSSGEN_COMPILE
3616 //=======================================================================
3618 // See FieldMarshaler for details.
3619 //=======================================================================
3620 VOID FieldMarshaler_FixedArray::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3627 PRECONDITION(CheckPointer(pNativeValue));
3631 if (*pCLRValue == NULL)
3633 FillMemory(pNativeValue, NativeSize(), 0);
3637 // Make sure the size of the array is >= as specified in the MarshalAs attribute (via the SizeConst field).
3638 if ((*pCLRValue)->GetNumComponents() < m_numElems)
3639 COMPlusThrow(kArgumentException, IDS_WRONGSIZEARRAY_IN_NSTRUCT);
3641 // Marshal the contents from the managed array to the native array.
3642 const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(m_vt, TRUE);
3643 if (pMarshaler == NULL || pMarshaler->ComToOleArray == NULL)
3645 memcpyNoGCRefs(pNativeValue, (*(BASEARRAYREF*)pCLRValue)->GetDataPtr(), NativeSize());
3649 MethodTable *pElementMT = m_arrayType.GetValue().AsArray()->GetArrayElementTypeHandle().GetMethodTable();
3651 // We never operate on an uninitialized native layout here, we have zero'ed it if needed.
3652 // Therefore fOleArrayIsValid is always TRUE.
3653 pMarshaler->ComToOleArray((BASEARRAYREF*)pCLRValue, pNativeValue, pElementMT, m_BestFitMap, m_ThrowOnUnmappableChar, TRUE, m_numElems);
3659 //=======================================================================
3661 // See FieldMarshaler for details.
3662 //=======================================================================
3663 VOID FieldMarshaler_FixedArray::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3670 INJECT_FAULT(COMPlusThrowOM());
3671 PRECONDITION(CheckPointer(pNativeValue));
3672 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3676 // Allocate the value class array.
3677 *ppProtectedCLRValue = AllocateArrayEx(m_arrayType.GetValue(), (INT32*)&m_numElems, 1);
3679 // Marshal the contents from the native array to the managed array.
3680 const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(m_vt, TRUE);
3681 if (pMarshaler == NULL || pMarshaler->OleToComArray == NULL)
3683 memcpyNoGCRefs((*(BASEARRAYREF*)ppProtectedCLRValue)->GetDataPtr(), pNativeValue, NativeSize());
3687 MethodTable *pElementMT = m_arrayType.GetValue().AsArray()->GetArrayElementTypeHandle().GetMethodTable();
3688 pMarshaler->OleToComArray((VOID *)pNativeValue, (BASEARRAYREF*)ppProtectedCLRValue, pElementMT);
3692 //=======================================================================
3694 // See FieldMarshaler for details.
3695 //=======================================================================
3696 VOID FieldMarshaler_FixedArray::DestroyNativeImpl(LPVOID pNativeValue) const
3703 INJECT_FAULT(COMPlusThrowOM());
3704 PRECONDITION(CheckPointer(pNativeValue));
3708 const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(m_vt, FALSE);
3710 if (pMarshaler != NULL && pMarshaler->ClearOleArray != NULL)
3712 MethodTable *pElementMT = m_arrayType.GetValue().AsArray()->GetArrayElementTypeHandle().GetMethodTable();
3713 pMarshaler->ClearOleArray(pNativeValue, m_numElems, pElementMT);
3717 #endif // CROSSGEN_COMPILE
3720 //=======================================================================
3722 // See FieldMarshaler for details.
3723 //=======================================================================
3724 UINT32 FieldMarshaler_FixedArray::AlignmentRequirementImpl() const
3726 WRAPPER_NO_CONTRACT;
3728 UINT32 alignment = 0;
3729 TypeHandle elementType = m_arrayType.GetValue().AsArray()->GetArrayElementTypeHandle();
3742 alignment = elementType.GetMethodTable()->GetLayoutInfo()->GetLargestAlignmentRequirementOfAllMembers();
3746 alignment = OleVariant::GetElementSizeForVarType(m_vt, elementType.GetMethodTable());
3753 #ifndef CROSSGEN_COMPILE
3755 #ifdef FEATURE_CLASSIC_COMINTEROP
3756 //=======================================================================
3758 // See FieldMarshaler for details.
3759 //=======================================================================
3760 VOID FieldMarshaler_SafeArray::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3767 PRECONDITION(CheckPointer(pNativeValue));
3771 BASEARRAYREF pArray;
3772 *((OBJECTREF*)&pArray) = *pCLRValue;
3773 if ((pArray == NULL) || (OBJECTREFToObject(pArray) == NULL))
3775 FillMemory(pNativeValue, sizeof(LPSAFEARRAY*), 0);
3779 LPSAFEARRAY* pSafeArray;
3780 pSafeArray = (LPSAFEARRAY*)pNativeValue;
3783 MethodTable* pMT = m_pMT.GetValueMaybeNull();
3785 GCPROTECT_BEGIN(pArray)
3788 vt = OleVariant::GetElementVarTypeForArrayRef(pArray);
3791 pMT = OleVariant::GetArrayElementTypeWrapperAware(&pArray).GetMethodTable();
3793 // OleVariant calls throw on error.
3794 *pSafeArray = OleVariant::CreateSafeArrayForArrayRef(&pArray, vt, pMT);
3795 OleVariant::MarshalSafeArrayForArrayRef(&pArray, *pSafeArray, vt, pMT);
3801 //=======================================================================
3803 // See FieldMarshaler for details.
3804 //=======================================================================
3805 VOID FieldMarshaler_SafeArray::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3812 INJECT_FAULT(COMPlusThrowOM());
3813 PRECONDITION(CheckPointer(pNativeValue));
3814 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3818 LPSAFEARRAY* pSafeArray;
3819 pSafeArray = (LPSAFEARRAY*)pNativeValue;
3821 if ((pSafeArray == NULL) || (*pSafeArray == NULL))
3823 *ppProtectedCLRValue = NULL;
3828 MethodTable* pMT = m_pMT.GetValueMaybeNull();
3830 // If we have an empty vartype, get it from the safearray vartype
3833 if (FAILED(ClrSafeArrayGetVartype(*pSafeArray, &vt)))
3834 COMPlusThrow(kArgumentException, IDS_EE_INVALID_SAFEARRAY);
3837 // Get the method table if we need to.
3838 if ((vt == VT_RECORD) && (!pMT))
3839 pMT = OleVariant::GetElementTypeForRecordSafeArray(*pSafeArray).GetMethodTable();
3841 // If we have a single dimension safearray, it will be converted into a SZArray.
3842 // SZArray must have a lower bound of zero.
3843 LONG LowerBound = -1;
3844 UINT Dimensions = SafeArrayGetDim( (SAFEARRAY*)*pSafeArray );
3846 if (Dimensions == 1)
3848 HRESULT hr = SafeArrayGetLBound((SAFEARRAY*)*pSafeArray, 1, &LowerBound);
3849 if ( FAILED(hr) || LowerBound != 0)
3850 COMPlusThrow(kSafeArrayRankMismatchException, IDS_EE_SAFEARRAYSZARRAYMISMATCH);
3853 // OleVariant calls throw on error.
3854 *ppProtectedCLRValue = OleVariant::CreateArrayRefForSafeArray(*pSafeArray, vt, pMT);
3855 OleVariant::MarshalArrayRefForSafeArray(*pSafeArray, (BASEARRAYREF*)ppProtectedCLRValue, vt, pMT);
3859 //=======================================================================
3861 // See FieldMarshaler for details.
3862 //=======================================================================
3863 VOID FieldMarshaler_SafeArray::DestroyNativeImpl(LPVOID pNativeValue) const
3870 PRECONDITION(CheckPointer(pNativeValue));
3877 LPSAFEARRAY psa = (LPSAFEARRAY)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
3878 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
3882 _ASSERTE (GetModuleHandleA("oleaut32.dll") != NULL);
3883 // SafeArray has been created, which means oleaut32 should have been loaded.
3884 // Delay load will not fail.
3885 CONTRACT_VIOLATION(ThrowsViolation);
3886 hr = SafeArrayDestroy(psa);
3887 _ASSERTE(!FAILED(hr));
3890 #endif //FEATURE_CLASSIC_COMINTEROP
3893 //=======================================================================
3894 // function ptr <--> Delegate
3895 // See FieldMarshaler for details.
3896 //=======================================================================
3897 VOID FieldMarshaler_Delegate::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3904 PRECONDITION(CheckPointer(pNativeValue));
3908 LPVOID fnPtr = COMDelegate::ConvertToCallback(*pCLRValue);
3910 // If there is no CleanupWorkList (i.e. a call from Marshal.StructureToPtr), we don't use it to manage delegate lifetime.
3911 // In that case, it falls on the user to manage the delegate lifetime. This is the cleanest way to do this since there is no well-defined
3912 // object lifetime for the unmanaged memory that the structure would be marshalled to in the Marshal.StructureToPtr case.
3913 if (*pCLRValue != NULL && ppCleanupWorkListOnStack != NULL)
3915 // Call StubHelpers.AddToCleanupList to ensure the delegate is kept alive across the full native call.
3916 MethodDescCallSite AddToCleanupList(METHOD__STUBHELPERS__ADD_TO_CLEANUP_LIST_DELEGATE);
3920 (ARG_SLOT)ppCleanupWorkListOnStack,
3921 ObjToArgSlot(*pCLRValue)
3924 AddToCleanupList.Call(args);
3927 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, fnPtr);
3931 //=======================================================================
3932 // function ptr <--> Delegate
3933 // See FieldMarshaler for details.
3934 //=======================================================================
3935 VOID FieldMarshaler_Delegate::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
3942 PRECONDITION(CheckPointer(pNativeValue));
3943 PRECONDITION(CheckPointer(ppProtectedCLRValue));
3947 *ppProtectedCLRValue = COMDelegate::ConvertToDelegate((LPVOID)MAYBE_UNALIGNED_READ(pNativeValue, _PTR), GetMethodTable());
3951 //=======================================================================
3952 // SafeHandle <--> Handle
3953 // See FieldMarshaler for details.
3954 //=======================================================================
3955 VOID FieldMarshaler_SafeHandle::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
3962 PRECONDITION(CheckPointer(pNativeValue));
3963 PRECONDITION(CheckPointer(ppCleanupWorkListOnStack, NULL_OK));
3967 SAFEHANDLE *pSafeHandleObj = ((SAFEHANDLE *)pCLRValue);
3969 // A cleanup list MUST be specified in order for us to be able to marshal
3971 if (ppCleanupWorkListOnStack == NULL)
3972 COMPlusThrow(kInvalidOperationException, IDS_EE_SH_FIELD_INVALID_OPERATION);
3974 if (*pSafeHandleObj == NULL)
3975 COMPlusThrow(kArgumentNullException, W("ArgumentNull_SafeHandle"));
3977 // Call StubHelpers.AddToCleanupList to AddRef and schedule Release on this SafeHandle
3978 // This is realiable, i.e. the cleanup will happen if and only if the SH was actually AddRef'ed.
3979 MethodDescCallSite AddToCleanupList(METHOD__STUBHELPERS__ADD_TO_CLEANUP_LIST_SAFEHANDLE);
3983 (ARG_SLOT)ppCleanupWorkListOnStack,
3984 ObjToArgSlot(*pSafeHandleObj)
3987 LPVOID handle = AddToCleanupList.Call_RetLPVOID(args);
3989 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, handle);
3993 //=======================================================================
3994 // SafeHandle <--> Handle
3995 // See FieldMarshaler for details.
3996 //=======================================================================
3997 VOID FieldMarshaler_SafeHandle::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
4004 PRECONDITION(CheckPointer(pNativeValue));
4005 PRECONDITION(CheckPointer(ppProtectedCLRValue));
4006 PRECONDITION(CheckPointer(ppProtectedOldCLRValue));
4010 // Since we dissallow marshaling SafeHandle fields from unmanaged to managed, check
4011 // to see if this handle was obtained from a SafeHandle and if it was that the
4012 // handle value hasn't changed.
4013 SAFEHANDLE *pSafeHandleObj = (SAFEHANDLE *)ppProtectedOldCLRValue;
4014 if (!*pSafeHandleObj || (*pSafeHandleObj)->GetHandle() != (LPVOID)MAYBE_UNALIGNED_READ(pNativeValue, _PTR))
4015 COMPlusThrow(kNotSupportedException, IDS_EE_CANNOT_CREATE_SAFEHANDLE_FIELD);
4017 // Now that we know the handle hasn't changed we just copy set the new SafeHandle
4019 *ppProtectedCLRValue = *ppProtectedOldCLRValue;
4023 //=======================================================================
4024 // CriticalHandle <--> Handle
4025 // See FieldMarshaler for details.
4026 //=======================================================================
4027 VOID FieldMarshaler_CriticalHandle::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
4034 PRECONDITION(CheckPointer(pNativeValue));
4038 LPVOID handle = ((CRITICALHANDLE)*pCLRValue)->GetHandle();
4039 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, handle);
4043 //=======================================================================
4044 // CriticalHandle <--> Handle
4045 // See FieldMarshaler for details.
4046 //=======================================================================
4047 VOID FieldMarshaler_CriticalHandle::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
4054 PRECONDITION(CheckPointer(pNativeValue));
4055 PRECONDITION(CheckPointer(ppProtectedCLRValue));
4056 PRECONDITION(CheckPointer(ppProtectedOldCLRValue));
4060 // Since we dissallow marshaling CriticalHandle fields from unmanaged to managed, check
4061 // to see if this handle was obtained from a CriticalHandle and if it was that the
4062 // handle value hasn't changed.
4063 CRITICALHANDLE *pCriticalHandleObj = (CRITICALHANDLE *)ppProtectedOldCLRValue;
4064 if (!*pCriticalHandleObj || (*pCriticalHandleObj)->GetHandle() != (LPVOID)MAYBE_UNALIGNED_READ(pNativeValue, _PTR))
4065 COMPlusThrow(kNotSupportedException, IDS_EE_CANNOT_CREATE_CRITICALHANDLE_FIELD);
4067 // Now that we know the handle hasn't changed we just copy set the new CriticalHandle
4069 *ppProtectedCLRValue = *ppProtectedOldCLRValue;
4072 #ifdef FEATURE_COMINTEROP
4074 //=======================================================================
4075 // COM IP <--> interface
4076 // See FieldMarshaler for details.
4077 //=======================================================================
4078 VOID FieldMarshaler_Interface::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
4085 PRECONDITION(CheckPointer(pNativeValue));
4089 IUnknown *pUnk = NULL;
4091 if (!m_pItfMT.IsNull())
4093 pUnk = GetComIPFromObjectRef(pCLRValue, GetInterfaceMethodTable());
4095 else if (!(m_dwFlags & ItfMarshalInfo::ITF_MARSHAL_USE_BASIC_ITF))
4097 pUnk = GetComIPFromObjectRef(pCLRValue, GetMethodTable());
4101 ComIpType ReqIpType = !!(m_dwFlags & ItfMarshalInfo::ITF_MARSHAL_DISP_ITF) ? ComIpType_Dispatch : ComIpType_Unknown;
4102 pUnk = GetComIPFromObjectRef(pCLRValue, ReqIpType, NULL);
4105 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, pUnk);
4109 //=======================================================================
4110 // COM IP <--> interface
4111 // See FieldMarshaler for details.
4112 //=======================================================================
4113 VOID FieldMarshaler_Interface::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
4120 PRECONDITION(CheckPointer(pNativeValue));
4121 PRECONDITION(CheckPointer(ppProtectedCLRValue));
4122 PRECONDITION(IsProtectedByGCFrame(ppProtectedCLRValue));
4126 IUnknown *pUnk = (IUnknown*)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
4128 MethodTable *pItfMT = GetInterfaceMethodTable();
4129 if (pItfMT != NULL && !pItfMT->IsInterface())
4132 GetObjectRefFromComIP(
4133 ppProtectedCLRValue, // Created object
4134 pUnk, // Interface pointer
4135 GetMethodTable(), // Class MT
4136 pItfMT, // Interface MT
4137 (m_dwFlags & ItfMarshalInfo::ITF_MARSHAL_CLASS_IS_HINT) // Flags
4142 //=======================================================================
4143 // COM IP <--> interface
4144 // See FieldMarshaler for details.
4145 //=======================================================================
4146 VOID FieldMarshaler_Interface::DestroyNativeImpl(LPVOID pNativeValue) const
4153 PRECONDITION(CheckPointer(pNativeValue));
4157 IUnknown *pUnk = (IUnknown*)MAYBE_UNALIGNED_READ(pNativeValue, _PTR);
4158 MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL);
4162 ULONG cbRef = SafeRelease(pUnk);
4163 LogInteropRelease(pUnk, cbRef, "Field marshaler destroy native");
4167 #endif // FEATURE_COMINTEROP
4170 //=======================================================================
4171 // See FieldMarshaler for details.
4172 //=======================================================================
4173 VOID FieldMarshaler_Date::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const
4180 PRECONDITION(CheckPointer(pCLR));
4181 PRECONDITION(CheckPointer(pNative));
4185 // <TODO> Handle unaligned native fields </TODO>
4186 *((DATE*)pNative) = COMDateTime::TicksToDoubleDate(*((INT64*)pCLR));
4190 //=======================================================================
4191 // See FieldMarshaler for details.
4192 //=======================================================================
4193 VOID FieldMarshaler_Date::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const
4200 PRECONDITION(CheckPointer(pNative));
4201 PRECONDITION(CheckPointer(pCLR));
4205 // <TODO> Handle unaligned native fields </TODO>
4206 *((INT64*)pCLR) = COMDateTime::DoubleDateToTicks(*((DATE*)pNative));
4210 #ifdef FEATURE_COMINTEROP
4212 //=======================================================================
4213 // See FieldMarshaler for details.
4214 //=======================================================================
4215 VOID FieldMarshaler_Currency::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const
4222 PRECONDITION(CheckPointer(pCLR));
4223 PRECONDITION(CheckPointer(pNative));
4227 // no need to switch to preemptive mode because it's very primitive operaion, doesn't take
4228 // long and is guaranteed not to call 3rd party code.
4229 // But if we do need to switch to preemptive mode, we can't pass the managed pointer to native code directly
4230 HRESULT hr = VarCyFromDec( (DECIMAL *)pCLR, (CURRENCY*)pNative);
4237 //=======================================================================
4238 // See FieldMarshaler for details.
4239 //=======================================================================
4240 VOID FieldMarshaler_Currency::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const
4247 PRECONDITION(CheckPointer(pNative));
4248 PRECONDITION(CheckPointer(pCLR));
4252 // no need to switch to preemptive mode because it's very primitive operaion, doesn't take
4253 // long and is guaranteed not to call 3rd party code.
4254 // But if we do need to switch to preemptive mode, we can't pass the managed pointer to native code directly
4255 VarDecFromCyCanonicalize( *(CURRENCY*)pNative, (DECIMAL *)pCLR );
4258 VOID FieldMarshaler_DateTimeOffset::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const
4265 PRECONDITION(CheckPointer(pCLR));
4266 PRECONDITION(CheckPointer(pNative));
4270 MethodDescCallSite convertToNative(METHOD__DATETIMEOFFSETMARSHALER__CONVERT_TO_NATIVE);
4274 PtrToArgSlot(pNative)
4276 convertToNative.Call(args);
4279 VOID FieldMarshaler_DateTimeOffset::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const
4286 PRECONDITION(CheckPointer(pNative));
4287 PRECONDITION(CheckPointer(pCLR));
4291 MethodDescCallSite convertToManaged(METHOD__DATETIMEOFFSETMARSHALER__CONVERT_TO_MANAGED);
4295 PtrToArgSlot(pNative)
4297 convertToManaged.Call(args);
4300 #endif // FEATURE_COMINTEROP
4303 //=======================================================================
4304 // See FieldMarshaler for details.
4305 //=======================================================================
4306 VOID FieldMarshaler_Illegal::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const
4313 PRECONDITION(CheckPointer(pCLR));
4314 PRECONDITION(CheckPointer(pNative));
4318 DefineFullyQualifiedNameForClassW();
4320 StackSString ssFieldName(SString::Utf8, GetFieldDesc()->GetName());
4322 StackSString errorString(W("Unknown error."));
4323 errorString.LoadResource(CCompRC::Error, m_resIDWhy);
4325 COMPlusThrow(kTypeLoadException, IDS_EE_BADMARSHALFIELD_ERROR_MSG,
4326 GetFullyQualifiedNameForClassW(GetFieldDesc()->GetEnclosingMethodTable()),
4327 ssFieldName.GetUnicode(), errorString.GetUnicode());
4331 //=======================================================================
4332 // See FieldMarshaler for details.
4333 //=======================================================================
4334 VOID FieldMarshaler_Illegal::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const
4341 PRECONDITION(CheckPointer(pNative));
4342 PRECONDITION(CheckPointer(pCLR));
4346 DefineFullyQualifiedNameForClassW();
4348 StackSString ssFieldName(SString::Utf8, GetFieldDesc()->GetName());
4350 StackSString errorString(W("Unknown error."));
4351 errorString.LoadResource(CCompRC::Error,m_resIDWhy);
4353 COMPlusThrow(kTypeLoadException, IDS_EE_BADMARSHALFIELD_ERROR_MSG,
4354 GetFullyQualifiedNameForClassW(GetFieldDesc()->GetEnclosingMethodTable()),
4355 ssFieldName.GetUnicode(), errorString.GetUnicode());
4358 #ifdef FEATURE_COMINTEROP
4361 //=======================================================================
4362 // See FieldMarshaler for details.
4363 //=======================================================================
4364 VOID FieldMarshaler_Variant::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const
4371 PRECONDITION(CheckPointer(pNativeValue));
4375 OleVariant::MarshalOleVariantForObject(pCLRValue, (VARIANT*)pNativeValue);
4380 //=======================================================================
4381 // See FieldMarshaler for details.
4382 //=======================================================================
4383 VOID FieldMarshaler_Variant::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const
4390 PRECONDITION(CheckPointer(pNativeValue));
4391 PRECONDITION(CheckPointer(ppProtectedCLRValue));
4395 OleVariant::MarshalObjectForOleVariant((VARIANT*)pNativeValue, ppProtectedCLRValue);
4399 //=======================================================================
4400 // See FieldMarshaler for details.
4401 //=======================================================================
4402 VOID FieldMarshaler_Variant::DestroyNativeImpl(LPVOID pNativeValue) const
4409 PRECONDITION(CheckPointer(pNativeValue));
4413 SafeVariantClear( (VARIANT*)pNativeValue );
4416 #endif // FEATURE_COMINTEROP
4418 #endif // CROSSGEN_COMPILE
4422 // Implementation of the virtual functions using switch statements.
4424 // We are not able bake pointers to the FieldMarshaller vtables into NGen images. We store
4425 // the field marshaller id instead, and implement the virtualization by switch based on the id.
4428 #ifdef FEATURE_CLASSIC_COMINTEROP
4429 #define FieldMarshaler_SafeArray_Case(rettype, name, args) case NFT_SAFEARRAY: rettype ((FieldMarshaler_SafeArray*)this)->name##Impl args; break;
4431 #define FieldMarshaler_SafeArray_Case(rettype, name, args)
4434 #ifdef FEATURE_COMINTEROP
4436 #define IMPLEMENT_FieldMarshaler_METHOD(ret, name, argsdecl, rettype, args) \
4437 ret FieldMarshaler::name argsdecl { \
4438 WRAPPER_NO_CONTRACT; \
4439 switch (GetNStructFieldType()) { \
4440 case NFT_STRINGUNI: rettype ((FieldMarshaler_StringUni*)this)->name##Impl args; break; \
4441 case NFT_STRINGANSI: rettype ((FieldMarshaler_StringAnsi*)this)->name##Impl args; break; \
4442 case NFT_STRINGUTF8: rettype ((FieldMarshaler_StringUtf8*)this)->name##Impl args; break; \
4443 case NFT_FIXEDSTRINGUNI: rettype ((FieldMarshaler_FixedStringUni*)this)->name##Impl args; break; \
4444 case NFT_FIXEDSTRINGANSI: rettype ((FieldMarshaler_FixedStringAnsi*)this)->name##Impl args; break; \
4445 case NFT_FIXEDCHARARRAYANSI: rettype ((FieldMarshaler_FixedCharArrayAnsi*)this)->name##Impl args; break; \
4446 case NFT_FIXEDARRAY: rettype ((FieldMarshaler_FixedArray*)this)->name##Impl args; break; \
4447 case NFT_DELEGATE: rettype ((FieldMarshaler_Delegate*)this)->name##Impl args; break; \
4448 case NFT_COPY1: rettype ((FieldMarshaler_Copy1*)this)->name##Impl args; break; \
4449 case NFT_COPY2: rettype ((FieldMarshaler_Copy2*)this)->name##Impl args; break; \
4450 case NFT_COPY4: rettype ((FieldMarshaler_Copy4*)this)->name##Impl args; break; \
4451 case NFT_COPY8: rettype ((FieldMarshaler_Copy8*)this)->name##Impl args; break; \
4452 case NFT_ANSICHAR: rettype ((FieldMarshaler_Ansi*)this)->name##Impl args; break; \
4453 case NFT_WINBOOL: rettype ((FieldMarshaler_WinBool*)this)->name##Impl args; break; \
4454 case NFT_NESTEDLAYOUTCLASS: rettype ((FieldMarshaler_NestedLayoutClass*)this)->name##Impl args; break; \
4455 case NFT_NESTEDVALUECLASS: rettype ((FieldMarshaler_NestedValueClass*)this)->name##Impl args; break; \
4456 case NFT_CBOOL: rettype ((FieldMarshaler_CBool*)this)->name##Impl args; break; \
4457 case NFT_DATE: rettype ((FieldMarshaler_Date*)this)->name##Impl args; break; \
4458 case NFT_DECIMAL: rettype ((FieldMarshaler_Decimal*)this)->name##Impl args; break; \
4459 case NFT_INTERFACE: rettype ((FieldMarshaler_Interface*)this)->name##Impl args; break; \
4460 case NFT_SAFEHANDLE: rettype ((FieldMarshaler_SafeHandle*)this)->name##Impl args; break; \
4461 case NFT_CRITICALHANDLE: rettype ((FieldMarshaler_CriticalHandle*)this)->name##Impl args; break; \
4462 FieldMarshaler_SafeArray_Case(rettype, name, args) \
4463 case NFT_BSTR: rettype ((FieldMarshaler_BSTR*)this)->name##Impl args; break; \
4464 case NFT_HSTRING: rettype ((FieldMarshaler_HSTRING*)this)->name##Impl args; break; \
4465 case NFT_VARIANT: rettype ((FieldMarshaler_Variant*)this)->name##Impl args; break; \
4466 case NFT_VARIANTBOOL: rettype ((FieldMarshaler_VariantBool*)this)->name##Impl args; break; \
4467 case NFT_CURRENCY: rettype ((FieldMarshaler_Currency*)this)->name##Impl args; break; \
4468 case NFT_DATETIMEOFFSET: rettype ((FieldMarshaler_DateTimeOffset*)this)->name##Impl args; break; \
4469 case NFT_SYSTEMTYPE: rettype ((FieldMarshaler_SystemType *)this)->name##Impl args; break; \
4470 case NFT_WINDOWSFOUNDATIONHRESULT: rettype ((FieldMarshaler_Exception*)this)->name##Impl args; break; \
4471 case NFT_WINDOWSFOUNDATIONIREFERENCE: rettype ((FieldMarshaler_Nullable*)this)->name##Impl args; break; \
4472 case NFT_ILLEGAL: rettype ((FieldMarshaler_Illegal*)this)->name##Impl args; break; \
4473 default: UNREACHABLE_MSG("unexpected type of FieldMarshaler"); break; \
4477 #else // FEATURE_COMINTEROP
4479 #define IMPLEMENT_FieldMarshaler_METHOD(ret, name, argsdecl, rettype, args) \
4480 ret FieldMarshaler::name argsdecl { \
4481 WRAPPER_NO_CONTRACT; \
4482 switch (GetNStructFieldType()) { \
4483 case NFT_STRINGUNI: rettype ((FieldMarshaler_StringUni*)this)->name##Impl args; break; \
4484 case NFT_STRINGANSI: rettype ((FieldMarshaler_StringAnsi*)this)->name##Impl args; break; \
4485 case NFT_STRINGUTF8: rettype ((FieldMarshaler_StringUtf8*)this)->name##Impl args; break; \
4486 case NFT_FIXEDSTRINGUNI: rettype ((FieldMarshaler_FixedStringUni*)this)->name##Impl args; break; \
4487 case NFT_FIXEDSTRINGANSI: rettype ((FieldMarshaler_FixedStringAnsi*)this)->name##Impl args; break; \
4488 case NFT_FIXEDCHARARRAYANSI: rettype ((FieldMarshaler_FixedCharArrayAnsi*)this)->name##Impl args; break; \
4489 case NFT_FIXEDARRAY: rettype ((FieldMarshaler_FixedArray*)this)->name##Impl args; break; \
4490 case NFT_DELEGATE: rettype ((FieldMarshaler_Delegate*)this)->name##Impl args; break; \
4491 case NFT_COPY1: rettype ((FieldMarshaler_Copy1*)this)->name##Impl args; break; \
4492 case NFT_COPY2: rettype ((FieldMarshaler_Copy2*)this)->name##Impl args; break; \
4493 case NFT_COPY4: rettype ((FieldMarshaler_Copy4*)this)->name##Impl args; break; \
4494 case NFT_COPY8: rettype ((FieldMarshaler_Copy8*)this)->name##Impl args; break; \
4495 case NFT_ANSICHAR: rettype ((FieldMarshaler_Ansi*)this)->name##Impl args; break; \
4496 case NFT_WINBOOL: rettype ((FieldMarshaler_WinBool*)this)->name##Impl args; break; \
4497 case NFT_NESTEDLAYOUTCLASS: rettype ((FieldMarshaler_NestedLayoutClass*)this)->name##Impl args; break; \
4498 case NFT_NESTEDVALUECLASS: rettype ((FieldMarshaler_NestedValueClass*)this)->name##Impl args; break; \
4499 case NFT_CBOOL: rettype ((FieldMarshaler_CBool*)this)->name##Impl args; break; \
4500 case NFT_DATE: rettype ((FieldMarshaler_Date*)this)->name##Impl args; break; \
4501 case NFT_DECIMAL: rettype ((FieldMarshaler_Decimal*)this)->name##Impl args; break; \
4502 case NFT_SAFEHANDLE: rettype ((FieldMarshaler_SafeHandle*)this)->name##Impl args; break; \
4503 case NFT_CRITICALHANDLE: rettype ((FieldMarshaler_CriticalHandle*)this)->name##Impl args; break; \
4504 case NFT_BSTR: rettype ((FieldMarshaler_BSTR*)this)->name##Impl args; break; \
4505 case NFT_ILLEGAL: rettype ((FieldMarshaler_Illegal*)this)->name##Impl args; break; \
4506 default: UNREACHABLE_MSG("unexpected type of FieldMarshaler"); break; \
4510 #endif // FEATURE_COMINTEROP
4513 IMPLEMENT_FieldMarshaler_METHOD(UINT32, NativeSize,
4518 IMPLEMENT_FieldMarshaler_METHOD(UINT32, AlignmentRequirement,
4523 IMPLEMENT_FieldMarshaler_METHOD(BOOL, IsScalarMarshaler,
4528 IMPLEMENT_FieldMarshaler_METHOD(BOOL, IsNestedValueClassMarshaler,
4533 #ifndef CROSSGEN_COMPILE
4534 IMPLEMENT_FieldMarshaler_METHOD(VOID, UpdateNative,
4535 (OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const,
4537 (pCLRValue, pNativeValue, ppCleanupWorkListOnStack))
4539 IMPLEMENT_FieldMarshaler_METHOD(VOID, UpdateCLR,
4540 (const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const,
4542 (pNativeValue, ppProtectedCLRValue, ppProtectedOldCLRValue))
4544 IMPLEMENT_FieldMarshaler_METHOD(VOID, DestroyNative,
4545 (LPVOID pNativeValue) const,
4549 IMPLEMENT_FieldMarshaler_METHOD(VOID, ScalarUpdateNative,
4550 (LPVOID pCLR, LPVOID pNative) const,
4554 IMPLEMENT_FieldMarshaler_METHOD(VOID, ScalarUpdateCLR,
4555 (const VOID *pNative, LPVOID pCLR) const,
4559 IMPLEMENT_FieldMarshaler_METHOD(VOID, NestedValueClassUpdateNative,
4560 (const VOID **ppProtectedCLR, SIZE_T startoffset, LPVOID pNative, OBJECTREF *ppCleanupWorkListOnStack) const,
4562 (ppProtectedCLR, startoffset, pNative, ppCleanupWorkListOnStack))
4564 IMPLEMENT_FieldMarshaler_METHOD(VOID, NestedValueClassUpdateCLR,
4565 (const VOID *pNative, LPVOID *ppProtectedCLR, SIZE_T startoffset) const,
4567 (pNative, ppProtectedCLR, startoffset))
4568 #endif // CROSSGEN_COMPILE
4570 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
4571 IMPLEMENT_FieldMarshaler_METHOD(void, Save,
4576 IMPLEMENT_FieldMarshaler_METHOD(void, Fixup,
4580 #endif // FEATURE_NATIVE_IMAGE_GENERATION
4582 IMPLEMENT_FieldMarshaler_METHOD(void, Restore,
4587 #ifndef DACCESS_COMPILE
4588 IMPLEMENT_FieldMarshaler_METHOD(VOID, CopyTo,
4589 (VOID *pDest, SIZE_T destSize) const,
4592 #endif // !DACCESS_COMPILE