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: mlinfo.cpp
6//
7
8//
9
10
11#include "common.h"
12#include "mlinfo.h"
13#include "dllimport.h"
14#include "sigformat.h"
15#include "eeconfig.h"
16#include "eehash.h"
17#include "../dlls/mscorrc/resource.h"
18#include "mdaassistants.h"
19#include "typeparse.h"
20#include "comdelegate.h"
21#include "olevariant.h"
22#include "ilmarshalers.h"
23#include "interoputil.h"
24
25#ifdef FEATURE_PREJIT
26 #include "dataimage.h"
27#endif
28
29#ifdef FEATURE_COMINTEROP
30#include "comcallablewrapper.h"
31#include "runtimecallablewrapper.h"
32#include "dispparammarshaler.h"
33#include "winrttypenameconverter.h"
34#endif // FEATURE_COMINTEROP
35
36
37#ifndef lengthof
38 #define lengthof(rg) (sizeof(rg)/sizeof(rg[0]))
39#endif
40
41
42#ifdef FEATURE_COMINTEROP
43 DEFINE_ASM_QUAL_TYPE_NAME(ENUMERATOR_TO_ENUM_VARIANT_CM_NAME, g_EnumeratorToEnumClassName, g_CorelibAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken);
44
45 static const int ENUMERATOR_TO_ENUM_VARIANT_CM_NAME_LEN = lengthof(ENUMERATOR_TO_ENUM_VARIANT_CM_NAME);
46 static const char ENUMERATOR_TO_ENUM_VARIANT_CM_COOKIE[] = {""};
47 static const int ENUMERATOR_TO_ENUM_VARIANT_CM_COOKIE_LEN = lengthof(ENUMERATOR_TO_ENUM_VARIANT_CM_COOKIE);
48
49 DEFINE_ASM_QUAL_TYPE_NAME(COLOR_TRANSLATOR_ASM_QUAL_TYPE_NAME, g_ColorTranslatorClassName, g_DrawingAsmName, VER_ASSEMBLYVERSION_STR, g_FXKeyToken);
50 DEFINE_ASM_QUAL_TYPE_NAME(COLOR_ASM_QUAL_TYPE_NAME, g_ColorClassName, g_DrawingAsmName, VER_ASSEMBLYVERSION_STR, g_FXKeyToken);
51
52 DEFINE_ASM_QUAL_TYPE_NAME(URI_ASM_QUAL_TYPE_NAME, g_SystemUriClassName, g_SystemRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_FXKeyToken);
53
54 DEFINE_ASM_QUAL_TYPE_NAME(NCCEVENTARGS_ASM_QUAL_TYPE_NAME, g_NotifyCollectionChangedEventArgsName, g_ObjectModelAsmName, VER_ASSEMBLYVERSION_STR, g_FXKeyToken);
55 DEFINE_ASM_QUAL_TYPE_NAME(NCCEVENTARGS_MARSHALER_ASM_QUAL_TYPE_NAME, g_NotifyCollectionChangedEventArgsMarshalerName, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken);
56
57
58 DEFINE_ASM_QUAL_TYPE_NAME(PCEVENTARGS_ASM_QUAL_TYPE_NAME, g_PropertyChangedEventArgsName, g_ObjectModelAsmName, VER_ASSEMBLYVERSION_STR, g_FXKeyToken);
59 DEFINE_ASM_QUAL_TYPE_NAME(PCEVENTARGS_MARSHALER_ASM_QUAL_TYPE_NAME, g_PropertyChangedEventArgsMarshalerName, g_SystemRuntimeWindowsRuntimeAsmName, VER_ASSEMBLYVERSION_STR, g_ECMAKeyToken);
60
61
62 #define OLECOLOR_TO_SYSTEMCOLOR_METH_NAME "FromOle"
63 #define SYSTEMCOLOR_TO_OLECOLOR_METH_NAME "ToOle"
64
65 #define EVENTARGS_TO_WINRT_EVENTARGS_METH_NAME "ConvertToNative"
66 #define WINRT_EVENTARGS_TO_EVENTARGS_METH_NAME "ConvertToManaged"
67
68 #define ORIGINALSTRING_PROPERTY_NAME "OriginalString"
69#endif // FEATURE_COMINTEROP
70
71
72
73#define INITIAL_NUM_CMHELPER_HASHTABLE_BUCKETS 32
74#define INITIAL_NUM_CMINFO_HASHTABLE_BUCKETS 32
75#define DEBUG_CONTEXT_STR_LEN 2000
76
77
78//-------------------------------------------------------------------------------------
79// Return the copy ctor for a VC class (if any exists)
80//-------------------------------------------------------------------------------------
81void FindCopyCtor(Module *pModule, MethodTable *pMT, MethodDesc **pMDOut)
82{
83 CONTRACTL
84 {
85 THROWS;
86 GC_TRIGGERS; // CompareTypeTokens may trigger GC
87 MODE_ANY;
88 }
89 CONTRACTL_END;
90
91 *pMDOut = NULL;
92
93 HRESULT hr;
94 mdMethodDef tk;
95 mdTypeDef cl = pMT->GetCl();
96 TypeHandle th = TypeHandle(pMT);
97 SigTypeContext typeContext(th);
98
99 IMDInternalImport *pInternalImport = pModule->GetMDImport();
100 MDEnumHolder hEnumMethod(pInternalImport);
101
102 //
103 // First try for the new syntax: <MarshalCopy>
104 //
105 IfFailThrow(pInternalImport->EnumInit(mdtMethodDef, cl, &hEnumMethod));
106
107 while (pInternalImport->EnumNext(&hEnumMethod, &tk))
108 {
109 _ASSERTE(TypeFromToken(tk) == mdtMethodDef);
110 DWORD dwMemberAttrs;
111 IfFailThrow(pInternalImport->GetMethodDefProps(tk, &dwMemberAttrs));
112
113 if (IsMdSpecialName(dwMemberAttrs))
114 {
115 ULONG cSig;
116 PCCOR_SIGNATURE pSig;
117 LPCSTR pName;
118 IfFailThrow(pInternalImport->GetNameAndSigOfMethodDef(tk, &pSig, &cSig, &pName));
119
120 const char *pBaseName = "<MarshalCopy>";
121 int ncBaseName = (int)strlen(pBaseName);
122 int nc = (int)strlen(pName);
123 if (nc >= ncBaseName && 0 == strcmp(pName + nc - ncBaseName, pBaseName))
124 {
125 MetaSig msig(pSig, cSig, pModule, &typeContext);
126
127 // Looking for the prototype void <MarshalCopy>(Ptr VC, Ptr VC);
128 if (msig.NumFixedArgs() == 2)
129 {
130 if (msig.GetReturnType() == ELEMENT_TYPE_VOID)
131 {
132 if (msig.NextArg() == ELEMENT_TYPE_PTR)
133 {
134 SigPointer sp1 = msig.GetArgProps();
135 IfFailThrow(sp1.GetElemType(NULL));
136 CorElementType eType;
137 IfFailThrow(sp1.GetElemType(&eType));
138 if (eType == ELEMENT_TYPE_VALUETYPE)
139 {
140 mdToken tk1;
141 IfFailThrow(sp1.GetToken(&tk1));
142 hr = CompareTypeTokensNT(tk1, cl, pModule, pModule);
143 if (FAILED(hr))
144 {
145 pInternalImport->EnumClose(&hEnumMethod);
146 ThrowHR(hr);
147 }
148
149 if (hr == S_OK)
150 {
151 if (msig.NextArg() == ELEMENT_TYPE_PTR)
152 {
153 SigPointer sp2 = msig.GetArgProps();
154 IfFailThrow(sp2.GetElemType(NULL));
155 IfFailThrow(sp2.GetElemType(&eType));
156 if (eType == ELEMENT_TYPE_VALUETYPE)
157 {
158 mdToken tk2;
159 IfFailThrow(sp2.GetToken(&tk2));
160
161 hr = (tk2 == tk1) ? S_OK : CompareTypeTokensNT(tk2, cl, pModule, pModule);
162 if (hr == S_OK)
163 {
164 *pMDOut = pModule->LookupMethodDef(tk);
165 return;
166 }
167 }
168 }
169 }
170 }
171 }
172 }
173 }
174 }
175 }
176 }
177
178 //
179 // Next try the old syntax: global .__ctor
180 //
181 IfFailThrow(pInternalImport->EnumGlobalFunctionsInit(&hEnumMethod));
182
183 while (pInternalImport->EnumNext(&hEnumMethod, &tk))
184 {
185 _ASSERTE(TypeFromToken(tk) == mdtMethodDef);
186 DWORD dwMemberAttrs;
187 IfFailThrow(pInternalImport->GetMethodDefProps(tk, &dwMemberAttrs));
188
189 if (IsMdSpecialName(dwMemberAttrs))
190 {
191 ULONG cSig;
192 PCCOR_SIGNATURE pSig;
193 LPCSTR pName;
194 IfFailThrow(pInternalImport->GetNameAndSigOfMethodDef(tk, &pSig, &cSig, &pName));
195
196 const char *pBaseName = ".__ctor";
197 int ncBaseName = (int)strlen(pBaseName);
198 int nc = (int)strlen(pName);
199 if (nc >= ncBaseName && 0 == strcmp(pName + nc - ncBaseName, pBaseName))
200 {
201
202 MetaSig msig(pSig, cSig, pModule, &typeContext);
203
204 // Looking for the prototype Ptr VC __ctor(Ptr VC, ByRef VC);
205 if (msig.NumFixedArgs() == 2)
206 {
207 if (msig.GetReturnType() == ELEMENT_TYPE_PTR)
208 {
209 SigPointer spret = msig.GetReturnProps();
210 IfFailThrow(spret.GetElemType(NULL));
211 CorElementType eType;
212 IfFailThrow(spret.GetElemType(&eType));
213 if (eType == ELEMENT_TYPE_VALUETYPE)
214 {
215 mdToken tk0;
216 IfFailThrow(spret.GetToken(&tk0));
217 hr = CompareTypeTokensNT(tk0, cl, pModule, pModule);
218 if (FAILED(hr))
219 {
220 pInternalImport->EnumClose(&hEnumMethod);
221 ThrowHR(hr);
222 }
223
224 if (hr == S_OK)
225 {
226 if (msig.NextArg() == ELEMENT_TYPE_PTR)
227 {
228 SigPointer sp1 = msig.GetArgProps();
229 IfFailThrow(sp1.GetElemType(NULL));
230 IfFailThrow(sp1.GetElemType(&eType));
231 if (eType == ELEMENT_TYPE_VALUETYPE)
232 {
233 mdToken tk1;
234 IfFailThrow(sp1.GetToken(&tk1));
235 hr = (tk1 == tk0) ? S_OK : CompareTypeTokensNT(tk1, cl, pModule, pModule);
236 if (FAILED(hr))
237 {
238 pInternalImport->EnumClose(&hEnumMethod);
239 ThrowHR(hr);
240 }
241
242 if (hr == S_OK)
243 {
244 if (msig.NextArg() == ELEMENT_TYPE_PTR &&
245 msig.GetArgProps().HasCustomModifier(pModule, "Microsoft.VisualC.IsCXXReferenceModifier", ELEMENT_TYPE_CMOD_OPT))
246 {
247 SigPointer sp2 = msig.GetArgProps();
248 IfFailThrow(sp2.GetElemType(NULL));
249 IfFailThrow(sp2.GetElemType(&eType));
250 if (eType == ELEMENT_TYPE_VALUETYPE)
251 {
252 mdToken tk2;
253 IfFailThrow(sp2.GetToken(&tk2));
254
255 hr = (tk2 == tk0) ? S_OK : CompareTypeTokensNT(tk2, cl, pModule, pModule);
256 if (hr == S_OK)
257 {
258 *pMDOut = pModule->LookupMethodDef(tk);
259 return;
260 }
261 }
262 }
263 }
264 }
265 }
266 }
267 }
268 }
269 }
270 }
271 }
272 }
273}
274
275
276//-------------------------------------------------------------------------------------
277// Return the destructor for a VC class (if any exists)
278//-------------------------------------------------------------------------------------
279void FindDtor(Module *pModule, MethodTable *pMT, MethodDesc **pMDOut)
280{
281 CONTRACTL
282 {
283 THROWS;
284 GC_TRIGGERS; // CompareTypeTokens may trigger GC
285 MODE_ANY;
286 }
287 CONTRACTL_END;
288
289 *pMDOut = NULL;
290
291 HRESULT hr;
292 mdMethodDef tk;
293 mdTypeDef cl = pMT->GetCl();
294 TypeHandle th = TypeHandle(pMT);
295 SigTypeContext typeContext(th);
296
297 IMDInternalImport *pInternalImport = pModule->GetMDImport();
298 MDEnumHolder hEnumMethod(pInternalImport);
299
300 //
301 // First try for the new syntax: <MarshalDestroy>
302 //
303 IfFailThrow(pInternalImport->EnumInit(mdtMethodDef, cl, &hEnumMethod));
304
305 while (pInternalImport->EnumNext(&hEnumMethod, &tk))
306 {
307 _ASSERTE(TypeFromToken(tk) == mdtMethodDef);
308 DWORD dwMemberAttrs;
309 IfFailThrow(pInternalImport->GetMethodDefProps(tk, &dwMemberAttrs));
310
311 if (IsMdSpecialName(dwMemberAttrs))
312 {
313 ULONG cSig;
314 PCCOR_SIGNATURE pSig;
315 LPCSTR pName;
316 IfFailThrow(pInternalImport->GetNameAndSigOfMethodDef(tk, &pSig, &cSig, &pName));
317
318 const char *pBaseName = "<MarshalDestroy>";
319 int ncBaseName = (int)strlen(pBaseName);
320 int nc = (int)strlen(pName);
321 if (nc >= ncBaseName && 0 == strcmp(pName + nc - ncBaseName, pBaseName))
322 {
323 MetaSig msig(pSig, cSig, pModule, &typeContext);
324
325 // Looking for the prototype void <MarshalDestroy>(Ptr VC);
326 if (msig.NumFixedArgs() == 1)
327 {
328 if (msig.GetReturnType() == ELEMENT_TYPE_VOID)
329 {
330 if (msig.NextArg() == ELEMENT_TYPE_PTR)
331 {
332 SigPointer sp1 = msig.GetArgProps();
333 IfFailThrow(sp1.GetElemType(NULL));
334 CorElementType eType;
335 IfFailThrow(sp1.GetElemType(&eType));
336 if (eType == ELEMENT_TYPE_VALUETYPE)
337 {
338 mdToken tk1;
339 IfFailThrow(sp1.GetToken(&tk1));
340
341 hr = CompareTypeTokensNT(tk1, cl, pModule, pModule);
342 IfFailThrow(hr);
343
344 if (hr == S_OK)
345 {
346 *pMDOut = pModule->LookupMethodDef(tk);
347 return;
348 }
349 }
350 }
351 }
352 }
353 }
354 }
355 }
356
357
358 //
359 // Next try the old syntax: global .__dtor
360 //
361 IfFailThrow(pInternalImport->EnumGlobalFunctionsInit(&hEnumMethod));
362
363 while (pInternalImport->EnumNext(&hEnumMethod, &tk))
364 {
365 _ASSERTE(TypeFromToken(tk) == mdtMethodDef);
366 ULONG cSig;
367 PCCOR_SIGNATURE pSig;
368 LPCSTR pName;
369 IfFailThrow(pInternalImport->GetNameAndSigOfMethodDef(tk, &pSig, &cSig, &pName));
370
371 const char *pBaseName = ".__dtor";
372 int ncBaseName = (int)strlen(pBaseName);
373 int nc = (int)strlen(pName);
374 if (nc >= ncBaseName && 0 == strcmp(pName + nc - ncBaseName, pBaseName))
375 {
376 MetaSig msig(pSig, cSig, pModule, &typeContext);
377
378 // Looking for the prototype void __dtor(Ptr VC);
379 if (msig.NumFixedArgs() == 1)
380 {
381 if (msig.GetReturnType() == ELEMENT_TYPE_VOID)
382 {
383 if (msig.NextArg() == ELEMENT_TYPE_PTR)
384 {
385 SigPointer sp1 = msig.GetArgProps();
386 IfFailThrow(sp1.GetElemType(NULL));
387 CorElementType eType;
388 IfFailThrow(sp1.GetElemType(&eType));
389 if (eType == ELEMENT_TYPE_VALUETYPE)
390 {
391 mdToken tk1;
392 IfFailThrow(sp1.GetToken(&tk1));
393 hr = CompareTypeTokensNT(tk1, cl, pModule, pModule);
394 if (FAILED(hr))
395 {
396 pInternalImport->EnumClose(&hEnumMethod);
397 ThrowHR(hr);
398 }
399
400 if (hr == S_OK)
401 {
402 *pMDOut = pModule->LookupMethodDef(tk);
403 return;
404 }
405 }
406 }
407 }
408 }
409 }
410 }
411}
412
413//==========================================================================
414// Set's up the custom marshaler information.
415//==========================================================================
416CustomMarshalerHelper *SetupCustomMarshalerHelper(LPCUTF8 strMarshalerTypeName, DWORD cMarshalerTypeNameBytes, LPCUTF8 strCookie, DWORD cCookieStrBytes, Assembly *pAssembly, TypeHandle hndManagedType)
417{
418#ifndef CROSSGEN_COMPILE
419 CONTRACT (CustomMarshalerHelper*)
420 {
421 THROWS;
422 GC_TRIGGERS;
423 MODE_ANY;
424 PRECONDITION(CheckPointer(pAssembly));
425 POSTCONDITION(CheckPointer(RETVAL));
426 }
427 CONTRACT_END;
428
429 EEMarshalingData *pMarshalingData = NULL;
430
431 // The assembly is not shared so we use the current app domain's marshaling data.
432 pMarshalingData = GetThread()->GetDomain()->GetMarshalingData();
433
434 // Retrieve the custom marshaler helper from the EE marshaling data.
435 RETURN pMarshalingData->GetCustomMarshalerHelper(pAssembly, hndManagedType, strMarshalerTypeName, cMarshalerTypeNameBytes, strCookie, cCookieStrBytes);
436#else
437 _ASSERTE(false);
438 RETURN NULL;
439#endif
440}
441
442//==========================================================================
443// Return: S_OK if there is valid data to compress
444// S_FALSE if at end of data block
445// E_FAIL if corrupt data found
446//==========================================================================
447HRESULT CheckForCompressedData(PCCOR_SIGNATURE pvNativeTypeStart, PCCOR_SIGNATURE pvNativeType, ULONG cbNativeType)
448{
449 CONTRACTL
450 {
451 NOTHROW;
452 GC_NOTRIGGER;
453 MODE_ANY;
454 }
455 CONTRACTL_END;
456
457 if (pvNativeTypeStart + cbNativeType == pvNativeType)
458 { // end of data block
459 return S_FALSE;
460 }
461
462 ULONG ulDummy;
463 BYTE const *pbDummy;
464 return CPackedLen::SafeGetLength((BYTE const *)pvNativeType,
465 (BYTE const *)pvNativeTypeStart + cbNativeType,
466 &ulDummy,
467 &pbDummy);
468}
469
470//==========================================================================
471// Parse and validate the NATIVE_TYPE_ metadata.
472// Note! NATIVE_TYPE_ metadata is optional. If it's not present, this
473// routine sets NativeTypeParamInfo->m_NativeType to NATIVE_TYPE_DEFAULT.
474//==========================================================================
475BOOL ParseNativeTypeInfo(NativeTypeParamInfo* pParamInfo, PCCOR_SIGNATURE pvNativeType, ULONG cbNativeType);
476
477BOOL ParseNativeTypeInfo(mdToken token,
478 IMDInternalImport* pScope,
479 NativeTypeParamInfo* pParamInfo)
480{
481 CONTRACTL
482 {
483 NOTHROW;
484 GC_NOTRIGGER;
485 MODE_ANY;
486 }
487 CONTRACTL_END;
488
489 PCCOR_SIGNATURE pvNativeType;
490 ULONG cbNativeType;
491
492 if (token == mdParamDefNil || pScope->GetFieldMarshal(token, &pvNativeType, &cbNativeType) != S_OK)
493 return TRUE;
494
495 return ParseNativeTypeInfo(pParamInfo, pvNativeType, cbNativeType);
496}
497
498BOOL ParseNativeTypeInfo(NativeTypeParamInfo* pParamInfo,
499 PCCOR_SIGNATURE pvNativeType,
500 ULONG cbNativeType)
501{
502 LIMITED_METHOD_CONTRACT;
503 HRESULT hr;
504
505 PCCOR_SIGNATURE pvNativeTypeStart = pvNativeType;
506 PCCOR_SIGNATURE pvNativeTypeEnd = pvNativeType + cbNativeType;
507
508 if (cbNativeType == 0)
509 return FALSE; // Zero-length NATIVE_TYPE block
510
511 pParamInfo->m_NativeType = (CorNativeType)*(pvNativeType++);
512 ULONG strLen = 0;
513
514 // Retrieve any extra information associated with the native type.
515 switch (pParamInfo->m_NativeType)
516 {
517#ifdef FEATURE_COMINTEROP
518 case NATIVE_TYPE_INTF:
519 case NATIVE_TYPE_IUNKNOWN:
520 case NATIVE_TYPE_IDISPATCH:
521 if (S_OK != CheckForCompressedData(pvNativeTypeStart, pvNativeType, cbNativeType))
522 return TRUE;
523
524 pParamInfo->m_IidParamIndex = (int)CorSigUncompressData(pvNativeType);
525 break;
526#endif
527
528 case NATIVE_TYPE_FIXEDARRAY:
529
530 if (S_OK != CheckForCompressedData(pvNativeTypeStart, pvNativeType, cbNativeType))
531 return FALSE;
532
533 pParamInfo->m_Additive = CorSigUncompressData(pvNativeType);
534
535 if (S_OK != CheckForCompressedData(pvNativeTypeStart, pvNativeType, cbNativeType))
536 return TRUE;
537
538 pParamInfo->m_ArrayElementType = (CorNativeType)CorSigUncompressData(pvNativeType);
539 break;
540
541 case NATIVE_TYPE_FIXEDSYSSTRING:
542 if (S_OK != CheckForCompressedData(pvNativeTypeStart, pvNativeType, cbNativeType))
543 return FALSE;
544
545 pParamInfo->m_Additive = CorSigUncompressData(pvNativeType);
546 break;
547
548#ifdef FEATURE_COMINTEROP
549 case NATIVE_TYPE_SAFEARRAY:
550 // Check for the safe array element type.
551 hr = CheckForCompressedData(pvNativeTypeStart, pvNativeType, cbNativeType);
552 if (FAILED(hr))
553 return FALSE;
554
555 if (hr == S_OK)
556 pParamInfo->m_SafeArrayElementVT = (VARTYPE) (CorSigUncompressData(/*modifies*/pvNativeType));
557
558 // Extract the name of the record type's.
559 if (S_OK == CheckForCompressedData(pvNativeTypeStart, pvNativeType, cbNativeType))
560 {
561 hr = CPackedLen::SafeGetData((BYTE const *)pvNativeType,
562 (BYTE const *)pvNativeTypeEnd,
563 &strLen,
564 (BYTE const **)&pvNativeType);
565 if (FAILED(hr))
566 {
567 return FALSE;
568 }
569
570 pParamInfo->m_strSafeArrayUserDefTypeName = (LPUTF8)pvNativeType;
571 pParamInfo->m_cSafeArrayUserDefTypeNameBytes = strLen;
572 _ASSERTE((ULONG)(pvNativeType + strLen - pvNativeTypeStart) == cbNativeType);
573 }
574 break;
575
576#endif // FEATURE_COMINTEROP
577
578 case NATIVE_TYPE_ARRAY:
579 hr = CheckForCompressedData(pvNativeTypeStart, pvNativeType, cbNativeType);
580 if (FAILED(hr))
581 return FALSE;
582
583 if (hr == S_OK)
584 pParamInfo->m_ArrayElementType = (CorNativeType) (CorSigUncompressData(/*modifies*/pvNativeType));
585
586 // Check for "sizeis" param index
587 hr = CheckForCompressedData(pvNativeTypeStart, pvNativeType, cbNativeType);
588 if (FAILED(hr))
589 return FALSE;
590
591 if (hr == S_OK)
592 {
593 pParamInfo->m_SizeIsSpecified = TRUE;
594 pParamInfo->m_CountParamIdx = (UINT16)(CorSigUncompressData(/*modifies*/pvNativeType));
595
596 // If an "sizeis" param index is present, the defaults for multiplier and additive change
597 pParamInfo->m_Multiplier = 1;
598 pParamInfo->m_Additive = 0;
599
600 // Check for "sizeis" additive
601 hr = CheckForCompressedData(pvNativeTypeStart, pvNativeType, cbNativeType);
602 if (FAILED(hr))
603 return FALSE;
604
605 if (hr == S_OK)
606 {
607 // Extract the additive.
608 pParamInfo->m_Additive = (DWORD)CorSigUncompressData(/*modifies*/pvNativeType);
609
610 // Check to see if the flags field is present.
611 hr = CheckForCompressedData(pvNativeTypeStart, pvNativeType, cbNativeType);
612 if (FAILED(hr))
613 return FALSE;
614
615 if (hr == S_OK)
616 {
617 // If the param index specified flag isn't set then we need to reset the
618 // multiplier to 0 to indicate no size param index was specified.
619 NativeTypeArrayFlags flags = (NativeTypeArrayFlags)CorSigUncompressData(/*modifies*/pvNativeType);;
620 if (!(flags & ntaSizeParamIndexSpecified))
621 pParamInfo->m_Multiplier = 0;
622 }
623 }
624 }
625
626 break;
627
628 case NATIVE_TYPE_CUSTOMMARSHALER:
629 // Skip the typelib guid.
630 if (S_OK != CheckForCompressedData(pvNativeTypeStart, pvNativeType, cbNativeType))
631 return FALSE;
632
633 if (FAILED(CPackedLen::SafeGetData(pvNativeType, pvNativeTypeEnd, &strLen, (void const **)&pvNativeType)))
634 return FALSE;
635
636 pvNativeType += strLen;
637 _ASSERTE((ULONG)(pvNativeType - pvNativeTypeStart) < cbNativeType);
638
639 // Skip the name of the native type.
640 if (S_OK != CheckForCompressedData(pvNativeTypeStart, pvNativeType, cbNativeType))
641 return FALSE;
642
643 if (FAILED(CPackedLen::SafeGetData(pvNativeType, pvNativeTypeEnd, &strLen, (void const **)&pvNativeType)))
644 return FALSE;
645
646 pvNativeType += strLen;
647 _ASSERTE((ULONG)(pvNativeType - pvNativeTypeStart) < cbNativeType);
648
649 // Extract the name of the custom marshaler.
650 if (S_OK != CheckForCompressedData(pvNativeTypeStart, pvNativeType, cbNativeType))
651 return FALSE;
652
653 if (FAILED(CPackedLen::SafeGetData(pvNativeType, pvNativeTypeEnd, &strLen, (void const **)&pvNativeType)))
654 return FALSE;
655
656 pParamInfo->m_strCMMarshalerTypeName = (LPUTF8)pvNativeType;
657 pParamInfo->m_cCMMarshalerTypeNameBytes = strLen;
658 pvNativeType += strLen;
659 _ASSERTE((ULONG)(pvNativeType - pvNativeTypeStart) < cbNativeType);
660
661 // Extract the cookie string.
662 if (S_OK != CheckForCompressedData(pvNativeTypeStart, pvNativeType, cbNativeType))
663 return FALSE;
664
665 if (FAILED(CPackedLen::SafeGetData(pvNativeType, pvNativeTypeEnd, &strLen, (void const **)&pvNativeType)))
666 return FALSE;
667
668 pParamInfo->m_strCMCookie = (LPUTF8)pvNativeType;
669 pParamInfo->m_cCMCookieStrBytes = strLen;
670 _ASSERTE((ULONG)(pvNativeType + strLen - pvNativeTypeStart) == cbNativeType);
671 break;
672
673 default:
674 break;
675 }
676
677 return TRUE;
678}
679
680//==========================================================================
681// Determines whether *pManagedElemType is really normalized (i.e. differs
682// from what sigPtr points to modulo generic instantiation). If it is the
683// case, all types that have been normalized away are checked for valid
684// managed/unmanaged type combination, and *pNativeType is updated to contain
685// the native type of the primitive type field inside. On error (a generic
686// type is encountered or managed/unmanaged type mismatch) or non-default
687// native type of the primitive type inside, *pManagedElemType is un-normalized
688// so that the calling code can deal with the situation in its own way.
689//==========================================================================
690void VerifyAndAdjustNormalizedType(
691 Module * pModule,
692 SigPointer sigPtr,
693 const SigTypeContext * pTypeContext,
694 CorElementType * pManagedElemType,
695 CorNativeType * pNativeType)
696{
697 CorElementType sigElemType = sigPtr.PeekElemTypeClosed(pModule, pTypeContext);
698
699 if (*pManagedElemType != sigElemType)
700 {
701 // Normalized element type differs from closed element type, which means that
702 // normalization has occurred.
703 _ASSERTE(sigElemType == ELEMENT_TYPE_VALUETYPE);
704
705 // Now we know that this is a normalized value type - we have to verify the removed
706 // value type(s) and get to the true primitive type inside.
707 TypeHandle th = sigPtr.GetTypeHandleThrowing(pModule,
708 pTypeContext,
709 ClassLoader::LoadTypes,
710 CLASS_LOAD_UNRESTORED,
711 TRUE);
712 _ASSERTE(!th.IsNull() && !th.IsTypeDesc());
713
714 CorNativeType ntype = *pNativeType;
715
716 if (!th.AsMethodTable()->IsTruePrimitive() &&
717 !th.IsEnum())
718 {
719 // This is a trivial (yet non-primitive) value type that has been normalized.
720 // Loop until we eventually hit the primitive type or enum inside.
721 do
722 {
723 if (th.HasInstantiation())
724 {
725 // generic structures are either not marshalable or special-cased - the caller needs to know either way
726 *pManagedElemType = sigElemType;
727 return;
728 }
729
730 // verify the native type of the value type (must be default or Struct)
731 if (!(ntype == NATIVE_TYPE_DEFAULT || ntype == NATIVE_TYPE_STRUCT))
732 {
733 *pManagedElemType = sigElemType;
734 return;
735 }
736
737 MethodTable *pMT = th.GetMethodTable();
738 _ASSERTE(pMT != NULL && pMT->IsValueType() && pMT->GetNumInstanceFields() == 1);
739
740 // get the only instance field
741 PTR_FieldDesc fieldDesc = pMT->GetApproxFieldDescListRaw();
742
743 // retrieve the MarshalAs of the field
744 NativeTypeParamInfo paramInfo;
745 if (!ParseNativeTypeInfo(fieldDesc->GetMemberDef(), th.GetModule()->GetMDImport(), &paramInfo))
746 {
747 *pManagedElemType = sigElemType;
748 return;
749 }
750
751 ntype = paramInfo.m_NativeType;
752
753 th = fieldDesc->GetApproxFieldTypeHandleThrowing();
754 }
755 while (!th.IsTypeDesc() &&
756 !th.AsMethodTable()->IsTruePrimitive() &&
757 !th.IsEnum());
758
759 // now ntype contains the native type of *pManagedElemType
760 if (ntype == NATIVE_TYPE_DEFAULT)
761 {
762 // Let's update the caller's native type with default type only.
763 // Updating with a non-default native type that is not allowed
764 // for the given managed type would result in confusing exception
765 // messages.
766 *pNativeType = ntype;
767 }
768 else
769 {
770 *pManagedElemType = sigElemType;
771 }
772 }
773 }
774}
775
776VOID ThrowInteropParamException(UINT resID, UINT paramIdx)
777{
778 CONTRACTL
779 {
780 THROWS;
781 GC_TRIGGERS;
782 MODE_ANY;
783 }
784 CONTRACTL_END;
785
786 SString paramString;
787 if (paramIdx == 0)
788 paramString.Set(W("return value"));
789 else
790 paramString.Printf(W("parameter #%u"), paramIdx);
791
792 SString errorString(W("Unknown error."));
793 errorString.LoadResource(CCompRC::Error, resID);
794
795 COMPlusThrow(kMarshalDirectiveException, IDS_EE_BADMARSHAL_ERROR_MSG, paramString.GetUnicode(), errorString.GetUnicode());
796}
797
798//===============================================================
799// Collects paraminfo's in an indexed array so that:
800//
801// aParams[0] == param token for return value
802// aParams[1] == param token for argument #1...
803// aParams[numargs] == param token for argument #n...
804//
805// If no param token exists, the corresponding array element
806// is set to mdParamDefNil.
807//
808// Inputs:
809// pInternalImport -- ifc for metadata api
810// md -- token of method. If token is mdMethodNil,
811// all aParam elements will be set to mdParamDefNil.
812// numargs -- # of arguments in mdMethod
813// aParams -- uninitialized array with numargs+1 elements.
814// on exit, will be filled with param tokens.
815//===============================================================
816VOID CollateParamTokens(IMDInternalImport *pInternalImport, mdMethodDef md, ULONG numargs, mdParamDef *aParams)
817{
818 CONTRACTL
819 {
820 THROWS;
821 GC_NOTRIGGER;
822 MODE_ANY;
823 }
824 CONTRACTL_END;
825
826 for (ULONG i = 0; i < numargs + 1; i++)
827 aParams[i] = mdParamDefNil;
828
829 if (md != mdMethodDefNil)
830 {
831 MDEnumHolder hEnumParams(pInternalImport);
832 HRESULT hr = pInternalImport->EnumInit(mdtParamDef, md, &hEnumParams);
833 if (FAILED(hr))
834 {
835 // no param info: nothing left to do here
836 }
837 else
838 {
839 mdParamDef CurrParam = mdParamDefNil;
840 while (pInternalImport->EnumNext(&hEnumParams, &CurrParam))
841 {
842 USHORT usSequence;
843 DWORD dwAttr;
844 LPCSTR szParamName_Ignore;
845 if (SUCCEEDED(pInternalImport->GetParamDefProps(CurrParam, &usSequence, &dwAttr, &szParamName_Ignore)))
846 {
847 if (usSequence > numargs)
848 { // Invalid argument index
849 ThrowHR(COR_E_BADIMAGEFORMAT);
850 }
851 if (aParams[usSequence] != mdParamDefNil)
852 { // Duplicit argument index
853 ThrowHR(COR_E_BADIMAGEFORMAT);
854 }
855 aParams[usSequence] = CurrParam;
856 }
857 }
858 }
859 }
860}
861
862
863#ifdef FEATURE_COMINTEROP
864
865void *EventArgsMarshalingInfo::operator new(size_t size, LoaderHeap *pHeap)
866{
867 CONTRACT (void*)
868 {
869 THROWS;
870 GC_NOTRIGGER;
871 MODE_ANY;
872 INJECT_FAULT(COMPlusThrowOM());
873 PRECONDITION(CheckPointer(pHeap));
874 POSTCONDITION(CheckPointer(RETVAL));
875 }
876 CONTRACT_END;
877
878 void* mem = pHeap->AllocMem(S_SIZE_T(size));
879
880 RETURN mem;
881}
882
883void EventArgsMarshalingInfo::operator delete(void *pMem)
884{
885 LIMITED_METHOD_CONTRACT;
886 // Instances of this class are always allocated on the loader heap so
887 // the delete operator has nothing to do.
888}
889
890EventArgsMarshalingInfo::EventArgsMarshalingInfo()
891{
892 CONTRACTL
893 {
894 THROWS;
895 GC_TRIGGERS;
896 MODE_ANY;
897 }
898 CONTRACTL_END;
899
900 // Load the System.Collections.Specialized.NotifyCollectionChangedEventArgs class.
901 SString qualifiedNCCEventArgsTypeName(SString::Utf8, NCCEVENTARGS_ASM_QUAL_TYPE_NAME);
902 m_hndSystemNCCEventArgsType = TypeName::GetTypeFromAsmQualifiedName(qualifiedNCCEventArgsTypeName.GetUnicode());
903 _ASSERTE(!m_hndSystemNCCEventArgsType.IsNull() && "Cannot load System.Collections.Specialized.NotifyCollectionChangedEventArgs!");
904
905 // Load the System.ComponentModel.PropertyChangedEventArgs class.
906 SString qualifiedPCEventArgsTypeName(SString::Utf8, PCEVENTARGS_ASM_QUAL_TYPE_NAME);
907 m_hndSystemPCEventArgsType = TypeName::GetTypeFromAsmQualifiedName(qualifiedPCEventArgsTypeName.GetUnicode());
908 _ASSERTE(!m_hndSystemPCEventArgsType.IsNull() && "Cannot load System.ComponentModel.PropertyChangedEventArgs!");
909
910 // Load the NCCEventArgs marshaler class.
911 SString qualifiedNCCEventArgsMarshalerTypeName(SString::Utf8, NCCEVENTARGS_MARSHALER_ASM_QUAL_TYPE_NAME);
912 TypeHandle hndNCCEventArgsMarshalerType = TypeName::GetTypeFromAsmQualifiedName(qualifiedNCCEventArgsMarshalerTypeName.GetUnicode());
913
914 // Retrieve the method to convert a .NET NCCEventArgs to a WinRT NCCEventArgs.
915 m_pSystemNCCEventArgsToWinRTNCCEventArgsMD = MemberLoader::FindMethodByName(hndNCCEventArgsMarshalerType.GetMethodTable(), EVENTARGS_TO_WINRT_EVENTARGS_METH_NAME);
916 _ASSERTE(m_pSystemNCCEventArgsToWinRTNCCEventArgsMD && "Unable to find the marshaler method to convert a .NET NCCEventArgs to a WinRT NCCEventArgs!");
917
918 // Retrieve the method to convert a WinRT NCCEventArgs to a .NET NCCEventArgs.
919 m_pWinRTNCCEventArgsToSystemNCCEventArgsMD = MemberLoader::FindMethodByName(hndNCCEventArgsMarshalerType.GetMethodTable(), WINRT_EVENTARGS_TO_EVENTARGS_METH_NAME);
920 _ASSERTE(m_pWinRTNCCEventArgsToSystemNCCEventArgsMD && "Unable to find the marshaler method to convert a WinRT NCCEventArgs to a .NET NCCEventArgs!");
921
922 // Load the PCEventArgs marshaler class.
923 SString qualifiedPCEventArgsMarshalerTypeName(SString::Utf8, PCEVENTARGS_MARSHALER_ASM_QUAL_TYPE_NAME);
924 TypeHandle hndPCEventArgsMarshalerType = TypeName::GetTypeFromAsmQualifiedName(qualifiedPCEventArgsMarshalerTypeName.GetUnicode());
925
926 // Retrieve the method to convert a .NET PCEventArgs to a WinRT PCEventArgs.
927 m_pSystemPCEventArgsToWinRTPCEventArgsMD = MemberLoader::FindMethodByName(hndPCEventArgsMarshalerType.GetMethodTable(), EVENTARGS_TO_WINRT_EVENTARGS_METH_NAME);
928 _ASSERTE(m_pSystemPCEventArgsToWinRTPCEventArgsMD && "Unable to find the marshaler method to convert a .NET PCEventArgs to a WinRT PCEventArgs!");
929
930 // Retrieve the method to convert a WinRT PCEventArgs to a .NET PCEventArgs.
931 m_pWinRTPCEventArgsToSystemPCEventArgsMD = MemberLoader::FindMethodByName(hndPCEventArgsMarshalerType.GetMethodTable(), WINRT_EVENTARGS_TO_EVENTARGS_METH_NAME);
932 _ASSERTE(m_pWinRTPCEventArgsToSystemPCEventArgsMD && "Unable to find the marshaler method to convert a WinRT PCEventArgs to a .NET PCEventArgs!");
933}
934
935EventArgsMarshalingInfo::~EventArgsMarshalingInfo()
936{
937 LIMITED_METHOD_CONTRACT;
938}
939
940void *UriMarshalingInfo::operator new(size_t size, LoaderHeap *pHeap)
941{
942 CONTRACT (void*)
943 {
944 THROWS;
945 GC_NOTRIGGER;
946 MODE_ANY;
947 INJECT_FAULT(COMPlusThrowOM());
948 PRECONDITION(CheckPointer(pHeap));
949 POSTCONDITION(CheckPointer(RETVAL));
950 }
951 CONTRACT_END;
952
953 void* mem = pHeap->AllocMem(S_SIZE_T(size));
954
955 RETURN mem;
956}
957
958
959void UriMarshalingInfo::operator delete(void *pMem)
960{
961 LIMITED_METHOD_CONTRACT;
962 // Instances of this class are always allocated on the loader heap so
963 // the delete operator has nothing to do.
964}
965
966UriMarshalingInfo::UriMarshalingInfo()
967{
968 CONTRACTL
969 {
970 THROWS;
971 GC_TRIGGERS;
972 MODE_ANY;
973 }
974 CONTRACTL_END;
975
976 // Create on-demand as we don't want to create the factories in NGEN time
977 m_pUriFactory = NULL;
978
979 // Load the System.Uri class.
980 SString qualifiedUriTypeName(SString::Utf8, URI_ASM_QUAL_TYPE_NAME);
981 m_hndSystemUriType = TypeName::GetTypeFromAsmQualifiedName(qualifiedUriTypeName.GetUnicode());
982 _ASSERTE(!m_hndSystemUriType.IsNull() && "Cannot load System.Uri!");
983
984 m_SystemUriOriginalStringGetterMD = MemberLoader::FindPropertyMethod(m_hndSystemUriType.GetMethodTable(), ORIGINALSTRING_PROPERTY_NAME, PropertyGet);
985 _ASSERTE(m_SystemUriOriginalStringGetterMD && "Unable to find the System.Uri.get_OriginalString()!");
986 _ASSERTE(!m_SystemUriOriginalStringGetterMD->IsStatic() && "System.Uri.get_OriginalString() is static!");
987
988 // Windows.Foundation.Uri..ctor(string) and System.Uri..ctor(string)
989 MethodTable* pSystemUriMT = m_hndSystemUriType.AsMethodTable();
990 m_SystemUriCtorMD = MemberLoader::FindConstructor(pSystemUriMT, &gsig_IM_Str_RetVoid);
991 _ASSERTE(m_SystemUriCtorMD && "Unable to find the constructor on System.Uri that takes a string!");
992 _ASSERTE(m_SystemUriCtorMD->IsClassConstructorOrCtor() && !m_SystemUriCtorMD->IsStatic() && "The method retrieved from System.Uri is not a constructor!");
993}
994
995UriMarshalingInfo::~UriMarshalingInfo()
996{
997 CONTRACTL
998 {
999 NOTHROW;
1000 GC_TRIGGERS;
1001 MODE_ANY;
1002 }
1003 CONTRACTL_END;
1004#ifndef CROSSGEN_COMPILE
1005 if (m_pUriFactory)
1006 {
1007 SafeRelease(m_pUriFactory);
1008 m_pUriFactory = NULL;
1009 }
1010#endif
1011}
1012
1013OleColorMarshalingInfo::OleColorMarshalingInfo() :
1014 m_OleColorToSystemColorMD(NULL),
1015 m_SystemColorToOleColorMD(NULL)
1016{
1017 CONTRACTL
1018 {
1019 THROWS;
1020 GC_TRIGGERS;
1021 MODE_ANY;
1022 }
1023 CONTRACTL_END;
1024
1025 SString qualifiedColorTranslatorTypeName(SString::Utf8, COLOR_TRANSLATOR_ASM_QUAL_TYPE_NAME);
1026
1027 // Load the color translator class.
1028 TypeHandle hndColorTranslatorType = TypeName::GetTypeFromAsmQualifiedName(qualifiedColorTranslatorTypeName.GetUnicode());
1029
1030
1031 SString qualifiedColorTypeName(SString::Utf8, COLOR_ASM_QUAL_TYPE_NAME);
1032 // Load the color class.
1033 m_hndColorType = TypeName::GetTypeFromAsmQualifiedName(qualifiedColorTypeName.GetUnicode());
1034
1035 // Retrieve the method to convert an OLE_COLOR to a System.Drawing.Color.
1036 m_OleColorToSystemColorMD = MemberLoader::FindMethodByName(hndColorTranslatorType.GetMethodTable(), OLECOLOR_TO_SYSTEMCOLOR_METH_NAME);
1037 _ASSERTE(m_OleColorToSystemColorMD && "Unable to find the translator method to convert an OLE_COLOR to a System.Drawing.Color!");
1038 _ASSERTE(m_OleColorToSystemColorMD->IsStatic() && "The translator method to convert an OLE_COLOR to a System.Drawing.Color must be static!");
1039
1040 // Retrieve the method to convert a System.Drawing.Color to an OLE_COLOR.
1041 m_SystemColorToOleColorMD = MemberLoader::FindMethodByName(hndColorTranslatorType.GetMethodTable(), SYSTEMCOLOR_TO_OLECOLOR_METH_NAME);
1042 _ASSERTE(m_SystemColorToOleColorMD && "Unable to find the translator method to convert a System.Drawing.Color to an OLE_COLOR!");
1043 _ASSERTE(m_SystemColorToOleColorMD->IsStatic() && "The translator method to convert a System.Drawing.Color to an OLE_COLOR must be static!");
1044}
1045
1046
1047void *OleColorMarshalingInfo::operator new(size_t size, LoaderHeap *pHeap)
1048{
1049 CONTRACT (void*)
1050 {
1051 THROWS;
1052 GC_NOTRIGGER;
1053 MODE_ANY;
1054 INJECT_FAULT(COMPlusThrowOM());
1055 PRECONDITION(CheckPointer(pHeap));
1056 POSTCONDITION(CheckPointer(RETVAL));
1057 }
1058 CONTRACT_END;
1059
1060 void* mem = pHeap->AllocMem(S_SIZE_T(size));
1061
1062 RETURN mem;
1063}
1064
1065
1066void OleColorMarshalingInfo::operator delete(void *pMem)
1067{
1068 LIMITED_METHOD_CONTRACT;
1069 // Instances of this class are always allocated on the loader heap so
1070 // the delete operator has nothing to do.
1071}
1072
1073#endif // FEATURE_COMINTEROP
1074
1075EEMarshalingData::EEMarshalingData(BaseDomain *pDomain, LoaderHeap *pHeap, CrstBase *pCrst) :
1076 m_pHeap(pHeap),
1077 m_pDomain(pDomain)
1078{
1079 CONTRACTL
1080 {
1081 NOTHROW;
1082 GC_NOTRIGGER;
1083 MODE_ANY;
1084 }
1085 CONTRACTL_END;
1086
1087 LockOwner lock = {pCrst, IsOwnerOfCrst};
1088#ifndef CROSSGEN_COMPILE
1089 m_CMHelperHashtable.Init(INITIAL_NUM_CMHELPER_HASHTABLE_BUCKETS, &lock);
1090 m_SharedCMHelperToCMInfoMap.Init(INITIAL_NUM_CMINFO_HASHTABLE_BUCKETS, &lock);
1091#endif // CROSSGEN_COMPILE
1092}
1093
1094
1095EEMarshalingData::~EEMarshalingData()
1096{
1097 WRAPPER_NO_CONTRACT;
1098
1099 CustomMarshalerInfo *pCMInfo;
1100
1101 // <TODO>@TODO(DM): Remove the linked list of CMInfo's and instead hang the OBJECTHANDLE
1102 // contained inside the CMInfo off the AppDomain directly. The AppDomain can have
1103 // a list of tasks to do when it gets teared down and we could leverage that
1104 // to release the object handles.</TODO>
1105
1106 // Walk through the linked list and delete all the custom marshaler info's.
1107 while ((pCMInfo = m_pCMInfoList.RemoveHead()) != NULL)
1108 delete pCMInfo;
1109
1110#ifdef FEATURE_COMINTEROP
1111 if (m_pOleColorInfo)
1112 {
1113 delete m_pOleColorInfo;
1114 m_pOleColorInfo = NULL;
1115 }
1116
1117 if (m_pUriInfo)
1118 {
1119 delete m_pUriInfo;
1120 m_pUriInfo = NULL;
1121 }
1122
1123 if (m_pEventArgsInfo)
1124 {
1125 delete m_pEventArgsInfo;
1126 m_pEventArgsInfo = NULL;
1127 }
1128#endif
1129}
1130
1131
1132void *EEMarshalingData::operator new(size_t size, LoaderHeap *pHeap)
1133{
1134 CONTRACT (void*)
1135 {
1136 THROWS;
1137 GC_NOTRIGGER;
1138 MODE_ANY;
1139 INJECT_FAULT(COMPlusThrowOM());
1140 PRECONDITION(CheckPointer(pHeap));
1141 POSTCONDITION(CheckPointer(RETVAL));
1142 }
1143 CONTRACT_END;
1144
1145 void* mem = pHeap->AllocMem(S_SIZE_T(sizeof(EEMarshalingData)));
1146
1147 RETURN mem;
1148}
1149
1150
1151void EEMarshalingData::operator delete(void *pMem)
1152{
1153 LIMITED_METHOD_CONTRACT;
1154 // Instances of this class are always allocated on the loader heap so
1155 // the delete operator has nothing to do.
1156}
1157
1158#ifndef CROSSGEN_COMPILE
1159
1160CustomMarshalerHelper *EEMarshalingData::GetCustomMarshalerHelper(Assembly *pAssembly, TypeHandle hndManagedType, LPCUTF8 strMarshalerTypeName, DWORD cMarshalerTypeNameBytes, LPCUTF8 strCookie, DWORD cCookieStrBytes)
1161{
1162 CONTRACT (CustomMarshalerHelper*)
1163 {
1164 THROWS;
1165 GC_TRIGGERS;
1166 MODE_ANY;
1167 INJECT_FAULT(COMPlusThrowOM());
1168 PRECONDITION(CheckPointer(pAssembly));
1169 POSTCONDITION(CheckPointer(RETVAL));
1170 }
1171 CONTRACT_END;
1172
1173 CustomMarshalerHelper *pCMHelper = NULL;
1174 CustomMarshalerHelper* pNewCMHelper = NULL;
1175 NewHolder<CustomMarshalerInfo> pNewCMInfo(NULL);
1176
1177 TypeHandle hndCustomMarshalerType;
1178
1179 // Create the key that will be used to lookup in the hashtable.
1180 EECMHelperHashtableKey Key(cMarshalerTypeNameBytes, strMarshalerTypeName, cCookieStrBytes, strCookie, hndManagedType.GetInstantiation());
1181
1182 // Lookup the custom marshaler helper in the hashtable.
1183 if (m_CMHelperHashtable.GetValue(&Key, (HashDatum*)&pCMHelper))
1184 RETURN pCMHelper;
1185
1186 {
1187 GCX_COOP();
1188
1189 // Validate the arguments.
1190 _ASSERTE(strMarshalerTypeName && strCookie && !hndManagedType.IsNull());
1191
1192 // Append a NULL terminator to the marshaler type name.
1193 SString strCMMarshalerTypeName(SString::Utf8, strMarshalerTypeName, cMarshalerTypeNameBytes);
1194
1195 // Load the custom marshaler class.
1196 BOOL fNameIsAsmQualified = FALSE;
1197 hndCustomMarshalerType = TypeName::GetTypeUsingCASearchRules(strCMMarshalerTypeName.GetUTF8NoConvert(), pAssembly, &fNameIsAsmQualified);
1198
1199 if (hndCustomMarshalerType.IsGenericTypeDefinition())
1200 {
1201 // Instantiate generic custom marshalers using the instantiation of the type being marshaled.
1202 hndCustomMarshalerType = hndCustomMarshalerType.Instantiate(hndManagedType.GetInstantiation());
1203 }
1204
1205 // Set the assembly to null to indicate that the custom marshaler name is assembly
1206 // qualified.
1207 if (fNameIsAsmQualified)
1208 pAssembly = NULL;
1209
1210
1211 // Create the custom marshaler info in the specified heap.
1212 pNewCMInfo = new (m_pHeap) CustomMarshalerInfo(m_pDomain, hndCustomMarshalerType, hndManagedType, strCookie, cCookieStrBytes);
1213
1214 // Create the custom marshaler helper in the specified heap.
1215 pNewCMHelper = new (m_pHeap) NonSharedCustomMarshalerHelper(pNewCMInfo);
1216 }
1217
1218 // Take the app domain lock before we insert the custom marshaler info into the hashtable.
1219 {
1220 BaseDomain::LockHolder lh(m_pDomain);
1221
1222 // Verify that the custom marshaler helper has not already been added by another thread.
1223 if (m_CMHelperHashtable.GetValue(&Key, (HashDatum*)&pCMHelper))
1224 {
1225 RETURN pCMHelper;
1226 }
1227
1228 // Add the custom marshaler helper to the hash table.
1229 m_CMHelperHashtable.InsertValue(&Key, pNewCMHelper, FALSE);
1230
1231 // If we create the CM info, then add it to the linked list.
1232 if (pNewCMInfo)
1233 {
1234 m_pCMInfoList.InsertHead(pNewCMInfo);
1235 pNewCMInfo.SuppressRelease();
1236 }
1237
1238 // Release the lock and return the custom marshaler info.
1239 }
1240
1241 RETURN pNewCMHelper;
1242}
1243
1244CustomMarshalerInfo *EEMarshalingData::GetCustomMarshalerInfo(SharedCustomMarshalerHelper *pSharedCMHelper)
1245{
1246 CONTRACT (CustomMarshalerInfo*)
1247 {
1248 THROWS;
1249 GC_TRIGGERS;
1250 MODE_COOPERATIVE;
1251 INJECT_FAULT(COMPlusThrowOM());
1252 POSTCONDITION(CheckPointer(RETVAL));
1253 }
1254 CONTRACT_END;
1255
1256 CustomMarshalerInfo *pCMInfo = NULL;
1257 NewHolder<CustomMarshalerInfo> pNewCMInfo(NULL);
1258 TypeHandle hndCustomMarshalerType;
1259
1260 // Lookup the custom marshaler helper in the hashtable.
1261 if (m_SharedCMHelperToCMInfoMap.GetValue(pSharedCMHelper, (HashDatum*)&pCMInfo))
1262 RETURN pCMInfo;
1263
1264 // Append a NULL terminator to the marshaler type name.
1265 CQuickArray<char> strCMMarshalerTypeName;
1266 DWORD strLen = pSharedCMHelper->GetMarshalerTypeNameByteCount();
1267 strCMMarshalerTypeName.ReSizeThrows(pSharedCMHelper->GetMarshalerTypeNameByteCount() + 1);
1268 memcpy(strCMMarshalerTypeName.Ptr(), pSharedCMHelper->GetMarshalerTypeName(), strLen);
1269 strCMMarshalerTypeName[strLen] = 0;
1270
1271 // Load the custom marshaler class.
1272 hndCustomMarshalerType = TypeName::GetTypeUsingCASearchRules(strCMMarshalerTypeName.Ptr(), pSharedCMHelper->GetAssembly());
1273 if (hndCustomMarshalerType.IsGenericTypeDefinition())
1274 {
1275 // Instantiate generic custom marshalers using the instantiation of the type being marshaled.
1276 hndCustomMarshalerType = hndCustomMarshalerType.Instantiate(pSharedCMHelper->GetManagedType().GetInstantiation());
1277 }
1278
1279 // Create the custom marshaler info in the specified heap.
1280 pNewCMInfo = new (m_pHeap) CustomMarshalerInfo(m_pDomain,
1281 hndCustomMarshalerType,
1282 pSharedCMHelper->GetManagedType(),
1283 pSharedCMHelper->GetCookieString(),
1284 pSharedCMHelper->GetCookieStringByteCount());
1285
1286 {
1287 // Take the app domain lock before we insert the custom marshaler info into the hashtable.
1288 BaseDomain::LockHolder lh(m_pDomain);
1289
1290 // Verify that the custom marshaler info has not already been added by another thread.
1291 if (m_SharedCMHelperToCMInfoMap.GetValue(pSharedCMHelper, (HashDatum*)&pCMInfo))
1292 {
1293 RETURN pCMInfo;
1294 }
1295
1296 // Add the custom marshaler helper to the hash table.
1297 m_SharedCMHelperToCMInfoMap.InsertValue(pSharedCMHelper, pNewCMInfo, FALSE);
1298
1299 // Add the custom marshaler into the linked list.
1300 m_pCMInfoList.InsertHead(pNewCMInfo);
1301
1302 // Release the lock and return the custom marshaler info.
1303 }
1304
1305 pNewCMInfo.SuppressRelease();
1306 RETURN pNewCMInfo;
1307}
1308#endif // CROSSGEN_COMPILE
1309
1310#ifdef FEATURE_COMINTEROP
1311UriMarshalingInfo *EEMarshalingData::GetUriMarshalingInfo()
1312{
1313 CONTRACT (UriMarshalingInfo*)
1314 {
1315 THROWS;
1316 GC_TRIGGERS;
1317 MODE_ANY;
1318 INJECT_FAULT(COMPlusThrowOM());
1319 POSTCONDITION(CheckPointer(RETVAL));
1320 }
1321 CONTRACT_END;
1322
1323 if (m_pUriInfo == NULL)
1324 {
1325 UriMarshalingInfo *pUriInfo = new (m_pHeap) UriMarshalingInfo();
1326
1327 if (InterlockedCompareExchangeT(&m_pUriInfo, pUriInfo, NULL) != NULL)
1328 {
1329 // Another thread beat us to it. Delete on UriMarshalingInfo is an empty operation
1330 // which is OK, since the possible leak is rare, small, and constant. This is the same
1331 // pattern as in code:GetCustomMarshalerInfo.
1332 delete pUriInfo;
1333 }
1334 }
1335
1336 RETURN m_pUriInfo;
1337}
1338
1339EventArgsMarshalingInfo *EEMarshalingData::GetEventArgsMarshalingInfo()
1340{
1341 CONTRACT (EventArgsMarshalingInfo*)
1342 {
1343 THROWS;
1344 GC_TRIGGERS;
1345 MODE_ANY;
1346 INJECT_FAULT(COMPlusThrowOM());
1347 POSTCONDITION(CheckPointer(RETVAL));
1348 }
1349 CONTRACT_END;
1350
1351 if (m_pEventArgsInfo == NULL)
1352 {
1353 EventArgsMarshalingInfo *pEventArgsInfo = new (m_pHeap) EventArgsMarshalingInfo();
1354
1355 if (InterlockedCompareExchangeT(&m_pEventArgsInfo, pEventArgsInfo, NULL) != NULL)
1356 {
1357 // Another thread beat us to it. Delete on EventArgsMarshalingInfo is an empty operation
1358 // which is OK, since the possible leak is rare, small, and constant. This is the same
1359 // pattern as in code:GetCustomMarshalerInfo.
1360 delete pEventArgsInfo;
1361 }
1362 }
1363
1364 RETURN m_pEventArgsInfo;
1365}
1366
1367OleColorMarshalingInfo *EEMarshalingData::GetOleColorMarshalingInfo()
1368{
1369 CONTRACT (OleColorMarshalingInfo*)
1370 {
1371 THROWS;
1372 GC_TRIGGERS;
1373 MODE_ANY;
1374 INJECT_FAULT(COMPlusThrowOM());
1375 POSTCONDITION(CheckPointer(RETVAL));
1376 }
1377 CONTRACT_END;
1378
1379 if (m_pOleColorInfo == NULL)
1380 {
1381 OleColorMarshalingInfo *pOleColorInfo = new (m_pHeap) OleColorMarshalingInfo();
1382
1383 if (InterlockedCompareExchangeT(&m_pOleColorInfo, pOleColorInfo, NULL) != NULL)
1384 {
1385 // Another thread beat us to it. Delete on OleColorMarshalingInfo is an empty operation
1386 // which is OK, since the possible leak is rare, small, and constant. This is the same
1387 // pattern as in code:GetCustomMarshalerInfo.
1388 delete pOleColorInfo;
1389 }
1390 }
1391
1392 RETURN m_pOleColorInfo;
1393}
1394#endif // FEATURE_COMINTEROP
1395
1396//==========================================================================
1397// Constructs MarshalInfo.
1398//==========================================================================
1399#ifdef _PREFAST_
1400#pragma warning(push)
1401#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
1402#endif
1403MarshalInfo::MarshalInfo(Module* pModule,
1404 SigPointer sig,
1405 const SigTypeContext *pTypeContext,
1406 mdToken token,
1407 MarshalScenario ms,
1408 CorNativeLinkType nlType,
1409 CorNativeLinkFlags nlFlags,
1410 BOOL isParam,
1411 UINT paramidx, // parameter # for use in error messages (ignored if not parameter)
1412 UINT numArgs, // number of arguments
1413 BOOL BestFit,
1414 BOOL ThrowOnUnmappableChar,
1415 BOOL fEmitsIL,
1416 MethodDesc* pMD,
1417 BOOL fLoadCustomMarshal
1418#ifdef _DEBUG
1419 ,
1420 LPCUTF8 pDebugName,
1421 LPCUTF8 pDebugClassName,
1422 UINT argidx // 0 for return value, -1 for field
1423#endif
1424)
1425{
1426 STANDARD_VM_CONTRACT;
1427
1428 HRESULT hr;
1429 NativeTypeParamInfo ParamInfo;
1430
1431 // we expect a 1-based paramidx, but we like to use a 0-based paramidx
1432 m_paramidx = paramidx - 1;
1433
1434 // if no one overwrites this with a better message, we'll still at least say something
1435 m_resID = IDS_EE_BADMARSHAL_GENERIC;
1436
1437 // flag for uninitialized type
1438 m_type = MARSHAL_TYPE_UNKNOWN;
1439
1440 CorNativeType nativeType = NATIVE_TYPE_DEFAULT;
1441 Assembly *pAssembly = pModule->GetAssembly();
1442 m_BestFit = BestFit;
1443 m_ThrowOnUnmappableChar = ThrowOnUnmappableChar;
1444 m_ms = ms;
1445 m_fAnsi = (ms == MARSHAL_SCENARIO_NDIRECT) && (nlType == nltAnsi);
1446 m_managedArgSize = 0;
1447 m_nativeArgSize = 0;
1448 m_pCMHelper = NULL;
1449 m_CMVt = VT_EMPTY;
1450 m_args.m_pMarshalInfo = this;
1451 m_args.m_pMT = NULL;
1452 m_pModule = pModule;
1453 CorElementType mtype = ELEMENT_TYPE_END;
1454 CorElementType corElemType = ELEMENT_TYPE_END;
1455 m_pMT = NULL;
1456 m_pMD = pMD;
1457
1458#ifdef FEATURE_COMINTEROP
1459 m_fDispItf = FALSE;
1460 m_fInspItf = FALSE;
1461 m_fErrorNativeType = FALSE;
1462 m_hiddenLengthParamIndex = (UINT16)-1;
1463 m_dwHiddenLengthManagedHomeLocal= 0xFFFFFFFF;
1464 m_dwHiddenLengthNativeHomeLocal = 0xFFFFFFFF;
1465
1466 m_pDefaultItfMT = NULL;
1467#endif // FEATURE_COMINTEROP
1468
1469
1470#ifdef _DEBUG
1471
1472 CHAR achDbgContext[DEBUG_CONTEXT_STR_LEN] = "";
1473 if (!pDebugName)
1474 {
1475 strncpy_s(achDbgContext, COUNTOF(achDbgContext), "<Unknown>", _TRUNCATE);
1476 }
1477 else
1478 {
1479 strncat_s(achDbgContext, COUNTOF(achDbgContext), pDebugClassName, _TRUNCATE);
1480 strncat_s(achDbgContext, COUNTOF(achDbgContext), NAMESPACE_SEPARATOR_STR, _TRUNCATE);
1481 strncat_s(achDbgContext, COUNTOF(achDbgContext), pDebugName, _TRUNCATE);
1482 strncat_s(achDbgContext, COUNTOF(achDbgContext), " ", _TRUNCATE);
1483 switch (argidx)
1484 {
1485 case (UINT)-1:
1486 strncat_s(achDbgContext, COUNTOF(achDbgContext), "field", _TRUNCATE);
1487 break;
1488 case 0:
1489 strncat_s(achDbgContext, COUNTOF(achDbgContext), "return value", _TRUNCATE);
1490 break;
1491 default:
1492 {
1493 char buf[30];
1494 sprintf_s(buf, COUNTOF(buf), "param #%lu", (ULONG)argidx);
1495 strncat_s(achDbgContext, COUNTOF(achDbgContext), buf, _TRUNCATE);
1496 }
1497 }
1498 }
1499
1500 m_strDebugMethName = pDebugName;
1501 m_strDebugClassName = pDebugClassName;
1502 m_iArg = argidx;
1503
1504 m_in = m_out = FALSE;
1505 m_byref = TRUE;
1506#endif
1507
1508
1509
1510 // Retrieve the native type for the current parameter.
1511 if (!ParseNativeTypeInfo(token, pModule->GetMDImport(), &ParamInfo))
1512 {
1513 IfFailGoto(E_FAIL, lFail);
1514 }
1515
1516 nativeType = ParamInfo.m_NativeType;
1517 corElemType = sig.PeekElemTypeNormalized(pModule, pTypeContext);
1518 mtype = corElemType;
1519
1520#ifdef FEATURE_COMINTEROP
1521 if (IsWinRTScenario() && nativeType != NATIVE_TYPE_DEFAULT)
1522 {
1523 // Do not allow any MarshalAs in WinRT scenarios - marshaling is fully described by the parameter type.
1524 m_type = MARSHAL_TYPE_UNKNOWN;
1525 m_resID = IDS_EE_BADMARSHAL_WINRT_MARSHAL_AS;
1526 IfFailGoto(E_FAIL, lFail);
1527 }
1528#endif // FEATURE_COMINTEROP
1529
1530 // Make sure SizeParamIndex < numArgs when marshalling native arrays
1531 if (nativeType == NATIVE_TYPE_ARRAY && ParamInfo.m_SizeIsSpecified)
1532 {
1533 if (ParamInfo.m_Multiplier > 0 && ParamInfo.m_CountParamIdx >= numArgs)
1534 {
1535 // Do not throw exception here.
1536 // We'll use EmitOrThrowInteropException to throw exception in non-COM interop
1537 // and emit exception throwing code directly in STUB in COM interop
1538 m_type = MARSHAL_TYPE_UNKNOWN;
1539 m_resID = IDS_EE_SIZECONTROLOUTOFRANGE;
1540 IfFailGoto(E_FAIL, lFail);
1541 }
1542 }
1543
1544 // Parse ET_BYREF signature
1545 if (mtype == ELEMENT_TYPE_BYREF)
1546 {
1547 m_byref = TRUE;
1548 SigPointer sigtmp = sig;
1549 IfFailGoto(sig.GetElemType(NULL), lFail);
1550 mtype = sig.PeekElemTypeNormalized(pModule, pTypeContext);
1551
1552 }
1553 else
1554 {
1555 m_byref = FALSE;
1556 }
1557
1558 // Check for valid ET_PTR signature
1559 if (mtype == ELEMENT_TYPE_PTR)
1560 {
1561#ifdef FEATURE_COMINTEROP
1562 // WinRT does not support ET_PTR
1563 if (IsWinRTScenario())
1564 {
1565 m_type = MARSHAL_TYPE_UNKNOWN;
1566 m_resID = IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE;
1567 IfFailGoto(E_FAIL, lFail);
1568 }
1569#endif // FEATURE_COMINTEROP
1570
1571 SigPointer sigtmp = sig;
1572 IfFailGoto(sigtmp.GetElemType(NULL), lFail);
1573
1574 // Peek closed elem type here to prevent ELEMENT_TYPE_VALUETYPE turning into a primitive.
1575 CorElementType mtype2 = sigtmp.PeekElemTypeClosed(pModule, pTypeContext);
1576
1577 if (mtype2 == ELEMENT_TYPE_VALUETYPE)
1578 {
1579
1580 TypeHandle th = sigtmp.GetTypeHandleThrowing(pModule, pTypeContext);
1581 _ASSERTE(!th.IsNull());
1582
1583 // We want to leave out enums as they surely don't have copy constructors
1584 // plus they are not marked as blittable.
1585 if (!th.IsEnum())
1586 {
1587 // It should be blittable
1588 if (!th.IsBlittable())
1589 {
1590 m_resID = IDS_EE_BADMARSHAL_PTRNONBLITTABLE;
1591 IfFailGoto(E_FAIL, lFail);
1592 }
1593
1594 }
1595 }
1596 else
1597 {
1598 if (!(mtype2 != ELEMENT_TYPE_CLASS &&
1599 mtype2 != ELEMENT_TYPE_STRING &&
1600 mtype2 != ELEMENT_TYPE_OBJECT &&
1601 mtype2 != ELEMENT_TYPE_SZARRAY))
1602 {
1603 m_resID = IDS_EE_BADMARSHAL_PTRSUBTYPE;
1604 IfFailGoto(E_FAIL, lFail);
1605 }
1606 }
1607 }
1608
1609
1610 // System primitive types (System.Int32, et.al.) will be marshaled as expected
1611 // because the mtype CorElementType is normalized (e.g. ELEMENT_TYPE_I4).
1612#ifdef _TARGET_X86_
1613 // We however need to detect if such a normalization occurred for non-system
1614 // trivial value types, because we hold CorNativeType belonging to the original
1615 // "un-normalized" signature type. It has to be verified that all the value types
1616 // that have been normalized away have default marshaling or MarshalAs(Struct).
1617 // In addition, the nativeType must be updated with the type of the real primitive inside.
1618 //
1619 VerifyAndAdjustNormalizedType(pModule, sig, pTypeContext, &mtype, &nativeType);
1620#endif // _TARGET_X86_
1621
1622
1623 if (nativeType == NATIVE_TYPE_CUSTOMMARSHALER)
1624 {
1625 switch (mtype)
1626 {
1627 case ELEMENT_TYPE_VAR:
1628 case ELEMENT_TYPE_CLASS:
1629 case ELEMENT_TYPE_OBJECT:
1630 m_CMVt = VT_UNKNOWN;
1631 break;
1632
1633 case ELEMENT_TYPE_STRING:
1634 case ELEMENT_TYPE_SZARRAY:
1635 case ELEMENT_TYPE_ARRAY:
1636 m_CMVt = VT_I4;
1637 break;
1638
1639 default:
1640 m_resID = IDS_EE_BADMARSHAL_CUSTOMMARSHALER;
1641 IfFailGoto(E_FAIL, lFail);
1642 }
1643
1644 // Set m_type to MARSHAL_TYPE_UNKNOWN in case SetupCustomMarshalerHelper throws.
1645 m_type = MARSHAL_TYPE_UNKNOWN;
1646
1647 if (fLoadCustomMarshal)
1648 {
1649 // Set up the custom marshaler info.
1650 TypeHandle hndManagedType = sig.GetTypeHandleThrowing(pModule, pTypeContext);
1651
1652 if (!fEmitsIL)
1653 {
1654 m_pCMHelper = SetupCustomMarshalerHelper(ParamInfo.m_strCMMarshalerTypeName,
1655 ParamInfo.m_cCMMarshalerTypeNameBytes,
1656 ParamInfo.m_strCMCookie,
1657 ParamInfo.m_cCMCookieStrBytes,
1658 pAssembly,
1659 hndManagedType);
1660 }
1661 else
1662 {
1663 m_pCMHelper = NULL;
1664 MethodDesc* pMDforModule = pMD;
1665 if (pMD->IsILStub())
1666 {
1667 pMDforModule = pMD->AsDynamicMethodDesc()->GetILStubResolver()->GetStubTargetMethodDesc();
1668 }
1669 m_args.rcm.m_pMD = pMDforModule;
1670 m_args.rcm.m_paramToken = token;
1671 m_args.rcm.m_hndManagedType = hndManagedType.AsPtr();
1672 CONSISTENCY_CHECK(pModule == pMDforModule->GetModule());
1673 }
1674 }
1675
1676 // Specify which custom marshaler to use.
1677 m_type = MARSHAL_TYPE_REFERENCECUSTOMMARSHALER;
1678
1679 goto lExit;
1680 }
1681
1682 switch (mtype)
1683 {
1684 case ELEMENT_TYPE_BOOLEAN:
1685 switch (nativeType)
1686 {
1687 case NATIVE_TYPE_BOOLEAN:
1688 m_type = MARSHAL_TYPE_WINBOOL;
1689 break;
1690
1691#ifdef FEATURE_COMINTEROP
1692 case NATIVE_TYPE_VARIANTBOOL:
1693 m_type = MARSHAL_TYPE_VTBOOL;
1694 break;
1695#endif // FEATURE_COMINTEROP
1696
1697 case NATIVE_TYPE_U1:
1698 case NATIVE_TYPE_I1:
1699 m_type = MARSHAL_TYPE_CBOOL;
1700 break;
1701
1702 case NATIVE_TYPE_DEFAULT:
1703#ifdef FEATURE_COMINTEROP
1704 if (m_ms == MARSHAL_SCENARIO_COMINTEROP)
1705 {
1706 // 2-byte COM VARIANT_BOOL
1707 m_type = MARSHAL_TYPE_VTBOOL;
1708 }
1709 else if (m_ms == MARSHAL_SCENARIO_WINRT)
1710 {
1711 // 1-byte WinRT bool
1712 m_type = MARSHAL_TYPE_CBOOL;
1713 }
1714 else
1715#endif // FEATURE_COMINTEROP
1716 {
1717 // 4-byte Windows BOOL
1718 _ASSERTE(m_ms == MARSHAL_SCENARIO_NDIRECT);
1719 m_type = MARSHAL_TYPE_WINBOOL;
1720 }
1721 break;
1722
1723 default:
1724 m_resID = IDS_EE_BADMARSHAL_BOOLEAN;
1725 IfFailGoto(E_FAIL, lFail);
1726 }
1727 break;
1728
1729 case ELEMENT_TYPE_CHAR:
1730 switch (nativeType)
1731 {
1732 case NATIVE_TYPE_I1: //fallthru
1733 case NATIVE_TYPE_U1:
1734 m_type = MARSHAL_TYPE_ANSICHAR;
1735 break;
1736
1737 case NATIVE_TYPE_I2: //fallthru
1738 case NATIVE_TYPE_U2:
1739 m_type = MARSHAL_TYPE_GENERIC_U2;
1740 break;
1741
1742 case NATIVE_TYPE_DEFAULT:
1743 m_type = ( (m_ms == MARSHAL_SCENARIO_NDIRECT && m_fAnsi) ? MARSHAL_TYPE_ANSICHAR : MARSHAL_TYPE_GENERIC_U2 );
1744 break;
1745
1746 default:
1747 m_resID = IDS_EE_BADMARSHAL_CHAR;
1748 IfFailGoto(E_FAIL, lFail);
1749
1750 }
1751 break;
1752
1753 case ELEMENT_TYPE_I1:
1754 if (!(nativeType == NATIVE_TYPE_I1 || nativeType == NATIVE_TYPE_U1 || nativeType == NATIVE_TYPE_DEFAULT))
1755 {
1756 m_resID = IDS_EE_BADMARSHAL_I1;
1757 IfFailGoto(E_FAIL, lFail);
1758 }
1759 m_type = MARSHAL_TYPE_GENERIC_1;
1760 break;
1761
1762 case ELEMENT_TYPE_U1:
1763 if (!(nativeType == NATIVE_TYPE_U1 || nativeType == NATIVE_TYPE_I1 || nativeType == NATIVE_TYPE_DEFAULT))
1764 {
1765 m_resID = IDS_EE_BADMARSHAL_I1;
1766 IfFailGoto(E_FAIL, lFail);
1767 }
1768 m_type = MARSHAL_TYPE_GENERIC_U1;
1769 break;
1770
1771 case ELEMENT_TYPE_I2:
1772 if (!(nativeType == NATIVE_TYPE_I2 || nativeType == NATIVE_TYPE_U2 || nativeType == NATIVE_TYPE_DEFAULT))
1773 {
1774 m_resID = IDS_EE_BADMARSHAL_I2;
1775 IfFailGoto(E_FAIL, lFail);
1776 }
1777 m_type = MARSHAL_TYPE_GENERIC_2;
1778 break;
1779
1780 case ELEMENT_TYPE_U2:
1781 if (!(nativeType == NATIVE_TYPE_U2 || nativeType == NATIVE_TYPE_I2 || nativeType == NATIVE_TYPE_DEFAULT))
1782 {
1783 m_resID = IDS_EE_BADMARSHAL_I2;
1784 IfFailGoto(E_FAIL, lFail);
1785 }
1786 m_type = MARSHAL_TYPE_GENERIC_U2;
1787 break;
1788
1789 case ELEMENT_TYPE_I4:
1790 switch (nativeType)
1791 {
1792 case NATIVE_TYPE_I4:
1793 case NATIVE_TYPE_U4:
1794 case NATIVE_TYPE_DEFAULT:
1795 break;
1796
1797#ifdef FEATURE_COMINTEROP
1798 case NATIVE_TYPE_ERROR:
1799 m_fErrorNativeType = TRUE;
1800 break;
1801#endif // FEATURE_COMINTEROP
1802
1803 default:
1804 m_resID = IDS_EE_BADMARSHAL_I4;
1805 IfFailGoto(E_FAIL, lFail);
1806 }
1807 m_type = MARSHAL_TYPE_GENERIC_4;
1808 break;
1809
1810 case ELEMENT_TYPE_U4:
1811 switch (nativeType)
1812 {
1813 case NATIVE_TYPE_I4:
1814 case NATIVE_TYPE_U4:
1815 case NATIVE_TYPE_DEFAULT:
1816 break;
1817
1818#ifdef FEATURE_COMINTEROP
1819 case NATIVE_TYPE_ERROR:
1820 m_fErrorNativeType = TRUE;
1821 break;
1822#endif // FEATURE_COMINTEROP
1823
1824 default:
1825 m_resID = IDS_EE_BADMARSHAL_I4;
1826 IfFailGoto(E_FAIL, lFail);
1827 }
1828 m_type = MARSHAL_TYPE_GENERIC_4;
1829 break;
1830
1831 case ELEMENT_TYPE_I8:
1832 if (!(nativeType == NATIVE_TYPE_I8 || nativeType == NATIVE_TYPE_U8 || nativeType == NATIVE_TYPE_DEFAULT))
1833 {
1834 m_resID = IDS_EE_BADMARSHAL_I8;
1835 IfFailGoto(E_FAIL, lFail);
1836 }
1837 m_type = MARSHAL_TYPE_GENERIC_8;
1838 break;
1839
1840 case ELEMENT_TYPE_U8:
1841 if (!(nativeType == NATIVE_TYPE_U8 || nativeType == NATIVE_TYPE_I8 || nativeType == NATIVE_TYPE_DEFAULT))
1842 {
1843 m_resID = IDS_EE_BADMARSHAL_I8;
1844 IfFailGoto(E_FAIL, lFail);
1845 }
1846 m_type = MARSHAL_TYPE_GENERIC_8;
1847 break;
1848
1849 case ELEMENT_TYPE_I:
1850#ifdef FEATURE_COMINTEROP
1851 if (IsWinRTScenario())
1852 {
1853 m_resID = IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE;
1854 IfFailGoto(E_FAIL, lFail);
1855 }
1856#endif // FEATURE_COMINTEROP
1857
1858 if (!(nativeType == NATIVE_TYPE_INT || nativeType == NATIVE_TYPE_UINT || nativeType == NATIVE_TYPE_DEFAULT))
1859 {
1860 m_resID = IDS_EE_BADMARSHAL_I;
1861 IfFailGoto(E_FAIL, lFail);
1862 }
1863 m_type = (sizeof(LPVOID) == 4 ? MARSHAL_TYPE_GENERIC_4 : MARSHAL_TYPE_GENERIC_8);
1864 break;
1865
1866 case ELEMENT_TYPE_U:
1867#ifdef FEATURE_COMINTEROP
1868 if (IsWinRTScenario())
1869 {
1870 m_resID = IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE;
1871 IfFailGoto(E_FAIL, lFail);
1872 }
1873#endif // FEATURE_COMINTEROP
1874
1875 if (!(nativeType == NATIVE_TYPE_UINT || nativeType == NATIVE_TYPE_INT || nativeType == NATIVE_TYPE_DEFAULT))
1876 {
1877 m_resID = IDS_EE_BADMARSHAL_I;
1878 IfFailGoto(E_FAIL, lFail);
1879 }
1880 m_type = (sizeof(LPVOID) == 4 ? MARSHAL_TYPE_GENERIC_4 : MARSHAL_TYPE_GENERIC_8);
1881 break;
1882
1883
1884 case ELEMENT_TYPE_R4:
1885 if (!(nativeType == NATIVE_TYPE_R4 || nativeType == NATIVE_TYPE_DEFAULT))
1886 {
1887 m_resID = IDS_EE_BADMARSHAL_R4;
1888 IfFailGoto(E_FAIL, lFail);
1889 }
1890 m_type = MARSHAL_TYPE_FLOAT;
1891 break;
1892
1893 case ELEMENT_TYPE_R8:
1894 if (!(nativeType == NATIVE_TYPE_R8 || nativeType == NATIVE_TYPE_DEFAULT))
1895 {
1896 m_resID = IDS_EE_BADMARSHAL_R8;
1897 IfFailGoto(E_FAIL, lFail);
1898 }
1899 m_type = MARSHAL_TYPE_DOUBLE;
1900 break;
1901
1902 case ELEMENT_TYPE_PTR:
1903#ifdef FEATURE_COMINTEROP
1904 _ASSERTE(!IsWinRTScenario()); // we checked for this earlier
1905#endif // FEATURE_COMINTEROP
1906
1907 if (nativeType != NATIVE_TYPE_DEFAULT)
1908 {
1909 m_resID = IDS_EE_BADMARSHAL_PTR;
1910 IfFailGoto(E_FAIL, lFail);
1911 }
1912 m_type = ( (sizeof(void*)==4) ? MARSHAL_TYPE_GENERIC_4 : MARSHAL_TYPE_GENERIC_8 );
1913 break;
1914
1915 case ELEMENT_TYPE_FNPTR:
1916#ifdef FEATURE_COMINTEROP
1917 if (IsWinRTScenario())
1918 {
1919 m_resID = IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE;
1920 IfFailGoto(E_FAIL, lFail);
1921 }
1922#endif // FEATURE_COMINTEROP
1923
1924 if (!(nativeType == NATIVE_TYPE_FUNC || nativeType == NATIVE_TYPE_DEFAULT))
1925 {
1926 m_resID = IDS_EE_BADMARSHAL_FNPTR;
1927 IfFailGoto(E_FAIL, lFail);
1928 }
1929 m_type = ( (sizeof(void*)==4) ? MARSHAL_TYPE_GENERIC_4 : MARSHAL_TYPE_GENERIC_8 );
1930 break;
1931
1932 case ELEMENT_TYPE_OBJECT:
1933 case ELEMENT_TYPE_STRING:
1934 case ELEMENT_TYPE_CLASS:
1935 case ELEMENT_TYPE_VAR:
1936 {
1937 TypeHandle sigTH = sig.GetTypeHandleThrowing(pModule, pTypeContext);
1938
1939 // Disallow marshaling generic types except for WinRT interfaces.
1940 if (sigTH.HasInstantiation())
1941 {
1942#ifdef FEATURE_COMINTEROP
1943 if (!sigTH.SupportsGenericInterop(TypeHandle::Interop_NativeToManaged))
1944#endif // FEATURE_COMINTEROP
1945 {
1946 m_resID = IDS_EE_BADMARSHAL_GENERICS_RESTRICTION;
1947 IfFailGoto(E_FAIL, lFail);
1948 }
1949 }
1950
1951 m_pMT = sigTH.GetMethodTable();
1952 if (m_pMT == NULL)
1953 IfFailGoto(COR_E_TYPELOAD, lFail);
1954
1955#ifdef FEATURE_COMINTEROP
1956 MethodTable* pDefaultMT = NULL;
1957
1958 // Look for marshaling of WinRT runtime classes
1959 if ((m_pMT->IsProjectedFromWinRT() || m_pMT->IsExportedToWinRT()) && !m_pMT->HasExplicitGuid())
1960 {
1961 // The type loader guarantees that there are no WinRT interfaces without explicit GUID
1962 _ASSERTE(!m_pMT->IsInterface());
1963
1964 // Make sure that this is really a legal runtime class and not a custom attribute or delegate
1965 if (!m_pMT->IsLegalNonArrayWinRTType() || m_pMT->IsDelegate())
1966 {
1967 m_resID = IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE;
1968 IfFailGoto(E_FAIL, lFail);
1969 }
1970
1971 // This class must have a default interface that describes how it is marshaled
1972 pDefaultMT = m_pMT->GetDefaultWinRTInterface();
1973 if (pDefaultMT == NULL)
1974 {
1975 m_resID = IDS_EE_BADMARSHAL_WINRT_MISSING_GUID;
1976 IfFailGoto(E_FAIL, lFail);
1977 }
1978 }
1979
1980 if (nativeType == NATIVE_TYPE_INTF)
1981 {
1982 // whatever...
1983 if (sig.IsStringType(pModule, pTypeContext))
1984 {
1985 m_resID = IDS_EE_BADMARSHALPARAM_STRING;
1986 IfFailGoto(E_FAIL, lFail);
1987 }
1988
1989 if (m_ms == MARSHAL_SCENARIO_WINRT && COMDelegate::IsDelegate(m_pMT))
1990 {
1991 // In WinRT scenarios delegates must be WinRT delegates
1992 if (!m_pMT->IsProjectedFromWinRT() && !WinRTTypeNameConverter::IsRedirectedType(m_pMT))
1993 {
1994 m_resID = IDS_EE_BADMARSHAL_WINRT_DELEGATE;
1995 IfFailGoto(E_FAIL, lFail);
1996 }
1997 }
1998
1999 m_type = MARSHAL_TYPE_INTERFACE;
2000 }
2001 else if (pDefaultMT != NULL && nativeType == NATIVE_TYPE_DEFAULT)
2002 {
2003 // Pretend this is really marshaling as the default interface type
2004
2005 // Validate it's a WinRT interface with GUID
2006 if (!pDefaultMT->IsInterface() ||
2007 (!pDefaultMT->IsProjectedFromWinRT() && !pDefaultMT->IsExportedToWinRT()) ||
2008 !pDefaultMT->HasExplicitGuid())
2009 {
2010 // This might also be a redirected interface - which is also allowed
2011 if (!pDefaultMT->IsWinRTRedirectedInterface(TypeHandle::Interop_NativeToManaged))
2012 {
2013 m_resID = IDS_EE_BADMARSHAL_DEFAULTIFACE_NOT_WINRT_IFACE;
2014 IfFailGoto(E_FAIL, lFail);
2015 }
2016 }
2017
2018 // Validate that it's one of the component interfaces of the class in the signature
2019 if (!m_pMT->ImplementsEquivalentInterface(pDefaultMT))
2020 {
2021 m_resID = IDS_EE_BADMARSHAL_DEFAULTIFACE_NOT_SUBTYPE;
2022 IfFailGoto(E_FAIL, lFail);
2023 }
2024
2025 // Make sure it's not an unexpected generic case (not clear we can actually get here in practice due
2026 // to the above Implements check)
2027 if (pDefaultMT->HasInstantiation() && !pDefaultMT->SupportsGenericInterop(TypeHandle::Interop_NativeToManaged))
2028 {
2029 m_resID = IDS_EE_BADMARSHAL_GENERICS_RESTRICTION;
2030 IfFailGoto(E_FAIL, lFail);
2031 }
2032
2033 // Store the marshal data just as if we were marshaling as this default interface type
2034 m_type = MARSHAL_TYPE_INTERFACE;
2035 m_pDefaultItfMT = pDefaultMT;
2036 }
2037 else
2038#endif // FEATURE_COMINTEROP
2039 {
2040 bool builder = false;
2041 if (sig.IsStringTypeThrowing(pModule, pTypeContext)
2042 || ((builder = true), 0)
2043 || sig.IsClassThrowing(pModule, g_StringBufferClassName, pTypeContext)
2044 )
2045 {
2046 switch ( nativeType )
2047 {
2048 case NATIVE_TYPE_LPWSTR:
2049 m_type = builder ? MARSHAL_TYPE_LPWSTR_BUFFER : MARSHAL_TYPE_LPWSTR;
2050 break;
2051
2052 case NATIVE_TYPE_LPSTR:
2053 m_type = builder ? MARSHAL_TYPE_LPSTR_BUFFER : MARSHAL_TYPE_LPSTR;
2054 break;
2055
2056 case NATIVE_TYPE_LPUTF8STR:
2057 m_type = builder ? MARSHAL_TYPE_UTF8_BUFFER : MARSHAL_TYPE_LPUTF8STR;
2058 break;
2059
2060 case NATIVE_TYPE_LPTSTR:
2061 {
2062#ifdef FEATURE_COMINTEROP
2063 if (m_ms != MARSHAL_SCENARIO_NDIRECT)
2064 {
2065 _ASSERTE(m_ms == MARSHAL_SCENARIO_COMINTEROP);
2066 // We disallow NATIVE_TYPE_LPTSTR for COM.
2067 IfFailGoto(E_FAIL, lFail);
2068 }
2069#endif // FEATURE_COMINTEROP
2070 // We no longer support Win9x so LPTSTR always maps to a Unicode string.
2071 m_type = builder ? MARSHAL_TYPE_LPWSTR_BUFFER : MARSHAL_TYPE_LPWSTR;
2072 break;
2073 }
2074
2075 case NATIVE_TYPE_BSTR:
2076 if (builder)
2077 {
2078 m_resID = IDS_EE_BADMARSHALPARAM_STRINGBUILDER;
2079 IfFailGoto(E_FAIL, lFail);
2080 }
2081 m_type = MARSHAL_TYPE_BSTR;
2082 break;
2083
2084 case NATIVE_TYPE_ANSIBSTR:
2085 if (builder)
2086 {
2087 m_resID = IDS_EE_BADMARSHALPARAM_STRINGBUILDER;
2088 IfFailGoto(E_FAIL, lFail);
2089 }
2090 m_type = MARSHAL_TYPE_ANSIBSTR;
2091 break;
2092
2093 case NATIVE_TYPE_TBSTR:
2094 {
2095 if (builder)
2096 {
2097 m_resID = IDS_EE_BADMARSHALPARAM_STRINGBUILDER;
2098 IfFailGoto(E_FAIL, lFail);
2099 }
2100
2101 // We no longer support Win9x so TBSTR always maps to a normal (unicode) BSTR.
2102 m_type = MARSHAL_TYPE_BSTR;
2103 break;
2104 }
2105
2106#ifdef FEATURE_COMINTEROP
2107 case NATIVE_TYPE_BYVALSTR:
2108 {
2109 if (builder)
2110 {
2111 m_resID = IDS_EE_BADMARSHALPARAM_STRINGBUILDER;
2112 IfFailGoto(E_FAIL, lFail);
2113 }
2114 m_type = m_fAnsi ? MARSHAL_TYPE_VBBYVALSTR : MARSHAL_TYPE_VBBYVALSTRW;
2115 break;
2116 }
2117
2118 case NATIVE_TYPE_HSTRING:
2119 {
2120 if (builder)
2121 {
2122 m_resID = IDS_EE_BADMARSHALPARAM_STRINGBUILDER;
2123 IfFailGoto(E_FAIL, lFail);
2124 }
2125
2126 m_type = MARSHAL_TYPE_HSTRING;
2127 break;
2128 }
2129#endif // FEATURE_COMINTEROP
2130
2131 case NATIVE_TYPE_DEFAULT:
2132 {
2133#ifdef FEATURE_COMINTEROP
2134 if (m_ms == MARSHAL_SCENARIO_WINRT)
2135 {
2136 if (builder)
2137 {
2138 m_resID = IDS_EE_BADMARSHALPARAM_STRINGBUILDER;
2139 IfFailGoto(E_FAIL, lFail);
2140 }
2141
2142 m_type = MARSHAL_TYPE_HSTRING;
2143 }
2144 else if (m_ms != MARSHAL_SCENARIO_NDIRECT)
2145 {
2146 _ASSERTE(m_ms == MARSHAL_SCENARIO_COMINTEROP);
2147 m_type = builder ? MARSHAL_TYPE_LPWSTR_BUFFER : MARSHAL_TYPE_BSTR;
2148 }
2149 else
2150#endif // FEATURE_COMINTEROP
2151 if (m_fAnsi)
2152 {
2153 m_type = builder ? MARSHAL_TYPE_LPSTR_BUFFER : MARSHAL_TYPE_LPSTR;
2154 }
2155 else
2156 {
2157 m_type = builder ? MARSHAL_TYPE_LPWSTR_BUFFER : MARSHAL_TYPE_LPWSTR;
2158 }
2159 break;
2160 }
2161
2162 default:
2163 m_resID = builder ? IDS_EE_BADMARSHALPARAM_STRINGBUILDER : IDS_EE_BADMARSHALPARAM_STRING;
2164 IfFailGoto(E_FAIL, lFail);
2165 break;
2166 }
2167 }
2168#ifdef FEATURE_COMINTEROP
2169 else if (sig.IsClassThrowing(pModule, g_CollectionsEnumeratorClassName, pTypeContext) &&
2170 nativeType == NATIVE_TYPE_DEFAULT)
2171 {
2172 m_CMVt = VT_UNKNOWN;
2173 m_type = MARSHAL_TYPE_REFERENCECUSTOMMARSHALER;
2174
2175 if (fLoadCustomMarshal)
2176 {
2177 if (!fEmitsIL)
2178 {
2179 m_pCMHelper = SetupCustomMarshalerHelper(ENUMERATOR_TO_ENUM_VARIANT_CM_NAME,
2180 ENUMERATOR_TO_ENUM_VARIANT_CM_NAME_LEN,
2181 ENUMERATOR_TO_ENUM_VARIANT_CM_COOKIE,
2182 ENUMERATOR_TO_ENUM_VARIANT_CM_COOKIE_LEN,
2183 pAssembly, sigTH);
2184 }
2185 else
2186 {
2187 m_pCMHelper = NULL;
2188 MethodDesc* pMDforModule = pMD;
2189 if (pMD->IsILStub())
2190 {
2191 pMDforModule = pMD->AsDynamicMethodDesc()->GetILStubResolver()->GetStubTargetMethodDesc();
2192 }
2193 m_args.rcm.m_pMD = pMDforModule;
2194 m_args.rcm.m_paramToken = token;
2195 m_args.rcm.m_hndManagedType = sigTH.AsPtr();
2196 CONSISTENCY_CHECK(pModule == pMDforModule->GetModule());
2197 }
2198 }
2199 }
2200#endif // FEATURE_COMINTEROP
2201 else if (sigTH.CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__SAFE_HANDLE))))
2202 {
2203 if (nativeType != NATIVE_TYPE_DEFAULT)
2204 {
2205 m_resID = IDS_EE_BADMARSHAL_SAFEHANDLE;
2206 IfFailGoto(E_FAIL, lFail);
2207 }
2208 m_args.m_pMT = m_pMT;
2209 m_type = MARSHAL_TYPE_SAFEHANDLE;
2210 }
2211 else if (sigTH.CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__CRITICAL_HANDLE))))
2212 {
2213 if (nativeType != NATIVE_TYPE_DEFAULT)
2214 {
2215 m_resID = IDS_EE_BADMARSHAL_CRITICALHANDLE;
2216 IfFailGoto(E_FAIL, lFail);
2217 }
2218 m_args.m_pMT = m_pMT;
2219 m_type = MARSHAL_TYPE_CRITICALHANDLE;
2220 }
2221 else if (sig.IsClassThrowing(pModule, g_ReflectionMethodInterfaceName, pTypeContext))
2222 {
2223 if (nativeType != NATIVE_TYPE_DEFAULT)
2224 {
2225 IfFailGoto(E_FAIL, lFail);
2226 }
2227
2228 m_type = MARSHAL_TYPE_RUNTIMEMETHODINFO;
2229 }
2230#ifdef FEATURE_COMINTEROP
2231 else if (m_pMT->IsInterface())
2232 {
2233 if (!(nativeType == NATIVE_TYPE_DEFAULT ||
2234 nativeType == NATIVE_TYPE_INTF))
2235 {
2236 m_resID = IDS_EE_BADMARSHAL_INTERFACE;
2237 IfFailGoto(E_FAIL, lFail);
2238 }
2239 m_type = MARSHAL_TYPE_INTERFACE;
2240
2241 if (m_ms == MARSHAL_SCENARIO_WINRT)
2242 {
2243 // all interfaces marshaled in WinRT scenarios are IInspectable-based
2244 m_fInspItf = TRUE;
2245 }
2246 }
2247 // Check for Windows.Foundation.HResult <-> Exception
2248 else if (m_ms == MARSHAL_SCENARIO_WINRT && MscorlibBinder::IsClass(m_pMT, CLASS__EXCEPTION))
2249 {
2250 m_args.m_pMT = m_pMT;
2251 m_type = MARSHAL_TYPE_EXCEPTION;
2252 }
2253#endif // FEATURE_COMINTEROP
2254 else if (COMDelegate::IsDelegate(m_pMT))
2255 {
2256 m_args.m_pMT = m_pMT;
2257#ifdef FEATURE_COMINTEROP
2258 if (m_ms == MARSHAL_SCENARIO_WINRT)
2259 {
2260 // Delegates must be imported from WinRT and marshaled as Interface
2261 if (!m_pMT->IsProjectedFromWinRT() && !WinRTTypeNameConverter::IsRedirectedType(m_pMT))
2262 {
2263 m_resID = IDS_EE_BADMARSHAL_WINRT_DELEGATE;
2264 IfFailGoto(E_FAIL, lFail);
2265 }
2266 }
2267#endif // FEATURE_COMINTEROP
2268
2269 switch (nativeType)
2270 {
2271 case NATIVE_TYPE_FUNC:
2272 m_type = MARSHAL_TYPE_DELEGATE;
2273 break;
2274
2275 case NATIVE_TYPE_DEFAULT:
2276#ifdef FEATURE_COMINTEROP
2277 if (m_ms != MARSHAL_SCENARIO_NDIRECT)
2278 {
2279 _ASSERTE(m_ms == MARSHAL_SCENARIO_COMINTEROP || m_ms == MARSHAL_SCENARIO_WINRT);
2280 m_type = MARSHAL_TYPE_INTERFACE;
2281 }
2282 else
2283#endif // FEATURE_COMINTEROP
2284 m_type = MARSHAL_TYPE_DELEGATE;
2285
2286 break;
2287
2288 default:
2289 m_resID = IDS_EE_BADMARSHAL_DELEGATE;
2290 IfFailGoto(E_FAIL, lFail);
2291 break;
2292 }
2293 }
2294 else if (m_pMT->IsBlittable())
2295 {
2296 if (!(nativeType == NATIVE_TYPE_DEFAULT || nativeType == NATIVE_TYPE_LPSTRUCT))
2297 {
2298 m_resID = IDS_EE_BADMARSHAL_CLASS;
2299 IfFailGoto(E_FAIL, lFail);
2300 }
2301 m_type = MARSHAL_TYPE_BLITTABLEPTR;
2302 m_args.m_pMT = m_pMT;
2303 }
2304 else if (m_pMT->HasLayout())
2305 {
2306 if (!(nativeType == NATIVE_TYPE_DEFAULT || nativeType == NATIVE_TYPE_LPSTRUCT))
2307 {
2308 m_resID = IDS_EE_BADMARSHAL_CLASS;
2309 IfFailGoto(E_FAIL, lFail);
2310 }
2311 m_type = MARSHAL_TYPE_LAYOUTCLASSPTR;
2312 m_args.m_pMT = m_pMT;
2313 }
2314 else if (sig.IsClassThrowing(pModule, g_ReflectionModuleName, pTypeContext))
2315 {
2316 if (nativeType != NATIVE_TYPE_DEFAULT)
2317 {
2318 IfFailGoto(E_FAIL, lFail);
2319 }
2320
2321 m_type = MARSHAL_TYPE_RUNTIMEMODULE;
2322 }
2323 else if (sig.IsClassThrowing(pModule, g_ReflectionAssemblyName, pTypeContext))
2324 {
2325 if (nativeType != NATIVE_TYPE_DEFAULT)
2326 {
2327 IfFailGoto(E_FAIL, lFail);
2328 }
2329
2330 m_type = MARSHAL_TYPE_RUNTIMEASSEMBLY;
2331 }
2332#ifdef FEATURE_COMINTEROP
2333 else if (m_ms == MARSHAL_SCENARIO_WINRT && sig.IsClassThrowing(pModule, g_SystemUriClassName, pTypeContext))
2334 {
2335 m_type = MARSHAL_TYPE_URI;
2336 }
2337 else if (m_ms == MARSHAL_SCENARIO_WINRT && sig.IsClassThrowing(pModule, g_NotifyCollectionChangedEventArgsName, pTypeContext))
2338 {
2339 m_type = MARSHAL_TYPE_NCCEVENTARGS;
2340 }
2341 else if (m_ms == MARSHAL_SCENARIO_WINRT && sig.IsClassThrowing(pModule, g_PropertyChangedEventArgsName, pTypeContext))
2342 {
2343 m_type = MARSHAL_TYPE_PCEVENTARGS;
2344 }
2345#endif // FEATURE_COMINTEROP
2346 else if (m_pMT->IsObjectClass())
2347 {
2348 switch(nativeType)
2349 {
2350#ifdef FEATURE_COMINTEROP
2351 case NATIVE_TYPE_DEFAULT:
2352 if (ms == MARSHAL_SCENARIO_WINRT)
2353 {
2354 m_fInspItf = TRUE;
2355 m_type = MARSHAL_TYPE_INTERFACE;
2356 break;
2357 }
2358 // fall through
2359 case NATIVE_TYPE_STRUCT:
2360 m_type = MARSHAL_TYPE_OBJECT;
2361 break;
2362
2363 case NATIVE_TYPE_INTF:
2364 case NATIVE_TYPE_IUNKNOWN:
2365 m_type = MARSHAL_TYPE_INTERFACE;
2366 break;
2367
2368 case NATIVE_TYPE_IDISPATCH:
2369 m_fDispItf = TRUE;
2370 m_type = MARSHAL_TYPE_INTERFACE;
2371 break;
2372
2373 case NATIVE_TYPE_IINSPECTABLE:
2374 m_fInspItf = TRUE;
2375 m_type = MARSHAL_TYPE_INTERFACE;
2376 break;
2377#else
2378 case NATIVE_TYPE_DEFAULT:
2379 case NATIVE_TYPE_STRUCT:
2380 m_resID = IDS_EE_OBJECT_TO_VARIANT_NOT_SUPPORTED;
2381 IfFailGoto(E_FAIL, lFail);
2382
2383 case NATIVE_TYPE_INTF:
2384 case NATIVE_TYPE_IUNKNOWN:
2385 case NATIVE_TYPE_IDISPATCH:
2386 m_resID = IDS_EE_OBJECT_TO_ITF_NOT_SUPPORTED;
2387 IfFailGoto(E_FAIL, lFail);
2388#endif // FEATURE_COMINTEROP
2389
2390 case NATIVE_TYPE_ASANY:
2391 m_type = m_fAnsi ? MARSHAL_TYPE_ASANYA : MARSHAL_TYPE_ASANYW;
2392 break;
2393
2394 default:
2395 m_resID = IDS_EE_BADMARSHAL_OBJECT;
2396 IfFailGoto(E_FAIL, lFail);
2397 }
2398 }
2399
2400#ifdef FEATURE_COMINTEROP
2401 else if (sig.IsClassThrowing(pModule, g_ArrayClassName, pTypeContext))
2402 {
2403 if (IsWinRTScenario())
2404 {
2405 m_resID = IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE;
2406 IfFailGoto(E_FAIL, lFail);
2407 }
2408
2409 switch(nativeType)
2410 {
2411 case NATIVE_TYPE_DEFAULT:
2412 case NATIVE_TYPE_INTF:
2413 m_type = MARSHAL_TYPE_INTERFACE;
2414 break;
2415
2416 case NATIVE_TYPE_SAFEARRAY:
2417 {
2418 TypeHandle thElement = TypeHandle(g_pObjectClass);
2419
2420 if (ParamInfo.m_SafeArrayElementVT != VT_EMPTY)
2421 {
2422 if (ParamInfo.m_cSafeArrayUserDefTypeNameBytes > 0)
2423 {
2424 // Load the type. Use an SString for the string since we need to NULL terminate the string
2425 // that comes from the metadata.
2426 StackScratchBuffer utf8Name;
2427 SString safeArrayUserDefTypeName(SString::Utf8, ParamInfo.m_strSafeArrayUserDefTypeName, ParamInfo.m_cSafeArrayUserDefTypeNameBytes);
2428 thElement = TypeName::GetTypeUsingCASearchRules(safeArrayUserDefTypeName.GetUTF8(utf8Name), pAssembly);
2429 }
2430 }
2431 else
2432 {
2433 // Compat: If no safe array VT was specified, default to VT_VARIANT.
2434 ParamInfo.m_SafeArrayElementVT = VT_VARIANT;
2435 }
2436
2437 IfFailGoto(HandleArrayElemType(&ParamInfo, 0, thElement, -1, FALSE, isParam, pAssembly), lFail);
2438 break;
2439 }
2440
2441 default:
2442 m_resID = IDS_EE_BADMARSHAL_SYSARRAY;
2443 IfFailGoto(E_FAIL, lFail);
2444
2445 }
2446 }
2447
2448 else if (m_pMT->IsArray())
2449 {
2450 _ASSERTE(!"This invalid signature should never be hit!");
2451 IfFailGoto(E_FAIL, lFail);
2452 }
2453 else if ((m_ms == MARSHAL_SCENARIO_WINRT) && sig.IsClassThrowing(pModule, g_TypeClassName, pTypeContext))
2454 {
2455 m_type = MARSHAL_TYPE_SYSTEMTYPE;
2456 }
2457#endif // FEATURE_COMINTEROP
2458 else if (!m_pMT->IsValueType())
2459 {
2460#ifdef FEATURE_COMINTEROP
2461 if (IsWinRTScenario() && !m_pMT->IsLegalNonArrayWinRTType())
2462 {
2463 m_resID = IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE;
2464 IfFailGoto(E_FAIL, lFail);
2465 }
2466#endif // FEATURE_COMINTEROP
2467
2468 if (!(nativeType == NATIVE_TYPE_INTF || nativeType == NATIVE_TYPE_DEFAULT))
2469 {
2470 m_resID = IDS_EE_BADMARSHAL_NOLAYOUT;
2471 IfFailGoto(E_FAIL, lFail);
2472 }
2473#ifdef FEATURE_COMINTEROP
2474 // default marshalling is interface
2475 m_type = MARSHAL_TYPE_INTERFACE;
2476#else // FEATURE_COMINTEROP
2477 m_resID = IDS_EE_OBJECT_TO_ITF_NOT_SUPPORTED;
2478 IfFailGoto(E_FAIL, lFail);
2479#endif // FEATURE_COMINTEROP
2480 }
2481
2482 else
2483 {
2484 _ASSERTE(m_pMT->IsValueType());
2485 goto lValueClass;
2486 }
2487 }
2488 break;
2489 }
2490
2491
2492 case ELEMENT_TYPE_VALUETYPE:
2493 lValueClass:
2494 {
2495 if (sig.IsClassThrowing(pModule, g_DecimalClassName, pTypeContext))
2496 {
2497 switch (nativeType)
2498 {
2499 case NATIVE_TYPE_DEFAULT:
2500 case NATIVE_TYPE_STRUCT:
2501 m_type = MARSHAL_TYPE_DECIMAL;
2502 break;
2503
2504 case NATIVE_TYPE_LPSTRUCT:
2505 m_type = MARSHAL_TYPE_DECIMAL_PTR;
2506 break;
2507
2508 case NATIVE_TYPE_CURRENCY:
2509 m_type = MARSHAL_TYPE_CURRENCY;
2510 break;
2511
2512 default:
2513 m_resID = IDS_EE_BADMARSHALPARAM_DECIMAL;
2514 IfFailGoto(E_FAIL, lFail);
2515 }
2516 }
2517 else if (sig.IsClassThrowing(pModule, g_GuidClassName, pTypeContext))
2518 {
2519 switch (nativeType)
2520 {
2521 case NATIVE_TYPE_DEFAULT:
2522 case NATIVE_TYPE_STRUCT:
2523 m_type = MARSHAL_TYPE_GUID;
2524 break;
2525
2526 case NATIVE_TYPE_LPSTRUCT:
2527 m_type = MARSHAL_TYPE_GUID_PTR;
2528 break;
2529
2530 default:
2531 m_resID = IDS_EE_BADMARSHAL_GUID;
2532 IfFailGoto(E_FAIL, lFail);
2533 }
2534 }
2535#ifdef FEATURE_COMINTEROP
2536 else if (sig.IsClassThrowing(pModule, g_DateTimeOffsetClassName, pTypeContext))
2537 {
2538 if (!(nativeType == NATIVE_TYPE_DEFAULT || nativeType == NATIVE_TYPE_STRUCT))
2539 {
2540 m_resID = IDS_EE_BADMARSHAL_DATETIMEOFFSET;
2541 IfFailGoto(E_FAIL, lFail);
2542 }
2543 m_type = MARSHAL_TYPE_DATETIME;
2544 m_pMT = MscorlibBinder::GetClass(CLASS__DATE_TIME_OFFSET);
2545 }
2546#endif // FEATURE_COMINTEROP
2547 else if (sig.IsClassThrowing(pModule, g_DateClassName, pTypeContext))
2548 {
2549 if (!(nativeType == NATIVE_TYPE_DEFAULT || nativeType == NATIVE_TYPE_STRUCT))
2550 {
2551 m_resID = IDS_EE_BADMARSHAL_DATETIME;
2552 IfFailGoto(E_FAIL, lFail);
2553 }
2554 m_type = MARSHAL_TYPE_DATE;
2555 }
2556 else if (sig.IsClassThrowing(pModule, "System.Runtime.InteropServices.ArrayWithOffset", pTypeContext))
2557 {
2558 if (!(nativeType == NATIVE_TYPE_DEFAULT))
2559 {
2560 IfFailGoto(E_FAIL, lFail);
2561 }
2562 m_type = MARSHAL_TYPE_ARRAYWITHOFFSET;
2563 }
2564 else if (sig.IsClassThrowing(pModule, "System.Runtime.InteropServices.HandleRef", pTypeContext))
2565 {
2566 if (!(nativeType == NATIVE_TYPE_DEFAULT))
2567 {
2568 IfFailGoto(E_FAIL, lFail);
2569 }
2570 m_type = MARSHAL_TYPE_HANDLEREF;
2571 }
2572 else if (sig.IsClassThrowing(pModule, "System.ArgIterator", pTypeContext))
2573 {
2574 if (!(nativeType == NATIVE_TYPE_DEFAULT))
2575 {
2576 IfFailGoto(E_FAIL, lFail);
2577 }
2578 m_type = MARSHAL_TYPE_ARGITERATOR;
2579 }
2580#ifdef FEATURE_COMINTEROP
2581 else if (sig.IsClassThrowing(pModule, g_ColorClassName, pTypeContext))
2582 {
2583 if (!(nativeType == NATIVE_TYPE_DEFAULT))
2584 {
2585 IfFailGoto(E_FAIL, lFail);
2586 }
2587
2588 // This is only supported for COM interop.
2589 if (m_ms != MARSHAL_SCENARIO_COMINTEROP)
2590 {
2591 IfFailGoto(E_FAIL, lFail);
2592 }
2593
2594 m_type = MARSHAL_TYPE_OLECOLOR;
2595 }
2596#endif // FEATURE_COMINTEROP
2597 else if (sig.IsClassThrowing(pModule, g_RuntimeTypeHandleClassName, pTypeContext))
2598 {
2599 if (nativeType != NATIVE_TYPE_DEFAULT)
2600 {
2601 IfFailGoto(E_FAIL, lFail);
2602 }
2603
2604 m_type = MARSHAL_TYPE_RUNTIMETYPEHANDLE;
2605 }
2606 else if (sig.IsClassThrowing(pModule, g_RuntimeFieldHandleClassName, pTypeContext))
2607 {
2608 if (nativeType != NATIVE_TYPE_DEFAULT)
2609 {
2610 IfFailGoto(E_FAIL, lFail);
2611 }
2612
2613 m_type = MARSHAL_TYPE_RUNTIMEFIELDHANDLE;
2614 }
2615 else if (sig.IsClassThrowing(pModule, g_RuntimeMethodHandleClassName, pTypeContext))
2616 {
2617 if (nativeType != NATIVE_TYPE_DEFAULT)
2618 {
2619 IfFailGoto(E_FAIL, lFail);
2620 }
2621
2622 m_type = MARSHAL_TYPE_RUNTIMEMETHODHANDLE;
2623 }
2624 else
2625 {
2626 m_pMT = sig.GetTypeHandleThrowing(pModule, pTypeContext).GetMethodTable();
2627 if (m_pMT == NULL)
2628 break;
2629
2630#ifdef FEATURE_COMINTEROP
2631 // Handle Nullable<T> and KeyValuePair<K, V> for WinRT
2632 if (m_ms == MARSHAL_SCENARIO_WINRT)
2633 {
2634 if (m_pMT->HasSameTypeDefAs(g_pNullableClass))
2635 {
2636 m_type = MARSHAL_TYPE_NULLABLE;
2637 m_args.m_pMT = m_pMT;
2638 break;
2639 }
2640
2641 if (m_pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__KEYVALUEPAIRGENERIC)))
2642 {
2643 m_type = MARSHAL_TYPE_KEYVALUEPAIR;
2644 m_args.m_pMT = m_pMT;
2645 break;
2646 }
2647
2648 if (!m_pMT->IsLegalNonArrayWinRTType())
2649 {
2650 m_resID = IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE;
2651 IfFailGoto(E_FAIL, lFail);
2652 }
2653 }
2654#endif // FEATURE_COMINTEROP
2655
2656 if (m_pMT->HasInstantiation())
2657 {
2658 m_resID = IDS_EE_BADMARSHAL_GENERICS_RESTRICTION;
2659 IfFailGoto(E_FAIL, lFail);
2660 }
2661
2662 UINT managedSize = m_pMT->GetAlignedNumInstanceFieldBytes();
2663 UINT nativeSize = m_pMT->GetNativeSize();
2664
2665 if ( nativeSize > 0xfff0 ||
2666 managedSize > 0xfff0)
2667 {
2668 m_resID = IDS_EE_STRUCTTOOCOMPLEX;
2669 IfFailGoto(E_FAIL, lFail);
2670 }
2671
2672 if (m_pMT->IsBlittable())
2673 {
2674 if (!(nativeType == NATIVE_TYPE_DEFAULT || nativeType == NATIVE_TYPE_STRUCT))
2675 {
2676 m_resID = IDS_EE_BADMARSHAL_VALUETYPE;
2677 IfFailGoto(E_FAIL, lFail);
2678 }
2679
2680 if (m_byref && !isParam)
2681 {
2682 // Override the prohibition on byref returns so that IJW works
2683 m_byref = FALSE;
2684 m_type = ((sizeof(void*) == 4) ? MARSHAL_TYPE_GENERIC_4 : MARSHAL_TYPE_GENERIC_8);
2685 }
2686 else
2687 {
2688#ifdef _TARGET_X86_
2689 // JIT64 is not aware of normalized value types and this optimization
2690 // (returning small value types by value in registers) is already done in JIT64.
2691 if ( !m_byref // Permit register-sized structs as return values
2692 && !isParam
2693 && CorIsPrimitiveType(m_pMT->GetInternalCorElementType())
2694 && !IsUnmanagedValueTypeReturnedByRef(nativeSize)
2695 && managedSize <= sizeof(void*)
2696 && nativeSize <= sizeof(void*))
2697 {
2698 m_type = MARSHAL_TYPE_GENERIC_4;
2699 m_args.m_pMT = m_pMT;
2700 }
2701 else
2702#endif // _TARGET_X86_
2703 {
2704 m_args.m_pMT = m_pMT;
2705 m_type = MARSHAL_TYPE_BLITTABLEVALUECLASS;
2706 }
2707 }
2708 }
2709 else if (m_pMT->HasLayout())
2710 {
2711 if (!(nativeType == NATIVE_TYPE_DEFAULT || nativeType == NATIVE_TYPE_STRUCT))
2712 {
2713 m_resID = IDS_EE_BADMARSHAL_VALUETYPE;
2714 IfFailGoto(E_FAIL, lFail);
2715 }
2716
2717 m_args.m_pMT = m_pMT;
2718 m_type = MARSHAL_TYPE_VALUECLASS;
2719 }
2720 }
2721 break;
2722 }
2723
2724 case ELEMENT_TYPE_SZARRAY:
2725 case ELEMENT_TYPE_ARRAY:
2726 {
2727 // Get class info from array.
2728 TypeHandle arrayTypeHnd = sig.GetTypeHandleThrowing(pModule, pTypeContext);
2729 _ASSERTE(!arrayTypeHnd.IsNull());
2730
2731 ArrayTypeDesc* asArray = arrayTypeHnd.AsArray();
2732 if (asArray == NULL)
2733 IfFailGoto(E_FAIL, lFail);
2734
2735 TypeHandle thElement = asArray->GetTypeParam();
2736
2737#ifdef FEATURE_COMINTEROP
2738 if (m_ms != MARSHAL_SCENARIO_WINRT)
2739#endif // FEATURE_COMINTEROP
2740 {
2741 if (thElement.HasInstantiation())
2742 {
2743 m_resID = IDS_EE_BADMARSHAL_GENERICS_RESTRICTION;
2744 IfFailGoto(E_FAIL, lFail);
2745 }
2746 }
2747
2748 unsigned ofs = 0;
2749 if (arrayTypeHnd.GetMethodTable())
2750 {
2751 ofs = ArrayBase::GetDataPtrOffset(arrayTypeHnd.GetMethodTable());
2752 if (ofs > 0xffff)
2753 {
2754 ofs = 0; // can't represent it, so pass on magic value (which causes fallback to regular ML code)
2755 }
2756 }
2757
2758 // Handle retrieving the information for the array type.
2759 IfFailGoto(HandleArrayElemType(&ParamInfo, (UINT16)ofs, thElement, asArray->GetRank(), mtype == ELEMENT_TYPE_SZARRAY, isParam, pAssembly), lFail);
2760 break;
2761 }
2762
2763 default:
2764 m_resID = IDS_EE_BADMARSHAL_BADMANAGED;
2765 }
2766
2767lExit:
2768#ifdef FEATURE_COMINTEROP
2769//Field scenario is not blocked here because we don't want to block loading structs that
2770//have the types which we are blocking, but never pass it to Interop.
2771
2772 if (AppX::IsAppXProcess() && ms != MarshalInfo::MARSHAL_SCENARIO_FIELD)
2773 {
2774 bool set_error = false;
2775 switch (m_type)
2776 {
2777 case MARSHAL_TYPE_ANSIBSTR:
2778 m_resID = IDS_EE_BADMARSHAL_TYPE_ANSIBSTR;
2779 set_error = true;
2780 break;
2781 case MARSHAL_TYPE_VBBYVALSTR:
2782 case MARSHAL_TYPE_VBBYVALSTRW:
2783 m_resID = IDS_EE_BADMARSHAL_TYPE_VBBYVALSTR;
2784 set_error = true;
2785 break;
2786 case MARSHAL_TYPE_REFERENCECUSTOMMARSHALER:
2787 m_resID = IDS_EE_BADMARSHAL_TYPE_REFERENCECUSTOMMARSHALER;
2788 set_error = true;
2789 break;
2790 case MARSHAL_TYPE_ASANYA:
2791 case MARSHAL_TYPE_ASANYW:
2792 m_resID = IDS_EE_BADMARSHAL_TYPE_ASANYA;
2793 set_error = true;
2794 break;
2795 case MARSHAL_TYPE_INTERFACE:
2796 if (m_fDispItf)
2797 {
2798 m_resID = IDS_EE_BADMARSHAL_TYPE_IDISPATCH;
2799 set_error = true;
2800 }
2801 break;
2802 }
2803
2804 if (set_error)
2805 COMPlusThrow(kPlatformNotSupportedException, m_resID);
2806
2807 }
2808
2809 if (IsWinRTScenario() && !IsSupportedForWinRT(m_type))
2810 {
2811 // the marshaler we came up with is not supported in WinRT scenarios
2812 m_type = MARSHAL_TYPE_UNKNOWN;
2813 m_resID = IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE;
2814 goto lReallyExit;
2815 }
2816#endif // FEATURE_COMINTEROP
2817
2818 if (m_byref && !isParam)
2819 {
2820 // byref returns don't work: the thing pointed to lives on
2821 // a stack that disappears!
2822 m_type = MARSHAL_TYPE_UNKNOWN;
2823 goto lReallyExit;
2824 }
2825
2826 //---------------------------------------------------------------------
2827 // Now, figure out the IN/OUT status.
2828 // Also set the m_fOleVarArgCandidate here to save perf of invoking Metadata API
2829 //---------------------------------------------------------------------
2830 m_fOleVarArgCandidate = FALSE;
2831 if (m_type != MARSHAL_TYPE_UNKNOWN && IsInOnly(m_type) && !m_byref)
2832 {
2833 // If we got here, the parameter is something like an "int" where
2834 // [in] is the only semantically valid choice. Since there is no
2835 // possible way to interpret an [out] for such a type, we will ignore
2836 // the metadata and force the bits to "in". We could have defined
2837 // it as an error instead but this is less likely to cause problems
2838 // with metadata autogenerated from typelibs and poorly
2839 // defined C headers.
2840 //
2841 m_in = TRUE;
2842 m_out = FALSE;
2843 }
2844 else
2845 {
2846
2847 // Capture and save away "In/Out" bits. If none is present, set both to FALSE (they will be properly defaulted downstream)
2848 if (token == mdParamDefNil)
2849 {
2850 m_in = FALSE;
2851 m_out = FALSE;
2852 }
2853 else if (TypeFromToken(token) != mdtParamDef)
2854 {
2855 _ASSERTE(TypeFromToken(token) == mdtFieldDef);
2856
2857 // Field setters are always In, the flags are ignored for return values of getters
2858 m_in = TRUE;
2859 m_out = FALSE;
2860 }
2861 else
2862 {
2863 IMDInternalImport *pInternalImport = pModule->GetMDImport();
2864 USHORT usSequence;
2865 DWORD dwAttr;
2866 LPCSTR szParamName_Ignore;
2867
2868 if (FAILED(pInternalImport->GetParamDefProps(token, &usSequence, &dwAttr, &szParamName_Ignore)))
2869 {
2870 m_in = FALSE;
2871 m_out = FALSE;
2872 }
2873 else
2874 {
2875 m_in = IsPdIn(dwAttr) != 0;
2876 m_out = IsPdOut(dwAttr) != 0;
2877#ifdef FEATURE_COMINTEROP
2878 // set m_fOleVarArgCandidate. The rule is same as the one defined in vm\tlbexp.cpp
2879 if(paramidx == numArgs && // arg is the last arg of the method
2880 !(dwAttr & PARAMFLAG_FOPT) && // arg is not a optional arg
2881 !IsNilToken(token) && // token is not a nil token
2882 (m_type == MARSHAL_TYPE_SAFEARRAY) && // arg is marshaled as SafeArray
2883 (m_arrayElementType == VT_VARIANT)) // the element of the safearray is VARIANT
2884 {
2885 // check if it has default value
2886 MDDefaultValue defaultValue;
2887 if (SUCCEEDED(pInternalImport->GetDefaultValue(token, &defaultValue)) && defaultValue.m_bType == ELEMENT_TYPE_VOID)
2888 {
2889 // check if it has params attribute
2890 if (pInternalImport->GetCustomAttributeByName(token, INTEROP_PARAMARRAY_TYPE, 0,0) == S_OK)
2891 m_fOleVarArgCandidate = TRUE;
2892 }
2893 }
2894#endif
2895 }
2896 }
2897
2898 // If neither IN nor OUT are true, this signals the URT to use the default
2899 // rules.
2900 if (!m_in && !m_out)
2901 {
2902 if (m_byref ||
2903 (mtype == ELEMENT_TYPE_CLASS
2904 && !(sig.IsStringType(pModule, pTypeContext))
2905 && sig.IsClass(pModule, g_StringBufferClassName, pTypeContext)))
2906 {
2907 m_in = TRUE;
2908 m_out = TRUE;
2909 }
2910 else
2911 {
2912 m_in = TRUE;
2913 m_out = FALSE;
2914 }
2915
2916 }
2917 }
2918
2919lReallyExit:
2920
2921#ifdef _DEBUG
2922 DumpMarshalInfo(pModule, sig, pTypeContext, token, ms, nlType, nlFlags);
2923#endif
2924 return;
2925
2926
2927 lFail:
2928 // We got here because of an illegal ELEMENT_TYPE/NATIVE_TYPE combo.
2929 m_type = MARSHAL_TYPE_UNKNOWN;
2930 //_ASSERTE(!"Invalid ELEMENT_TYPE/NATIVE_TYPE combination");
2931 goto lExit;
2932}
2933#ifdef _PREFAST_
2934#pragma warning(pop)
2935#endif
2936
2937VOID MarshalInfo::EmitOrThrowInteropParamException(NDirectStubLinker* psl, BOOL fMngToNative, UINT resID, UINT paramIdx)
2938{
2939 CONTRACTL
2940 {
2941 THROWS;
2942 GC_TRIGGERS;
2943 MODE_ANY;
2944 }
2945 CONTRACTL_END;
2946
2947#ifdef FEATURE_COMINTEROP
2948 // If this is not forward COM interop, throw the exception right away. We rely on this
2949 // for example in code:ComPreStubWorker when we fire the InvalidMemberDeclaration MDA.
2950 if ((m_ms == MARSHAL_SCENARIO_COMINTEROP || m_ms == MARSHAL_SCENARIO_WINRT) && fMngToNative)
2951 {
2952 psl->SetInteropParamExceptionInfo(resID, paramIdx);
2953 return;
2954 }
2955#endif // FEATURE_COMINTEROP
2956
2957 ThrowInteropParamException(resID, paramIdx);
2958}
2959
2960
2961HRESULT MarshalInfo::HandleArrayElemType(NativeTypeParamInfo *pParamInfo, UINT16 optbaseoffset, TypeHandle thElement, int iRank, BOOL fNoLowerBounds, BOOL isParam, Assembly *pAssembly)
2962{
2963 CONTRACTL
2964 {
2965 STANDARD_VM_CHECK;
2966 PRECONDITION(CheckPointer(pParamInfo));
2967 }
2968 CONTRACTL_END;
2969
2970 ArrayMarshalInfo arrayMarshalInfo(amiRuntime);
2971
2972
2973 //
2974 // Store rank and bound information.
2975 //
2976
2977 m_iArrayRank = iRank;
2978 m_nolowerbounds = fNoLowerBounds;
2979
2980
2981 //
2982 // Determine which type of marshaler to use.
2983 //
2984
2985#ifdef FEATURE_COMINTEROP
2986 if (m_ms == MARSHAL_SCENARIO_WINRT)
2987 {
2988 m_type = MARSHAL_TYPE_HIDDENLENGTHARRAY;
2989 }
2990 else if (pParamInfo->m_NativeType == NATIVE_TYPE_SAFEARRAY)
2991 {
2992 m_type = MARSHAL_TYPE_SAFEARRAY;
2993 }
2994 else
2995#endif // FEATURE_COMINTEROP
2996 if (pParamInfo->m_NativeType == NATIVE_TYPE_ARRAY)
2997 {
2998 m_type = MARSHAL_TYPE_NATIVEARRAY;
2999 }
3000 else if (pParamInfo->m_NativeType == NATIVE_TYPE_DEFAULT)
3001 {
3002#ifdef FEATURE_COMINTEROP
3003 if (m_ms != MARSHAL_SCENARIO_NDIRECT)
3004 {
3005 m_type = MARSHAL_TYPE_SAFEARRAY;
3006 }
3007 else
3008#endif // FEATURE_COMINTEROP
3009 {
3010 m_type = MARSHAL_TYPE_NATIVEARRAY;
3011 }
3012 }
3013 else
3014 {
3015 m_resID = IDS_EE_BADMARSHAL_ARRAY;
3016 return E_FAIL;
3017 }
3018
3019#ifdef FEATURE_COMINTEROP
3020 if (m_type == MARSHAL_TYPE_SAFEARRAY)
3021 {
3022 arrayMarshalInfo.InitForSafeArray(m_ms, thElement, pParamInfo->m_SafeArrayElementVT, m_fAnsi);
3023 }
3024 else if (m_type == MARSHAL_TYPE_HIDDENLENGTHARRAY)
3025 {
3026 arrayMarshalInfo.InitForHiddenLengthArray(thElement);
3027 }
3028 else
3029#endif // FEATURE_COMINTEROP
3030 {
3031 _ASSERTE(m_type == MARSHAL_TYPE_NATIVEARRAY);
3032 arrayMarshalInfo.InitForNativeArray(m_ms, thElement, pParamInfo->m_ArrayElementType, m_fAnsi);
3033 }
3034
3035 // Make sure the marshalling information is valid.
3036 if (!arrayMarshalInfo.IsValid())
3037 {
3038 m_resID = arrayMarshalInfo.GetErrorResourceId();
3039 return E_FAIL;
3040 }
3041
3042 // Set the array type handle and VARTYPE to use for marshalling.
3043 m_hndArrayElemType = arrayMarshalInfo.GetElementTypeHandle();
3044 m_arrayElementType = arrayMarshalInfo.GetElementVT();
3045
3046 if (m_type == MARSHAL_TYPE_NATIVEARRAY)
3047 {
3048 // Retrieve the extra information associated with the native array marshaling.
3049 m_args.na.m_vt = m_arrayElementType;
3050 m_args.na.m_pMT = !m_hndArrayElemType.IsTypeDesc() ? m_hndArrayElemType.AsMethodTable() : NULL;
3051 m_args.na.m_optionalbaseoffset = optbaseoffset;
3052 m_countParamIdx = pParamInfo->m_CountParamIdx;
3053 m_multiplier = pParamInfo->m_Multiplier;
3054 m_additive = pParamInfo->m_Additive;
3055 }
3056#ifdef FEATURE_COMINTEROP
3057 else if (m_type == MARSHAL_TYPE_HIDDENLENGTHARRAY)
3058 {
3059 m_args.na.m_optionalbaseoffset = optbaseoffset;
3060
3061 m_args.na.m_vt = m_arrayElementType;
3062 m_args.na.m_pMT = m_hndArrayElemType.AsMethodTable();
3063 m_args.na.m_cbElementSize = arrayMarshalInfo.GetElementSize();
3064 m_args.na.m_redirectedTypeIndex = arrayMarshalInfo.GetRedirectedTypeIndex();
3065 }
3066#endif // FEATURE_COMINTEROP
3067
3068 return S_OK;
3069}
3070
3071ILMarshaler* CreateILMarshaler(MarshalInfo::MarshalType mtype, NDirectStubLinker* psl)
3072{
3073 CONTRACTL
3074 {
3075 THROWS;
3076 GC_NOTRIGGER;
3077 SO_TOLERANT;
3078 MODE_ANY;
3079 }
3080 CONTRACTL_END;
3081 ILMarshaler* pMarshaler = NULL;
3082 switch (mtype)
3083 {
3084
3085#define DEFINE_MARSHALER_TYPE(mt, mclass, fWinRTSupported) \
3086 case MarshalInfo::mt: \
3087 pMarshaler = new IL##mclass(); \
3088 break;
3089#include "mtypes.h"
3090#undef DEFINE_MARSHALER_TYPE
3091
3092 default:
3093 UNREACHABLE_MSG("unexpected MarshalType passed to CreateILMarshaler");
3094 }
3095
3096 pMarshaler->SetNDirectStubLinker(psl);
3097 return pMarshaler;
3098}
3099
3100
3101
3102DWORD CalculateArgumentMarshalFlags(BOOL byref, BOOL in, BOOL out, BOOL fMngToNative)
3103{
3104 LIMITED_METHOD_CONTRACT;
3105 DWORD dwMarshalFlags = 0;
3106
3107 if (byref)
3108 {
3109 dwMarshalFlags |= MARSHAL_FLAG_BYREF;
3110 }
3111
3112 if (in)
3113 {
3114 dwMarshalFlags |= MARSHAL_FLAG_IN;
3115 }
3116
3117 if (out)
3118 {
3119 dwMarshalFlags |= MARSHAL_FLAG_OUT;
3120 }
3121
3122 if (fMngToNative)
3123 {
3124 dwMarshalFlags |= MARSHAL_FLAG_CLR_TO_NATIVE;
3125 }
3126
3127 return dwMarshalFlags;
3128}
3129
3130DWORD CalculateReturnMarshalFlags(BOOL hrSwap, BOOL fMngToNative)
3131{
3132 LIMITED_METHOD_CONTRACT;
3133 DWORD dwMarshalFlags = MARSHAL_FLAG_RETVAL;
3134
3135 if (hrSwap)
3136 {
3137 dwMarshalFlags |= MARSHAL_FLAG_HRESULT_SWAP;
3138 }
3139
3140 if (fMngToNative)
3141 {
3142 dwMarshalFlags |= MARSHAL_FLAG_CLR_TO_NATIVE;
3143 }
3144
3145 return dwMarshalFlags;
3146}
3147
3148void MarshalInfo::GenerateArgumentIL(NDirectStubLinker* psl,
3149 int argOffset, // the argument's index is m_paramidx + argOffset
3150 UINT nativeStackOffset, // offset of the argument on the native stack
3151 BOOL fMngToNative)
3152{
3153 CONTRACTL
3154 {
3155 STANDARD_VM_CHECK;
3156 PRECONDITION(CheckPointer(psl));
3157 }
3158 CONTRACTL_END;
3159
3160 if (m_type == MARSHAL_TYPE_UNKNOWN)
3161 {
3162 EmitOrThrowInteropParamException(psl, fMngToNative, m_resID, m_paramidx + 1); // m_paramidx is 0-based, but the user wants to see a 1-based index
3163 return;
3164 }
3165
3166 // set up m_corArgSize and m_nativeArgSize
3167 SetupArgumentSizes();
3168
3169 MarshalerOverrideStatus amostat;
3170 UINT resID = IDS_EE_BADMARSHAL_RESTRICTION;
3171 amostat = (GetArgumentOverrideProc(m_type)) (psl,
3172 m_byref,
3173 m_in,
3174 m_out,
3175 fMngToNative,
3176 &m_args,
3177 &resID,
3178 m_paramidx + argOffset,
3179 nativeStackOffset);
3180
3181
3182 if (amostat == OVERRIDDEN)
3183 {
3184 return;
3185 }
3186
3187 if (amostat == DISALLOWED)
3188 {
3189 EmitOrThrowInteropParamException(psl, fMngToNative, resID, m_paramidx + 1); // m_paramidx is 0-based, but the user wants to see a 1-based index
3190 return;
3191 }
3192
3193 CONSISTENCY_CHECK(amostat == HANDLEASNORMAL);
3194
3195 NewHolder<ILMarshaler> pMarshaler = CreateILMarshaler(m_type, psl);
3196 DWORD dwMarshalFlags = CalculateArgumentMarshalFlags(m_byref, m_in, m_out, fMngToNative);
3197
3198 if (!pMarshaler->SupportsArgumentMarshal(dwMarshalFlags, &resID))
3199 {
3200 EmitOrThrowInteropParamException(psl, fMngToNative, resID, m_paramidx + 1); // m_paramidx is 0-based, but the user wants to see a 1-based index
3201 return;
3202 }
3203
3204 ILCodeStream* pcsMarshal = psl->GetMarshalCodeStream();
3205 ILCodeStream* pcsUnmarshal = psl->GetUnmarshalCodeStream();
3206 ILCodeStream* pcsDispatch = psl->GetDispatchCodeStream();
3207
3208 pcsMarshal->EmitNOP("// argument { ");
3209 pcsUnmarshal->EmitNOP("// argument { ");
3210
3211 pMarshaler->EmitMarshalArgument(pcsMarshal, pcsUnmarshal, m_paramidx + argOffset, dwMarshalFlags, &m_args);
3212
3213 //
3214 // Increment a counter so that when the finally clause
3215 // is run, we only run the cleanup that is needed.
3216 //
3217 if (pMarshaler->NeedsMarshalCleanupIndex())
3218 {
3219 // we don't bother writing to the counter if marshaling does not need cleanup
3220 psl->EmitSetArgMarshalIndex(pcsMarshal, NDirectStubLinker::CLEANUP_INDEX_ARG0_MARSHAL + m_paramidx + argOffset);
3221 }
3222 if (pMarshaler->NeedsUnmarshalCleanupIndex())
3223 {
3224 // we don't bother writing to the counter if unmarshaling does not need exception cleanup
3225 psl->EmitSetArgMarshalIndex(pcsUnmarshal, NDirectStubLinker::CLEANUP_INDEX_ARG0_UNMARSHAL + m_paramidx + argOffset);
3226 }
3227
3228 pcsMarshal->EmitNOP("// } argument");
3229 pcsUnmarshal->EmitNOP("// } argument");
3230
3231 pMarshaler->EmitSetupArgument(pcsDispatch);
3232 if (m_paramidx == 0)
3233 {
3234 CorCallingConvention callConv = psl->GetStubTargetCallingConv();
3235 if ((callConv & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_UNMANAGED_CALLCONV_THISCALL)
3236 {
3237 // Make sure the 'this' argument to thiscall is of native int type; JIT asserts this.
3238 pcsDispatch->EmitCONV_I();
3239 }
3240 }
3241}
3242
3243void MarshalInfo::GenerateReturnIL(NDirectStubLinker* psl,
3244 int argOffset,
3245 BOOL fMngToNative,
3246 BOOL fieldGetter,
3247 BOOL retval)
3248{
3249 CONTRACTL
3250 {
3251 STANDARD_VM_CHECK;
3252 PRECONDITION(CheckPointer(psl));
3253 }
3254 CONTRACTL_END;
3255
3256 MarshalerOverrideStatus amostat;
3257 UINT resID = IDS_EE_BADMARSHAL_RESTRICTION;
3258
3259 if (m_type == MARSHAL_TYPE_UNKNOWN)
3260 {
3261 amostat = HANDLEASNORMAL;
3262 }
3263 else
3264 {
3265 amostat = (GetReturnOverrideProc(m_type)) (psl,
3266 fMngToNative,
3267 retval,
3268 &m_args,
3269 &resID);
3270 }
3271
3272 if (amostat == DISALLOWED)
3273 {
3274 EmitOrThrowInteropParamException(psl, fMngToNative, resID, 0);
3275 return;
3276 }
3277
3278 if (amostat == HANDLEASNORMAL)
3279 {
3280 // Historically we have always allowed reading fields that are marshaled as C arrays.
3281 if (m_type == MARSHAL_TYPE_UNKNOWN || (!fieldGetter && m_type == MARSHAL_TYPE_NATIVEARRAY))
3282 {
3283 EmitOrThrowInteropParamException(psl, fMngToNative, m_resID, 0);
3284 return;
3285 }
3286
3287 NewHolder<ILMarshaler> pMarshaler = CreateILMarshaler(m_type, psl);
3288 DWORD dwMarshalFlags = CalculateReturnMarshalFlags(retval, fMngToNative);
3289
3290 if (!pMarshaler->SupportsReturnMarshal(dwMarshalFlags, &resID))
3291 {
3292 EmitOrThrowInteropParamException(psl, fMngToNative, resID, 0);
3293 return;
3294 }
3295
3296 ILCodeStream* pcsMarshal = psl->GetMarshalCodeStream();
3297 ILCodeStream* pcsUnmarshal = psl->GetReturnUnmarshalCodeStream();
3298 ILCodeStream* pcsDispatch = psl->GetDispatchCodeStream();
3299
3300 pcsMarshal->EmitNOP("// return { ");
3301 pcsUnmarshal->EmitNOP("// return { ");
3302
3303 UINT16 wNativeSize = GetNativeSize(m_type, m_ms);
3304
3305 // The following statement behaviour has existed for a long time. By aligning the size of the return
3306 // value up to stack slot size, we prevent EmitMarshalReturnValue from distinguishing between, say, 3-byte
3307 // structure and 4-byte structure. The former is supposed to be returned by-ref using a secret argument
3308 // (at least in MSVC compiled code) while the latter is returned in EAX. We are keeping the behavior for
3309 // now for backward compatibility.
3310 X86_ONLY(wNativeSize = StackElemSize(wNativeSize));
3311
3312 pMarshaler->EmitMarshalReturnValue(pcsMarshal, pcsUnmarshal, pcsDispatch, m_paramidx + argOffset, wNativeSize, dwMarshalFlags, &m_args);
3313
3314 pcsMarshal->EmitNOP("// } return");
3315 pcsUnmarshal->EmitNOP("// } return");
3316
3317 return;
3318 }
3319}
3320
3321void MarshalInfo::SetupArgumentSizes()
3322{
3323 CONTRACTL
3324 {
3325 NOTHROW;
3326 GC_NOTRIGGER;
3327 MODE_ANY;
3328 }
3329 CONTRACTL_END;
3330
3331 if (m_byref)
3332 {
3333 m_managedArgSize = StackElemSize(sizeof(void*));
3334 m_nativeArgSize = StackElemSize(sizeof(void*));
3335 }
3336 else
3337 {
3338 m_managedArgSize = StackElemSize(GetManagedSize(m_type, m_ms));
3339 m_nativeArgSize = StackElemSize(GetNativeSize(m_type, m_ms));
3340 }
3341
3342#ifdef ENREGISTERED_PARAMTYPE_MAXSIZE
3343 if (m_managedArgSize > ENREGISTERED_PARAMTYPE_MAXSIZE)
3344 m_managedArgSize = StackElemSize(sizeof(void*));
3345
3346 if (m_nativeArgSize > ENREGISTERED_PARAMTYPE_MAXSIZE)
3347 m_nativeArgSize = StackElemSize(sizeof(void*));
3348#endif // ENREGISTERED_PARAMTYPE_MAXSIZE
3349}
3350
3351UINT16 MarshalInfo::GetManagedSize(MarshalType mtype, MarshalScenario ms)
3352{
3353 CONTRACTL
3354 {
3355 NOTHROW;
3356 GC_NOTRIGGER;
3357 MODE_ANY;
3358 }
3359 CONTRACTL_END;
3360
3361 static const BYTE managedSizes[]=
3362 {
3363 #define DEFINE_MARSHALER_TYPE(mt, mclass, fWinRTSupported) IL##mclass::c_CLRSize,
3364 #include "mtypes.h"
3365 };
3366
3367 _ASSERTE((SIZE_T)mtype < COUNTOF(managedSizes));
3368 BYTE managedSize = managedSizes[mtype];
3369
3370 if (managedSize == VARIABLESIZE)
3371 {
3372 switch (mtype)
3373 {
3374
3375 case MARSHAL_TYPE_BLITTABLEVALUECLASS:
3376 case MARSHAL_TYPE_VALUECLASS:
3377#ifdef FEATURE_COMINTEROP
3378 case MARSHAL_TYPE_DATETIME:
3379 case MARSHAL_TYPE_NULLABLE:
3380 case MARSHAL_TYPE_KEYVALUEPAIR:
3381#endif // FEATURE_COMINTEROP
3382 return (UINT16) m_pMT->GetAlignedNumInstanceFieldBytes();
3383 break;
3384
3385 default:
3386 _ASSERTE(0);
3387 }
3388 }
3389
3390 return managedSize;
3391}
3392
3393UINT16 MarshalInfo::GetNativeSize(MarshalType mtype, MarshalScenario ms)
3394{
3395 CONTRACTL
3396 {
3397 NOTHROW;
3398 GC_NOTRIGGER;
3399 MODE_ANY;
3400 }
3401 CONTRACTL_END;
3402
3403 static const BYTE nativeSizes[]=
3404 {
3405 #define DEFINE_MARSHALER_TYPE(mt, mclass, fWinRTSupported) IL##mclass::c_nativeSize,
3406 #include "mtypes.h"
3407 };
3408
3409 _ASSERTE((SIZE_T)mtype < COUNTOF(nativeSizes));
3410 BYTE nativeSize = nativeSizes[mtype];
3411
3412 if (nativeSize == VARIABLESIZE)
3413 {
3414 switch (mtype)
3415 {
3416 case MARSHAL_TYPE_BLITTABLEVALUECLASS:
3417 case MARSHAL_TYPE_VALUECLASS:
3418 return (UINT16) m_pMT->GetNativeSize();
3419
3420 default:
3421 _ASSERTE(0);
3422 }
3423 }
3424
3425 return nativeSize;
3426}
3427
3428bool MarshalInfo::IsInOnly(MarshalType mtype)
3429{
3430 CONTRACTL
3431 {
3432 NOTHROW;
3433 GC_NOTRIGGER;
3434 MODE_ANY;
3435 }
3436 CONTRACTL_END;
3437
3438 static const bool ILMarshalerIsInOnly[] =
3439 {
3440 #define DEFINE_MARSHALER_TYPE(mt, mclass, fWinRTSupported) \
3441 (IL##mclass::c_fInOnly ? true : false),
3442
3443 #include "mtypes.h"
3444 };
3445
3446 return ILMarshalerIsInOnly[mtype];
3447}
3448
3449bool MarshalInfo::IsSupportedForWinRT(MarshalType mtype)
3450{
3451 CONTRACTL
3452 {
3453 NOTHROW;
3454 GC_NOTRIGGER;
3455 MODE_ANY;
3456 }
3457 CONTRACTL_END;
3458
3459 static const bool MarshalerSupportsWinRT[] =
3460 {
3461 #define DEFINE_MARSHALER_TYPE(mt, mclass, fWinRTSupported) \
3462 fWinRTSupported,
3463
3464 #include "mtypes.h"
3465 };
3466
3467 return MarshalerSupportsWinRT[mtype];
3468}
3469
3470OVERRIDEPROC MarshalInfo::GetArgumentOverrideProc(MarshalType mtype)
3471{
3472 CONTRACTL
3473 {
3474 NOTHROW;
3475 GC_NOTRIGGER;
3476 MODE_ANY;
3477 }
3478 CONTRACTL_END;
3479
3480 static const OVERRIDEPROC ILArgumentOverrideProcs[] =
3481 {
3482 #define DEFINE_MARSHALER_TYPE(mt, mclass, fWinRTSupported) IL##mclass::ArgumentOverride,
3483 #include "mtypes.h"
3484 };
3485
3486 _ASSERTE((SIZE_T)mtype < COUNTOF(ILArgumentOverrideProcs));
3487 return ILArgumentOverrideProcs[mtype];
3488}
3489
3490RETURNOVERRIDEPROC MarshalInfo::GetReturnOverrideProc(MarshalType mtype)
3491{
3492 CONTRACTL
3493 {
3494 NOTHROW;
3495 GC_NOTRIGGER;
3496 MODE_ANY;
3497 }
3498 CONTRACTL_END;
3499
3500 static const RETURNOVERRIDEPROC ILReturnOverrideProcs[] =
3501 {
3502 #define DEFINE_MARSHALER_TYPE(mt, mclass, fWinRTSupported) IL##mclass::ReturnOverride,
3503 #include "mtypes.h"
3504 };
3505
3506 _ASSERTE((SIZE_T)mtype < COUNTOF(ILReturnOverrideProcs));
3507 return ILReturnOverrideProcs[mtype];
3508}
3509
3510void MarshalInfo::GetItfMarshalInfo(ItfMarshalInfo* pInfo)
3511{
3512 STANDARD_VM_CONTRACT;
3513
3514 GetItfMarshalInfo(TypeHandle(m_pMT),
3515#ifdef FEATURE_COMINTEROP
3516 TypeHandle(m_pDefaultItfMT),
3517#else // FEATURE_COMINTEROP
3518 TypeHandle(),
3519#endif // FEATURE_COMINTEROP
3520 m_fDispItf,
3521 m_fInspItf,
3522 m_ms,
3523 pInfo);
3524}
3525
3526void MarshalInfo::GetItfMarshalInfo(TypeHandle th, TypeHandle thItf, BOOL fDispItf, BOOL fInspItf, MarshalScenario ms, ItfMarshalInfo *pInfo)
3527{
3528 CONTRACTL
3529 {
3530 THROWS;
3531 GC_TRIGGERS;
3532 MODE_ANY;
3533 PRECONDITION(CheckPointer(pInfo));
3534 PRECONDITION(!th.IsNull());
3535 PRECONDITION(!th.IsTypeDesc());
3536 }
3537 CONTRACTL_END;
3538
3539#ifdef FEATURE_COMINTEROP
3540
3541 // Initialize the output parameter.
3542 pInfo->dwFlags = 0;
3543 pInfo->thItf = TypeHandle();
3544 pInfo->thClass = TypeHandle();
3545
3546 if (!th.IsInterface())
3547 {
3548 // If the parameter is not System.Object.
3549 if (!th.IsObjectType())
3550 {
3551 // Set the class method table.
3552 pInfo->thClass = th;
3553
3554 if (th.IsTypeDesc() || !th.AsMethodTable()->IsWinRTDelegate())
3555 {
3556 // If this is not a WinRT delegate, retrieve the default interface method table.
3557 TypeHandle hndDefItfClass;
3558 DefaultInterfaceType DefItfType;
3559
3560 if (!thItf.IsNull())
3561 {
3562 hndDefItfClass = thItf;
3563 DefItfType = DefaultInterfaceType_Explicit;
3564 }
3565 else if (th.IsProjectedFromWinRT() || th.IsExportedToWinRT())
3566 {
3567 // WinRT classes use their WinRT default interface
3568 hndDefItfClass = th.GetMethodTable()->GetDefaultWinRTInterface();
3569 DefItfType = DefaultInterfaceType_Explicit;
3570 }
3571 else
3572 {
3573 DefItfType = GetDefaultInterfaceForClassWrapper(th, &hndDefItfClass);
3574 }
3575 switch (DefItfType)
3576 {
3577 case DefaultInterfaceType_Explicit:
3578 {
3579 pInfo->thItf = hndDefItfClass;
3580 switch (hndDefItfClass.GetComInterfaceType())
3581 {
3582 case ifDispatch:
3583 case ifDual:
3584 pInfo->dwFlags |= ItfMarshalInfo::ITF_MARSHAL_DISP_ITF;
3585 break;
3586
3587 case ifInspectable:
3588 pInfo->dwFlags |= ItfMarshalInfo::ITF_MARSHAL_INSP_ITF;
3589 break;
3590 }
3591 break;
3592 }
3593
3594 case DefaultInterfaceType_AutoDual:
3595 {
3596 pInfo->thItf = hndDefItfClass;
3597 pInfo->dwFlags |= ItfMarshalInfo::ITF_MARSHAL_DISP_ITF;
3598 break;
3599 }
3600
3601 case DefaultInterfaceType_IUnknown:
3602 case DefaultInterfaceType_BaseComClass:
3603 {
3604 break;
3605 }
3606
3607 case DefaultInterfaceType_AutoDispatch:
3608 {
3609 pInfo->thItf = hndDefItfClass;
3610 pInfo->dwFlags |= ItfMarshalInfo::ITF_MARSHAL_DISP_ITF;
3611 break;
3612 }
3613
3614 default:
3615 {
3616 _ASSERTE(!"Invalid default interface type!");
3617 break;
3618 }
3619 }
3620 }
3621 }
3622 else
3623 {
3624 // The type will be marshalled as an IUnknown, IInspectable, or IDispatch pointer depending
3625 // on the value of fDispItf and fInspItf
3626 if (fDispItf)
3627 {
3628 pInfo->dwFlags |= ItfMarshalInfo::ITF_MARSHAL_DISP_ITF;
3629 }
3630 else if (fInspItf)
3631 {
3632 pInfo->dwFlags |= ItfMarshalInfo::ITF_MARSHAL_INSP_ITF;
3633 }
3634
3635 pInfo->dwFlags |= ItfMarshalInfo::ITF_MARSHAL_USE_BASIC_ITF;
3636 }
3637 }
3638 else if (fInspItf)
3639 {
3640 // IInspectable-based interfaces are simple
3641 pInfo->thItf = th;
3642 pInfo->dwFlags |= ItfMarshalInfo::ITF_MARSHAL_INSP_ITF;
3643 }
3644 else
3645 {
3646 // Determine the interface this type will be marshalled as.
3647 if (th.IsComClassInterface())
3648 pInfo->thItf = th.GetDefItfForComClassItf();
3649 else
3650 pInfo->thItf = th;
3651
3652 // Determine if we are dealing with an IDispatch, IInspectable, or IUnknown based interface.
3653 switch (pInfo->thItf.GetComInterfaceType())
3654 {
3655 case ifDispatch:
3656 case ifDual:
3657 pInfo->dwFlags |= ItfMarshalInfo::ITF_MARSHAL_DISP_ITF;
3658 break;
3659
3660 case ifInspectable:
3661 pInfo->dwFlags |= ItfMarshalInfo::ITF_MARSHAL_INSP_ITF;
3662 break;
3663 }
3664
3665 // Look to see if the interface has a coclass defined
3666 pInfo->thClass = th.GetCoClassForInterface();
3667 if (!pInfo->thClass.IsNull())
3668 {
3669 pInfo->dwFlags |= ItfMarshalInfo::ITF_MARSHAL_CLASS_IS_HINT;
3670 }
3671 }
3672
3673 // store the pre-redirection interface type as thNativeItf
3674 pInfo->thNativeItf = pInfo->thItf;
3675
3676 if (ms == MARSHAL_SCENARIO_WINRT)
3677 {
3678 // Use the "class is hint" flag so GetObjectRefFromComIP doesn't verify that the
3679 // WinRT object really supports IInspectable - note that we'll do the verification
3680 // in UnmarshalObjectFromInterface for this exact pInfo->thItf.
3681 pInfo->dwFlags |= ItfMarshalInfo::ITF_MARSHAL_CLASS_IS_HINT;
3682
3683 pInfo->dwFlags |= ItfMarshalInfo::ITF_MARSHAL_WINRT_SCENARIO;
3684
3685 // Perform interface redirection statically here. When the resulting ItfMarshalInfo
3686 // is used for CLR->WinRT marshaling, this is necessary so we know which COM vtable
3687 // to pass out (for instance IList could be marshaled out as IList or IBindableVector
3688 // depending on the marshal scenario). In the WinRT->CLR direction, it's just an
3689 // optimization which saves us from performing redirection at run-time.
3690
3691 if (!pInfo->thItf.IsNull())
3692 {
3693 MethodTable *pNewItfMT1;
3694 MethodTable *pNewItfMT2;
3695 switch (RCW::GetInterfacesForQI(pInfo->thItf.GetMethodTable(), &pNewItfMT1, &pNewItfMT2))
3696 {
3697 case RCW::InterfaceRedirection_None:
3698 case RCW::InterfaceRedirection_UnresolvedIEnumerable:
3699 break;
3700
3701 case RCW::InterfaceRedirection_IEnumerable_RetryOnFailure:
3702 case RCW::InterfaceRedirection_IEnumerable:
3703 case RCW::InterfaceRedirection_Other:
3704 pInfo->thNativeItf = pNewItfMT1;
3705 break;
3706
3707 case RCW::InterfaceRedirection_Other_RetryOnFailure:
3708 pInfo->thNativeItf = pNewItfMT2;
3709 break;
3710 }
3711 }
3712
3713 if (!pInfo->thNativeItf.IsNull())
3714 {
3715 // The native interface is redirected WinRT interface - need to change the flags
3716 _ASSERTE(pInfo->thNativeItf.AsMethodTable()->IsProjectedFromWinRT());
3717
3718 pInfo->dwFlags &= ~ItfMarshalInfo::ITF_MARSHAL_DISP_ITF;
3719 pInfo->dwFlags |= ItfMarshalInfo::ITF_MARSHAL_INSP_ITF;
3720 }
3721 }
3722
3723#else // FEATURE_COMINTEROP
3724 if (!th.IsInterface())
3725 pInfo->thClass = th;
3726 else
3727 pInfo->thItf = th;
3728#endif // FEATURE_COMINTEROP
3729}
3730
3731HRESULT MarshalInfo::TryGetItfMarshalInfo(TypeHandle th, BOOL fDispItf, BOOL fInspItf, ItfMarshalInfo *pInfo)
3732{
3733 CONTRACTL
3734 {
3735 STANDARD_VM_CHECK;
3736 PRECONDITION(!th.IsNull());
3737 PRECONDITION(CheckPointer(pInfo));
3738 }
3739 CONTRACTL_END;
3740
3741 HRESULT hr = S_OK;
3742
3743 EX_TRY
3744 {
3745 GetItfMarshalInfo(th, TypeHandle(), fDispItf, fInspItf,
3746#ifdef FEATURE_COMINTEROP
3747 MARSHAL_SCENARIO_COMINTEROP,
3748#else // FEATURE_COMINTEROP
3749 MARSHAL_SCENARIO_NDIRECT,
3750#endif // FEATURE_COMINTEROP
3751 pInfo);
3752 }
3753 EX_CATCH
3754 {
3755 hr = GET_EXCEPTION()->GetHR();
3756 }
3757 EX_END_CATCH(RethrowTerminalExceptions);
3758
3759 return hr;
3760}
3761
3762#ifdef _DEBUG
3763VOID MarshalInfo::DumpMarshalInfo(Module* pModule, SigPointer sig, const SigTypeContext *pTypeContext, mdToken token,
3764 MarshalScenario ms, CorNativeLinkType nlType, CorNativeLinkFlags nlFlags)
3765{
3766 CONTRACTL
3767 {
3768 THROWS;
3769 GC_TRIGGERS;
3770 MODE_ANY;
3771 }
3772 CONTRACTL_END;
3773
3774 if (LoggingOn(LF_MARSHALER, LL_INFO10))
3775 {
3776 SString logbuf;
3777 StackScratchBuffer scratch;
3778
3779 IMDInternalImport *pInternalImport = pModule->GetMDImport();
3780
3781 logbuf.AppendASCII("------------------------------------------------------------\n");
3782 LOG((LF_MARSHALER, LL_INFO10, logbuf.GetANSI(scratch)));
3783 logbuf.Clear();
3784
3785 logbuf.AppendASCII("Managed type: ");
3786 if (m_byref)
3787 logbuf.AppendASCII("Byref ");
3788
3789 TypeHandle th = sig.GetTypeHandleNT(pModule, pTypeContext);
3790 if (th.IsNull())
3791 logbuf.AppendASCII("<error>");
3792 else
3793 {
3794 SigFormat sigfmt;
3795 sigfmt.AddType(th);
3796 logbuf.AppendUTF8(sigfmt.GetCString());
3797 }
3798
3799 logbuf.AppendASCII("\n");
3800 LOG((LF_MARSHALER, LL_INFO10, logbuf.GetANSI(scratch)));
3801 logbuf.Clear();
3802
3803 logbuf.AppendASCII("NativeType : ");
3804 PCCOR_SIGNATURE pvNativeType;
3805 ULONG cbNativeType;
3806 if (token == mdParamDefNil
3807 || pInternalImport->GetFieldMarshal(token,
3808 &pvNativeType,
3809 &cbNativeType) != S_OK)
3810 {
3811 logbuf.AppendASCII("<absent>");
3812 }
3813 else
3814 {
3815
3816 while (cbNativeType--)
3817 {
3818 char num[100];
3819 sprintf_s(num, COUNTOF(num), "0x%lx ", (ULONG)*pvNativeType);
3820 logbuf.AppendASCII(num);
3821 switch (*(pvNativeType++))
3822 {
3823#define XXXXX(nt) case nt: logbuf.AppendASCII("(" #nt ")"); break;
3824
3825 XXXXX(NATIVE_TYPE_BOOLEAN)
3826 XXXXX(NATIVE_TYPE_I1)
3827
3828 XXXXX(NATIVE_TYPE_U1)
3829 XXXXX(NATIVE_TYPE_I2)
3830 XXXXX(NATIVE_TYPE_U2)
3831 XXXXX(NATIVE_TYPE_I4)
3832
3833 XXXXX(NATIVE_TYPE_U4)
3834 XXXXX(NATIVE_TYPE_I8)
3835 XXXXX(NATIVE_TYPE_U8)
3836 XXXXX(NATIVE_TYPE_R4)
3837
3838 XXXXX(NATIVE_TYPE_R8)
3839
3840 XXXXX(NATIVE_TYPE_LPSTR)
3841 XXXXX(NATIVE_TYPE_LPWSTR)
3842 XXXXX(NATIVE_TYPE_LPTSTR)
3843 XXXXX(NATIVE_TYPE_FIXEDSYSSTRING)
3844
3845 XXXXX(NATIVE_TYPE_STRUCT)
3846
3847 XXXXX(NATIVE_TYPE_INT)
3848 XXXXX(NATIVE_TYPE_FIXEDARRAY)
3849
3850 XXXXX(NATIVE_TYPE_UINT)
3851
3852 XXXXX(NATIVE_TYPE_FUNC)
3853
3854 XXXXX(NATIVE_TYPE_ASANY)
3855
3856 XXXXX(NATIVE_TYPE_ARRAY)
3857 XXXXX(NATIVE_TYPE_LPSTRUCT)
3858
3859 XXXXX(NATIVE_TYPE_IUNKNOWN)
3860
3861 XXXXX(NATIVE_TYPE_BSTR)
3862#ifdef FEATURE_COMINTEROP
3863 XXXXX(NATIVE_TYPE_TBSTR)
3864 XXXXX(NATIVE_TYPE_ANSIBSTR)
3865 XXXXX(NATIVE_TYPE_HSTRING)
3866 XXXXX(NATIVE_TYPE_BYVALSTR)
3867
3868 XXXXX(NATIVE_TYPE_VARIANTBOOL)
3869 XXXXX(NATIVE_TYPE_SAFEARRAY)
3870
3871 XXXXX(NATIVE_TYPE_IDISPATCH)
3872 XXXXX(NATIVE_TYPE_INTF)
3873#endif // FEATURE_COMINTEROP
3874
3875#undef XXXXX
3876
3877
3878 case NATIVE_TYPE_CUSTOMMARSHALER:
3879 {
3880 int strLen = 0;
3881 logbuf.AppendASCII("(NATIVE_TYPE_CUSTOMMARSHALER)");
3882
3883 // Skip the typelib guid.
3884 logbuf.AppendASCII(" ");
3885
3886 strLen = CPackedLen::GetLength(pvNativeType, (void const **)&pvNativeType);
3887 if (strLen)
3888 {
3889 BYTE* p = (BYTE*)logbuf.OpenANSIBuffer(strLen);
3890 memcpyNoGCRefs(p, pvNativeType, strLen);
3891 logbuf.CloseBuffer();
3892 logbuf.AppendASCII("\0");
3893
3894 pvNativeType += strLen;
3895 cbNativeType -= strLen + 1;
3896
3897 // Skip the name of the native type.
3898 logbuf.AppendASCII(" ");
3899 }
3900
3901
3902 strLen = CPackedLen::GetLength(pvNativeType, (void const **)&pvNativeType);
3903 if (strLen)
3904 {
3905 BYTE* p = (BYTE*)logbuf.OpenANSIBuffer(strLen);
3906 memcpyNoGCRefs(p, pvNativeType, strLen);
3907 logbuf.CloseBuffer();
3908 logbuf.AppendASCII("\0");
3909
3910 pvNativeType += strLen;
3911 cbNativeType -= strLen + 1;
3912
3913 // Extract the name of the custom marshaler.
3914 logbuf.AppendASCII(" ");
3915 }
3916
3917
3918 strLen = CPackedLen::GetLength(pvNativeType, (void const **)&pvNativeType);
3919 if (strLen)
3920 {
3921 BYTE* p = (BYTE*)logbuf.OpenANSIBuffer(strLen);
3922 memcpyNoGCRefs(p, pvNativeType, strLen);
3923 logbuf.CloseBuffer();
3924 logbuf.AppendASCII("\0");
3925
3926 pvNativeType += strLen;
3927 cbNativeType -= strLen + 1;
3928
3929 // Extract the cookie string.
3930 logbuf.AppendASCII(" ");
3931 }
3932
3933 strLen = CPackedLen::GetLength(pvNativeType, (void const **)&pvNativeType);
3934 if (strLen)
3935 {
3936 BYTE* p = (BYTE*)logbuf.OpenANSIBuffer(strLen);
3937 memcpyNoGCRefs(p, pvNativeType, strLen);
3938 logbuf.CloseBuffer();
3939 logbuf.AppendASCII("\0");
3940
3941 pvNativeType += strLen;
3942 cbNativeType -= strLen + 1;
3943 }
3944
3945 break;
3946 }
3947
3948 default:
3949 logbuf.AppendASCII("(?)");
3950 }
3951
3952 logbuf.AppendASCII(" ");
3953 }
3954 }
3955 logbuf.AppendASCII("\n");
3956 LOG((LF_MARSHALER, LL_INFO10, logbuf.GetANSI(scratch)));
3957 logbuf.Clear();
3958
3959 logbuf.AppendASCII("MarshalType : ");
3960 {
3961 char num[100];
3962 sprintf_s(num, COUNTOF(num), "0x%lx ", (ULONG)m_type);
3963 logbuf.AppendASCII(num);
3964 }
3965 switch (m_type)
3966 {
3967 #define DEFINE_MARSHALER_TYPE(mt, mc, fWinRTSupported) case mt: logbuf.AppendASCII( #mt " (IL" #mc ")"); break;
3968 #include "mtypes.h"
3969
3970 case MARSHAL_TYPE_UNKNOWN:
3971 logbuf.AppendASCII("MARSHAL_TYPE_UNKNOWN (illegal combination)");
3972 break;
3973
3974 default:
3975 logbuf.AppendASCII("MARSHAL_TYPE_???");
3976 break;
3977 }
3978
3979 logbuf.AppendASCII("\n");
3980
3981
3982 logbuf.AppendASCII("Metadata In/Out : ");
3983 if (TypeFromToken(token) != mdtParamDef || token == mdParamDefNil)
3984 logbuf.AppendASCII("<absent>");
3985
3986 else
3987 {
3988 DWORD dwAttr = 0;
3989 USHORT usSequence;
3990 LPCSTR szParamName_Ignore;
3991 if (FAILED(pInternalImport->GetParamDefProps(token, &usSequence, &dwAttr, &szParamName_Ignore)))
3992 {
3993 logbuf.AppendASCII("Invalid ParamDef record ");
3994 }
3995 else
3996 {
3997 if (IsPdIn(dwAttr))
3998 logbuf.AppendASCII("In ");
3999
4000 if (IsPdOut(dwAttr))
4001 logbuf.AppendASCII("Out ");
4002 }
4003 }
4004
4005 logbuf.AppendASCII("\n");
4006
4007 logbuf.AppendASCII("Effective In/Out : ");
4008 if (m_in)
4009 logbuf.AppendASCII("In ");
4010
4011 if (m_out)
4012 logbuf.AppendASCII("Out ");
4013
4014 logbuf.AppendASCII("\n");
4015
4016 LOG((LF_MARSHALER, LL_INFO10, logbuf.GetANSI(scratch)));
4017 logbuf.Clear();
4018 }
4019} // MarshalInfo::DumpMarshalInfo
4020#endif //_DEBUG
4021
4022#ifndef CROSSGEN_COMPILE
4023#ifdef FEATURE_COMINTEROP
4024DispParamMarshaler *MarshalInfo::GenerateDispParamMarshaler()
4025{
4026 CONTRACT (DispParamMarshaler*)
4027 {
4028 THROWS;
4029 GC_TRIGGERS;
4030 MODE_ANY;
4031 INJECT_FAULT(COMPlusThrowOM());
4032 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
4033 }
4034 CONTRACT_END;
4035
4036 NewHolder<DispParamMarshaler> pDispParamMarshaler = NULL;
4037
4038 switch (m_type)
4039 {
4040 case MARSHAL_TYPE_OLECOLOR:
4041 pDispParamMarshaler = new DispParamOleColorMarshaler();
4042 break;
4043
4044 case MARSHAL_TYPE_CURRENCY:
4045 pDispParamMarshaler = new DispParamCurrencyMarshaler();
4046 break;
4047
4048 case MARSHAL_TYPE_GENERIC_4:
4049 if (m_fErrorNativeType)
4050 pDispParamMarshaler = new DispParamErrorMarshaler();
4051 break;
4052
4053 case MARSHAL_TYPE_INTERFACE:
4054 {
4055 ItfMarshalInfo itfInfo;
4056 GetItfMarshalInfo(TypeHandle(m_pMT), TypeHandle(m_pDefaultItfMT), m_fDispItf, m_fInspItf, m_ms, &itfInfo);
4057 pDispParamMarshaler = new DispParamInterfaceMarshaler(
4058 itfInfo.dwFlags & ItfMarshalInfo::ITF_MARSHAL_DISP_ITF,
4059 itfInfo.thItf.GetMethodTable(),
4060 itfInfo.thClass.GetMethodTable(),
4061 itfInfo.dwFlags & ItfMarshalInfo::ITF_MARSHAL_CLASS_IS_HINT);
4062 break;
4063 }
4064
4065 case MARSHAL_TYPE_VALUECLASS:
4066 case MARSHAL_TYPE_BLITTABLEVALUECLASS:
4067 case MARSHAL_TYPE_BLITTABLEPTR:
4068 case MARSHAL_TYPE_LAYOUTCLASSPTR:
4069 pDispParamMarshaler = new DispParamRecordMarshaler(m_pMT);
4070 break;
4071
4072#ifdef FEATURE_CLASSIC_COMINTEROP
4073 case MARSHAL_TYPE_SAFEARRAY:
4074 pDispParamMarshaler = new DispParamArrayMarshaler(m_arrayElementType, m_hndArrayElemType.GetMethodTable());
4075 break;
4076#endif
4077
4078 case MARSHAL_TYPE_DELEGATE:
4079 pDispParamMarshaler = new DispParamDelegateMarshaler(m_pMT);
4080 break;
4081
4082 case MARSHAL_TYPE_REFERENCECUSTOMMARSHALER:
4083 pDispParamMarshaler = new DispParamCustomMarshaler(m_pCMHelper, m_CMVt);
4084 break;
4085 }
4086
4087 pDispParamMarshaler.SuppressRelease();
4088 RETURN pDispParamMarshaler;
4089}
4090
4091
4092DispatchWrapperType MarshalInfo::GetDispWrapperType()
4093{
4094 STANDARD_VM_CONTRACT;
4095
4096 DispatchWrapperType WrapperType = (DispatchWrapperType)0;
4097
4098 switch (m_type)
4099 {
4100 case MARSHAL_TYPE_CURRENCY:
4101 WrapperType = DispatchWrapperType_Currency;
4102 break;
4103
4104 case MARSHAL_TYPE_BSTR:
4105 WrapperType = DispatchWrapperType_BStr;
4106 break;
4107
4108 case MARSHAL_TYPE_GENERIC_4:
4109 if (m_fErrorNativeType)
4110 WrapperType = DispatchWrapperType_Error;
4111 break;
4112
4113 case MARSHAL_TYPE_INTERFACE:
4114 {
4115 ItfMarshalInfo itfInfo;
4116 GetItfMarshalInfo(TypeHandle(m_pMT), TypeHandle(m_pDefaultItfMT), m_fDispItf, m_fInspItf, m_ms, &itfInfo);
4117 WrapperType = !!(itfInfo.dwFlags & ItfMarshalInfo::ITF_MARSHAL_DISP_ITF) ? DispatchWrapperType_Dispatch : DispatchWrapperType_Unknown;
4118 break;
4119 }
4120
4121 case MARSHAL_TYPE_SAFEARRAY:
4122 switch (m_arrayElementType)
4123 {
4124 case VT_CY:
4125 WrapperType = (DispatchWrapperType)(DispatchWrapperType_SafeArray | DispatchWrapperType_Currency);
4126 break;
4127 case VT_UNKNOWN:
4128 WrapperType = (DispatchWrapperType)(DispatchWrapperType_SafeArray | DispatchWrapperType_Unknown);
4129 break;
4130 case VT_DISPATCH:
4131 WrapperType = (DispatchWrapperType)(DispatchWrapperType_SafeArray | DispatchWrapperType_Dispatch);
4132 break;
4133 case VT_ERROR:
4134 WrapperType = (DispatchWrapperType)(DispatchWrapperType_SafeArray | DispatchWrapperType_Error);
4135 break;
4136 case VT_BSTR:
4137 WrapperType = (DispatchWrapperType)(DispatchWrapperType_SafeArray | DispatchWrapperType_BStr);
4138 break;
4139 }
4140 break;
4141 }
4142
4143 return WrapperType;
4144}
4145
4146#endif // FEATURE_COMINTEROP
4147
4148
4149VOID MarshalInfo::MarshalTypeToString(SString& strMarshalType, BOOL fSizeIsSpecified)
4150{
4151 CONTRACTL
4152 {
4153 THROWS;
4154 GC_TRIGGERS;
4155 MODE_ANY;
4156 }
4157 CONTRACTL_END;
4158
4159 LPCWSTR strRetVal;
4160
4161 if (m_type == MARSHAL_TYPE_NATIVEARRAY)
4162 {
4163 SString strVarType;
4164 VarTypeToString(m_arrayElementType, strVarType);
4165
4166 if (!fSizeIsSpecified)
4167 {
4168 strMarshalType.Printf(W("native array of %s (size not specified by a parameter)"),
4169 strVarType.GetUnicode());
4170 }
4171 else
4172 {
4173 strMarshalType.Printf(W("native array of %s (size specified by parameter %i)"),
4174 strVarType.GetUnicode(), m_countParamIdx);
4175 }
4176
4177 return;
4178 }
4179#ifdef FEATURE_COMINTEROP
4180 // Some MarshalTypes have extra information and require special handling
4181 else if (m_type == MARSHAL_TYPE_INTERFACE)
4182 {
4183 ItfMarshalInfo itfInfo;
4184 GetItfMarshalInfo(TypeHandle(m_pMT), TypeHandle(m_pDefaultItfMT), m_fDispItf, m_fInspItf, m_ms, &itfInfo);
4185
4186 if (!itfInfo.thItf.IsNull())
4187 {
4188 StackSString ssClassName;
4189 itfInfo.thItf.GetMethodTable()->_GetFullyQualifiedNameForClass(ssClassName);
4190
4191 if (!!(itfInfo.dwFlags & ItfMarshalInfo::ITF_MARSHAL_DISP_ITF))
4192 {
4193 strMarshalType.SetLiteral(W("IDispatch "));
4194 }
4195 else if (!!(itfInfo.dwFlags & ItfMarshalInfo::ITF_MARSHAL_INSP_ITF))
4196 {
4197 strMarshalType.SetLiteral(W("IInspectable"));
4198 }
4199 else
4200 {
4201 strMarshalType.SetLiteral(W("IUnknown "));
4202 }
4203
4204 if (itfInfo.dwFlags & ItfMarshalInfo::ITF_MARSHAL_USE_BASIC_ITF)
4205 {
4206 strMarshalType.Append(W("(basic) "));
4207 }
4208
4209 strMarshalType.Append(ssClassName);
4210 return;
4211 }
4212 else
4213 {
4214 if (!!(itfInfo.dwFlags & ItfMarshalInfo::ITF_MARSHAL_DISP_ITF))
4215 strRetVal = W("IDispatch");
4216 else if (!!(itfInfo.dwFlags & ItfMarshalInfo::ITF_MARSHAL_INSP_ITF))
4217 strRetVal = W("IInspectable");
4218 else
4219 strRetVal = W("IUnknown");
4220 }
4221 }
4222 else if (m_type == MARSHAL_TYPE_SAFEARRAY)
4223 {
4224 StackSString strVarType;
4225 VarTypeToString(m_arrayElementType, strVarType);
4226
4227 strMarshalType = SL(W("SafeArray of "));
4228 strMarshalType.Append(strVarType);
4229
4230 return;
4231 }
4232#endif // FEATURE_COMINTEROP
4233 else if (m_type == MARSHAL_TYPE_REFERENCECUSTOMMARSHALER)
4234 {
4235 GCX_COOP();
4236
4237 OBJECTHANDLE objHandle = m_pCMHelper->GetCustomMarshalerInfo()->GetCustomMarshaler();
4238 {
4239 OBJECTREF pObjRef = ObjectFromHandle(objHandle);
4240 DefineFullyQualifiedNameForClassW();
4241
4242 strMarshalType.Printf(W("custom marshaler (%s)"),
4243 GetFullyQualifiedNameForClassW(pObjRef->GetMethodTable()));
4244 }
4245
4246 return;
4247 }
4248 else
4249 {
4250 // All other MarshalTypes with no special handling
4251 switch (m_type)
4252 {
4253 case MARSHAL_TYPE_GENERIC_1:
4254 strRetVal = W("BYTE");
4255 break;
4256 case MARSHAL_TYPE_GENERIC_U1:
4257 strRetVal = W("unsigned BYTE");
4258 break;
4259 case MARSHAL_TYPE_GENERIC_2:
4260 strRetVal = W("WORD");
4261 break;
4262 case MARSHAL_TYPE_GENERIC_U2:
4263 strRetVal = W("unsigned WORD");
4264 break;
4265 case MARSHAL_TYPE_GENERIC_4:
4266 strRetVal = W("DWORD");
4267 break;
4268 case MARSHAL_TYPE_GENERIC_8:
4269 strRetVal = W("QUADWORD");
4270 break;
4271 case MARSHAL_TYPE_WINBOOL:
4272 strRetVal = W("Windows Bool");
4273 break;
4274#ifdef FEATURE_COMINTEROP
4275 case MARSHAL_TYPE_VTBOOL:
4276 strRetVal = W("VARIANT Bool");
4277 break;
4278#endif // FEATURE_COMINTEROP
4279 case MARSHAL_TYPE_ANSICHAR:
4280 strRetVal = W("Ansi character");
4281 break;
4282 case MARSHAL_TYPE_CBOOL:
4283 strRetVal = W("CBool");
4284 break;
4285 case MARSHAL_TYPE_FLOAT:
4286 strRetVal = W("float");
4287 break;
4288 case MARSHAL_TYPE_DOUBLE:
4289 strRetVal = W("double");
4290 break;
4291 case MARSHAL_TYPE_CURRENCY:
4292 strRetVal = W("CURRENCY");
4293 break;
4294 case MARSHAL_TYPE_DECIMAL:
4295 strRetVal = W("DECIMAL");
4296 break;
4297 case MARSHAL_TYPE_DECIMAL_PTR:
4298 strRetVal = W("DECIMAL pointer");
4299 break;
4300 case MARSHAL_TYPE_GUID:
4301 strRetVal = W("GUID");
4302 break;
4303 case MARSHAL_TYPE_GUID_PTR:
4304 strRetVal = W("GUID pointer");
4305 break;
4306 case MARSHAL_TYPE_DATE:
4307 strRetVal = W("DATE");
4308 break;
4309 case MARSHAL_TYPE_BSTR:
4310 strRetVal = W("BSTR");
4311 break;
4312 case MARSHAL_TYPE_LPWSTR:
4313 strRetVal = W("LPWSTR");
4314 break;
4315 case MARSHAL_TYPE_LPSTR:
4316 strRetVal = W("LPSTR");
4317 break;
4318 case MARSHAL_TYPE_LPUTF8STR:
4319 strRetVal = W("LPUTF8STR");
4320 break;
4321#ifdef FEATURE_COMINTEROP
4322 case MARSHAL_TYPE_ANSIBSTR:
4323 strRetVal = W("AnsiBStr");
4324 break;
4325#endif // FEATURE_COMINTEROP
4326 case MARSHAL_TYPE_LPWSTR_BUFFER:
4327 strRetVal = W("LPWSTR buffer");
4328 break;
4329 case MARSHAL_TYPE_LPSTR_BUFFER:
4330 strRetVal = W("LPSTR buffer");
4331 break;
4332 case MARSHAL_TYPE_UTF8_BUFFER:
4333 strRetVal = W("UTF8 buffer");
4334 break;
4335 case MARSHAL_TYPE_ASANYA:
4336 strRetVal = W("AsAnyA");
4337 break;
4338 case MARSHAL_TYPE_ASANYW:
4339 strRetVal = W("AsAnyW");
4340 break;
4341 case MARSHAL_TYPE_DELEGATE:
4342 strRetVal = W("Delegate");
4343 break;
4344 case MARSHAL_TYPE_BLITTABLEPTR:
4345 strRetVal = W("blittable pointer");
4346 break;
4347#ifdef FEATURE_COMINTEROP
4348 case MARSHAL_TYPE_VBBYVALSTR:
4349 strRetVal = W("VBByValStr");
4350 break;
4351 case MARSHAL_TYPE_VBBYVALSTRW:
4352 strRetVal = W("VBByRefStr");
4353 break;
4354#endif // FEATURE_COMINTEROP
4355 case MARSHAL_TYPE_LAYOUTCLASSPTR:
4356 strRetVal = W("Layout class pointer");
4357 break;
4358 case MARSHAL_TYPE_ARRAYWITHOFFSET:
4359 strRetVal = W("ArrayWithOffset");
4360 break;
4361 case MARSHAL_TYPE_BLITTABLEVALUECLASS:
4362 strRetVal = W("blittable value class");
4363 break;
4364 case MARSHAL_TYPE_VALUECLASS:
4365 strRetVal = W("value class");
4366 break;
4367 case MARSHAL_TYPE_ARGITERATOR:
4368 strRetVal = W("ArgIterator");
4369 break;
4370#ifdef FEATURE_COMINTEROP
4371 case MARSHAL_TYPE_OBJECT:
4372 strRetVal = W("VARIANT");
4373 break;
4374#endif // FEATURE_COMINTEROP
4375 case MARSHAL_TYPE_HANDLEREF:
4376 strRetVal = W("HandleRef");
4377 break;
4378#ifdef FEATURE_COMINTEROP
4379 case MARSHAL_TYPE_OLECOLOR:
4380 strRetVal = W("OLE_COLOR");
4381 break;
4382#endif // FEATURE_COMINTEROP
4383 case MARSHAL_TYPE_RUNTIMETYPEHANDLE:
4384 strRetVal = W("RuntimeTypeHandle");
4385 break;
4386 case MARSHAL_TYPE_RUNTIMEFIELDHANDLE:
4387 strRetVal = W("RuntimeFieldHandle");
4388 break;
4389 case MARSHAL_TYPE_RUNTIMEMETHODHANDLE:
4390 strRetVal = W("RuntimeMethodHandle");
4391 break;
4392 case MARSHAL_TYPE_RUNTIMEMETHODINFO:
4393 strRetVal = W("RuntimeMethodInfo");
4394 break;
4395 case MARSHAL_TYPE_RUNTIMEMODULE:
4396 strRetVal = W("RuntimeModule");
4397 break;
4398 case MARSHAL_TYPE_RUNTIMEASSEMBLY:
4399 strRetVal = W("RuntimeAssembly");
4400 break;
4401 default:
4402 strRetVal = W("<UNKNOWN>");
4403 break;
4404 }
4405 }
4406
4407 strMarshalType.Set(strRetVal);
4408 return;
4409}
4410
4411VOID MarshalInfo::VarTypeToString(VARTYPE vt, SString& strVarType)
4412{
4413 CONTRACTL
4414 {
4415 THROWS;
4416 GC_NOTRIGGER;
4417 MODE_ANY;
4418 }
4419 CONTRACTL_END;
4420
4421
4422 LPCWSTR strRetVal;
4423
4424 switch(vt)
4425 {
4426 case VT_I2:
4427 strRetVal = W("2-byte signed int");
4428 break;
4429 case VT_I4:
4430 strRetVal = W("4-byte signed int");
4431 break;
4432 case VT_R4:
4433 strRetVal = W("4-byte real");
4434 break;
4435 case VT_R8:
4436 strRetVal = W("8-byte real");
4437 break;
4438 case VT_CY:
4439 strRetVal = W("currency");
4440 break;
4441 case VT_DATE:
4442 strRetVal = W("date");
4443 break;
4444 case VT_BSTR:
4445 strRetVal = W("binary string");
4446 break;
4447 case VT_DISPATCH:
4448 strRetVal = W("IDispatch *");
4449 break;
4450 case VT_ERROR:
4451 strRetVal = W("Scode");
4452 break;
4453 case VT_BOOL:
4454 strRetVal = W("boolean");
4455 break;
4456 case VT_VARIANT:
4457 strRetVal = W("VARIANT *");
4458 break;
4459 case VT_UNKNOWN:
4460 strRetVal = W("IUnknown *");
4461 break;
4462 case VT_DECIMAL:
4463 strRetVal = W("16-byte fixed point");
4464 break;
4465 case VT_RECORD:
4466 strRetVal = W("user defined structure");
4467 break;
4468 case VT_I1:
4469 strRetVal = W("signed char");
4470 break;
4471 case VT_UI1:
4472 strRetVal = W("unsigned char");
4473 break;
4474 case VT_UI2:
4475 strRetVal = W("unsigned short");
4476 break;
4477 case VT_UI4:
4478 strRetVal = W("unsigned short");
4479 break;
4480 case VT_INT:
4481 strRetVal = W("signed int");
4482 break;
4483 case VT_UINT:
4484 strRetVal = W("unsigned int");
4485 break;
4486 case VT_LPSTR:
4487 strRetVal = W("LPSTR");
4488 break;
4489 case VT_LPWSTR:
4490 strRetVal = W("LPWSTR");
4491 break;
4492 case VT_HRESULT:
4493 strRetVal = W("HResult");
4494 break;
4495 case VT_I8:
4496 strRetVal = W("8-byte signed int");
4497 break;
4498 case VT_NULL:
4499 strRetVal = W("null");
4500 break;
4501 case VT_UI8:
4502 strRetVal = W("8-byte unsigned int");
4503 break;
4504 case VT_VOID:
4505 strRetVal = W("void");
4506 break;
4507 case VTHACK_WINBOOL:
4508 strRetVal = W("boolean");
4509 break;
4510 case VTHACK_ANSICHAR:
4511 strRetVal = W("char");
4512 break;
4513 case VTHACK_CBOOL:
4514 strRetVal = W("1-byte C bool");
4515 break;
4516 default:
4517 strRetVal = W("unknown");
4518 break;
4519 }
4520
4521 strVarType.Set(strRetVal);
4522 return;
4523}
4524
4525#endif // CROSSGEN_COMPILE
4526
4527// Returns true if the marshaler represented by this instance requires COM to have been started.
4528bool MarshalInfo::MarshalerRequiresCOM()
4529{
4530 LIMITED_METHOD_CONTRACT;
4531
4532#ifdef FEATURE_COMINTEROP
4533 switch (m_type)
4534 {
4535 case MARSHAL_TYPE_REFERENCECUSTOMMARSHALER:
4536
4537 case MARSHAL_TYPE_BSTR:
4538 case MARSHAL_TYPE_ANSIBSTR:
4539 case MARSHAL_TYPE_OBJECT:
4540 case MARSHAL_TYPE_OLECOLOR:
4541 case MARSHAL_TYPE_SAFEARRAY:
4542 case MARSHAL_TYPE_INTERFACE:
4543
4544 case MARSHAL_TYPE_URI:
4545 case MARSHAL_TYPE_KEYVALUEPAIR:
4546 case MARSHAL_TYPE_NULLABLE:
4547 case MARSHAL_TYPE_SYSTEMTYPE:
4548 case MARSHAL_TYPE_EXCEPTION:
4549 case MARSHAL_TYPE_HIDDENLENGTHARRAY:
4550 case MARSHAL_TYPE_HSTRING:
4551 case MARSHAL_TYPE_NCCEVENTARGS:
4552 case MARSHAL_TYPE_PCEVENTARGS:
4553 {
4554 // some of these types do not strictly require COM for the actual marshaling
4555 // but they tend to be used in COM context so we keep the logic we had in
4556 // previous versions and return true here
4557 return true;
4558 }
4559
4560 case MARSHAL_TYPE_LAYOUTCLASSPTR:
4561 case MARSHAL_TYPE_VALUECLASS:
4562 {
4563 // pessimistic guess, but in line with previous versions
4564 return true;
4565 }
4566
4567 case MARSHAL_TYPE_NATIVEARRAY:
4568 {
4569 return (m_arrayElementType == VT_UNKNOWN ||
4570 m_arrayElementType == VT_DISPATCH ||
4571 m_arrayElementType == VT_VARIANT);
4572 }
4573 }
4574#endif // FEATURE_COMINTEROP
4575
4576 return false;
4577}
4578
4579#ifdef FEATURE_COMINTEROP
4580MarshalInfo::MarshalType MarshalInfo::GetHiddenLengthParamMarshalType()
4581{
4582 LIMITED_METHOD_CONTRACT;
4583 return MARSHAL_TYPE_GENERIC_U4;
4584}
4585
4586CorElementType MarshalInfo::GetHiddenLengthParamElementType()
4587{
4588 LIMITED_METHOD_CONTRACT;
4589 return ELEMENT_TYPE_U4;
4590}
4591
4592UINT16 MarshalInfo::GetHiddenLengthParamStackSize()
4593{
4594 LIMITED_METHOD_CONTRACT;
4595 return StackElemSize(GetNativeSize(GetHiddenLengthParamMarshalType(), m_ms));
4596}
4597
4598void MarshalInfo::MarshalHiddenLengthArgument(NDirectStubLinker *psl, BOOL managedToNative, BOOL isForReturnArray)
4599{
4600 CONTRACTL
4601 {
4602 STANDARD_VM_CHECK;
4603 PRECONDITION(CheckPointer(psl));
4604 PRECONDITION(m_type == MARSHAL_TYPE_HIDDENLENGTHARRAY);
4605 PRECONDITION(m_dwHiddenLengthManagedHomeLocal == 0xFFFFFFFF);
4606 PRECONDITION(m_dwHiddenLengthNativeHomeLocal == 0xFFFFFFFF);
4607 }
4608 CONTRACTL_END;
4609
4610 NewHolder<ILMarshaler> pHiddenLengthMarshaler = CreateILMarshaler(GetHiddenLengthParamMarshalType(), psl);
4611
4612
4613 ILCodeStream *pcsMarshal = psl->GetMarshalCodeStream();
4614 ILCodeStream *pcsUnmarshal = psl->GetUnmarshalCodeStream();
4615
4616 pcsMarshal->EmitNOP("// hidden length argument { ");
4617 pcsUnmarshal->EmitNOP("// hidden length argument { ");
4618
4619 DWORD dwMarshalFlags = MARSHAL_FLAG_HIDDENLENPARAM;
4620 if (isForReturnArray)
4621 {
4622 // This is a hidden length argument for an [out, retval] argument, so setup flags to match that
4623 dwMarshalFlags |= CalculateArgumentMarshalFlags(TRUE, FALSE, TRUE, managedToNative);
4624 }
4625 else
4626 {
4627 // The length parameter needs to be an [in] parameter if the array itself is an [in] parameter.
4628 // Additionally, in order to support the FillArray pattern:
4629 // FillArray([in] UInt32 length, [out, size_is(length)] ElementType* value)
4630 //
4631 // We need to make sure that the length parameter is [in] if the array pointer is not byref, since
4632 // this means that the caller is allocating the array. This includes array buffers which are [out]
4633 // but not byref, since the [out] marshaling applies to the array contents but not the array pointer
4634 // value itself.
4635 BOOL marshalHiddenLengthIn = m_in || !m_byref;
4636 dwMarshalFlags |= CalculateArgumentMarshalFlags(m_byref, marshalHiddenLengthIn, m_out, managedToNative);
4637 }
4638 pHiddenLengthMarshaler->EmitMarshalHiddenLengthArgument(pcsMarshal,
4639 pcsUnmarshal,
4640 this,
4641 m_paramidx,
4642 dwMarshalFlags,
4643 HiddenLengthParamIndex(),
4644 &m_args,
4645 &m_dwHiddenLengthManagedHomeLocal,
4646 &m_dwHiddenLengthNativeHomeLocal);
4647
4648 pcsMarshal->EmitNOP("// } hidden length argument");
4649 pcsUnmarshal->EmitNOP("// } hidden length argument");
4650
4651 // Only emit into the dispatch stream for CLR -> Native cases - in the reverse, there is no argument
4652 // to pass to the managed method. Instead, the length is encoded in the marshaled array.
4653 if (managedToNative)
4654 {
4655 ILCodeStream* pcsDispatch = psl->GetDispatchCodeStream();
4656 pHiddenLengthMarshaler->EmitSetupArgument(pcsDispatch);
4657 }
4658}
4659
4660#endif // FEATURE_COMINTEROP
4661
4662#define ReportInvalidArrayMarshalInfo(resId) \
4663 do \
4664 { \
4665 m_vtElement = VT_EMPTY; \
4666 m_errorResourceId = resId; \
4667 m_thElement = TypeHandle(); \
4668 goto LExit; \
4669 } \
4670 while (0)
4671
4672void ArrayMarshalInfo::InitForNativeArray(MarshalInfo::MarshalScenario ms, TypeHandle thElement, CorNativeType ntElement, BOOL isAnsi)
4673{
4674 WRAPPER_NO_CONTRACT;
4675 InitElementInfo(NATIVE_TYPE_ARRAY, ms, thElement, ntElement, isAnsi);
4676}
4677
4678void ArrayMarshalInfo::InitForFixedArray(TypeHandle thElement, CorNativeType ntElement, BOOL isAnsi)
4679{
4680 WRAPPER_NO_CONTRACT;
4681 InitElementInfo(NATIVE_TYPE_FIXEDARRAY, MarshalInfo::MARSHAL_SCENARIO_FIELD, thElement, ntElement, isAnsi);
4682}
4683
4684#ifdef FEATURE_COMINTEROP
4685void ArrayMarshalInfo::InitForSafeArray(MarshalInfo::MarshalScenario ms, TypeHandle thElement, VARTYPE vtElement, BOOL isAnsi)
4686{
4687 STANDARD_VM_CONTRACT;
4688
4689 InitElementInfo(NATIVE_TYPE_SAFEARRAY, ms, thElement, NATIVE_TYPE_DEFAULT, isAnsi);
4690
4691 if (IsValid() && vtElement != VT_EMPTY)
4692 {
4693 if (vtElement == VT_USERDEFINED)
4694 {
4695 // If the user explicitly sets the VARTYPE to VT_USERDEFINED, we simply ignore it
4696 // since the exporter will take care of transforming the vt to VT_USERDEFINED and the
4697 // marshallers needs the actual type.
4698 }
4699 else
4700 {
4701 m_flags = (ArrayMarshalInfoFlags)(m_flags | amiSafeArraySubTypeExplicitlySpecified);
4702 m_vtElement = vtElement;
4703 }
4704 }
4705}
4706
4707void ArrayMarshalInfo::InitForHiddenLengthArray(TypeHandle thElement)
4708{
4709 STANDARD_VM_CONTRACT;
4710
4711 MethodTable *pMT = NULL;
4712
4713 // WinRT supports arrays of any WinRT-legal types
4714 if (thElement.IsArray())
4715 {
4716 ReportInvalidArrayMarshalInfo(IDS_EE_BADMARSHAL_NESTEDARRAY);
4717 }
4718 else if (thElement.IsTypeDesc() || !thElement.GetMethodTable()->IsLegalNonArrayWinRTType())
4719 {
4720 ReportInvalidArrayMarshalInfo(IDS_EE_BADMARSHAL_WINRT_ILLEGAL_TYPE);
4721 }
4722
4723 m_thElement = thElement;
4724
4725 pMT = thElement.GetMethodTable();
4726 if (pMT->IsString())
4727 {
4728 m_vtElement = VTHACK_HSTRING;
4729 m_cbElementSize = sizeof(HSTRING);
4730 }
4731 else if (WinRTTypeNameConverter::ResolveRedirectedType(pMT, &m_redirectedTypeIndex))
4732 {
4733 m_vtElement = VTHACK_REDIRECTEDTYPE;
4734
4735 switch (m_redirectedTypeIndex)
4736 {
4737 case WinMDAdapter::RedirectedTypeIndex_System_DateTimeOffset:
4738 m_cbElementSize = ILDateTimeMarshaler::c_nativeSize;
4739 break;
4740
4741 case WinMDAdapter::RedirectedTypeIndex_System_Type:
4742 m_cbElementSize = ILSystemTypeMarshaler::c_nativeSize;
4743 break;
4744
4745 case WinMDAdapter::RedirectedTypeIndex_System_Exception:
4746 m_cbElementSize = ILHResultExceptionMarshaler::c_nativeSize;
4747 break;
4748
4749 // WinRT delegates are IUnknown pointers
4750 case WinMDAdapter::RedirectedTypeIndex_System_EventHandlerGeneric:
4751 m_vtElement = VTHACK_INSPECTABLE;
4752 m_cbElementSize = sizeof(IUnknown*);
4753 break;
4754
4755 case WinMDAdapter::RedirectedTypeIndex_System_Collections_Generic_KeyValuePair:
4756 case WinMDAdapter::RedirectedTypeIndex_System_Nullable:
4757 case WinMDAdapter::RedirectedTypeIndex_System_Uri:
4758 case WinMDAdapter::RedirectedTypeIndex_System_Collections_Specialized_NotifyCollectionChangedEventArgs:
4759 case WinMDAdapter::RedirectedTypeIndex_System_ComponentModel_PropertyChangedEventArgs:
4760 {
4761 m_cbElementSize = sizeof(IInspectable *);
4762 break;
4763 }
4764
4765 default:
4766 {
4767 if (pMT->IsValueType())
4768 {
4769 // other redirected structs are blittable and don't need special marshaling
4770 m_vtElement = VTHACK_BLITTABLERECORD;
4771 m_cbElementSize = pMT->GetNativeSize();
4772 }
4773 else
4774 {
4775 // redirected interfaces should be treated as interface pointers
4776 _ASSERTE(pMT->IsInterface());
4777 m_vtElement = VTHACK_INSPECTABLE;
4778 m_cbElementSize = sizeof(IInspectable *);
4779 }
4780 break;
4781 }
4782 }
4783 }
4784 else if (pMT->IsBlittable() || pMT->IsTruePrimitive() || pMT->IsEnum())
4785 {
4786 m_vtElement = VTHACK_BLITTABLERECORD;
4787
4788 CorElementType elemType = pMT->GetInternalCorElementType();
4789 if (CorTypeInfo::IsPrimitiveType(elemType))
4790 {
4791 // .NET and WinRT primitives have the same size
4792 m_cbElementSize = CorTypeInfo::Size(elemType);
4793 }
4794 else
4795 {
4796 m_cbElementSize = pMT->GetNativeSize();
4797 }
4798 }
4799 else if (pMT->IsValueType())
4800 {
4801 m_vtElement = VTHACK_NONBLITTABLERECORD;
4802 m_cbElementSize = pMT->GetNativeSize();
4803 }
4804 else
4805 {
4806 m_vtElement = VTHACK_INSPECTABLE;
4807 m_cbElementSize = sizeof(IInspectable *);
4808 }
4809
4810LExit:;
4811}
4812#endif // FEATURE_COMINTEROP
4813
4814void ArrayMarshalInfo::InitElementInfo(CorNativeType arrayNativeType, MarshalInfo::MarshalScenario ms, TypeHandle thElement, CorNativeType ntElement, BOOL isAnsi)
4815{
4816 CONTRACT_VOID
4817 {
4818 STANDARD_VM_CHECK;
4819 PRECONDITION(!thElement.IsNull());
4820 POSTCONDITION(!IsValid() || !m_thElement.IsNull());
4821 }
4822 CONTRACT_END;
4823
4824 CorElementType etElement = ELEMENT_TYPE_END;
4825
4826 //
4827 // IMPORTANT: The error resource IDs used in this function must not contain any placeholders!
4828 //
4829 // Also please maintain the standard of using IDS_EE_BADMARSHAL_XXX when defining new error
4830 // message resource IDs.
4831 //
4832
4833 if (thElement.IsArray())
4834 ReportInvalidArrayMarshalInfo(IDS_EE_BADMARSHAL_NESTEDARRAY);
4835
4836 m_thElement = thElement;
4837
4838 if (m_thElement.IsPointer())
4839 {
4840 m_flags = (ArrayMarshalInfoFlags)(m_flags | amiIsPtr);
4841 m_thElement = ((ParamTypeDesc*)m_thElement.AsTypeDesc())->GetModifiedType();
4842 }
4843
4844 etElement = m_thElement.GetSignatureCorElementType();
4845
4846 if (IsAMIPtr(m_flags) && (etElement > ELEMENT_TYPE_R8))
4847 {
4848 ReportInvalidArrayMarshalInfo(IDS_EE_BADMARSHAL_UNSUPPORTED_SIG);
4849 }
4850
4851 if (etElement == ELEMENT_TYPE_CHAR)
4852 {
4853 switch (ntElement)
4854 {
4855 case NATIVE_TYPE_I1: //fallthru
4856 case NATIVE_TYPE_U1:
4857 m_vtElement = VTHACK_ANSICHAR;
4858 break;
4859
4860 case NATIVE_TYPE_I2: //fallthru
4861 case NATIVE_TYPE_U2:
4862 m_vtElement = VT_UI2;
4863 break;
4864
4865 // Compat: If the native type doesn't make sense, we need to ignore it and not report an error.
4866 case NATIVE_TYPE_DEFAULT: //fallthru
4867 default:
4868#ifdef FEATURE_COMINTEROP
4869 if (ms == MarshalInfo::MARSHAL_SCENARIO_COMINTEROP)
4870 m_vtElement = VT_UI2;
4871 else
4872#endif // FEATURE_COMINTEROP
4873 m_vtElement = isAnsi ? VTHACK_ANSICHAR : VT_UI2;
4874 }
4875 }
4876 else if (etElement == ELEMENT_TYPE_BOOLEAN)
4877 {
4878 switch (ntElement)
4879 {
4880 case NATIVE_TYPE_BOOLEAN:
4881 m_vtElement = VTHACK_WINBOOL;
4882 break;
4883
4884#ifdef FEATURE_COMINTEROP
4885 case NATIVE_TYPE_VARIANTBOOL:
4886 m_vtElement = VT_BOOL;
4887 break;
4888#endif // FEATURE_COMINTEROP
4889
4890 case NATIVE_TYPE_I1 :
4891 case NATIVE_TYPE_U1 :
4892 m_vtElement = VTHACK_CBOOL;
4893 break;
4894
4895 // Compat: if the native type doesn't make sense, we need to ignore it and not report an error.
4896 case NATIVE_TYPE_DEFAULT: //fallthru
4897 default:
4898#ifdef FEATURE_COMINTEROP
4899 if (ms == MarshalInfo::MARSHAL_SCENARIO_COMINTEROP ||
4900 arrayNativeType == NATIVE_TYPE_SAFEARRAY)
4901 {
4902 m_vtElement = VT_BOOL;
4903 }
4904 else
4905#endif // FEATURE_COMINTEROP
4906 {
4907 m_vtElement = VTHACK_WINBOOL;
4908 }
4909 break;
4910 }
4911 }
4912 else if (etElement == ELEMENT_TYPE_I)
4913 {
4914 m_vtElement = static_cast<VARTYPE>((GetPointerSize() == 4) ? VT_I4 : VT_I8);
4915 }
4916 else if (etElement == ELEMENT_TYPE_U)
4917 {
4918 m_vtElement = static_cast<VARTYPE>((GetPointerSize() == 4) ? VT_UI4 : VT_UI8);
4919 }
4920 else if (etElement <= ELEMENT_TYPE_R8)
4921 {
4922 static const BYTE map [] =
4923 {
4924 VT_NULL, // ELEMENT_TYPE_END
4925 VT_VOID, // ELEMENT_TYPE_VOID
4926 VT_NULL, // ELEMENT_TYPE_BOOLEAN
4927 VT_NULL, // ELEMENT_TYPE_CHAR
4928 VT_I1, // ELEMENT_TYPE_I1
4929 VT_UI1, // ELEMENT_TYPE_U1
4930 VT_I2, // ELEMENT_TYPE_I2
4931 VT_UI2, // ELEMENT_TYPE_U2
4932 VT_I4, // ELEMENT_TYPE_I4
4933 VT_UI4, // ELEMENT_TYPE_U4
4934 VT_I8, // ELEMENT_TYPE_I8
4935 VT_UI8, // ELEMENT_TYPE_U8
4936 VT_R4, // ELEMENT_TYPE_R4
4937 VT_R8 // ELEMENT_TYPE_R8
4938
4939 };
4940
4941 _ASSERTE(map[etElement] != VT_NULL);
4942 m_vtElement = map[etElement];
4943 }
4944 else
4945 {
4946 if (m_thElement == TypeHandle(g_pStringClass))
4947 {
4948 switch (ntElement)
4949 {
4950 case NATIVE_TYPE_DEFAULT:
4951#ifdef FEATURE_COMINTEROP
4952 if (arrayNativeType == NATIVE_TYPE_SAFEARRAY || ms == MarshalInfo::MARSHAL_SCENARIO_COMINTEROP)
4953 {
4954 m_vtElement = VT_BSTR;
4955 }
4956 else
4957#endif // FEATURE_COMINTEROP
4958 {
4959 m_vtElement = static_cast<VARTYPE>(isAnsi ? VT_LPSTR : VT_LPWSTR);
4960 }
4961 break;
4962 case NATIVE_TYPE_BSTR:
4963 m_vtElement = VT_BSTR;
4964 break;
4965 case NATIVE_TYPE_LPSTR:
4966 m_vtElement = VT_LPSTR;
4967 break;
4968 case NATIVE_TYPE_LPWSTR:
4969 m_vtElement = VT_LPWSTR;
4970 break;
4971 case NATIVE_TYPE_LPTSTR:
4972 {
4973#ifdef FEATURE_COMINTEROP
4974 if (ms == MarshalInfo::MARSHAL_SCENARIO_COMINTEROP || IsAMIExport(m_flags))
4975 {
4976 // We disallow NATIVE_TYPE_LPTSTR for COM or if we are exporting.
4977 ReportInvalidArrayMarshalInfo(IDS_EE_BADMARSHALPARAM_NO_LPTSTR);
4978 }
4979 else
4980#endif // FEATURE_COMINTEROP
4981 {
4982 // We no longer support Win9x so LPTSTR always maps to a Unicode string.
4983 m_vtElement = VT_LPWSTR;
4984 }
4985 break;
4986 }
4987
4988 default:
4989 ReportInvalidArrayMarshalInfo(IDS_EE_BADMARSHAL_STRINGARRAY);
4990 }
4991 }
4992 else if (m_thElement == TypeHandle(g_pObjectClass))
4993 {
4994#ifdef FEATURE_COMINTEROP
4995 switch(ntElement)
4996 {
4997 case NATIVE_TYPE_DEFAULT:
4998 if (ms == MarshalInfo::MARSHAL_SCENARIO_FIELD)
4999 m_vtElement = VT_UNKNOWN;
5000 else
5001 m_vtElement = VT_VARIANT;
5002 break;
5003
5004 case NATIVE_TYPE_STRUCT:
5005 m_vtElement = VT_VARIANT;
5006 break;
5007
5008 case NATIVE_TYPE_INTF:
5009 case NATIVE_TYPE_IUNKNOWN:
5010 m_vtElement = VT_UNKNOWN;
5011 break;
5012
5013 case NATIVE_TYPE_IDISPATCH:
5014 m_vtElement = VT_DISPATCH;
5015 break;
5016
5017 default:
5018 ReportInvalidArrayMarshalInfo(IDS_EE_BADMARSHAL_OBJECTARRAY);
5019 }
5020
5021#else // FEATURE_COMINTEROP
5022 switch (ntElement)
5023 {
5024 case NATIVE_TYPE_IUNKNOWN:
5025 m_vtElement = VT_UNKNOWN;
5026 break;
5027
5028 default:
5029 ReportInvalidArrayMarshalInfo(IDS_EE_BADMARSHAL_UNSUPPORTED_SIG);
5030 }
5031#endif // FEATURE_COMINTEROP
5032 }
5033 else if (m_thElement.CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__SAFE_HANDLE))))
5034 {
5035 // Array's of SAFEHANDLEs are not supported.
5036 ReportInvalidArrayMarshalInfo(IDS_EE_BADMARSHAL_SAFEHANDLEARRAY);
5037 }
5038 else if (m_thElement.CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__CRITICAL_HANDLE))))
5039 {
5040 // Array's of CRITICALHANDLEs are not supported.
5041 ReportInvalidArrayMarshalInfo(IDS_EE_BADMARSHAL_CRITICALHANDLEARRAY);
5042 }
5043 else if (etElement == ELEMENT_TYPE_VALUETYPE)
5044 {
5045 if (m_thElement == TypeHandle(MscorlibBinder::GetClass(CLASS__DATE_TIME)))
5046 {
5047 if (ntElement == NATIVE_TYPE_STRUCT || ntElement == NATIVE_TYPE_DEFAULT)
5048 m_vtElement = VT_DATE;
5049 else
5050 ReportInvalidArrayMarshalInfo(IDS_EE_BADMARSHAL_DATETIMEARRAY);
5051 }
5052 else if (m_thElement == TypeHandle(MscorlibBinder::GetClass(CLASS__DECIMAL)))
5053 {
5054 if (ntElement == NATIVE_TYPE_STRUCT || ntElement == NATIVE_TYPE_DEFAULT)
5055 m_vtElement = VT_DECIMAL;
5056#ifdef FEATURE_COMINTEROP
5057 else if (ntElement == NATIVE_TYPE_CURRENCY)
5058 m_vtElement = VT_CY;
5059#endif // FEATURE_COMINTEROP
5060 else
5061 ReportInvalidArrayMarshalInfo(IDS_EE_BADMARSHAL_DECIMALARRAY);
5062 }
5063 else
5064 {
5065 // When exporting, we need to handle enums specially.
5066 if (IsAMIExport(m_flags) && m_thElement.IsEnum())
5067 {
5068 // Get the element type of the underlying type.
5069 CorElementType et = m_thElement.GetInternalCorElementType();
5070
5071 // If it is not a 32-bit type, convert as the underlying type.
5072 if ((et == ELEMENT_TYPE_I4) || (et == ELEMENT_TYPE_U4))
5073 m_vtElement = VT_RECORD;
5074 else
5075 m_vtElement = OleVariant::GetVarTypeForTypeHandle(m_thElement);
5076 }
5077 else
5078 {
5079 m_vtElement = OleVariant::GetVarTypeForTypeHandle(m_thElement);
5080 }
5081 }
5082 }
5083#ifdef FEATURE_COMINTEROP
5084 else if (m_thElement == TypeHandle(MscorlibBinder::GetClass(CLASS__ERROR_WRAPPER)))
5085 {
5086 m_vtElement = VT_ERROR;
5087 }
5088#endif
5089 else
5090 {
5091#ifdef FEATURE_COMINTEROP
5092
5093 // Compat: Even if the classes have layout, we still convert them to interface pointers.
5094
5095 ItfMarshalInfo itfInfo;
5096 MarshalInfo::GetItfMarshalInfo(m_thElement, TypeHandle(), FALSE, FALSE, ms, &itfInfo);
5097
5098 // Compat: We must always do VT_UNKNOWN marshaling for parameters, even if the interface is marked late-bound.
5099 if (ms == MarshalInfo::MARSHAL_SCENARIO_FIELD)
5100 m_vtElement = static_cast<VARTYPE>(!!(itfInfo.dwFlags & ItfMarshalInfo::ITF_MARSHAL_DISP_ITF) ? VT_DISPATCH : VT_UNKNOWN);
5101 else
5102 m_vtElement = VT_UNKNOWN;
5103
5104 m_thElement = itfInfo.thItf.IsNull() ? TypeHandle(g_pObjectClass) : itfInfo.thItf;
5105 m_thInterfaceArrayElementClass = itfInfo.thClass;
5106
5107#else // FEATURE_COMINTEROP
5108 ReportInvalidArrayMarshalInfo(IDS_EE_BADMARSHAL_UNSUPPORTED_SIG);
5109#endif // FEATURE_COMINTEROP
5110 }
5111 }
5112
5113 // Avoid throwing exceptions for any managed structs that have layouts and have types of fields that gets default to those banned types by default
5114 // We don't know if they will be passed to native code anyway, and the right place to make the check is in the marshallers
5115 if (AppX::IsAppXProcess() && ms != MarshalInfo::MARSHAL_SCENARIO_FIELD)
5116 {
5117 bool set_error = false;
5118 UINT m_resID = 0;
5119 switch (m_vtElement)
5120 {
5121 case VT_DISPATCH:
5122 m_resID = IDS_EE_BADMARSHAL_TYPE_IDISPATCH ;
5123 set_error = true;
5124 break;
5125 }
5126 if (set_error)
5127 COMPlusThrow(kPlatformNotSupportedException, m_resID);
5128 }
5129
5130 // If we are exporting, we need to substitute the VTHACK_* VARTYPE with the actual
5131 // types as expressed in the type library.
5132 if (IsAMIExport(m_flags))
5133 {
5134 if (m_vtElement == VTHACK_ANSICHAR)
5135 m_vtElement = VT_UI1;
5136 else if (m_vtElement == VTHACK_WINBOOL)
5137 m_vtElement = VT_I4;
5138 else if (m_vtElement == VTHACK_CBOOL)
5139 m_vtElement = VT_UI1;
5140 }
5141
5142LExit:;
5143
5144 RETURN;
5145}
5146
5147bool IsUnsupportedValueTypeReturn(MetaSig& msig)
5148{
5149 CONTRACTL
5150 {
5151 THROWS;
5152 GC_TRIGGERS;
5153 MODE_ANY;
5154 }
5155 CONTRACTL_END
5156
5157 CorElementType type = msig.GetReturnTypeNormalized();
5158
5159 if (type == ELEMENT_TYPE_VALUETYPE || type == ELEMENT_TYPE_TYPEDBYREF)
5160 {
5161#ifdef _TARGET_X86_
5162 // On x86, the internal CorElementType for value types is normalized by the type loader
5163 // (see calls to ComputeInternalCorElementTypeForValueType in MethodTableBuilder).
5164 // We don't need to redo the normalization here.
5165 return true;
5166#else
5167 TypeHandle th = msig.GetRetTypeHandleThrowing();
5168
5169 return EEClass::ComputeInternalCorElementTypeForValueType(th.GetMethodTable()) == ELEMENT_TYPE_VALUETYPE;
5170#endif // _TARGET_X86_
5171 }
5172
5173 return false;
5174}
5175
5176#ifndef CROSSGEN_COMPILE
5177
5178#include "stubhelpers.h"
5179FCIMPL3(void*, StubHelpers::CreateCustomMarshalerHelper,
5180 MethodDesc* pMD,
5181 mdToken paramToken,
5182 TypeHandle hndManagedType)
5183{
5184 FCALL_CONTRACT;
5185
5186 CustomMarshalerHelper* pCMHelper = NULL;
5187
5188 HELPER_METHOD_FRAME_BEGIN_RET_0();
5189
5190 Module* pModule = pMD->GetModule();
5191 Assembly* pAssembly = pModule->GetAssembly();
5192
5193
5194#ifdef FEATURE_COMINTEROP
5195 if (!hndManagedType.IsTypeDesc() &&
5196 IsTypeRefOrDef(g_CollectionsEnumeratorClassName, hndManagedType.GetModule(), hndManagedType.GetCl()))
5197 {
5198 pCMHelper = SetupCustomMarshalerHelper(ENUMERATOR_TO_ENUM_VARIANT_CM_NAME,
5199 ENUMERATOR_TO_ENUM_VARIANT_CM_NAME_LEN,
5200 ENUMERATOR_TO_ENUM_VARIANT_CM_COOKIE,
5201 ENUMERATOR_TO_ENUM_VARIANT_CM_COOKIE_LEN,
5202 pAssembly, hndManagedType);
5203 }
5204 else
5205#endif // FEATURE_COMINTEROP
5206 {
5207 //
5208 // Retrieve the native type for the current parameter.
5209 //
5210
5211 BOOL result;
5212 NativeTypeParamInfo ParamInfo;
5213 result = ParseNativeTypeInfo(paramToken, pModule->GetMDImport(), &ParamInfo);
5214
5215 //
5216 // this should all have been done at stub creation time
5217 //
5218 CONSISTENCY_CHECK(result != 0);
5219 CONSISTENCY_CHECK(ParamInfo.m_NativeType == NATIVE_TYPE_CUSTOMMARSHALER);
5220
5221 // Set up the custom marshaler info.
5222 pCMHelper = SetupCustomMarshalerHelper(ParamInfo.m_strCMMarshalerTypeName,
5223 ParamInfo.m_cCMMarshalerTypeNameBytes,
5224 ParamInfo.m_strCMCookie,
5225 ParamInfo.m_cCMCookieStrBytes,
5226 pAssembly,
5227 hndManagedType);
5228 }
5229
5230 HELPER_METHOD_FRAME_END();
5231
5232 return (void*)pCMHelper;
5233}
5234FCIMPLEND
5235
5236#endif // CROSSGEN_COMPILE
5237