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: OleVariant.cpp |
6 | // |
7 | |
8 | // |
9 | |
10 | |
11 | #include "common.h" |
12 | |
13 | #include "object.h" |
14 | #include "excep.h" |
15 | #include "frames.h" |
16 | #include "vars.hpp" |
17 | #include "olevariant.h" |
18 | #include "comdatetime.h" |
19 | #include "fieldmarshaler.h" |
20 | #include "mdaassistants.h" |
21 | |
22 | /* ------------------------------------------------------------------------- * |
23 | * Local constants |
24 | * ------------------------------------------------------------------------- */ |
25 | |
26 | #define NO_MAPPING ((BYTE) -1) |
27 | |
28 | #define GCPROTECT_BEGIN_VARIANTDATA(/*VARIANTDATA*/vd) do { \ |
29 | FrameWithCookie<GCFrame> __gcframe(vd.GetObjRefPtr(), 1, FALSE); \ |
30 | /* work around unreachable code warning */ \ |
31 | if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT); |
32 | |
33 | |
34 | #define GCPROTECT_END_VARIANTDATA() \ |
35 | DEBUG_ASSURE_NO_RETURN_END(GCPROTECT); } \ |
36 | __gcframe.Pop(); } while(0) |
37 | |
38 | |
39 | //Mapping from CVType to type handle. Used for conversion between the two internally. |
40 | const BinderClassID CVTypeToBinderClassID[] = |
41 | { |
42 | CLASS__EMPTY, //CV_EMPTY |
43 | CLASS__VOID, //CV_VOID, Changing this to object messes up signature resolution very badly. |
44 | CLASS__BOOLEAN, //CV_BOOLEAN |
45 | CLASS__CHAR, //CV_CHAR |
46 | CLASS__SBYTE, //CV_I1 |
47 | CLASS__BYTE, //CV_U1 |
48 | CLASS__INT16, //CV_I2 |
49 | CLASS__UINT16, //CV_U2 |
50 | CLASS__INT32, //CV_I4 |
51 | CLASS__UINT32, //CV_UI4 |
52 | CLASS__INT64, //CV_I8 |
53 | CLASS__UINT64, //CV_UI8 |
54 | CLASS__SINGLE, //CV_R4 |
55 | CLASS__DOUBLE, //CV_R8 |
56 | CLASS__STRING, //CV_STRING |
57 | CLASS__VOID, //CV_PTR...We treat this as void |
58 | CLASS__DATE_TIME, //CV_DATETIME |
59 | CLASS__TIMESPAN, //CV_TIMESPAN |
60 | CLASS__OBJECT, //CV_OBJECT |
61 | CLASS__DECIMAL, //CV_DECIMAL |
62 | CLASS__CURRENCY, //CV_CURRENCY |
63 | CLASS__OBJECT, //ENUM...We treat this as OBJECT |
64 | CLASS__MISSING, //CV_MISSING |
65 | CLASS__NULL, //CV_NULL |
66 | CLASS__NIL, //CV_LAST |
67 | }; |
68 | |
69 | // Use this very carefully. There is not a direct mapping between |
70 | // CorElementType and CVTypes for a bunch of things. In this case |
71 | // we return CV_LAST. You need to check this at the call site. |
72 | CVTypes CorElementTypeToCVTypes(CorElementType type) |
73 | { |
74 | LIMITED_METHOD_CONTRACT; |
75 | |
76 | if (type <= ELEMENT_TYPE_STRING) |
77 | return (CVTypes) type; |
78 | |
79 | if (type == ELEMENT_TYPE_CLASS || type == ELEMENT_TYPE_OBJECT) |
80 | return (CVTypes) ELEMENT_TYPE_CLASS; |
81 | |
82 | return CV_LAST; |
83 | } |
84 | |
85 | /* ------------------------------------------------------------------------- * |
86 | * Mapping routines |
87 | * ------------------------------------------------------------------------- */ |
88 | |
89 | VARTYPE OleVariant::GetVarTypeForCVType(CVTypes type) |
90 | { |
91 | CONTRACTL |
92 | { |
93 | THROWS; |
94 | GC_NOTRIGGER; |
95 | MODE_ANY; |
96 | } |
97 | CONTRACTL_END; |
98 | |
99 | static const BYTE map[] = |
100 | { |
101 | VT_EMPTY, // CV_EMPTY |
102 | VT_VOID, // CV_VOID |
103 | VT_BOOL, // CV_BOOLEAN |
104 | VT_UI2, // CV_CHAR |
105 | VT_I1, // CV_I1 |
106 | VT_UI1, // CV_U1 |
107 | VT_I2, // CV_I2 |
108 | VT_UI2, // CV_U2 |
109 | VT_I4, // CV_I4 |
110 | VT_UI4, // CV_U4 |
111 | VT_I8, // CV_I8 |
112 | VT_UI8, // CV_U8 |
113 | VT_R4, // CV_R4 |
114 | VT_R8, // CV_R8 |
115 | VT_BSTR, // CV_STRING |
116 | NO_MAPPING, // CV_PTR |
117 | VT_DATE, // CV_DATETIME |
118 | NO_MAPPING, // CV_TIMESPAN |
119 | VT_DISPATCH, // CV_OBJECT |
120 | VT_DECIMAL, // CV_DECIMAL |
121 | VT_CY, // CV_CURRENCY |
122 | VT_I4, // CV_ENUM |
123 | VT_ERROR, // CV_MISSING |
124 | VT_NULL // CV_NULL |
125 | }; |
126 | |
127 | _ASSERTE(type < (CVTypes) (sizeof(map) / sizeof(map[0]))); |
128 | |
129 | VARTYPE vt = VARTYPE(map[type]); |
130 | |
131 | if (vt == NO_MAPPING) |
132 | COMPlusThrow(kArgumentException, IDS_EE_COM_UNSUPPORTED_SIG); |
133 | |
134 | return vt; |
135 | } |
136 | |
137 | // |
138 | // GetCVTypeForVarType returns the COM+ variant type for a given |
139 | // VARTYPE. This is called by the marshaller in the context of |
140 | // a function call. |
141 | // |
142 | |
143 | CVTypes OleVariant::GetCVTypeForVarType(VARTYPE vt) |
144 | { |
145 | CONTRACTL |
146 | { |
147 | THROWS; |
148 | GC_NOTRIGGER; |
149 | MODE_ANY; |
150 | } |
151 | CONTRACTL_END; |
152 | |
153 | static const BYTE map[] = |
154 | { |
155 | CV_EMPTY, // VT_EMPTY |
156 | CV_NULL, // VT_NULL |
157 | CV_I2, // VT_I2 |
158 | CV_I4, // VT_I4 |
159 | CV_R4, // VT_R4 |
160 | CV_R8, // VT_R8 |
161 | CV_DECIMAL, // VT_CY |
162 | CV_DATETIME, // VT_DATE |
163 | CV_STRING, // VT_BSTR |
164 | CV_OBJECT, // VT_DISPATCH |
165 | CV_I4, // VT_ERROR |
166 | CV_BOOLEAN, // VT_BOOL |
167 | NO_MAPPING, // VT_VARIANT |
168 | CV_OBJECT, // VT_UNKNOWN |
169 | CV_DECIMAL, // VT_DECIMAL |
170 | NO_MAPPING, // unused |
171 | CV_I1, // VT_I1 |
172 | CV_U1, // VT_UI1 |
173 | CV_U2, // VT_UI2 |
174 | CV_U4, // VT_UI4 |
175 | CV_I8, // VT_I8 |
176 | CV_U8, // VT_UI8 |
177 | CV_I4, // VT_INT |
178 | CV_U4, // VT_UINT |
179 | CV_VOID, // VT_VOID |
180 | NO_MAPPING, // VT_HRESULT |
181 | NO_MAPPING, // VT_PTR |
182 | NO_MAPPING, // VT_SAFEARRAY |
183 | NO_MAPPING, // VT_CARRAY |
184 | NO_MAPPING, // VT_USERDEFINED |
185 | NO_MAPPING, // VT_LPSTR |
186 | NO_MAPPING, // VT_LPWSTR |
187 | NO_MAPPING, // unused |
188 | NO_MAPPING, // unused |
189 | NO_MAPPING, // unused |
190 | NO_MAPPING, // unused |
191 | CV_OBJECT, // VT_RECORD |
192 | }; |
193 | |
194 | CVTypes type = CV_LAST; |
195 | |
196 | // Validate the arguments. |
197 | _ASSERTE((vt & VT_BYREF) == 0); |
198 | |
199 | // Array's map to CV_OBJECT. |
200 | if (vt & VT_ARRAY) |
201 | return CV_OBJECT; |
202 | |
203 | // This is prety much a workaround because you cannot cast a CorElementType into a CVTYPE |
204 | if (vt > VT_RECORD || (BYTE)(type = (CVTypes) map[vt]) == NO_MAPPING) |
205 | COMPlusThrow(kArgumentException, IDS_EE_COM_UNSUPPORTED_TYPE); |
206 | |
207 | return type; |
208 | } // CVTypes OleVariant::GetCVTypeForVarType() |
209 | |
210 | #ifdef FEATURE_COMINTEROP |
211 | |
212 | // GetVarTypeForComVariant retusn the VARTYPE for the contents |
213 | // of a COM+ variant. |
214 | // |
215 | VARTYPE OleVariant::GetVarTypeForComVariant(VariantData *pComVariant) |
216 | { |
217 | CONTRACTL |
218 | { |
219 | THROWS; |
220 | GC_TRIGGERS; |
221 | MODE_COOPERATIVE; |
222 | } |
223 | CONTRACTL_END; |
224 | |
225 | CVTypes type = pComVariant->GetType(); |
226 | VARTYPE vt; |
227 | |
228 | vt = pComVariant->GetVT(); |
229 | if (vt != VT_EMPTY) |
230 | { |
231 | // This variant was originally unmarshaled from unmanaged, and had the original VT recorded in it. |
232 | // We'll always use that over inference. |
233 | return vt; |
234 | } |
235 | |
236 | if (type == CV_OBJECT) |
237 | { |
238 | OBJECTREF obj = pComVariant->GetObjRef(); |
239 | |
240 | // Null objects will be converted to VT_DISPATCH variants with a null |
241 | // IDispatch pointer. |
242 | if (obj == NULL) |
243 | return VT_DISPATCH; |
244 | |
245 | // Retrieve the object's method table. |
246 | MethodTable *pMT = obj->GetMethodTable(); |
247 | |
248 | // Handle the value class case. |
249 | if (pMT->IsValueType()) |
250 | return VT_RECORD; |
251 | |
252 | // Handle the array case. |
253 | if (pMT->IsArray()) |
254 | { |
255 | vt = GetElementVarTypeForArrayRef((BASEARRAYREF)obj); |
256 | if (vt == VT_ARRAY) |
257 | vt = VT_VARIANT; |
258 | |
259 | return vt | VT_ARRAY; |
260 | } |
261 | |
262 | #ifdef FEATURE_COMINTEROP |
263 | // SafeHandle's or CriticalHandle's cannot be stored in VARIANT's. |
264 | if (pMT->CanCastToClass(MscorlibBinder::GetClass(CLASS__SAFE_HANDLE))) |
265 | COMPlusThrow(kArgumentException, IDS_EE_SH_IN_VARIANT_NOT_SUPPORTED); |
266 | if (pMT->CanCastToClass(MscorlibBinder::GetClass(CLASS__CRITICAL_HANDLE))) |
267 | COMPlusThrow(kArgumentException, IDS_EE_CH_IN_VARIANT_NOT_SUPPORTED); |
268 | |
269 | // VariantWrappers cannot be stored in VARIANT's. |
270 | if (MscorlibBinder::IsClass(pMT, CLASS__VARIANT_WRAPPER)) |
271 | COMPlusThrow(kArgumentException, IDS_EE_VAR_WRAP_IN_VAR_NOT_SUPPORTED); |
272 | |
273 | // We are dealing with a normal object (not a wrapper) so we will |
274 | // leave the VT as VT_DISPATCH for now and we will determine the actual |
275 | // VT when we convert the object to a COM IP. |
276 | return VT_DISPATCH; |
277 | #else // FEATURE_COMINTEROP |
278 | return VT_UNKNOWN; |
279 | #endif // FEATURE_COMINTEROP |
280 | } |
281 | |
282 | return GetVarTypeForCVType(type); |
283 | } |
284 | |
285 | #endif // FEATURE_COMINTEROP |
286 | |
287 | VARTYPE OleVariant::GetVarTypeForTypeHandle(TypeHandle type) |
288 | { |
289 | CONTRACTL |
290 | { |
291 | THROWS; |
292 | GC_TRIGGERS; |
293 | MODE_ANY; |
294 | } |
295 | CONTRACTL_END; |
296 | |
297 | // Handle primitive types. |
298 | CorElementType elemType = type.GetSignatureCorElementType(); |
299 | if (elemType <= ELEMENT_TYPE_R8) |
300 | return GetVarTypeForCVType(CorElementTypeToCVTypes(elemType)); |
301 | |
302 | // Handle objects. |
303 | if (!type.IsTypeDesc()) |
304 | { |
305 | MethodTable * pMT = type.AsMethodTable(); |
306 | |
307 | if (pMT == g_pStringClass) |
308 | return VT_BSTR; |
309 | if (pMT == g_pObjectClass) |
310 | return VT_VARIANT; |
311 | |
312 | // We need to make sure the CVClasses table is populated. |
313 | if(MscorlibBinder::IsClass(pMT, CLASS__DATE_TIME)) |
314 | return VT_DATE; |
315 | if(MscorlibBinder::IsClass(pMT, CLASS__DECIMAL)) |
316 | return VT_DECIMAL; |
317 | |
318 | #ifdef _WIN64 |
319 | if (MscorlibBinder::IsClass(pMT, CLASS__INTPTR)) |
320 | return VT_I8; |
321 | if (MscorlibBinder::IsClass(pMT, CLASS__UINTPTR)) |
322 | return VT_UI8; |
323 | #else |
324 | if (MscorlibBinder::IsClass(pMT, CLASS__INTPTR)) |
325 | return VT_INT; |
326 | if (MscorlibBinder::IsClass(pMT, CLASS__UINTPTR)) |
327 | return VT_UINT; |
328 | #endif |
329 | |
330 | #ifdef FEATURE_COMINTEROP |
331 | if (MscorlibBinder::IsClass(pMT, CLASS__DISPATCH_WRAPPER)) |
332 | return VT_DISPATCH; |
333 | if (MscorlibBinder::IsClass(pMT, CLASS__UNKNOWN_WRAPPER)) |
334 | return VT_UNKNOWN; |
335 | if (MscorlibBinder::IsClass(pMT, CLASS__ERROR_WRAPPER)) |
336 | return VT_ERROR; |
337 | if (MscorlibBinder::IsClass(pMT, CLASS__CURRENCY_WRAPPER)) |
338 | return VT_CY; |
339 | if (MscorlibBinder::IsClass(pMT, CLASS__BSTR_WRAPPER)) |
340 | return VT_BSTR; |
341 | |
342 | // VariantWrappers cannot be stored in VARIANT's. |
343 | if (MscorlibBinder::IsClass(pMT, CLASS__VARIANT_WRAPPER)) |
344 | COMPlusThrow(kArgumentException, IDS_EE_COM_UNSUPPORTED_SIG); |
345 | #endif // FEATURE_COMINTEROP |
346 | |
347 | if (pMT->IsEnum()) |
348 | return GetVarTypeForCVType((CVTypes)type.GetInternalCorElementType()); |
349 | |
350 | if (pMT->IsValueType()) |
351 | return VT_RECORD; |
352 | |
353 | #ifdef FEATURE_COMINTEROP |
354 | // There is no VT corresponding to SafeHandles as they cannot be stored in |
355 | // VARIANTs or Arrays. The same applies to CriticalHandle. |
356 | if (type.CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__SAFE_HANDLE)))) |
357 | COMPlusThrow(kArgumentException, IDS_EE_COM_UNSUPPORTED_SIG); |
358 | if (type.CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__CRITICAL_HANDLE)))) |
359 | COMPlusThrow(kArgumentException, IDS_EE_COM_UNSUPPORTED_SIG); |
360 | |
361 | if (pMT->IsInterface()) |
362 | { |
363 | CorIfaceAttr ifaceType = pMT->GetComInterfaceType(); |
364 | return static_cast<VARTYPE>(IsDispatchBasedItf(ifaceType) ? VT_DISPATCH : VT_UNKNOWN); |
365 | } |
366 | |
367 | TypeHandle hndDefItfClass; |
368 | DefaultInterfaceType DefItfType = GetDefaultInterfaceForClassWrapper(type, &hndDefItfClass); |
369 | switch (DefItfType) |
370 | { |
371 | case DefaultInterfaceType_Explicit: |
372 | { |
373 | CorIfaceAttr ifaceType = hndDefItfClass.GetMethodTable()->GetComInterfaceType(); |
374 | return static_cast<VARTYPE>(IsDispatchBasedItf(ifaceType) ? VT_DISPATCH : VT_UNKNOWN); |
375 | } |
376 | |
377 | case DefaultInterfaceType_AutoDual: |
378 | { |
379 | return VT_DISPATCH; |
380 | } |
381 | |
382 | case DefaultInterfaceType_IUnknown: |
383 | case DefaultInterfaceType_BaseComClass: |
384 | { |
385 | return VT_UNKNOWN; |
386 | } |
387 | |
388 | case DefaultInterfaceType_AutoDispatch: |
389 | { |
390 | return VT_DISPATCH; |
391 | } |
392 | |
393 | default: |
394 | { |
395 | _ASSERTE(!"Invalid default interface type!" ); |
396 | } |
397 | } |
398 | #endif // FEATURE_COMINTEROP |
399 | |
400 | return VT_UNKNOWN; |
401 | } |
402 | |
403 | // Handle array's. |
404 | if (!CorTypeInfo::IsArray(elemType)) |
405 | { |
406 | // Non interop compatible type. |
407 | COMPlusThrow(kArgumentException, IDS_EE_COM_UNSUPPORTED_SIG); |
408 | } |
409 | |
410 | return VT_ARRAY; |
411 | } |
412 | |
413 | // |
414 | // GetElementVarTypeForArrayRef returns the safearray variant type for the |
415 | // underlying elements in the array. |
416 | // |
417 | |
418 | VARTYPE OleVariant::GetElementVarTypeForArrayRef(BASEARRAYREF pArrayRef) |
419 | { |
420 | CONTRACTL |
421 | { |
422 | THROWS; |
423 | GC_TRIGGERS; |
424 | MODE_COOPERATIVE; |
425 | } |
426 | CONTRACTL_END; |
427 | |
428 | TypeHandle elemTypeHnd = pArrayRef->GetArrayElementTypeHandle(); |
429 | return(GetVarTypeForTypeHandle(elemTypeHnd)); |
430 | } |
431 | |
432 | #ifdef FEATURE_COMINTEROP |
433 | |
434 | BOOL OleVariant::IsValidArrayForSafeArrayElementType(BASEARRAYREF *pArrayRef, VARTYPE vtExpected) |
435 | { |
436 | CONTRACTL |
437 | { |
438 | THROWS; |
439 | GC_TRIGGERS; |
440 | MODE_COOPERATIVE; |
441 | } |
442 | CONTRACTL_END; |
443 | |
444 | // Retrieve the VARTYPE for the managed array. |
445 | VARTYPE vtActual = GetElementVarTypeForArrayRef(*pArrayRef); |
446 | |
447 | // If the actual type is the same as the expected type, then the array is valid. |
448 | if (vtActual == vtExpected) |
449 | return TRUE; |
450 | |
451 | // Check for additional supported VARTYPES. |
452 | switch (vtExpected) |
453 | { |
454 | case VT_I4: |
455 | return vtActual == VT_INT; |
456 | |
457 | case VT_INT: |
458 | return vtActual == VT_I4; |
459 | |
460 | case VT_UI4: |
461 | return vtActual == VT_UINT; |
462 | |
463 | case VT_UINT: |
464 | return vtActual == VT_UI4; |
465 | |
466 | case VT_UNKNOWN: |
467 | return vtActual == VT_VARIANT || vtActual == VT_DISPATCH; |
468 | |
469 | case VT_DISPATCH: |
470 | return vtActual == VT_VARIANT; |
471 | |
472 | case VT_CY: |
473 | return vtActual == VT_DECIMAL; |
474 | |
475 | case VT_LPSTR: |
476 | case VT_LPWSTR: |
477 | return vtActual == VT_BSTR; |
478 | |
479 | default: |
480 | return FALSE; |
481 | } |
482 | } |
483 | |
484 | #endif // FEATURE_COMINTEROP |
485 | |
486 | // |
487 | // GetArrayClassForVarType returns the element class name and underlying method table |
488 | // to use to represent an array with the given variant type. |
489 | // |
490 | |
491 | TypeHandle OleVariant::GetArrayForVarType(VARTYPE vt, TypeHandle elemType, unsigned rank) |
492 | { |
493 | CONTRACTL |
494 | { |
495 | THROWS; |
496 | GC_TRIGGERS; |
497 | MODE_COOPERATIVE; |
498 | } |
499 | CONTRACTL_END; |
500 | |
501 | CorElementType baseElement = ELEMENT_TYPE_END; |
502 | TypeHandle baseType; |
503 | |
504 | if (!elemType.IsNull() && elemType.IsEnum()) |
505 | { |
506 | baseType = elemType; |
507 | } |
508 | else |
509 | { |
510 | switch (vt) |
511 | { |
512 | case VT_BOOL: |
513 | case VTHACK_WINBOOL: |
514 | case VTHACK_CBOOL: |
515 | baseElement = ELEMENT_TYPE_BOOLEAN; |
516 | break; |
517 | |
518 | case VTHACK_ANSICHAR: |
519 | baseElement = ELEMENT_TYPE_CHAR; |
520 | break; |
521 | |
522 | case VT_UI1: |
523 | baseElement = ELEMENT_TYPE_U1; |
524 | break; |
525 | |
526 | case VT_I1: |
527 | baseElement = ELEMENT_TYPE_I1; |
528 | break; |
529 | |
530 | case VT_UI2: |
531 | baseElement = ELEMENT_TYPE_U2; |
532 | break; |
533 | |
534 | case VT_I2: |
535 | baseElement = ELEMENT_TYPE_I2; |
536 | break; |
537 | |
538 | case VT_UI4: |
539 | case VT_UINT: |
540 | case VT_ERROR: |
541 | if (vt == VT_UI4) |
542 | { |
543 | if (elemType.IsNull() || elemType == TypeHandle(g_pObjectClass)) |
544 | { |
545 | baseElement = ELEMENT_TYPE_U4; |
546 | } |
547 | else |
548 | { |
549 | switch (elemType.AsMethodTable()->GetInternalCorElementType()) |
550 | { |
551 | case ELEMENT_TYPE_U4: |
552 | baseElement = ELEMENT_TYPE_U4; |
553 | break; |
554 | case ELEMENT_TYPE_U: |
555 | baseElement = ELEMENT_TYPE_U; |
556 | break; |
557 | default: |
558 | _ASSERTE(0); |
559 | } |
560 | } |
561 | } |
562 | else |
563 | { |
564 | baseElement = ELEMENT_TYPE_U4; |
565 | } |
566 | break; |
567 | |
568 | case VT_I4: |
569 | case VT_INT: |
570 | if (vt == VT_I4) |
571 | { |
572 | if (elemType.IsNull() || elemType == TypeHandle(g_pObjectClass)) |
573 | { |
574 | baseElement = ELEMENT_TYPE_I4; |
575 | } |
576 | else |
577 | { |
578 | switch (elemType.AsMethodTable()->GetInternalCorElementType()) |
579 | { |
580 | case ELEMENT_TYPE_I4: |
581 | baseElement = ELEMENT_TYPE_I4; |
582 | break; |
583 | case ELEMENT_TYPE_I: |
584 | baseElement = ELEMENT_TYPE_I; |
585 | break; |
586 | default: |
587 | _ASSERTE(0); |
588 | } |
589 | } |
590 | } |
591 | else |
592 | { |
593 | baseElement = ELEMENT_TYPE_I4; |
594 | } |
595 | break; |
596 | |
597 | case VT_I8: |
598 | if (elemType.IsNull() || elemType == TypeHandle(g_pObjectClass)) |
599 | { |
600 | baseElement = ELEMENT_TYPE_I8; |
601 | } |
602 | else |
603 | { |
604 | switch (elemType.AsMethodTable()->GetInternalCorElementType()) |
605 | { |
606 | case ELEMENT_TYPE_I8: |
607 | baseElement = ELEMENT_TYPE_I8; |
608 | break; |
609 | case ELEMENT_TYPE_I: |
610 | baseElement = ELEMENT_TYPE_I; |
611 | break; |
612 | default: |
613 | _ASSERTE(0); |
614 | } |
615 | } |
616 | break; |
617 | |
618 | case VT_UI8: |
619 | if (elemType.IsNull() || elemType == TypeHandle(g_pObjectClass)) |
620 | { |
621 | baseElement = ELEMENT_TYPE_U8; |
622 | } |
623 | else |
624 | { |
625 | switch (elemType.AsMethodTable()->GetInternalCorElementType()) |
626 | { |
627 | case ELEMENT_TYPE_U8: |
628 | baseElement = ELEMENT_TYPE_U8; |
629 | break; |
630 | case ELEMENT_TYPE_U: |
631 | baseElement = ELEMENT_TYPE_U; |
632 | break; |
633 | default: |
634 | _ASSERTE(0); |
635 | } |
636 | } |
637 | break; |
638 | |
639 | case VT_R4: |
640 | baseElement = ELEMENT_TYPE_R4; |
641 | break; |
642 | |
643 | case VT_R8: |
644 | baseElement = ELEMENT_TYPE_R8; |
645 | break; |
646 | |
647 | case VT_CY: |
648 | baseType = TypeHandle(MscorlibBinder::GetClass(CLASS__DECIMAL)); |
649 | break; |
650 | |
651 | case VT_DATE: |
652 | baseType = TypeHandle(MscorlibBinder::GetClass(CLASS__DATE_TIME)); |
653 | break; |
654 | |
655 | case VT_DECIMAL: |
656 | baseType = TypeHandle(MscorlibBinder::GetClass(CLASS__DECIMAL)); |
657 | break; |
658 | |
659 | case VT_VARIANT: |
660 | |
661 | // |
662 | // It would be nice if our conversion between SAFEARRAY and |
663 | // array ref were symmetric. Right now it is not, because a |
664 | // jagged array converted to a SAFEARRAY and back will come |
665 | // back as an array of variants. |
666 | // |
667 | // We could try to detect the case where we can turn a |
668 | // safearray of variants into a jagged array. Basically we |
669 | // needs to make sure that all of the variants in the array |
670 | // have the same array type. (And if that is array of |
671 | // variant, we need to look recursively for another layer.) |
672 | // |
673 | // We also needs to check the dimensions of each array stored |
674 | // in the variant to make sure they have the same rank, and |
675 | // this rank is needed to build the correct array class name. |
676 | // (Note that it will be impossible to tell the rank if all |
677 | // elements in the array are NULL.) |
678 | // |
679 | |
680 | // <TODO>@nice: implement this functionality if we decide it really makes sense |
681 | // For now, just live with the asymmetry</TODO> |
682 | |
683 | baseType = TypeHandle(g_pObjectClass); |
684 | break; |
685 | |
686 | case VT_BSTR: |
687 | case VT_LPWSTR: |
688 | case VT_LPSTR: |
689 | baseElement = ELEMENT_TYPE_STRING; |
690 | break; |
691 | |
692 | case VT_DISPATCH: |
693 | case VT_UNKNOWN: |
694 | if (elemType.IsNull()) |
695 | baseType = TypeHandle(g_pObjectClass); |
696 | else |
697 | baseType = elemType; |
698 | break; |
699 | |
700 | case VT_RECORD: |
701 | _ASSERTE(!elemType.IsNull()); |
702 | baseType = elemType; |
703 | break; |
704 | |
705 | default: |
706 | COMPlusThrow(kArgumentException, IDS_EE_COM_UNSUPPORTED_SIG); |
707 | } |
708 | } |
709 | |
710 | if (baseType.IsNull()) |
711 | baseType = TypeHandle(MscorlibBinder::GetElementType(baseElement)); |
712 | |
713 | _ASSERTE(!baseType.IsNull()); |
714 | |
715 | return ClassLoader::LoadArrayTypeThrowing(baseType, rank == 0 ? ELEMENT_TYPE_SZARRAY : ELEMENT_TYPE_ARRAY, rank == 0 ? 1 : rank); |
716 | } |
717 | |
718 | // |
719 | // GetElementSizeForVarType returns the array element size for the given variant type. |
720 | // |
721 | |
722 | UINT OleVariant::GetElementSizeForVarType(VARTYPE vt, MethodTable *pInterfaceMT) |
723 | { |
724 | CONTRACTL |
725 | { |
726 | NOTHROW; |
727 | GC_NOTRIGGER; |
728 | MODE_ANY; |
729 | } |
730 | CONTRACTL_END; |
731 | |
732 | static const BYTE map[] = |
733 | { |
734 | 0, // VT_EMPTY |
735 | 0, // VT_NULL |
736 | 2, // VT_I2 |
737 | 4, // VT_I4 |
738 | 4, // VT_R4 |
739 | 8, // VT_R8 |
740 | sizeof(CURRENCY), // VT_CY |
741 | sizeof(DATE), // VT_DATE |
742 | sizeof(BSTR), // VT_BSTR |
743 | sizeof(IDispatch*), // VT_DISPATCH |
744 | sizeof(SCODE), // VT_ERROR |
745 | sizeof(VARIANT_BOOL), // VT_BOOL |
746 | sizeof(VARIANT), // VT_VARIANT |
747 | sizeof(IUnknown*), // VT_UNKNOWN |
748 | sizeof(DECIMAL), // VT_DECIMAL |
749 | 0, // unused |
750 | 1, // VT_I1 |
751 | 1, // VT_UI1 |
752 | 2, // VT_UI2 |
753 | 4, // VT_UI4 |
754 | 8, // VT_I8 |
755 | 8, // VT_UI8 |
756 | 4, // VT_INT |
757 | 4, // VT_UINT |
758 | 0, // VT_VOID |
759 | sizeof(HRESULT), // VT_HRESULT |
760 | sizeof(void*), // VT_PTR |
761 | sizeof(SAFEARRAY*), // VT_SAFEARRAY |
762 | sizeof(void*), // VT_CARRAY |
763 | sizeof(void*), // VT_USERDEFINED |
764 | sizeof(LPSTR), // VT_LPSTR |
765 | sizeof(LPWSTR), // VT_LPWSTR |
766 | }; |
767 | |
768 | // Special cases |
769 | switch (vt) |
770 | { |
771 | case VTHACK_WINBOOL: |
772 | return sizeof(BOOL); |
773 | break; |
774 | case VTHACK_ANSICHAR: |
775 | return GetMaxDBCSCharByteSize(); // Multi byte characters. |
776 | break; |
777 | case VTHACK_CBOOL: |
778 | return sizeof(BYTE); |
779 | default: |
780 | break; |
781 | } |
782 | |
783 | // VT_ARRAY indicates a safe array which is always sizeof(SAFEARRAY *). |
784 | if (vt & VT_ARRAY) |
785 | return sizeof(SAFEARRAY*); |
786 | |
787 | if (vt == VTHACK_NONBLITTABLERECORD || vt == VTHACK_BLITTABLERECORD || vt == VT_RECORD) |
788 | { |
789 | PREFIX_ASSUME(pInterfaceMT != NULL); |
790 | return pInterfaceMT->GetNativeSize(); |
791 | } |
792 | else if (vt > VT_LPWSTR) |
793 | return 0; |
794 | else |
795 | return map[vt]; |
796 | } |
797 | |
798 | // |
799 | // GetMarshalerForVarType returns the marshaler for the |
800 | // given VARTYPE. |
801 | // |
802 | |
803 | const OleVariant::Marshaler *OleVariant::GetMarshalerForVarType(VARTYPE vt, BOOL fThrow) |
804 | { |
805 | CONTRACT (const OleVariant::Marshaler*) |
806 | { |
807 | if (fThrow) THROWS; else NOTHROW; |
808 | GC_NOTRIGGER; |
809 | MODE_ANY; |
810 | POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); |
811 | } |
812 | CONTRACT_END; |
813 | |
814 | #ifdef FEATURE_COMINTEROP |
815 | |
816 | #ifdef CROSSGEN_COMPILE |
817 | #define RETURN_MARSHALER(OleToCom, ComToOle, OleRefToCom, ArrayOleToCom, ArrayComToOle, ClearArray) \ |
818 | { static const Marshaler marshaler = { NULL, NULL, NULL, NULL, NULL, NULL }; RETURN &marshaler; } |
819 | #else |
820 | #define RETURN_MARSHALER(OleToCom, ComToOle, OleRefToCom, ArrayOleToCom, ArrayComToOle, ClearArray) \ |
821 | { static const Marshaler marshaler = { OleToCom, ComToOle, OleRefToCom, ArrayOleToCom, ArrayComToOle, ClearArray }; RETURN &marshaler; } |
822 | #endif |
823 | |
824 | #else // FEATURE_COMINTEROP |
825 | |
826 | #ifdef CROSSGEN_COMPILE |
827 | #define RETURN_MARSHALER(OleToCom, ComToOle, OleRefToCom, ArrayOleToCom, ArrayComToOle, ClearArray) \ |
828 | { static const Marshaler marshaler = { NULL, NULL, NULL }; RETURN &marshaler; } |
829 | #else |
830 | #define RETURN_MARSHALER(OleToCom, ComToOle, OleRefToCom, ArrayOleToCom, ArrayComToOle, ClearArray) \ |
831 | { static const Marshaler marshaler = { ArrayOleToCom, ArrayComToOle, ClearArray }; RETURN &marshaler; } |
832 | #endif |
833 | |
834 | #endif // FEATURE_COMINTEROP |
835 | |
836 | #ifdef FEATURE_CLASSIC_COMINTEROP |
837 | if (vt & VT_ARRAY) |
838 | { |
839 | VariantArray: |
840 | RETURN_MARSHALER( |
841 | MarshalArrayVariantOleToCom, |
842 | MarshalArrayVariantComToOle, |
843 | MarshalArrayVariantOleRefToCom, |
844 | NULL, |
845 | NULL, |
846 | ClearVariantArray |
847 | ); |
848 | } |
849 | #endif // FEATURE_CLASSIC_COMINTEROP |
850 | |
851 | switch (vt) |
852 | { |
853 | case VT_BOOL: |
854 | RETURN_MARSHALER( |
855 | MarshalBoolVariantOleToCom, |
856 | NULL, |
857 | NULL, |
858 | MarshalBoolArrayOleToCom, |
859 | MarshalBoolArrayComToOle, |
860 | NULL |
861 | ); |
862 | |
863 | case VT_DATE: |
864 | RETURN_MARSHALER( |
865 | MarshalDateVariantOleToCom, |
866 | MarshalDateVariantComToOle, |
867 | MarshalDateVariantOleRefToCom, |
868 | MarshalDateArrayOleToCom, |
869 | MarshalDateArrayComToOle, |
870 | NULL |
871 | ); |
872 | |
873 | case VT_DECIMAL: |
874 | RETURN_MARSHALER( |
875 | MarshalDecimalVariantOleToCom, |
876 | MarshalDecimalVariantComToOle, |
877 | MarshalDecimalVariantOleRefToCom, |
878 | NULL, NULL, NULL |
879 | ); |
880 | |
881 | #ifdef FEATURE_COMINTEROP |
882 | case VT_CY: |
883 | RETURN_MARSHALER( |
884 | MarshalCurrencyVariantOleToCom, |
885 | MarshalCurrencyVariantComToOle, |
886 | MarshalCurrencyVariantOleRefToCom, |
887 | MarshalCurrencyArrayOleToCom, |
888 | MarshalCurrencyArrayComToOle, |
889 | NULL |
890 | ); |
891 | |
892 | case VT_BSTR: |
893 | RETURN_MARSHALER( |
894 | MarshalBSTRVariantOleToCom, |
895 | MarshalBSTRVariantComToOle, |
896 | NULL, |
897 | MarshalBSTRArrayOleToCom, |
898 | MarshalBSTRArrayComToOle, |
899 | ClearBSTRArray |
900 | ); |
901 | |
902 | case VT_UNKNOWN: |
903 | RETURN_MARSHALER( |
904 | MarshalInterfaceVariantOleToCom, |
905 | MarshalInterfaceVariantComToOle, |
906 | MarshalInterfaceVariantOleRefToCom, |
907 | MarshalInterfaceArrayOleToCom, |
908 | MarshalIUnknownArrayComToOle, |
909 | ClearInterfaceArray |
910 | ); |
911 | |
912 | case VT_DISPATCH: |
913 | RETURN_MARSHALER( |
914 | MarshalInterfaceVariantOleToCom, |
915 | MarshalInterfaceVariantComToOle, |
916 | MarshalInterfaceVariantOleRefToCom, |
917 | MarshalInterfaceArrayOleToCom, |
918 | MarshalIDispatchArrayComToOle, |
919 | ClearInterfaceArray |
920 | ); |
921 | |
922 | #ifdef FEATURE_CLASSIC_COMINTEROP |
923 | case VT_SAFEARRAY: |
924 | goto VariantArray; |
925 | #endif |
926 | |
927 | case VT_VARIANT: |
928 | RETURN_MARSHALER( |
929 | NULL, NULL, NULL, |
930 | MarshalVariantArrayOleToCom, |
931 | MarshalVariantArrayComToOle, |
932 | ClearVariantArray |
933 | ); |
934 | |
935 | case VT_ERROR: |
936 | RETURN_MARSHALER( |
937 | MarshalErrorVariantOleToCom, |
938 | MarshalErrorVariantComToOle, |
939 | MarshalErrorVariantOleRefToCom, |
940 | NULL, NULL, NULL |
941 | ); |
942 | #endif // FEATURE_COMINTEROP |
943 | |
944 | case VTHACK_NONBLITTABLERECORD: |
945 | RETURN_MARSHALER( |
946 | NULL, NULL, NULL, |
947 | MarshalNonBlittableRecordArrayOleToCom, |
948 | MarshalNonBlittableRecordArrayComToOle, |
949 | ClearNonBlittableRecordArray |
950 | ); |
951 | |
952 | case VTHACK_BLITTABLERECORD: |
953 | RETURN NULL; // Requires no marshaling |
954 | |
955 | case VTHACK_WINBOOL: |
956 | RETURN_MARSHALER( |
957 | MarshalWinBoolVariantOleToCom, |
958 | MarshalWinBoolVariantComToOle, |
959 | MarshalWinBoolVariantOleRefToCom, |
960 | MarshalWinBoolArrayOleToCom, |
961 | MarshalWinBoolArrayComToOle, |
962 | NULL |
963 | ); |
964 | |
965 | case VTHACK_CBOOL: |
966 | RETURN_MARSHALER( |
967 | MarshalCBoolVariantOleToCom, |
968 | MarshalCBoolVariantComToOle, |
969 | MarshalCBoolVariantOleRefToCom, |
970 | MarshalCBoolArrayOleToCom, |
971 | MarshalCBoolArrayComToOle, |
972 | NULL |
973 | ); |
974 | |
975 | case VTHACK_ANSICHAR: |
976 | RETURN_MARSHALER( |
977 | MarshalAnsiCharVariantOleToCom, |
978 | MarshalAnsiCharVariantComToOle, |
979 | MarshalAnsiCharVariantOleRefToCom, |
980 | MarshalAnsiCharArrayOleToCom, |
981 | MarshalAnsiCharArrayComToOle, |
982 | NULL |
983 | ); |
984 | |
985 | case VT_LPSTR: |
986 | RETURN_MARSHALER( |
987 | NULL, NULL, NULL, |
988 | MarshalLPSTRArrayOleToCom, |
989 | MarshalLPSTRRArrayComToOle, |
990 | ClearLPSTRArray |
991 | ); |
992 | |
993 | case VT_LPWSTR: |
994 | RETURN_MARSHALER( |
995 | NULL, NULL, NULL, |
996 | MarshalLPWSTRArrayOleToCom, |
997 | MarshalLPWSTRRArrayComToOle, |
998 | ClearLPWSTRArray |
999 | ); |
1000 | |
1001 | case VT_RECORD: |
1002 | #ifdef FEATURE_CLASSIC_COMINTEROP |
1003 | RETURN_MARSHALER( |
1004 | MarshalRecordVariantOleToCom, |
1005 | MarshalRecordVariantComToOle, |
1006 | MarshalRecordVariantOleRefToCom, |
1007 | MarshalRecordArrayOleToCom, |
1008 | MarshalRecordArrayComToOle, |
1009 | ClearRecordArray |
1010 | ); |
1011 | #else |
1012 | RETURN_MARSHALER( |
1013 | NULL, NULL, NULL, |
1014 | MarshalRecordArrayOleToCom, |
1015 | MarshalRecordArrayComToOle, |
1016 | ClearRecordArray |
1017 | ); |
1018 | #endif // FEATURE_CLASSIC_COMINTEROP |
1019 | |
1020 | case VT_CARRAY: |
1021 | case VT_USERDEFINED: |
1022 | if (fThrow) |
1023 | { |
1024 | COMPlusThrow(kArgumentException, IDS_EE_COM_UNSUPPORTED_SIG); |
1025 | } |
1026 | else |
1027 | { |
1028 | RETURN NULL; |
1029 | } |
1030 | |
1031 | default: |
1032 | RETURN NULL; |
1033 | } |
1034 | } // OleVariant::Marshaler *OleVariant::GetMarshalerForVarType() |
1035 | |
1036 | #ifndef CROSSGEN_COMPILE |
1037 | |
1038 | #ifdef FEATURE_COMINTEROP |
1039 | |
1040 | /*==================================NewVariant================================== |
1041 | **N.B.: This method does a GC Allocation. Any method calling it is required to |
1042 | ** GC_PROTECT the OBJECTREF. |
1043 | ** |
1044 | **Actions: Allocates a new Variant and fills it with the appropriate data. |
1045 | **Returns: A new Variant with all of the appropriate fields filled out. |
1046 | **Exceptions: OutOfMemoryError if v can't be allocated. |
1047 | ==============================================================================*/ |
1048 | void VariantData::NewVariant(VariantData * const& dest, const CVTypes type, INT64 data |
1049 | DEBUG_ARG(BOOL bDestIsInterior)) |
1050 | { |
1051 | CONTRACTL |
1052 | { |
1053 | THROWS; |
1054 | GC_TRIGGERS; |
1055 | MODE_COOPERATIVE; |
1056 | // Don't pass an object in for Empty. |
1057 | PRECONDITION(CheckPointer(dest)); |
1058 | PRECONDITION((bDestIsInterior && IsProtectedByGCFrame ((OBJECTREF *) &dest)) |
1059 | || (!bDestIsInterior && IsProtectedByGCFrame (dest->GetObjRefPtr ()))); |
1060 | PRECONDITION((type == CV_EMPTY) || (type == CV_NULL) || (type == CV_U4) || (type == CV_U8)); |
1061 | } |
1062 | CONTRACTL_END; |
1063 | |
1064 | //If both arguments are null or both are specified, we're in an illegal situation. Bail. |
1065 | //If all three are null, we're creating an empty variant |
1066 | if ( (type != CV_EMPTY) && (type != CV_NULL) && (type != CV_U4) && (type != CV_U8) ) |
1067 | { |
1068 | COMPlusThrow(kArgumentException); |
1069 | } |
1070 | |
1071 | //Fill in the data. |
1072 | dest->SetType(type); |
1073 | |
1074 | switch (type) |
1075 | { |
1076 | case CV_U4: |
1077 | dest->SetObjRef(NULL); |
1078 | dest->SetDataAsUInt32((UINT32)data); |
1079 | break; |
1080 | |
1081 | case CV_U8: |
1082 | dest->SetObjRef(NULL); |
1083 | dest->SetDataAsInt64(data); |
1084 | break; |
1085 | |
1086 | case CV_NULL: |
1087 | { |
1088 | FieldDesc * pFD = MscorlibBinder::GetField(FIELD__NULL__VALUE); |
1089 | _ASSERTE(pFD); |
1090 | |
1091 | pFD->CheckRunClassInitThrowing(); |
1092 | |
1093 | OBJECTREF obj = pFD->GetStaticOBJECTREF(); |
1094 | _ASSERTE(obj!=NULL); |
1095 | |
1096 | dest->SetObjRef(obj); |
1097 | dest->SetDataAsInt64(0); |
1098 | break; |
1099 | } |
1100 | |
1101 | case CV_EMPTY: |
1102 | { |
1103 | dest->SetObjRef(NULL); |
1104 | break; |
1105 | } |
1106 | |
1107 | default: |
1108 | // Did you add any new CVTypes? |
1109 | COMPlusThrow(kNotSupportedException, W("Arg_InvalidOleVariantTypeException" )); |
1110 | } |
1111 | } |
1112 | |
1113 | void SafeVariantClearHelper(_Inout_ VARIANT* pVar) |
1114 | { |
1115 | STATIC_CONTRACT_SO_INTOLERANT; |
1116 | WRAPPER_NO_CONTRACT; |
1117 | |
1118 | BEGIN_SO_TOLERANT_CODE(GetThread()); |
1119 | VariantClear(pVar); |
1120 | END_SO_TOLERANT_CODE; |
1121 | } |
1122 | |
1123 | class OutOfMemoryException; |
1124 | |
1125 | void SafeVariantClear(VARIANT* pVar) |
1126 | { |
1127 | CONTRACTL |
1128 | { |
1129 | NOTHROW; |
1130 | GC_TRIGGERS; |
1131 | MODE_ANY; |
1132 | } |
1133 | CONTRACTL_END; |
1134 | |
1135 | if (pVar) |
1136 | { |
1137 | GCX_PREEMP(); |
1138 | SCAN_EHMARKER(); |
1139 | PAL_CPP_TRY |
1140 | { |
1141 | // These are holders to tell the contract system that we're catching all exceptions. |
1142 | SCAN_EHMARKER_TRY(); |
1143 | CLR_TRY_MARKER(); |
1144 | |
1145 | // Most of time, oleaut32.dll is loaded already when we get here. |
1146 | // Sometimes, CLR initializes Variant without loading oleaut32.dll, e.g. VT_BOOL. |
1147 | // It is better for performance with EX_TRY than |
1148 | |
1149 | SafeVariantClearHelper(pVar); |
1150 | |
1151 | SCAN_EHMARKER_END_TRY(); |
1152 | } |
1153 | #pragma warning(suppress: 4101) |
1154 | PAL_CPP_CATCH_DERIVED(OutOfMemoryException, obj) |
1155 | { |
1156 | SCAN_EHMARKER_CATCH(); |
1157 | |
1158 | #if defined(STACK_GUARDS_DEBUG) |
1159 | // Catching and just swallowing an exception means we need to tell |
1160 | // the SO code that it should go back to normal operation, as it |
1161 | // currently thinks that the exception is still on the fly. |
1162 | GetThread()->GetCurrentStackGuard()->RestoreCurrentGuard(); |
1163 | #endif |
1164 | |
1165 | SCAN_EHMARKER_END_CATCH(); |
1166 | } |
1167 | PAL_CPP_ENDTRY; |
1168 | |
1169 | FillMemory(pVar, sizeof(VARIANT), 0x00); |
1170 | } |
1171 | } |
1172 | |
1173 | FORCEINLINE void EmptyVariant(VARIANT* value) |
1174 | { |
1175 | WRAPPER_NO_CONTRACT; |
1176 | SafeVariantClear(value); |
1177 | } |
1178 | |
1179 | class VariantEmptyHolder : public Wrapper<VARIANT*, ::DoNothing<VARIANT*>, EmptyVariant, NULL> |
1180 | { |
1181 | public: |
1182 | VariantEmptyHolder(VARIANT* p = NULL) : |
1183 | Wrapper<VARIANT*, ::DoNothing<VARIANT*>, EmptyVariant, NULL>(p) |
1184 | { |
1185 | WRAPPER_NO_CONTRACT; |
1186 | } |
1187 | |
1188 | FORCEINLINE void operator=(VARIANT* p) |
1189 | { |
1190 | WRAPPER_NO_CONTRACT; |
1191 | |
1192 | Wrapper<VARIANT*, ::DoNothing<VARIANT*>, EmptyVariant, NULL>::operator=(p); |
1193 | } |
1194 | }; |
1195 | |
1196 | FORCEINLINE void RecordVariantRelease(VARIANT* value) |
1197 | { |
1198 | if (value) |
1199 | { |
1200 | WRAPPER_NO_CONTRACT; |
1201 | |
1202 | if (V_RECORD(value)) |
1203 | V_RECORDINFO(value)->RecordDestroy(V_RECORD(value)); |
1204 | if (V_RECORDINFO(value)) |
1205 | V_RECORDINFO(value)->Release(); |
1206 | } |
1207 | } |
1208 | |
1209 | class RecordVariantHolder : public Wrapper<VARIANT*, ::DoNothing<VARIANT*>, RecordVariantRelease, NULL> |
1210 | { |
1211 | public: |
1212 | RecordVariantHolder(VARIANT* p = NULL) |
1213 | : Wrapper<VARIANT*, ::DoNothing<VARIANT*>, RecordVariantRelease, NULL>(p) |
1214 | { |
1215 | WRAPPER_NO_CONTRACT; |
1216 | } |
1217 | |
1218 | FORCEINLINE void operator=(VARIANT* p) |
1219 | { |
1220 | WRAPPER_NO_CONTRACT; |
1221 | Wrapper<VARIANT*, ::DoNothing<VARIANT*>, RecordVariantRelease, NULL>::operator=(p); |
1222 | } |
1223 | }; |
1224 | #endif // FEATURE_COMINTEROP |
1225 | |
1226 | /* ------------------------------------------------------------------------- * |
1227 | * Boolean marshaling routines |
1228 | * ------------------------------------------------------------------------- */ |
1229 | |
1230 | #ifdef FEATURE_COMINTEROP |
1231 | |
1232 | void OleVariant::MarshalBoolVariantOleToCom(VARIANT *pOleVariant, |
1233 | VariantData *pComVariant) |
1234 | { |
1235 | CONTRACTL |
1236 | { |
1237 | NOTHROW; |
1238 | GC_NOTRIGGER; |
1239 | MODE_ANY; |
1240 | PRECONDITION(CheckPointer(pComVariant)); |
1241 | PRECONDITION(CheckPointer(pOleVariant)); |
1242 | } |
1243 | CONTRACTL_END; |
1244 | |
1245 | *(INT64*)pComVariant->GetData() = V_BOOL(pOleVariant) ? 1 : 0; |
1246 | } |
1247 | |
1248 | #endif // FEATURE_COMINTEROP |
1249 | |
1250 | void OleVariant::MarshalBoolArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray, |
1251 | MethodTable *pInterfaceMT) |
1252 | { |
1253 | CONTRACTL |
1254 | { |
1255 | NOTHROW; |
1256 | GC_NOTRIGGER; |
1257 | MODE_COOPERATIVE; |
1258 | PRECONDITION(CheckPointer(oleArray)); |
1259 | PRECONDITION(CheckPointer(pComArray)); |
1260 | } |
1261 | CONTRACTL_END; |
1262 | |
1263 | ASSERT_PROTECTED(pComArray); |
1264 | |
1265 | SIZE_T elementCount = (*pComArray)->GetNumComponents(); |
1266 | |
1267 | VARIANT_BOOL *pOle = (VARIANT_BOOL *) oleArray; |
1268 | VARIANT_BOOL *pOleEnd = pOle + elementCount; |
1269 | |
1270 | UCHAR *pCom = (UCHAR *) (*pComArray)->GetDataPtr(); |
1271 | |
1272 | while (pOle < pOleEnd) |
1273 | { |
1274 | static_assert_no_msg(sizeof(VARIANT_BOOL) == sizeof(UINT16)); |
1275 | (*(pCom++)) = MAYBE_UNALIGNED_READ(pOle, 16) ? 1 : 0; |
1276 | pOle++; |
1277 | } |
1278 | } |
1279 | |
1280 | void OleVariant::MarshalBoolArrayComToOle(BASEARRAYREF *pComArray, void *oleArray, |
1281 | MethodTable *pInterfaceMT, BOOL fBestFitMapping, |
1282 | BOOL fThrowOnUnmappableChar, |
1283 | BOOL fOleArrayIsValid, SIZE_T cElements) |
1284 | { |
1285 | CONTRACTL |
1286 | { |
1287 | NOTHROW; |
1288 | GC_NOTRIGGER; |
1289 | MODE_COOPERATIVE; |
1290 | PRECONDITION(CheckPointer(oleArray)); |
1291 | PRECONDITION(CheckPointer(pComArray)); |
1292 | } |
1293 | CONTRACTL_END; |
1294 | |
1295 | ASSERT_PROTECTED(pComArray); |
1296 | |
1297 | VARIANT_BOOL *pOle = (VARIANT_BOOL *) oleArray; |
1298 | VARIANT_BOOL *pOleEnd = pOle + cElements; |
1299 | |
1300 | UCHAR *pCom = (UCHAR *) (*pComArray)->GetDataPtr(); |
1301 | |
1302 | while (pOle < pOleEnd) |
1303 | { |
1304 | static_assert_no_msg(sizeof(VARIANT_BOOL) == sizeof(UINT16)); |
1305 | MAYBE_UNALIGNED_WRITE(pOle, 16, *pCom ? VARIANT_TRUE : VARIANT_FALSE); |
1306 | pOle++; pCom++; |
1307 | } |
1308 | } |
1309 | |
1310 | /* ------------------------------------------------------------------------- * |
1311 | * WinBoolean marshaling routines |
1312 | * ------------------------------------------------------------------------- */ |
1313 | |
1314 | #ifdef FEATURE_COMINTEROP |
1315 | void OleVariant::MarshalWinBoolVariantOleToCom(VARIANT *pOleVariant, |
1316 | VariantData *pComVariant) |
1317 | { |
1318 | LIMITED_METHOD_CONTRACT; |
1319 | |
1320 | _ASSERTE(!"Not supposed to get here." ); |
1321 | } |
1322 | |
1323 | void OleVariant::MarshalWinBoolVariantComToOle(VariantData *pComVariant, |
1324 | VARIANT *pOleVariant) |
1325 | { |
1326 | LIMITED_METHOD_CONTRACT; |
1327 | |
1328 | _ASSERTE(!"Not supposed to get here." ); |
1329 | } |
1330 | |
1331 | void OleVariant::MarshalWinBoolVariantOleRefToCom(VARIANT *pOleVariant, |
1332 | VariantData *pComVariant) |
1333 | { |
1334 | LIMITED_METHOD_CONTRACT; |
1335 | |
1336 | _ASSERTE(!"Not supposed to get here." ); |
1337 | } |
1338 | #endif // FEATURE_COMINTEROP |
1339 | |
1340 | void OleVariant::MarshalWinBoolArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray, |
1341 | MethodTable *pInterfaceMT) |
1342 | { |
1343 | CONTRACTL |
1344 | { |
1345 | NOTHROW; |
1346 | GC_NOTRIGGER; |
1347 | MODE_COOPERATIVE; |
1348 | PRECONDITION(CheckPointer(oleArray)); |
1349 | PRECONDITION(CheckPointer(pComArray)); |
1350 | } |
1351 | CONTRACTL_END; |
1352 | |
1353 | ASSERT_PROTECTED(pComArray); |
1354 | |
1355 | SIZE_T elementCount = (*pComArray)->GetNumComponents(); |
1356 | |
1357 | BOOL *pOle = (BOOL *) oleArray; |
1358 | BOOL *pOleEnd = pOle + elementCount; |
1359 | |
1360 | UCHAR *pCom = (UCHAR *) (*pComArray)->GetDataPtr(); |
1361 | |
1362 | while (pOle < pOleEnd) |
1363 | { |
1364 | static_assert_no_msg(sizeof(BOOL) == sizeof(UINT32)); |
1365 | (*(pCom++)) = MAYBE_UNALIGNED_READ(pOle, 32) ? 1 : 0; |
1366 | pOle++; |
1367 | } |
1368 | } |
1369 | |
1370 | void OleVariant::MarshalWinBoolArrayComToOle(BASEARRAYREF *pComArray, void *oleArray, |
1371 | MethodTable *pInterfaceMT, BOOL fBestFitMapping, |
1372 | BOOL fThrowOnUnmappableChar, |
1373 | BOOL fOleArrayIsValid, SIZE_T cElements) |
1374 | { |
1375 | CONTRACTL |
1376 | { |
1377 | NOTHROW; |
1378 | GC_NOTRIGGER; |
1379 | MODE_COOPERATIVE; |
1380 | PRECONDITION(CheckPointer(oleArray)); |
1381 | PRECONDITION(CheckPointer(pComArray)); |
1382 | } |
1383 | CONTRACTL_END; |
1384 | |
1385 | ASSERT_PROTECTED(pComArray); |
1386 | |
1387 | BOOL *pOle = (BOOL *) oleArray; |
1388 | BOOL *pOleEnd = pOle + cElements; |
1389 | |
1390 | UCHAR *pCom = (UCHAR *) (*pComArray)->GetDataPtr(); |
1391 | |
1392 | while (pOle < pOleEnd) |
1393 | { |
1394 | static_assert_no_msg(sizeof(BOOL) == sizeof(UINT32)); |
1395 | MAYBE_UNALIGNED_WRITE(pOle, 32, *pCom ? 1 : 0); |
1396 | pOle++; pCom++; |
1397 | } |
1398 | } |
1399 | |
1400 | /* ------------------------------------------------------------------------- * |
1401 | * CBool marshaling routines |
1402 | * ------------------------------------------------------------------------- */ |
1403 | |
1404 | #ifdef FEATURE_COMINTEROP |
1405 | void OleVariant::MarshalCBoolVariantOleToCom(VARIANT* pOleVariant, VariantData* pComVariant) |
1406 | { |
1407 | LIMITED_METHOD_CONTRACT; |
1408 | |
1409 | _ASSERTE(!"Not supposed to get here." ); |
1410 | } |
1411 | |
1412 | void OleVariant::MarshalCBoolVariantComToOle(VariantData* pComVariant, VARIANT* pOleVariant) |
1413 | { |
1414 | LIMITED_METHOD_CONTRACT; |
1415 | |
1416 | _ASSERTE(!"Not supposed to get here." ); |
1417 | } |
1418 | |
1419 | void OleVariant::MarshalCBoolVariantOleRefToCom(VARIANT* pOleVariant, VariantData* pComVariant) |
1420 | { |
1421 | LIMITED_METHOD_CONTRACT; |
1422 | |
1423 | _ASSERTE(!"Not supposed to get here." ); |
1424 | } |
1425 | #endif // FEATURE_COMINTEROP |
1426 | |
1427 | void OleVariant::MarshalCBoolArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray, |
1428 | MethodTable* pInterfaceMT) |
1429 | { |
1430 | LIMITED_METHOD_CONTRACT; |
1431 | |
1432 | CONTRACTL |
1433 | { |
1434 | NOTHROW; |
1435 | GC_NOTRIGGER; |
1436 | MODE_COOPERATIVE; |
1437 | PRECONDITION(CheckPointer(oleArray)); |
1438 | PRECONDITION(CheckPointer(pComArray)); |
1439 | } |
1440 | CONTRACTL_END; |
1441 | |
1442 | ASSERT_PROTECTED(pComArray); |
1443 | |
1444 | _ASSERTE((*pComArray)->GetArrayElementType() == ELEMENT_TYPE_BOOLEAN); |
1445 | |
1446 | SIZE_T cbArray = (*pComArray)->GetNumComponents(); |
1447 | |
1448 | BYTE *pOle = (BYTE *) oleArray; |
1449 | BYTE *pOleEnd = pOle + cbArray; |
1450 | |
1451 | UCHAR *pCom = (UCHAR *) (*pComArray)->GetDataPtr(); |
1452 | |
1453 | while (pOle < pOleEnd) |
1454 | { |
1455 | (*pCom) = (*pOle ? 1 : 0); |
1456 | pOle++; pCom++; |
1457 | } |
1458 | } |
1459 | |
1460 | void OleVariant::MarshalCBoolArrayComToOle(BASEARRAYREF* pComArray, void* oleArray, |
1461 | MethodTable* pInterfaceMT, BOOL fBestFitMapping, |
1462 | BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid, |
1463 | SIZE_T cElements) |
1464 | { |
1465 | LIMITED_METHOD_CONTRACT; |
1466 | |
1467 | CONTRACTL |
1468 | { |
1469 | NOTHROW; |
1470 | GC_NOTRIGGER; |
1471 | MODE_COOPERATIVE; |
1472 | PRECONDITION(CheckPointer(oleArray)); |
1473 | PRECONDITION(CheckPointer(pComArray)); |
1474 | } |
1475 | CONTRACTL_END; |
1476 | |
1477 | ASSERT_PROTECTED(pComArray); |
1478 | |
1479 | _ASSERTE((*pComArray)->GetArrayElementType() == ELEMENT_TYPE_BOOLEAN); |
1480 | |
1481 | BYTE *pOle = (BYTE *) oleArray; |
1482 | BYTE *pOleEnd = pOle + cElements; |
1483 | |
1484 | UCHAR *pCom = (UCHAR *) (*pComArray)->GetDataPtr(); |
1485 | |
1486 | while (pOle < pOleEnd) |
1487 | { |
1488 | *pOle = (*pCom ? 1 : 0); |
1489 | pOle++; pCom++; |
1490 | } |
1491 | } |
1492 | |
1493 | /* ------------------------------------------------------------------------- * |
1494 | * Ansi char marshaling routines |
1495 | * ------------------------------------------------------------------------- */ |
1496 | |
1497 | #ifdef FEATURE_COMINTEROP |
1498 | void OleVariant::MarshalAnsiCharVariantOleToCom(VARIANT *pOleVariant, |
1499 | VariantData *pComVariant) |
1500 | { |
1501 | LIMITED_METHOD_CONTRACT; |
1502 | |
1503 | _ASSERTE(!"Not supposed to get here." ); |
1504 | } |
1505 | |
1506 | void OleVariant::MarshalAnsiCharVariantComToOle(VariantData *pComVariant, |
1507 | VARIANT *pOleVariant) |
1508 | { |
1509 | LIMITED_METHOD_CONTRACT; |
1510 | |
1511 | _ASSERTE(!"Not supposed to get here." ); |
1512 | } |
1513 | |
1514 | void OleVariant::MarshalAnsiCharVariantOleRefToCom(VARIANT *pOleVariant, |
1515 | VariantData *pComVariant) |
1516 | { |
1517 | LIMITED_METHOD_CONTRACT; |
1518 | |
1519 | _ASSERTE(!"Not supposed to get here." ); |
1520 | } |
1521 | #endif // FEATURE_COMINTEROP |
1522 | |
1523 | void OleVariant::MarshalAnsiCharArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray, |
1524 | MethodTable *pInterfaceMT) |
1525 | { |
1526 | CONTRACTL |
1527 | { |
1528 | THROWS; |
1529 | GC_NOTRIGGER; |
1530 | MODE_COOPERATIVE; |
1531 | PRECONDITION(CheckPointer(oleArray)); |
1532 | PRECONDITION(CheckPointer(pComArray)); |
1533 | } |
1534 | CONTRACTL_END; |
1535 | |
1536 | ASSERT_PROTECTED(pComArray); |
1537 | |
1538 | SIZE_T elementCount = (*pComArray)->GetNumComponents(); |
1539 | |
1540 | WCHAR *pCom = (WCHAR *) (*pComArray)->GetDataPtr(); |
1541 | |
1542 | if (0 == elementCount) |
1543 | { |
1544 | *pCom = '\0'; |
1545 | return; |
1546 | } |
1547 | |
1548 | if (0 == MultiByteToWideChar(CP_ACP, |
1549 | MB_PRECOMPOSED, |
1550 | (const CHAR *)oleArray, |
1551 | (int)elementCount, |
1552 | pCom, |
1553 | (int)elementCount)) |
1554 | { |
1555 | COMPlusThrowWin32(); |
1556 | } |
1557 | } |
1558 | |
1559 | void OleVariant::MarshalAnsiCharArrayComToOle(BASEARRAYREF *pComArray, void *oleArray, |
1560 | MethodTable *pInterfaceMT, BOOL fBestFitMapping, |
1561 | BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid, |
1562 | SIZE_T cElements) |
1563 | { |
1564 | CONTRACTL |
1565 | { |
1566 | THROWS; |
1567 | GC_TRIGGERS; |
1568 | MODE_COOPERATIVE; |
1569 | PRECONDITION(CheckPointer(oleArray)); |
1570 | PRECONDITION(CheckPointer(pComArray)); |
1571 | } |
1572 | CONTRACTL_END; |
1573 | |
1574 | const WCHAR *pCom = (const WCHAR *) (*pComArray)->GetDataPtr(); |
1575 | |
1576 | if (!FitsIn<int>(cElements)) |
1577 | COMPlusThrowHR(COR_E_OVERFLOW); |
1578 | |
1579 | int cchCount = (int)cElements; |
1580 | int cbBuffer; |
1581 | |
1582 | if (!ClrSafeInt<int>::multiply(cchCount, GetMaxDBCSCharByteSize(), cbBuffer)) |
1583 | COMPlusThrowHR(COR_E_OVERFLOW); |
1584 | |
1585 | InternalWideToAnsi((WCHAR*)pCom, cchCount, (CHAR*)oleArray, cbBuffer, |
1586 | fBestFitMapping, fThrowOnUnmappableChar); |
1587 | } |
1588 | |
1589 | /* ------------------------------------------------------------------------- * |
1590 | * Interface marshaling routines |
1591 | * ------------------------------------------------------------------------- */ |
1592 | |
1593 | #ifdef FEATURE_COMINTEROP |
1594 | void OleVariant::MarshalInterfaceVariantOleToCom(VARIANT *pOleVariant, |
1595 | VariantData *pComVariant) |
1596 | { |
1597 | CONTRACTL |
1598 | { |
1599 | THROWS; |
1600 | GC_TRIGGERS; |
1601 | MODE_COOPERATIVE; |
1602 | PRECONDITION(CheckPointer(pOleVariant)); |
1603 | PRECONDITION(CheckPointer(pComVariant)); |
1604 | } |
1605 | CONTRACTL_END; |
1606 | |
1607 | IUnknown *unk = V_UNKNOWN(pOleVariant); |
1608 | |
1609 | OBJECTREF obj = NULL; |
1610 | if (unk != NULL) |
1611 | { |
1612 | GCPROTECT_BEGIN(obj); |
1613 | GetObjectRefFromComIP(&obj, V_UNKNOWN(pOleVariant)); |
1614 | GCPROTECT_END(); |
1615 | } |
1616 | |
1617 | pComVariant->SetObjRef(obj); |
1618 | } |
1619 | |
1620 | void OleVariant::MarshalInterfaceVariantComToOle(VariantData *pComVariant, |
1621 | VARIANT *pOleVariant) |
1622 | |
1623 | { |
1624 | CONTRACTL |
1625 | { |
1626 | THROWS; |
1627 | GC_TRIGGERS; |
1628 | MODE_COOPERATIVE; |
1629 | PRECONDITION(CheckPointer(pOleVariant)); |
1630 | PRECONDITION(CheckPointer(pComVariant)); |
1631 | } |
1632 | CONTRACTL_END; |
1633 | |
1634 | OBJECTREF *obj = pComVariant->GetObjRefPtr(); |
1635 | VARTYPE vt = pComVariant->GetVT(); |
1636 | |
1637 | ASSERT_PROTECTED(obj); |
1638 | |
1639 | if (*obj == NULL) |
1640 | { |
1641 | // If there is no VT set in the managed variant, then default to VT_UNKNOWN. |
1642 | if (vt == VT_EMPTY) |
1643 | vt = VT_UNKNOWN; |
1644 | |
1645 | V_UNKNOWN(pOleVariant) = NULL; |
1646 | V_VT(pOleVariant) = vt; |
1647 | } |
1648 | else |
1649 | { |
1650 | #ifdef FEATURE_COMINTEROP |
1651 | ComIpType FetchedIpType = ComIpType_None; |
1652 | ComIpType ReqIpType; |
1653 | |
1654 | if (vt != VT_EMPTY) |
1655 | { |
1656 | // We are dealing with an UnknownWrapper or DispatchWrapper. |
1657 | // In this case, we need to respect the VT. |
1658 | _ASSERTE(vt == VT_DISPATCH || vt == VT_UNKNOWN); |
1659 | ReqIpType = vt == VT_DISPATCH ? ComIpType_Dispatch : ComIpType_Unknown; |
1660 | } |
1661 | else |
1662 | { |
1663 | // We are dealing with a normal object so we can give either |
1664 | // IDispatch or IUnknown out depending on what it supports. |
1665 | ReqIpType = ComIpType_Both; |
1666 | } |
1667 | |
1668 | IUnknown *unk = GetComIPFromObjectRef(obj, ReqIpType, &FetchedIpType); |
1669 | BOOL ItfIsDispatch = FetchedIpType == ComIpType_Dispatch; |
1670 | |
1671 | V_UNKNOWN(pOleVariant) = unk; |
1672 | V_VT(pOleVariant) = static_cast<VARTYPE>(ItfIsDispatch ? VT_DISPATCH : VT_UNKNOWN); |
1673 | #else // FEATURE_COMINTEROP |
1674 | V_UNKNOWN(pOleVariant) = GetComIPFromObjectRef(obj); |
1675 | V_VT(pOleVariant) = VT_UNKNOWN; |
1676 | #endif // FEATURE_COMINTEROP |
1677 | } |
1678 | } |
1679 | |
1680 | void OleVariant::MarshalInterfaceVariantOleRefToCom(VARIANT *pOleVariant, |
1681 | VariantData *pComVariant) |
1682 | { |
1683 | CONTRACTL |
1684 | { |
1685 | THROWS; |
1686 | GC_TRIGGERS; |
1687 | MODE_COOPERATIVE; |
1688 | PRECONDITION(CheckPointer(pOleVariant)); |
1689 | PRECONDITION(CheckPointer(pComVariant)); |
1690 | } |
1691 | CONTRACTL_END; |
1692 | |
1693 | IUnknown *unk = V_UNKNOWN(pOleVariant); |
1694 | |
1695 | OBJECTREF obj = NULL; |
1696 | if (unk != NULL) |
1697 | { |
1698 | GCPROTECT_BEGIN(obj); |
1699 | GetObjectRefFromComIP(&obj, *V_UNKNOWNREF(pOleVariant)); |
1700 | GCPROTECT_END(); |
1701 | } |
1702 | |
1703 | pComVariant->SetObjRef(obj); |
1704 | } |
1705 | |
1706 | void OleVariant::MarshalInterfaceArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray, |
1707 | MethodTable *pElementMT) |
1708 | { |
1709 | CONTRACTL |
1710 | { |
1711 | THROWS; |
1712 | GC_TRIGGERS; |
1713 | MODE_COOPERATIVE; |
1714 | PRECONDITION(CheckPointer(oleArray)); |
1715 | PRECONDITION(CheckPointer(pComArray)); |
1716 | } |
1717 | CONTRACTL_END; |
1718 | |
1719 | ASSERT_PROTECTED(pComArray); |
1720 | |
1721 | SIZE_T elementCount = (*pComArray)->GetNumComponents(); |
1722 | |
1723 | IUnknown **pOle = (IUnknown **) oleArray; |
1724 | IUnknown **pOleEnd = pOle + elementCount; |
1725 | |
1726 | BASEARRAYREF unprotectedArray = *pComArray; |
1727 | OBJECTREF *pCom = (OBJECTREF *) unprotectedArray->GetDataPtr(); |
1728 | |
1729 | OBJECTREF obj = NULL; |
1730 | GCPROTECT_BEGIN(obj) |
1731 | { |
1732 | while (pOle < pOleEnd) |
1733 | { |
1734 | IUnknown *unk = *pOle++; |
1735 | |
1736 | if (unk == NULL) |
1737 | obj = NULL; |
1738 | else |
1739 | GetObjectRefFromComIP(&obj, unk); |
1740 | |
1741 | // |
1742 | // Make sure the object can be cast to the destination type. |
1743 | // |
1744 | |
1745 | if (pElementMT != NULL && !CanCastComObject(obj, pElementMT)) |
1746 | { |
1747 | StackSString ssObjClsName; |
1748 | StackSString ssDestClsName; |
1749 | obj->GetMethodTable()->_GetFullyQualifiedNameForClass(ssObjClsName); |
1750 | pElementMT->_GetFullyQualifiedNameForClass(ssDestClsName); |
1751 | COMPlusThrow(kInvalidCastException, IDS_EE_CANNOTCAST, |
1752 | ssObjClsName.GetUnicode(), ssDestClsName.GetUnicode()); |
1753 | } |
1754 | |
1755 | // |
1756 | // Reset pCom pointer only if array object has moved, rather than |
1757 | // recomputing every time through the loop. Beware implicit calls to |
1758 | // ValidateObject inside OBJECTREF methods. |
1759 | // |
1760 | |
1761 | if (*(void **)&unprotectedArray != *(void **)&*pComArray) |
1762 | { |
1763 | SIZE_T currentOffset = ((BYTE *)pCom) - (*(Object **) &unprotectedArray)->GetAddress(); |
1764 | unprotectedArray = *pComArray; |
1765 | pCom = (OBJECTREF *) (unprotectedArray->GetAddress() + currentOffset); |
1766 | } |
1767 | |
1768 | SetObjectReference(pCom++, obj, pDomain); |
1769 | } |
1770 | } |
1771 | GCPROTECT_END(); |
1772 | } |
1773 | |
1774 | void OleVariant::MarshalIUnknownArrayComToOle(BASEARRAYREF *pComArray, void *oleArray, |
1775 | MethodTable *pElementMT, BOOL fBestFitMapping, |
1776 | BOOL fThrowOnUnmappableChar, |
1777 | BOOL fOleArrayIsValid, SIZE_T cElements) |
1778 | { |
1779 | WRAPPER_NO_CONTRACT; |
1780 | |
1781 | MarshalInterfaceArrayComToOleHelper(pComArray, oleArray, pElementMT, FALSE, cElements); |
1782 | } |
1783 | |
1784 | void OleVariant::ClearInterfaceArray(void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT) |
1785 | { |
1786 | CONTRACTL |
1787 | { |
1788 | NOTHROW; |
1789 | GC_TRIGGERS; |
1790 | MODE_ANY; |
1791 | PRECONDITION(CheckPointer(oleArray)); |
1792 | } |
1793 | CONTRACTL_END; |
1794 | |
1795 | IUnknown **pOle = (IUnknown **) oleArray; |
1796 | IUnknown **pOleEnd = pOle + cElements; |
1797 | |
1798 | GCX_PREEMP(); |
1799 | while (pOle < pOleEnd) |
1800 | { |
1801 | IUnknown *pUnk = *pOle++; |
1802 | |
1803 | if (pUnk != NULL) |
1804 | { |
1805 | ULONG cbRef = SafeReleasePreemp(pUnk); |
1806 | LogInteropRelease(pUnk, cbRef, "VariantClearInterfacArray" ); |
1807 | } |
1808 | } |
1809 | } |
1810 | |
1811 | |
1812 | /* ------------------------------------------------------------------------- * |
1813 | * BSTR marshaling routines |
1814 | * ------------------------------------------------------------------------- */ |
1815 | |
1816 | void OleVariant::MarshalBSTRVariantOleToCom(VARIANT *pOleVariant, |
1817 | VariantData *pComVariant) |
1818 | { |
1819 | CONTRACTL |
1820 | { |
1821 | WRAPPER(THROWS); |
1822 | WRAPPER(GC_TRIGGERS); |
1823 | MODE_COOPERATIVE; |
1824 | INJECT_FAULT(COMPlusThrowOM()); |
1825 | PRECONDITION(CheckPointer(pOleVariant)); |
1826 | PRECONDITION(CheckPointer(pComVariant)); |
1827 | } |
1828 | CONTRACTL_END; |
1829 | |
1830 | BSTR bstr = V_BSTR(pOleVariant); |
1831 | |
1832 | STRINGREF stringObj = NULL; |
1833 | GCPROTECT_BEGIN(stringObj) |
1834 | { |
1835 | ConvertBSTRToString(bstr, &stringObj); |
1836 | pComVariant->SetObjRef((OBJECTREF) stringObj); |
1837 | } |
1838 | GCPROTECT_END(); |
1839 | |
1840 | pComVariant->SetObjRef((OBJECTREF) stringObj); |
1841 | } |
1842 | |
1843 | void OleVariant::MarshalBSTRVariantComToOle(VariantData *pComVariant, |
1844 | VARIANT *pOleVariant) |
1845 | { |
1846 | CONTRACTL |
1847 | { |
1848 | THROWS; |
1849 | WRAPPER(GC_TRIGGERS); |
1850 | MODE_COOPERATIVE; |
1851 | INJECT_FAULT(COMPlusThrowOM()); |
1852 | PRECONDITION(CheckPointer(pOleVariant)); |
1853 | PRECONDITION(CheckPointer(pComVariant)); |
1854 | } |
1855 | CONTRACTL_END; |
1856 | |
1857 | STRINGREF stringObj = (STRINGREF) pComVariant->GetObjRef(); |
1858 | GCPROTECT_BEGIN(stringObj) |
1859 | { |
1860 | V_BSTR(pOleVariant) = ConvertStringToBSTR(&stringObj); |
1861 | } |
1862 | GCPROTECT_END(); |
1863 | } |
1864 | |
1865 | void OleVariant::MarshalBSTRArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray, |
1866 | MethodTable *pInterfaceMT) |
1867 | { |
1868 | CONTRACTL |
1869 | { |
1870 | WRAPPER(THROWS); |
1871 | WRAPPER(GC_TRIGGERS); |
1872 | MODE_COOPERATIVE; |
1873 | INJECT_FAULT(COMPlusThrowOM()); |
1874 | PRECONDITION(CheckPointer(oleArray)); |
1875 | PRECONDITION(CheckPointer(pComArray)); |
1876 | } |
1877 | CONTRACTL_END; |
1878 | |
1879 | STRINGREF stringObj = NULL; |
1880 | GCPROTECT_BEGIN(stringObj) |
1881 | { |
1882 | ASSERT_PROTECTED(pComArray); |
1883 | SIZE_T elementCount = (*pComArray)->GetNumComponents(); |
1884 | |
1885 | BSTR *pOle = (BSTR *) oleArray; |
1886 | BSTR *pOleEnd = pOle + elementCount; |
1887 | |
1888 | BASEARRAYREF unprotectedArray = *pComArray; |
1889 | STRINGREF *pCom = (STRINGREF *) unprotectedArray->GetDataPtr(); |
1890 | |
1891 | while (pOle < pOleEnd) |
1892 | { |
1893 | BSTR bstr = *pOle++; |
1894 | |
1895 | ConvertBSTRToString(bstr, &stringObj); |
1896 | |
1897 | // |
1898 | // Reset pCom pointer only if array object has moved, rather than |
1899 | // recomputing it every time through the loop. Beware implicit calls to |
1900 | // ValidateObject inside OBJECTREF methods. |
1901 | // |
1902 | |
1903 | if (*(void **)&unprotectedArray != *(void **)&*pComArray) |
1904 | { |
1905 | SIZE_T currentOffset = ((BYTE *)pCom) - (*(Object **) &unprotectedArray)->GetAddress(); |
1906 | unprotectedArray = *pComArray; |
1907 | pCom = (STRINGREF *) (unprotectedArray->GetAddress() + currentOffset); |
1908 | } |
1909 | |
1910 | SetObjectReference((OBJECTREF*) pCom++, (OBJECTREF) stringObj, pDomain); |
1911 | } |
1912 | } |
1913 | GCPROTECT_END(); |
1914 | } |
1915 | |
1916 | void OleVariant::MarshalBSTRArrayComToOle(BASEARRAYREF *pComArray, void *oleArray, |
1917 | MethodTable *pInterfaceMT, BOOL fBestFitMapping, |
1918 | BOOL fThrowOnUnmappableChar, |
1919 | BOOL fOleArrayIsValid, SIZE_T cElements) |
1920 | { |
1921 | CONTRACTL |
1922 | { |
1923 | THROWS; |
1924 | WRAPPER(GC_TRIGGERS); |
1925 | MODE_COOPERATIVE; |
1926 | INJECT_FAULT(COMPlusThrowOM()); |
1927 | PRECONDITION(CheckPointer(oleArray)); |
1928 | PRECONDITION(CheckPointer(pComArray)); |
1929 | } |
1930 | CONTRACTL_END; |
1931 | |
1932 | STRINGREF stringObj = NULL; |
1933 | GCPROTECT_BEGIN(stringObj) |
1934 | { |
1935 | ASSERT_PROTECTED(pComArray); |
1936 | |
1937 | BSTR *pOle = (BSTR *) oleArray; |
1938 | BSTR *pOleEnd = pOle + cElements; |
1939 | |
1940 | STRINGREF *pCom = (STRINGREF *) (*pComArray)->GetDataPtr(); |
1941 | |
1942 | while (pOle < pOleEnd) |
1943 | { |
1944 | stringObj = *pCom++; |
1945 | BSTR bstr = ConvertStringToBSTR(&stringObj); |
1946 | |
1947 | // |
1948 | // We aren't calling anything which might cause a GC, so don't worry about |
1949 | // the array moving here. |
1950 | // |
1951 | |
1952 | *pOle++ = bstr; |
1953 | } |
1954 | } |
1955 | GCPROTECT_END(); |
1956 | } |
1957 | |
1958 | void OleVariant::ClearBSTRArray(void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT) |
1959 | { |
1960 | CONTRACTL |
1961 | { |
1962 | NOTHROW; |
1963 | GC_TRIGGERS; |
1964 | MODE_ANY; |
1965 | PRECONDITION(CheckPointer(oleArray)); |
1966 | } |
1967 | CONTRACTL_END; |
1968 | |
1969 | BSTR *pOle = (BSTR *) oleArray; |
1970 | BSTR *pOleEnd = pOle + cElements; |
1971 | |
1972 | while (pOle < pOleEnd) |
1973 | { |
1974 | BSTR bstr = *pOle++; |
1975 | |
1976 | if (bstr != NULL) |
1977 | SysFreeString(bstr); |
1978 | } |
1979 | } |
1980 | #endif // FEATURE_COMINTEROP |
1981 | |
1982 | |
1983 | |
1984 | /* ------------------------------------------------------------------------- * |
1985 | * Structure marshaling routines |
1986 | * ------------------------------------------------------------------------- */ |
1987 | void OleVariant::MarshalNonBlittableRecordArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray, |
1988 | MethodTable *pInterfaceMT) |
1989 | { |
1990 | CONTRACTL |
1991 | { |
1992 | THROWS; |
1993 | GC_TRIGGERS; |
1994 | MODE_COOPERATIVE; |
1995 | PRECONDITION(CheckPointer(oleArray)); |
1996 | PRECONDITION(CheckPointer(pComArray)); |
1997 | PRECONDITION(CheckPointer(pInterfaceMT)); |
1998 | } |
1999 | CONTRACTL_END; |
2000 | |
2001 | ASSERT_PROTECTED(pComArray); |
2002 | SIZE_T elementCount = (*pComArray)->GetNumComponents(); |
2003 | SIZE_T elemSize = pInterfaceMT->GetNativeSize(); |
2004 | |
2005 | BYTE *pOle = (BYTE *) oleArray; |
2006 | BYTE *pOleEnd = pOle + elemSize * elementCount; |
2007 | |
2008 | SIZE_T dstofs = ArrayBase::GetDataPtrOffset( (*pComArray)->GetMethodTable() ); |
2009 | while (pOle < pOleEnd) |
2010 | { |
2011 | LayoutUpdateCLR( (LPVOID*)pComArray, dstofs, pInterfaceMT, pOle ); |
2012 | dstofs += (*pComArray)->GetComponentSize(); |
2013 | pOle += elemSize; |
2014 | } |
2015 | } |
2016 | |
2017 | void OleVariant::MarshalNonBlittableRecordArrayComToOle(BASEARRAYREF *pComArray, void *oleArray, |
2018 | MethodTable *pInterfaceMT, BOOL fBestFitMapping, |
2019 | BOOL fThrowOnUnmappableChar, |
2020 | BOOL fOleArrayIsValid, SIZE_T cElements) |
2021 | { |
2022 | CONTRACTL |
2023 | { |
2024 | THROWS; |
2025 | GC_TRIGGERS; |
2026 | MODE_COOPERATIVE; |
2027 | PRECONDITION(CheckPointer(oleArray)); |
2028 | PRECONDITION(CheckPointer(pComArray)); |
2029 | PRECONDITION(CheckPointer(pInterfaceMT)); |
2030 | } |
2031 | CONTRACTL_END; |
2032 | |
2033 | ASSERT_PROTECTED(pComArray); |
2034 | |
2035 | SIZE_T elemSize = pInterfaceMT->GetNativeSize(); |
2036 | |
2037 | BYTE *pOle = (BYTE *) oleArray; |
2038 | BYTE *pOleEnd = pOle + elemSize * cElements; |
2039 | |
2040 | if (!fOleArrayIsValid) |
2041 | { |
2042 | // field marshalers assume that the native structure is valid |
2043 | FillMemory(pOle, pOleEnd - pOle, 0); |
2044 | } |
2045 | |
2046 | SIZE_T srcofs = ArrayBase::GetDataPtrOffset( (*pComArray)->GetMethodTable() ); |
2047 | while (pOle < pOleEnd) |
2048 | { |
2049 | LayoutUpdateNative( (LPVOID*)pComArray, srcofs, pInterfaceMT, pOle, NULL ); |
2050 | pOle += elemSize; |
2051 | srcofs += (*pComArray)->GetComponentSize(); |
2052 | } |
2053 | } |
2054 | |
2055 | void OleVariant::ClearNonBlittableRecordArray(void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT) |
2056 | { |
2057 | CONTRACTL |
2058 | { |
2059 | NOTHROW; |
2060 | GC_TRIGGERS; |
2061 | MODE_ANY; |
2062 | PRECONDITION(CheckPointer(oleArray)); |
2063 | PRECONDITION(CheckPointer(pInterfaceMT)); |
2064 | } |
2065 | CONTRACTL_END; |
2066 | |
2067 | SIZE_T elemSize = pInterfaceMT->GetNativeSize(); |
2068 | BYTE *pOle = (BYTE *) oleArray; |
2069 | BYTE *pOleEnd = pOle + elemSize * cElements; |
2070 | while (pOle < pOleEnd) |
2071 | { |
2072 | LayoutDestroyNative(pOle, pInterfaceMT); |
2073 | pOle += elemSize; |
2074 | } |
2075 | } |
2076 | |
2077 | |
2078 | /* ------------------------------------------------------------------------- * |
2079 | * LPWSTR marshaling routines |
2080 | * ------------------------------------------------------------------------- */ |
2081 | |
2082 | void OleVariant::MarshalLPWSTRArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray, |
2083 | MethodTable *pInterfaceMT) |
2084 | { |
2085 | CONTRACTL |
2086 | { |
2087 | THROWS; |
2088 | GC_TRIGGERS; |
2089 | MODE_COOPERATIVE; |
2090 | INJECT_FAULT(COMPlusThrowOM()); |
2091 | PRECONDITION(CheckPointer(oleArray)); |
2092 | PRECONDITION(CheckPointer(pComArray)); |
2093 | } |
2094 | CONTRACTL_END; |
2095 | |
2096 | ASSERT_PROTECTED(pComArray); |
2097 | SIZE_T elementCount = (*pComArray)->GetNumComponents(); |
2098 | |
2099 | LPWSTR *pOle = (LPWSTR *) oleArray; |
2100 | LPWSTR *pOleEnd = pOle + elementCount; |
2101 | |
2102 | BASEARRAYREF unprotectedArray = *pComArray; |
2103 | STRINGREF *pCom = (STRINGREF *) unprotectedArray->GetDataPtr(); |
2104 | |
2105 | while (pOle < pOleEnd) |
2106 | { |
2107 | LPWSTR lpwstr = *pOle++; |
2108 | |
2109 | STRINGREF string; |
2110 | if (lpwstr == NULL) |
2111 | string = NULL; |
2112 | else |
2113 | string = StringObject::NewString(lpwstr); |
2114 | |
2115 | // |
2116 | // Reset pCom pointer only if array object has moved, rather than |
2117 | // recomputing it every time through the loop. Beware implicit calls to |
2118 | // ValidateObject inside OBJECTREF methods. |
2119 | // |
2120 | |
2121 | if (*(void **)&unprotectedArray != *(void **)&*pComArray) |
2122 | { |
2123 | SIZE_T currentOffset = ((BYTE *)pCom) - (*(Object **) &unprotectedArray)->GetAddress(); |
2124 | unprotectedArray = *pComArray; |
2125 | pCom = (STRINGREF *) (unprotectedArray->GetAddress() + currentOffset); |
2126 | } |
2127 | |
2128 | SetObjectReference((OBJECTREF*) pCom++, (OBJECTREF) string, pDomain); |
2129 | } |
2130 | } |
2131 | |
2132 | void OleVariant::MarshalLPWSTRRArrayComToOle(BASEARRAYREF *pComArray, void *oleArray, |
2133 | MethodTable *pInterfaceMT, BOOL fBestFitMapping, |
2134 | BOOL fThrowOnUnmappableChar, |
2135 | BOOL fOleArrayIsValid, SIZE_T cElements) |
2136 | { |
2137 | CONTRACTL |
2138 | { |
2139 | THROWS; |
2140 | GC_TRIGGERS; |
2141 | MODE_COOPERATIVE; |
2142 | INJECT_FAULT(COMPlusThrowOM()); |
2143 | PRECONDITION(CheckPointer(oleArray)); |
2144 | PRECONDITION(CheckPointer(pComArray)); |
2145 | } |
2146 | CONTRACTL_END; |
2147 | |
2148 | ASSERT_PROTECTED(pComArray); |
2149 | |
2150 | LPWSTR *pOle = (LPWSTR *) oleArray; |
2151 | LPWSTR *pOleEnd = pOle + cElements; |
2152 | |
2153 | STRINGREF *pCom = (STRINGREF *) (*pComArray)->GetDataPtr(); |
2154 | |
2155 | while (pOle < pOleEnd) |
2156 | { |
2157 | // |
2158 | // We aren't calling anything which might cause a GC, so don't worry about |
2159 | // the array moving here. |
2160 | // |
2161 | |
2162 | STRINGREF stringRef = *pCom++; |
2163 | |
2164 | LPWSTR lpwstr; |
2165 | if (stringRef == NULL) |
2166 | { |
2167 | lpwstr = NULL; |
2168 | } |
2169 | else |
2170 | { |
2171 | // Retrieve the length of the string. |
2172 | int Length = stringRef->GetStringLength(); |
2173 | int allocLength = (Length + 1) * sizeof(WCHAR); |
2174 | if (allocLength < Length) |
2175 | ThrowOutOfMemory(); |
2176 | |
2177 | // Allocate the string using CoTaskMemAlloc. |
2178 | lpwstr = (LPWSTR)CoTaskMemAlloc(allocLength); |
2179 | if (lpwstr == NULL) |
2180 | ThrowOutOfMemory(); |
2181 | |
2182 | // Copy the COM+ string into the newly allocated LPWSTR. |
2183 | memcpyNoGCRefs(lpwstr, stringRef->GetBuffer(), (Length + 1) * sizeof(WCHAR)); |
2184 | lpwstr[Length] = 0; |
2185 | } |
2186 | |
2187 | *pOle++ = lpwstr; |
2188 | } |
2189 | } |
2190 | |
2191 | void OleVariant::ClearLPWSTRArray(void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT) |
2192 | { |
2193 | CONTRACTL |
2194 | { |
2195 | NOTHROW; |
2196 | GC_NOTRIGGER; |
2197 | MODE_ANY; |
2198 | PRECONDITION(CheckPointer(oleArray)); |
2199 | } |
2200 | CONTRACTL_END; |
2201 | |
2202 | LPWSTR *pOle = (LPWSTR *) oleArray; |
2203 | LPWSTR *pOleEnd = pOle + cElements; |
2204 | |
2205 | while (pOle < pOleEnd) |
2206 | { |
2207 | LPWSTR lpwstr = *pOle++; |
2208 | |
2209 | if (lpwstr != NULL) |
2210 | CoTaskMemFree(lpwstr); |
2211 | } |
2212 | } |
2213 | |
2214 | /* ------------------------------------------------------------------------- * |
2215 | * LPWSTR marshaling routines |
2216 | * ------------------------------------------------------------------------- */ |
2217 | |
2218 | void OleVariant::MarshalLPSTRArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray, |
2219 | MethodTable *pInterfaceMT) |
2220 | { |
2221 | CONTRACTL |
2222 | { |
2223 | THROWS; |
2224 | GC_TRIGGERS; |
2225 | MODE_COOPERATIVE; |
2226 | INJECT_FAULT(COMPlusThrowOM()); |
2227 | PRECONDITION(CheckPointer(oleArray)); |
2228 | PRECONDITION(CheckPointer(pComArray)); |
2229 | } |
2230 | CONTRACTL_END; |
2231 | |
2232 | ASSERT_PROTECTED(pComArray); |
2233 | SIZE_T elementCount = (*pComArray)->GetNumComponents(); |
2234 | |
2235 | LPSTR *pOle = (LPSTR *) oleArray; |
2236 | LPSTR *pOleEnd = pOle + elementCount; |
2237 | |
2238 | BASEARRAYREF unprotectedArray = *pComArray; |
2239 | STRINGREF *pCom = (STRINGREF *) unprotectedArray->GetDataPtr(); |
2240 | |
2241 | while (pOle < pOleEnd) |
2242 | { |
2243 | LPSTR lpstr = *pOle++; |
2244 | |
2245 | STRINGREF string; |
2246 | if (lpstr == NULL) |
2247 | string = NULL; |
2248 | else |
2249 | string = StringObject::NewString(lpstr); |
2250 | |
2251 | // |
2252 | // Reset pCom pointer only if array object has moved, rather than |
2253 | // recomputing it every time through the loop. Beware implicit calls to |
2254 | // ValidateObject inside OBJECTREF methods. |
2255 | // |
2256 | |
2257 | if (*(void **)&unprotectedArray != *(void **)&*pComArray) |
2258 | { |
2259 | SIZE_T currentOffset = ((BYTE *)pCom) - (*(Object **) &unprotectedArray)->GetAddress(); |
2260 | unprotectedArray = *pComArray; |
2261 | pCom = (STRINGREF *) (unprotectedArray->GetAddress() + currentOffset); |
2262 | } |
2263 | |
2264 | SetObjectReference((OBJECTREF*) pCom++, (OBJECTREF) string, pDomain); |
2265 | } |
2266 | } |
2267 | |
2268 | void OleVariant::MarshalLPSTRRArrayComToOle(BASEARRAYREF *pComArray, void *oleArray, |
2269 | MethodTable *pInterfaceMT, BOOL fBestFitMapping, |
2270 | BOOL fThrowOnUnmappableChar, |
2271 | BOOL fOleArrayIsValid, SIZE_T cElements) |
2272 | { |
2273 | CONTRACTL |
2274 | { |
2275 | THROWS; |
2276 | GC_TRIGGERS; |
2277 | MODE_COOPERATIVE; |
2278 | INJECT_FAULT(COMPlusThrowOM()); |
2279 | PRECONDITION(CheckPointer(oleArray)); |
2280 | PRECONDITION(CheckPointer(pComArray)); |
2281 | } |
2282 | CONTRACTL_END; |
2283 | |
2284 | ASSERT_PROTECTED(pComArray); |
2285 | |
2286 | LPSTR *pOle = (LPSTR *) oleArray; |
2287 | LPSTR *pOleEnd = pOle + cElements; |
2288 | |
2289 | STRINGREF *pCom = (STRINGREF *) (*pComArray)->GetDataPtr(); |
2290 | |
2291 | while (pOle < pOleEnd) |
2292 | { |
2293 | // |
2294 | // We aren't calling anything which might cause a GC, so don't worry about |
2295 | // the array moving here. |
2296 | // |
2297 | STRINGREF stringRef = *pCom++; |
2298 | |
2299 | CoTaskMemHolder<CHAR> lpstr(NULL); |
2300 | if (stringRef == NULL) |
2301 | { |
2302 | lpstr = NULL; |
2303 | } |
2304 | else |
2305 | { |
2306 | // Retrieve the length of the string. |
2307 | int Length = stringRef->GetStringLength(); |
2308 | int allocLength = Length * GetMaxDBCSCharByteSize() + 1; |
2309 | if (allocLength < Length) |
2310 | ThrowOutOfMemory(); |
2311 | |
2312 | // Allocate the string using CoTaskMemAlloc. |
2313 | lpstr = (LPSTR)CoTaskMemAlloc(allocLength); |
2314 | if (lpstr == NULL) |
2315 | ThrowOutOfMemory(); |
2316 | |
2317 | // Convert the unicode string to an ansi string. |
2318 | int bytesWritten = InternalWideToAnsi(stringRef->GetBuffer(), Length, lpstr, allocLength, fBestFitMapping, fThrowOnUnmappableChar); |
2319 | _ASSERTE(bytesWritten >= 0 && bytesWritten < allocLength); |
2320 | lpstr[bytesWritten] = 0; |
2321 | } |
2322 | |
2323 | *pOle++ = lpstr; |
2324 | lpstr.SuppressRelease(); |
2325 | } |
2326 | } |
2327 | |
2328 | void OleVariant::ClearLPSTRArray(void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT) |
2329 | { |
2330 | CONTRACTL |
2331 | { |
2332 | NOTHROW; |
2333 | GC_NOTRIGGER; |
2334 | MODE_ANY; |
2335 | PRECONDITION(CheckPointer(oleArray)); |
2336 | } |
2337 | CONTRACTL_END; |
2338 | |
2339 | LPSTR *pOle = (LPSTR *) oleArray; |
2340 | LPSTR *pOleEnd = pOle + cElements; |
2341 | |
2342 | while (pOle < pOleEnd) |
2343 | { |
2344 | LPSTR lpstr = *pOle++; |
2345 | |
2346 | if (lpstr != NULL) |
2347 | CoTaskMemFree(lpstr); |
2348 | } |
2349 | } |
2350 | |
2351 | /* ------------------------------------------------------------------------- * |
2352 | * Date marshaling routines |
2353 | * ------------------------------------------------------------------------- */ |
2354 | |
2355 | #ifdef FEATURE_COMINTEROP |
2356 | void OleVariant::MarshalDateVariantOleToCom(VARIANT *pOleVariant, |
2357 | VariantData *pComVariant) |
2358 | { |
2359 | WRAPPER_NO_CONTRACT; |
2360 | |
2361 | *(INT64*)pComVariant->GetData() = COMDateTime::DoubleDateToTicks(V_DATE(pOleVariant)); |
2362 | } |
2363 | |
2364 | void OleVariant::MarshalDateVariantComToOle(VariantData *pComVariant, |
2365 | VARIANT *pOleVariant) |
2366 | { |
2367 | WRAPPER_NO_CONTRACT; |
2368 | |
2369 | V_DATE(pOleVariant) = COMDateTime::TicksToDoubleDate(*(INT64*)pComVariant->GetData()); |
2370 | } |
2371 | |
2372 | void OleVariant::MarshalDateVariantOleRefToCom(VARIANT *pOleVariant, |
2373 | VariantData *pComVariant) |
2374 | { |
2375 | WRAPPER_NO_CONTRACT; |
2376 | |
2377 | *(INT64*)pComVariant->GetData() = COMDateTime::DoubleDateToTicks(*V_DATEREF(pOleVariant)); |
2378 | } |
2379 | #endif // FEATURE_COMINTEROP |
2380 | |
2381 | void OleVariant::MarshalDateArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray, |
2382 | MethodTable *pInterfaceMT) |
2383 | { |
2384 | CONTRACTL |
2385 | { |
2386 | THROWS; |
2387 | GC_TRIGGERS; |
2388 | MODE_COOPERATIVE; |
2389 | PRECONDITION(CheckPointer(oleArray)); |
2390 | PRECONDITION(CheckPointer(pComArray)); |
2391 | } |
2392 | CONTRACTL_END; |
2393 | |
2394 | ASSERT_PROTECTED(pComArray); |
2395 | |
2396 | SIZE_T elementCount = (*pComArray)->GetNumComponents(); |
2397 | |
2398 | DATE *pOle = (DATE *) oleArray; |
2399 | DATE *pOleEnd = pOle + elementCount; |
2400 | |
2401 | INT64 *pCom = (INT64 *) (*pComArray)->GetDataPtr(); |
2402 | |
2403 | // |
2404 | // We aren't calling anything which might cause a GC, so don't worry about |
2405 | // the array moving here. |
2406 | // |
2407 | |
2408 | while (pOle < pOleEnd) |
2409 | *pCom++ = COMDateTime::DoubleDateToTicks(*pOle++); |
2410 | } |
2411 | |
2412 | void OleVariant::MarshalDateArrayComToOle(BASEARRAYREF *pComArray, void *oleArray, |
2413 | MethodTable *pInterfaceMT, BOOL fBestFitMapping, |
2414 | BOOL fThrowOnUnmappableChar, |
2415 | BOOL fOleArrayIsValid, SIZE_T cElements) |
2416 | { |
2417 | CONTRACTL |
2418 | { |
2419 | THROWS; |
2420 | GC_TRIGGERS; |
2421 | MODE_COOPERATIVE; |
2422 | PRECONDITION(CheckPointer(oleArray)); |
2423 | PRECONDITION(CheckPointer(pComArray)); |
2424 | } |
2425 | CONTRACTL_END; |
2426 | |
2427 | ASSERT_PROTECTED(pComArray); |
2428 | |
2429 | DATE *pOle = (DATE *) oleArray; |
2430 | DATE *pOleEnd = pOle + cElements; |
2431 | |
2432 | INT64 *pCom = (INT64 *) (*pComArray)->GetDataPtr(); |
2433 | |
2434 | // |
2435 | // We aren't calling anything which might cause a GC, so don't worry about |
2436 | // the array moving here. |
2437 | // |
2438 | |
2439 | while (pOle < pOleEnd) |
2440 | *pOle++ = COMDateTime::TicksToDoubleDate(*pCom++); |
2441 | } |
2442 | |
2443 | /* ------------------------------------------------------------------------- * |
2444 | * Decimal marshaling routines |
2445 | * ------------------------------------------------------------------------- */ |
2446 | |
2447 | #ifdef FEATURE_COMINTEROP |
2448 | |
2449 | void OleVariant::MarshalDecimalVariantOleToCom(VARIANT *pOleVariant, |
2450 | VariantData *pComVariant) |
2451 | { |
2452 | CONTRACTL |
2453 | { |
2454 | THROWS; |
2455 | GC_TRIGGERS; |
2456 | MODE_COOPERATIVE; |
2457 | INJECT_FAULT(COMPlusThrowOM()); |
2458 | PRECONDITION(CheckPointer(pOleVariant)); |
2459 | PRECONDITION(CheckPointer(pComVariant)); |
2460 | } |
2461 | CONTRACTL_END; |
2462 | |
2463 | OBJECTREF pDecimalRef = AllocateObject(MscorlibBinder::GetClass(CLASS__DECIMAL)); |
2464 | |
2465 | DECIMAL* pDecimal = (DECIMAL *) pDecimalRef->UnBox(); |
2466 | *pDecimal = V_DECIMAL(pOleVariant); |
2467 | // Mashaling uses the reserved value to store the variant type, so clear it out when marshaling back |
2468 | pDecimal->wReserved = 0; |
2469 | |
2470 | pComVariant->SetObjRef(pDecimalRef); |
2471 | } |
2472 | |
2473 | void OleVariant::MarshalDecimalVariantComToOle(VariantData *pComVariant, |
2474 | VARIANT *pOleVariant) |
2475 | { |
2476 | CONTRACTL |
2477 | { |
2478 | WRAPPER(THROWS); |
2479 | WRAPPER(GC_TRIGGERS); |
2480 | MODE_COOPERATIVE; |
2481 | PRECONDITION(CheckPointer(pOleVariant)); |
2482 | PRECONDITION(CheckPointer(pComVariant)); |
2483 | } |
2484 | CONTRACTL_END; |
2485 | |
2486 | VARTYPE vt = V_VT(pOleVariant); |
2487 | _ASSERTE(vt == VT_DECIMAL); |
2488 | V_DECIMAL(pOleVariant) = * (DECIMAL*) pComVariant->GetObjRef()->UnBox(); |
2489 | V_VT(pOleVariant) = vt; |
2490 | } |
2491 | |
2492 | void OleVariant::MarshalDecimalVariantOleRefToCom(VARIANT *pOleVariant, |
2493 | VariantData *pComVariant ) |
2494 | { |
2495 | CONTRACTL |
2496 | { |
2497 | THROWS; |
2498 | GC_TRIGGERS; |
2499 | MODE_COOPERATIVE; |
2500 | INJECT_FAULT(COMPlusThrowOM()); |
2501 | PRECONDITION(CheckPointer(pOleVariant)); |
2502 | PRECONDITION(CheckPointer(pComVariant)); |
2503 | } |
2504 | CONTRACTL_END; |
2505 | |
2506 | OBJECTREF pDecimalRef = AllocateObject(MscorlibBinder::GetClass(CLASS__DECIMAL)); |
2507 | |
2508 | DECIMAL* pDecimal = (DECIMAL *) pDecimalRef->UnBox(); |
2509 | *pDecimal = *V_DECIMALREF(pOleVariant); |
2510 | // Mashaling uses the reserved value to store the variant type, so clear it out when marshaling back |
2511 | pDecimal->wReserved = 0; |
2512 | |
2513 | pComVariant->SetObjRef(pDecimalRef); |
2514 | } |
2515 | #endif // FEATURE_COMINTEROP |
2516 | |
2517 | /* ------------------------------------------------------------------------- * |
2518 | * Record marshaling routines |
2519 | * ------------------------------------------------------------------------- */ |
2520 | |
2521 | #ifdef FEATURE_CLASSIC_COMINTEROP |
2522 | void OleVariant::MarshalRecordVariantOleToCom(VARIANT *pOleVariant, |
2523 | VariantData *pComVariant) |
2524 | { |
2525 | CONTRACTL |
2526 | { |
2527 | THROWS; |
2528 | GC_TRIGGERS; |
2529 | MODE_COOPERATIVE; |
2530 | INJECT_FAULT(COMPlusThrowOM()); |
2531 | PRECONDITION(CheckPointer(pOleVariant)); |
2532 | PRECONDITION(CheckPointer(pComVariant)); |
2533 | } |
2534 | CONTRACTL_END; |
2535 | |
2536 | HRESULT hr = S_OK; |
2537 | IRecordInfo *pRecInfo = V_RECORDINFO(pOleVariant); |
2538 | if (!pRecInfo) |
2539 | COMPlusThrow(kArgumentException, IDS_EE_INVALID_OLE_VARIANT); |
2540 | |
2541 | OBJECTREF BoxedValueClass = NULL; |
2542 | GCPROTECT_BEGIN(BoxedValueClass) |
2543 | { |
2544 | LPVOID pvRecord = V_RECORD(pOleVariant); |
2545 | if (pvRecord) |
2546 | { |
2547 | // Go to the registry to find the value class associated |
2548 | // with the record's guid. |
2549 | GUID guid; |
2550 | { |
2551 | GCX_PREEMP(); |
2552 | IfFailThrow(pRecInfo->GetGuid(&guid)); |
2553 | } |
2554 | MethodTable *pValueClass = GetValueTypeForGUID(guid); |
2555 | if (!pValueClass) |
2556 | COMPlusThrow(kArgumentException, IDS_EE_CANNOT_MAP_TO_MANAGED_VC); |
2557 | |
2558 | // Now that we have the value class, allocate an instance of the |
2559 | // boxed value class and copy the contents of the record into it. |
2560 | BoxedValueClass = AllocateObject(pValueClass); |
2561 | FmtClassUpdateCLR(&BoxedValueClass, (BYTE*)pvRecord); |
2562 | } |
2563 | |
2564 | pComVariant->SetObjRef(BoxedValueClass); |
2565 | } |
2566 | GCPROTECT_END(); |
2567 | } |
2568 | |
2569 | void OleVariant::MarshalRecordVariantComToOle(VariantData *pComVariant, |
2570 | VARIANT *pOleVariant) |
2571 | { |
2572 | CONTRACTL |
2573 | { |
2574 | THROWS; |
2575 | GC_TRIGGERS; |
2576 | MODE_COOPERATIVE; |
2577 | PRECONDITION(CheckPointer(pOleVariant)); |
2578 | PRECONDITION(CheckPointer(pComVariant)); |
2579 | } |
2580 | CONTRACTL_END; |
2581 | |
2582 | OBJECTREF BoxedValueClass = pComVariant->GetObjRef(); |
2583 | GCPROTECT_BEGIN(BoxedValueClass) |
2584 | { |
2585 | _ASSERTE(BoxedValueClass != NULL); |
2586 | ConvertValueClassToVariant(&BoxedValueClass, pOleVariant); |
2587 | } |
2588 | GCPROTECT_END(); |
2589 | } |
2590 | |
2591 | void OleVariant::MarshalRecordVariantOleRefToCom(VARIANT *pOleVariant, |
2592 | VariantData *pComVariant) |
2593 | { |
2594 | WRAPPER_NO_CONTRACT; |
2595 | |
2596 | // The representation of a VT_RECORD and a VT_BYREF | VT_RECORD VARIANT are |
2597 | // the same so we can simply forward the call to the non byref API. |
2598 | MarshalRecordVariantOleToCom(pOleVariant, pComVariant); |
2599 | } |
2600 | #endif // FEATURE_CLASSIC_COMINTEROP |
2601 | |
2602 | void OleVariant::MarshalRecordArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray, |
2603 | MethodTable *pElementMT) |
2604 | { |
2605 | CONTRACTL |
2606 | { |
2607 | THROWS; |
2608 | GC_TRIGGERS; |
2609 | MODE_COOPERATIVE; |
2610 | PRECONDITION(CheckPointer(oleArray)); |
2611 | PRECONDITION(CheckPointer(pComArray)); |
2612 | PRECONDITION(CheckPointer(pElementMT)); |
2613 | } |
2614 | CONTRACTL_END; |
2615 | |
2616 | if (pElementMT->IsBlittable()) |
2617 | { |
2618 | // The array is blittable so we can simply copy it. |
2619 | _ASSERTE(pComArray); |
2620 | SIZE_T elementCount = (*pComArray)->GetNumComponents(); |
2621 | SIZE_T elemSize = pElementMT->GetNativeSize(); |
2622 | memcpyNoGCRefs((*pComArray)->GetDataPtr(), oleArray, elementCount * elemSize); |
2623 | } |
2624 | else |
2625 | { |
2626 | // The array is non blittable so we need to marshal the elements. |
2627 | _ASSERTE(pElementMT->HasLayout()); |
2628 | MarshalNonBlittableRecordArrayOleToCom(oleArray, pComArray, pElementMT); |
2629 | } |
2630 | } |
2631 | |
2632 | void OleVariant::MarshalRecordArrayComToOle(BASEARRAYREF *pComArray, void *oleArray, |
2633 | MethodTable *pElementMT, BOOL fBestFitMapping, |
2634 | BOOL fThrowOnUnmappableChar, |
2635 | BOOL fOleArrayIsValid, SIZE_T cElements) |
2636 | { |
2637 | CONTRACTL |
2638 | { |
2639 | THROWS; |
2640 | GC_TRIGGERS; |
2641 | MODE_COOPERATIVE; |
2642 | PRECONDITION(CheckPointer(oleArray)); |
2643 | PRECONDITION(CheckPointer(pComArray)); |
2644 | PRECONDITION(CheckPointer(pElementMT)); |
2645 | } |
2646 | CONTRACTL_END; |
2647 | |
2648 | if (pElementMT->IsBlittable()) |
2649 | { |
2650 | // The array is blittable so we can simply copy it. |
2651 | _ASSERTE(pComArray); |
2652 | SIZE_T elemSize = pElementMT->GetNativeSize(); |
2653 | memcpyNoGCRefs(oleArray, (*pComArray)->GetDataPtr(), cElements * elemSize); |
2654 | } |
2655 | else |
2656 | { |
2657 | // The array is non blittable so we need to marshal the elements. |
2658 | _ASSERTE(pElementMT->HasLayout()); |
2659 | MarshalNonBlittableRecordArrayComToOle(pComArray, oleArray, pElementMT, fBestFitMapping, fThrowOnUnmappableChar, fOleArrayIsValid, cElements); |
2660 | } |
2661 | } |
2662 | |
2663 | |
2664 | void OleVariant::ClearRecordArray(void *oleArray, SIZE_T cElements, MethodTable *pElementMT) |
2665 | { |
2666 | CONTRACTL |
2667 | { |
2668 | NOTHROW; |
2669 | GC_TRIGGERS; |
2670 | MODE_ANY; |
2671 | PRECONDITION(CheckPointer(oleArray)); |
2672 | PRECONDITION(CheckPointer(pElementMT)); |
2673 | } |
2674 | CONTRACTL_END; |
2675 | |
2676 | if (!pElementMT->IsBlittable()) |
2677 | { |
2678 | _ASSERTE(pElementMT->HasLayout()); |
2679 | ClearNonBlittableRecordArray(oleArray, cElements, pElementMT); |
2680 | } |
2681 | } |
2682 | |
2683 | #ifdef FEATURE_COMINTEROP |
2684 | |
2685 | // Warning! VariantClear's previous contents of pVarOut. |
2686 | void OleVariant::MarshalOleVariantForObject(OBJECTREF * const & pObj, VARIANT *pOle) |
2687 | { |
2688 | CONTRACTL |
2689 | { |
2690 | THROWS; |
2691 | GC_TRIGGERS; |
2692 | MODE_COOPERATIVE; |
2693 | PRECONDITION(CheckPointer(pObj)); |
2694 | PRECONDITION(*pObj == NULL || (IsProtectedByGCFrame (pObj))); |
2695 | |
2696 | PRECONDITION(CheckPointer(pOle)); |
2697 | } |
2698 | CONTRACTL_END; |
2699 | |
2700 | if (AppX::IsAppXProcess()) |
2701 | { |
2702 | COMPlusThrow(kPlatformNotSupportedException, IDS_EE_BADMARSHAL_TYPE_VARIANTASOBJECT); |
2703 | } |
2704 | |
2705 | SafeVariantClear(pOle); |
2706 | |
2707 | #ifdef _DEBUG |
2708 | FillMemory(pOle, sizeof(VARIANT),0xdd); |
2709 | V_VT(pOle) = VT_EMPTY; |
2710 | #endif |
2711 | |
2712 | // For perf reasons, let's handle the more common and easy cases |
2713 | // without transitioning to managed code. |
2714 | if (*pObj == NULL) |
2715 | { |
2716 | // null maps to VT_EMPTY - nothing to do here. |
2717 | } |
2718 | else |
2719 | { |
2720 | MethodTable *pMT = (*pObj)->GetMethodTable(); |
2721 | if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_I4)) |
2722 | { |
2723 | V_I4(pOle) = *(LONG*)( (*pObj)->GetData() ); |
2724 | V_VT(pOle) = VT_I4; |
2725 | } |
2726 | else if (pMT == g_pStringClass) |
2727 | { |
2728 | if (*(pObj) == NULL) |
2729 | { |
2730 | V_BSTR(pOle) = NULL; |
2731 | } |
2732 | else |
2733 | { |
2734 | STRINGREF stringRef = (STRINGREF)(*pObj); |
2735 | V_BSTR(pOle) = SysAllocStringLen(stringRef->GetBuffer(), stringRef->GetStringLength()); |
2736 | if (NULL == V_BSTR(pOle)) |
2737 | COMPlusThrowOM(); |
2738 | } |
2739 | |
2740 | V_VT(pOle) = VT_BSTR; |
2741 | } |
2742 | else if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_I2)) |
2743 | { |
2744 | V_I2(pOle) = *(SHORT*)( (*pObj)->GetData() ); |
2745 | V_VT(pOle) = VT_I2; |
2746 | } |
2747 | else if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_I1)) |
2748 | { |
2749 | V_I1(pOle) = *(CHAR*)( (*pObj)->GetData() ); |
2750 | V_VT(pOle) = VT_I1; |
2751 | } |
2752 | else if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_U4)) |
2753 | { |
2754 | V_UI4(pOle) = *(ULONG*)( (*pObj)->GetData() ); |
2755 | V_VT(pOle) = VT_UI4; |
2756 | } |
2757 | else if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_U2)) |
2758 | { |
2759 | V_UI2(pOle) = *(USHORT*)( (*pObj)->GetData() ); |
2760 | V_VT(pOle) = VT_UI2; |
2761 | } |
2762 | else if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_U1)) |
2763 | { |
2764 | V_UI1(pOle) = *(BYTE*)( (*pObj)->GetData() ); |
2765 | V_VT(pOle) = VT_UI1; |
2766 | } |
2767 | else if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_R4)) |
2768 | { |
2769 | V_R4(pOle) = *(FLOAT*)( (*pObj)->GetData() ); |
2770 | V_VT(pOle) = VT_R4; |
2771 | } |
2772 | else if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_R8)) |
2773 | { |
2774 | V_R8(pOle) = *(DOUBLE*)( (*pObj)->GetData() ); |
2775 | V_VT(pOle) = VT_R8; |
2776 | } |
2777 | else if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_BOOLEAN)) |
2778 | { |
2779 | V_BOOL(pOle) = *(U1*)( (*pObj)->GetData() ) ? VARIANT_TRUE : VARIANT_FALSE; |
2780 | V_VT(pOle) = VT_BOOL; |
2781 | } |
2782 | else if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_I)) |
2783 | { |
2784 | *(LPVOID*)&(V_INT(pOle)) = *(LPVOID*)( (*pObj)->GetData() ); |
2785 | V_VT(pOle) = VT_INT; |
2786 | } |
2787 | else if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_U)) |
2788 | { |
2789 | *(LPVOID*)&(V_UINT(pOle)) = *(LPVOID*)( (*pObj)->GetData() ); |
2790 | V_VT(pOle) = VT_UINT; |
2791 | } |
2792 | else |
2793 | { |
2794 | MethodDescCallSite convertObjectToVariant(METHOD__VARIANT__CONVERT_OBJECT_TO_VARIANT); |
2795 | |
2796 | VariantData managedVariant; |
2797 | FillMemory(&managedVariant, sizeof(managedVariant), 0); |
2798 | GCPROTECT_BEGIN_VARIANTDATA(managedVariant) |
2799 | { |
2800 | ARG_SLOT args[] = { |
2801 | ObjToArgSlot(*pObj), |
2802 | PtrToArgSlot(&managedVariant), |
2803 | }; |
2804 | |
2805 | convertObjectToVariant.Call(args); |
2806 | |
2807 | OleVariant::MarshalOleVariantForComVariant(&managedVariant, pOle); |
2808 | } |
2809 | GCPROTECT_END_VARIANTDATA(); |
2810 | } |
2811 | } |
2812 | } |
2813 | |
2814 | void OleVariant::MarshalOleRefVariantForObject(OBJECTREF *pObj, VARIANT *pOle) |
2815 | { |
2816 | CONTRACTL |
2817 | { |
2818 | THROWS; |
2819 | GC_TRIGGERS; |
2820 | MODE_COOPERATIVE; |
2821 | PRECONDITION(CheckPointer(pObj)); |
2822 | PRECONDITION(IsProtectedByGCFrame (pObj)); |
2823 | PRECONDITION(CheckPointer(pOle)); |
2824 | PRECONDITION(V_VT(pOle) & VT_BYREF); |
2825 | } |
2826 | CONTRACTL_END; |
2827 | |
2828 | if (AppX::IsAppXProcess()) |
2829 | { |
2830 | COMPlusThrow(kPlatformNotSupportedException, IDS_EE_BADMARSHAL_TYPE_VARIANTASOBJECT); |
2831 | } |
2832 | |
2833 | HRESULT hr = MarshalCommonOleRefVariantForObject(pObj, pOle); |
2834 | |
2835 | if (FAILED(hr)) |
2836 | { |
2837 | if (hr == DISP_E_BADVARTYPE) |
2838 | { |
2839 | COMPlusThrow(kInvalidOleVariantTypeException, IDS_EE_INVALID_OLE_VARIANT); |
2840 | } |
2841 | else if (hr == DISP_E_TYPEMISMATCH) |
2842 | { |
2843 | COMPlusThrow(kInvalidCastException, IDS_EE_CANNOT_COERCE_BYREF_VARIANT); |
2844 | } |
2845 | else |
2846 | { |
2847 | MethodDescCallSite castVariant(METHOD__VARIANT__CAST_VARIANT); |
2848 | |
2849 | // MarshalOleRefVariantForObjectNoCast has checked that the variant is not an array |
2850 | // so we can use the marshal cast helper to coerce the object to the proper type. |
2851 | VariantData vd; |
2852 | FillMemory(&vd, sizeof(vd), 0); |
2853 | VARTYPE vt = V_VT(pOle) & ~VT_BYREF; |
2854 | |
2855 | GCPROTECT_BEGIN_VARIANTDATA(vd); |
2856 | { |
2857 | ARG_SLOT args[3]; |
2858 | args[0] = ObjToArgSlot(*pObj); |
2859 | args[1] = (ARG_SLOT)vt; |
2860 | args[2] = PtrToArgSlot(&vd); |
2861 | castVariant.Call(args); |
2862 | VARIANT vtmp; |
2863 | VariantInit(&vtmp); |
2864 | OleVariant::MarshalOleVariantForComVariant(&vd, &vtmp); |
2865 | |
2866 | // If the variant types are still not the same then call VariantChangeType to |
2867 | // try and coerse them. |
2868 | if (V_VT(&vtmp) != vt) |
2869 | { |
2870 | VARIANT vtmp2; |
2871 | memset(&vtmp2, 0, sizeof(VARIANT)); |
2872 | |
2873 | // The type of the variant has changed so attempt to change |
2874 | // the type back. |
2875 | hr = SafeVariantChangeType(&vtmp2, &vtmp, 0, vt); |
2876 | if (FAILED(hr)) |
2877 | { |
2878 | if (hr == DISP_E_TYPEMISMATCH) |
2879 | COMPlusThrow(kInvalidCastException, IDS_EE_CANNOT_COERCE_BYREF_VARIANT); |
2880 | else |
2881 | COMPlusThrowHR(hr); |
2882 | } |
2883 | |
2884 | // Copy the converted variant back into the original variant and clear the temp. |
2885 | InsertContentsIntoByrefVariant(&vtmp2, pOle); |
2886 | SafeVariantClear(&vtmp); |
2887 | } |
2888 | else |
2889 | { |
2890 | InsertContentsIntoByrefVariant(&vtmp, pOle); |
2891 | } |
2892 | } |
2893 | GCPROTECT_END_VARIANTDATA(); |
2894 | } |
2895 | } |
2896 | } |
2897 | |
2898 | HRESULT OleVariant::MarshalCommonOleRefVariantForObject(OBJECTREF *pObj, VARIANT *pOle) |
2899 | { |
2900 | CONTRACTL |
2901 | { |
2902 | THROWS; |
2903 | GC_TRIGGERS; |
2904 | MODE_COOPERATIVE; |
2905 | PRECONDITION(CheckPointer(pObj)); |
2906 | PRECONDITION(IsProtectedByGCFrame (pObj)); |
2907 | PRECONDITION(CheckPointer(pOle)); |
2908 | PRECONDITION(V_VT(pOle) & VT_BYREF); |
2909 | } |
2910 | CONTRACTL_END; |
2911 | |
2912 | HRESULT hr = S_OK; |
2913 | |
2914 | // Let's try to handle the common trivial cases quickly first before |
2915 | // running the generalized stuff. |
2916 | MethodTable *pMT = (*pObj) == NULL ? NULL : (*pObj)->GetMethodTable(); |
2917 | if ( (V_VT(pOle) == (VT_BYREF | VT_I4) || V_VT(pOle) == (VT_BYREF | VT_UI4)) && (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_I4) || pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_U4)) ) |
2918 | { |
2919 | // deallocation of old value optimized away since there's nothing to |
2920 | // deallocate for this vartype. |
2921 | |
2922 | *(V_I4REF(pOle)) = *(LONG*)( (*pObj)->GetData() ); |
2923 | } |
2924 | else if ( (V_VT(pOle) == (VT_BYREF | VT_I2) || V_VT(pOle) == (VT_BYREF | VT_UI2)) && (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_I2) || pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_U2)) ) |
2925 | { |
2926 | // deallocation of old value optimized away since there's nothing to |
2927 | // deallocate for this vartype. |
2928 | |
2929 | *(V_I2REF(pOle)) = *(SHORT*)( (*pObj)->GetData() ); |
2930 | } |
2931 | else if ( (V_VT(pOle) == (VT_BYREF | VT_I1) || V_VT(pOle) == (VT_BYREF | VT_UI1)) && (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_I1) || pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_U1)) ) |
2932 | { |
2933 | // deallocation of old value optimized away since there's nothing to |
2934 | // deallocate for this vartype. |
2935 | |
2936 | *(V_I1REF(pOle)) = *(CHAR*)( (*pObj)->GetData() ); |
2937 | } |
2938 | else if ( V_VT(pOle) == (VT_BYREF | VT_R4) && pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_R4) ) |
2939 | { |
2940 | // deallocation of old value optimized away since there's nothing to |
2941 | // deallocate for this vartype. |
2942 | |
2943 | *(V_R4REF(pOle)) = *(FLOAT*)( (*pObj)->GetData() ); |
2944 | } |
2945 | else if ( V_VT(pOle) == (VT_BYREF | VT_R8) && pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_R8) ) |
2946 | { |
2947 | // deallocation of old value optimized away since there's nothing to |
2948 | // deallocate for this vartype. |
2949 | |
2950 | *(V_R8REF(pOle)) = *(DOUBLE*)( (*pObj)->GetData() ); |
2951 | } |
2952 | else if ( V_VT(pOle) == (VT_BYREF | VT_BOOL) && pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_BOOLEAN) ) |
2953 | { |
2954 | // deallocation of old value optimized away since there's nothing to |
2955 | // deallocate for this vartype. |
2956 | |
2957 | *(V_BOOLREF(pOle)) = ( *(U1*)( (*pObj)->GetData() ) ) ? VARIANT_TRUE : VARIANT_FALSE; |
2958 | } |
2959 | else if ( (V_VT(pOle) == (VT_BYREF | VT_INT) || V_VT(pOle) == (VT_BYREF | VT_UINT)) && (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_I4) || pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_U4)) ) |
2960 | { |
2961 | // deallocation of old value optimized away since there's nothing to |
2962 | // deallocate for this vartype. |
2963 | |
2964 | *(V_INTREF(pOle)) = *(LONG*)( (*pObj)->GetData() ); |
2965 | } |
2966 | else if ( V_VT(pOle) == (VT_BYREF | VT_BSTR) && pMT == g_pStringClass ) |
2967 | { |
2968 | if (*(V_BSTRREF(pOle))) |
2969 | { |
2970 | SysFreeString(*(V_BSTRREF(pOle))); |
2971 | *(V_BSTRREF(pOle)) = NULL; |
2972 | } |
2973 | |
2974 | *(V_BSTRREF(pOle)) = ConvertStringToBSTR((STRINGREF*)pObj); |
2975 | } |
2976 | // Special case VT_BYREF|VT_RECORD |
2977 | else if (V_VT(pOle) == (VT_BYREF | VT_RECORD)) |
2978 | { |
2979 | // We have a special BYREF RECORD - we cannot call VariantClear on this one, because the caller owns the memory, |
2980 | // so we will call RecordClear, then write our data into the same location. |
2981 | hr = ClearAndInsertContentsIntoByrefRecordVariant(pOle, pObj); |
2982 | goto Exit; |
2983 | } |
2984 | else |
2985 | { |
2986 | VARIANT vtmp; |
2987 | VARTYPE vt = V_VT(pOle) & ~VT_BYREF; |
2988 | |
2989 | ExtractContentsFromByrefVariant(pOle, &vtmp); |
2990 | SafeVariantClear(&vtmp); |
2991 | |
2992 | if (vt == VT_VARIANT) |
2993 | { |
2994 | // Since variants can contain any VARTYPE we simply convert the object to |
2995 | // a variant and stuff it back into the byref variant. |
2996 | MarshalOleVariantForObject(pObj, &vtmp); |
2997 | InsertContentsIntoByrefVariant(&vtmp, pOle); |
2998 | } |
2999 | else if (vt & VT_ARRAY) |
3000 | { |
3001 | // Since the marshal cast helper does not support array's the best we can do |
3002 | // is marshal the object back to a variant and hope it is of the right type. |
3003 | // If it is not then we must throw an exception. |
3004 | MarshalOleVariantForObject(pObj, &vtmp); |
3005 | if (V_VT(&vtmp) != vt) |
3006 | { |
3007 | hr = DISP_E_TYPEMISMATCH; |
3008 | goto Exit; |
3009 | } |
3010 | InsertContentsIntoByrefVariant(&vtmp, pOle); |
3011 | } |
3012 | else if ( (*pObj) == NULL && |
3013 | (vt == VT_BSTR || |
3014 | vt == VT_DISPATCH || |
3015 | vt == VT_UNKNOWN || |
3016 | vt == VT_PTR || |
3017 | vt == VT_CARRAY || |
3018 | vt == VT_SAFEARRAY || |
3019 | vt == VT_LPSTR || |
3020 | vt == VT_LPWSTR) ) |
3021 | { |
3022 | // Have to handle this specially since the managed variant |
3023 | // conversion will return a VT_EMPTY which isn't what we want. |
3024 | V_VT(&vtmp) = vt; |
3025 | V_UNKNOWN(&vtmp) = NULL; |
3026 | InsertContentsIntoByrefVariant(&vtmp, pOle); |
3027 | } |
3028 | else |
3029 | { |
3030 | hr = E_FAIL; |
3031 | } |
3032 | } |
3033 | Exit: |
3034 | return hr; |
3035 | } |
3036 | |
3037 | void OleVariant::MarshalObjectForOleVariant(const VARIANT * pOle, OBJECTREF * const & pObj) |
3038 | { |
3039 | CONTRACT_VOID |
3040 | { |
3041 | THROWS; |
3042 | GC_TRIGGERS; |
3043 | MODE_COOPERATIVE; |
3044 | INJECT_FAULT(COMPlusThrowOM()); |
3045 | PRECONDITION(CheckPointer(pOle)); |
3046 | PRECONDITION(CheckPointer(pObj)); |
3047 | PRECONDITION(*pObj == NULL || (IsProtectedByGCFrame (pObj))); |
3048 | } |
3049 | CONTRACT_END; |
3050 | |
3051 | if (AppX::IsAppXProcess()) |
3052 | { |
3053 | COMPlusThrow(kPlatformNotSupportedException, IDS_EE_BADMARSHAL_TYPE_VARIANTASOBJECT); |
3054 | } |
3055 | |
3056 | #ifdef MDA_SUPPORTED |
3057 | MdaInvalidVariant* pProbe = MDA_GET_ASSISTANT(InvalidVariant); |
3058 | if (pProbe && !CheckVariant((VARIANT*)pOle)) |
3059 | pProbe->ReportViolation(); |
3060 | #endif |
3061 | |
3062 | // if V_ISBYREF(pOle) and V_BYREF(pOle) is null then we have a problem, |
3063 | // unless we're dealing with VT_EMPTY or VT_NULL in which case that is ok?? |
3064 | VARTYPE vt = V_VT(pOle) & ~VT_BYREF; |
3065 | if (V_ISBYREF(pOle) && !V_BYREF(pOle) && !(vt == VT_EMPTY || vt == VT_NULL)) |
3066 | COMPlusThrow(kArgumentException, IDS_EE_INVALID_OLE_VARIANT); |
3067 | |
3068 | switch (V_VT(pOle)) |
3069 | { |
3070 | case VT_EMPTY: |
3071 | SetObjectReference( pObj, |
3072 | NULL, |
3073 | GetAppDomain() ); |
3074 | break; |
3075 | |
3076 | case VT_I4: |
3077 | case VT_INT: |
3078 | SetObjectReference( pObj, |
3079 | AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_I4)), |
3080 | GetAppDomain() ); |
3081 | *(LONG*)((*pObj)->GetData()) = V_I4(pOle); |
3082 | break; |
3083 | |
3084 | case VT_BYREF|VT_I4: |
3085 | case VT_BYREF|VT_INT: |
3086 | SetObjectReference( pObj, |
3087 | AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_I4)), |
3088 | GetAppDomain() ); |
3089 | *(LONG*)((*pObj)->GetData()) = *(V_I4REF(pOle)); |
3090 | break; |
3091 | |
3092 | case VT_UI4: |
3093 | case VT_UINT: |
3094 | SetObjectReference( pObj, |
3095 | AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_U4)), |
3096 | GetAppDomain() ); |
3097 | *(ULONG*)((*pObj)->GetData()) = V_UI4(pOle); |
3098 | break; |
3099 | |
3100 | case VT_BYREF|VT_UI4: |
3101 | case VT_BYREF|VT_UINT: |
3102 | SetObjectReference( pObj, |
3103 | AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_U4)), |
3104 | GetAppDomain() ); |
3105 | *(ULONG*)((*pObj)->GetData()) = *(V_UI4REF(pOle)); |
3106 | break; |
3107 | |
3108 | case VT_I2: |
3109 | SetObjectReference( pObj, |
3110 | AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_I2)), |
3111 | GetAppDomain() ); |
3112 | (*(SHORT*)((*pObj)->GetData())) = V_I2(pOle); |
3113 | break; |
3114 | |
3115 | case VT_BYREF|VT_I2: |
3116 | SetObjectReference( pObj, |
3117 | AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_I2)), |
3118 | GetAppDomain() ); |
3119 | *(SHORT*)((*pObj)->GetData()) = *(V_I2REF(pOle)); |
3120 | break; |
3121 | |
3122 | case VT_UI2: |
3123 | SetObjectReference( pObj, |
3124 | AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_U2)), |
3125 | GetAppDomain() ); |
3126 | *(USHORT*)((*pObj)->GetData()) = V_UI2(pOle); |
3127 | break; |
3128 | |
3129 | case VT_BYREF|VT_UI2: |
3130 | SetObjectReference( pObj, |
3131 | AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_U2)), |
3132 | GetAppDomain() ); |
3133 | *(USHORT*)((*pObj)->GetData()) = *(V_UI2REF(pOle)); |
3134 | break; |
3135 | |
3136 | case VT_I1: |
3137 | SetObjectReference( pObj, |
3138 | AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_I1)), |
3139 | GetAppDomain() ); |
3140 | *(CHAR*)((*pObj)->GetData()) = V_I1(pOle); |
3141 | break; |
3142 | |
3143 | case VT_BYREF|VT_I1: |
3144 | SetObjectReference( pObj, |
3145 | AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_I1)), |
3146 | GetAppDomain() ); |
3147 | *(CHAR*)((*pObj)->GetData()) = *(V_I1REF(pOle)); |
3148 | break; |
3149 | |
3150 | case VT_UI1: |
3151 | SetObjectReference( pObj, |
3152 | AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_U1)), |
3153 | GetAppDomain() ); |
3154 | *(BYTE*)((*pObj)->GetData()) = V_UI1(pOle); |
3155 | break; |
3156 | |
3157 | case VT_BYREF|VT_UI1: |
3158 | SetObjectReference( pObj, |
3159 | AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_U1)), |
3160 | GetAppDomain() ); |
3161 | *(BYTE*)((*pObj)->GetData()) = *(V_UI1REF(pOle)); |
3162 | break; |
3163 | |
3164 | case VT_R4: |
3165 | SetObjectReference( pObj, |
3166 | AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_R4)), |
3167 | GetAppDomain() ); |
3168 | *(FLOAT*)((*pObj)->GetData()) = V_R4(pOle); |
3169 | break; |
3170 | |
3171 | case VT_BYREF|VT_R4: |
3172 | SetObjectReference( pObj, |
3173 | AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_R4)), |
3174 | GetAppDomain() ); |
3175 | *(FLOAT*)((*pObj)->GetData()) = *(V_R4REF(pOle)); |
3176 | break; |
3177 | |
3178 | case VT_R8: |
3179 | SetObjectReference( pObj, |
3180 | AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_R8)), |
3181 | GetAppDomain() ); |
3182 | *(DOUBLE*)((*pObj)->GetData()) = V_R8(pOle); |
3183 | break; |
3184 | |
3185 | case VT_BYREF|VT_R8: |
3186 | SetObjectReference( pObj, |
3187 | AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_R8)), |
3188 | GetAppDomain() ); |
3189 | *(DOUBLE*)((*pObj)->GetData()) = *(V_R8REF(pOle)); |
3190 | break; |
3191 | |
3192 | case VT_BOOL: |
3193 | SetObjectReference( pObj, |
3194 | AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_BOOLEAN)), |
3195 | GetAppDomain() ); |
3196 | *(VARIANT_BOOL*)((*pObj)->GetData()) = V_BOOL(pOle) ? 1 : 0; |
3197 | break; |
3198 | |
3199 | case VT_BYREF|VT_BOOL: |
3200 | SetObjectReference( pObj, |
3201 | AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_BOOLEAN)), |
3202 | GetAppDomain() ); |
3203 | *(VARIANT_BOOL*)((*pObj)->GetData()) = *(V_BOOLREF(pOle)) ? 1 : 0; |
3204 | break; |
3205 | |
3206 | case VT_BSTR: |
3207 | ConvertBSTRToString(V_BSTR(pOle), (STRINGREF*)pObj); |
3208 | break; |
3209 | |
3210 | case VT_BYREF|VT_BSTR: |
3211 | ConvertBSTRToString(*(V_BSTRREF(pOle)), (STRINGREF*)pObj); |
3212 | break; |
3213 | |
3214 | default: |
3215 | { |
3216 | MethodDescCallSite convertVariantToObject(METHOD__VARIANT__CONVERT_VARIANT_TO_OBJECT); |
3217 | |
3218 | VariantData managedVariant; |
3219 | FillMemory(&managedVariant, sizeof(managedVariant), 0); |
3220 | GCPROTECT_BEGIN_VARIANTDATA(managedVariant) |
3221 | { |
3222 | OleVariant::MarshalComVariantForOleVariant((VARIANT*)pOle, &managedVariant); |
3223 | ARG_SLOT args[] = { PtrToArgSlot(&managedVariant) }; |
3224 | SetObjectReference( pObj, |
3225 | convertVariantToObject.Call_RetOBJECTREF(args), |
3226 | GetAppDomain() ); |
3227 | } |
3228 | GCPROTECT_END_VARIANTDATA(); |
3229 | } |
3230 | } |
3231 | RETURN; |
3232 | } |
3233 | |
3234 | /* ------------------------------------------------------------------------- * |
3235 | * Byref variant manipulation helpers. |
3236 | * ------------------------------------------------------------------------- */ |
3237 | |
3238 | void OleVariant::ExtractContentsFromByrefVariant(VARIANT *pByrefVar, VARIANT *pDestVar) |
3239 | { |
3240 | CONTRACT_VOID |
3241 | { |
3242 | THROWS; |
3243 | GC_TRIGGERS; |
3244 | MODE_ANY; |
3245 | PRECONDITION(CheckPointer(pByrefVar)); |
3246 | PRECONDITION(CheckPointer(pDestVar)); |
3247 | } |
3248 | CONTRACT_END; |
3249 | |
3250 | VARTYPE vt = V_VT(pByrefVar) & ~VT_BYREF; |
3251 | |
3252 | // VT_BYREF | VT_EMPTY is not a valid combination. |
3253 | if (vt == 0 || vt == VT_EMPTY) |
3254 | COMPlusThrow(kInvalidOleVariantTypeException, IDS_EE_INVALID_OLE_VARIANT); |
3255 | |
3256 | switch (vt) |
3257 | { |
3258 | case VT_RECORD: |
3259 | { |
3260 | // VT_RECORD's are weird in that regardless of is the VT_BYREF flag is set or not |
3261 | // they have the same internal representation. |
3262 | V_RECORD(pDestVar) = V_RECORD(pByrefVar); |
3263 | V_RECORDINFO(pDestVar) = V_RECORDINFO(pByrefVar); |
3264 | |
3265 | // Set the variant type of the destination variant. |
3266 | V_VT(pDestVar) = vt; |
3267 | |
3268 | break; |
3269 | } |
3270 | |
3271 | case VT_VARIANT: |
3272 | { |
3273 | // A byref variant is not allowed to contain a byref variant. |
3274 | if (V_ISBYREF(V_VARIANTREF(pByrefVar))) |
3275 | COMPlusThrow(kInvalidOleVariantTypeException, IDS_EE_INVALID_OLE_VARIANT); |
3276 | |
3277 | // Copy the variant that the byref variant points to into the destination variant. |
3278 | // This will replace the VARTYPE of pDestVar with the VARTYPE of the VARIANT being |
3279 | // pointed to. |
3280 | memcpyNoGCRefs(pDestVar, V_VARIANTREF(pByrefVar), sizeof(VARIANT)); |
3281 | break; |
3282 | } |
3283 | |
3284 | case VT_DECIMAL: |
3285 | { |
3286 | // Copy the value that the byref variant points to into the destination variant. |
3287 | // Decimal's are special in that they occupy the 16 bits of padding between the |
3288 | // VARTYPE and the intVal field. |
3289 | memcpyNoGCRefs(&V_DECIMAL(pDestVar), V_DECIMALREF(pByrefVar), sizeof(DECIMAL)); |
3290 | |
3291 | // Set the variant type of the destination variant. |
3292 | V_VT(pDestVar) = vt; |
3293 | |
3294 | break; |
3295 | } |
3296 | |
3297 | default: |
3298 | { |
3299 | // Copy the value that the byref variant points to into the destination variant. |
3300 | SIZE_T sz = OleVariant::GetElementSizeForVarType(vt, NULL); |
3301 | memcpyNoGCRefs(&V_INT(pDestVar), V_INTREF(pByrefVar), sz); |
3302 | |
3303 | // Set the variant type of the destination variant. |
3304 | V_VT(pDestVar) = vt; |
3305 | |
3306 | break; |
3307 | } |
3308 | } |
3309 | |
3310 | RETURN; |
3311 | } |
3312 | |
3313 | void OleVariant::InsertContentsIntoByrefVariant(VARIANT *pSrcVar, VARIANT *pByrefVar) |
3314 | { |
3315 | CONTRACT_VOID |
3316 | { |
3317 | THROWS; |
3318 | GC_TRIGGERS; |
3319 | MODE_ANY; |
3320 | PRECONDITION(CheckPointer(pByrefVar)); |
3321 | PRECONDITION(CheckPointer(pSrcVar)); |
3322 | } |
3323 | CONTRACT_END; |
3324 | |
3325 | _ASSERTE(V_VT(pSrcVar) == (V_VT(pByrefVar) & ~VT_BYREF) || V_VT(pByrefVar) == (VT_BYREF | VT_VARIANT)); |
3326 | |
3327 | |
3328 | VARTYPE vt = V_VT(pByrefVar) & ~VT_BYREF; |
3329 | |
3330 | // VT_BYREF | VT_EMPTY is not a valid combination. |
3331 | if (vt == 0 || vt == VT_EMPTY) |
3332 | COMPlusThrow(kInvalidOleVariantTypeException, IDS_EE_INVALID_OLE_VARIANT); |
3333 | |
3334 | switch (vt) |
3335 | { |
3336 | case VT_RECORD: |
3337 | { |
3338 | // VT_RECORD's are weird in that regardless of is the VT_BYREF flag is set or not |
3339 | // they have the same internal representation. |
3340 | V_RECORD(pByrefVar) = V_RECORD(pSrcVar); |
3341 | V_RECORDINFO(pByrefVar) = V_RECORDINFO(pSrcVar); |
3342 | break; |
3343 | } |
3344 | |
3345 | case VT_VARIANT: |
3346 | { |
3347 | // Copy the variant that the byref variant points to into the destination variant. |
3348 | memcpyNoGCRefs(V_VARIANTREF(pByrefVar), pSrcVar, sizeof(VARIANT)); |
3349 | break; |
3350 | } |
3351 | |
3352 | case VT_DECIMAL: |
3353 | { |
3354 | // Copy the value inside the source variant into the location pointed to by the byref variant. |
3355 | memcpyNoGCRefs(V_DECIMALREF(pByrefVar), &V_DECIMAL(pSrcVar), sizeof(DECIMAL)); |
3356 | break; |
3357 | } |
3358 | |
3359 | default: |
3360 | { |
3361 | // Copy the value inside the source variant into the location pointed to by the byref variant. |
3362 | |
3363 | SIZE_T sz = OleVariant::GetElementSizeForVarType(vt, NULL); |
3364 | memcpyNoGCRefs(V_INTREF(pByrefVar), &V_INT(pSrcVar), sz); |
3365 | break; |
3366 | } |
3367 | } |
3368 | RETURN; |
3369 | } |
3370 | |
3371 | void OleVariant::CreateByrefVariantForVariant(VARIANT *pSrcVar, VARIANT *pByrefVar) |
3372 | { |
3373 | CONTRACT_VOID |
3374 | { |
3375 | THROWS; |
3376 | GC_TRIGGERS; |
3377 | MODE_ANY; |
3378 | PRECONDITION(CheckPointer(pByrefVar)); |
3379 | PRECONDITION(CheckPointer(pSrcVar)); |
3380 | } |
3381 | CONTRACT_END; |
3382 | |
3383 | // Set the type of the byref variant based on the type of the source variant. |
3384 | VARTYPE vt = V_VT(pSrcVar); |
3385 | |
3386 | // VT_BYREF | VT_EMPTY is not a valid combination. |
3387 | if (vt == VT_EMPTY) |
3388 | COMPlusThrow(kInvalidOleVariantTypeException, IDS_EE_INVALID_OLE_VARIANT); |
3389 | |
3390 | if (vt == VT_NULL) |
3391 | { |
3392 | // VT_BYREF | VT_NULL is not a valid combination either but we'll allow VT_NULL |
3393 | // to be passed this way (meaning that the callee can change the type and return |
3394 | // data), note that the VT_BYREF flag is not added |
3395 | V_VT(pByrefVar) = vt; |
3396 | } |
3397 | else |
3398 | { |
3399 | switch (vt) |
3400 | { |
3401 | case VT_RECORD: |
3402 | { |
3403 | // VT_RECORD's are weird in that regardless of is the VT_BYREF flag is set or not |
3404 | // they have the same internal representation. |
3405 | V_RECORD(pByrefVar) = V_RECORD(pSrcVar); |
3406 | V_RECORDINFO(pByrefVar) = V_RECORDINFO(pSrcVar); |
3407 | break; |
3408 | } |
3409 | |
3410 | case VT_VARIANT: |
3411 | { |
3412 | V_VARIANTREF(pByrefVar) = pSrcVar; |
3413 | break; |
3414 | } |
3415 | |
3416 | case VT_DECIMAL: |
3417 | { |
3418 | V_DECIMALREF(pByrefVar) = &V_DECIMAL(pSrcVar); |
3419 | break; |
3420 | } |
3421 | |
3422 | default: |
3423 | { |
3424 | V_INTREF(pByrefVar) = &V_INT(pSrcVar); |
3425 | break; |
3426 | } |
3427 | } |
3428 | |
3429 | V_VT(pByrefVar) = vt | VT_BYREF; |
3430 | } |
3431 | |
3432 | RETURN; |
3433 | } |
3434 | |
3435 | /* ------------------------------------------------------------------------- * |
3436 | * Variant marshaling |
3437 | * ------------------------------------------------------------------------- */ |
3438 | |
3439 | // |
3440 | // MarshalComVariantForOleVariant copies the contents of the OLE variant from |
3441 | // the COM variant. |
3442 | // |
3443 | |
3444 | void OleVariant::MarshalComVariantForOleVariant(VARIANT *pOle, VariantData *pCom) |
3445 | { |
3446 | CONTRACTL |
3447 | { |
3448 | THROWS; |
3449 | GC_TRIGGERS; |
3450 | MODE_COOPERATIVE; |
3451 | PRECONDITION(CheckPointer(pOle)); |
3452 | PRECONDITION(CheckPointer(pCom)); |
3453 | } |
3454 | CONTRACTL_END; |
3455 | |
3456 | BOOL byref = V_ISBYREF(pOle); |
3457 | VARTYPE vt = V_VT(pOle) & ~VT_BYREF; |
3458 | |
3459 | // Note that the following check also covers VT_ILLEGAL. |
3460 | if ((vt & ~VT_ARRAY) >= 128 ) |
3461 | COMPlusThrow(kInvalidOleVariantTypeException, IDS_EE_INVALID_OLE_VARIANT); |
3462 | |
3463 | if (byref && !V_BYREF(pOle) && !(vt == VT_EMPTY || vt == VT_NULL)) |
3464 | COMPlusThrow(kArgumentException, IDS_EE_INVALID_OLE_VARIANT); |
3465 | |
3466 | if (byref && vt == VT_VARIANT) |
3467 | { |
3468 | pOle = V_VARIANTREF(pOle); |
3469 | byref = V_ISBYREF(pOle); |
3470 | vt = V_VT(pOle) & ~VT_BYREF; |
3471 | |
3472 | // Byref VARIANTS are not allowed to be nested. |
3473 | if (byref) |
3474 | COMPlusThrow(kInvalidOleVariantTypeException, IDS_EE_INVALID_OLE_VARIANT); |
3475 | } |
3476 | |
3477 | CVTypes cvt = GetCVTypeForVarType(vt); |
3478 | const Marshaler *marshal = GetMarshalerForVarType(vt, TRUE); |
3479 | |
3480 | pCom->SetType(cvt); |
3481 | pCom->SetVT(vt); // store away VT for return trip. |
3482 | if (marshal == NULL || (byref |
3483 | ? marshal->OleRefToComVariant == NULL |
3484 | : marshal->OleToComVariant == NULL)) |
3485 | { |
3486 | if (cvt==CV_EMPTY) |
3487 | { |
3488 | if (V_ISBYREF(pOle)) |
3489 | { |
3490 | // Must set ObjectRef field of Variant to a specific instance. |
3491 | #ifdef _WIN64 |
3492 | VariantData::NewVariant(pCom, CV_U8, (INT64)(size_t)V_BYREF(pOle)); |
3493 | #else // _WIN64 |
3494 | VariantData::NewVariant(pCom, CV_U4, (INT32)(size_t)V_BYREF(pOle)); |
3495 | #endif // _WIN64 |
3496 | } |
3497 | else |
3498 | { |
3499 | VariantData::NewVariant(pCom, cvt, NULL); |
3500 | } |
3501 | } |
3502 | else if (cvt==CV_NULL) |
3503 | { |
3504 | VariantData::NewVariant(pCom, cvt, NULL); |
3505 | } |
3506 | else |
3507 | { |
3508 | pCom->SetObjRef(NULL); |
3509 | if (byref) |
3510 | { |
3511 | INT64 data = 0; |
3512 | CopyMemory(&data, V_R8REF(pOle), GetElementSizeForVarType(vt, NULL)); |
3513 | pCom->SetData(&data); |
3514 | } |
3515 | else |
3516 | pCom->SetData(&V_R8(pOle)); |
3517 | } |
3518 | } |
3519 | else |
3520 | { |
3521 | if (byref) |
3522 | marshal->OleRefToComVariant(pOle, pCom); |
3523 | else |
3524 | marshal->OleToComVariant(pOle, pCom); |
3525 | } |
3526 | } |
3527 | |
3528 | // |
3529 | // MarshalOleVariantForComVariant copies the contents of the OLE variant from |
3530 | // the COM variant. |
3531 | // |
3532 | |
3533 | void OleVariant::MarshalOleVariantForComVariant(VariantData *pCom, VARIANT *pOle) |
3534 | { |
3535 | CONTRACTL |
3536 | { |
3537 | THROWS; |
3538 | GC_TRIGGERS; |
3539 | MODE_COOPERATIVE; |
3540 | PRECONDITION(CheckPointer(pCom)); |
3541 | PRECONDITION(CheckPointer(pOle)); |
3542 | } |
3543 | CONTRACTL_END; |
3544 | |
3545 | SafeVariantClear(pOle); |
3546 | |
3547 | VariantEmptyHolder veh; |
3548 | veh = pOle; |
3549 | |
3550 | VARTYPE vt = GetVarTypeForComVariant(pCom); |
3551 | V_VT(pOle) = vt; |
3552 | |
3553 | const Marshaler *marshal = GetMarshalerForVarType(vt, TRUE); |
3554 | |
3555 | if (marshal == NULL || marshal->ComToOleVariant == NULL) |
3556 | { |
3557 | *(INT64*)&V_R8(pOle) = *(INT64*)pCom->GetData(); |
3558 | } |
3559 | else |
3560 | { |
3561 | marshal->ComToOleVariant(pCom, pOle); |
3562 | } |
3563 | |
3564 | veh.SuppressRelease(); |
3565 | } |
3566 | |
3567 | void OleVariant::MarshalInterfaceArrayComToOleHelper(BASEARRAYREF *pComArray, void *oleArray, |
3568 | MethodTable *pElementMT, BOOL bDefaultIsDispatch, |
3569 | SIZE_T cElements) |
3570 | { |
3571 | CONTRACTL |
3572 | { |
3573 | THROWS; |
3574 | GC_TRIGGERS; |
3575 | MODE_COOPERATIVE; |
3576 | PRECONDITION(CheckPointer(pComArray)); |
3577 | PRECONDITION(CheckPointer(oleArray)); |
3578 | } |
3579 | CONTRACTL_END; |
3580 | |
3581 | ASSERT_PROTECTED(pComArray); |
3582 | |
3583 | |
3584 | BOOL bDispatch = bDefaultIsDispatch; |
3585 | BOOL bHeterogenous = (pElementMT == NULL); |
3586 | |
3587 | // If the method table is for Object then don't consider it. |
3588 | if (pElementMT == g_pObjectClass) |
3589 | pElementMT = NULL; |
3590 | |
3591 | // If the element MT represents a class, then we need to determine the default |
3592 | // interface to use to expose the object out to COM. |
3593 | if (pElementMT && !pElementMT->IsInterface()) |
3594 | { |
3595 | pElementMT = GetDefaultInterfaceMTForClass(pElementMT, &bDispatch); |
3596 | } |
3597 | |
3598 | // Determine the start and the end of the data in the OLE array. |
3599 | IUnknown **pOle = (IUnknown **) oleArray; |
3600 | IUnknown **pOleEnd = pOle + cElements; |
3601 | |
3602 | // Retrieve the start of the data in the managed array. |
3603 | BASEARRAYREF unprotectedArray = *pComArray; |
3604 | OBJECTREF *pCom = (OBJECTREF *) unprotectedArray->GetDataPtr(); |
3605 | |
3606 | OBJECTREF TmpObj = NULL; |
3607 | GCPROTECT_BEGIN(TmpObj) |
3608 | { |
3609 | MethodTable *pLastElementMT = NULL; |
3610 | |
3611 | while (pOle < pOleEnd) |
3612 | { |
3613 | TmpObj = *pCom++; |
3614 | |
3615 | IUnknown *unk; |
3616 | if (TmpObj == NULL) |
3617 | unk = NULL; |
3618 | else |
3619 | { |
3620 | if (bHeterogenous) |
3621 | { |
3622 | // Inspect the type of each element separately (cache the last type for perf). |
3623 | if (TmpObj->GetMethodTable() != pLastElementMT) |
3624 | { |
3625 | pLastElementMT = TmpObj->GetMethodTable(); |
3626 | pElementMT = GetDefaultInterfaceMTForClass(pLastElementMT, &bDispatch); |
3627 | } |
3628 | } |
3629 | |
3630 | if (pElementMT) |
3631 | { |
3632 | // Convert to COM IP based on an interface MT (a specific interface will be exposed). |
3633 | unk = GetComIPFromObjectRef(&TmpObj, pElementMT); |
3634 | } |
3635 | else |
3636 | { |
3637 | // Convert to COM IP exposing either IDispatch or IUnknown. |
3638 | unk = GetComIPFromObjectRef(&TmpObj, (bDispatch ? ComIpType_Dispatch : ComIpType_Unknown), NULL); |
3639 | } |
3640 | } |
3641 | |
3642 | *pOle++ = unk; |
3643 | |
3644 | if (*(void **)&unprotectedArray != *(void **)&*pComArray) |
3645 | { |
3646 | SIZE_T currentOffset = ((BYTE *)pCom) - (*(Object **) &unprotectedArray)->GetAddress(); |
3647 | unprotectedArray = *pComArray; |
3648 | pCom = (OBJECTREF *) (unprotectedArray->GetAddress() + currentOffset); |
3649 | } |
3650 | } |
3651 | } |
3652 | GCPROTECT_END(); |
3653 | } |
3654 | |
3655 | // Used by customer checked build to test validity of VARIANT |
3656 | |
3657 | BOOL OleVariant::CheckVariant(VARIANT* pOle) |
3658 | { |
3659 | CONTRACTL |
3660 | { |
3661 | THROWS; |
3662 | GC_TRIGGERS; |
3663 | MODE_ANY; |
3664 | PRECONDITION(CheckPointer(pOle)); |
3665 | } |
3666 | CONTRACTL_END; |
3667 | |
3668 | BOOL bValidVariant = FALSE; |
3669 | |
3670 | // We need a try/catch here since VariantCopy could cause an AV if the VARIANT isn't valid. |
3671 | EX_TRY |
3672 | { |
3673 | VARIANT pOleCopy; |
3674 | SafeVariantInit(&pOleCopy); |
3675 | |
3676 | GCX_PREEMP(); |
3677 | if (SUCCEEDED(VariantCopy(&pOleCopy, pOle))) |
3678 | { |
3679 | SafeVariantClear(&pOleCopy); |
3680 | bValidVariant = TRUE; |
3681 | } |
3682 | } |
3683 | EX_CATCH |
3684 | { |
3685 | } |
3686 | EX_END_CATCH(SwallowAllExceptions); |
3687 | |
3688 | return bValidVariant; |
3689 | } |
3690 | |
3691 | HRESULT OleVariant::ClearAndInsertContentsIntoByrefRecordVariant(VARIANT* pOle, OBJECTREF* pObj) |
3692 | { |
3693 | CONTRACTL |
3694 | { |
3695 | THROWS; |
3696 | GC_TRIGGERS; |
3697 | MODE_ANY; |
3698 | } |
3699 | CONTRACTL_END; |
3700 | |
3701 | if (V_VT(pOle) != (VT_BYREF | VT_RECORD)) |
3702 | return DISP_E_BADVARTYPE; |
3703 | |
3704 | // Clear the current contents of the record. |
3705 | { |
3706 | GCX_PREEMP(); |
3707 | V_RECORDINFO(pOle)->RecordClear(V_RECORD(pOle)); |
3708 | } |
3709 | |
3710 | // Ok - let's marshal the returning object into a VT_RECORD. |
3711 | if ((*pObj) != NULL) |
3712 | { |
3713 | VARIANT vtmp; |
3714 | SafeVariantInit(&vtmp); |
3715 | |
3716 | MarshalOleVariantForObject(pObj, &vtmp); |
3717 | |
3718 | { |
3719 | GCX_PREEMP(); |
3720 | |
3721 | // Verify that we have a VT_RECORD. |
3722 | if (V_VT(&vtmp) != VT_RECORD) |
3723 | { |
3724 | SafeVariantClear(&vtmp); |
3725 | return DISP_E_TYPEMISMATCH; |
3726 | } |
3727 | |
3728 | // Verify that we have the same type of record. |
3729 | if (! V_RECORDINFO(pOle)->IsMatchingType(V_RECORDINFO(&vtmp))) |
3730 | { |
3731 | SafeVariantClear(&vtmp); |
3732 | return DISP_E_TYPEMISMATCH; |
3733 | } |
3734 | |
3735 | // Now copy the contents of the new variant back into the old variant. |
3736 | HRESULT hr = V_RECORDINFO(pOle)->RecordCopy(V_RECORD(&vtmp), V_RECORD(pOle)); |
3737 | if (hr != S_OK) |
3738 | { |
3739 | SafeVariantClear(&vtmp); |
3740 | return DISP_E_TYPEMISMATCH; |
3741 | } |
3742 | } |
3743 | } |
3744 | return S_OK; |
3745 | } |
3746 | |
3747 | void OleVariant::MarshalIDispatchArrayComToOle(BASEARRAYREF *pComArray, void *oleArray, |
3748 | MethodTable *pElementMT, BOOL fBestFitMapping, |
3749 | BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid, |
3750 | SIZE_T cElements) |
3751 | { |
3752 | WRAPPER_NO_CONTRACT; |
3753 | |
3754 | MarshalInterfaceArrayComToOleHelper(pComArray, oleArray, pElementMT, TRUE, cElements); |
3755 | } |
3756 | |
3757 | |
3758 | /* ------------------------------------------------------------------------- * |
3759 | * Currency marshaling routines |
3760 | * ------------------------------------------------------------------------- */ |
3761 | |
3762 | void OleVariant::MarshalCurrencyVariantOleToCom(VARIANT *pOleVariant, |
3763 | VariantData *pComVariant) |
3764 | { |
3765 | CONTRACTL |
3766 | { |
3767 | THROWS; |
3768 | GC_TRIGGERS; |
3769 | MODE_COOPERATIVE; |
3770 | INJECT_FAULT(COMPlusThrowOM()); |
3771 | PRECONDITION(CheckPointer(pOleVariant)); |
3772 | PRECONDITION(CheckPointer(pComVariant)); |
3773 | } |
3774 | CONTRACTL_END; |
3775 | |
3776 | OBJECTREF pDecimalRef = AllocateObject(MscorlibBinder::GetClass(CLASS__DECIMAL)); |
3777 | DECIMAL DecVal; |
3778 | |
3779 | // Convert the currency to a decimal. |
3780 | VarDecFromCyCanonicalize(V_CY(pOleVariant), &DecVal); |
3781 | |
3782 | // Store the value into the unboxes decimal and store the decimal in the variant. |
3783 | *(DECIMAL *) pDecimalRef->UnBox() = DecVal; |
3784 | pComVariant->SetObjRef(pDecimalRef); |
3785 | } |
3786 | |
3787 | void OleVariant::MarshalCurrencyVariantComToOle(VariantData *pComVariant, |
3788 | VARIANT *pOleVariant) |
3789 | { |
3790 | CONTRACTL |
3791 | { |
3792 | THROWS; |
3793 | GC_TRIGGERS; |
3794 | MODE_COOPERATIVE; |
3795 | PRECONDITION(CheckPointer(pOleVariant)); |
3796 | PRECONDITION(CheckPointer(pComVariant)); |
3797 | } |
3798 | CONTRACTL_END; |
3799 | |
3800 | CURRENCY CyVal; |
3801 | |
3802 | // Convert the decimal to a currency. |
3803 | HRESULT hr = VarCyFromDec((DECIMAL*)pComVariant->GetObjRef()->UnBox(), &CyVal); |
3804 | IfFailThrow(hr); |
3805 | |
3806 | // Store the currency in the VARIANT and set the VT. |
3807 | V_CY(pOleVariant) = CyVal; |
3808 | } |
3809 | |
3810 | void OleVariant::MarshalCurrencyVariantOleRefToCom(VARIANT *pOleVariant, |
3811 | VariantData *pComVariant) |
3812 | { |
3813 | CONTRACTL |
3814 | { |
3815 | THROWS; |
3816 | GC_TRIGGERS; |
3817 | MODE_COOPERATIVE; |
3818 | INJECT_FAULT(COMPlusThrowOM()); |
3819 | PRECONDITION(CheckPointer(pOleVariant)); |
3820 | PRECONDITION(CheckPointer(pComVariant)); |
3821 | } |
3822 | CONTRACTL_END; |
3823 | |
3824 | OBJECTREF pDecimalRef = AllocateObject(MscorlibBinder::GetClass(CLASS__DECIMAL)); |
3825 | DECIMAL DecVal; |
3826 | |
3827 | // Convert the currency to a decimal. |
3828 | VarDecFromCyCanonicalize(*V_CYREF(pOleVariant), &DecVal); |
3829 | |
3830 | // Store the value into the unboxes decimal and store the decimal in the variant. |
3831 | *(DECIMAL *) pDecimalRef->UnBox() = DecVal; |
3832 | pComVariant->SetObjRef(pDecimalRef); |
3833 | } |
3834 | |
3835 | void OleVariant::MarshalCurrencyArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray, |
3836 | MethodTable *pInterfaceMT) |
3837 | { |
3838 | CONTRACTL |
3839 | { |
3840 | THROWS; |
3841 | GC_TRIGGERS; |
3842 | MODE_COOPERATIVE; |
3843 | PRECONDITION(CheckPointer(oleArray)); |
3844 | PRECONDITION(CheckPointer(pComArray)); |
3845 | } |
3846 | CONTRACTL_END; |
3847 | |
3848 | ASSERT_PROTECTED(pComArray); |
3849 | SIZE_T elementCount = (*pComArray)->GetNumComponents(); |
3850 | |
3851 | CURRENCY *pOle = (CURRENCY *) oleArray; |
3852 | CURRENCY *pOleEnd = pOle + elementCount; |
3853 | |
3854 | DECIMAL *pCom = (DECIMAL *) (*pComArray)->GetDataPtr(); |
3855 | |
3856 | while (pOle < pOleEnd) |
3857 | { |
3858 | VarDecFromCyCanonicalize(*pOle++, pCom++); |
3859 | } |
3860 | } |
3861 | |
3862 | void OleVariant::MarshalCurrencyArrayComToOle(BASEARRAYREF *pComArray, void *oleArray, |
3863 | MethodTable *pInterfaceMT, BOOL fBestFitMapping, |
3864 | BOOL fThrowOnUnmappableChar, |
3865 | BOOL fOleArrayIsValid, SIZE_T cElements) |
3866 | { |
3867 | CONTRACTL |
3868 | { |
3869 | THROWS; |
3870 | GC_TRIGGERS; |
3871 | MODE_COOPERATIVE; |
3872 | PRECONDITION(CheckPointer(oleArray)); |
3873 | PRECONDITION(CheckPointer(pComArray)); |
3874 | } |
3875 | CONTRACTL_END; |
3876 | |
3877 | ASSERT_PROTECTED(pComArray); |
3878 | |
3879 | CURRENCY *pOle = (CURRENCY *) oleArray; |
3880 | CURRENCY *pOleEnd = pOle + cElements; |
3881 | |
3882 | DECIMAL *pCom = (DECIMAL *) (*pComArray)->GetDataPtr(); |
3883 | |
3884 | while (pOle < pOleEnd) |
3885 | IfFailThrow(VarCyFromDec(pCom++, pOle++)); |
3886 | } |
3887 | |
3888 | |
3889 | /* ------------------------------------------------------------------------- * |
3890 | * Variant marshaling routines |
3891 | * ------------------------------------------------------------------------- */ |
3892 | |
3893 | void OleVariant::MarshalVariantArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray, |
3894 | MethodTable *pInterfaceMT) |
3895 | { |
3896 | CONTRACTL |
3897 | { |
3898 | THROWS; |
3899 | GC_TRIGGERS; |
3900 | MODE_COOPERATIVE; |
3901 | PRECONDITION(CheckPointer(oleArray)); |
3902 | PRECONDITION(CheckPointer(pComArray)); |
3903 | } |
3904 | CONTRACTL_END; |
3905 | |
3906 | ASSERT_PROTECTED(pComArray); |
3907 | |
3908 | SIZE_T elementCount = (*pComArray)->GetNumComponents(); |
3909 | |
3910 | VARIANT *pOle = (VARIANT *) oleArray; |
3911 | VARIANT *pOleEnd = pOle + elementCount; |
3912 | |
3913 | BASEARRAYREF unprotectedArray = *pComArray; |
3914 | OBJECTREF *pCom = (OBJECTREF *) unprotectedArray->GetDataPtr(); |
3915 | |
3916 | AppDomain *pDomain = unprotectedArray->GetAppDomain(); |
3917 | |
3918 | OBJECTREF TmpObj = NULL; |
3919 | GCPROTECT_BEGIN(TmpObj) |
3920 | { |
3921 | while (pOle < pOleEnd) |
3922 | { |
3923 | // Marshal the OLE variant into a temp managed variant. |
3924 | MarshalObjectForOleVariant(pOle++, &TmpObj); |
3925 | |
3926 | // Reset pCom pointer only if array object has moved, rather than |
3927 | // recomputing it every time through the loop. Beware implicit calls to |
3928 | // ValidateObject inside OBJECTREF methods. |
3929 | if (*(void **)&unprotectedArray != *(void **)&*pComArray) |
3930 | { |
3931 | SIZE_T currentOffset = ((BYTE *)pCom) - (*(Object **) &unprotectedArray)->GetAddress(); |
3932 | unprotectedArray = *pComArray; |
3933 | pCom = (OBJECTREF *) (unprotectedArray->GetAddress() + currentOffset); |
3934 | } |
3935 | SetObjectReference(pCom++, TmpObj, pDomain); |
3936 | } |
3937 | } |
3938 | GCPROTECT_END(); |
3939 | } |
3940 | |
3941 | void OleVariant::MarshalVariantArrayComToOle(BASEARRAYREF *pComArray, void *oleArray, |
3942 | MethodTable *pInterfaceMT, BOOL fBestFitMapping, |
3943 | BOOL fThrowOnUnmappableChar, |
3944 | BOOL fOleArrayIsValid, SIZE_T cElements) |
3945 | { |
3946 | CONTRACTL |
3947 | { |
3948 | THROWS; |
3949 | GC_TRIGGERS; |
3950 | MODE_COOPERATIVE; |
3951 | PRECONDITION(CheckPointer(oleArray)); |
3952 | PRECONDITION(CheckPointer(pComArray)); |
3953 | } |
3954 | CONTRACTL_END; |
3955 | |
3956 | |
3957 | MarshalVariantArrayComToOle(pComArray, oleArray, pInterfaceMT, fBestFitMapping, fThrowOnUnmappableChar, FALSE, fOleArrayIsValid); |
3958 | } |
3959 | |
3960 | |
3961 | void OleVariant::MarshalVariantArrayComToOle(BASEARRAYREF *pComArray, void *oleArray, |
3962 | MethodTable *pInterfaceMT, BOOL fBestFitMapping, |
3963 | BOOL fThrowOnUnmappableChar, BOOL fMarshalByrefArgOnly, |
3964 | BOOL fOleArrayIsValid, int nOleArrayStepLength) |
3965 | { |
3966 | CONTRACTL |
3967 | { |
3968 | THROWS; |
3969 | GC_TRIGGERS; |
3970 | MODE_COOPERATIVE; |
3971 | PRECONDITION(CheckPointer(oleArray)); |
3972 | PRECONDITION(CheckPointer(pComArray)); |
3973 | } |
3974 | CONTRACTL_END; |
3975 | |
3976 | ASSERT_PROTECTED(pComArray); |
3977 | |
3978 | SIZE_T elementCount = (*pComArray)->GetNumComponents(); |
3979 | |
3980 | VARIANT *pOle = (VARIANT *) oleArray; |
3981 | VARIANT *pOleEnd = pOle + elementCount * nOleArrayStepLength; |
3982 | |
3983 | BASEARRAYREF unprotectedArray = *pComArray; |
3984 | OBJECTREF *pCom = (OBJECTREF *) unprotectedArray->GetDataPtr(); |
3985 | |
3986 | OBJECTREF TmpObj = NULL; |
3987 | GCPROTECT_BEGIN(TmpObj) |
3988 | { |
3989 | while (pOle != pOleEnd) |
3990 | { |
3991 | // Reset pCom pointer only if array object has moved, rather than |
3992 | // recomputing it every time through the loop. Beware implicit calls to |
3993 | // ValidateObject inside OBJECTREF methods. |
3994 | if (*(void **)&unprotectedArray != *(void **)&*pComArray) |
3995 | { |
3996 | SIZE_T currentOffset = ((BYTE *)pCom) - (*(Object **) &unprotectedArray)->GetAddress(); |
3997 | unprotectedArray = *pComArray; |
3998 | pCom = (OBJECTREF *) (unprotectedArray->GetAddress() + currentOffset); |
3999 | } |
4000 | TmpObj = *pCom++; |
4001 | |
4002 | // Marshal the temp managed variant into the OLE variant. |
4003 | if (fOleArrayIsValid) |
4004 | { |
4005 | // We firstly try MarshalCommonOleRefVariantForObject for VT_BYREF variant because |
4006 | // MarshalOleVariantForObject() VariantClear the variant and does not keep the VT_BYREF. |
4007 | // For back compating the old behavior(we used MarshalOleVariantForObject in the previous |
4008 | // version) that casts the managed object to Variant based on the object's MethodTable, |
4009 | // MarshalCommonOleRefVariantForObject is used instead of MarshalOleRefVariantForObject so |
4010 | // that cast will not be done based on the VT of the variant. |
4011 | if (!((pOle->vt & VT_BYREF) && |
4012 | SUCCEEDED(MarshalCommonOleRefVariantForObject(&TmpObj, pOle)))) |
4013 | if (pOle->vt & VT_BYREF || !fMarshalByrefArgOnly) |
4014 | MarshalOleVariantForObject(&TmpObj, pOle); |
4015 | } |
4016 | else |
4017 | { |
4018 | // The contents of pOle is undefined, don't try to handle byrefs. |
4019 | MarshalOleVariantForObject(&TmpObj, pOle); |
4020 | } |
4021 | |
4022 | pOle += nOleArrayStepLength; |
4023 | } |
4024 | } |
4025 | GCPROTECT_END(); |
4026 | } |
4027 | |
4028 | void OleVariant::ClearVariantArray(void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT) |
4029 | { |
4030 | CONTRACTL |
4031 | { |
4032 | NOTHROW; |
4033 | GC_TRIGGERS; |
4034 | MODE_ANY; |
4035 | PRECONDITION(CheckPointer(oleArray)); |
4036 | } |
4037 | CONTRACTL_END; |
4038 | |
4039 | VARIANT *pOle = (VARIANT *) oleArray; |
4040 | VARIANT *pOleEnd = pOle + cElements; |
4041 | |
4042 | while (pOle < pOleEnd) |
4043 | SafeVariantClear(pOle++); |
4044 | } |
4045 | |
4046 | |
4047 | /* ------------------------------------------------------------------------- * |
4048 | * Array marshaling routines |
4049 | * ------------------------------------------------------------------------- */ |
4050 | #ifdef FEATURE_CLASSIC_COMINTEROP |
4051 | |
4052 | void OleVariant::MarshalArrayVariantOleToCom(VARIANT *pOleVariant, |
4053 | VariantData *pComVariant) |
4054 | { |
4055 | CONTRACTL |
4056 | { |
4057 | THROWS; |
4058 | GC_TRIGGERS; |
4059 | MODE_COOPERATIVE; |
4060 | PRECONDITION(CheckPointer(pOleVariant)); |
4061 | PRECONDITION(CheckPointer(pComVariant)); |
4062 | } |
4063 | CONTRACTL_END; |
4064 | |
4065 | SAFEARRAY *pSafeArray = V_ARRAY(pOleVariant); |
4066 | |
4067 | VARTYPE vt = V_VT(pOleVariant) & ~VT_ARRAY; |
4068 | |
4069 | if (pSafeArray) |
4070 | { |
4071 | if (vt == VT_EMPTY) |
4072 | COMPlusThrow(kInvalidOleVariantTypeException, IDS_EE_INVALID_OLE_VARIANT); |
4073 | |
4074 | MethodTable *pElemMT = NULL; |
4075 | if (vt == VT_RECORD) |
4076 | pElemMT = GetElementTypeForRecordSafeArray(pSafeArray).GetMethodTable(); |
4077 | |
4078 | BASEARRAYREF pArrayRef = CreateArrayRefForSafeArray(pSafeArray, vt, pElemMT); |
4079 | pComVariant->SetObjRef((OBJECTREF) pArrayRef); |
4080 | MarshalArrayRefForSafeArray(pSafeArray, (BASEARRAYREF *) pComVariant->GetObjRefPtr(), vt, pElemMT); |
4081 | } |
4082 | else |
4083 | { |
4084 | pComVariant->SetObjRef(NULL); |
4085 | } |
4086 | } |
4087 | |
4088 | void OleVariant::MarshalArrayVariantComToOle(VariantData *pComVariant, |
4089 | VARIANT *pOleVariant) |
4090 | { |
4091 | CONTRACTL |
4092 | { |
4093 | THROWS; |
4094 | GC_TRIGGERS; |
4095 | MODE_COOPERATIVE; |
4096 | PRECONDITION(CheckPointer(pOleVariant)); |
4097 | PRECONDITION(CheckPointer(pComVariant)); |
4098 | } |
4099 | CONTRACTL_END; |
4100 | |
4101 | SafeArrayPtrHolder pSafeArray = NULL; |
4102 | BASEARRAYREF *pArrayRef = (BASEARRAYREF *) pComVariant->GetObjRefPtr(); |
4103 | MethodTable *pElemMT = NULL; |
4104 | |
4105 | _ASSERTE(pArrayRef); |
4106 | |
4107 | VARTYPE vt = GetElementVarTypeForArrayRef(*pArrayRef); |
4108 | if (vt == VT_ARRAY) |
4109 | vt = VT_VARIANT; |
4110 | |
4111 | pElemMT = GetArrayElementTypeWrapperAware(pArrayRef).GetMethodTable(); |
4112 | |
4113 | if (*pArrayRef != NULL) |
4114 | { |
4115 | pSafeArray = CreateSafeArrayForArrayRef(pArrayRef, vt, pElemMT); |
4116 | MarshalSafeArrayForArrayRef(pArrayRef, pSafeArray, vt, pElemMT); |
4117 | } |
4118 | V_ARRAY(pOleVariant) = pSafeArray; |
4119 | pSafeArray.SuppressRelease(); |
4120 | } |
4121 | |
4122 | void OleVariant::MarshalArrayVariantOleRefToCom(VARIANT *pOleVariant, |
4123 | VariantData *pComVariant) |
4124 | { |
4125 | CONTRACTL |
4126 | { |
4127 | THROWS; |
4128 | GC_TRIGGERS; |
4129 | MODE_COOPERATIVE; |
4130 | PRECONDITION(CheckPointer(pOleVariant)); |
4131 | PRECONDITION(CheckPointer(pComVariant)); |
4132 | } |
4133 | CONTRACTL_END; |
4134 | |
4135 | SAFEARRAY *pSafeArray = *V_ARRAYREF(pOleVariant); |
4136 | |
4137 | VARTYPE vt = V_VT(pOleVariant) & ~(VT_ARRAY|VT_BYREF); |
4138 | |
4139 | if (pSafeArray) |
4140 | { |
4141 | MethodTable *pElemMT = NULL; |
4142 | if (vt == VT_RECORD) |
4143 | pElemMT = GetElementTypeForRecordSafeArray(pSafeArray).GetMethodTable(); |
4144 | |
4145 | BASEARRAYREF pArrayRef = CreateArrayRefForSafeArray(pSafeArray, vt, pElemMT); |
4146 | pComVariant->SetObjRef((OBJECTREF) pArrayRef); |
4147 | MarshalArrayRefForSafeArray(pSafeArray, (BASEARRAYREF *) pComVariant->GetObjRefPtr(), vt, pElemMT); |
4148 | } |
4149 | else |
4150 | { |
4151 | pComVariant->SetObjRef(NULL); |
4152 | } |
4153 | } |
4154 | #endif //FEATURE_CLASSIC_COMINTEROP |
4155 | |
4156 | |
4157 | /* ------------------------------------------------------------------------- * |
4158 | * Error marshaling routines |
4159 | * ------------------------------------------------------------------------- */ |
4160 | |
4161 | void OleVariant::MarshalErrorVariantOleToCom(VARIANT *pOleVariant, |
4162 | VariantData *pComVariant) |
4163 | { |
4164 | CONTRACTL |
4165 | { |
4166 | NOTHROW; |
4167 | GC_NOTRIGGER; |
4168 | MODE_ANY; |
4169 | PRECONDITION(CheckPointer(pOleVariant)); |
4170 | PRECONDITION(CheckPointer(pComVariant)); |
4171 | } |
4172 | CONTRACTL_END; |
4173 | |
4174 | // Check to see if the variant represents a missing argument. |
4175 | if (V_ERROR(pOleVariant) == DISP_E_PARAMNOTFOUND) |
4176 | { |
4177 | pComVariant->SetType(CV_MISSING); |
4178 | } |
4179 | else |
4180 | { |
4181 | pComVariant->SetDataAsInt32(V_ERROR(pOleVariant)); |
4182 | } |
4183 | } |
4184 | |
4185 | void OleVariant::MarshalErrorVariantOleRefToCom(VARIANT *pOleVariant, |
4186 | VariantData *pComVariant) |
4187 | { |
4188 | CONTRACTL |
4189 | { |
4190 | NOTHROW; |
4191 | GC_NOTRIGGER; |
4192 | MODE_ANY; |
4193 | PRECONDITION(CheckPointer(pOleVariant)); |
4194 | PRECONDITION(CheckPointer(pComVariant)); |
4195 | } |
4196 | CONTRACTL_END; |
4197 | |
4198 | // Check to see if the variant represents a missing argument. |
4199 | if (*V_ERRORREF(pOleVariant) == DISP_E_PARAMNOTFOUND) |
4200 | { |
4201 | pComVariant->SetType(CV_MISSING); |
4202 | } |
4203 | else |
4204 | { |
4205 | pComVariant->SetDataAsInt32(*V_ERRORREF(pOleVariant)); |
4206 | } |
4207 | } |
4208 | |
4209 | void OleVariant::MarshalErrorVariantComToOle(VariantData *pComVariant, |
4210 | VARIANT *pOleVariant) |
4211 | { |
4212 | CONTRACTL |
4213 | { |
4214 | NOTHROW; |
4215 | GC_NOTRIGGER; |
4216 | MODE_ANY; |
4217 | PRECONDITION(CheckPointer(pOleVariant)); |
4218 | PRECONDITION(CheckPointer(pComVariant)); |
4219 | } |
4220 | CONTRACTL_END; |
4221 | |
4222 | if (pComVariant->GetType() == CV_MISSING) |
4223 | { |
4224 | V_ERROR(pOleVariant) = DISP_E_PARAMNOTFOUND; |
4225 | } |
4226 | else |
4227 | { |
4228 | V_ERROR(pOleVariant) = pComVariant->GetDataAsInt32(); |
4229 | } |
4230 | } |
4231 | |
4232 | |
4233 | /* ------------------------------------------------------------------------- * |
4234 | * Safearray allocation & conversion |
4235 | * ------------------------------------------------------------------------- */ |
4236 | |
4237 | // |
4238 | // CreateSafeArrayDescriptorForArrayRef creates a SAFEARRAY descriptor with the |
4239 | // appropriate type & dimensions for the given array ref. No memory is |
4240 | // allocated. |
4241 | // |
4242 | // This function is useful when you want to allocate the data specially using |
4243 | // a fixed buffer or pinning. |
4244 | // |
4245 | |
4246 | SAFEARRAY *OleVariant::CreateSafeArrayDescriptorForArrayRef(BASEARRAYREF *pArrayRef, VARTYPE vt, |
4247 | MethodTable *pInterfaceMT) |
4248 | { |
4249 | CONTRACT (SAFEARRAY*) |
4250 | { |
4251 | THROWS; |
4252 | GC_TRIGGERS; |
4253 | MODE_COOPERATIVE; |
4254 | PRECONDITION(CheckPointer(pArrayRef)); |
4255 | PRECONDITION(!(vt & VT_ARRAY)); |
4256 | POSTCONDITION(CheckPointer(RETVAL)); |
4257 | } |
4258 | CONTRACT_END; |
4259 | |
4260 | ASSERT_PROTECTED(pArrayRef); |
4261 | |
4262 | ULONG nElem = (*pArrayRef)->GetNumComponents(); |
4263 | ULONG nRank = (*pArrayRef)->GetRank(); |
4264 | |
4265 | SafeArrayPtrHolder pSafeArray = NULL; |
4266 | |
4267 | IfFailThrow(SafeArrayAllocDescriptorEx(vt, nRank, &pSafeArray)); |
4268 | |
4269 | switch (vt) |
4270 | { |
4271 | case VT_VARIANT: |
4272 | { |
4273 | // OleAut32.dll only sets FADF_HASVARTYPE, but VB says we also need to set |
4274 | // the FADF_VARIANT bit for this safearray to destruct properly. OleAut32 |
4275 | // doesn't want to change their code unless there's a strong reason, since |
4276 | // it's all "black magic" anyway. |
4277 | pSafeArray->fFeatures |= FADF_VARIANT; |
4278 | break; |
4279 | } |
4280 | |
4281 | case VT_BSTR: |
4282 | { |
4283 | pSafeArray->fFeatures |= FADF_BSTR; |
4284 | break; |
4285 | } |
4286 | |
4287 | case VT_UNKNOWN: |
4288 | { |
4289 | pSafeArray->fFeatures |= FADF_UNKNOWN; |
4290 | break; |
4291 | } |
4292 | |
4293 | case VT_DISPATCH: |
4294 | { |
4295 | pSafeArray->fFeatures |= FADF_DISPATCH; |
4296 | break; |
4297 | } |
4298 | |
4299 | case VT_RECORD: |
4300 | { |
4301 | pSafeArray->fFeatures |= FADF_RECORD; |
4302 | break; |
4303 | } |
4304 | } |
4305 | |
4306 | // |
4307 | // Fill in bounds |
4308 | // |
4309 | |
4310 | SAFEARRAYBOUND *bounds = pSafeArray->rgsabound; |
4311 | SAFEARRAYBOUND *boundsEnd = bounds + nRank; |
4312 | SIZE_T cElements; |
4313 | |
4314 | if (!(*pArrayRef)->IsMultiDimArray()) |
4315 | { |
4316 | bounds[0].cElements = nElem; |
4317 | bounds[0].lLbound = 0; |
4318 | cElements = nElem; |
4319 | } |
4320 | else |
4321 | { |
4322 | const INT32 *count = (*pArrayRef)->GetBoundsPtr() + nRank - 1; |
4323 | const INT32 *lower = (*pArrayRef)->GetLowerBoundsPtr() + nRank - 1; |
4324 | |
4325 | cElements = 1; |
4326 | while (bounds < boundsEnd) |
4327 | { |
4328 | bounds->lLbound = *lower--; |
4329 | bounds->cElements = *count--; |
4330 | cElements *= bounds->cElements; |
4331 | bounds++; |
4332 | } |
4333 | } |
4334 | |
4335 | pSafeArray->cbElements = (unsigned)GetElementSizeForVarType(vt, pInterfaceMT); |
4336 | |
4337 | // If the SAFEARRAY contains VT_RECORD's, then we need to set the |
4338 | // IRecordInfo. |
4339 | if (vt == VT_RECORD) |
4340 | { |
4341 | GCX_PREEMP(); |
4342 | |
4343 | SafeComHolder<ITypeInfo> pITI; |
4344 | SafeComHolder<IRecordInfo> pRecInfo; |
4345 | IfFailThrow(GetITypeInfoForEEClass(pInterfaceMT, &pITI)); |
4346 | IfFailThrow(GetRecordInfoFromTypeInfo(pITI, &pRecInfo)); |
4347 | IfFailThrow(SafeArraySetRecordInfo(pSafeArray, pRecInfo)); |
4348 | } |
4349 | |
4350 | pSafeArray.SuppressRelease(); |
4351 | RETURN pSafeArray; |
4352 | } |
4353 | |
4354 | // |
4355 | // CreateSafeArrayDescriptorForArrayRef creates a SAFEARRAY with the appropriate |
4356 | // type & dimensions & data for the given array ref. The data is initialized to |
4357 | // zero if necessary for safe destruction. |
4358 | // |
4359 | |
4360 | SAFEARRAY *OleVariant::CreateSafeArrayForArrayRef(BASEARRAYREF *pArrayRef, VARTYPE vt, |
4361 | MethodTable *pInterfaceMT) |
4362 | { |
4363 | CONTRACT (SAFEARRAY*) |
4364 | { |
4365 | THROWS; |
4366 | GC_TRIGGERS; |
4367 | MODE_COOPERATIVE; |
4368 | PRECONDITION(CheckPointer(pArrayRef)); |
4369 | // PRECONDITION(CheckPointer(*pArrayRef)); |
4370 | PRECONDITION(vt != VT_EMPTY); |
4371 | } |
4372 | CONTRACT_END; |
4373 | ASSERT_PROTECTED(pArrayRef); |
4374 | |
4375 | // Validate that the type of the managed array is the expected type. |
4376 | if (!IsValidArrayForSafeArrayElementType(pArrayRef, vt)) |
4377 | COMPlusThrow(kSafeArrayTypeMismatchException); |
4378 | |
4379 | // For structs and interfaces, verify that the array is of the valid type. |
4380 | if (vt == VT_RECORD || vt == VT_UNKNOWN || vt == VT_DISPATCH) |
4381 | { |
4382 | if (pInterfaceMT && !GetArrayElementTypeWrapperAware(pArrayRef).CanCastTo(TypeHandle(pInterfaceMT))) |
4383 | COMPlusThrow(kSafeArrayTypeMismatchException); |
4384 | } |
4385 | |
4386 | SAFEARRAY *pSafeArray = CreateSafeArrayDescriptorForArrayRef(pArrayRef, vt, pInterfaceMT); |
4387 | |
4388 | HRESULT hr = SafeArrayAllocData(pSafeArray); |
4389 | if (FAILED(hr)) |
4390 | { |
4391 | SafeArrayDestroy(pSafeArray); |
4392 | COMPlusThrowHR(hr); |
4393 | } |
4394 | |
4395 | RETURN pSafeArray; |
4396 | } |
4397 | |
4398 | // |
4399 | // CreateArrayRefForSafeArray creates an array object with the same layout and type |
4400 | // as the given safearray. The variant type of the safearray must be passed in. |
4401 | // The underlying element method table may also be specified (or NULL may be passed in |
4402 | // to use the base class method table for the VARTYPE. |
4403 | // |
4404 | |
4405 | BASEARRAYREF OleVariant::CreateArrayRefForSafeArray(SAFEARRAY *pSafeArray, VARTYPE vt, |
4406 | MethodTable *pElementMT) |
4407 | { |
4408 | CONTRACTL |
4409 | { |
4410 | THROWS; |
4411 | GC_TRIGGERS; |
4412 | MODE_COOPERATIVE; |
4413 | INJECT_FAULT(COMPlusThrowOM()); |
4414 | PRECONDITION(CheckPointer(pSafeArray)); |
4415 | PRECONDITION(vt != VT_EMPTY); |
4416 | } |
4417 | CONTRACTL_END; |
4418 | |
4419 | TypeHandle arrayType; |
4420 | INT32 *pAllocateArrayArgs; |
4421 | int cAllocateArrayArgs; |
4422 | int Rank; |
4423 | VARTYPE SafeArrayVT; |
4424 | |
4425 | // Validate that the type of the SAFEARRAY is the expected type. |
4426 | if (SUCCEEDED(ClrSafeArrayGetVartype(pSafeArray, &SafeArrayVT)) && (SafeArrayVT != VT_EMPTY)) |
4427 | { |
4428 | if ((SafeArrayVT != vt) && |
4429 | !(vt == VT_INT && SafeArrayVT == VT_I4) && |
4430 | !(vt == VT_UINT && SafeArrayVT == VT_UI4) && |
4431 | !(vt == VT_I4 && SafeArrayVT == VT_INT) && |
4432 | !(vt == VT_UI4 && SafeArrayVT == VT_UINT) && |
4433 | !(vt == VT_UNKNOWN && SafeArrayVT == VT_DISPATCH) && |
4434 | !(SafeArrayVT == VT_RECORD)) // Add this to allowed values as a VT_RECORD might represent a |
4435 | // valuetype with a single field that we'll just treat as a primitive type if possible. |
4436 | { |
4437 | COMPlusThrow(kSafeArrayTypeMismatchException); |
4438 | } |
4439 | } |
4440 | else |
4441 | { |
4442 | UINT ArrayElemSize = SafeArrayGetElemsize(pSafeArray); |
4443 | if (ArrayElemSize != GetElementSizeForVarType(vt, NULL)) |
4444 | { |
4445 | COMPlusThrow(kSafeArrayTypeMismatchException, IDS_EE_SAFEARRAYTYPEMISMATCH); |
4446 | } |
4447 | } |
4448 | |
4449 | // Determine if the input SAFEARRAY can be converted to an SZARRAY. |
4450 | if ((pSafeArray->cDims == 1) && (pSafeArray->rgsabound->lLbound == 0)) |
4451 | { |
4452 | // The SAFEARRAY maps to an SZARRAY. For SZARRAY's AllocateArrayEx() |
4453 | // expects the arguments to be a pointer to the cound of elements in the array |
4454 | // and the size of the args must be set to 1. |
4455 | Rank = 1; |
4456 | cAllocateArrayArgs = 1; |
4457 | pAllocateArrayArgs = (INT32 *) &pSafeArray->rgsabound[0].cElements; |
4458 | } |
4459 | else |
4460 | { |
4461 | // The SAFEARRAY maps to an general array. For general arrays AllocateArrayEx() |
4462 | // expects the arguments to be composed of the lower bounds / element count pairs |
4463 | // for each of the dimensions. We need to reverse the order that the lower bounds |
4464 | // and element pairs are presented before we call AllocateArrayEx(). |
4465 | Rank = pSafeArray->cDims; |
4466 | cAllocateArrayArgs = Rank * 2; |
4467 | pAllocateArrayArgs = (INT32*)_alloca(sizeof(INT32) * Rank * 2); |
4468 | INT32 * pBoundsPtr = pAllocateArrayArgs; |
4469 | |
4470 | // Copy the lower bounds and count of elements for the dimensions. These |
4471 | // need to copied in reverse order. |
4472 | for (int i = Rank - 1; i >= 0; i--) |
4473 | { |
4474 | *pBoundsPtr++ = pSafeArray->rgsabound[i].lLbound; |
4475 | *pBoundsPtr++ = pSafeArray->rgsabound[i].cElements; |
4476 | } |
4477 | } |
4478 | |
4479 | // Retrieve the type of the array. |
4480 | arrayType = GetArrayForVarType(vt, pElementMT, Rank); |
4481 | |
4482 | // Allocate the array. |
4483 | return (BASEARRAYREF) AllocateArrayEx(arrayType, pAllocateArrayArgs, cAllocateArrayArgs); |
4484 | } |
4485 | |
4486 | /* ------------------------------------------------------------------------- * |
4487 | * Safearray marshaling |
4488 | * ------------------------------------------------------------------------- */ |
4489 | |
4490 | // |
4491 | // MarshalSafeArrayForArrayRef marshals the contents of the array ref into the given |
4492 | // safe array. It is assumed that the type & dimensions of the arrays are compatible. |
4493 | // |
4494 | void OleVariant::MarshalSafeArrayForArrayRef(BASEARRAYREF *pArrayRef, |
4495 | SAFEARRAY *pSafeArray, |
4496 | VARTYPE vt, |
4497 | MethodTable *pInterfaceMT, |
4498 | BOOL fSafeArrayIsValid /*= TRUE*/) |
4499 | { |
4500 | CONTRACTL |
4501 | { |
4502 | THROWS; |
4503 | GC_TRIGGERS; |
4504 | MODE_COOPERATIVE; |
4505 | PRECONDITION(CheckPointer(pSafeArray)); |
4506 | PRECONDITION(CheckPointer(pArrayRef)); |
4507 | // PRECONDITION(CheckPointer(*pArrayRef)); |
4508 | PRECONDITION(vt != VT_EMPTY); |
4509 | } |
4510 | CONTRACTL_END; |
4511 | |
4512 | ASSERT_PROTECTED(pArrayRef); |
4513 | |
4514 | // Retrieve the size and number of components. |
4515 | SIZE_T dwComponentSize = GetElementSizeForVarType(vt, pInterfaceMT); |
4516 | SIZE_T dwNumComponents = (*pArrayRef)->GetNumComponents(); |
4517 | BASEARRAYREF Array = NULL; |
4518 | |
4519 | GCPROTECT_BEGIN(Array) |
4520 | { |
4521 | // Retrieve the marshaler to use to convert the contents. |
4522 | const Marshaler *marshal = GetMarshalerForVarType(vt, TRUE); |
4523 | |
4524 | // If the array is an array of wrappers, then we need to extract the objects |
4525 | // being wrapped and create an array of those. |
4526 | BOOL bArrayOfInterfaceWrappers; |
4527 | if (IsArrayOfWrappers(pArrayRef, &bArrayOfInterfaceWrappers)) |
4528 | { |
4529 | Array = ExtractWrappedObjectsFromArray(pArrayRef); |
4530 | } |
4531 | else |
4532 | { |
4533 | Array = *pArrayRef; |
4534 | } |
4535 | |
4536 | if (marshal == NULL || marshal->ComToOleArray == NULL) |
4537 | { |
4538 | if (pSafeArray->cDims == 1) |
4539 | { |
4540 | // If the array is single dimensionnal then we can simply copy it over. |
4541 | memcpyNoGCRefs(pSafeArray->pvData, Array->GetDataPtr(), dwNumComponents * dwComponentSize); |
4542 | } |
4543 | else |
4544 | { |
4545 | // Copy and transpose the data. |
4546 | TransposeArrayData((BYTE*)pSafeArray->pvData, Array->GetDataPtr(), dwNumComponents, dwComponentSize, pSafeArray, FALSE); |
4547 | } |
4548 | } |
4549 | else |
4550 | { |
4551 | { |
4552 | PinningHandleHolder handle = GetAppDomain()->CreatePinningHandle((OBJECTREF)Array); |
4553 | |
4554 | if (bArrayOfInterfaceWrappers) |
4555 | { |
4556 | _ASSERTE(vt == VT_UNKNOWN || vt == VT_DISPATCH); |
4557 | // Signal to code:OleVariant::MarshalInterfaceArrayComToOleHelper that this was an array |
4558 | // of UnknownWrapper or DispatchWrapper. It shall use a different logic and marshal each |
4559 | // element according to its specific default interface. |
4560 | pInterfaceMT = NULL; |
4561 | } |
4562 | marshal->ComToOleArray(&Array, pSafeArray->pvData, pInterfaceMT, TRUE, FALSE, fSafeArrayIsValid, dwNumComponents); |
4563 | } |
4564 | |
4565 | if (pSafeArray->cDims != 1) |
4566 | { |
4567 | // The array is multidimensionnal we need to transpose it. |
4568 | TransposeArrayData((BYTE*)pSafeArray->pvData, (BYTE*)pSafeArray->pvData, dwNumComponents, dwComponentSize, pSafeArray, FALSE); |
4569 | } |
4570 | } |
4571 | } |
4572 | GCPROTECT_END(); |
4573 | } |
4574 | |
4575 | // |
4576 | // MarshalArrayRefForSafeArray marshals the contents of the safe array into the given |
4577 | // array ref. It is assumed that the type & dimensions of the arrays are compatible. |
4578 | // |
4579 | |
4580 | void OleVariant::MarshalArrayRefForSafeArray(SAFEARRAY *pSafeArray, |
4581 | BASEARRAYREF *pArrayRef, |
4582 | VARTYPE vt, |
4583 | MethodTable *pInterfaceMT) |
4584 | { |
4585 | CONTRACTL |
4586 | { |
4587 | THROWS; |
4588 | GC_TRIGGERS; |
4589 | MODE_COOPERATIVE; |
4590 | PRECONDITION(CheckPointer(pSafeArray)); |
4591 | PRECONDITION(CheckPointer(pArrayRef)); |
4592 | PRECONDITION(*pArrayRef != NULL); |
4593 | PRECONDITION(vt != VT_EMPTY); |
4594 | } |
4595 | CONTRACTL_END; |
4596 | |
4597 | ASSERT_PROTECTED(pArrayRef); |
4598 | |
4599 | // Retrieve the number of components. |
4600 | SIZE_T dwNumComponents = (*pArrayRef)->GetNumComponents(); |
4601 | |
4602 | // Retrieve the marshaler to use to convert the contents. |
4603 | const Marshaler *marshal = GetMarshalerForVarType(vt, TRUE); |
4604 | |
4605 | if (marshal == NULL || marshal->OleToComArray == NULL) |
4606 | { |
4607 | SIZE_T dwManagedComponentSize = (*pArrayRef)->GetComponentSize(); |
4608 | |
4609 | #ifdef _DEBUG |
4610 | { |
4611 | // If we're blasting bits, this better be a primitive type. Currency is |
4612 | // an I8 on managed & unmanaged, so it's good enough. |
4613 | TypeHandle th = (*pArrayRef)->GetArrayElementTypeHandle(); |
4614 | |
4615 | if (!CorTypeInfo::IsPrimitiveType(th.GetInternalCorElementType())) |
4616 | { |
4617 | _ASSERTE(!strcmp(th.AsMethodTable()->GetDebugClassName(), |
4618 | "System.Currency" )); |
4619 | } |
4620 | } |
4621 | #endif |
4622 | if (pSafeArray->cDims == 1) |
4623 | { |
4624 | // If the array is single dimensionnal then we can simply copy it over. |
4625 | memcpyNoGCRefs((*pArrayRef)->GetDataPtr(), pSafeArray->pvData, dwNumComponents * dwManagedComponentSize); |
4626 | } |
4627 | else |
4628 | { |
4629 | // Copy and transpose the data. |
4630 | TransposeArrayData((*pArrayRef)->GetDataPtr(), (BYTE*)pSafeArray->pvData, dwNumComponents, dwManagedComponentSize, pSafeArray, TRUE); |
4631 | } |
4632 | } |
4633 | else |
4634 | { |
4635 | CQuickArray<BYTE> TmpArray; |
4636 | BYTE* pSrcData = NULL; |
4637 | SIZE_T dwNativeComponentSize = GetElementSizeForVarType(vt, pInterfaceMT); |
4638 | |
4639 | if (pSafeArray->cDims != 1) |
4640 | { |
4641 | TmpArray.ReSizeThrows(dwNumComponents * dwNativeComponentSize); |
4642 | pSrcData = TmpArray.Ptr(); |
4643 | TransposeArrayData(pSrcData, (BYTE*)pSafeArray->pvData, dwNumComponents, dwNativeComponentSize, pSafeArray, TRUE); |
4644 | } |
4645 | else |
4646 | { |
4647 | pSrcData = (BYTE*)pSafeArray->pvData; |
4648 | } |
4649 | |
4650 | PinningHandleHolder handle = GetAppDomain()->CreatePinningHandle((OBJECTREF)*pArrayRef); |
4651 | |
4652 | marshal->OleToComArray(pSrcData, pArrayRef, pInterfaceMT); |
4653 | } |
4654 | } |
4655 | |
4656 | void OleVariant::ConvertValueClassToVariant(OBJECTREF *pBoxedValueClass, VARIANT *pOleVariant) |
4657 | { |
4658 | CONTRACTL |
4659 | { |
4660 | THROWS; |
4661 | GC_TRIGGERS; |
4662 | MODE_COOPERATIVE; |
4663 | PRECONDITION(CheckPointer(pBoxedValueClass)); |
4664 | PRECONDITION(CheckPointer(pOleVariant)); |
4665 | } |
4666 | CONTRACTL_END; |
4667 | |
4668 | HRESULT hr = S_OK; |
4669 | SafeComHolder<ITypeInfo> pTypeInfo = NULL; |
4670 | RecordVariantHolder pRecHolder = pOleVariant; |
4671 | |
4672 | BOOL bSuccess = FALSE; |
4673 | |
4674 | // Initialize the OLE variant's VT_RECORD fields to NULL. |
4675 | V_RECORDINFO(pRecHolder) = NULL; |
4676 | V_RECORD(pRecHolder) = NULL; |
4677 | |
4678 | // Retrieve the ITypeInfo for the value class. |
4679 | MethodTable *pValueClassMT = (*pBoxedValueClass)->GetMethodTable(); |
4680 | IfFailThrow(GetITypeInfoForEEClass(pValueClassMT, &pTypeInfo, true /* bClassInfo */)); |
4681 | |
4682 | // Convert the ITypeInfo to an IRecordInfo. |
4683 | hr = GetRecordInfoFromTypeInfo(pTypeInfo, &V_RECORDINFO(pRecHolder)); |
4684 | if (FAILED(hr)) |
4685 | { |
4686 | // An HRESULT of TYPE_E_UNSUPFORMAT really means that the struct contains |
4687 | // fields that aren't supported inside a OLEAUT record. |
4688 | if (TYPE_E_UNSUPFORMAT == hr) |
4689 | COMPlusThrow(kArgumentException, IDS_EE_RECORD_NON_SUPPORTED_FIELDS); |
4690 | else |
4691 | COMPlusThrowHR(hr); |
4692 | } |
4693 | |
4694 | // Allocate an instance of the record. |
4695 | V_RECORD(pRecHolder) = V_RECORDINFO(pRecHolder)->RecordCreate(); |
4696 | IfNullThrow(V_RECORD(pRecHolder)); |
4697 | |
4698 | // Marshal the contents of the value class into the record. |
4699 | FmtClassUpdateNative(pBoxedValueClass, (BYTE*)V_RECORD(pRecHolder), NULL); |
4700 | |
4701 | pRecHolder.SuppressRelease(); |
4702 | } |
4703 | |
4704 | void OleVariant::TransposeArrayData(BYTE *pDestData, BYTE *pSrcData, SIZE_T dwNumComponents, SIZE_T dwComponentSize, SAFEARRAY *pSafeArray, BOOL bSafeArrayToMngArray) |
4705 | { |
4706 | CONTRACTL |
4707 | { |
4708 | THROWS; |
4709 | GC_TRIGGERS; |
4710 | MODE_COOPERATIVE; |
4711 | INJECT_FAULT(COMPlusThrowOM()); |
4712 | PRECONDITION(CheckPointer(pDestData)); |
4713 | PRECONDITION(CheckPointer(pSrcData)); |
4714 | PRECONDITION(CheckPointer(pSafeArray)); |
4715 | } |
4716 | CONTRACTL_END; |
4717 | |
4718 | int iDims; |
4719 | DWORD *aDestElemCount = (DWORD*)_alloca(pSafeArray->cDims * sizeof(DWORD)); |
4720 | DWORD *aDestIndex = (DWORD*)_alloca(pSafeArray->cDims * sizeof(DWORD)); |
4721 | BYTE **aDestDataPos = (BYTE **)_alloca(pSafeArray->cDims * sizeof(BYTE *)); |
4722 | SIZE_T *aDestDelta = (SIZE_T*)_alloca(pSafeArray->cDims * sizeof(SIZE_T)); |
4723 | CQuickArray<BYTE> TmpArray; |
4724 | |
4725 | // If there are no components, then there we are done. |
4726 | if (dwNumComponents == 0) |
4727 | return; |
4728 | |
4729 | // Check to see if we are transposing in place or copying and transposing. |
4730 | if (pSrcData == pDestData) |
4731 | { |
4732 | TmpArray.ReSizeThrows(dwNumComponents * dwComponentSize); |
4733 | memcpyNoGCRefs(TmpArray.Ptr(), pSrcData, dwNumComponents * dwComponentSize); |
4734 | pSrcData = TmpArray.Ptr(); |
4735 | } |
4736 | |
4737 | // Copy the element count in reverse order if we are copying from a safe array to |
4738 | // a managed array and in direct order otherwise. |
4739 | if (bSafeArrayToMngArray) |
4740 | { |
4741 | for (iDims = 0; iDims < pSafeArray->cDims; iDims++) |
4742 | aDestElemCount[iDims] = pSafeArray->rgsabound[pSafeArray->cDims - iDims - 1].cElements; |
4743 | } |
4744 | else |
4745 | { |
4746 | for (iDims = 0; iDims < pSafeArray->cDims; iDims++) |
4747 | aDestElemCount[iDims] = pSafeArray->rgsabound[iDims].cElements; |
4748 | } |
4749 | |
4750 | // Initalize the indexes for each dimension to 0. |
4751 | memset(aDestIndex, 0, pSafeArray->cDims * sizeof(int)); |
4752 | |
4753 | // Set all the destination data positions to the start of the array. |
4754 | for (iDims = 0; iDims < pSafeArray->cDims; iDims++) |
4755 | aDestDataPos[iDims] = (BYTE*)pDestData; |
4756 | |
4757 | // Calculate the destination delta for each of the dimensions. |
4758 | aDestDelta[pSafeArray->cDims - 1] = dwComponentSize; |
4759 | for (iDims = pSafeArray->cDims - 2; iDims >= 0; iDims--) |
4760 | aDestDelta[iDims] = aDestDelta[iDims + 1] * aDestElemCount[iDims + 1]; |
4761 | |
4762 | // Calculate the source data end pointer. |
4763 | BYTE *pSrcDataEnd = pSrcData + dwNumComponents * dwComponentSize; |
4764 | _ASSERTE(pDestData < pSrcData || pDestData >= pSrcDataEnd); |
4765 | |
4766 | // Copy and transpose the data. |
4767 | while (TRUE) |
4768 | { |
4769 | // Copy one component. |
4770 | memcpyNoGCRefs(aDestDataPos[0], pSrcData, dwComponentSize); |
4771 | |
4772 | // Update the source position. |
4773 | pSrcData += dwComponentSize; |
4774 | |
4775 | // Check to see if we have reached the end of the array. |
4776 | if (pSrcData >= pSrcDataEnd) |
4777 | break; |
4778 | |
4779 | // Update the destination position. |
4780 | for (iDims = 0; aDestIndex[iDims] >= aDestElemCount[iDims] - 1; iDims++); |
4781 | |
4782 | _ASSERTE(iDims < pSafeArray->cDims); |
4783 | |
4784 | aDestIndex[iDims]++; |
4785 | aDestDataPos[iDims] += aDestDelta[iDims]; |
4786 | for (--iDims; iDims >= 0; iDims--) |
4787 | { |
4788 | aDestIndex[iDims] = 0; |
4789 | aDestDataPos[iDims] = aDestDataPos[iDims + 1]; |
4790 | } |
4791 | } |
4792 | } |
4793 | |
4794 | BOOL OleVariant::IsArrayOfWrappers(BASEARRAYREF *pArray, BOOL *pbOfInterfaceWrappers) |
4795 | { |
4796 | CONTRACTL |
4797 | { |
4798 | THROWS; |
4799 | GC_TRIGGERS; |
4800 | MODE_ANY; |
4801 | } |
4802 | CONTRACTL_END; |
4803 | |
4804 | TypeHandle hndElemType = (*pArray)->GetArrayElementTypeHandle(); |
4805 | |
4806 | if (!hndElemType.IsTypeDesc()) |
4807 | { |
4808 | if (hndElemType == TypeHandle(MscorlibBinder::GetClass(CLASS__DISPATCH_WRAPPER)) || |
4809 | hndElemType == TypeHandle(MscorlibBinder::GetClass(CLASS__UNKNOWN_WRAPPER))) |
4810 | { |
4811 | *pbOfInterfaceWrappers = TRUE; |
4812 | return TRUE; |
4813 | } |
4814 | |
4815 | if (hndElemType == TypeHandle(MscorlibBinder::GetClass(CLASS__ERROR_WRAPPER)) || |
4816 | hndElemType == TypeHandle(MscorlibBinder::GetClass(CLASS__CURRENCY_WRAPPER)) || |
4817 | hndElemType == TypeHandle(MscorlibBinder::GetClass(CLASS__BSTR_WRAPPER))) |
4818 | { |
4819 | *pbOfInterfaceWrappers = FALSE; |
4820 | return TRUE; |
4821 | } |
4822 | } |
4823 | |
4824 | *pbOfInterfaceWrappers = FALSE; |
4825 | return FALSE; |
4826 | } |
4827 | |
4828 | BASEARRAYREF OleVariant::ExtractWrappedObjectsFromArray(BASEARRAYREF *pArray) |
4829 | { |
4830 | CONTRACTL |
4831 | { |
4832 | THROWS; |
4833 | GC_TRIGGERS; |
4834 | MODE_COOPERATIVE; |
4835 | PRECONDITION(CheckPointer(pArray)); |
4836 | } |
4837 | CONTRACTL_END; |
4838 | |
4839 | TypeHandle hndWrapperType = (*pArray)->GetArrayElementTypeHandle(); |
4840 | TypeHandle hndElemType; |
4841 | TypeHandle hndArrayType; |
4842 | BOOL bIsMDArray = (*pArray)->IsMultiDimArray(); |
4843 | unsigned rank = (*pArray)->GetRank(); |
4844 | BASEARRAYREF RetArray = NULL; |
4845 | |
4846 | // Retrieve the element type handle for the array to create. |
4847 | if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__DISPATCH_WRAPPER))) |
4848 | hndElemType = TypeHandle(g_pObjectClass); |
4849 | |
4850 | else if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__UNKNOWN_WRAPPER))) |
4851 | hndElemType = TypeHandle(g_pObjectClass); |
4852 | |
4853 | else if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__BSTR_WRAPPER))) |
4854 | hndElemType = TypeHandle(g_pStringClass); |
4855 | |
4856 | else if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__ERROR_WRAPPER))) |
4857 | hndElemType = TypeHandle(MscorlibBinder::GetClass(CLASS__INT32)); |
4858 | |
4859 | else if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__CURRENCY_WRAPPER))) |
4860 | hndElemType = TypeHandle(MscorlibBinder::GetClass(CLASS__DECIMAL)); |
4861 | |
4862 | else |
4863 | _ASSERTE(!"Invalid wrapper type" ); |
4864 | |
4865 | // Retrieve the type handle that represents the array. |
4866 | if (bIsMDArray) |
4867 | { |
4868 | hndArrayType = ClassLoader::LoadArrayTypeThrowing(hndElemType, ELEMENT_TYPE_ARRAY, rank); |
4869 | } |
4870 | else |
4871 | { |
4872 | hndArrayType = ClassLoader::LoadArrayTypeThrowing(hndElemType, ELEMENT_TYPE_SZARRAY); |
4873 | } |
4874 | _ASSERTE(!hndArrayType.IsNull()); |
4875 | |
4876 | // Set up the bounds arguments. |
4877 | DWORD numArgs = rank*2; |
4878 | INT32* args = (INT32*) _alloca(sizeof(INT32)*numArgs); |
4879 | |
4880 | if (bIsMDArray) |
4881 | { |
4882 | const INT32* bounds = (*pArray)->GetBoundsPtr(); |
4883 | const INT32* lowerBounds = (*pArray)->GetLowerBoundsPtr(); |
4884 | for(unsigned int i=0; i < rank; i++) |
4885 | { |
4886 | args[2*i] = lowerBounds[i]; |
4887 | args[2*i+1] = bounds[i]; |
4888 | } |
4889 | } |
4890 | else |
4891 | { |
4892 | numArgs = 1; |
4893 | args[0] = (*pArray)->GetNumComponents(); |
4894 | } |
4895 | |
4896 | // Extract the values from the source array and copy them into the destination array. |
4897 | BASEARRAYREF DestArray = (BASEARRAYREF)AllocateArrayEx(hndArrayType, args, numArgs); |
4898 | GCPROTECT_BEGIN(DestArray) |
4899 | { |
4900 | SIZE_T NumComponents = (*pArray)->GetNumComponents(); |
4901 | AppDomain *pDomain = DestArray->GetAppDomain(); |
4902 | |
4903 | if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__DISPATCH_WRAPPER))) |
4904 | { |
4905 | DISPATCHWRAPPEROBJECTREF *pSrc = (DISPATCHWRAPPEROBJECTREF *)(*pArray)->GetDataPtr(); |
4906 | DISPATCHWRAPPEROBJECTREF *pSrcEnd = pSrc + NumComponents; |
4907 | OBJECTREF *pDest = (OBJECTREF *)DestArray->GetDataPtr(); |
4908 | for (; pSrc < pSrcEnd; pSrc++, pDest++) |
4909 | SetObjectReference(pDest, (*pSrc) != NULL ? (*pSrc)->GetWrappedObject() : NULL, pDomain); |
4910 | } |
4911 | else if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__UNKNOWN_WRAPPER))) |
4912 | { |
4913 | UNKNOWNWRAPPEROBJECTREF *pSrc = (UNKNOWNWRAPPEROBJECTREF *)(*pArray)->GetDataPtr(); |
4914 | UNKNOWNWRAPPEROBJECTREF *pSrcEnd = pSrc + NumComponents; |
4915 | OBJECTREF *pDest = (OBJECTREF *)DestArray->GetDataPtr(); |
4916 | for (; pSrc < pSrcEnd; pSrc++, pDest++) |
4917 | SetObjectReference(pDest, (*pSrc) != NULL ? (*pSrc)->GetWrappedObject() : NULL, pDomain); |
4918 | } |
4919 | else if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__ERROR_WRAPPER))) |
4920 | { |
4921 | ERRORWRAPPEROBJECTREF *pSrc = (ERRORWRAPPEROBJECTREF *)(*pArray)->GetDataPtr(); |
4922 | ERRORWRAPPEROBJECTREF *pSrcEnd = pSrc + NumComponents; |
4923 | INT32 *pDest = (INT32 *)DestArray->GetDataPtr(); |
4924 | for (; pSrc < pSrcEnd; pSrc++, pDest++) |
4925 | *pDest = (*pSrc) != NULL ? (*pSrc)->GetErrorCode() : NULL; |
4926 | } |
4927 | else if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__CURRENCY_WRAPPER))) |
4928 | { |
4929 | CURRENCYWRAPPEROBJECTREF *pSrc = (CURRENCYWRAPPEROBJECTREF *)(*pArray)->GetDataPtr(); |
4930 | CURRENCYWRAPPEROBJECTREF *pSrcEnd = pSrc + NumComponents; |
4931 | DECIMAL *pDest = (DECIMAL *)DestArray->GetDataPtr(); |
4932 | for (; pSrc < pSrcEnd; pSrc++, pDest++) |
4933 | { |
4934 | if (*pSrc != NULL) |
4935 | memcpyNoGCRefs(pDest, &(*pSrc)->GetWrappedObject(), sizeof(DECIMAL)); |
4936 | else |
4937 | memset(pDest, 0, sizeof(DECIMAL)); |
4938 | } |
4939 | } |
4940 | else if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__BSTR_WRAPPER))) |
4941 | { |
4942 | BSTRWRAPPEROBJECTREF *pSrc = (BSTRWRAPPEROBJECTREF *)(*pArray)->GetDataPtr(); |
4943 | BSTRWRAPPEROBJECTREF *pSrcEnd = pSrc + NumComponents; |
4944 | OBJECTREF *pDest = (OBJECTREF *)DestArray->GetDataPtr(); |
4945 | for (; pSrc < pSrcEnd; pSrc++, pDest++) |
4946 | SetObjectReference(pDest, (*pSrc) != NULL ? (*pSrc)->GetWrappedObject() : NULL, pDomain); |
4947 | } |
4948 | else |
4949 | { |
4950 | _ASSERTE(!"Invalid wrapper type" ); |
4951 | } |
4952 | |
4953 | // GCPROTECT_END() will wack NewArray so we need to copy the OBJECTREF into |
4954 | // a temp to be able to return it. |
4955 | RetArray = DestArray; |
4956 | } |
4957 | GCPROTECT_END(); |
4958 | |
4959 | return RetArray; |
4960 | } |
4961 | |
4962 | TypeHandle OleVariant::GetWrappedArrayElementType(BASEARRAYREF *pArray) |
4963 | { |
4964 | CONTRACTL |
4965 | { |
4966 | THROWS; |
4967 | GC_TRIGGERS; |
4968 | MODE_COOPERATIVE; |
4969 | PRECONDITION(CheckPointer(pArray)); |
4970 | } |
4971 | CONTRACTL_END; |
4972 | |
4973 | TypeHandle hndWrapperType = (*pArray)->GetArrayElementTypeHandle(); |
4974 | TypeHandle pWrappedObjType; |
4975 | |
4976 | if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__DISPATCH_WRAPPER)) || |
4977 | hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__UNKNOWN_WRAPPER))) |
4978 | { |
4979 | // There's no need to traverse the array up front. We'll use the default interface |
4980 | // for each element in code:OleVariant::MarshalInterfaceArrayComToOleHelper. |
4981 | pWrappedObjType = TypeHandle(g_pObjectClass); |
4982 | } |
4983 | else if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__ERROR_WRAPPER))) |
4984 | { |
4985 | pWrappedObjType = TypeHandle(MscorlibBinder::GetClass(CLASS__INT32)); |
4986 | } |
4987 | else if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__CURRENCY_WRAPPER))) |
4988 | { |
4989 | pWrappedObjType = TypeHandle(MscorlibBinder::GetClass(CLASS__DECIMAL)); |
4990 | } |
4991 | else if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__BSTR_WRAPPER))) |
4992 | { |
4993 | pWrappedObjType = TypeHandle(g_pStringClass); |
4994 | } |
4995 | else |
4996 | { |
4997 | _ASSERTE(!"Invalid wrapper type" ); |
4998 | } |
4999 | |
5000 | return pWrappedObjType; |
5001 | } |
5002 | |
5003 | |
5004 | TypeHandle OleVariant::GetArrayElementTypeWrapperAware(BASEARRAYREF *pArray) |
5005 | { |
5006 | CONTRACTL |
5007 | { |
5008 | THROWS; |
5009 | GC_TRIGGERS; |
5010 | MODE_ANY; |
5011 | PRECONDITION(CheckPointer(pArray)); |
5012 | } |
5013 | CONTRACTL_END; |
5014 | |
5015 | BOOL bArrayOfInterfaceWrappers; |
5016 | if (IsArrayOfWrappers(pArray, &bArrayOfInterfaceWrappers)) |
5017 | { |
5018 | return GetWrappedArrayElementType(pArray); |
5019 | } |
5020 | else |
5021 | { |
5022 | return (*pArray)->GetArrayElementTypeHandle(); |
5023 | } |
5024 | } |
5025 | |
5026 | #ifdef FEATURE_CLASSIC_COMINTEROP |
5027 | TypeHandle OleVariant::GetElementTypeForRecordSafeArray(SAFEARRAY* pSafeArray) |
5028 | { |
5029 | CONTRACTL |
5030 | { |
5031 | THROWS; |
5032 | GC_TRIGGERS; |
5033 | MODE_COOPERATIVE; |
5034 | PRECONDITION(CheckPointer(pSafeArray)); |
5035 | } |
5036 | CONTRACTL_END; |
5037 | |
5038 | HRESULT hr = S_OK; |
5039 | |
5040 | GUID guid; |
5041 | { |
5042 | GCX_PREEMP(); |
5043 | |
5044 | SafeComHolder<IRecordInfo> pRecInfo; |
5045 | IfFailThrow(SafeArrayGetRecordInfo(pSafeArray, &pRecInfo)); |
5046 | IfFailThrow(pRecInfo->GetGuid(&guid)); |
5047 | } |
5048 | MethodTable *pValueClass = GetValueTypeForGUID(guid); |
5049 | if (!pValueClass) |
5050 | COMPlusThrow(kArgumentException, IDS_EE_CANNOT_MAP_TO_MANAGED_VC); |
5051 | |
5052 | return TypeHandle(pValueClass); |
5053 | } |
5054 | #endif //FEATURE_CLASSIC_COMINTEROP |
5055 | |
5056 | void OleVariant::AllocateEmptyStringForBSTR(BSTR bstr, STRINGREF *pStringObj) |
5057 | { |
5058 | CONTRACTL |
5059 | { |
5060 | THROWS; |
5061 | GC_TRIGGERS; |
5062 | MODE_COOPERATIVE; |
5063 | PRECONDITION(CheckPointer(bstr)); |
5064 | PRECONDITION(CheckPointer(pStringObj)); |
5065 | } |
5066 | CONTRACTL_END; |
5067 | |
5068 | // The BSTR isn't null so allocate a managed string of the appropriate length. |
5069 | ULONG length = SysStringByteLen(bstr); |
5070 | |
5071 | if (length > MAX_SIZE_FOR_INTEROP) |
5072 | COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG); |
5073 | |
5074 | // Check to see if the BSTR has trailing odd byte. |
5075 | BOOL bHasTrailByte = ((length%sizeof(WCHAR)) != 0); |
5076 | length = length / sizeof(WCHAR); |
5077 | SetObjectReference((OBJECTREF*)pStringObj, (OBJECTREF)StringObject::NewString(length, bHasTrailByte), GetAppDomain()); |
5078 | } |
5079 | |
5080 | void OleVariant::ConvertContentsBSTRToString(BSTR bstr, STRINGREF *pStringObj) |
5081 | { |
5082 | CONTRACTL |
5083 | { |
5084 | THROWS; |
5085 | GC_TRIGGERS; |
5086 | MODE_COOPERATIVE; |
5087 | PRECONDITION(CheckPointer(bstr)); |
5088 | PRECONDITION(CheckPointer(pStringObj)); |
5089 | } |
5090 | CONTRACTL_END; |
5091 | |
5092 | // this is the right thing to do, but sometimes we |
5093 | // end up thinking we're marshaling a BSTR when we're not, because |
5094 | // it's the default type. |
5095 | ULONG length = SysStringByteLen((BSTR)bstr); |
5096 | if (length > MAX_SIZE_FOR_INTEROP) |
5097 | COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG); |
5098 | |
5099 | ULONG charLength = length/sizeof(WCHAR); |
5100 | BOOL hasTrailByte = (length%sizeof(WCHAR) != 0); |
5101 | |
5102 | memcpyNoGCRefs((*pStringObj)->GetBuffer(), bstr, charLength*sizeof(WCHAR)); |
5103 | |
5104 | if (hasTrailByte) |
5105 | { |
5106 | BYTE* buff = (BYTE*)bstr; |
5107 | //set the trail byte |
5108 | (*pStringObj)->SetTrailByte(buff[length-1]); |
5109 | } |
5110 | |
5111 | // null terminate the StringRef |
5112 | WCHAR* wstr = (WCHAR *)(*pStringObj)->GetBuffer(); |
5113 | wstr[charLength] = '\0'; |
5114 | } |
5115 | |
5116 | void OleVariant::ConvertBSTRToString(BSTR bstr, STRINGREF *pStringObj) |
5117 | { |
5118 | CONTRACTL |
5119 | { |
5120 | THROWS; |
5121 | GC_TRIGGERS; |
5122 | MODE_COOPERATIVE; |
5123 | PRECONDITION(CheckPointer(bstr, NULL_OK)); |
5124 | PRECONDITION(CheckPointer(pStringObj)); |
5125 | } |
5126 | CONTRACTL_END; |
5127 | |
5128 | // Initialize the output string object to null to start. |
5129 | *pStringObj = NULL; |
5130 | |
5131 | // If the BSTR is null then we leave the output string object set to null. |
5132 | if (bstr == NULL) |
5133 | return; |
5134 | |
5135 | AllocateEmptyStringForBSTR(bstr, pStringObj); |
5136 | ConvertContentsBSTRToString(bstr, pStringObj); |
5137 | } |
5138 | |
5139 | BSTR OleVariant::AllocateEmptyBSTRForString(STRINGREF *pStringObj) |
5140 | { |
5141 | CONTRACT(BSTR) |
5142 | { |
5143 | THROWS; |
5144 | GC_NOTRIGGER; |
5145 | MODE_COOPERATIVE; |
5146 | PRECONDITION(CheckPointer(pStringObj)); |
5147 | PRECONDITION(*pStringObj != NULL); |
5148 | POSTCONDITION(RETVAL != NULL); |
5149 | } |
5150 | CONTRACT_END; |
5151 | |
5152 | ULONG length = (*pStringObj)->GetStringLength(); |
5153 | if (length > MAX_SIZE_FOR_INTEROP) |
5154 | COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG); |
5155 | |
5156 | length = length*sizeof(WCHAR); |
5157 | if ((*pStringObj)->HasTrailByte()) |
5158 | { |
5159 | length += 1; |
5160 | } |
5161 | BSTR bstr = SysAllocStringByteLen(NULL, length); |
5162 | if (bstr == NULL) |
5163 | ThrowOutOfMemory(); |
5164 | |
5165 | RETURN bstr; |
5166 | } |
5167 | |
5168 | void OleVariant::ConvertContentsStringToBSTR(STRINGREF *pStringObj, BSTR bstr) |
5169 | { |
5170 | CONTRACTL |
5171 | { |
5172 | THROWS; |
5173 | GC_NOTRIGGER; |
5174 | MODE_COOPERATIVE; |
5175 | PRECONDITION(CheckPointer(pStringObj)); |
5176 | PRECONDITION(*pStringObj != NULL); |
5177 | PRECONDITION(CheckPointer(bstr)); |
5178 | } |
5179 | CONTRACTL_END; |
5180 | |
5181 | DWORD length = (DWORD)(*pStringObj)->GetStringLength(); |
5182 | if (length > MAX_SIZE_FOR_INTEROP) |
5183 | COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG); |
5184 | |
5185 | BYTE *buff = (BYTE*)bstr; |
5186 | ULONG byteLen = length * sizeof(WCHAR); |
5187 | |
5188 | memcpyNoGCRefs(bstr, (*pStringObj)->GetBuffer(), byteLen); |
5189 | |
5190 | if ((*pStringObj)->HasTrailByte()) |
5191 | { |
5192 | BYTE b; |
5193 | BOOL hasTrailB; |
5194 | hasTrailB = (*pStringObj)->GetTrailByte(&b); |
5195 | _ASSERTE(hasTrailB); |
5196 | buff[byteLen] = b; |
5197 | } |
5198 | else |
5199 | { |
5200 | // copy the null terminator |
5201 | bstr[length] = W('\0'); |
5202 | } |
5203 | } |
5204 | |
5205 | BSTR OleVariant::ConvertStringToBSTR(STRINGREF *pStringObj) |
5206 | { |
5207 | CONTRACT(BSTR) |
5208 | { |
5209 | THROWS; |
5210 | GC_NOTRIGGER; |
5211 | MODE_COOPERATIVE; |
5212 | PRECONDITION(CheckPointer(pStringObj)); |
5213 | |
5214 | // A null BSTR should only be returned if the input string is null. |
5215 | POSTCONDITION(RETVAL != NULL || *pStringObj == NULL); |
5216 | } |
5217 | CONTRACT_END; |
5218 | |
5219 | // Initiatilize the return BSTR value to null. |
5220 | BSTR bstr = NULL; |
5221 | |
5222 | // If the string object isn't null then we convert it to a BSTR. Otherwise we will return null. |
5223 | if (*pStringObj != NULL) |
5224 | { |
5225 | bstr = AllocateEmptyBSTRForString(pStringObj); |
5226 | ConvertContentsStringToBSTR(pStringObj, bstr); |
5227 | } |
5228 | |
5229 | RETURN bstr; |
5230 | } |
5231 | #endif // FEATURE_COMINTEROP |
5232 | |
5233 | #endif // CROSSGEN_COMPILE |
5234 | |