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.
40const 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.
72CVTypes 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
89VARTYPE 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
143CVTypes 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//
215VARTYPE 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
287VARTYPE 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
418VARTYPE 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
434BOOL 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
491TypeHandle 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
722UINT 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
803const 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 {
839VariantArray:
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==============================================================================*/
1048void 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
1113void 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
1123class OutOfMemoryException;
1124
1125void 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
1173FORCEINLINE void EmptyVariant(VARIANT* value)
1174{
1175 WRAPPER_NO_CONTRACT;
1176 SafeVariantClear(value);
1177}
1178
1179class VariantEmptyHolder : public Wrapper<VARIANT*, ::DoNothing<VARIANT*>, EmptyVariant, NULL>
1180{
1181public:
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
1196FORCEINLINE 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
1209class RecordVariantHolder : public Wrapper<VARIANT*, ::DoNothing<VARIANT*>, RecordVariantRelease, NULL>
1210{
1211public:
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
1232void 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
1250void 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
1280void 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
1315void OleVariant::MarshalWinBoolVariantOleToCom(VARIANT *pOleVariant,
1316 VariantData *pComVariant)
1317{
1318 LIMITED_METHOD_CONTRACT;
1319
1320 _ASSERTE(!"Not supposed to get here.");
1321}
1322
1323void OleVariant::MarshalWinBoolVariantComToOle(VariantData *pComVariant,
1324 VARIANT *pOleVariant)
1325{
1326 LIMITED_METHOD_CONTRACT;
1327
1328 _ASSERTE(!"Not supposed to get here.");
1329}
1330
1331void 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
1340void 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
1370void 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
1405void OleVariant::MarshalCBoolVariantOleToCom(VARIANT* pOleVariant, VariantData* pComVariant)
1406{
1407 LIMITED_METHOD_CONTRACT;
1408
1409 _ASSERTE(!"Not supposed to get here.");
1410}
1411
1412void OleVariant::MarshalCBoolVariantComToOle(VariantData* pComVariant, VARIANT* pOleVariant)
1413{
1414 LIMITED_METHOD_CONTRACT;
1415
1416 _ASSERTE(!"Not supposed to get here.");
1417}
1418
1419void 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
1427void 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
1460void 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
1498void OleVariant::MarshalAnsiCharVariantOleToCom(VARIANT *pOleVariant,
1499 VariantData *pComVariant)
1500{
1501 LIMITED_METHOD_CONTRACT;
1502
1503 _ASSERTE(!"Not supposed to get here.");
1504}
1505
1506void OleVariant::MarshalAnsiCharVariantComToOle(VariantData *pComVariant,
1507 VARIANT *pOleVariant)
1508{
1509 LIMITED_METHOD_CONTRACT;
1510
1511 _ASSERTE(!"Not supposed to get here.");
1512}
1513
1514void 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
1523void 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
1559void 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
1594void 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
1620void 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
1680void 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
1706void 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
1774void 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
1784void 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
1816void 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
1843void 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
1865void 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
1916void 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
1958void 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 * ------------------------------------------------------------------------- */
1987void 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
2017void 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
2055void 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
2082void 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
2132void 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
2191void 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
2218void 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
2268void 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
2328void 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
2356void OleVariant::MarshalDateVariantOleToCom(VARIANT *pOleVariant,
2357 VariantData *pComVariant)
2358{
2359 WRAPPER_NO_CONTRACT;
2360
2361 *(INT64*)pComVariant->GetData() = COMDateTime::DoubleDateToTicks(V_DATE(pOleVariant));
2362}
2363
2364void OleVariant::MarshalDateVariantComToOle(VariantData *pComVariant,
2365 VARIANT *pOleVariant)
2366{
2367 WRAPPER_NO_CONTRACT;
2368
2369 V_DATE(pOleVariant) = COMDateTime::TicksToDoubleDate(*(INT64*)pComVariant->GetData());
2370}
2371
2372void 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
2381void 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
2412void 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
2449void 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
2473void 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
2492void 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
2522void 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
2569void 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
2591void 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
2602void 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
2632void 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
2664void 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.
2686void 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
2814void 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
2898HRESULT 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 }
3033Exit:
3034 return hr;
3035}
3036
3037void 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
3238void 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
3313void 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
3371void 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
3444void 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
3533void 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
3567void 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
3657BOOL 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
3691HRESULT 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
3747void 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
3762void 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
3787void 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
3810void 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
3835void 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
3862void 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
3893void 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
3941void 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
3961void 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
4028void 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
4052void 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
4088void 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
4122void 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
4161void 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
4185void 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
4209void 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
4246SAFEARRAY *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
4360SAFEARRAY *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
4405BASEARRAYREF 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//
4494void 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
4580void 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
4656void 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
4704void 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
4794BOOL 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
4828BASEARRAYREF 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
4962TypeHandle 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
5004TypeHandle 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
5027TypeHandle 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
5056void 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
5080void 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
5116void 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
5139BSTR 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
5168void 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
5205BSTR 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