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 | //------------------------------------------------------------------------------------- |
81 | void 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 | //------------------------------------------------------------------------------------- |
279 | void 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 | //========================================================================== |
416 | CustomMarshalerHelper *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 | //========================================================================== |
447 | HRESULT 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 | //========================================================================== |
475 | BOOL ParseNativeTypeInfo(NativeTypeParamInfo* pParamInfo, PCCOR_SIGNATURE pvNativeType, ULONG cbNativeType); |
476 | |
477 | BOOL 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 | |
498 | BOOL 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 | //========================================================================== |
690 | void 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(), ¶mInfo)) |
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 | |
776 | VOID 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 | //=============================================================== |
816 | VOID 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 | |
865 | void *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 | |
883 | void 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 | |
890 | EventArgsMarshalingInfo::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 | |
935 | EventArgsMarshalingInfo::~EventArgsMarshalingInfo() |
936 | { |
937 | LIMITED_METHOD_CONTRACT; |
938 | } |
939 | |
940 | void *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 | |
959 | void 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 | |
966 | UriMarshalingInfo::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 | |
995 | UriMarshalingInfo::~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 | |
1013 | OleColorMarshalingInfo::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 | |
1047 | void *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 | |
1066 | void 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 | |
1075 | EEMarshalingData::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 | |
1095 | EEMarshalingData::~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 | |
1132 | void *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 | |
1151 | void 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 | |
1160 | CustomMarshalerHelper *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 | |
1244 | CustomMarshalerInfo *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 |
1311 | UriMarshalingInfo *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 | |
1339 | EventArgsMarshalingInfo *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 | |
1367 | OleColorMarshalingInfo *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 |
1403 | MarshalInfo::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 | |
2767 | lExit: |
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 | |
2919 | lReallyExit: |
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 | |
2937 | VOID 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 | |
2961 | HRESULT 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 | |
3071 | ILMarshaler* 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 | |
3102 | DWORD 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 | |
3130 | DWORD 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 | |
3148 | void 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 | |
3243 | void 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 | |
3321 | void 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 | |
3351 | UINT16 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 | |
3393 | UINT16 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 | |
3428 | bool 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 | |
3449 | bool 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 | |
3470 | OVERRIDEPROC 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 | |
3490 | RETURNOVERRIDEPROC 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 | |
3510 | void 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 | |
3526 | void 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 | |
3731 | HRESULT 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 |
3763 | VOID 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 |
4024 | DispParamMarshaler *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 | |
4092 | DispatchWrapperType 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 | |
4149 | VOID 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 | |
4411 | VOID 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. |
4528 | bool 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 |
4580 | MarshalInfo::MarshalType MarshalInfo::GetHiddenLengthParamMarshalType() |
4581 | { |
4582 | LIMITED_METHOD_CONTRACT; |
4583 | return MARSHAL_TYPE_GENERIC_U4; |
4584 | } |
4585 | |
4586 | CorElementType MarshalInfo::GetHiddenLengthParamElementType() |
4587 | { |
4588 | LIMITED_METHOD_CONTRACT; |
4589 | return ELEMENT_TYPE_U4; |
4590 | } |
4591 | |
4592 | UINT16 MarshalInfo::GetHiddenLengthParamStackSize() |
4593 | { |
4594 | LIMITED_METHOD_CONTRACT; |
4595 | return StackElemSize(GetNativeSize(GetHiddenLengthParamMarshalType(), m_ms)); |
4596 | } |
4597 | |
4598 | void 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 | |
4672 | void 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 | |
4678 | void 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 |
4685 | void 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 | |
4707 | void 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 | |
4810 | LExit:; |
4811 | } |
4812 | #endif // FEATURE_COMINTEROP |
4813 | |
4814 | void 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 | |
5142 | LExit:; |
5143 | |
5144 | RETURN; |
5145 | } |
5146 | |
5147 | bool 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" |
5179 | FCIMPL3(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 | } |
5234 | FCIMPLEND |
5235 | |
5236 | #endif // CROSSGEN_COMPILE |
5237 | |