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. |
4 | // |
5 | // File: FieldMarshaler.cpp |
6 | // |
7 | |
8 | // |
9 | |
10 | |
11 | #include "common.h" |
12 | #include "vars.hpp" |
13 | #include "class.h" |
14 | #include "ceeload.h" |
15 | #include "excep.h" |
16 | #include "fieldmarshaler.h" |
17 | #include "field.h" |
18 | #include "frames.h" |
19 | #include "dllimport.h" |
20 | #include "comdelegate.h" |
21 | #include "eeconfig.h" |
22 | #include "comdatetime.h" |
23 | #include "olevariant.h" |
24 | #include <cor.h> |
25 | #include <corpriv.h> |
26 | #include <corerror.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 |
33 | |
34 | // forward declaration |
35 | BOOL CheckForPrimitiveType(CorElementType elemType, CQuickArray<WCHAR> *pStrPrimitiveType); |
36 | TypeHandle ArraySubTypeLoadWorker(const SString &strUserDefTypeName, Assembly* pAssembly); |
37 | TypeHandle GetFieldTypeHandleWorker(MetaSig *pFieldSig); |
38 | #ifdef _DEBUG |
39 | BOOL IsFixedBuffer(mdFieldDef field, IMDInternalImport *pInternalImport); |
40 | #endif |
41 | |
42 | |
43 | //======================================================================= |
44 | // A database of NFT types. |
45 | //======================================================================= |
46 | struct NFTDataBaseEntry |
47 | { |
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 |
50 | }; |
51 | |
52 | static const NFTDataBaseEntry NFTDataBase[] = |
53 | { |
54 | #undef DEFINE_NFT |
55 | #define DEFINE_NFT(name, nativesize, fWinRTSupported) { nativesize, fWinRTSupported }, |
56 | #include "nsenums.h" |
57 | }; |
58 | |
59 | |
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. |
63 | // |
64 | // Returns: |
65 | // TRUE - yes, there's layout metadata |
66 | // FALSE - no, there's no layout. |
67 | // fail - throws a typeload exception |
68 | // |
69 | // If TRUE, |
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) |
75 | { |
76 | CONTRACTL |
77 | { |
78 | THROWS; |
79 | GC_TRIGGERS; |
80 | MODE_ANY; |
81 | PRECONDITION(CheckPointer(pInternalImport)); |
82 | PRECONDITION(CheckPointer(pPackingSize)); |
83 | PRECONDITION(CheckPointer(pNLTType)); |
84 | PRECONDITION(CheckPointer(pfExplicitOffsets)); |
85 | } |
86 | CONTRACTL_END; |
87 | |
88 | HRESULT hr; |
89 | ULONG clFlags; |
90 | #ifdef _DEBUG |
91 | clFlags = 0xcccccccc; |
92 | #endif |
93 | |
94 | if (FAILED(pInternalImport->GetTypeDefProps(cl, &clFlags, NULL))) |
95 | { |
96 | pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT); |
97 | } |
98 | |
99 | if (IsTdAutoLayout(clFlags)) |
100 | { |
101 | // <BUGNUM>workaround for B#104780 - VC fails to set SequentialLayout on some classes |
102 | // with ClassSize. Too late to fix compiler for V1. |
103 | // |
104 | // To compensate, we treat AutoLayout classes as Sequential if they |
105 | // meet all of the following criteria: |
106 | // |
107 | // - ClassSize present and nonzero. |
108 | // - No instance fields declared |
109 | // - Base class is System.ValueType. |
110 | //</BUGNUM> |
111 | ULONG cbTotalSize = 0; |
112 | if (SUCCEEDED(pInternalImport->GetClassTotalSize(cl, &cbTotalSize)) && cbTotalSize != 0) |
113 | { |
114 | if (pParentMT && pParentMT->IsValueTypeClass()) |
115 | { |
116 | MDEnumHolder hEnumField(pInternalImport); |
117 | if (SUCCEEDED(pInternalImport->EnumInit(mdtFieldDef, cl, &hEnumField))) |
118 | { |
119 | ULONG numFields = pInternalImport->EnumGetCount(&hEnumField); |
120 | if (numFields == 0) |
121 | { |
122 | *pfExplicitOffsets = FALSE; |
123 | *pNLTType = nltAnsi; |
124 | *pPackingSize = 1; |
125 | return TRUE; |
126 | } |
127 | } |
128 | } |
129 | } |
130 | |
131 | return FALSE; |
132 | } |
133 | else if (IsTdSequentialLayout(clFlags)) |
134 | { |
135 | *pfExplicitOffsets = FALSE; |
136 | } |
137 | else if (IsTdExplicitLayout(clFlags)) |
138 | { |
139 | *pfExplicitOffsets = TRUE; |
140 | } |
141 | else |
142 | { |
143 | pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT); |
144 | } |
145 | |
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); |
149 | |
150 | if (IsTdAnsiClass(clFlags)) |
151 | { |
152 | *pNLTType = nltAnsi; |
153 | } |
154 | else if (IsTdUnicodeClass(clFlags)) |
155 | { |
156 | *pNLTType = nltUnicode; |
157 | } |
158 | else if (IsTdAutoClass(clFlags)) |
159 | { |
160 | // We no longer support Win9x so TdAuto always maps to Unicode. |
161 | *pNLTType = nltUnicode; |
162 | } |
163 | else |
164 | { |
165 | pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT); |
166 | } |
167 | |
168 | DWORD dwPackSize; |
169 | hr = pInternalImport->GetClassPackSize(cl, &dwPackSize); |
170 | if (FAILED(hr) || dwPackSize == 0) |
171 | dwPackSize = DEFAULT_PACKING_SIZE; |
172 | |
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))) |
177 | { |
178 | pAssembly->ThrowTypeLoadException(pInternalImport, cl, IDS_CLASSLOAD_BADFORMAT); |
179 | } |
180 | |
181 | *pPackingSize = (BYTE)dwPackSize; |
182 | |
183 | return TRUE; |
184 | } |
185 | |
186 | typedef enum |
187 | { |
188 | ParseNativeTypeFlag_None = 0x00, |
189 | ParseNativeTypeFlag_IsAnsi = 0x01, |
190 | |
191 | #ifdef FEATURE_COMINTEROP |
192 | ParseNativeTypeFlag_IsWinRT = 0x02, |
193 | #endif // FEATURE_COMINTEROP |
194 | } |
195 | ParseNativeTypeFlags; |
196 | |
197 | inline ParseNativeTypeFlags operator|=(ParseNativeTypeFlags& lhs, ParseNativeTypeFlags rhs) |
198 | { |
199 | LIMITED_METHOD_CONTRACT; |
200 | lhs = static_cast<ParseNativeTypeFlags>(lhs | rhs); |
201 | return lhs; |
202 | } |
203 | |
204 | #ifdef _PREFAST_ |
205 | #pragma warning(push) |
206 | #pragma warning(disable:21000) // Suppress PREFast warning about overly large function |
207 | #endif |
208 | VOID ParseNativeType(Module* pModule, |
209 | PCCOR_SIGNATURE pCOMSignature, |
210 | DWORD cbCOMSignature, |
211 | ParseNativeTypeFlags flags, |
212 | LayoutRawFieldInfo* pfwalk, |
213 | PCCOR_SIGNATURE pNativeType, |
214 | ULONG cbNativeType, |
215 | IMDInternalImport* pInternalImport, |
216 | mdTypeDef cl, |
217 | const SigTypeContext * pTypeContext, |
218 | BOOL *pfDisqualifyFromManagedSequential // set to TRUE if needed (never set to FALSE, it may come in as TRUE!) |
219 | #ifdef _DEBUG |
220 | , |
221 | LPCUTF8 szNamespace, |
222 | LPCUTF8 szClassName, |
223 | LPCUTF8 szFieldName |
224 | #endif |
225 | ) |
226 | { |
227 | CONTRACTL |
228 | { |
229 | STANDARD_VM_CHECK; |
230 | PRECONDITION(CheckPointer(pfwalk)); |
231 | } |
232 | CONTRACTL_END; |
233 | |
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); |
236 | |
237 | #define INITFIELDMARSHALER(nfttype, fmtype, args) \ |
238 | do \ |
239 | { \ |
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); \ |
244 | } while(0) |
245 | |
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; |
253 | CorNativeType ntype; |
254 | BOOL fDefault; |
255 | BOOL BestFit; |
256 | BOOL ThrowOnUnmappableChar; |
257 | |
258 | pfwalk->m_nft = NFT_NONE; |
259 | |
260 | if (cbNativeType == 0) |
261 | { |
262 | ntype = NATIVE_TYPE_DEFAULT; |
263 | fDefault = TRUE; |
264 | } |
265 | else |
266 | { |
267 | ntype = (CorNativeType) *( ((BYTE*&)pNativeType)++ ); |
268 | cbNativeType--; |
269 | fDefault = (ntype == NATIVE_TYPE_DEFAULT); |
270 | } |
271 | |
272 | #ifdef FEATURE_COMINTEROP |
273 | if (fIsWinRT && !fDefault) |
274 | { |
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)); |
277 | } |
278 | #endif // FEATURE_COMINTEROP |
279 | |
280 | // Setup the signature and normalize |
281 | MetaSig fsig(pCOMSignature, cbCOMSignature, pModule, pTypeContext, MetaSig::sigField); |
282 | corElemType = fsig.NextArgNormalized(); |
283 | |
284 | |
285 | if (!(*pfDisqualifyFromManagedSequential)) |
286 | { |
287 | // This type may qualify for ManagedSequential. Collect managed size and alignment info. |
288 | if (CorTypeInfo::IsPrimitiveType(corElemType)) |
289 | { |
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) |
292 | switch (corElemType) |
293 | { |
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: |
298 | { |
299 | pfwalk->m_managedAlignmentReq = 4; |
300 | break; |
301 | } |
302 | |
303 | default: |
304 | { |
305 | pfwalk->m_managedAlignmentReq = pfwalk->m_managedSize; |
306 | break; |
307 | } |
308 | } |
309 | #else // _TARGET_X86_ && UNIX_X86_ABI |
310 | pfwalk->m_managedAlignmentReq = pfwalk->m_managedSize; |
311 | #endif |
312 | } |
313 | else if (corElemType == ELEMENT_TYPE_PTR) |
314 | { |
315 | pfwalk->m_managedSize = TARGET_POINTER_SIZE; |
316 | pfwalk->m_managedAlignmentReq = TARGET_POINTER_SIZE; |
317 | } |
318 | else if (corElemType == ELEMENT_TYPE_VALUETYPE) |
319 | { |
320 | TypeHandle pNestedType = fsig.GetLastTypeHandleThrowing(ClassLoader::LoadTypes, |
321 | CLASS_LOAD_APPROXPARENTS, |
322 | TRUE); |
323 | if (pNestedType.GetMethodTable()->IsManagedSequential()) |
324 | { |
325 | pfwalk->m_managedSize = (pNestedType.GetMethodTable()->GetNumInstanceFieldBytes()); |
326 | |
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; |
329 | } |
330 | else |
331 | { |
332 | *pfDisqualifyFromManagedSequential = TRUE; |
333 | } |
334 | } |
335 | else |
336 | { |
337 | // No other type permitted for ManagedSequential. |
338 | *pfDisqualifyFromManagedSequential = TRUE; |
339 | } |
340 | } |
341 | |
342 | #ifdef _TARGET_X86_ |
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. |
346 | // |
347 | VerifyAndAdjustNormalizedType(pModule, fsig.GetArgProps(), fsig.GetSigTypeContext(), &corElemType, &ntype); |
348 | |
349 | fDefault = (ntype == NATIVE_TYPE_DEFAULT); |
350 | #endif // _TARGET_X86_ |
351 | |
352 | CorElementType sigElemType; |
353 | IfFailThrow(fsig.GetArgProps().PeekElemType(&sigElemType)); |
354 | if ((sigElemType == ELEMENT_TYPE_GENERICINST || sigElemType == ELEMENT_TYPE_VAR) && corElemType == ELEMENT_TYPE_CLASS) |
355 | { |
356 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_GENERICS_RESTRICTION)); |
357 | } |
358 | else switch (corElemType) |
359 | { |
360 | case ELEMENT_TYPE_CHAR: |
361 | if (fDefault) |
362 | { |
363 | if (fAnsi) |
364 | { |
365 | ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar); |
366 | INITFIELDMARSHALER(NFT_ANSICHAR, FieldMarshaler_Ansi, (BestFit, ThrowOnUnmappableChar)); |
367 | } |
368 | else |
369 | { |
370 | INITFIELDMARSHALER(NFT_COPY2, FieldMarshaler_Copy2, ()); |
371 | } |
372 | } |
373 | else if (ntype == NATIVE_TYPE_I1 || ntype == NATIVE_TYPE_U1) |
374 | { |
375 | ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar); |
376 | INITFIELDMARSHALER(NFT_ANSICHAR, FieldMarshaler_Ansi, (BestFit, ThrowOnUnmappableChar)); |
377 | } |
378 | else if (ntype == NATIVE_TYPE_I2 || ntype == NATIVE_TYPE_U2) |
379 | { |
380 | INITFIELDMARSHALER(NFT_COPY2, FieldMarshaler_Copy2, ()); |
381 | } |
382 | else |
383 | { |
384 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_CHAR)); |
385 | } |
386 | break; |
387 | |
388 | case ELEMENT_TYPE_BOOLEAN: |
389 | if (fDefault) |
390 | { |
391 | #ifdef FEATURE_COMINTEROP |
392 | if (fIsWinRT) |
393 | { |
394 | INITFIELDMARSHALER(NFT_CBOOL, FieldMarshaler_CBool, ()); |
395 | } |
396 | else |
397 | #endif // FEATURE_COMINTEROP |
398 | { |
399 | INITFIELDMARSHALER(NFT_WINBOOL, FieldMarshaler_WinBool, ()); |
400 | } |
401 | } |
402 | else if (ntype == NATIVE_TYPE_BOOLEAN) |
403 | { |
404 | INITFIELDMARSHALER(NFT_WINBOOL, FieldMarshaler_WinBool, ()); |
405 | } |
406 | #ifdef FEATURE_COMINTEROP |
407 | else if (ntype == NATIVE_TYPE_VARIANTBOOL) |
408 | { |
409 | INITFIELDMARSHALER(NFT_VARIANTBOOL, FieldMarshaler_VariantBool, ()); |
410 | } |
411 | #endif // FEATURE_COMINTEROP |
412 | else if (ntype == NATIVE_TYPE_U1 || ntype == NATIVE_TYPE_I1) |
413 | { |
414 | INITFIELDMARSHALER(NFT_CBOOL, FieldMarshaler_CBool, ()); |
415 | } |
416 | else |
417 | { |
418 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_BOOLEAN)); |
419 | } |
420 | break; |
421 | |
422 | |
423 | case ELEMENT_TYPE_I1: |
424 | if (fDefault || ntype == NATIVE_TYPE_I1 || ntype == NATIVE_TYPE_U1) |
425 | { |
426 | INITFIELDMARSHALER(NFT_COPY1, FieldMarshaler_Copy1, ()); |
427 | } |
428 | else |
429 | { |
430 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I1)); |
431 | } |
432 | break; |
433 | |
434 | case ELEMENT_TYPE_U1: |
435 | if (fDefault || ntype == NATIVE_TYPE_U1 || ntype == NATIVE_TYPE_I1) |
436 | { |
437 | INITFIELDMARSHALER(NFT_COPY1, FieldMarshaler_Copy1, ()); |
438 | } |
439 | else |
440 | { |
441 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I1)); |
442 | } |
443 | break; |
444 | |
445 | case ELEMENT_TYPE_I2: |
446 | if (fDefault || ntype == NATIVE_TYPE_I2 || ntype == NATIVE_TYPE_U2) |
447 | { |
448 | INITFIELDMARSHALER(NFT_COPY2, FieldMarshaler_Copy2, ()); |
449 | } |
450 | else |
451 | { |
452 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I2)); |
453 | } |
454 | break; |
455 | |
456 | case ELEMENT_TYPE_U2: |
457 | if (fDefault || ntype == NATIVE_TYPE_U2 || ntype == NATIVE_TYPE_I2) |
458 | { |
459 | INITFIELDMARSHALER(NFT_COPY2, FieldMarshaler_Copy2, ()); |
460 | } |
461 | else |
462 | { |
463 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I2)); |
464 | } |
465 | break; |
466 | |
467 | case ELEMENT_TYPE_I4: |
468 | if (fDefault || ntype == NATIVE_TYPE_I4 || ntype == NATIVE_TYPE_U4 || ntype == NATIVE_TYPE_ERROR) |
469 | { |
470 | INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ()); |
471 | } |
472 | else |
473 | { |
474 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I4)); |
475 | } |
476 | break; |
477 | |
478 | case ELEMENT_TYPE_U4: |
479 | if (fDefault || ntype == NATIVE_TYPE_U4 || ntype == NATIVE_TYPE_I4 || ntype == NATIVE_TYPE_ERROR) |
480 | { |
481 | INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ()); |
482 | } |
483 | else |
484 | { |
485 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I4)); |
486 | } |
487 | break; |
488 | |
489 | case ELEMENT_TYPE_I8: |
490 | if (fDefault || ntype == NATIVE_TYPE_I8 || ntype == NATIVE_TYPE_U8) |
491 | { |
492 | INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ()); |
493 | } |
494 | else |
495 | { |
496 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I8)); |
497 | } |
498 | break; |
499 | |
500 | case ELEMENT_TYPE_U8: |
501 | if (fDefault || ntype == NATIVE_TYPE_U8 || ntype == NATIVE_TYPE_I8) |
502 | { |
503 | INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ()); |
504 | } |
505 | else |
506 | { |
507 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I8)); |
508 | } |
509 | break; |
510 | |
511 | case ELEMENT_TYPE_I: //fallthru |
512 | case ELEMENT_TYPE_U: |
513 | #ifdef FEATURE_COMINTEROP |
514 | if (fIsWinRT) |
515 | { |
516 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE)); |
517 | } |
518 | else |
519 | #endif // FEATURE_COMINTEROP |
520 | if (fDefault || ntype == NATIVE_TYPE_INT || ntype == NATIVE_TYPE_UINT) |
521 | { |
522 | #ifdef _TARGET_64BIT_ |
523 | INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ()); |
524 | #else // !_TARGET_64BIT_ |
525 | INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ()); |
526 | #endif // !_TARGET_64BIT_ |
527 | } |
528 | else |
529 | { |
530 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_I)); |
531 | } |
532 | break; |
533 | |
534 | case ELEMENT_TYPE_R4: |
535 | if (fDefault || ntype == NATIVE_TYPE_R4) |
536 | { |
537 | INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ()); |
538 | } |
539 | else |
540 | { |
541 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_R4)); |
542 | } |
543 | break; |
544 | |
545 | case ELEMENT_TYPE_R8: |
546 | if (fDefault || ntype == NATIVE_TYPE_R8) |
547 | { |
548 | INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ()); |
549 | } |
550 | else |
551 | { |
552 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_R8)); |
553 | } |
554 | break; |
555 | |
556 | case ELEMENT_TYPE_PTR: |
557 | #ifdef FEATURE_COMINTEROP |
558 | if (fIsWinRT) |
559 | { |
560 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE)); |
561 | } |
562 | else |
563 | #endif // FEATURE_COMINTEROP |
564 | if (fDefault) |
565 | { |
566 | #ifdef _TARGET_64BIT_ |
567 | INITFIELDMARSHALER(NFT_COPY8, FieldMarshaler_Copy8, ()); |
568 | #else // !_TARGET_64BIT_ |
569 | INITFIELDMARSHALER(NFT_COPY4, FieldMarshaler_Copy4, ()); |
570 | #endif // !_TARGET_64BIT_ |
571 | } |
572 | else |
573 | { |
574 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_PTR)); |
575 | } |
576 | break; |
577 | |
578 | case ELEMENT_TYPE_VALUETYPE: |
579 | { |
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()) |
585 | break; |
586 | #ifdef FEATURE_COMINTEROP |
587 | if (fIsWinRT && sigElemType == ELEMENT_TYPE_GENERICINST) |
588 | { |
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)) |
592 | { |
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. |
597 | // 2. It is string |
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()) |
602 | { |
603 | // Type is not a valid WinRT value type. |
604 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_NULLABLE_RESTRICTION)); |
605 | } |
606 | else |
607 | { |
608 | INITFIELDMARSHALER(NFT_WINDOWSFOUNDATIONIREFERENCE, FieldMarshaler_Nullable, (genType.GetMethodTable())); |
609 | } |
610 | break; |
611 | } |
612 | } |
613 | #endif |
614 | if (fsig.IsClass(g_DateClassName)) |
615 | { |
616 | if (fDefault || ntype == NATIVE_TYPE_STRUCT) |
617 | { |
618 | INITFIELDMARSHALER(NFT_DATE, FieldMarshaler_Date, ()); |
619 | } |
620 | else |
621 | { |
622 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_DATETIME)); |
623 | } |
624 | } |
625 | else if (fsig.IsClass(g_DecimalClassName)) |
626 | { |
627 | if (fDefault || ntype == NATIVE_TYPE_STRUCT) |
628 | { |
629 | INITFIELDMARSHALER(NFT_DECIMAL, FieldMarshaler_Decimal, ()); |
630 | } |
631 | #ifdef FEATURE_COMINTEROP |
632 | else if (ntype == NATIVE_TYPE_CURRENCY) |
633 | { |
634 | INITFIELDMARSHALER(NFT_CURRENCY, FieldMarshaler_Currency, ()); |
635 | } |
636 | #endif // FEATURE_COMINTEROP |
637 | else |
638 | { |
639 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_DECIMAL)); |
640 | } |
641 | } |
642 | #ifdef FEATURE_COMINTEROP |
643 | else if (fsig.IsClass(g_DateTimeOffsetClassName)) |
644 | { |
645 | if (fDefault || ntype == NATIVE_TYPE_STRUCT) |
646 | { |
647 | INITFIELDMARSHALER(NFT_DATETIMEOFFSET, FieldMarshaler_DateTimeOffset, ()); |
648 | } |
649 | else |
650 | { |
651 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_DATETIMEOFFSET)); |
652 | } |
653 | } |
654 | else if (fIsWinRT && !thNestedType.GetMethodTable()->IsLegalNonArrayWinRTType()) |
655 | { |
656 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE)); |
657 | } |
658 | #endif // FEATURE_COMINTEROP |
659 | else if (thNestedType.GetMethodTable()->HasLayout()) |
660 | { |
661 | if (fDefault || ntype == NATIVE_TYPE_STRUCT) |
662 | { |
663 | if (IsStructMarshalable(thNestedType)) |
664 | { |
665 | #ifdef _DEBUG |
666 | INITFIELDMARSHALER(NFT_NESTEDVALUECLASS, FieldMarshaler_NestedValueClass, (thNestedType.GetMethodTable(), IsFixedBuffer(pfwalk->m_MD, pInternalImport))); |
667 | #else |
668 | INITFIELDMARSHALER(NFT_NESTEDVALUECLASS, FieldMarshaler_NestedValueClass, (thNestedType.GetMethodTable())); |
669 | #endif |
670 | } |
671 | else |
672 | { |
673 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_NOTMARSHALABLE)); |
674 | } |
675 | } |
676 | else |
677 | { |
678 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_VALUETYPE)); |
679 | } |
680 | } |
681 | else |
682 | { |
683 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_NOTMARSHALABLE)); |
684 | } |
685 | break; |
686 | } |
687 | |
688 | case ELEMENT_TYPE_CLASS: |
689 | { |
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()) |
695 | break; |
696 | |
697 | if (thNestedType.GetMethodTable()->IsObjectClass()) |
698 | { |
699 | #ifdef FEATURE_COMINTEROP |
700 | if (fDefault || ntype == NATIVE_TYPE_IUNKNOWN || ntype == NATIVE_TYPE_IDISPATCH || ntype == NATIVE_TYPE_INTF) |
701 | { |
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) |
705 | { |
706 | dwFlags |= ItfMarshalInfo::ITF_MARSHAL_DISP_ITF; |
707 | } |
708 | INITFIELDMARSHALER(NFT_INTERFACE, FieldMarshaler_Interface, (NULL, NULL, dwFlags)); |
709 | } |
710 | else if (ntype == NATIVE_TYPE_STRUCT) |
711 | { |
712 | INITFIELDMARSHALER(NFT_VARIANT, FieldMarshaler_Variant, ()); |
713 | } |
714 | #else // FEATURE_COMINTEROP |
715 | if (fDefault || ntype == NATIVE_TYPE_IUNKNOWN || ntype == NATIVE_TYPE_IDISPATCH || ntype == NATIVE_TYPE_INTF) |
716 | { |
717 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_OBJECT_TO_ITF_NOT_SUPPORTED)); |
718 | } |
719 | else if (ntype == NATIVE_TYPE_STRUCT) |
720 | { |
721 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_OBJECT_TO_VARIANT_NOT_SUPPORTED)); |
722 | } |
723 | #endif // FEATURE_COMINTEROP |
724 | else |
725 | { |
726 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_OBJECT)); |
727 | } |
728 | } |
729 | #ifdef FEATURE_COMINTEROP |
730 | else if (ntype == NATIVE_TYPE_INTF || thNestedType.IsInterface()) |
731 | { |
732 | if (fIsWinRT && !thNestedType.GetMethodTable()->IsLegalNonArrayWinRTType()) |
733 | { |
734 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE)); |
735 | } |
736 | else |
737 | { |
738 | ItfMarshalInfo itfInfo; |
739 | if (FAILED(MarshalInfo::TryGetItfMarshalInfo(thNestedType, FALSE, FALSE, &itfInfo))) |
740 | break; |
741 | |
742 | INITFIELDMARSHALER(NFT_INTERFACE, FieldMarshaler_Interface, (itfInfo.thClass.GetMethodTable(), itfInfo.thItf.GetMethodTable(), itfInfo.dwFlags)); |
743 | } |
744 | } |
745 | #else // FEATURE_COMINTEROP |
746 | else if (ntype == NATIVE_TYPE_INTF || thNestedType.IsInterface()) |
747 | { |
748 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_OBJECT_TO_ITF_NOT_SUPPORTED)); |
749 | } |
750 | #endif // FEATURE_COMINTEROP |
751 | else if (ntype == NATIVE_TYPE_CUSTOMMARSHALER) |
752 | { |
753 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_NOCUSTOMMARSH)); |
754 | } |
755 | else if (thNestedType == TypeHandle(g_pStringClass)) |
756 | { |
757 | if (fDefault) |
758 | { |
759 | #ifdef FEATURE_COMINTEROP |
760 | if (fIsWinRT) |
761 | { |
762 | INITFIELDMARSHALER(NFT_HSTRING, FieldMarshaler_HSTRING, ()); |
763 | } |
764 | else |
765 | #endif // FEATURE_COMINTEROP |
766 | if (fAnsi) |
767 | { |
768 | ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar); |
769 | INITFIELDMARSHALER(NFT_STRINGANSI, FieldMarshaler_StringAnsi, (BestFit, ThrowOnUnmappableChar)); |
770 | } |
771 | else |
772 | { |
773 | INITFIELDMARSHALER(NFT_STRINGUNI, FieldMarshaler_StringUni, ()); |
774 | } |
775 | } |
776 | else |
777 | { |
778 | switch (ntype) |
779 | { |
780 | case NATIVE_TYPE_LPSTR: |
781 | ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar); |
782 | INITFIELDMARSHALER(NFT_STRINGANSI, FieldMarshaler_StringAnsi, (BestFit, ThrowOnUnmappableChar)); |
783 | break; |
784 | |
785 | case NATIVE_TYPE_LPWSTR: |
786 | INITFIELDMARSHALER(NFT_STRINGUNI, FieldMarshaler_StringUni, ()); |
787 | break; |
788 | |
789 | case NATIVE_TYPE_LPUTF8STR: |
790 | INITFIELDMARSHALER(NFT_STRINGUTF8, FieldMarshaler_StringUtf8, ()); |
791 | break; |
792 | |
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, ()); |
796 | break; |
797 | |
798 | case NATIVE_TYPE_BSTR: |
799 | INITFIELDMARSHALER(NFT_BSTR, FieldMarshaler_BSTR, ()); |
800 | break; |
801 | |
802 | #ifdef FEATURE_COMINTEROP |
803 | case NATIVE_TYPE_HSTRING: |
804 | INITFIELDMARSHALER(NFT_HSTRING, FieldMarshaler_HSTRING, ()); |
805 | break; |
806 | #endif // FEATURE_COMINTEROP |
807 | case NATIVE_TYPE_FIXEDSYSSTRING: |
808 | { |
809 | ULONG nchars; |
810 | ULONG udatasize = CorSigUncompressedDataSize(pNativeType); |
811 | |
812 | if (cbNativeType < udatasize) |
813 | break; |
814 | |
815 | nchars = CorSigUncompressData(pNativeType); |
816 | cbNativeType -= udatasize; |
817 | |
818 | if (nchars == 0) |
819 | { |
820 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_ZEROLENGTHFIXEDSTRING)); |
821 | break; |
822 | } |
823 | |
824 | if (fAnsi) |
825 | { |
826 | ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar); |
827 | INITFIELDMARSHALER(NFT_FIXEDSTRINGANSI, FieldMarshaler_FixedStringAnsi, (nchars, BestFit, ThrowOnUnmappableChar)); |
828 | } |
829 | else |
830 | { |
831 | INITFIELDMARSHALER(NFT_FIXEDSTRINGUNI, FieldMarshaler_FixedStringUni, (nchars)); |
832 | } |
833 | } |
834 | break; |
835 | |
836 | default: |
837 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_STRING)); |
838 | break; |
839 | } |
840 | } |
841 | } |
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, ()); |
846 | } |
847 | else if (fIsWinRT && fsig.IsClass(g_ExceptionClassName)) // Marshal Windows.Foundation.HResult as System.Exception for WinRT. |
848 | { |
849 | INITFIELDMARSHALER(NFT_WINDOWSFOUNDATIONHRESULT, FieldMarshaler_Exception, ()); |
850 | } |
851 | #endif //FEATURE_COMINTEROP |
852 | #ifdef FEATURE_CLASSIC_COMINTEROP |
853 | else if (thNestedType.GetMethodTable() == g_pArrayClass) |
854 | { |
855 | if (ntype == NATIVE_TYPE_SAFEARRAY) |
856 | { |
857 | NativeTypeParamInfo ParamInfo; |
858 | CorElementType etyp = ELEMENT_TYPE_OBJECT; |
859 | MethodTable* pMT = NULL; |
860 | VARTYPE vtElement = VT_EMPTY; |
861 | |
862 | // Compat: If no safe array used def subtype was specified, we assume TypeOf(Object). |
863 | TypeHandle thElement = TypeHandle(g_pObjectClass); |
864 | |
865 | // If we have no native type data, assume default behavior |
866 | if (S_OK != CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart)) |
867 | { |
868 | INITFIELDMARSHALER(NFT_SAFEARRAY, FieldMarshaler_SafeArray, (VT_EMPTY, NULL)); |
869 | break; |
870 | } |
871 | |
872 | vtElement = (VARTYPE) (CorSigUncompressData(/*modifies*/pNativeType)); |
873 | |
874 | // Extract the name of the record type's. |
875 | if (S_OK == CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart)) |
876 | { |
877 | ULONG strLen; |
878 | if (FAILED(CPackedLen::SafeGetData(pNativeType, pNativeTypeStart + cbNativeTypeStart, &strLen, &pNativeType))) |
879 | { |
880 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_BADMETADATA)); |
881 | break; |
882 | } |
883 | if (strLen > 0) |
884 | { |
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); |
889 | |
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()) |
895 | break; |
896 | } |
897 | } |
898 | |
899 | ArrayMarshalInfo arrayMarshalInfo(amiRuntime); |
900 | arrayMarshalInfo.InitForSafeArray(MarshalInfo::MARSHAL_SCENARIO_FIELD, thElement, vtElement, fAnsi); |
901 | |
902 | if (!arrayMarshalInfo.IsValid()) |
903 | { |
904 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (arrayMarshalInfo.GetErrorResourceId())); |
905 | break; |
906 | } |
907 | |
908 | INITFIELDMARSHALER(NFT_SAFEARRAY, FieldMarshaler_SafeArray, (arrayMarshalInfo.GetElementVT(), arrayMarshalInfo.GetElementTypeHandle().GetMethodTable())); |
909 | } |
910 | else if (ntype == NATIVE_TYPE_FIXEDARRAY) |
911 | { |
912 | // Check for the number of elements. This is required, if not present fail. |
913 | if (S_OK != CheckForCompressedData(pNativeTypeStart, pNativeType, cbNativeTypeStart)) |
914 | { |
915 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_FIXEDARRAY_NOSIZE)); |
916 | break; |
917 | } |
918 | |
919 | ULONG numElements = CorSigUncompressData(/*modifies*/pNativeType); |
920 | |
921 | if (numElements == 0) |
922 | { |
923 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_FIXEDARRAY_ZEROSIZE)); |
924 | break; |
925 | } |
926 | |
927 | // Since these always export to arrays of BSTRs, we don't need to fetch the native type. |
928 | |
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)); |
931 | } |
932 | } |
933 | #endif // FEATURE_CLASSIC_COMINTEROP |
934 | else if (COMDelegate::IsDelegate(thNestedType.GetMethodTable())) |
935 | { |
936 | if (fDefault || ntype == NATIVE_TYPE_FUNC) |
937 | { |
938 | INITFIELDMARSHALER(NFT_DELEGATE, FieldMarshaler_Delegate, (thNestedType.GetMethodTable())); |
939 | } |
940 | else |
941 | { |
942 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_DELEGATE)); |
943 | } |
944 | } |
945 | else if (thNestedType.CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__SAFE_HANDLE)))) |
946 | { |
947 | if (fDefault) |
948 | { |
949 | INITFIELDMARSHALER(NFT_SAFEHANDLE, FieldMarshaler_SafeHandle, ()); |
950 | } |
951 | else |
952 | { |
953 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_SAFEHANDLE)); |
954 | } |
955 | } |
956 | else if (thNestedType.CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__CRITICAL_HANDLE)))) |
957 | { |
958 | if (fDefault) |
959 | { |
960 | INITFIELDMARSHALER(NFT_CRITICALHANDLE, FieldMarshaler_CriticalHandle, ()); |
961 | } |
962 | else |
963 | { |
964 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_CRITICALHANDLE)); |
965 | } |
966 | } |
967 | else if (fsig.IsClass(g_StringBufferClassName)) |
968 | { |
969 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_NOSTRINGBUILDER)); |
970 | } |
971 | else if (IsStructMarshalable(thNestedType)) |
972 | { |
973 | if (fDefault || ntype == NATIVE_TYPE_STRUCT) |
974 | { |
975 | INITFIELDMARSHALER(NFT_NESTEDLAYOUTCLASS, FieldMarshaler_NestedLayoutClass, (thNestedType.GetMethodTable())); |
976 | } |
977 | else |
978 | { |
979 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_LAYOUTCLASS)); |
980 | } |
981 | } |
982 | #ifdef FEATURE_COMINTEROP |
983 | else if (fIsWinRT) |
984 | { |
985 | // no other reference types are allowed as field types in WinRT |
986 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE)); |
987 | } |
988 | else if (fDefault) |
989 | { |
990 | ItfMarshalInfo itfInfo; |
991 | if (FAILED(MarshalInfo::TryGetItfMarshalInfo(thNestedType, FALSE, FALSE, &itfInfo))) |
992 | { |
993 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_BADMANAGED)); |
994 | } |
995 | else |
996 | { |
997 | INITFIELDMARSHALER(NFT_INTERFACE, FieldMarshaler_Interface, (itfInfo.thClass.GetMethodTable(), itfInfo.thItf.GetMethodTable(), itfInfo.dwFlags)); |
998 | } |
999 | } |
1000 | #endif // FEATURE_COMINTEROP |
1001 | break; |
1002 | } |
1003 | |
1004 | case ELEMENT_TYPE_SZARRAY: |
1005 | case ELEMENT_TYPE_ARRAY: |
1006 | { |
1007 | #ifdef FEATURE_COMINTEROP |
1008 | if (fIsWinRT) |
1009 | { |
1010 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE)); |
1011 | break; |
1012 | } |
1013 | #endif // FEATURE_COMINTEROP |
1014 | |
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()) |
1020 | break; |
1021 | |
1022 | TypeHandle thElement = thArray.AsArray()->GetArrayElementTypeHandle(); |
1023 | if (thElement.IsNull()) |
1024 | break; |
1025 | |
1026 | if (ntype == NATIVE_TYPE_FIXEDARRAY) |
1027 | { |
1028 | CorNativeType elementNativeType = NATIVE_TYPE_DEFAULT; |
1029 | |
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)) |
1032 | { |
1033 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_FIXEDARRAY_NOSIZE)); |
1034 | break; |
1035 | } |
1036 | |
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) |
1040 | { |
1041 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_FIXEDARRAY_ZEROSIZE)); |
1042 | break; |
1043 | } |
1044 | |
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); |
1048 | |
1049 | ArrayMarshalInfo arrayMarshalInfo(amiRuntime); |
1050 | arrayMarshalInfo.InitForFixedArray(thElement, elementNativeType, fAnsi); |
1051 | |
1052 | if (!arrayMarshalInfo.IsValid()) |
1053 | { |
1054 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (arrayMarshalInfo.GetErrorResourceId())); |
1055 | break; |
1056 | } |
1057 | |
1058 | if (arrayMarshalInfo.GetElementVT() == VTHACK_ANSICHAR) |
1059 | { |
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 |
1062 | // properly. |
1063 | ReadBestFitCustomAttribute(pInternalImport, cl, &BestFit, &ThrowOnUnmappableChar); |
1064 | INITFIELDMARSHALER(NFT_FIXEDCHARARRAYANSI, FieldMarshaler_FixedCharArrayAnsi, (numElements, BestFit, ThrowOnUnmappableChar)); |
1065 | break; |
1066 | } |
1067 | else |
1068 | { |
1069 | VARTYPE elementVT = arrayMarshalInfo.GetElementVT(); |
1070 | |
1071 | INITFIELDMARSHALER(NFT_FIXEDARRAY, FieldMarshaler_FixedArray, (pInternalImport, cl, numElements, elementVT, arrayMarshalInfo.GetElementTypeHandle().GetMethodTable())); |
1072 | break; |
1073 | } |
1074 | } |
1075 | #ifdef FEATURE_CLASSIC_COMINTEROP |
1076 | else if (fDefault || ntype == NATIVE_TYPE_SAFEARRAY) |
1077 | { |
1078 | VARTYPE vtElement = VT_EMPTY; |
1079 | |
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)); |
1083 | |
1084 | ArrayMarshalInfo arrayMarshalInfo(amiRuntime); |
1085 | arrayMarshalInfo.InitForSafeArray(MarshalInfo::MARSHAL_SCENARIO_FIELD, thElement, vtElement, fAnsi); |
1086 | |
1087 | if (!arrayMarshalInfo.IsValid()) |
1088 | { |
1089 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (arrayMarshalInfo.GetErrorResourceId())); |
1090 | break; |
1091 | } |
1092 | |
1093 | INITFIELDMARSHALER(NFT_SAFEARRAY, FieldMarshaler_SafeArray, (arrayMarshalInfo.GetElementVT(), arrayMarshalInfo.GetElementTypeHandle().GetMethodTable())); |
1094 | } |
1095 | #endif //FEATURE_CLASSIC_COMINTEROP |
1096 | else |
1097 | { |
1098 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHALFIELD_ARRAY)); |
1099 | } |
1100 | break; |
1101 | } |
1102 | |
1103 | case ELEMENT_TYPE_OBJECT: |
1104 | case ELEMENT_TYPE_STRING: |
1105 | break; |
1106 | |
1107 | default: |
1108 | // let it fall thru as NFT_NONE |
1109 | break; |
1110 | } |
1111 | |
1112 | if (pfwalk->m_nft == NFT_NONE) |
1113 | { |
1114 | INITFIELDMARSHALER(NFT_ILLEGAL, FieldMarshaler_Illegal, (IDS_EE_BADMARSHAL_BADMANAGED)); |
1115 | } |
1116 | #ifdef FEATURE_COMINTEROP |
1117 | else if (fIsWinRT && !NFTDataBase[pfwalk->m_nft].m_fWinRTSupported) |
1118 | { |
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)); |
1122 | } |
1123 | #endif // FEATURE_COMINTEROP |
1124 | #undef INITFIELDMARSHALER |
1125 | } |
1126 | #ifdef _PREFAST_ |
1127 | #pragma warning(pop) |
1128 | #endif |
1129 | |
1130 | |
1131 | TypeHandle ArraySubTypeLoadWorker(const SString &strUserDefTypeName, Assembly* pAssembly) |
1132 | { |
1133 | CONTRACTL |
1134 | { |
1135 | THROWS; |
1136 | GC_TRIGGERS; |
1137 | MODE_ANY; |
1138 | PRECONDITION(CheckPointer(pAssembly)); |
1139 | } |
1140 | CONTRACTL_END; |
1141 | |
1142 | TypeHandle th; |
1143 | |
1144 | EX_TRY |
1145 | { |
1146 | // Load the user defined type. |
1147 | StackScratchBuffer utf8Name; |
1148 | th = TypeName::GetTypeUsingCASearchRules(strUserDefTypeName.GetUTF8(utf8Name), pAssembly); |
1149 | } |
1150 | EX_CATCH |
1151 | { |
1152 | } |
1153 | EX_END_CATCH(RethrowTerminalExceptions) |
1154 | |
1155 | return th; |
1156 | } |
1157 | |
1158 | |
1159 | TypeHandle GetFieldTypeHandleWorker(MetaSig *pFieldSig) |
1160 | { |
1161 | CONTRACTL |
1162 | { |
1163 | THROWS; |
1164 | GC_TRIGGERS; |
1165 | MODE_ANY; |
1166 | PRECONDITION(CheckPointer(pFieldSig)); |
1167 | } |
1168 | CONTRACTL_END; |
1169 | |
1170 | TypeHandle th; |
1171 | |
1172 | EX_TRY |
1173 | { |
1174 | // Load the user defined type. |
1175 | th = pFieldSig->GetLastTypeHandleThrowing(ClassLoader::LoadTypes, |
1176 | CLASS_LOAD_APPROXPARENTS, |
1177 | TRUE /*dropGenericArgumentLevel*/); |
1178 | } |
1179 | EX_CATCH |
1180 | { |
1181 | } |
1182 | EX_END_CATCH(RethrowTerminalExceptions) |
1183 | |
1184 | return th; |
1185 | } |
1186 | |
1187 | |
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) |
1193 | { |
1194 | CONTRACTL |
1195 | { |
1196 | NOTHROW; |
1197 | GC_NOTRIGGER; |
1198 | MODE_ANY; |
1199 | SO_TOLERANT; |
1200 | PRECONDITION(!th.IsNull()); |
1201 | } |
1202 | CONTRACTL_END; |
1203 | |
1204 | if (th.IsBlittable()) |
1205 | { |
1206 | // th.IsBlittable will return true for arrays of blittable types, however since IsStructMarshalable |
1207 | // is only supposed to return true for value classes or classes with layout that are marshallable |
1208 | // we need to return false if the type is an array. |
1209 | if (th.IsArray()) |
1210 | return FALSE; |
1211 | else |
1212 | return TRUE; |
1213 | } |
1214 | |
1215 | // Check to see if the type has layout. |
1216 | if (!th.HasLayout()) |
1217 | return FALSE; |
1218 | |
1219 | MethodTable *pMT= th.GetMethodTable(); |
1220 | PREFIX_ASSUME(pMT != NULL); |
1221 | |
1222 | if (pMT->IsStructMarshalable()) |
1223 | return TRUE; |
1224 | |
1225 | const FieldMarshaler *pFieldMarshaler = pMT->GetLayoutInfo()->GetFieldMarshalers(); |
1226 | UINT numReferenceFields = pMT->GetLayoutInfo()->GetNumCTMFields(); |
1227 | |
1228 | while (numReferenceFields--) |
1229 | { |
1230 | if (pFieldMarshaler->GetNStructFieldType() == NFT_ILLEGAL) |
1231 | return FALSE; |
1232 | |
1233 | ((BYTE*&)pFieldMarshaler) += MAXFIELDMARSHALERSIZE; |
1234 | } |
1235 | |
1236 | return TRUE; |
1237 | } |
1238 | |
1239 | #ifdef _DEBUG |
1240 | BOOL IsFixedBuffer(mdFieldDef field, IMDInternalImport *pInternalImport) |
1241 | { |
1242 | HRESULT hr = pInternalImport->GetCustomAttributeByName(field, g_FixedBufferAttribute, NULL, NULL); |
1243 | |
1244 | return hr == S_OK ? TRUE : FALSE; |
1245 | } |
1246 | #endif |
1247 | |
1248 | |
1249 | //======================================================================= |
1250 | // Called from the clsloader to load up and summarize the field metadata |
1251 | // for layout classes. |
1252 | // |
1253 | // Warning: This function can load other classes (esp. for nested structs.) |
1254 | //======================================================================= |
1255 | #ifdef _PREFAST_ |
1256 | #pragma warning(push) |
1257 | #pragma warning(disable:21000) // Suppress PREFast warning about overly large function |
1258 | #endif |
1259 | VOID EEClassLayoutInfo::CollectLayoutFieldMetadataThrowing( |
1260 | mdTypeDef cl, // cl of the NStruct being loaded |
1261 | BYTE packingSize, // packing size (from @dll.struct) |
1262 | BYTE nlType, // nltype (from @dll.struct) |
1263 | #ifdef FEATURE_COMINTEROP |
1264 | BOOL isWinRT, // Is the type a WinRT type |
1265 | #endif // FEATURE_COMINTEROP |
1266 | BOOL fExplicitOffsets, // explicit offsets? |
1267 | MethodTable *pParentMT, // the loaded superclass |
1268 | ULONG cMembers, // total number of members (methods + fields) |
1269 | HENUMInternal *phEnumField, // enumerator for field |
1270 | Module *pModule, // Module that defines the scope, loader and heap (for allocate FieldMarshalers) |
1271 | const SigTypeContext *pTypeContext, // Type parameters for NStruct being loaded |
1272 | EEClassLayoutInfo *pEEClassLayoutInfoOut, // caller-allocated structure to fill in. |
1273 | LayoutRawFieldInfo *pInfoArrayOut, // caller-allocated array to fill in. Needs room for cMember+1 elements |
1274 | LoaderAllocator *pAllocator, |
1275 | AllocMemTracker *pamTracker |
1276 | ) |
1277 | { |
1278 | CONTRACTL |
1279 | { |
1280 | THROWS; |
1281 | GC_TRIGGERS; |
1282 | MODE_ANY; |
1283 | INJECT_FAULT(COMPlusThrowOM()); |
1284 | PRECONDITION(CheckPointer(pModule)); |
1285 | } |
1286 | CONTRACTL_END; |
1287 | |
1288 | HRESULT hr; |
1289 | MD_CLASS_LAYOUT classlayout; |
1290 | mdFieldDef fd; |
1291 | ULONG ulOffset; |
1292 | ULONG cFields = 0; |
1293 | |
1294 | // Running tote - if anything in this type disqualifies it from being ManagedSequential, somebody will set this to TRUE by the the time |
1295 | // function exits. |
1296 | BOOL fDisqualifyFromManagedSequential = FALSE; |
1297 | |
1298 | // Internal interface for the NStruct being loaded. |
1299 | IMDInternalImport *pInternalImport = pModule->GetMDImport(); |
1300 | |
1301 | |
1302 | #ifdef _DEBUG |
1303 | LPCUTF8 szName; |
1304 | LPCUTF8 szNamespace; |
1305 | if (FAILED(pInternalImport->GetNameOfTypeDef(cl, &szName, &szNamespace))) |
1306 | { |
1307 | szName = szNamespace = "Invalid TypeDef record" ; |
1308 | } |
1309 | |
1310 | if (g_pConfig->ShouldBreakOnStructMarshalSetup(szName)) |
1311 | CONSISTENCY_CHECK_MSGF(false, ("BreakOnStructMarshalSetup: '%s' " , szName)); |
1312 | #endif |
1313 | |
1314 | |
1315 | // Check if this type might be ManagedSequential. Only valuetypes marked Sequential can be |
1316 | // ManagedSequential. Other issues checked below might also disqualify the type. |
1317 | if ( (!fExplicitOffsets) && // Is it marked sequential? |
1318 | (pParentMT && (pParentMT->IsValueTypeClass() || pParentMT->IsManagedSequential())) // Is it a valuetype or derived from a qualifying valuetype? |
1319 | ) |
1320 | { |
1321 | // Type qualifies so far... need do nothing. |
1322 | } |
1323 | else |
1324 | { |
1325 | fDisqualifyFromManagedSequential = TRUE; |
1326 | } |
1327 | |
1328 | |
1329 | BOOL fHasNonTrivialParent = pParentMT && |
1330 | !pParentMT->IsObjectClass() && |
1331 | !pParentMT->IsValueTypeClass(); |
1332 | |
1333 | |
1334 | //==================================================================== |
1335 | // First, some validation checks. |
1336 | //==================================================================== |
1337 | _ASSERTE(!(fHasNonTrivialParent && !(pParentMT->HasLayout()))); |
1338 | |
1339 | hr = pInternalImport->GetClassLayoutInit(cl, &classlayout); |
1340 | if (FAILED(hr)) |
1341 | { |
1342 | COMPlusThrowHR(hr, BFA_CANT_GET_CLASSLAYOUT); |
1343 | } |
1344 | |
1345 | pEEClassLayoutInfoOut->m_numCTMFields = fHasNonTrivialParent ? pParentMT->GetLayoutInfo()->m_numCTMFields : 0; |
1346 | pEEClassLayoutInfoOut->SetFieldMarshalers(NULL); |
1347 | pEEClassLayoutInfoOut->SetIsBlittable(TRUE); |
1348 | if (fHasNonTrivialParent) |
1349 | pEEClassLayoutInfoOut->SetIsBlittable(pParentMT->IsBlittable()); |
1350 | pEEClassLayoutInfoOut->SetIsZeroSized(FALSE); |
1351 | pEEClassLayoutInfoOut->SetHasExplicitSize(FALSE); |
1352 | pEEClassLayoutInfoOut->m_cbPackingSize = packingSize; |
1353 | |
1354 | LayoutRawFieldInfo *pfwalk = pInfoArrayOut; |
1355 | |
1356 | S_UINT32 cbSortArraySize = S_UINT32(cMembers) * S_UINT32(sizeof(LayoutRawFieldInfo *)); |
1357 | if (cbSortArraySize.IsOverflow()) |
1358 | { |
1359 | ThrowHR(COR_E_TYPELOAD); |
1360 | } |
1361 | LayoutRawFieldInfo **pSortArray = (LayoutRawFieldInfo **)_alloca(cbSortArraySize.Value()); |
1362 | LayoutRawFieldInfo **pSortArrayEnd = pSortArray; |
1363 | |
1364 | ULONG maxRid = pInternalImport->GetCountWithTokenKind(mdtFieldDef); |
1365 | |
1366 | |
1367 | //===================================================================== |
1368 | // Phase 1: Figure out the NFT of each field based on both the CLR |
1369 | // signature of the field and the FieldMarshaler metadata. |
1370 | //===================================================================== |
1371 | BOOL fParentHasLayout = pParentMT && pParentMT->HasLayout(); |
1372 | UINT32 cbAdjustedParentLayoutNativeSize = 0; |
1373 | EEClassLayoutInfo *pParentLayoutInfo = NULL;; |
1374 | if (fParentHasLayout) |
1375 | { |
1376 | pParentLayoutInfo = pParentMT->GetLayoutInfo(); |
1377 | // Treat base class as an initial member. |
1378 | cbAdjustedParentLayoutNativeSize = pParentLayoutInfo->GetNativeSize(); |
1379 | // If the parent was originally a zero-sized explicit type but |
1380 | // got bumped up to a size of 1 for compatibility reasons, then |
1381 | // we need to remove the padding, but ONLY for inheritance situations. |
1382 | if (pParentLayoutInfo->IsZeroSized()) { |
1383 | CONSISTENCY_CHECK(cbAdjustedParentLayoutNativeSize == 1); |
1384 | cbAdjustedParentLayoutNativeSize = 0; |
1385 | } |
1386 | } |
1387 | |
1388 | ULONG i; |
1389 | for (i = 0; pInternalImport->EnumNext(phEnumField, &fd); i++) |
1390 | { |
1391 | DWORD dwFieldAttrs; |
1392 | ULONG rid = RidFromToken(fd); |
1393 | |
1394 | if((rid == 0)||(rid > maxRid)) |
1395 | { |
1396 | COMPlusThrowHR(COR_E_TYPELOAD, BFA_BAD_FIELD_TOKEN); |
1397 | } |
1398 | |
1399 | IfFailThrow(pInternalImport->GetFieldDefProps(fd, &dwFieldAttrs)); |
1400 | |
1401 | PCCOR_SIGNATURE pNativeType = NULL; |
1402 | ULONG cbNativeType; |
1403 | // We ignore marshaling data attached to statics and literals, |
1404 | // since these do not contribute to instance data. |
1405 | if (!IsFdStatic(dwFieldAttrs) && !IsFdLiteral(dwFieldAttrs)) |
1406 | { |
1407 | PCCOR_SIGNATURE pCOMSignature; |
1408 | ULONG cbCOMSignature; |
1409 | |
1410 | if (IsFdHasFieldMarshal(dwFieldAttrs)) |
1411 | { |
1412 | hr = pInternalImport->GetFieldMarshal(fd, &pNativeType, &cbNativeType); |
1413 | if (FAILED(hr)) |
1414 | cbNativeType = 0; |
1415 | } |
1416 | else |
1417 | cbNativeType = 0; |
1418 | |
1419 | IfFailThrow(pInternalImport->GetSigOfFieldDef(fd,&cbCOMSignature, &pCOMSignature)); |
1420 | |
1421 | IfFailThrow(::validateTokenSig(fd,pCOMSignature,cbCOMSignature,dwFieldAttrs,pInternalImport)); |
1422 | |
1423 | // fill the appropriate entry in pInfoArrayOut |
1424 | pfwalk->m_MD = fd; |
1425 | pfwalk->m_nft = NULL; |
1426 | pfwalk->m_offset = (UINT32) -1; |
1427 | pfwalk->m_sequence = 0; |
1428 | |
1429 | #ifdef _DEBUG |
1430 | LPCUTF8 szFieldName; |
1431 | if (FAILED(pInternalImport->GetNameOfFieldDef(fd, &szFieldName))) |
1432 | { |
1433 | szFieldName = "Invalid FieldDef record" ; |
1434 | } |
1435 | #endif |
1436 | |
1437 | ParseNativeTypeFlags flags = ParseNativeTypeFlag_None; |
1438 | #ifdef FEATURE_COMINTEROP |
1439 | if (isWinRT) |
1440 | flags |= ParseNativeTypeFlag_IsWinRT; |
1441 | else // WinRT types have nlType == nltAnsi but should be treated as Unicode |
1442 | #endif // FEATURE_COMINTEROP |
1443 | if (nlType == nltAnsi) |
1444 | flags |= ParseNativeTypeFlag_IsAnsi; |
1445 | |
1446 | ParseNativeType(pModule, |
1447 | pCOMSignature, |
1448 | cbCOMSignature, |
1449 | flags, |
1450 | pfwalk, |
1451 | pNativeType, |
1452 | cbNativeType, |
1453 | pInternalImport, |
1454 | cl, |
1455 | pTypeContext, |
1456 | &fDisqualifyFromManagedSequential |
1457 | #ifdef _DEBUG |
1458 | , |
1459 | szNamespace, |
1460 | szName, |
1461 | szFieldName |
1462 | #endif |
1463 | ); |
1464 | |
1465 | |
1466 | //<TODO>@nice: This is obviously not the place to bury this logic. |
1467 | // We're replacing NFT's with MARSHAL_TYPES_* in the near future |
1468 | // so this isn't worth perfecting.</TODO> |
1469 | |
1470 | BOOL resetBlittable = TRUE; |
1471 | |
1472 | // if it's a simple copy... |
1473 | if (pfwalk->m_nft == NFT_COPY1 || |
1474 | pfwalk->m_nft == NFT_COPY2 || |
1475 | pfwalk->m_nft == NFT_COPY4 || |
1476 | pfwalk->m_nft == NFT_COPY8) |
1477 | { |
1478 | resetBlittable = FALSE; |
1479 | } |
1480 | |
1481 | // Or if it's a nested value class that is itself blittable... |
1482 | if (pfwalk->m_nft == NFT_NESTEDVALUECLASS) |
1483 | { |
1484 | FieldMarshaler *pFM = (FieldMarshaler*)&(pfwalk->m_FieldMarshaler); |
1485 | _ASSERTE(pFM->IsNestedValueClassMarshaler()); |
1486 | |
1487 | if (((FieldMarshaler_NestedValueClass *) pFM)->IsBlittable()) |
1488 | resetBlittable = FALSE; |
1489 | } |
1490 | |
1491 | // ...Otherwise, this field prevents blitting |
1492 | if (resetBlittable) |
1493 | pEEClassLayoutInfoOut->SetIsBlittable(FALSE); |
1494 | |
1495 | cFields++; |
1496 | pfwalk++; |
1497 | } |
1498 | } |
1499 | |
1500 | _ASSERTE(i == cMembers); |
1501 | |
1502 | // NULL out the last entry |
1503 | pfwalk->m_MD = mdFieldDefNil; |
1504 | |
1505 | |
1506 | // |
1507 | // fill in the layout information |
1508 | // |
1509 | |
1510 | // pfwalk points to the beginging of the array |
1511 | pfwalk = pInfoArrayOut; |
1512 | |
1513 | while (SUCCEEDED(hr = pInternalImport->GetClassLayoutNext( |
1514 | &classlayout, |
1515 | &fd, |
1516 | &ulOffset)) && |
1517 | fd != mdFieldDefNil) |
1518 | { |
1519 | // watch for the last entry: must be mdFieldDefNil |
1520 | while ((mdFieldDefNil != pfwalk->m_MD)&&(pfwalk->m_MD < fd)) |
1521 | pfwalk++; |
1522 | |
1523 | // if we haven't found a matching token, it must be a static field with layout -- ignore it |
1524 | if(pfwalk->m_MD != fd) continue; |
1525 | |
1526 | if (!fExplicitOffsets) |
1527 | { |
1528 | // ulOffset is the sequence |
1529 | pfwalk->m_sequence = ulOffset; |
1530 | } |
1531 | else |
1532 | { |
1533 | // ulOffset is the explicit offset |
1534 | pfwalk->m_offset = ulOffset; |
1535 | pfwalk->m_sequence = (ULONG) -1; |
1536 | |
1537 | // Treat base class as an initial member. |
1538 | if (!SafeAddUINT32(&(pfwalk->m_offset), cbAdjustedParentLayoutNativeSize)) |
1539 | COMPlusThrowOM(); |
1540 | } |
1541 | } |
1542 | IfFailThrow(hr); |
1543 | |
1544 | // now sort the array |
1545 | if (!fExplicitOffsets) |
1546 | { |
1547 | // sort sequential by ascending sequence |
1548 | for (i = 0; i < cFields; i++) |
1549 | { |
1550 | LayoutRawFieldInfo**pSortWalk = pSortArrayEnd; |
1551 | while (pSortWalk != pSortArray) |
1552 | { |
1553 | if (pInfoArrayOut[i].m_sequence >= (*(pSortWalk-1))->m_sequence) |
1554 | break; |
1555 | |
1556 | pSortWalk--; |
1557 | } |
1558 | |
1559 | // pSortWalk now points to the target location for new FieldInfo. |
1560 | MoveMemory(pSortWalk + 1, pSortWalk, (pSortArrayEnd - pSortWalk) * sizeof(LayoutRawFieldInfo*)); |
1561 | *pSortWalk = &pInfoArrayOut[i]; |
1562 | pSortArrayEnd++; |
1563 | } |
1564 | } |
1565 | else // no sorting for explicit layout |
1566 | { |
1567 | for (i = 0; i < cFields; i++) |
1568 | { |
1569 | if(pInfoArrayOut[i].m_MD != mdFieldDefNil) |
1570 | { |
1571 | if (pInfoArrayOut[i].m_offset == (UINT32)-1) |
1572 | { |
1573 | LPCUTF8 szFieldName; |
1574 | if (FAILED(pInternalImport->GetNameOfFieldDef(pInfoArrayOut[i].m_MD, &szFieldName))) |
1575 | { |
1576 | szFieldName = "Invalid FieldDef record" ; |
1577 | } |
1578 | pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, |
1579 | cl, |
1580 | szFieldName, |
1581 | IDS_CLASSLOAD_NSTRUCT_EXPLICIT_OFFSET); |
1582 | } |
1583 | else if ((INT)pInfoArrayOut[i].m_offset < 0) |
1584 | { |
1585 | LPCUTF8 szFieldName; |
1586 | if (FAILED(pInternalImport->GetNameOfFieldDef(pInfoArrayOut[i].m_MD, &szFieldName))) |
1587 | { |
1588 | szFieldName = "Invalid FieldDef record" ; |
1589 | } |
1590 | pModule->GetAssembly()->ThrowTypeLoadException(pInternalImport, |
1591 | cl, |
1592 | szFieldName, |
1593 | IDS_CLASSLOAD_NSTRUCT_NEGATIVE_OFFSET); |
1594 | } |
1595 | } |
1596 | |
1597 | *pSortArrayEnd = &pInfoArrayOut[i]; |
1598 | pSortArrayEnd++; |
1599 | } |
1600 | } |
1601 | |
1602 | //===================================================================== |
1603 | // Phase 2: Compute the native size (in bytes) of each field. |
1604 | // Store this in pInfoArrayOut[].cbNativeSize; |
1605 | //===================================================================== |
1606 | |
1607 | // Now compute the native size of each field |
1608 | for (pfwalk = pInfoArrayOut; pfwalk->m_MD != mdFieldDefNil; pfwalk++) |
1609 | { |
1610 | UINT8 nft = pfwalk->m_nft; |
1611 | pEEClassLayoutInfoOut->m_numCTMFields++; |
1612 | |
1613 | // If the NFT's size never changes, it is stored in the database. |
1614 | UINT32 cbNativeSize = NFTDataBase[nft].m_cbNativeSize; |
1615 | |
1616 | if (cbNativeSize == 0) |
1617 | { |
1618 | // Size of 0 means NFT's size is variable, so we have to figure it |
1619 | // out case by case. |
1620 | cbNativeSize = ((FieldMarshaler*)&(pfwalk->m_FieldMarshaler))->NativeSize(); |
1621 | } |
1622 | pfwalk->m_cbNativeSize = cbNativeSize; |
1623 | } |
1624 | |
1625 | if (pEEClassLayoutInfoOut->m_numCTMFields) |
1626 | { |
1627 | pEEClassLayoutInfoOut->SetFieldMarshalers((FieldMarshaler*)(pamTracker->Track(pAllocator->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(MAXFIELDMARSHALERSIZE) * S_SIZE_T(pEEClassLayoutInfoOut->m_numCTMFields))))); |
1628 | |
1629 | // Bring in the parent's fieldmarshalers |
1630 | if (fHasNonTrivialParent) |
1631 | { |
1632 | CONSISTENCY_CHECK(fParentHasLayout); |
1633 | PREFAST_ASSUME(pParentLayoutInfo != NULL); // See if (fParentHasLayout) branch above |
1634 | |
1635 | UINT numChildCTMFields = pEEClassLayoutInfoOut->m_numCTMFields - pParentLayoutInfo->m_numCTMFields; |
1636 | |
1637 | BYTE *pParentCTMFieldSrcArray = (BYTE*)pParentLayoutInfo->GetFieldMarshalers(); |
1638 | BYTE *pParentCTMFieldDestArray = ((BYTE*)pEEClassLayoutInfoOut->GetFieldMarshalers()) + MAXFIELDMARSHALERSIZE*numChildCTMFields; |
1639 | |
1640 | for (UINT parentCTMFieldIndex = 0; parentCTMFieldIndex < pParentLayoutInfo->m_numCTMFields; parentCTMFieldIndex++) |
1641 | { |
1642 | FieldMarshaler *pParentCTMFieldSrc = (FieldMarshaler *)(pParentCTMFieldSrcArray + MAXFIELDMARSHALERSIZE*parentCTMFieldIndex); |
1643 | FieldMarshaler *pParentCTMFieldDest = (FieldMarshaler *)(pParentCTMFieldDestArray + MAXFIELDMARSHALERSIZE*parentCTMFieldIndex); |
1644 | |
1645 | pParentCTMFieldSrc->CopyTo(pParentCTMFieldDest, MAXFIELDMARSHALERSIZE); |
1646 | } |
1647 | } |
1648 | |
1649 | } |
1650 | |
1651 | |
1652 | //===================================================================== |
1653 | // Phase 3: If FieldMarshaler requires autooffsetting, compute the offset |
1654 | // of each field and the size of the total structure. We do the layout |
1655 | // according to standard VC layout rules: |
1656 | // |
1657 | // Each field has an alignment requirement. The alignment-requirement |
1658 | // of a scalar field is the smaller of its size and the declared packsize. |
1659 | // The alignment-requirement of a struct field is the smaller of the |
1660 | // declared packsize and the largest of the alignment-requirement |
1661 | // of its fields. The alignment requirement of an array is that |
1662 | // of one of its elements. |
1663 | // |
1664 | // In addition, each struct gets padding at the end to ensure |
1665 | // that an array of such structs contain no unused space between |
1666 | // elements. |
1667 | //===================================================================== |
1668 | { |
1669 | BYTE LargestAlignmentRequirement = 1; |
1670 | UINT32 cbCurOffset = 0; |
1671 | |
1672 | // Treat base class as an initial member. |
1673 | if (!SafeAddUINT32(&cbCurOffset, cbAdjustedParentLayoutNativeSize)) |
1674 | COMPlusThrowOM(); |
1675 | |
1676 | if (fParentHasLayout) |
1677 | { |
1678 | BYTE alignmentRequirement; |
1679 | |
1680 | alignmentRequirement = min(packingSize, pParentLayoutInfo->GetLargestAlignmentRequirementOfAllMembers()); |
1681 | |
1682 | LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement); |
1683 | } |
1684 | |
1685 | // Start with the size inherited from the parent (if any). |
1686 | unsigned calcTotalSize = cbAdjustedParentLayoutNativeSize; |
1687 | |
1688 | LayoutRawFieldInfo **pSortWalk; |
1689 | for (pSortWalk = pSortArray, i=cFields; i; i--, pSortWalk++) |
1690 | { |
1691 | pfwalk = *pSortWalk; |
1692 | |
1693 | BYTE alignmentRequirement = static_cast<BYTE>(((FieldMarshaler*)&(pfwalk->m_FieldMarshaler))->AlignmentRequirement()); |
1694 | if (!(alignmentRequirement == 1 || |
1695 | alignmentRequirement == 2 || |
1696 | alignmentRequirement == 4 || |
1697 | alignmentRequirement == 8 || |
1698 | alignmentRequirement == 16 || |
1699 | alignmentRequirement == 32)) |
1700 | { |
1701 | COMPlusThrowHR(COR_E_INVALIDPROGRAM, BFA_METADATA_CORRUPT); |
1702 | } |
1703 | |
1704 | alignmentRequirement = min(alignmentRequirement, packingSize); |
1705 | |
1706 | LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement); |
1707 | |
1708 | // This assert means I forgot to special-case some NFT in the |
1709 | // above switch. |
1710 | _ASSERTE(alignmentRequirement <= 32); |
1711 | |
1712 | // Check if this field is overlapped with other(s) |
1713 | pfwalk->m_fIsOverlapped = FALSE; |
1714 | if (fExplicitOffsets) { |
1715 | LayoutRawFieldInfo *pfwalk1; |
1716 | DWORD dwBegin = pfwalk->m_offset; |
1717 | DWORD dwEnd = dwBegin+pfwalk->m_cbNativeSize; |
1718 | for (pfwalk1 = pInfoArrayOut; pfwalk1 < pfwalk; pfwalk1++) |
1719 | { |
1720 | if((pfwalk1->m_offset >= dwEnd) || (pfwalk1->m_offset+pfwalk1->m_cbNativeSize <= dwBegin)) continue; |
1721 | pfwalk->m_fIsOverlapped = TRUE; |
1722 | pfwalk1->m_fIsOverlapped = TRUE; |
1723 | } |
1724 | } |
1725 | else |
1726 | { |
1727 | // Insert enough padding to align the current data member. |
1728 | while (cbCurOffset % alignmentRequirement) |
1729 | { |
1730 | if (!SafeAddUINT32(&cbCurOffset, 1)) |
1731 | COMPlusThrowOM(); |
1732 | } |
1733 | |
1734 | // Insert current data member. |
1735 | pfwalk->m_offset = cbCurOffset; |
1736 | |
1737 | // if we overflow we will catch it below |
1738 | cbCurOffset += pfwalk->m_cbNativeSize; |
1739 | } |
1740 | |
1741 | unsigned fieldEnd = pfwalk->m_offset + pfwalk->m_cbNativeSize; |
1742 | if (fieldEnd < pfwalk->m_offset) |
1743 | COMPlusThrowOM(); |
1744 | |
1745 | // size of the structure is the size of the last field. |
1746 | if (fieldEnd > calcTotalSize) |
1747 | calcTotalSize = fieldEnd; |
1748 | } |
1749 | |
1750 | ULONG clstotalsize = 0; |
1751 | if (FAILED(pInternalImport->GetClassTotalSize(cl, &clstotalsize))) |
1752 | { |
1753 | clstotalsize = 0; |
1754 | } |
1755 | |
1756 | if (clstotalsize != 0) |
1757 | { |
1758 | if (!SafeAddULONG(&clstotalsize, (ULONG)cbAdjustedParentLayoutNativeSize)) |
1759 | COMPlusThrowOM(); |
1760 | |
1761 | // size must be large enough to accomodate layout. If not, we use the layout size instead. |
1762 | if (clstotalsize < calcTotalSize) |
1763 | { |
1764 | clstotalsize = calcTotalSize; |
1765 | } |
1766 | calcTotalSize = clstotalsize; // use the size they told us |
1767 | } |
1768 | else |
1769 | { |
1770 | // The did not give us an explict size, so lets round up to a good size (for arrays) |
1771 | while (calcTotalSize % LargestAlignmentRequirement != 0) |
1772 | { |
1773 | if (!SafeAddUINT32(&calcTotalSize, 1)) |
1774 | COMPlusThrowOM(); |
1775 | } |
1776 | } |
1777 | |
1778 | // We'll cap the total native size at a (somewhat) arbitrary limit to ensure |
1779 | // that we don't expose some overflow bug later on. |
1780 | if (calcTotalSize >= MAX_SIZE_FOR_INTEROP) |
1781 | COMPlusThrowOM(); |
1782 | |
1783 | // This is a zero-sized struct - need to record the fact and bump it up to 1. |
1784 | if (calcTotalSize == 0) |
1785 | { |
1786 | pEEClassLayoutInfoOut->SetIsZeroSized(TRUE); |
1787 | calcTotalSize = 1; |
1788 | } |
1789 | |
1790 | pEEClassLayoutInfoOut->m_cbNativeSize = calcTotalSize; |
1791 | |
1792 | // The packingSize acts as a ceiling on all individual alignment |
1793 | // requirements so it follows that the largest alignment requirement |
1794 | // is also capped. |
1795 | _ASSERTE(LargestAlignmentRequirement <= packingSize); |
1796 | pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers = LargestAlignmentRequirement; |
1797 | } |
1798 | |
1799 | |
1800 | |
1801 | //===================================================================== |
1802 | // Phase 4: Now we do the same thing again for managedsequential layout. |
1803 | //===================================================================== |
1804 | if (!fDisqualifyFromManagedSequential) |
1805 | { |
1806 | BYTE LargestAlignmentRequirement = 1; |
1807 | UINT32 cbCurOffset = 0; |
1808 | |
1809 | if (pParentMT && pParentMT->IsManagedSequential()) |
1810 | { |
1811 | // Treat base class as an initial member. |
1812 | if (!SafeAddUINT32(&cbCurOffset, pParentMT->GetNumInstanceFieldBytes())) |
1813 | COMPlusThrowOM(); |
1814 | |
1815 | BYTE alignmentRequirement = 0; |
1816 | |
1817 | alignmentRequirement = min(packingSize, pParentLayoutInfo->m_ManagedLargestAlignmentRequirementOfAllMembers); |
1818 | |
1819 | LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement); |
1820 | } |
1821 | |
1822 | // The current size of the structure as a whole, we start at 1, because we disallow 0 sized structures. |
1823 | // NOTE: We do not need to do the same checking for zero-sized types as phase 3 because only ValueTypes |
1824 | // can be ManagedSequential and ValueTypes can not be inherited from. |
1825 | unsigned calcTotalSize = 1; |
1826 | |
1827 | LayoutRawFieldInfo **pSortWalk; |
1828 | for (pSortWalk = pSortArray, i=cFields; i; i--, pSortWalk++) |
1829 | { |
1830 | pfwalk = *pSortWalk; |
1831 | |
1832 | BYTE alignmentRequirement = ((BYTE)(pfwalk->m_managedAlignmentReq)); |
1833 | if (!(alignmentRequirement == 1 || |
1834 | alignmentRequirement == 2 || |
1835 | alignmentRequirement == 4 || |
1836 | alignmentRequirement == 8 || |
1837 | alignmentRequirement == 16 || |
1838 | alignmentRequirement == 32)) |
1839 | { |
1840 | COMPlusThrowHR(COR_E_INVALIDPROGRAM, BFA_METADATA_CORRUPT); |
1841 | } |
1842 | |
1843 | alignmentRequirement = min(alignmentRequirement, packingSize); |
1844 | |
1845 | LargestAlignmentRequirement = max(LargestAlignmentRequirement, alignmentRequirement); |
1846 | |
1847 | _ASSERTE(alignmentRequirement <= 32); |
1848 | |
1849 | // Insert enough padding to align the current data member. |
1850 | while (cbCurOffset % alignmentRequirement) |
1851 | { |
1852 | if (!SafeAddUINT32(&cbCurOffset, 1)) |
1853 | COMPlusThrowOM(); |
1854 | } |
1855 | |
1856 | // Insert current data member. |
1857 | pfwalk->m_managedOffset = cbCurOffset; |
1858 | |
1859 | // if we overflow we will catch it below |
1860 | cbCurOffset += pfwalk->m_managedSize; |
1861 | |
1862 | unsigned fieldEnd = pfwalk->m_managedOffset + pfwalk->m_managedSize; |
1863 | if (fieldEnd < pfwalk->m_managedOffset) |
1864 | COMPlusThrowOM(); |
1865 | |
1866 | // size of the structure is the size of the last field. |
1867 | if (fieldEnd > calcTotalSize) |
1868 | calcTotalSize = fieldEnd; |
1869 | |
1870 | #ifdef _DEBUG |
1871 | // @perf: If the type is blittable, the managed and native layouts have to be identical |
1872 | // so they really shouldn't be calculated twice. Until this code has been well tested and |
1873 | // stabilized, however, it is useful to compute both and assert that they are equal in the blittable |
1874 | // case. |
1875 | if (pEEClassLayoutInfoOut->IsBlittable()) |
1876 | { |
1877 | _ASSERTE(pfwalk->m_managedOffset == pfwalk->m_offset); |
1878 | _ASSERTE(pfwalk->m_managedSize == pfwalk->m_cbNativeSize); |
1879 | } |
1880 | #endif |
1881 | } //for |
1882 | |
1883 | ULONG clstotalsize = 0; |
1884 | if (FAILED(pInternalImport->GetClassTotalSize(cl, &clstotalsize))) |
1885 | { |
1886 | clstotalsize = 0; |
1887 | } |
1888 | |
1889 | if (clstotalsize != 0) |
1890 | { |
1891 | pEEClassLayoutInfoOut->SetHasExplicitSize(TRUE); |
1892 | |
1893 | if (pParentMT && pParentMT->IsManagedSequential()) |
1894 | { |
1895 | // Treat base class as an initial member. |
1896 | UINT32 parentSize = pParentMT->GetNumInstanceFieldBytes(); |
1897 | if (!SafeAddULONG(&clstotalsize, parentSize)) |
1898 | COMPlusThrowOM(); |
1899 | } |
1900 | |
1901 | // size must be large enough to accomodate layout. If not, we use the layout size instead. |
1902 | if (clstotalsize < calcTotalSize) |
1903 | { |
1904 | clstotalsize = calcTotalSize; |
1905 | } |
1906 | calcTotalSize = clstotalsize; // use the size they told us |
1907 | } |
1908 | else |
1909 | { |
1910 | // The did not give us an explict size, so lets round up to a good size (for arrays) |
1911 | while (calcTotalSize % LargestAlignmentRequirement != 0) |
1912 | { |
1913 | if (!SafeAddUINT32(&calcTotalSize, 1)) |
1914 | COMPlusThrowOM(); |
1915 | } |
1916 | } |
1917 | |
1918 | pEEClassLayoutInfoOut->m_cbManagedSize = calcTotalSize; |
1919 | |
1920 | // The packingSize acts as a ceiling on all individual alignment |
1921 | // requirements so it follows that the largest alignment requirement |
1922 | // is also capped. |
1923 | _ASSERTE(LargestAlignmentRequirement <= packingSize); |
1924 | pEEClassLayoutInfoOut->m_ManagedLargestAlignmentRequirementOfAllMembers = LargestAlignmentRequirement; |
1925 | |
1926 | #ifdef _DEBUG |
1927 | // @perf: If the type is blittable, the managed and native layouts have to be identical |
1928 | // so they really shouldn't be calculated twice. Until this code has been well tested and |
1929 | // stabilized, however, it is useful to compute both and assert that they are equal in the blittable |
1930 | // case. |
1931 | if (pEEClassLayoutInfoOut->IsBlittable()) |
1932 | { |
1933 | _ASSERTE(pEEClassLayoutInfoOut->m_cbManagedSize == pEEClassLayoutInfoOut->m_cbNativeSize); |
1934 | _ASSERTE(pEEClassLayoutInfoOut->m_ManagedLargestAlignmentRequirementOfAllMembers == pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers); |
1935 | } |
1936 | #endif |
1937 | } //if |
1938 | |
1939 | pEEClassLayoutInfoOut->SetIsManagedSequential(!fDisqualifyFromManagedSequential); |
1940 | |
1941 | #ifdef _DEBUG |
1942 | { |
1943 | BOOL illegalMarshaler = FALSE; |
1944 | |
1945 | LOG((LF_INTEROP, LL_INFO100000, "\n\n" )); |
1946 | LOG((LF_INTEROP, LL_INFO100000, "%s.%s\n" , szNamespace, szName)); |
1947 | LOG((LF_INTEROP, LL_INFO100000, "Packsize = %lu\n" , (ULONG)packingSize)); |
1948 | LOG((LF_INTEROP, LL_INFO100000, "Max align req = %lu\n" , (ULONG)(pEEClassLayoutInfoOut->m_LargestAlignmentRequirementOfAllMembers))); |
1949 | LOG((LF_INTEROP, LL_INFO100000, "----------------------------\n" )); |
1950 | for (pfwalk = pInfoArrayOut; pfwalk->m_MD != mdFieldDefNil; pfwalk++) |
1951 | { |
1952 | LPCUTF8 fieldname; |
1953 | if (FAILED(pInternalImport->GetNameOfFieldDef(pfwalk->m_MD, &fieldname))) |
1954 | { |
1955 | fieldname = "??" ; |
1956 | } |
1957 | LOG((LF_INTEROP, LL_INFO100000, "+%-5lu " , (ULONG)(pfwalk->m_offset))); |
1958 | LOG((LF_INTEROP, LL_INFO100000, "%s" , fieldname)); |
1959 | LOG((LF_INTEROP, LL_INFO100000, "\n" )); |
1960 | |
1961 | if (((FieldMarshaler*)&pfwalk->m_FieldMarshaler)->GetNStructFieldType() == NFT_ILLEGAL) |
1962 | illegalMarshaler = TRUE; |
1963 | } |
1964 | |
1965 | // If we are dealing with a non trivial parent, determine if it has any illegal marshallers. |
1966 | if (fHasNonTrivialParent) |
1967 | { |
1968 | FieldMarshaler *pParentFM = pParentMT->GetLayoutInfo()->GetFieldMarshalers(); |
1969 | for (i = 0; i < pParentMT->GetLayoutInfo()->m_numCTMFields; i++) |
1970 | { |
1971 | if (pParentFM->GetNStructFieldType() == NFT_ILLEGAL) |
1972 | illegalMarshaler = TRUE; |
1973 | ((BYTE*&)pParentFM) += MAXFIELDMARSHALERSIZE; |
1974 | } |
1975 | } |
1976 | |
1977 | LOG((LF_INTEROP, LL_INFO100000, "+%-5lu EOS\n" , (ULONG)(pEEClassLayoutInfoOut->m_cbNativeSize))); |
1978 | LOG((LF_INTEROP, LL_INFO100000, "Allocated %d %s field marshallers for %s.%s\n" , pEEClassLayoutInfoOut->m_numCTMFields, (illegalMarshaler ? "pointless" : "usable" ), szNamespace, szName)); |
1979 | } |
1980 | #endif |
1981 | return; |
1982 | } |
1983 | #ifdef _PREFAST_ |
1984 | #pragma warning(pop) |
1985 | #endif |
1986 | |
1987 | |
1988 | #ifndef CROSSGEN_COMPILE |
1989 | |
1990 | //======================================================================= |
1991 | // For each reference-typed FieldMarshaler field, marshals the current CLR value |
1992 | // to a new native instance and stores it in the fixed portion of the FieldMarshaler. |
1993 | // |
1994 | // This function does not attempt to delete the native value that it overwrites. |
1995 | // |
1996 | // If there is a SafeHandle field, ppCleanupWorkListOnStack must be non-null, otherwise |
1997 | // InvalidOperationException is thrown. |
1998 | //======================================================================= |
1999 | VOID LayoutUpdateNative(LPVOID *ppProtectedManagedData, SIZE_T offsetbias, MethodTable *pMT, BYTE* pNativeData, OBJECTREF *ppCleanupWorkListOnStack) |
2000 | { |
2001 | CONTRACTL |
2002 | { |
2003 | THROWS; |
2004 | GC_TRIGGERS; |
2005 | MODE_COOPERATIVE; |
2006 | PRECONDITION(CheckPointer(pMT)); |
2007 | } |
2008 | CONTRACTL_END; |
2009 | |
2010 | FieldMarshaler* pFM = pMT->GetLayoutInfo()->GetFieldMarshalers(); |
2011 | UINT numReferenceFields = pMT->GetLayoutInfo()->GetNumCTMFields(); |
2012 | |
2013 | OBJECTREF pCLRValue = NULL; |
2014 | LPVOID scalar = NULL; |
2015 | |
2016 | GCPROTECT_BEGIN(pCLRValue) |
2017 | GCPROTECT_BEGININTERIOR(scalar) |
2018 | { |
2019 | g_IBCLogger.LogFieldMarshalersReadAccess(pMT); |
2020 | |
2021 | while (numReferenceFields--) |
2022 | { |
2023 | pFM->Restore(); |
2024 | |
2025 | DWORD internalOffset = pFM->GetFieldDesc()->GetOffset(); |
2026 | |
2027 | if (pFM->IsScalarMarshaler()) |
2028 | { |
2029 | scalar = (LPVOID)(internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData)); |
2030 | // Note this will throw for FieldMarshaler_Illegal |
2031 | pFM->ScalarUpdateNative(scalar, pNativeData + pFM->GetExternalOffset() ); |
2032 | |
2033 | } |
2034 | else if (pFM->IsNestedValueClassMarshaler()) |
2035 | { |
2036 | pFM->NestedValueClassUpdateNative((const VOID **)ppProtectedManagedData, internalOffset + offsetbias, pNativeData + pFM->GetExternalOffset(), |
2037 | ppCleanupWorkListOnStack); |
2038 | } |
2039 | else |
2040 | { |
2041 | pCLRValue = *(OBJECTREF*)(internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData)); |
2042 | pFM->UpdateNative(&pCLRValue, pNativeData + pFM->GetExternalOffset(), ppCleanupWorkListOnStack); |
2043 | SetObjectReferenceUnchecked( (OBJECTREF*) (internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData)), pCLRValue); |
2044 | } |
2045 | |
2046 | // The cleanup work list is not used to clean up the native contents. It is used |
2047 | // to handle cleanup of any additional resources the FieldMarshalers allocate. |
2048 | |
2049 | ((BYTE*&)pFM) += MAXFIELDMARSHALERSIZE; |
2050 | } |
2051 | } |
2052 | GCPROTECT_END(); |
2053 | GCPROTECT_END(); |
2054 | } |
2055 | |
2056 | VOID FmtClassUpdateNative(OBJECTREF *ppProtectedManagedData, BYTE *pNativeData, OBJECTREF *ppCleanupWorkListOnStack) |
2057 | { |
2058 | CONTRACTL |
2059 | { |
2060 | THROWS; |
2061 | GC_TRIGGERS; |
2062 | MODE_COOPERATIVE; |
2063 | PRECONDITION(CheckPointer(ppProtectedManagedData)); |
2064 | } |
2065 | CONTRACTL_END; |
2066 | |
2067 | MethodTable *pMT = (*ppProtectedManagedData)->GetMethodTable(); |
2068 | _ASSERTE(pMT->IsBlittable() || pMT->HasLayout()); |
2069 | UINT32 cbsize = pMT->GetNativeSize(); |
2070 | |
2071 | if (pMT->IsBlittable()) |
2072 | { |
2073 | memcpyNoGCRefs(pNativeData, (*ppProtectedManagedData)->GetData(), cbsize); |
2074 | } |
2075 | else |
2076 | { |
2077 | // This allows us to do a partial LayoutDestroyNative in the case of |
2078 | // a marshaling error on one of the fields. |
2079 | FillMemory(pNativeData, cbsize, 0); |
2080 | NativeLayoutDestroyer nld(pNativeData, pMT, cbsize); |
2081 | |
2082 | LayoutUpdateNative( (VOID**)ppProtectedManagedData, |
2083 | Object::GetOffsetOfFirstField(), |
2084 | pMT, |
2085 | pNativeData, |
2086 | ppCleanupWorkListOnStack); |
2087 | |
2088 | nld.SuppressRelease(); |
2089 | } |
2090 | |
2091 | } |
2092 | |
2093 | |
2094 | VOID FmtClassUpdateCLR(OBJECTREF *ppProtectedManagedData, BYTE *pNativeData) |
2095 | { |
2096 | CONTRACTL |
2097 | { |
2098 | THROWS; |
2099 | GC_TRIGGERS; |
2100 | MODE_COOPERATIVE; |
2101 | } |
2102 | CONTRACTL_END; |
2103 | |
2104 | MethodTable *pMT = (*ppProtectedManagedData)->GetMethodTable(); |
2105 | _ASSERTE(pMT->IsBlittable() || pMT->HasLayout()); |
2106 | UINT32 cbsize = pMT->GetNativeSize(); |
2107 | |
2108 | if (pMT->IsBlittable()) |
2109 | { |
2110 | memcpyNoGCRefs((*ppProtectedManagedData)->GetData(), pNativeData, cbsize); |
2111 | } |
2112 | else |
2113 | { |
2114 | LayoutUpdateCLR((VOID**)ppProtectedManagedData, |
2115 | Object::GetOffsetOfFirstField(), |
2116 | pMT, |
2117 | (BYTE*)pNativeData |
2118 | ); |
2119 | } |
2120 | } |
2121 | |
2122 | |
2123 | |
2124 | //======================================================================= |
2125 | // For each reference-typed FieldMarshaler field, marshals the current CLR value |
2126 | // to a new CLR instance and stores it in the GC portion of the FieldMarshaler. |
2127 | // |
2128 | // If fDeleteNativeCopies is true, it will also destroy the native version. |
2129 | // |
2130 | // NOTE: To avoid error-path leaks, this function attempts to destroy |
2131 | // all of the native fields even if one or more of the conversions fail. |
2132 | //======================================================================= |
2133 | VOID LayoutUpdateCLR(LPVOID *ppProtectedManagedData, SIZE_T offsetbias, MethodTable *pMT, BYTE *pNativeData) |
2134 | { |
2135 | CONTRACTL |
2136 | { |
2137 | THROWS; |
2138 | GC_TRIGGERS; |
2139 | MODE_COOPERATIVE; |
2140 | PRECONDITION(CheckPointer(pMT)); |
2141 | } |
2142 | CONTRACTL_END; |
2143 | |
2144 | // Don't try to destroy/free native the structure on exception, we may not own it. If we do own it and |
2145 | // are supposed to destroy/free it, we do it upstack (e.g. in a helper called from the marshaling stub). |
2146 | |
2147 | FieldMarshaler* pFM = pMT->GetLayoutInfo()->GetFieldMarshalers(); |
2148 | UINT numReferenceFields = pMT->GetLayoutInfo()->GetNumCTMFields(); |
2149 | |
2150 | struct _gc |
2151 | { |
2152 | OBJECTREF pCLRValue; |
2153 | OBJECTREF pOldCLRValue; |
2154 | } gc; |
2155 | |
2156 | gc.pCLRValue = NULL; |
2157 | gc.pOldCLRValue = NULL; |
2158 | LPVOID scalar = NULL; |
2159 | |
2160 | GCPROTECT_BEGIN(gc) |
2161 | GCPROTECT_BEGININTERIOR(scalar) |
2162 | { |
2163 | g_IBCLogger.LogFieldMarshalersReadAccess(pMT); |
2164 | |
2165 | while (numReferenceFields--) |
2166 | { |
2167 | pFM->Restore(); |
2168 | |
2169 | DWORD internalOffset = pFM->GetFieldDesc()->GetOffset(); |
2170 | |
2171 | if (pFM->IsScalarMarshaler()) |
2172 | { |
2173 | scalar = (LPVOID)(internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData)); |
2174 | // Note this will throw for FieldMarshaler_Illegal |
2175 | pFM->ScalarUpdateCLR( pNativeData + pFM->GetExternalOffset(), scalar); |
2176 | } |
2177 | else if (pFM->IsNestedValueClassMarshaler()) |
2178 | { |
2179 | pFM->NestedValueClassUpdateCLR(pNativeData + pFM->GetExternalOffset(), ppProtectedManagedData, internalOffset + offsetbias); |
2180 | } |
2181 | else |
2182 | { |
2183 | gc.pOldCLRValue = *(OBJECTREF*)(internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData)); |
2184 | pFM->UpdateCLR( pNativeData + pFM->GetExternalOffset(), &gc.pCLRValue, &gc.pOldCLRValue ); |
2185 | SetObjectReferenceUnchecked( (OBJECTREF*) (internalOffset + offsetbias + (BYTE*)(*ppProtectedManagedData)), gc.pCLRValue ); |
2186 | } |
2187 | |
2188 | ((BYTE*&)pFM) += MAXFIELDMARSHALERSIZE; |
2189 | } |
2190 | } |
2191 | GCPROTECT_END(); |
2192 | GCPROTECT_END(); |
2193 | } |
2194 | |
2195 | |
2196 | VOID LayoutDestroyNative(LPVOID pNative, MethodTable *pMT) |
2197 | { |
2198 | CONTRACTL |
2199 | { |
2200 | NOTHROW; |
2201 | GC_TRIGGERS; |
2202 | MODE_ANY; |
2203 | PRECONDITION(CheckPointer(pMT)); |
2204 | } |
2205 | CONTRACTL_END; |
2206 | |
2207 | FieldMarshaler *pFM = pMT->GetLayoutInfo()->GetFieldMarshalers(); |
2208 | UINT numReferenceFields = pMT->GetLayoutInfo()->GetNumCTMFields(); |
2209 | BYTE *pNativeData = (BYTE*)pNative; |
2210 | |
2211 | while (numReferenceFields--) |
2212 | { |
2213 | pFM->DestroyNative( pNativeData + pFM->GetExternalOffset() ); |
2214 | ((BYTE*&)pFM) += MAXFIELDMARSHALERSIZE; |
2215 | } |
2216 | } |
2217 | |
2218 | VOID FmtClassDestroyNative(LPVOID pNative, MethodTable *pMT) |
2219 | { |
2220 | CONTRACTL |
2221 | { |
2222 | NOTHROW; |
2223 | GC_TRIGGERS; |
2224 | MODE_ANY; |
2225 | PRECONDITION(CheckPointer(pMT)); |
2226 | } |
2227 | CONTRACTL_END; |
2228 | |
2229 | if (pNative) |
2230 | { |
2231 | if (!(pMT->IsBlittable())) |
2232 | { |
2233 | _ASSERTE(pMT->HasLayout()); |
2234 | LayoutDestroyNative(pNative, pMT); |
2235 | } |
2236 | } |
2237 | } |
2238 | |
2239 | VOID FmtValueTypeUpdateNative(LPVOID pProtectedManagedData, MethodTable *pMT, BYTE *pNativeData, OBJECTREF *ppCleanupWorkListOnStack) |
2240 | { |
2241 | CONTRACTL |
2242 | { |
2243 | THROWS; |
2244 | GC_TRIGGERS; |
2245 | MODE_COOPERATIVE; |
2246 | PRECONDITION(CheckPointer(pMT)); |
2247 | } |
2248 | CONTRACTL_END; |
2249 | |
2250 | _ASSERTE(pMT->IsValueType() && (pMT->IsBlittable() || pMT->HasLayout())); |
2251 | UINT32 cbsize = pMT->GetNativeSize(); |
2252 | |
2253 | if (pMT->IsBlittable()) |
2254 | { |
2255 | memcpyNoGCRefs(pNativeData, pProtectedManagedData, cbsize); |
2256 | } |
2257 | else |
2258 | { |
2259 | // This allows us to do a partial LayoutDestroyNative in the case of |
2260 | // a marshaling error on one of the fields. |
2261 | FillMemory(pNativeData, cbsize, 0); |
2262 | |
2263 | NativeLayoutDestroyer nld(pNativeData, pMT, cbsize); |
2264 | |
2265 | LayoutUpdateNative( (VOID**)pProtectedManagedData, |
2266 | 0, |
2267 | pMT, |
2268 | pNativeData, |
2269 | ppCleanupWorkListOnStack); |
2270 | |
2271 | nld.SuppressRelease(); |
2272 | } |
2273 | } |
2274 | |
2275 | VOID FmtValueTypeUpdateCLR(LPVOID pProtectedManagedData, MethodTable *pMT, BYTE *pNativeData) |
2276 | { |
2277 | CONTRACTL |
2278 | { |
2279 | THROWS; |
2280 | GC_TRIGGERS; |
2281 | MODE_COOPERATIVE; |
2282 | PRECONDITION(CheckPointer(pMT)); |
2283 | } |
2284 | CONTRACTL_END; |
2285 | |
2286 | _ASSERTE(pMT->IsValueType() && (pMT->IsBlittable() || pMT->HasLayout())); |
2287 | UINT32 cbsize = pMT->GetNativeSize(); |
2288 | |
2289 | if (pMT->IsBlittable()) |
2290 | { |
2291 | memcpyNoGCRefs(pProtectedManagedData, pNativeData, cbsize); |
2292 | } |
2293 | else |
2294 | { |
2295 | LayoutUpdateCLR((VOID**)pProtectedManagedData, |
2296 | 0, |
2297 | pMT, |
2298 | (BYTE*)pNativeData); |
2299 | } |
2300 | } |
2301 | |
2302 | //======================================================================= |
2303 | // BSTR <--> System.String |
2304 | // See FieldMarshaler for details. |
2305 | //======================================================================= |
2306 | VOID FieldMarshaler_BSTR::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const |
2307 | { |
2308 | CONTRACTL |
2309 | { |
2310 | THROWS; |
2311 | GC_NOTRIGGER; |
2312 | MODE_COOPERATIVE; |
2313 | INJECT_FAULT(COMPlusThrowOM()); |
2314 | PRECONDITION(CheckPointer(pNativeValue)); |
2315 | } |
2316 | CONTRACTL_END; |
2317 | |
2318 | STRINGREF pString; |
2319 | *((OBJECTREF*)&pString) = *pCLRValue; |
2320 | |
2321 | if (pString == NULL) |
2322 | MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL); |
2323 | else |
2324 | { |
2325 | BSTR pBSTR = SysAllocStringLen(pString->GetBuffer(), pString->GetStringLength()); |
2326 | if (!pBSTR) |
2327 | COMPlusThrowOM(); |
2328 | |
2329 | MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, pBSTR); |
2330 | } |
2331 | } |
2332 | |
2333 | |
2334 | //======================================================================= |
2335 | // BSTR <--> System.String |
2336 | // See FieldMarshaler for details. |
2337 | //======================================================================= |
2338 | VOID FieldMarshaler_BSTR::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const |
2339 | { |
2340 | STATIC_CONTRACT_THROWS; |
2341 | STATIC_CONTRACT_GC_TRIGGERS; |
2342 | STATIC_CONTRACT_MODE_COOPERATIVE; |
2343 | |
2344 | _ASSERTE(NULL != pNativeValue); |
2345 | _ASSERTE(NULL != ppProtectedCLRValue); |
2346 | |
2347 | STRINGREF pString; |
2348 | BSTR pBSTR = (BSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR); |
2349 | |
2350 | if (!pBSTR) |
2351 | pString = NULL; |
2352 | else |
2353 | { |
2354 | struct Param : CallOutFilterParam { |
2355 | int length; |
2356 | BSTR pBSTR; |
2357 | }; Param param; |
2358 | |
2359 | param.OneShot = TRUE; |
2360 | param.length = 0; |
2361 | param.pBSTR = pBSTR; |
2362 | |
2363 | PAL_TRY(Param *, pParam, ¶m) |
2364 | { |
2365 | pParam->length = SysStringLen(pParam->pBSTR); |
2366 | } |
2367 | PAL_EXCEPT_FILTER(CallOutFilter) |
2368 | { |
2369 | _ASSERTE(!"CallOutFilter returned EXECUTE_HANDLER." ); |
2370 | } |
2371 | PAL_ENDTRY; |
2372 | |
2373 | pString = StringObject::NewString(pBSTR, param.length); |
2374 | } |
2375 | |
2376 | *((STRINGREF*)ppProtectedCLRValue) = pString; |
2377 | } |
2378 | |
2379 | |
2380 | //======================================================================= |
2381 | // BSTR <--> System.String |
2382 | // See FieldMarshaler for details. |
2383 | //======================================================================= |
2384 | VOID FieldMarshaler_BSTR::DestroyNativeImpl(LPVOID pNativeValue) const |
2385 | { |
2386 | CONTRACTL |
2387 | { |
2388 | NOTHROW; |
2389 | GC_NOTRIGGER; |
2390 | MODE_ANY; |
2391 | PRECONDITION(CheckPointer(pNativeValue)); |
2392 | } |
2393 | CONTRACTL_END; |
2394 | |
2395 | BSTR pBSTR = (BSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR); |
2396 | MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL); |
2397 | |
2398 | if (pBSTR) |
2399 | { |
2400 | // BSTR has been created, Delay load will not fail. |
2401 | CONTRACT_VIOLATION(ThrowsViolation); |
2402 | SysFreeString(pBSTR); |
2403 | } |
2404 | } |
2405 | |
2406 | #ifdef FEATURE_COMINTEROP |
2407 | //=========================================================================================== |
2408 | // Windows.Foundation.IReference'1<-- System.Nullable'1 |
2409 | // |
2410 | VOID FieldMarshaler_Nullable::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const |
2411 | { |
2412 | CONTRACTL |
2413 | { |
2414 | THROWS; |
2415 | GC_TRIGGERS; |
2416 | MODE_COOPERATIVE; |
2417 | INJECT_FAULT(COMPlusThrowOM()); |
2418 | PRECONDITION(CheckPointer(pNative)); |
2419 | PRECONDITION(CheckPointer(pCLR)); |
2420 | } |
2421 | CONTRACTL_END; |
2422 | |
2423 | IUnknown *pUnk = NULL; |
2424 | |
2425 | // ConvertToNative<T>(ref Nullable<T> pManaged) where T : struct |
2426 | MethodDescCallSite convertToNative(GetMethodDescForGenericInstantiation(MscorlibBinder::GetMethod(METHOD__NULLABLEMARSHALER__CONVERT_TO_NATIVE))); |
2427 | ARG_SLOT args[] = |
2428 | { |
2429 | PtrToArgSlot(pCLR) |
2430 | }; |
2431 | |
2432 | pUnk = (IUnknown*) convertToNative.Call_RetLPVOID(args); |
2433 | |
2434 | MAYBE_UNALIGNED_WRITE(pNative, _PTR, pUnk); |
2435 | } |
2436 | |
2437 | //=========================================================================================== |
2438 | // Windows.Foundation.IReference'1--> System.Nullable'1 |
2439 | // |
2440 | VOID FieldMarshaler_Nullable::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const |
2441 | { |
2442 | CONTRACTL |
2443 | { |
2444 | THROWS; |
2445 | GC_TRIGGERS; |
2446 | MODE_COOPERATIVE; |
2447 | PRECONDITION(CheckPointer(pNative)); |
2448 | PRECONDITION(CheckPointer(pCLR)); |
2449 | } |
2450 | CONTRACTL_END; |
2451 | |
2452 | IUnknown *pUnk = (IUnknown*)MAYBE_UNALIGNED_READ(pNative, _PTR); |
2453 | |
2454 | MethodDescCallSite convertToManaged(GetMethodDescForGenericInstantiation(MscorlibBinder::GetMethod(METHOD__NULLABLEMARSHALER__CONVERT_TO_MANAGED_RET_VOID))); |
2455 | |
2456 | ARG_SLOT args[] = |
2457 | { |
2458 | PtrToArgSlot(pUnk), |
2459 | PtrToArgSlot(pCLR) |
2460 | }; |
2461 | |
2462 | //ConvertToManaged<T>(Intptr pNative, ref Nullable<T> retObj) where T : struct; |
2463 | convertToManaged.Call(args); |
2464 | } |
2465 | |
2466 | //=========================================================================================== |
2467 | // Windows.Foundation.IReference'1<--> System.Nullable'1 |
2468 | // |
2469 | VOID FieldMarshaler_Nullable::DestroyNativeImpl(const VOID* pNative) const |
2470 | { |
2471 | CONTRACTL |
2472 | { |
2473 | NOTHROW; |
2474 | GC_TRIGGERS; |
2475 | MODE_ANY; |
2476 | PRECONDITION(CheckPointer(pNative)); |
2477 | } |
2478 | CONTRACTL_END; |
2479 | |
2480 | IUnknown *pUnk = (IUnknown*)MAYBE_UNALIGNED_READ(pNative, _PTR); |
2481 | MAYBE_UNALIGNED_WRITE(pNative, _PTR, NULL); |
2482 | |
2483 | if (pUnk != NULL) |
2484 | { |
2485 | ULONG cbRef = SafeRelease(pUnk); |
2486 | LogInteropRelease(pUnk, cbRef, "Field marshaler destroy native" ); |
2487 | } |
2488 | } |
2489 | |
2490 | //======================================================================= |
2491 | // HSTRING <--> System.String |
2492 | // See FieldMarshaler for details. |
2493 | //======================================================================= |
2494 | VOID FieldMarshaler_HSTRING::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const |
2495 | { |
2496 | CONTRACTL |
2497 | { |
2498 | THROWS; |
2499 | GC_TRIGGERS; |
2500 | MODE_COOPERATIVE; |
2501 | PRECONDITION(CheckPointer(pCLRValue)); |
2502 | PRECONDITION(CheckPointer(pNativeValue)); |
2503 | } |
2504 | CONTRACTL_END; |
2505 | |
2506 | if (!WinRTSupported()) |
2507 | { |
2508 | COMPlusThrow(kPlatformNotSupportedException, W("PlatformNotSupported_WinRT" )); |
2509 | } |
2510 | |
2511 | STRINGREF stringref = (STRINGREF)(*pCLRValue); |
2512 | |
2513 | if (stringref == NULL) |
2514 | { |
2515 | DefineFullyQualifiedNameForClassW(); |
2516 | StackSString ssFieldName(SString::Utf8, GetFieldDesc()->GetName()); |
2517 | |
2518 | SString errorString; |
2519 | errorString.LoadResource(CCompRC::Error, IDS_EE_BADMARSHALFIELD_NULL_HSTRING); |
2520 | |
2521 | COMPlusThrow(kMarshalDirectiveException, |
2522 | IDS_EE_BADMARSHALFIELD_ERROR_MSG, |
2523 | GetFullyQualifiedNameForClassW(GetFieldDesc()->GetEnclosingMethodTable()), |
2524 | ssFieldName.GetUnicode(), |
2525 | errorString.GetUnicode()); |
2526 | } |
2527 | |
2528 | HSTRING hstring; |
2529 | IfFailThrow(WindowsCreateString(stringref->GetBuffer(), stringref->GetStringLength(), &hstring)); |
2530 | |
2531 | MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, hstring); |
2532 | } |
2533 | |
2534 | //======================================================================= |
2535 | // HSTRING <--> System.String |
2536 | // See FieldMarshaler for details. |
2537 | //======================================================================= |
2538 | VOID FieldMarshaler_HSTRING::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const |
2539 | { |
2540 | CONTRACTL |
2541 | { |
2542 | THROWS; |
2543 | GC_TRIGGERS; |
2544 | MODE_COOPERATIVE; |
2545 | PRECONDITION(CheckPointer(pNativeValue)); |
2546 | PRECONDITION(CheckPointer(ppProtectedCLRValue)); |
2547 | } |
2548 | CONTRACTL_END; |
2549 | |
2550 | if (!WinRTSupported()) |
2551 | { |
2552 | COMPlusThrow(kPlatformNotSupportedException, W("PlatformNotSupported_WinRT" )); |
2553 | } |
2554 | |
2555 | // NULL HSTRINGS are equivilent to empty strings |
2556 | UINT32 cchString = 0; |
2557 | LPCWSTR pwszString = W("" ); |
2558 | |
2559 | HSTRING hstring = (HSTRING)MAYBE_UNALIGNED_READ(pNativeValue, _PTR); |
2560 | if (hstring != NULL) |
2561 | { |
2562 | pwszString = WindowsGetStringRawBuffer(hstring, &cchString); |
2563 | } |
2564 | |
2565 | STRINGREF stringref = StringObject::NewString(pwszString, cchString); |
2566 | *((STRINGREF *)ppProtectedCLRValue) = stringref; |
2567 | } |
2568 | |
2569 | //======================================================================= |
2570 | // HSTRING <--> System.String |
2571 | // See FieldMarshaler for details. |
2572 | //======================================================================= |
2573 | VOID FieldMarshaler_HSTRING::DestroyNativeImpl(LPVOID pNativeValue) const |
2574 | { |
2575 | CONTRACTL |
2576 | { |
2577 | NOTHROW; |
2578 | GC_NOTRIGGER; |
2579 | MODE_ANY; |
2580 | PRECONDITION(CheckPointer(pNativeValue)); |
2581 | } |
2582 | CONTRACTL_END; |
2583 | |
2584 | HSTRING hstring = (HSTRING)MAYBE_UNALIGNED_READ(pNativeValue, _PTR); |
2585 | MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL); |
2586 | |
2587 | if (hstring != NULL) |
2588 | { |
2589 | // We need this for code:System.Runtime.InteropServices.Marshal.DestroyStructure (user can explicitly call it) |
2590 | if (WinRTSupported()) |
2591 | { |
2592 | // If WinRT is supported we've already loaded combase.dll, which means |
2593 | // this delay load will succeed |
2594 | CONTRACT_VIOLATION(ThrowsViolation); |
2595 | WindowsDeleteString(hstring); |
2596 | } |
2597 | } |
2598 | } |
2599 | |
2600 | //======================================================================================= |
2601 | // Windows.UI.Xaml.Interop.TypeName <--> System.Type |
2602 | // |
2603 | VOID FieldMarshaler_SystemType::UpdateNativeImpl(OBJECTREF * pCLRValue, LPVOID pNativeValue, OBJECTREF * ppCleanupWorkListOnStack) const |
2604 | { |
2605 | CONTRACTL |
2606 | { |
2607 | THROWS; |
2608 | GC_TRIGGERS; |
2609 | MODE_COOPERATIVE; |
2610 | PRECONDITION(CheckPointer(pCLRValue)); |
2611 | PRECONDITION(CheckPointer(pNativeValue)); |
2612 | } |
2613 | CONTRACTL_END; |
2614 | |
2615 | // ConvertToNative(System.Type managedType, TypeName *pTypeName) |
2616 | MethodDescCallSite convertToNative(METHOD__SYSTEMTYPEMARSHALER__CONVERT_TO_NATIVE); |
2617 | ARG_SLOT args[] = |
2618 | { |
2619 | ObjToArgSlot(*pCLRValue), |
2620 | PtrToArgSlot(pNativeValue) |
2621 | }; |
2622 | convertToNative.Call(args); |
2623 | } |
2624 | |
2625 | //======================================================================================= |
2626 | // Windows.UI.Xaml.Interop.TypeName <--> System.Type |
2627 | // |
2628 | VOID FieldMarshaler_SystemType::UpdateCLRImpl(const VOID * pNativeValue, OBJECTREF * ppProtectedCLRValue, OBJECTREF * ppProtectedOldCLRValue) const |
2629 | { |
2630 | CONTRACTL |
2631 | { |
2632 | THROWS; |
2633 | GC_TRIGGERS; |
2634 | MODE_COOPERATIVE; |
2635 | PRECONDITION(CheckPointer(pNativeValue)); |
2636 | PRECONDITION(CheckPointer(ppProtectedCLRValue)); |
2637 | } |
2638 | CONTRACTL_END; |
2639 | |
2640 | // ConvertToManaged(TypeName *pTypeName, out System.Type) |
2641 | MethodDescCallSite convertToManaged(METHOD__SYSTEMTYPEMARSHALER__CONVERT_TO_MANAGED); |
2642 | ARG_SLOT args[] = |
2643 | { |
2644 | PtrToArgSlot(pNativeValue), |
2645 | PtrToArgSlot(ppProtectedCLRValue) |
2646 | }; |
2647 | |
2648 | convertToManaged.Call(args); |
2649 | } |
2650 | |
2651 | //======================================================================================= |
2652 | // Windows.UI.Xaml.Interop.TypeName <--> System.Type |
2653 | // Clear the HSTRING field |
2654 | // |
2655 | VOID FieldMarshaler_SystemType::DestroyNativeImpl(LPVOID pNativeValue) const |
2656 | { |
2657 | CONTRACTL |
2658 | { |
2659 | NOTHROW; |
2660 | GC_NOTRIGGER; |
2661 | MODE_ANY; |
2662 | PRECONDITION(CheckPointer(pNativeValue)); |
2663 | PRECONDITION(WinRTSupported()); |
2664 | } |
2665 | CONTRACTL_END; |
2666 | |
2667 | // |
2668 | // Call WindowsDeleteString instead of SystemTypeMarshaler.ClearNative |
2669 | // because WindowsDeleteString does not throw and is much faster |
2670 | // |
2671 | size_t offset = offsetof(TypeNameNative, typeName); |
2672 | HSTRING hstring = (HSTRING)MAYBE_UNALIGNED_READ((LPBYTE) pNativeValue + offset , _PTR); |
2673 | MAYBE_UNALIGNED_WRITE((LPBYTE) pNativeValue + offset, _PTR, NULL); |
2674 | |
2675 | if (hstring != NULL) |
2676 | { |
2677 | // Note: we've already loaded combase.dll, which means this delay load will succeed |
2678 | CONTRACT_VIOLATION(ThrowsViolation); |
2679 | WindowsDeleteString(hstring); |
2680 | } |
2681 | } |
2682 | |
2683 | //======================================================================================= |
2684 | // Windows.Foundation.HResult <--> System.Exception |
2685 | // Note: The WinRT struct has exactly 1 field, Value (an HRESULT) |
2686 | // |
2687 | VOID FieldMarshaler_Exception::UpdateNativeImpl(OBJECTREF * pCLRValue, LPVOID pNativeValue, OBJECTREF * ppCleanupWorkListOnStack) const |
2688 | { |
2689 | CONTRACTL |
2690 | { |
2691 | THROWS; |
2692 | GC_TRIGGERS; |
2693 | MODE_COOPERATIVE; |
2694 | PRECONDITION(CheckPointer(pCLRValue)); |
2695 | PRECONDITION(CheckPointer(pNativeValue)); |
2696 | } |
2697 | CONTRACTL_END; |
2698 | |
2699 | // int ConvertToNative(Exception ex) |
2700 | MethodDescCallSite convertToNative(METHOD__HRESULTEXCEPTIONMARSHALER__CONVERT_TO_NATIVE); |
2701 | ARG_SLOT args[] = |
2702 | { |
2703 | ObjToArgSlot(*pCLRValue) |
2704 | }; |
2705 | int iReturnedValue = convertToNative.Call_RetI4(args); |
2706 | MAYBE_UNALIGNED_WRITE(pNativeValue, 32, iReturnedValue); |
2707 | } |
2708 | |
2709 | //======================================================================================= |
2710 | // Windows.Foundation.HResult <--> System.Exception |
2711 | // Note: The WinRT struct has exactly 1 field, Value (an HRESULT) |
2712 | // |
2713 | VOID FieldMarshaler_Exception::UpdateCLRImpl(const VOID * pNativeValue, OBJECTREF * ppProtectedCLRValue, OBJECTREF * ppProtectedOldCLRValue) const |
2714 | { |
2715 | CONTRACTL |
2716 | { |
2717 | THROWS; |
2718 | GC_TRIGGERS; |
2719 | MODE_COOPERATIVE; |
2720 | PRECONDITION(CheckPointer(pNativeValue)); |
2721 | PRECONDITION(CheckPointer(ppProtectedCLRValue)); |
2722 | } |
2723 | CONTRACTL_END; |
2724 | |
2725 | // Exception ConvertToManaged(int hr) |
2726 | MethodDescCallSite convertToManaged(METHOD__HRESULTEXCEPTIONMARSHALER__CONVERT_TO_MANAGED); |
2727 | ARG_SLOT args[] = |
2728 | { |
2729 | (ARG_SLOT)MAYBE_UNALIGNED_READ(pNativeValue, 32) |
2730 | }; |
2731 | *ppProtectedCLRValue = convertToManaged.Call_RetOBJECTREF(args); |
2732 | } |
2733 | |
2734 | #endif // FEATURE_COMINTEROP |
2735 | |
2736 | |
2737 | //======================================================================= |
2738 | // Nested structure conversion |
2739 | // See FieldMarshaler for details. |
2740 | //======================================================================= |
2741 | VOID FieldMarshaler_NestedLayoutClass::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const |
2742 | { |
2743 | CONTRACTL |
2744 | { |
2745 | THROWS; |
2746 | GC_TRIGGERS; |
2747 | MODE_COOPERATIVE; |
2748 | INJECT_FAULT(COMPlusThrowOM()); |
2749 | PRECONDITION(CheckPointer(pNativeValue)); |
2750 | } |
2751 | CONTRACTL_END; |
2752 | |
2753 | UINT32 cbNativeSize = GetMethodTable()->GetNativeSize(); |
2754 | |
2755 | if (*pCLRValue == NULL) |
2756 | { |
2757 | ZeroMemoryInGCHeap(pNativeValue, cbNativeSize); |
2758 | } |
2759 | else |
2760 | { |
2761 | LayoutUpdateNative((LPVOID*)pCLRValue, Object::GetOffsetOfFirstField(), |
2762 | GetMethodTable(), (BYTE*)pNativeValue, ppCleanupWorkListOnStack); |
2763 | } |
2764 | |
2765 | } |
2766 | |
2767 | |
2768 | //======================================================================= |
2769 | // Nested structure conversion |
2770 | // See FieldMarshaler for details. |
2771 | //======================================================================= |
2772 | VOID FieldMarshaler_NestedLayoutClass::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const |
2773 | { |
2774 | CONTRACTL |
2775 | { |
2776 | THROWS; |
2777 | GC_TRIGGERS; |
2778 | MODE_COOPERATIVE; |
2779 | INJECT_FAULT(COMPlusThrowOM()); |
2780 | PRECONDITION(CheckPointer(pNativeValue)); |
2781 | PRECONDITION(CheckPointer(ppProtectedCLRValue)); |
2782 | } |
2783 | CONTRACTL_END; |
2784 | |
2785 | *ppProtectedCLRValue = GetMethodTable()->Allocate(); |
2786 | |
2787 | LayoutUpdateCLR( (LPVOID*)ppProtectedCLRValue, |
2788 | Object::GetOffsetOfFirstField(), |
2789 | GetMethodTable(), |
2790 | (BYTE *)pNativeValue); |
2791 | |
2792 | } |
2793 | |
2794 | |
2795 | //======================================================================= |
2796 | // Nested structure conversion |
2797 | // See FieldMarshaler for details. |
2798 | //======================================================================= |
2799 | VOID FieldMarshaler_NestedLayoutClass::DestroyNativeImpl(LPVOID pNativeValue) const |
2800 | { |
2801 | CONTRACTL |
2802 | { |
2803 | NOTHROW; |
2804 | GC_TRIGGERS; |
2805 | MODE_ANY; |
2806 | PRECONDITION(CheckPointer(pNativeValue)); |
2807 | } |
2808 | CONTRACTL_END; |
2809 | |
2810 | LayoutDestroyNative(pNativeValue, GetMethodTable()); |
2811 | } |
2812 | |
2813 | #endif // CROSSGEN_COMPILE |
2814 | |
2815 | |
2816 | //======================================================================= |
2817 | // Nested structure conversion |
2818 | // See FieldMarshaler for details. |
2819 | //======================================================================= |
2820 | UINT32 FieldMarshaler_NestedLayoutClass::NativeSizeImpl() const |
2821 | { |
2822 | CONTRACTL |
2823 | { |
2824 | NOTHROW; |
2825 | GC_NOTRIGGER; |
2826 | MODE_ANY; |
2827 | } |
2828 | CONTRACTL_END; |
2829 | |
2830 | return GetMethodTable()->GetLayoutInfo()->GetNativeSize(); |
2831 | } |
2832 | |
2833 | //======================================================================= |
2834 | // Nested structure conversion |
2835 | // See FieldMarshaler for details. |
2836 | //======================================================================= |
2837 | UINT32 FieldMarshaler_NestedLayoutClass::AlignmentRequirementImpl() const |
2838 | { |
2839 | CONTRACTL |
2840 | { |
2841 | THROWS; |
2842 | GC_TRIGGERS; |
2843 | MODE_ANY; |
2844 | } |
2845 | CONTRACTL_END; |
2846 | |
2847 | return GetMethodTable()->GetLayoutInfo()->GetLargestAlignmentRequirementOfAllMembers(); |
2848 | } |
2849 | |
2850 | #if FEATURE_COMINTEROP |
2851 | MethodDesc* FieldMarshaler_Nullable::GetMethodDescForGenericInstantiation(MethodDesc* pMD) const |
2852 | { |
2853 | MethodDesc *pMethodInstantiation; |
2854 | |
2855 | pMethodInstantiation = MethodDesc::FindOrCreateAssociatedMethodDesc( |
2856 | pMD, |
2857 | pMD->GetMethodTable(), |
2858 | FALSE, |
2859 | GetMethodTable()->GetInstantiation(), |
2860 | FALSE, |
2861 | TRUE); |
2862 | |
2863 | _ASSERTE(pMethodInstantiation != NULL); |
2864 | |
2865 | return pMethodInstantiation; |
2866 | } |
2867 | #endif //FEATURE_COMINTEROP |
2868 | |
2869 | #ifndef CROSSGEN_COMPILE |
2870 | |
2871 | //======================================================================= |
2872 | // Nested structure conversion |
2873 | // See FieldMarshaler for details. |
2874 | //======================================================================= |
2875 | VOID FieldMarshaler_NestedValueClass::NestedValueClassUpdateNativeImpl(const VOID **ppProtectedCLR, SIZE_T startoffset, LPVOID pNative, OBJECTREF *ppCleanupWorkListOnStack) const |
2876 | { |
2877 | CONTRACTL |
2878 | { |
2879 | THROWS; |
2880 | GC_TRIGGERS; |
2881 | MODE_COOPERATIVE; |
2882 | INJECT_FAULT(COMPlusThrowOM()); |
2883 | PRECONDITION(CheckPointer(ppProtectedCLR)); |
2884 | PRECONDITION(CheckPointer(pNative)); |
2885 | } |
2886 | CONTRACTL_END; |
2887 | |
2888 | MethodTable* pMT = GetMethodTable(); |
2889 | |
2890 | // would be better to detect this at class load time (that have a nested value |
2891 | // class with no layout) but don't have a way to know |
2892 | if (!pMT->GetLayoutInfo()) |
2893 | COMPlusThrow(kArgumentException, IDS_NOLAYOUT_IN_EMBEDDED_VALUECLASS); |
2894 | |
2895 | if (pMT->IsBlittable()) |
2896 | { |
2897 | memcpyNoGCRefs(pNative, (BYTE*)(*ppProtectedCLR) + startoffset, pMT->GetNativeSize()); |
2898 | } |
2899 | else |
2900 | { |
2901 | #ifdef _DEBUG |
2902 | _ASSERTE_MSG(!IsFixedBuffer(), "Cannot correctly marshal fixed buffers of non-blittable types" ); |
2903 | #endif |
2904 | LayoutUpdateNative((LPVOID*)ppProtectedCLR, startoffset, pMT, (BYTE*)pNative, ppCleanupWorkListOnStack); |
2905 | } |
2906 | } |
2907 | |
2908 | |
2909 | //======================================================================= |
2910 | // Nested structure conversion |
2911 | // See FieldMarshaler for details. |
2912 | //======================================================================= |
2913 | VOID FieldMarshaler_NestedValueClass::NestedValueClassUpdateCLRImpl(const VOID *pNative, LPVOID *ppProtectedCLR, SIZE_T startoffset) const |
2914 | { |
2915 | CONTRACTL |
2916 | { |
2917 | THROWS; |
2918 | GC_TRIGGERS; |
2919 | MODE_COOPERATIVE; |
2920 | PRECONDITION(CheckPointer(pNative)); |
2921 | PRECONDITION(CheckPointer(ppProtectedCLR)); |
2922 | } |
2923 | CONTRACTL_END; |
2924 | |
2925 | MethodTable* pMT = GetMethodTable(); |
2926 | |
2927 | // would be better to detect this at class load time (that have a nested value |
2928 | // class with no layout) but don't have a way to know |
2929 | if (!pMT->GetLayoutInfo()) |
2930 | COMPlusThrow(kArgumentException, IDS_NOLAYOUT_IN_EMBEDDED_VALUECLASS); |
2931 | |
2932 | if (pMT->IsBlittable()) |
2933 | { |
2934 | memcpyNoGCRefs((BYTE*)(*ppProtectedCLR) + startoffset, pNative, pMT->GetNativeSize()); |
2935 | } |
2936 | else |
2937 | { |
2938 | #ifdef _DEBUG |
2939 | _ASSERTE_MSG(!IsFixedBuffer(), "Cannot correctly marshal fixed buffers of non-blittable types" ); |
2940 | #endif |
2941 | LayoutUpdateCLR((LPVOID*)ppProtectedCLR, |
2942 | startoffset, |
2943 | pMT, |
2944 | (BYTE *)pNative); |
2945 | } |
2946 | } |
2947 | |
2948 | |
2949 | //======================================================================= |
2950 | // Nested structure conversion |
2951 | // See FieldMarshaler for details. |
2952 | //======================================================================= |
2953 | VOID FieldMarshaler_NestedValueClass::DestroyNativeImpl(LPVOID pNativeValue) const |
2954 | { |
2955 | CONTRACTL |
2956 | { |
2957 | NOTHROW; |
2958 | GC_TRIGGERS; |
2959 | MODE_ANY; |
2960 | PRECONDITION(CheckPointer(pNativeValue)); |
2961 | } |
2962 | CONTRACTL_END; |
2963 | |
2964 | MethodTable* pMT = GetMethodTable(); |
2965 | |
2966 | if (!pMT->IsBlittable()) |
2967 | { |
2968 | LayoutDestroyNative(pNativeValue, pMT); |
2969 | } |
2970 | } |
2971 | |
2972 | #endif // CROSSGEN_COMPILE |
2973 | |
2974 | |
2975 | //======================================================================= |
2976 | // Nested structure conversion |
2977 | // See FieldMarshaler for details. |
2978 | //======================================================================= |
2979 | UINT32 FieldMarshaler_NestedValueClass::NativeSizeImpl() const |
2980 | { |
2981 | CONTRACTL |
2982 | { |
2983 | NOTHROW; |
2984 | GC_NOTRIGGER; |
2985 | MODE_ANY; |
2986 | } |
2987 | CONTRACTL_END; |
2988 | |
2989 | // this can't be marshalled as native type if no layout, so we allow the |
2990 | // native size info to be created if available, but the size will only |
2991 | // be valid for native, not unions. Marshaller will throw exception if |
2992 | // try to marshall a value class with no layout |
2993 | if (GetMethodTable()->HasLayout()) |
2994 | return GetMethodTable()->GetLayoutInfo()->GetNativeSize(); |
2995 | |
2996 | return 0; |
2997 | } |
2998 | |
2999 | |
3000 | //======================================================================= |
3001 | // Nested structure conversion |
3002 | // See FieldMarshaler for details. |
3003 | //======================================================================= |
3004 | UINT32 FieldMarshaler_NestedValueClass::AlignmentRequirementImpl() const |
3005 | { |
3006 | CONTRACTL |
3007 | { |
3008 | THROWS; |
3009 | GC_TRIGGERS; |
3010 | MODE_ANY; |
3011 | } |
3012 | CONTRACTL_END; |
3013 | |
3014 | // this can't be marshalled as native type if no layout, so we allow the |
3015 | // native size info to be created if available, but the alignment will only |
3016 | // be valid for native, not unions. Marshaller will throw exception if |
3017 | // try to marshall a value class with no layout |
3018 | if (GetMethodTable()->HasLayout()) |
3019 | { |
3020 | UINT32 uAlignmentReq = GetMethodTable()->GetLayoutInfo()->GetLargestAlignmentRequirementOfAllMembers(); |
3021 | return uAlignmentReq; |
3022 | } |
3023 | return 1; |
3024 | } |
3025 | |
3026 | |
3027 | #ifndef CROSSGEN_COMPILE |
3028 | |
3029 | //======================================================================= |
3030 | // CoTask Uni <--> System.String |
3031 | // See FieldMarshaler for details. |
3032 | //======================================================================= |
3033 | VOID FieldMarshaler_StringUni::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const |
3034 | { |
3035 | CONTRACTL |
3036 | { |
3037 | THROWS; |
3038 | GC_NOTRIGGER; |
3039 | MODE_COOPERATIVE; |
3040 | INJECT_FAULT(COMPlusThrowOM()); |
3041 | PRECONDITION(CheckPointer(pNativeValue)); |
3042 | } |
3043 | CONTRACTL_END; |
3044 | |
3045 | STRINGREF pString; |
3046 | *((OBJECTREF*)&pString) = *pCLRValue; |
3047 | |
3048 | if (pString == NULL) |
3049 | { |
3050 | MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL); |
3051 | } |
3052 | else |
3053 | { |
3054 | DWORD nc = pString->GetStringLength(); |
3055 | if (nc > MAX_SIZE_FOR_INTEROP) |
3056 | COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG); |
3057 | |
3058 | LPWSTR wsz = (LPWSTR)CoTaskMemAlloc( (nc + 1) * sizeof(WCHAR) ); |
3059 | if (!wsz) |
3060 | COMPlusThrowOM(); |
3061 | |
3062 | memcpyNoGCRefs(wsz, pString->GetBuffer(), nc*sizeof(WCHAR)); |
3063 | wsz[nc] = W('\0'); |
3064 | MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, wsz); |
3065 | } |
3066 | } |
3067 | |
3068 | |
3069 | //======================================================================= |
3070 | // CoTask Uni <--> System.String |
3071 | // See FieldMarshaler for details. |
3072 | //======================================================================= |
3073 | VOID FieldMarshaler_StringUni::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const |
3074 | { |
3075 | CONTRACTL |
3076 | { |
3077 | THROWS; |
3078 | GC_TRIGGERS; |
3079 | MODE_COOPERATIVE; |
3080 | PRECONDITION(CheckPointer(pNativeValue)); |
3081 | PRECONDITION(CheckPointer(ppProtectedCLRValue)); |
3082 | } |
3083 | CONTRACTL_END; |
3084 | |
3085 | STRINGREF pString; |
3086 | LPCWSTR wsz = (LPCWSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR); |
3087 | |
3088 | if (!wsz) |
3089 | pString = NULL; |
3090 | else |
3091 | { |
3092 | SIZE_T length = wcslen(wsz); |
3093 | if (length > MAX_SIZE_FOR_INTEROP) |
3094 | COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG); |
3095 | |
3096 | pString = StringObject::NewString(wsz, (DWORD)length); |
3097 | } |
3098 | |
3099 | *((STRINGREF*)ppProtectedCLRValue) = pString; |
3100 | } |
3101 | |
3102 | |
3103 | //======================================================================= |
3104 | // CoTask Uni <--> System.String |
3105 | // See FieldMarshaler for details. |
3106 | //======================================================================= |
3107 | VOID FieldMarshaler_StringUni::DestroyNativeImpl(LPVOID pNativeValue) const |
3108 | { |
3109 | CONTRACTL |
3110 | { |
3111 | NOTHROW; |
3112 | GC_NOTRIGGER; |
3113 | MODE_ANY; |
3114 | PRECONDITION(CheckPointer(pNativeValue)); |
3115 | } |
3116 | CONTRACTL_END; |
3117 | |
3118 | LPWSTR wsz = (LPWSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR); |
3119 | MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL); |
3120 | if (wsz) |
3121 | CoTaskMemFree(wsz); |
3122 | } |
3123 | |
3124 | |
3125 | |
3126 | //======================================================================= |
3127 | // CoTask Ansi <--> System.String |
3128 | // See FieldMarshaler for details. |
3129 | //======================================================================= |
3130 | VOID FieldMarshaler_StringAnsi::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const |
3131 | { |
3132 | CONTRACTL |
3133 | { |
3134 | THROWS; |
3135 | GC_TRIGGERS; |
3136 | MODE_COOPERATIVE; |
3137 | INJECT_FAULT(COMPlusThrowOM()); |
3138 | PRECONDITION(CheckPointer(pNativeValue)); |
3139 | } |
3140 | CONTRACTL_END; |
3141 | |
3142 | STRINGREF pString; |
3143 | *((OBJECTREF*)&pString) = *pCLRValue; |
3144 | |
3145 | if (pString == NULL) |
3146 | { |
3147 | MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL); |
3148 | } |
3149 | else |
3150 | { |
3151 | DWORD nc = pString->GetStringLength(); |
3152 | if (nc > MAX_SIZE_FOR_INTEROP) |
3153 | COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG); |
3154 | |
3155 | LPSTR sz = (LPSTR)CoTaskMemAlloc( (nc + 1) * 2 /* 2 for MBCS */ ); |
3156 | if (!sz) |
3157 | COMPlusThrowOM(); |
3158 | |
3159 | int nbytes = InternalWideToAnsi(pString->GetBuffer(), |
3160 | nc, |
3161 | sz, |
3162 | nc*2, |
3163 | m_BestFitMap, |
3164 | m_ThrowOnUnmappableChar); |
3165 | sz[nbytes] = '\0'; |
3166 | |
3167 | MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, sz); |
3168 | } |
3169 | } |
3170 | |
3171 | |
3172 | //======================================================================= |
3173 | // CoTask Ansi <--> System.String |
3174 | // See FieldMarshaler for details. |
3175 | //======================================================================= |
3176 | VOID FieldMarshaler_StringAnsi::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const |
3177 | { |
3178 | CONTRACTL |
3179 | { |
3180 | THROWS; |
3181 | GC_TRIGGERS; |
3182 | MODE_COOPERATIVE; |
3183 | INJECT_FAULT(COMPlusThrowOM()); |
3184 | PRECONDITION(CheckPointer(pNativeValue)); |
3185 | PRECONDITION(CheckPointer(ppProtectedCLRValue)); |
3186 | } |
3187 | CONTRACTL_END; |
3188 | |
3189 | STRINGREF pString = NULL; |
3190 | LPCSTR sz = (LPCSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR); |
3191 | if (!sz) |
3192 | pString = NULL; |
3193 | else |
3194 | { |
3195 | MAKE_WIDEPTR_FROMANSI(wsztemp, sz); |
3196 | pString = StringObject::NewString(wsztemp, __lwsztemp - 1); |
3197 | } |
3198 | |
3199 | *((STRINGREF*)ppProtectedCLRValue) = pString; |
3200 | } |
3201 | |
3202 | |
3203 | //======================================================================= |
3204 | // CoTask Ansi <--> System.String |
3205 | // See FieldMarshaler for details. |
3206 | //======================================================================= |
3207 | VOID FieldMarshaler_StringAnsi::DestroyNativeImpl(LPVOID pNativeValue) const |
3208 | { |
3209 | CONTRACTL |
3210 | { |
3211 | NOTHROW; |
3212 | GC_NOTRIGGER; |
3213 | MODE_ANY; |
3214 | PRECONDITION(CheckPointer(pNativeValue)); |
3215 | } |
3216 | CONTRACTL_END; |
3217 | |
3218 | LPSTR sz = (LPSTR)MAYBE_UNALIGNED_READ(pNativeValue, _PTR); |
3219 | MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL); |
3220 | if (sz) |
3221 | CoTaskMemFree(sz); |
3222 | } |
3223 | |
3224 | //======================================================================= |
3225 | // CoTask Utf8 <--> System.String |
3226 | // See FieldMarshaler for details. |
3227 | //======================================================================= |
3228 | VOID FieldMarshaler_StringUtf8::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const |
3229 | { |
3230 | CONTRACTL |
3231 | { |
3232 | THROWS; |
3233 | GC_TRIGGERS; |
3234 | MODE_COOPERATIVE; |
3235 | INJECT_FAULT(COMPlusThrowOM()); |
3236 | PRECONDITION(CheckPointer(pNativeValue)); |
3237 | } |
3238 | CONTRACTL_END; |
3239 | |
3240 | STRINGREF pString = (STRINGREF)(*pCLRValue); |
3241 | if (pString == NULL) |
3242 | { |
3243 | MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL); |
3244 | } |
3245 | else |
3246 | { |
3247 | DWORD nc = pString->GetStringLength(); |
3248 | if (nc > MAX_SIZE_FOR_INTEROP) |
3249 | COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG); |
3250 | |
3251 | // Characters would be # of characters + 1 in case left over high surrogate is ? |
3252 | // Max 3 bytes per char for basic multi-lingual plane. |
3253 | nc = (nc + 1) * MAX_UTF8_CHAR_SIZE; |
3254 | // +1 for '\0' |
3255 | LPUTF8 lpBuffer = (LPUTF8)CoTaskMemAlloc(nc + 1); |
3256 | if (!lpBuffer) |
3257 | { |
3258 | COMPlusThrowOM(); |
3259 | } |
3260 | |
3261 | // UTF8Marshaler.ConvertToNative |
3262 | MethodDescCallSite convertToNative(METHOD__CUTF8MARSHALER__CONVERT_TO_NATIVE); |
3263 | |
3264 | ARG_SLOT args[] = |
3265 | { |
3266 | ((ARG_SLOT)(CLR_I4)0), |
3267 | ObjToArgSlot(*pCLRValue), |
3268 | PtrToArgSlot(lpBuffer) |
3269 | }; |
3270 | convertToNative.Call(args); |
3271 | MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, lpBuffer); |
3272 | } |
3273 | } |
3274 | |
3275 | |
3276 | //======================================================================= |
3277 | // CoTask Utf8 <--> System.String |
3278 | // See FieldMarshaler for details. |
3279 | //======================================================================= |
3280 | VOID FieldMarshaler_StringUtf8::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const |
3281 | { |
3282 | CONTRACTL |
3283 | { |
3284 | THROWS; |
3285 | GC_TRIGGERS; |
3286 | MODE_COOPERATIVE; |
3287 | INJECT_FAULT(COMPlusThrowOM()); |
3288 | PRECONDITION(CheckPointer(pNativeValue)); |
3289 | PRECONDITION(CheckPointer(ppProtectedCLRValue)); |
3290 | } |
3291 | CONTRACTL_END; |
3292 | |
3293 | STRINGREF pString = NULL; |
3294 | LPCUTF8 sz = (LPCUTF8)MAYBE_UNALIGNED_READ(pNativeValue, _PTR); |
3295 | if (!sz) |
3296 | { |
3297 | pString = NULL; |
3298 | } |
3299 | else |
3300 | { |
3301 | MethodDescCallSite convertToManaged(METHOD__CUTF8MARSHALER__CONVERT_TO_MANAGED); |
3302 | ARG_SLOT args[] = |
3303 | { |
3304 | PtrToArgSlot(pNativeValue), |
3305 | }; |
3306 | pString = convertToManaged.Call_RetSTRINGREF(args); |
3307 | } |
3308 | *((STRINGREF*)ppProtectedCLRValue) = pString; |
3309 | } |
3310 | |
3311 | //======================================================================= |
3312 | // CoTask Utf8 <--> System.String |
3313 | // See FieldMarshaler for details. |
3314 | //======================================================================= |
3315 | VOID FieldMarshaler_StringUtf8::DestroyNativeImpl(LPVOID pNativeValue) const |
3316 | { |
3317 | CONTRACTL |
3318 | { |
3319 | NOTHROW; |
3320 | GC_NOTRIGGER; |
3321 | MODE_ANY; |
3322 | PRECONDITION(CheckPointer(pNativeValue)); |
3323 | } |
3324 | CONTRACTL_END; |
3325 | |
3326 | LPCUTF8 lpBuffer = (LPCUTF8)MAYBE_UNALIGNED_READ(pNativeValue, _PTR); |
3327 | MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL); |
3328 | if (lpBuffer) |
3329 | CoTaskMemFree((LPVOID)lpBuffer); |
3330 | } |
3331 | |
3332 | //======================================================================= |
3333 | // FixedString <--> System.String |
3334 | // See FieldMarshaler for details. |
3335 | //======================================================================= |
3336 | VOID FieldMarshaler_FixedStringUni::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const |
3337 | { |
3338 | CONTRACTL |
3339 | { |
3340 | NOTHROW; |
3341 | GC_NOTRIGGER; |
3342 | MODE_COOPERATIVE; |
3343 | PRECONDITION(CheckPointer(pNativeValue)); |
3344 | } |
3345 | CONTRACTL_END; |
3346 | |
3347 | STRINGREF pString; |
3348 | *((OBJECTREF*)&pString) = *pCLRValue; |
3349 | |
3350 | if (pString == NULL) |
3351 | { |
3352 | MAYBE_UNALIGNED_WRITE(pNativeValue, 16, W('\0')); |
3353 | } |
3354 | else |
3355 | { |
3356 | DWORD nc = pString->GetStringLength(); |
3357 | if (nc >= m_numchar) |
3358 | nc = m_numchar - 1; |
3359 | |
3360 | memcpyNoGCRefs(pNativeValue, pString->GetBuffer(), nc*sizeof(WCHAR)); |
3361 | MAYBE_UNALIGNED_WRITE(&(((WCHAR*)pNativeValue)[nc]), 16, W('\0')); |
3362 | } |
3363 | |
3364 | } |
3365 | |
3366 | |
3367 | //======================================================================= |
3368 | // FixedString <--> System.String |
3369 | // See FieldMarshaler for details. |
3370 | //======================================================================= |
3371 | VOID FieldMarshaler_FixedStringUni::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const |
3372 | { |
3373 | CONTRACTL |
3374 | { |
3375 | THROWS; |
3376 | GC_TRIGGERS; |
3377 | MODE_COOPERATIVE; |
3378 | PRECONDITION(CheckPointer(pNativeValue)); |
3379 | PRECONDITION(CheckPointer(ppProtectedCLRValue)); |
3380 | } |
3381 | CONTRACTL_END; |
3382 | |
3383 | STRINGREF pString; |
3384 | SIZE_T ncActual = wcsnlen((const WCHAR *)pNativeValue, m_numchar); |
3385 | |
3386 | if (!FitsIn<int>(ncActual)) |
3387 | COMPlusThrowHR(COR_E_OVERFLOW); |
3388 | |
3389 | pString = StringObject::NewString((const WCHAR *)pNativeValue, (int)ncActual); |
3390 | *((STRINGREF*)ppProtectedCLRValue) = pString; |
3391 | } |
3392 | |
3393 | |
3394 | |
3395 | |
3396 | |
3397 | |
3398 | |
3399 | //======================================================================= |
3400 | // FixedString <--> System.String |
3401 | // See FieldMarshaler for details. |
3402 | //======================================================================= |
3403 | VOID FieldMarshaler_FixedStringAnsi::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const |
3404 | { |
3405 | CONTRACTL |
3406 | { |
3407 | THROWS; |
3408 | GC_TRIGGERS; |
3409 | MODE_COOPERATIVE; |
3410 | PRECONDITION(CheckPointer(pNativeValue)); |
3411 | } |
3412 | CONTRACTL_END; |
3413 | |
3414 | STRINGREF pString; |
3415 | *((OBJECTREF*)&pString) = *pCLRValue; |
3416 | |
3417 | if (pString == NULL) |
3418 | *((CHAR*)pNativeValue) = W('\0'); |
3419 | else |
3420 | { |
3421 | DWORD nc = pString->GetStringLength(); |
3422 | if (nc >= m_numchar) |
3423 | nc = m_numchar - 1; |
3424 | |
3425 | int cbwritten = InternalWideToAnsi(pString->GetBuffer(), |
3426 | nc, |
3427 | (CHAR*)pNativeValue, |
3428 | m_numchar, |
3429 | m_BestFitMap, |
3430 | m_ThrowOnUnmappableChar); |
3431 | |
3432 | // Handle the case where SizeConst == Number of bytes.For single byte chars |
3433 | // this will never be the case since nc >= m_numchar check will truncate the last |
3434 | // character, but for multibyte chars nc>= m_numchar check won't truncate since GetStringLength |
3435 | // gives number of characters but not the actual number of bytes. For such cases need to make |
3436 | // sure that we dont write one past the buffer. |
3437 | if (cbwritten == (int) m_numchar) |
3438 | --cbwritten; |
3439 | |
3440 | ((CHAR*)pNativeValue)[cbwritten] = '\0'; |
3441 | } |
3442 | } |
3443 | |
3444 | |
3445 | //======================================================================= |
3446 | // FixedString <--> System.String |
3447 | // See FieldMarshaler for details. |
3448 | //======================================================================= |
3449 | VOID FieldMarshaler_FixedStringAnsi::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const |
3450 | { |
3451 | CONTRACTL |
3452 | { |
3453 | THROWS; |
3454 | GC_TRIGGERS; |
3455 | MODE_COOPERATIVE; |
3456 | INJECT_FAULT(COMPlusThrowOM()); |
3457 | PRECONDITION(CheckPointer(pNativeValue)); |
3458 | PRECONDITION(CheckPointer(ppProtectedCLRValue)); |
3459 | |
3460 | // should not have slipped past the metadata |
3461 | PRECONDITION(m_numchar != 0); |
3462 | } |
3463 | CONTRACTL_END; |
3464 | |
3465 | STRINGREF pString; |
3466 | if (m_numchar == 0) |
3467 | { |
3468 | // but if it does, better to throw an exception tardily rather than |
3469 | // allow a memory corrupt. |
3470 | COMPlusThrow(kMarshalDirectiveException); |
3471 | } |
3472 | |
3473 | UINT32 allocSize = m_numchar + 2; |
3474 | if (allocSize < m_numchar) |
3475 | ThrowOutOfMemory(); |
3476 | |
3477 | LPSTR tempbuf = (LPSTR)(_alloca((size_t)allocSize)); |
3478 | if (!tempbuf) |
3479 | ThrowOutOfMemory(); |
3480 | |
3481 | memcpyNoGCRefs(tempbuf, pNativeValue, m_numchar); |
3482 | tempbuf[m_numchar-1] = '\0'; |
3483 | tempbuf[m_numchar] = '\0'; |
3484 | tempbuf[m_numchar+1] = '\0'; |
3485 | |
3486 | allocSize = m_numchar * sizeof(WCHAR); |
3487 | if (allocSize < m_numchar) |
3488 | ThrowOutOfMemory(); |
3489 | |
3490 | LPWSTR wsztemp = (LPWSTR)_alloca( (size_t)allocSize ); |
3491 | int ncwritten = MultiByteToWideChar(CP_ACP, |
3492 | MB_PRECOMPOSED, |
3493 | tempbuf, |
3494 | -1, // # of CHAR's in inbuffer |
3495 | wsztemp, |
3496 | m_numchar // size (in WCHAR) of outbuffer |
3497 | ); |
3498 | |
3499 | if (!ncwritten) |
3500 | { |
3501 | // intentionally not throwing for MB2WC failure. We don't always know |
3502 | // whether to expect a valid string in the buffer and we don't want |
3503 | // to throw exceptions randomly. |
3504 | ncwritten++; |
3505 | } |
3506 | |
3507 | pString = StringObject::NewString((const WCHAR *)wsztemp, ncwritten-1); |
3508 | *((STRINGREF*)ppProtectedCLRValue) = pString; |
3509 | } |
3510 | |
3511 | |
3512 | //======================================================================= |
3513 | // CHAR[] <--> char[] |
3514 | // See FieldMarshaler for details. |
3515 | //======================================================================= |
3516 | VOID FieldMarshaler_FixedCharArrayAnsi::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const |
3517 | { |
3518 | CONTRACTL |
3519 | { |
3520 | THROWS; |
3521 | GC_TRIGGERS; |
3522 | MODE_COOPERATIVE; |
3523 | INJECT_FAULT(COMPlusThrowOM()); |
3524 | PRECONDITION(CheckPointer(pNativeValue)); |
3525 | } |
3526 | CONTRACTL_END; |
3527 | |
3528 | I2ARRAYREF pArray; |
3529 | *((OBJECTREF*)&pArray) = *pCLRValue; |
3530 | |
3531 | if (pArray == NULL) |
3532 | FillMemory(pNativeValue, m_numElems * sizeof(CHAR), 0); |
3533 | else |
3534 | { |
3535 | if (pArray->GetNumComponents() < m_numElems) |
3536 | COMPlusThrow(kArgumentException, IDS_WRONGSIZEARRAY_IN_NSTRUCT); |
3537 | else |
3538 | { |
3539 | InternalWideToAnsi((const WCHAR*) pArray->GetDataPtr(), |
3540 | m_numElems, |
3541 | (CHAR*)pNativeValue, |
3542 | m_numElems * sizeof(CHAR), |
3543 | m_BestFitMap, |
3544 | m_ThrowOnUnmappableChar); |
3545 | } |
3546 | } |
3547 | } |
3548 | |
3549 | |
3550 | //======================================================================= |
3551 | // CHAR[] <--> char[] |
3552 | // See FieldMarshaler for details. |
3553 | //======================================================================= |
3554 | VOID FieldMarshaler_FixedCharArrayAnsi::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const |
3555 | { |
3556 | CONTRACTL |
3557 | { |
3558 | THROWS; |
3559 | GC_TRIGGERS; |
3560 | MODE_COOPERATIVE; |
3561 | INJECT_FAULT(COMPlusThrowOM()); |
3562 | PRECONDITION(CheckPointer(pNativeValue)); |
3563 | PRECONDITION(CheckPointer(ppProtectedCLRValue)); |
3564 | } |
3565 | CONTRACTL_END; |
3566 | |
3567 | *ppProtectedCLRValue = AllocatePrimitiveArray(ELEMENT_TYPE_CHAR, m_numElems); |
3568 | |
3569 | MultiByteToWideChar(CP_ACP, |
3570 | MB_PRECOMPOSED, |
3571 | (const CHAR *)pNativeValue, |
3572 | m_numElems * sizeof(CHAR), // size, in bytes, of in buffer |
3573 | (WCHAR*) ((*((I2ARRAYREF*)ppProtectedCLRValue))->GetDirectPointerToNonObjectElements()), |
3574 | m_numElems); // size, in WCHAR's of outbuffer |
3575 | } |
3576 | |
3577 | #endif // CROSSGEN_COMPILE |
3578 | |
3579 | |
3580 | //======================================================================= |
3581 | // Embedded array |
3582 | // See FieldMarshaler for details. |
3583 | //======================================================================= |
3584 | FieldMarshaler_FixedArray::FieldMarshaler_FixedArray(IMDInternalImport *pMDImport, mdTypeDef cl, UINT32 numElems, VARTYPE vt, MethodTable* pElementMT) |
3585 | : m_numElems(numElems) |
3586 | , m_vt(vt) |
3587 | , m_BestFitMap(FALSE) |
3588 | , m_ThrowOnUnmappableChar(FALSE) |
3589 | { |
3590 | CONTRACTL |
3591 | { |
3592 | THROWS; |
3593 | GC_TRIGGERS; |
3594 | MODE_ANY; |
3595 | PRECONDITION(CheckPointer(pElementMT)); |
3596 | PRECONDITION(vt != VTHACK_ANSICHAR); // This must be handled by the FixedCharArrayAnsi marshaler. |
3597 | } |
3598 | CONTRACTL_END; |
3599 | |
3600 | // Only attempt to read the best fit mapping attribute if required to minimize |
3601 | // custom attribute accesses. |
3602 | if (vt == VT_LPSTR || vt == VT_RECORD) |
3603 | { |
3604 | BOOL BestFitMap = FALSE; |
3605 | BOOL ThrowOnUnmappableChar = FALSE; |
3606 | ReadBestFitCustomAttribute(pMDImport, cl, &BestFitMap, &ThrowOnUnmappableChar); |
3607 | m_BestFitMap = !!BestFitMap; |
3608 | m_ThrowOnUnmappableChar = !!ThrowOnUnmappableChar; |
3609 | } |
3610 | |
3611 | m_arrayType.SetValue(ClassLoader::LoadArrayTypeThrowing(TypeHandle(pElementMT), |
3612 | ELEMENT_TYPE_SZARRAY, |
3613 | 0, |
3614 | ClassLoader::LoadTypes, |
3615 | pElementMT->GetLoadLevel())); |
3616 | } |
3617 | |
3618 | |
3619 | #ifndef CROSSGEN_COMPILE |
3620 | |
3621 | //======================================================================= |
3622 | // Embedded array |
3623 | // See FieldMarshaler for details. |
3624 | //======================================================================= |
3625 | VOID FieldMarshaler_FixedArray::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const |
3626 | { |
3627 | CONTRACTL |
3628 | { |
3629 | THROWS; |
3630 | GC_TRIGGERS; |
3631 | MODE_COOPERATIVE; |
3632 | PRECONDITION(CheckPointer(pNativeValue)); |
3633 | } |
3634 | CONTRACTL_END; |
3635 | |
3636 | if (*pCLRValue == NULL) |
3637 | { |
3638 | FillMemory(pNativeValue, NativeSize(), 0); |
3639 | } |
3640 | else |
3641 | { |
3642 | // Make sure the size of the array is >= as specified in the MarshalAs attribute (via the SizeConst field). |
3643 | if ((*pCLRValue)->GetNumComponents() < m_numElems) |
3644 | COMPlusThrow(kArgumentException, IDS_WRONGSIZEARRAY_IN_NSTRUCT); |
3645 | |
3646 | // Marshal the contents from the managed array to the native array. |
3647 | const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(m_vt, TRUE); |
3648 | if (pMarshaler == NULL || pMarshaler->ComToOleArray == NULL) |
3649 | { |
3650 | memcpyNoGCRefs(pNativeValue, (*(BASEARRAYREF*)pCLRValue)->GetDataPtr(), NativeSize()); |
3651 | } |
3652 | else |
3653 | { |
3654 | MethodTable *pElementMT = m_arrayType.GetValue().AsArray()->GetArrayElementTypeHandle().GetMethodTable(); |
3655 | |
3656 | // We never operate on an uninitialized native layout here, we have zero'ed it if needed. |
3657 | // Therefore fOleArrayIsValid is always TRUE. |
3658 | pMarshaler->ComToOleArray((BASEARRAYREF*)pCLRValue, pNativeValue, pElementMT, m_BestFitMap, m_ThrowOnUnmappableChar, TRUE, m_numElems); |
3659 | } |
3660 | } |
3661 | } |
3662 | |
3663 | |
3664 | //======================================================================= |
3665 | // Embedded array |
3666 | // See FieldMarshaler for details. |
3667 | //======================================================================= |
3668 | VOID FieldMarshaler_FixedArray::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const |
3669 | { |
3670 | CONTRACTL |
3671 | { |
3672 | THROWS; |
3673 | GC_TRIGGERS; |
3674 | MODE_COOPERATIVE; |
3675 | INJECT_FAULT(COMPlusThrowOM()); |
3676 | PRECONDITION(CheckPointer(pNativeValue)); |
3677 | PRECONDITION(CheckPointer(ppProtectedCLRValue)); |
3678 | } |
3679 | CONTRACTL_END; |
3680 | |
3681 | // Allocate the value class array. |
3682 | *ppProtectedCLRValue = AllocateArrayEx(m_arrayType.GetValue(), (INT32*)&m_numElems, 1); |
3683 | |
3684 | // Marshal the contents from the native array to the managed array. |
3685 | const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(m_vt, TRUE); |
3686 | if (pMarshaler == NULL || pMarshaler->OleToComArray == NULL) |
3687 | { |
3688 | memcpyNoGCRefs((*(BASEARRAYREF*)ppProtectedCLRValue)->GetDataPtr(), pNativeValue, NativeSize()); |
3689 | } |
3690 | else |
3691 | { |
3692 | MethodTable *pElementMT = m_arrayType.GetValue().AsArray()->GetArrayElementTypeHandle().GetMethodTable(); |
3693 | pMarshaler->OleToComArray((VOID *)pNativeValue, (BASEARRAYREF*)ppProtectedCLRValue, pElementMT); |
3694 | } |
3695 | } |
3696 | |
3697 | //======================================================================= |
3698 | // Embedded array |
3699 | // See FieldMarshaler for details. |
3700 | //======================================================================= |
3701 | VOID FieldMarshaler_FixedArray::DestroyNativeImpl(LPVOID pNativeValue) const |
3702 | { |
3703 | CONTRACTL |
3704 | { |
3705 | NOTHROW; |
3706 | GC_TRIGGERS; |
3707 | MODE_ANY; |
3708 | INJECT_FAULT(COMPlusThrowOM()); |
3709 | PRECONDITION(CheckPointer(pNativeValue)); |
3710 | } |
3711 | CONTRACTL_END; |
3712 | |
3713 | const OleVariant::Marshaler *pMarshaler = OleVariant::GetMarshalerForVarType(m_vt, FALSE); |
3714 | |
3715 | if (pMarshaler != NULL && pMarshaler->ClearOleArray != NULL) |
3716 | { |
3717 | MethodTable *pElementMT = m_arrayType.GetValue().AsArray()->GetArrayElementTypeHandle().GetMethodTable(); |
3718 | pMarshaler->ClearOleArray(pNativeValue, m_numElems, pElementMT); |
3719 | } |
3720 | } |
3721 | |
3722 | #endif // CROSSGEN_COMPILE |
3723 | |
3724 | |
3725 | //======================================================================= |
3726 | // Embedded array |
3727 | // See FieldMarshaler for details. |
3728 | //======================================================================= |
3729 | UINT32 FieldMarshaler_FixedArray::AlignmentRequirementImpl() const |
3730 | { |
3731 | WRAPPER_NO_CONTRACT; |
3732 | |
3733 | UINT32 alignment = 0; |
3734 | TypeHandle elementType = m_arrayType.GetValue().AsArray()->GetArrayElementTypeHandle(); |
3735 | |
3736 | switch (m_vt) |
3737 | { |
3738 | case VT_DECIMAL: |
3739 | alignment = 8; |
3740 | break; |
3741 | |
3742 | case VT_VARIANT: |
3743 | alignment = 8; |
3744 | break; |
3745 | |
3746 | case VT_RECORD: |
3747 | alignment = elementType.GetMethodTable()->GetLayoutInfo()->GetLargestAlignmentRequirementOfAllMembers(); |
3748 | break; |
3749 | |
3750 | default: |
3751 | alignment = OleVariant::GetElementSizeForVarType(m_vt, elementType.GetMethodTable()); |
3752 | break; |
3753 | } |
3754 | |
3755 | return alignment; |
3756 | } |
3757 | |
3758 | #ifndef CROSSGEN_COMPILE |
3759 | |
3760 | #ifdef FEATURE_CLASSIC_COMINTEROP |
3761 | //======================================================================= |
3762 | // SafeArray |
3763 | // See FieldMarshaler for details. |
3764 | //======================================================================= |
3765 | VOID FieldMarshaler_SafeArray::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const |
3766 | { |
3767 | CONTRACTL |
3768 | { |
3769 | THROWS; |
3770 | GC_TRIGGERS; |
3771 | MODE_COOPERATIVE; |
3772 | PRECONDITION(CheckPointer(pNativeValue)); |
3773 | } |
3774 | CONTRACTL_END; |
3775 | |
3776 | BASEARRAYREF pArray; |
3777 | *((OBJECTREF*)&pArray) = *pCLRValue; |
3778 | if ((pArray == NULL) || (OBJECTREFToObject(pArray) == NULL)) |
3779 | { |
3780 | FillMemory(pNativeValue, sizeof(LPSAFEARRAY*), 0); |
3781 | return; |
3782 | } |
3783 | |
3784 | LPSAFEARRAY* pSafeArray; |
3785 | pSafeArray = (LPSAFEARRAY*)pNativeValue; |
3786 | |
3787 | VARTYPE vt = m_vt; |
3788 | MethodTable* pMT = m_pMT.GetValueMaybeNull(); |
3789 | |
3790 | GCPROTECT_BEGIN(pArray) |
3791 | { |
3792 | if (vt == VT_EMPTY) |
3793 | vt = OleVariant::GetElementVarTypeForArrayRef(pArray); |
3794 | |
3795 | if (!pMT) |
3796 | pMT = OleVariant::GetArrayElementTypeWrapperAware(&pArray).GetMethodTable(); |
3797 | |
3798 | // OleVariant calls throw on error. |
3799 | *pSafeArray = OleVariant::CreateSafeArrayForArrayRef(&pArray, vt, pMT); |
3800 | OleVariant::MarshalSafeArrayForArrayRef(&pArray, *pSafeArray, vt, pMT); |
3801 | } |
3802 | GCPROTECT_END(); |
3803 | } |
3804 | |
3805 | |
3806 | //======================================================================= |
3807 | // SafeArray |
3808 | // See FieldMarshaler for details. |
3809 | //======================================================================= |
3810 | VOID FieldMarshaler_SafeArray::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const |
3811 | { |
3812 | CONTRACTL |
3813 | { |
3814 | THROWS; |
3815 | GC_TRIGGERS; |
3816 | MODE_COOPERATIVE; |
3817 | INJECT_FAULT(COMPlusThrowOM()); |
3818 | PRECONDITION(CheckPointer(pNativeValue)); |
3819 | PRECONDITION(CheckPointer(ppProtectedCLRValue)); |
3820 | } |
3821 | CONTRACTL_END; |
3822 | |
3823 | LPSAFEARRAY* pSafeArray; |
3824 | pSafeArray = (LPSAFEARRAY*)pNativeValue; |
3825 | |
3826 | if ((pSafeArray == NULL) || (*pSafeArray == NULL)) |
3827 | { |
3828 | *ppProtectedCLRValue = NULL; |
3829 | return; |
3830 | } |
3831 | |
3832 | VARTYPE vt = m_vt; |
3833 | MethodTable* pMT = m_pMT.GetValueMaybeNull(); |
3834 | |
3835 | // If we have an empty vartype, get it from the safearray vartype |
3836 | if (vt == VT_EMPTY) |
3837 | { |
3838 | if (FAILED(ClrSafeArrayGetVartype(*pSafeArray, &vt))) |
3839 | COMPlusThrow(kArgumentException, IDS_EE_INVALID_SAFEARRAY); |
3840 | } |
3841 | |
3842 | // Get the method table if we need to. |
3843 | if ((vt == VT_RECORD) && (!pMT)) |
3844 | pMT = OleVariant::GetElementTypeForRecordSafeArray(*pSafeArray).GetMethodTable(); |
3845 | |
3846 | // If we have a single dimension safearray, it will be converted into a SZArray. |
3847 | // SZArray must have a lower bound of zero. |
3848 | LONG LowerBound = -1; |
3849 | UINT Dimensions = SafeArrayGetDim( (SAFEARRAY*)*pSafeArray ); |
3850 | |
3851 | if (Dimensions == 1) |
3852 | { |
3853 | HRESULT hr = SafeArrayGetLBound((SAFEARRAY*)*pSafeArray, 1, &LowerBound); |
3854 | if ( FAILED(hr) || LowerBound != 0) |
3855 | COMPlusThrow(kSafeArrayRankMismatchException, IDS_EE_SAFEARRAYSZARRAYMISMATCH); |
3856 | } |
3857 | |
3858 | // OleVariant calls throw on error. |
3859 | *ppProtectedCLRValue = OleVariant::CreateArrayRefForSafeArray(*pSafeArray, vt, pMT); |
3860 | OleVariant::MarshalArrayRefForSafeArray(*pSafeArray, (BASEARRAYREF*)ppProtectedCLRValue, vt, pMT); |
3861 | } |
3862 | |
3863 | |
3864 | //======================================================================= |
3865 | // SafeArray |
3866 | // See FieldMarshaler for details. |
3867 | //======================================================================= |
3868 | VOID FieldMarshaler_SafeArray::DestroyNativeImpl(LPVOID pNativeValue) const |
3869 | { |
3870 | CONTRACTL |
3871 | { |
3872 | NOTHROW; |
3873 | GC_TRIGGERS; |
3874 | MODE_ANY; |
3875 | PRECONDITION(CheckPointer(pNativeValue)); |
3876 | } |
3877 | CONTRACTL_END; |
3878 | |
3879 | HRESULT hr; |
3880 | GCX_PREEMP(); |
3881 | |
3882 | LPSAFEARRAY psa = (LPSAFEARRAY)MAYBE_UNALIGNED_READ(pNativeValue, _PTR); |
3883 | MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL); |
3884 | |
3885 | if (psa) |
3886 | { |
3887 | _ASSERTE (GetModuleHandleA("oleaut32.dll" ) != NULL); |
3888 | // SafeArray has been created, which means oleaut32 should have been loaded. |
3889 | // Delay load will not fail. |
3890 | CONTRACT_VIOLATION(ThrowsViolation); |
3891 | hr = SafeArrayDestroy(psa); |
3892 | _ASSERTE(!FAILED(hr)); |
3893 | } |
3894 | } |
3895 | #endif //FEATURE_CLASSIC_COMINTEROP |
3896 | |
3897 | |
3898 | //======================================================================= |
3899 | // function ptr <--> Delegate |
3900 | // See FieldMarshaler for details. |
3901 | //======================================================================= |
3902 | VOID FieldMarshaler_Delegate::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const |
3903 | { |
3904 | CONTRACTL |
3905 | { |
3906 | THROWS; |
3907 | GC_TRIGGERS; |
3908 | MODE_COOPERATIVE; |
3909 | PRECONDITION(CheckPointer(pNativeValue)); |
3910 | } |
3911 | CONTRACTL_END; |
3912 | |
3913 | LPVOID fnPtr = COMDelegate::ConvertToCallback(*pCLRValue); |
3914 | |
3915 | // If there is no CleanupWorkList (i.e. a call from Marshal.StructureToPtr), we don't use it to manage delegate lifetime. |
3916 | // 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 |
3917 | // object lifetime for the unmanaged memory that the structure would be marshalled to in the Marshal.StructureToPtr case. |
3918 | if (*pCLRValue != NULL && ppCleanupWorkListOnStack != NULL) |
3919 | { |
3920 | // Call StubHelpers.AddToCleanupList to ensure the delegate is kept alive across the full native call. |
3921 | MethodDescCallSite AddToCleanupList(METHOD__STUBHELPERS__ADD_TO_CLEANUP_LIST_DELEGATE); |
3922 | |
3923 | ARG_SLOT args[] = |
3924 | { |
3925 | (ARG_SLOT)ppCleanupWorkListOnStack, |
3926 | ObjToArgSlot(*pCLRValue) |
3927 | }; |
3928 | |
3929 | AddToCleanupList.Call(args); |
3930 | } |
3931 | |
3932 | MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, fnPtr); |
3933 | } |
3934 | |
3935 | |
3936 | //======================================================================= |
3937 | // function ptr <--> Delegate |
3938 | // See FieldMarshaler for details. |
3939 | //======================================================================= |
3940 | VOID FieldMarshaler_Delegate::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const |
3941 | { |
3942 | CONTRACTL |
3943 | { |
3944 | THROWS; |
3945 | GC_TRIGGERS; |
3946 | MODE_COOPERATIVE; |
3947 | PRECONDITION(CheckPointer(pNativeValue)); |
3948 | PRECONDITION(CheckPointer(ppProtectedCLRValue)); |
3949 | } |
3950 | CONTRACTL_END; |
3951 | |
3952 | *ppProtectedCLRValue = COMDelegate::ConvertToDelegate((LPVOID)MAYBE_UNALIGNED_READ(pNativeValue, _PTR), GetMethodTable()); |
3953 | } |
3954 | |
3955 | |
3956 | //======================================================================= |
3957 | // SafeHandle <--> Handle |
3958 | // See FieldMarshaler for details. |
3959 | //======================================================================= |
3960 | VOID FieldMarshaler_SafeHandle::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const |
3961 | { |
3962 | CONTRACTL |
3963 | { |
3964 | THROWS; |
3965 | GC_TRIGGERS; |
3966 | MODE_COOPERATIVE; |
3967 | PRECONDITION(CheckPointer(pNativeValue)); |
3968 | PRECONDITION(CheckPointer(ppCleanupWorkListOnStack, NULL_OK)); |
3969 | } |
3970 | CONTRACTL_END; |
3971 | |
3972 | SAFEHANDLE *pSafeHandleObj = ((SAFEHANDLE *)pCLRValue); |
3973 | |
3974 | // A cleanup list MUST be specified in order for us to be able to marshal |
3975 | // the SafeHandle. |
3976 | if (ppCleanupWorkListOnStack == NULL) |
3977 | COMPlusThrow(kInvalidOperationException, IDS_EE_SH_FIELD_INVALID_OPERATION); |
3978 | |
3979 | if (*pSafeHandleObj == NULL) |
3980 | COMPlusThrow(kArgumentNullException, W("ArgumentNull_SafeHandle" )); |
3981 | |
3982 | // Call StubHelpers.AddToCleanupList to AddRef and schedule Release on this SafeHandle |
3983 | // This is realiable, i.e. the cleanup will happen if and only if the SH was actually AddRef'ed. |
3984 | MethodDescCallSite AddToCleanupList(METHOD__STUBHELPERS__ADD_TO_CLEANUP_LIST_SAFEHANDLE); |
3985 | |
3986 | ARG_SLOT args[] = |
3987 | { |
3988 | (ARG_SLOT)ppCleanupWorkListOnStack, |
3989 | ObjToArgSlot(*pSafeHandleObj) |
3990 | }; |
3991 | |
3992 | LPVOID handle = AddToCleanupList.Call_RetLPVOID(args); |
3993 | |
3994 | MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, handle); |
3995 | } |
3996 | |
3997 | |
3998 | //======================================================================= |
3999 | // SafeHandle <--> Handle |
4000 | // See FieldMarshaler for details. |
4001 | //======================================================================= |
4002 | VOID FieldMarshaler_SafeHandle::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const |
4003 | { |
4004 | CONTRACTL |
4005 | { |
4006 | THROWS; |
4007 | GC_TRIGGERS; |
4008 | MODE_COOPERATIVE; |
4009 | PRECONDITION(CheckPointer(pNativeValue)); |
4010 | PRECONDITION(CheckPointer(ppProtectedCLRValue)); |
4011 | PRECONDITION(CheckPointer(ppProtectedOldCLRValue)); |
4012 | } |
4013 | CONTRACTL_END; |
4014 | |
4015 | // Since we dissallow marshaling SafeHandle fields from unmanaged to managed, check |
4016 | // to see if this handle was obtained from a SafeHandle and if it was that the |
4017 | // handle value hasn't changed. |
4018 | SAFEHANDLE *pSafeHandleObj = (SAFEHANDLE *)ppProtectedOldCLRValue; |
4019 | if (!*pSafeHandleObj || (*pSafeHandleObj)->GetHandle() != (LPVOID)MAYBE_UNALIGNED_READ(pNativeValue, _PTR)) |
4020 | COMPlusThrow(kNotSupportedException, IDS_EE_CANNOT_CREATE_SAFEHANDLE_FIELD); |
4021 | |
4022 | // Now that we know the handle hasn't changed we just copy set the new SafeHandle |
4023 | // to the old one. |
4024 | *ppProtectedCLRValue = *ppProtectedOldCLRValue; |
4025 | } |
4026 | |
4027 | |
4028 | //======================================================================= |
4029 | // CriticalHandle <--> Handle |
4030 | // See FieldMarshaler for details. |
4031 | //======================================================================= |
4032 | VOID FieldMarshaler_CriticalHandle::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const |
4033 | { |
4034 | CONTRACTL |
4035 | { |
4036 | THROWS; |
4037 | GC_TRIGGERS; |
4038 | MODE_COOPERATIVE; |
4039 | PRECONDITION(CheckPointer(pNativeValue)); |
4040 | } |
4041 | CONTRACTL_END; |
4042 | |
4043 | LPVOID handle = ((CRITICALHANDLE)*pCLRValue)->GetHandle(); |
4044 | MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, handle); |
4045 | } |
4046 | |
4047 | |
4048 | //======================================================================= |
4049 | // CriticalHandle <--> Handle |
4050 | // See FieldMarshaler for details. |
4051 | //======================================================================= |
4052 | VOID FieldMarshaler_CriticalHandle::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const |
4053 | { |
4054 | CONTRACTL |
4055 | { |
4056 | THROWS; |
4057 | GC_TRIGGERS; |
4058 | MODE_COOPERATIVE; |
4059 | PRECONDITION(CheckPointer(pNativeValue)); |
4060 | PRECONDITION(CheckPointer(ppProtectedCLRValue)); |
4061 | PRECONDITION(CheckPointer(ppProtectedOldCLRValue)); |
4062 | } |
4063 | CONTRACTL_END; |
4064 | |
4065 | // Since we dissallow marshaling CriticalHandle fields from unmanaged to managed, check |
4066 | // to see if this handle was obtained from a CriticalHandle and if it was that the |
4067 | // handle value hasn't changed. |
4068 | CRITICALHANDLE *pCriticalHandleObj = (CRITICALHANDLE *)ppProtectedOldCLRValue; |
4069 | if (!*pCriticalHandleObj || (*pCriticalHandleObj)->GetHandle() != (LPVOID)MAYBE_UNALIGNED_READ(pNativeValue, _PTR)) |
4070 | COMPlusThrow(kNotSupportedException, IDS_EE_CANNOT_CREATE_CRITICALHANDLE_FIELD); |
4071 | |
4072 | // Now that we know the handle hasn't changed we just copy set the new CriticalHandle |
4073 | // to the old one. |
4074 | *ppProtectedCLRValue = *ppProtectedOldCLRValue; |
4075 | } |
4076 | |
4077 | #ifdef FEATURE_COMINTEROP |
4078 | |
4079 | //======================================================================= |
4080 | // COM IP <--> interface |
4081 | // See FieldMarshaler for details. |
4082 | //======================================================================= |
4083 | VOID FieldMarshaler_Interface::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const |
4084 | { |
4085 | CONTRACTL |
4086 | { |
4087 | THROWS; |
4088 | GC_TRIGGERS; |
4089 | MODE_COOPERATIVE; |
4090 | PRECONDITION(CheckPointer(pNativeValue)); |
4091 | } |
4092 | CONTRACTL_END; |
4093 | |
4094 | IUnknown *pUnk = NULL; |
4095 | |
4096 | if (!m_pItfMT.IsNull()) |
4097 | { |
4098 | pUnk = GetComIPFromObjectRef(pCLRValue, GetInterfaceMethodTable()); |
4099 | } |
4100 | else if (!(m_dwFlags & ItfMarshalInfo::ITF_MARSHAL_USE_BASIC_ITF)) |
4101 | { |
4102 | pUnk = GetComIPFromObjectRef(pCLRValue, GetMethodTable()); |
4103 | } |
4104 | else |
4105 | { |
4106 | ComIpType ReqIpType = !!(m_dwFlags & ItfMarshalInfo::ITF_MARSHAL_DISP_ITF) ? ComIpType_Dispatch : ComIpType_Unknown; |
4107 | pUnk = GetComIPFromObjectRef(pCLRValue, ReqIpType, NULL); |
4108 | } |
4109 | |
4110 | MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, pUnk); |
4111 | } |
4112 | |
4113 | |
4114 | //======================================================================= |
4115 | // COM IP <--> interface |
4116 | // See FieldMarshaler for details. |
4117 | //======================================================================= |
4118 | VOID FieldMarshaler_Interface::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const |
4119 | { |
4120 | CONTRACTL |
4121 | { |
4122 | THROWS; |
4123 | GC_TRIGGERS; |
4124 | MODE_COOPERATIVE; |
4125 | PRECONDITION(CheckPointer(pNativeValue)); |
4126 | PRECONDITION(CheckPointer(ppProtectedCLRValue)); |
4127 | PRECONDITION(IsProtectedByGCFrame(ppProtectedCLRValue)); |
4128 | } |
4129 | CONTRACTL_END; |
4130 | |
4131 | IUnknown *pUnk = (IUnknown*)MAYBE_UNALIGNED_READ(pNativeValue, _PTR); |
4132 | |
4133 | MethodTable *pItfMT = GetInterfaceMethodTable(); |
4134 | if (pItfMT != NULL && !pItfMT->IsInterface()) |
4135 | pItfMT = NULL; |
4136 | |
4137 | GetObjectRefFromComIP( |
4138 | ppProtectedCLRValue, // Created object |
4139 | pUnk, // Interface pointer |
4140 | GetMethodTable(), // Class MT |
4141 | pItfMT, // Interface MT |
4142 | (m_dwFlags & ItfMarshalInfo::ITF_MARSHAL_CLASS_IS_HINT) // Flags |
4143 | ); |
4144 | } |
4145 | |
4146 | |
4147 | //======================================================================= |
4148 | // COM IP <--> interface |
4149 | // See FieldMarshaler for details. |
4150 | //======================================================================= |
4151 | VOID FieldMarshaler_Interface::DestroyNativeImpl(LPVOID pNativeValue) const |
4152 | { |
4153 | CONTRACTL |
4154 | { |
4155 | NOTHROW; |
4156 | GC_TRIGGERS; |
4157 | MODE_ANY; |
4158 | PRECONDITION(CheckPointer(pNativeValue)); |
4159 | } |
4160 | CONTRACTL_END; |
4161 | |
4162 | IUnknown *pUnk = (IUnknown*)MAYBE_UNALIGNED_READ(pNativeValue, _PTR); |
4163 | MAYBE_UNALIGNED_WRITE(pNativeValue, _PTR, NULL); |
4164 | |
4165 | if (pUnk != NULL) |
4166 | { |
4167 | ULONG cbRef = SafeRelease(pUnk); |
4168 | LogInteropRelease(pUnk, cbRef, "Field marshaler destroy native" ); |
4169 | } |
4170 | } |
4171 | |
4172 | #endif // FEATURE_COMINTEROP |
4173 | |
4174 | |
4175 | //======================================================================= |
4176 | // See FieldMarshaler for details. |
4177 | //======================================================================= |
4178 | VOID FieldMarshaler_Date::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const |
4179 | { |
4180 | CONTRACTL |
4181 | { |
4182 | THROWS; |
4183 | GC_TRIGGERS; |
4184 | MODE_COOPERATIVE; |
4185 | PRECONDITION(CheckPointer(pCLR)); |
4186 | PRECONDITION(CheckPointer(pNative)); |
4187 | } |
4188 | CONTRACTL_END; |
4189 | |
4190 | // <TODO> Handle unaligned native fields </TODO> |
4191 | *((DATE*)pNative) = COMDateTime::TicksToDoubleDate(*((INT64*)pCLR)); |
4192 | } |
4193 | |
4194 | |
4195 | //======================================================================= |
4196 | // See FieldMarshaler for details. |
4197 | //======================================================================= |
4198 | VOID FieldMarshaler_Date::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const |
4199 | { |
4200 | CONTRACTL |
4201 | { |
4202 | THROWS; |
4203 | GC_TRIGGERS; |
4204 | MODE_COOPERATIVE; |
4205 | PRECONDITION(CheckPointer(pNative)); |
4206 | PRECONDITION(CheckPointer(pCLR)); |
4207 | } |
4208 | CONTRACTL_END; |
4209 | |
4210 | // <TODO> Handle unaligned native fields </TODO> |
4211 | *((INT64*)pCLR) = COMDateTime::DoubleDateToTicks(*((DATE*)pNative)); |
4212 | } |
4213 | |
4214 | |
4215 | #ifdef FEATURE_COMINTEROP |
4216 | |
4217 | //======================================================================= |
4218 | // See FieldMarshaler for details. |
4219 | //======================================================================= |
4220 | VOID FieldMarshaler_Currency::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const |
4221 | { |
4222 | CONTRACTL |
4223 | { |
4224 | THROWS; |
4225 | GC_TRIGGERS; |
4226 | MODE_ANY; |
4227 | PRECONDITION(CheckPointer(pCLR)); |
4228 | PRECONDITION(CheckPointer(pNative)); |
4229 | } |
4230 | CONTRACTL_END; |
4231 | |
4232 | // no need to switch to preemptive mode because it's very primitive operaion, doesn't take |
4233 | // long and is guaranteed not to call 3rd party code. |
4234 | // But if we do need to switch to preemptive mode, we can't pass the managed pointer to native code directly |
4235 | HRESULT hr = VarCyFromDec( (DECIMAL *)pCLR, (CURRENCY*)pNative); |
4236 | if (FAILED(hr)) |
4237 | COMPlusThrowHR(hr); |
4238 | |
4239 | } |
4240 | |
4241 | |
4242 | //======================================================================= |
4243 | // See FieldMarshaler for details. |
4244 | //======================================================================= |
4245 | VOID FieldMarshaler_Currency::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const |
4246 | { |
4247 | CONTRACTL |
4248 | { |
4249 | THROWS; |
4250 | GC_TRIGGERS; |
4251 | MODE_ANY; |
4252 | PRECONDITION(CheckPointer(pNative)); |
4253 | PRECONDITION(CheckPointer(pCLR)); |
4254 | } |
4255 | CONTRACTL_END; |
4256 | |
4257 | // no need to switch to preemptive mode because it's very primitive operaion, doesn't take |
4258 | // long and is guaranteed not to call 3rd party code. |
4259 | // But if we do need to switch to preemptive mode, we can't pass the managed pointer to native code directly |
4260 | VarDecFromCyCanonicalize( *(CURRENCY*)pNative, (DECIMAL *)pCLR ); |
4261 | } |
4262 | |
4263 | VOID FieldMarshaler_DateTimeOffset::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const |
4264 | { |
4265 | CONTRACTL |
4266 | { |
4267 | THROWS; |
4268 | GC_TRIGGERS; |
4269 | MODE_COOPERATIVE; |
4270 | PRECONDITION(CheckPointer(pCLR)); |
4271 | PRECONDITION(CheckPointer(pNative)); |
4272 | } |
4273 | CONTRACTL_END; |
4274 | |
4275 | MethodDescCallSite convertToNative(METHOD__DATETIMEOFFSETMARSHALER__CONVERT_TO_NATIVE); |
4276 | ARG_SLOT args[] = |
4277 | { |
4278 | PtrToArgSlot(pCLR), |
4279 | PtrToArgSlot(pNative) |
4280 | }; |
4281 | convertToNative.Call(args); |
4282 | } |
4283 | |
4284 | VOID FieldMarshaler_DateTimeOffset::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const |
4285 | { |
4286 | CONTRACTL |
4287 | { |
4288 | THROWS; |
4289 | GC_TRIGGERS; |
4290 | MODE_COOPERATIVE; |
4291 | PRECONDITION(CheckPointer(pNative)); |
4292 | PRECONDITION(CheckPointer(pCLR)); |
4293 | } |
4294 | CONTRACTL_END; |
4295 | |
4296 | MethodDescCallSite convertToManaged(METHOD__DATETIMEOFFSETMARSHALER__CONVERT_TO_MANAGED); |
4297 | ARG_SLOT args[] = |
4298 | { |
4299 | PtrToArgSlot(pCLR), |
4300 | PtrToArgSlot(pNative) |
4301 | }; |
4302 | convertToManaged.Call(args); |
4303 | } |
4304 | |
4305 | #endif // FEATURE_COMINTEROP |
4306 | |
4307 | |
4308 | //======================================================================= |
4309 | // See FieldMarshaler for details. |
4310 | //======================================================================= |
4311 | VOID FieldMarshaler_Illegal::ScalarUpdateNativeImpl(LPVOID pCLR, LPVOID pNative) const |
4312 | { |
4313 | CONTRACTL |
4314 | { |
4315 | THROWS; |
4316 | GC_TRIGGERS; |
4317 | MODE_COOPERATIVE; |
4318 | PRECONDITION(CheckPointer(pCLR)); |
4319 | PRECONDITION(CheckPointer(pNative)); |
4320 | } |
4321 | CONTRACTL_END; |
4322 | |
4323 | DefineFullyQualifiedNameForClassW(); |
4324 | |
4325 | StackSString ssFieldName(SString::Utf8, GetFieldDesc()->GetName()); |
4326 | |
4327 | StackSString errorString(W("Unknown error." )); |
4328 | errorString.LoadResource(CCompRC::Error, m_resIDWhy); |
4329 | |
4330 | COMPlusThrow(kTypeLoadException, IDS_EE_BADMARSHALFIELD_ERROR_MSG, |
4331 | GetFullyQualifiedNameForClassW(GetFieldDesc()->GetEnclosingMethodTable()), |
4332 | ssFieldName.GetUnicode(), errorString.GetUnicode()); |
4333 | } |
4334 | |
4335 | |
4336 | //======================================================================= |
4337 | // See FieldMarshaler for details. |
4338 | //======================================================================= |
4339 | VOID FieldMarshaler_Illegal::ScalarUpdateCLRImpl(const VOID *pNative, LPVOID pCLR) const |
4340 | { |
4341 | CONTRACTL |
4342 | { |
4343 | THROWS; |
4344 | GC_TRIGGERS; |
4345 | MODE_COOPERATIVE; |
4346 | PRECONDITION(CheckPointer(pNative)); |
4347 | PRECONDITION(CheckPointer(pCLR)); |
4348 | } |
4349 | CONTRACTL_END; |
4350 | |
4351 | DefineFullyQualifiedNameForClassW(); |
4352 | |
4353 | StackSString ssFieldName(SString::Utf8, GetFieldDesc()->GetName()); |
4354 | |
4355 | StackSString errorString(W("Unknown error." )); |
4356 | errorString.LoadResource(CCompRC::Error,m_resIDWhy); |
4357 | |
4358 | COMPlusThrow(kTypeLoadException, IDS_EE_BADMARSHALFIELD_ERROR_MSG, |
4359 | GetFullyQualifiedNameForClassW(GetFieldDesc()->GetEnclosingMethodTable()), |
4360 | ssFieldName.GetUnicode(), errorString.GetUnicode()); |
4361 | } |
4362 | |
4363 | #ifdef FEATURE_COMINTEROP |
4364 | |
4365 | |
4366 | //======================================================================= |
4367 | // See FieldMarshaler for details. |
4368 | //======================================================================= |
4369 | VOID FieldMarshaler_Variant::UpdateNativeImpl(OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const |
4370 | { |
4371 | CONTRACTL |
4372 | { |
4373 | THROWS; |
4374 | GC_TRIGGERS; |
4375 | MODE_COOPERATIVE; |
4376 | PRECONDITION(CheckPointer(pNativeValue)); |
4377 | } |
4378 | CONTRACTL_END; |
4379 | |
4380 | OleVariant::MarshalOleVariantForObject(pCLRValue, (VARIANT*)pNativeValue); |
4381 | |
4382 | } |
4383 | |
4384 | |
4385 | //======================================================================= |
4386 | // See FieldMarshaler for details. |
4387 | //======================================================================= |
4388 | VOID FieldMarshaler_Variant::UpdateCLRImpl(const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const |
4389 | { |
4390 | CONTRACTL |
4391 | { |
4392 | THROWS; |
4393 | GC_TRIGGERS; |
4394 | MODE_COOPERATIVE; |
4395 | PRECONDITION(CheckPointer(pNativeValue)); |
4396 | PRECONDITION(CheckPointer(ppProtectedCLRValue)); |
4397 | } |
4398 | CONTRACTL_END; |
4399 | |
4400 | OleVariant::MarshalObjectForOleVariant((VARIANT*)pNativeValue, ppProtectedCLRValue); |
4401 | } |
4402 | |
4403 | |
4404 | //======================================================================= |
4405 | // See FieldMarshaler for details. |
4406 | //======================================================================= |
4407 | VOID FieldMarshaler_Variant::DestroyNativeImpl(LPVOID pNativeValue) const |
4408 | { |
4409 | CONTRACTL |
4410 | { |
4411 | NOTHROW; |
4412 | GC_TRIGGERS; |
4413 | MODE_ANY; |
4414 | PRECONDITION(CheckPointer(pNativeValue)); |
4415 | } |
4416 | CONTRACTL_END; |
4417 | |
4418 | SafeVariantClear( (VARIANT*)pNativeValue ); |
4419 | } |
4420 | |
4421 | #endif // FEATURE_COMINTEROP |
4422 | |
4423 | |
4424 | #ifdef _PREFAST_ |
4425 | #pragma warning(push) |
4426 | #pragma warning(disable:21000) // Suppress PREFast warning about overly large function |
4427 | #endif |
4428 | VOID NStructFieldTypeToString(FieldMarshaler* pFM, SString& strNStructFieldType) |
4429 | { |
4430 | CONTRACTL |
4431 | { |
4432 | THROWS; |
4433 | GC_NOTRIGGER; |
4434 | MODE_ANY; |
4435 | INJECT_FAULT(COMPlusThrowOM()); |
4436 | PRECONDITION(CheckPointer(pFM)); |
4437 | } |
4438 | CONTRACTL_END; |
4439 | |
4440 | NStructFieldType cls = pFM->GetNStructFieldType(); |
4441 | LPCWSTR strRetVal; |
4442 | CorElementType elemType = pFM->GetFieldDesc()->GetFieldType(); |
4443 | |
4444 | // Some NStruct Field Types have extra information and require special handling. |
4445 | if (cls == NFT_FIXEDCHARARRAYANSI) |
4446 | { |
4447 | strNStructFieldType.Printf(W("fixed array of ANSI char (size = %i bytes)" ), pFM->NativeSize()); |
4448 | return; |
4449 | } |
4450 | else if (cls == NFT_FIXEDARRAY) |
4451 | { |
4452 | VARTYPE vtElement = ((FieldMarshaler_FixedArray*)pFM)->GetElementVT(); |
4453 | TypeHandle thElement = ((FieldMarshaler_FixedArray*)pFM)->GetElementTypeHandle(); |
4454 | BOOL fElementTypeUserDefined = FALSE; |
4455 | |
4456 | // Determine if the array type is a user defined type. |
4457 | if (vtElement == VT_RECORD) |
4458 | { |
4459 | fElementTypeUserDefined = TRUE; |
4460 | } |
4461 | else if (vtElement == VT_UNKNOWN || vtElement == VT_DISPATCH) |
4462 | { |
4463 | fElementTypeUserDefined = !thElement.IsObjectType(); |
4464 | } |
4465 | |
4466 | // Retrieve the string representation for the VARTYPE. |
4467 | StackSString strVarType; |
4468 | MarshalInfo::VarTypeToString(vtElement, strVarType); |
4469 | |
4470 | MethodTable *pMT = ((FieldMarshaler_FixedArray*)pFM)->GetElementTypeHandle().GetMethodTable(); |
4471 | DefineFullyQualifiedNameForClassW(); |
4472 | WCHAR* szClassName = (WCHAR*)GetFullyQualifiedNameForClassW(pMT); |
4473 | |
4474 | if (fElementTypeUserDefined) |
4475 | { |
4476 | strNStructFieldType.Printf(W("fixed array of %s exposed as %s elements (array size = %i bytes)" ), |
4477 | szClassName, |
4478 | strVarType.GetUnicode(), pFM->NativeSize()); |
4479 | } |
4480 | else |
4481 | { |
4482 | strNStructFieldType.Printf(W("fixed array of %s (array size = %i bytes)" ), |
4483 | szClassName, pFM->NativeSize()); |
4484 | } |
4485 | |
4486 | return; |
4487 | } |
4488 | #ifdef FEATURE_COMINTEROP |
4489 | else if (cls == NFT_INTERFACE) |
4490 | { |
4491 | MethodTable *pItfMT = NULL; |
4492 | DWORD dwFlags = 0; |
4493 | |
4494 | ((FieldMarshaler_Interface*)pFM)->GetInterfaceInfo(&pItfMT, &dwFlags); |
4495 | |
4496 | if (dwFlags & ItfMarshalInfo::ITF_MARSHAL_DISP_ITF) |
4497 | { |
4498 | strNStructFieldType.Set(W("IDispatch " )); |
4499 | } |
4500 | else |
4501 | { |
4502 | strNStructFieldType.Set(W("IUnknown " )); |
4503 | } |
4504 | |
4505 | if (dwFlags & ItfMarshalInfo::ITF_MARSHAL_USE_BASIC_ITF) |
4506 | { |
4507 | strNStructFieldType.Append(W("(basic) " )); |
4508 | } |
4509 | |
4510 | |
4511 | if (pItfMT) |
4512 | { |
4513 | DefineFullyQualifiedNameForClassW(); |
4514 | GetFullyQualifiedNameForClassW(pItfMT); |
4515 | |
4516 | strNStructFieldType.Append(GetFullyQualifiedNameForClassW(pItfMT)); |
4517 | } |
4518 | |
4519 | return; |
4520 | } |
4521 | #ifdef FEATURE_CLASSIC_COMINTEROP |
4522 | else if (cls == NFT_SAFEARRAY) |
4523 | { |
4524 | VARTYPE vtElement = ((FieldMarshaler_SafeArray*)pFM)->GetElementVT(); |
4525 | TypeHandle thElement = ((FieldMarshaler_SafeArray*)pFM)->GetElementTypeHandle(); |
4526 | BOOL fElementTypeUserDefined = FALSE; |
4527 | |
4528 | // Determine if the array type is a user defined type. |
4529 | if (vtElement == VT_RECORD) |
4530 | { |
4531 | fElementTypeUserDefined = TRUE; |
4532 | } |
4533 | else if (vtElement == VT_UNKNOWN || vtElement == VT_DISPATCH) |
4534 | { |
4535 | fElementTypeUserDefined = !thElement.IsObjectType(); |
4536 | } |
4537 | |
4538 | // Retrieve the string representation for the VARTYPE. |
4539 | StackSString strVarType; |
4540 | MarshalInfo::VarTypeToString(vtElement, strVarType); |
4541 | |
4542 | |
4543 | StackSString strClassName; |
4544 | if (!thElement.IsNull()) |
4545 | { |
4546 | DefineFullyQualifiedNameForClassW(); |
4547 | MethodTable *pMT = ((FieldMarshaler_SafeArray*)pFM)->GetElementTypeHandle().GetMethodTable(); |
4548 | strClassName.Set((WCHAR*)GetFullyQualifiedNameForClassW(pMT)); |
4549 | } |
4550 | else |
4551 | { |
4552 | strClassName.Set(W("object" )); |
4553 | } |
4554 | |
4555 | if (fElementTypeUserDefined) |
4556 | { |
4557 | strNStructFieldType.Printf(W("safe array of %s exposed as %s elements (array size = %i bytes)" ), |
4558 | strClassName.GetUnicode(), |
4559 | strVarType.GetUnicode(), pFM->NativeSize()); |
4560 | } |
4561 | else |
4562 | { |
4563 | strNStructFieldType.Printf(W("safearray of %s (array size = %i bytes)" ), |
4564 | strClassName.GetUnicode(), pFM->NativeSize()); |
4565 | } |
4566 | |
4567 | return; |
4568 | } |
4569 | #endif // FEATURE_CLASSIC_COMINTEROP |
4570 | #endif // FEATURE_COMINTEROP |
4571 | else if (cls == NFT_NESTEDLAYOUTCLASS) |
4572 | { |
4573 | MethodTable *pMT = ((FieldMarshaler_NestedLayoutClass*)pFM)->GetMethodTable(); |
4574 | DefineFullyQualifiedNameForClassW(); |
4575 | strNStructFieldType.Printf(W("nested layout class %s" ), |
4576 | GetFullyQualifiedNameForClassW(pMT)); |
4577 | return; |
4578 | } |
4579 | else if (cls == NFT_NESTEDVALUECLASS) |
4580 | { |
4581 | MethodTable *pMT = ((FieldMarshaler_NestedValueClass*)pFM)->GetMethodTable(); |
4582 | DefineFullyQualifiedNameForClassW(); |
4583 | strNStructFieldType.Printf(W("nested value class %s" ), |
4584 | GetFullyQualifiedNameForClassW(pMT)); |
4585 | return; |
4586 | } |
4587 | else if (cls == NFT_COPY1) |
4588 | { |
4589 | // The following CorElementTypes are the only ones handled with FieldMarshaler_Copy1. |
4590 | switch (elemType) |
4591 | { |
4592 | case ELEMENT_TYPE_I1: |
4593 | strRetVal = W("SByte" ); |
4594 | break; |
4595 | |
4596 | case ELEMENT_TYPE_U1: |
4597 | strRetVal = W("Byte" ); |
4598 | break; |
4599 | |
4600 | default: |
4601 | strRetVal = W("Unknown" ); |
4602 | break; |
4603 | } |
4604 | } |
4605 | else if (cls == NFT_COPY2) |
4606 | { |
4607 | // The following CorElementTypes are the only ones handled with FieldMarshaler_Copy2. |
4608 | switch (elemType) |
4609 | { |
4610 | case ELEMENT_TYPE_CHAR: |
4611 | strRetVal = W("Unicode char" ); |
4612 | break; |
4613 | |
4614 | case ELEMENT_TYPE_I2: |
4615 | strRetVal = W("Int16" ); |
4616 | break; |
4617 | |
4618 | case ELEMENT_TYPE_U2: |
4619 | strRetVal = W("UInt16" ); |
4620 | break; |
4621 | |
4622 | default: |
4623 | strRetVal = W("Unknown" ); |
4624 | break; |
4625 | } |
4626 | } |
4627 | else if (cls == NFT_COPY4) |
4628 | { |
4629 | // The following CorElementTypes are the only ones handled with FieldMarshaler_Copy4. |
4630 | switch (elemType) |
4631 | { |
4632 | // At this point, ELEMENT_TYPE_I must be 4 bytes long. Same for ELEMENT_TYPE_U. |
4633 | case ELEMENT_TYPE_I: |
4634 | case ELEMENT_TYPE_I4: |
4635 | strRetVal = W("Int32" ); |
4636 | break; |
4637 | |
4638 | case ELEMENT_TYPE_U: |
4639 | case ELEMENT_TYPE_U4: |
4640 | strRetVal = W("UInt32" ); |
4641 | break; |
4642 | |
4643 | case ELEMENT_TYPE_R4: |
4644 | strRetVal = W("Single" ); |
4645 | break; |
4646 | |
4647 | case ELEMENT_TYPE_PTR: |
4648 | strRetVal = W("4-byte pointer" ); |
4649 | break; |
4650 | |
4651 | default: |
4652 | strRetVal = W("Unknown" ); |
4653 | break; |
4654 | } |
4655 | } |
4656 | else if (cls == NFT_COPY8) |
4657 | { |
4658 | // The following CorElementTypes are the only ones handled with FieldMarshaler_Copy8. |
4659 | switch (elemType) |
4660 | { |
4661 | // At this point, ELEMENT_TYPE_I must be 8 bytes long. Same for ELEMENT_TYPE_U. |
4662 | case ELEMENT_TYPE_I: |
4663 | case ELEMENT_TYPE_I8: |
4664 | strRetVal = W("Int64" ); |
4665 | break; |
4666 | |
4667 | case ELEMENT_TYPE_U: |
4668 | case ELEMENT_TYPE_U8: |
4669 | strRetVal = W("UInt64" ); |
4670 | break; |
4671 | |
4672 | case ELEMENT_TYPE_R8: |
4673 | strRetVal = W("Double" ); |
4674 | break; |
4675 | |
4676 | case ELEMENT_TYPE_PTR: |
4677 | strRetVal = W("8-byte pointer" ); |
4678 | break; |
4679 | |
4680 | default: |
4681 | strRetVal = W("Unknown" ); |
4682 | break; |
4683 | } |
4684 | } |
4685 | else if (cls == NFT_FIXEDSTRINGUNI) |
4686 | { |
4687 | int nativeSize = pFM->NativeSize(); |
4688 | int strLength = nativeSize / sizeof(WCHAR); |
4689 | |
4690 | strNStructFieldType.Printf(W("embedded LPWSTR (length %d)" ), strLength); |
4691 | |
4692 | return; |
4693 | } |
4694 | else if (cls == NFT_FIXEDSTRINGANSI) |
4695 | { |
4696 | int nativeSize = pFM->NativeSize(); |
4697 | int strLength = nativeSize / sizeof(CHAR); |
4698 | |
4699 | strNStructFieldType.Printf(W("embedded LPSTR (length %d)" ), strLength); |
4700 | |
4701 | return; |
4702 | } |
4703 | else |
4704 | { |
4705 | // All other NStruct Field Types which do not require special handling. |
4706 | switch (cls) |
4707 | { |
4708 | case NFT_BSTR: |
4709 | strRetVal = W("BSTR" ); |
4710 | break; |
4711 | #ifdef FEATURE_COMINTEROP |
4712 | case NFT_HSTRING: |
4713 | strRetVal = W("HSTRING" ); |
4714 | break; |
4715 | #endif // FEATURE_COMINTEROP |
4716 | case NFT_STRINGUNI: |
4717 | strRetVal = W("LPWSTR" ); |
4718 | break; |
4719 | case NFT_STRINGANSI: |
4720 | strRetVal = W("LPSTR" ); |
4721 | break; |
4722 | case NFT_DELEGATE: |
4723 | strRetVal = W("Delegate" ); |
4724 | break; |
4725 | #ifdef FEATURE_COMINTEROP |
4726 | case NFT_VARIANT: |
4727 | strRetVal = W("VARIANT" ); |
4728 | break; |
4729 | #endif // FEATURE_COMINTEROP |
4730 | case NFT_ANSICHAR: |
4731 | strRetVal = W("ANSI char" ); |
4732 | break; |
4733 | case NFT_WINBOOL: |
4734 | strRetVal = W("Windows Bool" ); |
4735 | break; |
4736 | case NFT_CBOOL: |
4737 | strRetVal = W("CBool" ); |
4738 | break; |
4739 | case NFT_DECIMAL: |
4740 | strRetVal = W("DECIMAL" ); |
4741 | break; |
4742 | case NFT_DATE: |
4743 | strRetVal = W("DATE" ); |
4744 | break; |
4745 | #ifdef FEATURE_COMINTEROP |
4746 | case NFT_VARIANTBOOL: |
4747 | strRetVal = W("VARIANT Bool" ); |
4748 | break; |
4749 | case NFT_CURRENCY: |
4750 | strRetVal = W("CURRENCY" ); |
4751 | break; |
4752 | #endif // FEATURE_COMINTEROP |
4753 | case NFT_ILLEGAL: |
4754 | strRetVal = W("illegal type" ); |
4755 | break; |
4756 | case NFT_SAFEHANDLE: |
4757 | strRetVal = W("SafeHandle" ); |
4758 | break; |
4759 | case NFT_CRITICALHANDLE: |
4760 | strRetVal = W("CriticalHandle" ); |
4761 | break; |
4762 | default: |
4763 | strRetVal = W("<UNKNOWN>" ); |
4764 | break; |
4765 | } |
4766 | } |
4767 | |
4768 | strNStructFieldType.Set(strRetVal); |
4769 | |
4770 | return; |
4771 | } |
4772 | #ifdef _PREFAST_ |
4773 | #pragma warning(pop) |
4774 | #endif |
4775 | |
4776 | #endif // CROSSGEN_COMPILE |
4777 | |
4778 | |
4779 | // |
4780 | // Implementation of the virtual functions using switch statements. |
4781 | // |
4782 | // We are not able bake pointers to the FieldMarshaller vtables into NGen images. We store |
4783 | // the field marshaller id instead, and implement the virtualization by switch based on the id. |
4784 | // |
4785 | |
4786 | #ifdef FEATURE_CLASSIC_COMINTEROP |
4787 | #define FieldMarshaler_SafeArray_Case(rettype, name, args) case NFT_SAFEARRAY: rettype ((FieldMarshaler_SafeArray*)this)->name##Impl args; break; |
4788 | #else |
4789 | #define FieldMarshaler_SafeArray_Case(rettype, name, args) |
4790 | #endif |
4791 | |
4792 | #ifdef FEATURE_COMINTEROP |
4793 | |
4794 | #define IMPLEMENT_FieldMarshaler_METHOD(ret, name, argsdecl, rettype, args) \ |
4795 | ret FieldMarshaler::name argsdecl { \ |
4796 | WRAPPER_NO_CONTRACT; \ |
4797 | switch (GetNStructFieldType()) { \ |
4798 | case NFT_STRINGUNI: rettype ((FieldMarshaler_StringUni*)this)->name##Impl args; break; \ |
4799 | case NFT_STRINGANSI: rettype ((FieldMarshaler_StringAnsi*)this)->name##Impl args; break; \ |
4800 | case NFT_STRINGUTF8: rettype ((FieldMarshaler_StringUtf8*)this)->name##Impl args; break; \ |
4801 | case NFT_FIXEDSTRINGUNI: rettype ((FieldMarshaler_FixedStringUni*)this)->name##Impl args; break; \ |
4802 | case NFT_FIXEDSTRINGANSI: rettype ((FieldMarshaler_FixedStringAnsi*)this)->name##Impl args; break; \ |
4803 | case NFT_FIXEDCHARARRAYANSI: rettype ((FieldMarshaler_FixedCharArrayAnsi*)this)->name##Impl args; break; \ |
4804 | case NFT_FIXEDARRAY: rettype ((FieldMarshaler_FixedArray*)this)->name##Impl args; break; \ |
4805 | case NFT_DELEGATE: rettype ((FieldMarshaler_Delegate*)this)->name##Impl args; break; \ |
4806 | case NFT_COPY1: rettype ((FieldMarshaler_Copy1*)this)->name##Impl args; break; \ |
4807 | case NFT_COPY2: rettype ((FieldMarshaler_Copy2*)this)->name##Impl args; break; \ |
4808 | case NFT_COPY4: rettype ((FieldMarshaler_Copy4*)this)->name##Impl args; break; \ |
4809 | case NFT_COPY8: rettype ((FieldMarshaler_Copy8*)this)->name##Impl args; break; \ |
4810 | case NFT_ANSICHAR: rettype ((FieldMarshaler_Ansi*)this)->name##Impl args; break; \ |
4811 | case NFT_WINBOOL: rettype ((FieldMarshaler_WinBool*)this)->name##Impl args; break; \ |
4812 | case NFT_NESTEDLAYOUTCLASS: rettype ((FieldMarshaler_NestedLayoutClass*)this)->name##Impl args; break; \ |
4813 | case NFT_NESTEDVALUECLASS: rettype ((FieldMarshaler_NestedValueClass*)this)->name##Impl args; break; \ |
4814 | case NFT_CBOOL: rettype ((FieldMarshaler_CBool*)this)->name##Impl args; break; \ |
4815 | case NFT_DATE: rettype ((FieldMarshaler_Date*)this)->name##Impl args; break; \ |
4816 | case NFT_DECIMAL: rettype ((FieldMarshaler_Decimal*)this)->name##Impl args; break; \ |
4817 | case NFT_INTERFACE: rettype ((FieldMarshaler_Interface*)this)->name##Impl args; break; \ |
4818 | case NFT_SAFEHANDLE: rettype ((FieldMarshaler_SafeHandle*)this)->name##Impl args; break; \ |
4819 | case NFT_CRITICALHANDLE: rettype ((FieldMarshaler_CriticalHandle*)this)->name##Impl args; break; \ |
4820 | FieldMarshaler_SafeArray_Case(rettype, name, args) \ |
4821 | case NFT_BSTR: rettype ((FieldMarshaler_BSTR*)this)->name##Impl args; break; \ |
4822 | case NFT_HSTRING: rettype ((FieldMarshaler_HSTRING*)this)->name##Impl args; break; \ |
4823 | case NFT_VARIANT: rettype ((FieldMarshaler_Variant*)this)->name##Impl args; break; \ |
4824 | case NFT_VARIANTBOOL: rettype ((FieldMarshaler_VariantBool*)this)->name##Impl args; break; \ |
4825 | case NFT_CURRENCY: rettype ((FieldMarshaler_Currency*)this)->name##Impl args; break; \ |
4826 | case NFT_DATETIMEOFFSET: rettype ((FieldMarshaler_DateTimeOffset*)this)->name##Impl args; break; \ |
4827 | case NFT_SYSTEMTYPE: rettype ((FieldMarshaler_SystemType *)this)->name##Impl args; break; \ |
4828 | case NFT_WINDOWSFOUNDATIONHRESULT: rettype ((FieldMarshaler_Exception*)this)->name##Impl args; break; \ |
4829 | case NFT_WINDOWSFOUNDATIONIREFERENCE: rettype ((FieldMarshaler_Nullable*)this)->name##Impl args; break; \ |
4830 | case NFT_ILLEGAL: rettype ((FieldMarshaler_Illegal*)this)->name##Impl args; break; \ |
4831 | default: UNREACHABLE_MSG("unexpected type of FieldMarshaler"); break; \ |
4832 | } \ |
4833 | } |
4834 | |
4835 | #else // FEATURE_COMINTEROP |
4836 | |
4837 | #define IMPLEMENT_FieldMarshaler_METHOD(ret, name, argsdecl, rettype, args) \ |
4838 | ret FieldMarshaler::name argsdecl { \ |
4839 | WRAPPER_NO_CONTRACT; \ |
4840 | switch (GetNStructFieldType()) { \ |
4841 | case NFT_STRINGUNI: rettype ((FieldMarshaler_StringUni*)this)->name##Impl args; break; \ |
4842 | case NFT_STRINGANSI: rettype ((FieldMarshaler_StringAnsi*)this)->name##Impl args; break; \ |
4843 | case NFT_STRINGUTF8: rettype ((FieldMarshaler_StringUtf8*)this)->name##Impl args; break; \ |
4844 | case NFT_FIXEDSTRINGUNI: rettype ((FieldMarshaler_FixedStringUni*)this)->name##Impl args; break; \ |
4845 | case NFT_FIXEDSTRINGANSI: rettype ((FieldMarshaler_FixedStringAnsi*)this)->name##Impl args; break; \ |
4846 | case NFT_FIXEDCHARARRAYANSI: rettype ((FieldMarshaler_FixedCharArrayAnsi*)this)->name##Impl args; break; \ |
4847 | case NFT_FIXEDARRAY: rettype ((FieldMarshaler_FixedArray*)this)->name##Impl args; break; \ |
4848 | case NFT_DELEGATE: rettype ((FieldMarshaler_Delegate*)this)->name##Impl args; break; \ |
4849 | case NFT_COPY1: rettype ((FieldMarshaler_Copy1*)this)->name##Impl args; break; \ |
4850 | case NFT_COPY2: rettype ((FieldMarshaler_Copy2*)this)->name##Impl args; break; \ |
4851 | case NFT_COPY4: rettype ((FieldMarshaler_Copy4*)this)->name##Impl args; break; \ |
4852 | case NFT_COPY8: rettype ((FieldMarshaler_Copy8*)this)->name##Impl args; break; \ |
4853 | case NFT_ANSICHAR: rettype ((FieldMarshaler_Ansi*)this)->name##Impl args; break; \ |
4854 | case NFT_WINBOOL: rettype ((FieldMarshaler_WinBool*)this)->name##Impl args; break; \ |
4855 | case NFT_NESTEDLAYOUTCLASS: rettype ((FieldMarshaler_NestedLayoutClass*)this)->name##Impl args; break; \ |
4856 | case NFT_NESTEDVALUECLASS: rettype ((FieldMarshaler_NestedValueClass*)this)->name##Impl args; break; \ |
4857 | case NFT_CBOOL: rettype ((FieldMarshaler_CBool*)this)->name##Impl args; break; \ |
4858 | case NFT_DATE: rettype ((FieldMarshaler_Date*)this)->name##Impl args; break; \ |
4859 | case NFT_DECIMAL: rettype ((FieldMarshaler_Decimal*)this)->name##Impl args; break; \ |
4860 | case NFT_SAFEHANDLE: rettype ((FieldMarshaler_SafeHandle*)this)->name##Impl args; break; \ |
4861 | case NFT_CRITICALHANDLE: rettype ((FieldMarshaler_CriticalHandle*)this)->name##Impl args; break; \ |
4862 | case NFT_BSTR: rettype ((FieldMarshaler_BSTR*)this)->name##Impl args; break; \ |
4863 | case NFT_ILLEGAL: rettype ((FieldMarshaler_Illegal*)this)->name##Impl args; break; \ |
4864 | default: UNREACHABLE_MSG("unexpected type of FieldMarshaler"); break; \ |
4865 | } \ |
4866 | } |
4867 | |
4868 | #endif // FEATURE_COMINTEROP |
4869 | |
4870 | |
4871 | IMPLEMENT_FieldMarshaler_METHOD(UINT32, NativeSize, |
4872 | () const, |
4873 | return, |
4874 | ()) |
4875 | |
4876 | IMPLEMENT_FieldMarshaler_METHOD(UINT32, AlignmentRequirement, |
4877 | () const, |
4878 | return, |
4879 | ()) |
4880 | |
4881 | IMPLEMENT_FieldMarshaler_METHOD(BOOL, IsScalarMarshaler, |
4882 | () const, |
4883 | return, |
4884 | ()) |
4885 | |
4886 | IMPLEMENT_FieldMarshaler_METHOD(BOOL, IsNestedValueClassMarshaler, |
4887 | () const, |
4888 | return, |
4889 | ()) |
4890 | |
4891 | #ifndef CROSSGEN_COMPILE |
4892 | IMPLEMENT_FieldMarshaler_METHOD(VOID, UpdateNative, |
4893 | (OBJECTREF* pCLRValue, LPVOID pNativeValue, OBJECTREF *ppCleanupWorkListOnStack) const, |
4894 | , |
4895 | (pCLRValue, pNativeValue, ppCleanupWorkListOnStack)) |
4896 | |
4897 | IMPLEMENT_FieldMarshaler_METHOD(VOID, UpdateCLR, |
4898 | (const VOID *pNativeValue, OBJECTREF *ppProtectedCLRValue, OBJECTREF *ppProtectedOldCLRValue) const, |
4899 | , |
4900 | (pNativeValue, ppProtectedCLRValue, ppProtectedOldCLRValue)) |
4901 | |
4902 | IMPLEMENT_FieldMarshaler_METHOD(VOID, DestroyNative, |
4903 | (LPVOID pNativeValue) const, |
4904 | , |
4905 | (pNativeValue)) |
4906 | |
4907 | IMPLEMENT_FieldMarshaler_METHOD(VOID, ScalarUpdateNative, |
4908 | (LPVOID pCLR, LPVOID pNative) const, |
4909 | return, |
4910 | (pCLR, pNative)) |
4911 | |
4912 | IMPLEMENT_FieldMarshaler_METHOD(VOID, ScalarUpdateCLR, |
4913 | (const VOID *pNative, LPVOID pCLR) const, |
4914 | return, |
4915 | (pNative, pCLR)) |
4916 | |
4917 | IMPLEMENT_FieldMarshaler_METHOD(VOID, NestedValueClassUpdateNative, |
4918 | (const VOID **ppProtectedCLR, SIZE_T startoffset, LPVOID pNative, OBJECTREF *ppCleanupWorkListOnStack) const, |
4919 | , |
4920 | (ppProtectedCLR, startoffset, pNative, ppCleanupWorkListOnStack)) |
4921 | |
4922 | IMPLEMENT_FieldMarshaler_METHOD(VOID, NestedValueClassUpdateCLR, |
4923 | (const VOID *pNative, LPVOID *ppProtectedCLR, SIZE_T startoffset) const, |
4924 | , |
4925 | (pNative, ppProtectedCLR, startoffset)) |
4926 | #endif // CROSSGEN_COMPILE |
4927 | |
4928 | #ifdef FEATURE_NATIVE_IMAGE_GENERATION |
4929 | IMPLEMENT_FieldMarshaler_METHOD(void, Save, |
4930 | (DataImage *image), |
4931 | , |
4932 | (image)) |
4933 | |
4934 | IMPLEMENT_FieldMarshaler_METHOD(void, Fixup, |
4935 | (DataImage *image), |
4936 | , |
4937 | (image)) |
4938 | #endif // FEATURE_NATIVE_IMAGE_GENERATION |
4939 | |
4940 | IMPLEMENT_FieldMarshaler_METHOD(void, Restore, |
4941 | (), |
4942 | , |
4943 | ()) |
4944 | |
4945 | #ifndef DACCESS_COMPILE |
4946 | IMPLEMENT_FieldMarshaler_METHOD(VOID, CopyTo, |
4947 | (VOID *pDest, SIZE_T destSize) const, |
4948 | , |
4949 | (pDest, destSize)) |
4950 | #endif // !DACCESS_COMPILE |
4951 | |