summaryrefslogtreecommitdiff
path: root/src/vm/olevariant.cpp
diff options
context:
space:
mode:
authordotnet-bot <dotnet-bot@microsoft.com>2015-01-30 14:14:42 -0800
committerdotnet-bot <dotnet-bot@microsoft.com>2015-01-30 14:14:42 -0800
commitef1e2ab328087c61a6878c1e84f4fc5d710aebce (patch)
treedee1bbb89e9d722e16b0d1485e3cdd1b6c8e2cfa /src/vm/olevariant.cpp
downloadcoreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.gz
coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.bz2
coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.zip
Initial commit to populate CoreCLR repo
[tfs-changeset: 1407945]
Diffstat (limited to 'src/vm/olevariant.cpp')
-rw-r--r--src/vm/olevariant.cpp5272
1 files changed, 5272 insertions, 0 deletions
diff --git a/src/vm/olevariant.cpp b/src/vm/olevariant.cpp
new file mode 100644
index 0000000000..0aa56e5908
--- /dev/null
+++ b/src/vm/olevariant.cpp
@@ -0,0 +1,5272 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+//
+// File: OleVariant.cpp
+//
+
+//
+
+
+#include "common.h"
+
+#include "object.h"
+#include "excep.h"
+#include "frames.h"
+#include "vars.hpp"
+#include "security.h"
+#include "olevariant.h"
+#include "comdatetime.h"
+#include "fieldmarshaler.h"
+#include "mdaassistants.h"
+
+/* ------------------------------------------------------------------------- *
+ * Local constants
+ * ------------------------------------------------------------------------- */
+
+#define NO_MAPPING ((BYTE) -1)
+
+#define GCPROTECT_BEGIN_VARIANTDATA(/*VARIANTDATA*/vd) do { \
+ FrameWithCookie<GCFrame> __gcframe(vd.GetObjRefPtr(), 1, FALSE); \
+ /* work around unreachable code warning */ \
+ if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT);
+
+
+#define GCPROTECT_END_VARIANTDATA() \
+ DEBUG_ASSURE_NO_RETURN_END(GCPROTECT); } \
+ __gcframe.Pop(); } while(0)
+
+
+//Mapping from CVType to type handle. Used for conversion between the two internally.
+const BinderClassID CVTypeToBinderClassID[] =
+{
+ CLASS__EMPTY, //CV_EMPTY
+ CLASS__VOID, //CV_VOID, Changing this to object messes up signature resolution very badly.
+ CLASS__BOOLEAN, //CV_BOOLEAN
+ CLASS__CHAR, //CV_CHAR
+ CLASS__SBYTE, //CV_I1
+ CLASS__BYTE, //CV_U1
+ CLASS__INT16, //CV_I2
+ CLASS__UINT16, //CV_U2
+ CLASS__INT32, //CV_I4
+ CLASS__UINT32, //CV_UI4
+ CLASS__INT64, //CV_I8
+ CLASS__UINT64, //CV_UI8
+ CLASS__SINGLE, //CV_R4
+ CLASS__DOUBLE, //CV_R8
+ CLASS__STRING, //CV_STRING
+ CLASS__VOID, //CV_PTR...We treat this as void
+ CLASS__DATE_TIME, //CV_DATETIME
+ CLASS__TIMESPAN, //CV_TIMESPAN
+ CLASS__OBJECT, //CV_OBJECT
+ CLASS__DECIMAL, //CV_DECIMAL
+ CLASS__CURRENCY, //CV_CURRENCY
+ CLASS__OBJECT, //ENUM...We treat this as OBJECT
+ CLASS__MISSING, //CV_MISSING
+ CLASS__NULL, //CV_NULL
+ CLASS__NIL, //CV_LAST
+};
+
+// Use this very carefully. There is not a direct mapping between
+// CorElementType and CVTypes for a bunch of things. In this case
+// we return CV_LAST. You need to check this at the call site.
+CVTypes CorElementTypeToCVTypes(CorElementType type)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ if (type <= ELEMENT_TYPE_STRING)
+ return (CVTypes) type;
+
+ if (type == ELEMENT_TYPE_CLASS || type == ELEMENT_TYPE_OBJECT)
+ return (CVTypes) ELEMENT_TYPE_CLASS;
+
+ return CV_LAST;
+}
+
+/* ------------------------------------------------------------------------- *
+ * Mapping routines
+ * ------------------------------------------------------------------------- */
+
+VARTYPE OleVariant::GetVarTypeForCVType(CVTypes type)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ static const BYTE map[] =
+ {
+ VT_EMPTY, // CV_EMPTY
+ VT_VOID, // CV_VOID
+ VT_BOOL, // CV_BOOLEAN
+ VT_UI2, // CV_CHAR
+ VT_I1, // CV_I1
+ VT_UI1, // CV_U1
+ VT_I2, // CV_I2
+ VT_UI2, // CV_U2
+ VT_I4, // CV_I4
+ VT_UI4, // CV_U4
+ VT_I8, // CV_I8
+ VT_UI8, // CV_U8
+ VT_R4, // CV_R4
+ VT_R8, // CV_R8
+ VT_BSTR, // CV_STRING
+ NO_MAPPING, // CV_PTR
+ VT_DATE, // CV_DATETIME
+ NO_MAPPING, // CV_TIMESPAN
+ VT_DISPATCH, // CV_OBJECT
+ VT_DECIMAL, // CV_DECIMAL
+ VT_CY, // CV_CURRENCY
+ VT_I4, // CV_ENUM
+ VT_ERROR, // CV_MISSING
+ VT_NULL // CV_NULL
+ };
+
+ _ASSERTE(type < (CVTypes) (sizeof(map) / sizeof(map[0])));
+
+ VARTYPE vt = VARTYPE(map[type]);
+
+ if (vt == NO_MAPPING)
+ COMPlusThrow(kArgumentException, IDS_EE_COM_UNSUPPORTED_SIG);
+
+ return vt;
+}
+
+//
+// GetCVTypeForVarType returns the COM+ variant type for a given
+// VARTYPE. This is called by the marshaller in the context of
+// a function call.
+//
+
+CVTypes OleVariant::GetCVTypeForVarType(VARTYPE vt)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ static const BYTE map[] =
+ {
+ CV_EMPTY, // VT_EMPTY
+ CV_NULL, // VT_NULL
+ CV_I2, // VT_I2
+ CV_I4, // VT_I4
+ CV_R4, // VT_R4
+ CV_R8, // VT_R8
+ CV_DECIMAL, // VT_CY
+ CV_DATETIME, // VT_DATE
+ CV_STRING, // VT_BSTR
+ CV_OBJECT, // VT_DISPATCH
+ CV_I4, // VT_ERROR
+ CV_BOOLEAN, // VT_BOOL
+ NO_MAPPING, // VT_VARIANT
+ CV_OBJECT, // VT_UNKNOWN
+ CV_DECIMAL, // VT_DECIMAL
+ NO_MAPPING, // unused
+ CV_I1, // VT_I1
+ CV_U1, // VT_UI1
+ CV_U2, // VT_UI2
+ CV_U4, // VT_UI4
+ CV_I8, // VT_I8
+ CV_U8, // VT_UI8
+ CV_I4, // VT_INT
+ CV_U4, // VT_UINT
+ CV_VOID, // VT_VOID
+ NO_MAPPING, // VT_HRESULT
+ NO_MAPPING, // VT_PTR
+ NO_MAPPING, // VT_SAFEARRAY
+ NO_MAPPING, // VT_CARRAY
+ NO_MAPPING, // VT_USERDEFINED
+ NO_MAPPING, // VT_LPSTR
+ NO_MAPPING, // VT_LPWSTR
+ NO_MAPPING, // unused
+ NO_MAPPING, // unused
+ NO_MAPPING, // unused
+ NO_MAPPING, // unused
+ CV_OBJECT, // VT_RECORD
+ };
+
+ CVTypes type = CV_LAST;
+
+ // Validate the arguments.
+ _ASSERTE((vt & VT_BYREF) == 0);
+
+ // Array's map to CV_OBJECT.
+ if (vt & VT_ARRAY)
+ return CV_OBJECT;
+
+ // This is prety much a workaround because you cannot cast a CorElementType into a CVTYPE
+ if (vt > VT_RECORD || (BYTE)(type = (CVTypes) map[vt]) == NO_MAPPING)
+ COMPlusThrow(kArgumentException, IDS_EE_COM_UNSUPPORTED_TYPE);
+
+ return type;
+} // CVTypes OleVariant::GetCVTypeForVarType()
+
+#ifdef FEATURE_COMINTEROP
+
+// GetVarTypeForComVariant retusn the VARTYPE for the contents
+// of a COM+ variant.
+//
+VARTYPE OleVariant::GetVarTypeForComVariant(VariantData *pComVariant)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ CVTypes type = pComVariant->GetType();
+ VARTYPE vt;
+
+ vt = pComVariant->GetVT();
+ if (vt != VT_EMPTY)
+ {
+ // This variant was originally unmarshaled from unmanaged, and had the original VT recorded in it.
+ // We'll always use that over inference.
+ return vt;
+ }
+
+ if (type == CV_OBJECT)
+ {
+ OBJECTREF obj = pComVariant->GetObjRef();
+
+ // Null objects will be converted to VT_DISPATCH variants with a null
+ // IDispatch pointer.
+ if (obj == NULL)
+ return VT_DISPATCH;
+
+ // Retrieve the object's method table.
+ MethodTable *pMT = obj->GetMethodTable();
+
+ // Handle the value class case.
+ if (pMT->IsValueType())
+ return VT_RECORD;
+
+ // Handle the array case.
+ if (pMT->IsArray())
+ {
+ vt = GetElementVarTypeForArrayRef((BASEARRAYREF)obj);
+ if (vt == VT_ARRAY)
+ vt = VT_VARIANT;
+
+ return vt | VT_ARRAY;
+ }
+
+#ifdef FEATURE_COMINTEROP
+ // SafeHandle's or CriticalHandle's cannot be stored in VARIANT's.
+ if (pMT->CanCastToClass(MscorlibBinder::GetClass(CLASS__SAFE_HANDLE)))
+ COMPlusThrow(kArgumentException, IDS_EE_SH_IN_VARIANT_NOT_SUPPORTED);
+ if (pMT->CanCastToClass(MscorlibBinder::GetClass(CLASS__CRITICAL_HANDLE)))
+ COMPlusThrow(kArgumentException, IDS_EE_CH_IN_VARIANT_NOT_SUPPORTED);
+
+ // VariantWrappers cannot be stored in VARIANT's.
+ if (MscorlibBinder::IsClass(pMT, CLASS__VARIANT_WRAPPER))
+ COMPlusThrow(kArgumentException, IDS_EE_VAR_WRAP_IN_VAR_NOT_SUPPORTED);
+
+ // We are dealing with a normal object (not a wrapper) so we will
+ // leave the VT as VT_DISPATCH for now and we will determine the actual
+ // VT when we convert the object to a COM IP.
+ return VT_DISPATCH;
+#else // FEATURE_COMINTEROP
+ return VT_UNKNOWN;
+#endif // FEATURE_COMINTEROP
+ }
+
+ return GetVarTypeForCVType(type);
+}
+
+#endif // FEATURE_COMINTEROP
+
+VARTYPE OleVariant::GetVarTypeForTypeHandle(TypeHandle type)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ // Handle primitive types.
+ CorElementType elemType = type.GetSignatureCorElementType();
+ if (elemType <= ELEMENT_TYPE_R8)
+ return GetVarTypeForCVType(CorElementTypeToCVTypes(elemType));
+
+ // Handle objects.
+ if (!type.IsTypeDesc())
+ {
+ MethodTable * pMT = type.AsMethodTable();
+
+ if (pMT == g_pStringClass)
+ return VT_BSTR;
+ if (pMT == g_pObjectClass)
+ return VT_VARIANT;
+
+ // We need to make sure the CVClasses table is populated.
+ if(MscorlibBinder::IsClass(pMT, CLASS__DATE_TIME))
+ return VT_DATE;
+ if(MscorlibBinder::IsClass(pMT, CLASS__DECIMAL))
+ return VT_DECIMAL;
+
+#ifdef _WIN64
+ if (MscorlibBinder::IsClass(pMT, CLASS__INTPTR))
+ return VT_I8;
+ if (MscorlibBinder::IsClass(pMT, CLASS__UINTPTR))
+ return VT_UI8;
+#else
+ if (MscorlibBinder::IsClass(pMT, CLASS__INTPTR))
+ return VT_INT;
+ if (MscorlibBinder::IsClass(pMT, CLASS__UINTPTR))
+ return VT_UINT;
+#endif
+
+#ifdef FEATURE_COMINTEROP
+ if (MscorlibBinder::IsClass(pMT, CLASS__DISPATCH_WRAPPER))
+ return VT_DISPATCH;
+ if (MscorlibBinder::IsClass(pMT, CLASS__UNKNOWN_WRAPPER))
+ return VT_UNKNOWN;
+ if (MscorlibBinder::IsClass(pMT, CLASS__ERROR_WRAPPER))
+ return VT_ERROR;
+ if (MscorlibBinder::IsClass(pMT, CLASS__CURRENCY_WRAPPER))
+ return VT_CY;
+ if (MscorlibBinder::IsClass(pMT, CLASS__BSTR_WRAPPER))
+ return VT_BSTR;
+
+ // VariantWrappers cannot be stored in VARIANT's.
+ if (MscorlibBinder::IsClass(pMT, CLASS__VARIANT_WRAPPER))
+ COMPlusThrow(kArgumentException, IDS_EE_COM_UNSUPPORTED_SIG);
+#endif // FEATURE_COMINTEROP
+
+ if (pMT->IsEnum())
+ return GetVarTypeForCVType((CVTypes)type.GetInternalCorElementType());
+
+ if (pMT->IsValueType())
+ return VT_RECORD;
+
+#ifdef FEATURE_COMINTEROP
+ // There is no VT corresponding to SafeHandles as they cannot be stored in
+ // VARIANTs or Arrays. The same applies to CriticalHandle.
+ if (type.CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__SAFE_HANDLE))))
+ COMPlusThrow(kArgumentException, IDS_EE_COM_UNSUPPORTED_SIG);
+ if (type.CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__CRITICAL_HANDLE))))
+ COMPlusThrow(kArgumentException, IDS_EE_COM_UNSUPPORTED_SIG);
+
+ if (pMT->IsInterface())
+ {
+ CorIfaceAttr ifaceType = pMT->GetComInterfaceType();
+ return static_cast<VARTYPE>(IsDispatchBasedItf(ifaceType) ? VT_DISPATCH : VT_UNKNOWN);
+ }
+
+ TypeHandle hndDefItfClass;
+ DefaultInterfaceType DefItfType = GetDefaultInterfaceForClassWrapper(type, &hndDefItfClass);
+ switch (DefItfType)
+ {
+ case DefaultInterfaceType_Explicit:
+ {
+ CorIfaceAttr ifaceType = hndDefItfClass.GetMethodTable()->GetComInterfaceType();
+ return static_cast<VARTYPE>(IsDispatchBasedItf(ifaceType) ? VT_DISPATCH : VT_UNKNOWN);
+ }
+
+ case DefaultInterfaceType_AutoDual:
+ {
+ return VT_DISPATCH;
+ }
+
+ case DefaultInterfaceType_IUnknown:
+ case DefaultInterfaceType_BaseComClass:
+ {
+ return VT_UNKNOWN;
+ }
+
+ case DefaultInterfaceType_AutoDispatch:
+ {
+ return VT_DISPATCH;
+ }
+
+ default:
+ {
+ _ASSERTE(!"Invalid default interface type!");
+ }
+ }
+#endif // FEATURE_COMINTEROP
+
+ return VT_UNKNOWN;
+ }
+
+ // Handle array's.
+ if (!CorTypeInfo::IsArray(elemType))
+ {
+ // Non interop compatible type.
+ COMPlusThrow(kArgumentException, IDS_EE_COM_UNSUPPORTED_SIG);
+ }
+
+ return VT_ARRAY;
+}
+
+//
+// GetElementVarTypeForArrayRef returns the safearray variant type for the
+// underlying elements in the array.
+//
+
+VARTYPE OleVariant::GetElementVarTypeForArrayRef(BASEARRAYREF pArrayRef)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ TypeHandle elemTypeHnd = pArrayRef->GetArrayElementTypeHandle();
+ return(GetVarTypeForTypeHandle(elemTypeHnd));
+}
+
+#ifdef FEATURE_COMINTEROP
+
+BOOL OleVariant::IsValidArrayForSafeArrayElementType(BASEARRAYREF *pArrayRef, VARTYPE vtExpected)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ // Retrieve the VARTYPE for the managed array.
+ VARTYPE vtActual = GetElementVarTypeForArrayRef(*pArrayRef);
+
+ // If the actual type is the same as the expected type, then the array is valid.
+ if (vtActual == vtExpected)
+ return TRUE;
+
+ // Check for additional supported VARTYPES.
+ switch (vtExpected)
+ {
+ case VT_I4:
+ return vtActual == VT_INT;
+
+ case VT_INT:
+ return vtActual == VT_I4;
+
+ case VT_UI4:
+ return vtActual == VT_UINT;
+
+ case VT_UINT:
+ return vtActual == VT_UI4;
+
+ case VT_UNKNOWN:
+ return vtActual == VT_VARIANT || vtActual == VT_DISPATCH;
+
+ case VT_DISPATCH:
+ return vtActual == VT_VARIANT;
+
+ case VT_CY:
+ return vtActual == VT_DECIMAL;
+
+ default:
+ return FALSE;
+ }
+}
+
+#endif // FEATURE_COMINTEROP
+
+//
+// GetArrayClassForVarType returns the element class name and underlying method table
+// to use to represent an array with the given variant type.
+//
+
+TypeHandle OleVariant::GetArrayForVarType(VARTYPE vt, TypeHandle elemType, unsigned rank)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ CorElementType baseElement = ELEMENT_TYPE_END;
+ TypeHandle baseType;
+
+ if (!elemType.IsNull() && elemType.IsEnum())
+ {
+ baseType = elemType;
+ }
+ else
+ {
+ switch (vt)
+ {
+ case VT_BOOL:
+ case VTHACK_WINBOOL:
+ case VTHACK_CBOOL:
+ baseElement = ELEMENT_TYPE_BOOLEAN;
+ break;
+
+ case VTHACK_ANSICHAR:
+ baseElement = ELEMENT_TYPE_CHAR;
+ break;
+
+ case VT_UI1:
+ baseElement = ELEMENT_TYPE_U1;
+ break;
+
+ case VT_I1:
+ baseElement = ELEMENT_TYPE_I1;
+ break;
+
+ case VT_UI2:
+ baseElement = ELEMENT_TYPE_U2;
+ break;
+
+ case VT_I2:
+ baseElement = ELEMENT_TYPE_I2;
+ break;
+
+ case VT_UI4:
+ case VT_UINT:
+ case VT_ERROR:
+ if (vt == VT_UI4)
+ {
+ if (elemType.IsNull() || elemType == TypeHandle(g_pObjectClass))
+ {
+ baseElement = ELEMENT_TYPE_U4;
+ }
+ else
+ {
+ switch (elemType.AsMethodTable()->GetInternalCorElementType())
+ {
+ case ELEMENT_TYPE_U4:
+ baseElement = ELEMENT_TYPE_U4;
+ break;
+ case ELEMENT_TYPE_U:
+ baseElement = ELEMENT_TYPE_U;
+ break;
+ default:
+ _ASSERTE(0);
+ }
+ }
+ }
+ else
+ {
+ baseElement = ELEMENT_TYPE_U4;
+ }
+ break;
+
+ case VT_I4:
+ case VT_INT:
+ if (vt == VT_I4)
+ {
+ if (elemType.IsNull() || elemType == TypeHandle(g_pObjectClass))
+ {
+ baseElement = ELEMENT_TYPE_I4;
+ }
+ else
+ {
+ switch (elemType.AsMethodTable()->GetInternalCorElementType())
+ {
+ case ELEMENT_TYPE_I4:
+ baseElement = ELEMENT_TYPE_I4;
+ break;
+ case ELEMENT_TYPE_I:
+ baseElement = ELEMENT_TYPE_I;
+ break;
+ default:
+ _ASSERTE(0);
+ }
+ }
+ }
+ else
+ {
+ baseElement = ELEMENT_TYPE_I4;
+ }
+ break;
+
+ case VT_I8:
+ if (elemType.IsNull() || elemType == TypeHandle(g_pObjectClass))
+ {
+ baseElement = ELEMENT_TYPE_I8;
+ }
+ else
+ {
+ switch (elemType.AsMethodTable()->GetInternalCorElementType())
+ {
+ case ELEMENT_TYPE_I8:
+ baseElement = ELEMENT_TYPE_I8;
+ break;
+ case ELEMENT_TYPE_I:
+ baseElement = ELEMENT_TYPE_I;
+ break;
+ default:
+ _ASSERTE(0);
+ }
+ }
+ break;
+
+ case VT_UI8:
+ if (elemType.IsNull() || elemType == TypeHandle(g_pObjectClass))
+ {
+ baseElement = ELEMENT_TYPE_U8;
+ }
+ else
+ {
+ switch (elemType.AsMethodTable()->GetInternalCorElementType())
+ {
+ case ELEMENT_TYPE_U8:
+ baseElement = ELEMENT_TYPE_U8;
+ break;
+ case ELEMENT_TYPE_U:
+ baseElement = ELEMENT_TYPE_U;
+ break;
+ default:
+ _ASSERTE(0);
+ }
+ }
+ break;
+
+ case VT_R4:
+ baseElement = ELEMENT_TYPE_R4;
+ break;
+
+ case VT_R8:
+ baseElement = ELEMENT_TYPE_R8;
+ break;
+
+ case VT_CY:
+ baseType = TypeHandle(MscorlibBinder::GetClass(CLASS__DECIMAL));
+ break;
+
+ case VT_DATE:
+ baseType = TypeHandle(MscorlibBinder::GetClass(CLASS__DATE_TIME));
+ break;
+
+ case VT_DECIMAL:
+ baseType = TypeHandle(MscorlibBinder::GetClass(CLASS__DECIMAL));
+ break;
+
+ case VT_VARIANT:
+
+ //
+ // It would be nice if our conversion between SAFEARRAY and
+ // array ref were symmetric. Right now it is not, because a
+ // jagged array converted to a SAFEARRAY and back will come
+ // back as an array of variants.
+ //
+ // We could try to detect the case where we can turn a
+ // safearray of variants into a jagged array. Basically we
+ // needs to make sure that all of the variants in the array
+ // have the same array type. (And if that is array of
+ // variant, we need to look recursively for another layer.)
+ //
+ // We also needs to check the dimensions of each array stored
+ // in the variant to make sure they have the same rank, and
+ // this rank is needed to build the correct array class name.
+ // (Note that it will be impossible to tell the rank if all
+ // elements in the array are NULL.)
+ //
+
+ // <TODO>@nice: implement this functionality if we decide it really makes sense
+ // For now, just live with the asymmetry</TODO>
+
+ baseType = TypeHandle(g_pObjectClass);
+ break;
+
+ case VT_BSTR:
+ case VT_LPWSTR:
+ case VT_LPSTR:
+ baseElement = ELEMENT_TYPE_STRING;
+ break;
+
+ case VT_DISPATCH:
+ case VT_UNKNOWN:
+ if (elemType.IsNull())
+ baseType = TypeHandle(g_pObjectClass);
+ else
+ baseType = elemType;
+ break;
+
+ case VT_RECORD:
+ _ASSERTE(!elemType.IsNull());
+ baseType = elemType;
+ break;
+
+ default:
+ COMPlusThrow(kArgumentException, IDS_EE_COM_UNSUPPORTED_SIG);
+ }
+ }
+
+ if (baseType.IsNull())
+ baseType = TypeHandle(MscorlibBinder::GetElementType(baseElement));
+
+ _ASSERTE(!baseType.IsNull());
+
+ return ClassLoader::LoadArrayTypeThrowing(baseType, rank == 0 ? ELEMENT_TYPE_SZARRAY : ELEMENT_TYPE_ARRAY, rank == 0 ? 1 : rank);
+}
+
+//
+// GetElementSizeForVarType returns the array element size for the given variant type.
+//
+
+UINT OleVariant::GetElementSizeForVarType(VARTYPE vt, MethodTable *pInterfaceMT)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ static const BYTE map[] =
+ {
+ 0, // VT_EMPTY
+ 0, // VT_NULL
+ 2, // VT_I2
+ 4, // VT_I4
+ 4, // VT_R4
+ 8, // VT_R8
+ sizeof(CURRENCY), // VT_CY
+ sizeof(DATE), // VT_DATE
+ sizeof(BSTR), // VT_BSTR
+ sizeof(IDispatch*), // VT_DISPATCH
+ sizeof(SCODE), // VT_ERROR
+ sizeof(VARIANT_BOOL), // VT_BOOL
+ sizeof(VARIANT), // VT_VARIANT
+ sizeof(IUnknown*), // VT_UNKNOWN
+ sizeof(DECIMAL), // VT_DECIMAL
+ 0, // unused
+ 1, // VT_I1
+ 1, // VT_UI1
+ 2, // VT_UI2
+ 4, // VT_UI4
+ 8, // VT_I8
+ 8, // VT_UI8
+ 4, // VT_INT
+ 4, // VT_UINT
+ 0, // VT_VOID
+ sizeof(HRESULT), // VT_HRESULT
+ sizeof(void*), // VT_PTR
+ sizeof(SAFEARRAY*), // VT_SAFEARRAY
+ sizeof(void*), // VT_CARRAY
+ sizeof(void*), // VT_USERDEFINED
+ sizeof(LPSTR), // VT_LPSTR
+ sizeof(LPWSTR), // VT_LPWSTR
+ };
+
+ // Special cases
+ switch (vt)
+ {
+ case VTHACK_WINBOOL:
+ return sizeof(BOOL);
+ break;
+ case VTHACK_ANSICHAR:
+ return GetMaxDBCSCharByteSize(); // Multi byte characters.
+ break;
+ case VTHACK_CBOOL:
+ return sizeof(BYTE);
+ default:
+ break;
+ }
+
+ // VT_ARRAY indicates a safe array which is always sizeof(SAFEARRAY *).
+ if (vt & VT_ARRAY)
+ return sizeof(SAFEARRAY*);
+
+ if (vt == VTHACK_NONBLITTABLERECORD || vt == VTHACK_BLITTABLERECORD || vt == VT_RECORD)
+ {
+ PREFIX_ASSUME(pInterfaceMT != NULL);
+ return pInterfaceMT->GetNativeSize();
+ }
+ else if (vt > VT_LPWSTR)
+ return 0;
+ else
+ return map[vt];
+}
+
+//
+// GetMarshalerForVarType returns the marshaler for the
+// given VARTYPE.
+//
+
+const OleVariant::Marshaler *OleVariant::GetMarshalerForVarType(VARTYPE vt, BOOL fThrow)
+{
+ CONTRACT (const OleVariant::Marshaler*)
+ {
+ if (fThrow) THROWS; else NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
+ }
+ CONTRACT_END;
+
+#ifdef FEATURE_COMINTEROP
+
+#ifdef CROSSGEN_COMPILE
+#define RETURN_MARSHALER(OleToCom, ComToOle, OleRefToCom, ArrayOleToCom, ArrayComToOle, ClearArray) \
+ { static const Marshaler marshaler = { NULL, NULL, NULL, NULL, NULL, NULL }; RETURN &marshaler; }
+#else
+#define RETURN_MARSHALER(OleToCom, ComToOle, OleRefToCom, ArrayOleToCom, ArrayComToOle, ClearArray) \
+ { static const Marshaler marshaler = { OleToCom, ComToOle, OleRefToCom, ArrayOleToCom, ArrayComToOle, ClearArray }; RETURN &marshaler; }
+#endif
+
+#else // FEATURE_COMINTEROP
+
+#ifdef CROSSGEN_COMPILE
+#define RETURN_MARSHALER(OleToCom, ComToOle, OleRefToCom, ArrayOleToCom, ArrayComToOle, ClearArray) \
+ { static const Marshaler marshaler = { NULL, NULL, NULL }; RETURN &marshaler; }
+#else
+#define RETURN_MARSHALER(OleToCom, ComToOle, OleRefToCom, ArrayOleToCom, ArrayComToOle, ClearArray) \
+ { static const Marshaler marshaler = { ArrayOleToCom, ArrayComToOle, ClearArray }; RETURN &marshaler; }
+#endif
+
+#endif // FEATURE_COMINTEROP
+
+#ifdef FEATURE_CLASSIC_COMINTEROP
+ if (vt & VT_ARRAY)
+ {
+VariantArray:
+ RETURN_MARSHALER(
+ MarshalArrayVariantOleToCom,
+ MarshalArrayVariantComToOle,
+ MarshalArrayVariantOleRefToCom,
+ NULL,
+ NULL,
+ ClearVariantArray
+ );
+ }
+#endif // FEATURE_CLASSIC_COMINTEROP
+
+ switch (vt)
+ {
+ case VT_BOOL:
+ RETURN_MARSHALER(
+ MarshalBoolVariantOleToCom,
+ NULL,
+ NULL,
+ MarshalBoolArrayOleToCom,
+ MarshalBoolArrayComToOle,
+ NULL
+ );
+
+ case VT_DATE:
+ RETURN_MARSHALER(
+ MarshalDateVariantOleToCom,
+ MarshalDateVariantComToOle,
+ MarshalDateVariantOleRefToCom,
+ MarshalDateArrayOleToCom,
+ MarshalDateArrayComToOle,
+ NULL
+ );
+
+ case VT_DECIMAL:
+ RETURN_MARSHALER(
+ MarshalDecimalVariantOleToCom,
+ MarshalDecimalVariantComToOle,
+ MarshalDecimalVariantOleRefToCom,
+ NULL, NULL, NULL
+ );
+
+#ifdef FEATURE_COMINTEROP
+ case VT_CY:
+ RETURN_MARSHALER(
+ MarshalCurrencyVariantOleToCom,
+ MarshalCurrencyVariantComToOle,
+ MarshalCurrencyVariantOleRefToCom,
+ MarshalCurrencyArrayOleToCom,
+ MarshalCurrencyArrayComToOle,
+ NULL
+ );
+
+ case VT_BSTR:
+ RETURN_MARSHALER(
+ MarshalBSTRVariantOleToCom,
+ MarshalBSTRVariantComToOle,
+ NULL,
+ MarshalBSTRArrayOleToCom,
+ MarshalBSTRArrayComToOle,
+ ClearBSTRArray
+ );
+
+ case VT_UNKNOWN:
+ RETURN_MARSHALER(
+ MarshalInterfaceVariantOleToCom,
+ MarshalInterfaceVariantComToOle,
+ MarshalInterfaceVariantOleRefToCom,
+ MarshalInterfaceArrayOleToCom,
+ MarshalIUnknownArrayComToOle,
+ ClearInterfaceArray
+ );
+
+ case VT_DISPATCH:
+ RETURN_MARSHALER(
+ MarshalInterfaceVariantOleToCom,
+ MarshalInterfaceVariantComToOle,
+ MarshalInterfaceVariantOleRefToCom,
+ MarshalInterfaceArrayOleToCom,
+ MarshalIDispatchArrayComToOle,
+ ClearInterfaceArray
+ );
+
+#ifdef FEATURE_CLASSIC_COMINTEROP
+ case VT_SAFEARRAY:
+ goto VariantArray;
+#endif
+
+ case VT_VARIANT:
+ RETURN_MARSHALER(
+ NULL, NULL, NULL,
+ MarshalVariantArrayOleToCom,
+ MarshalVariantArrayComToOle,
+ ClearVariantArray
+ );
+
+ case VT_ERROR:
+ RETURN_MARSHALER(
+ MarshalErrorVariantOleToCom,
+ MarshalErrorVariantComToOle,
+ MarshalErrorVariantOleRefToCom,
+ NULL, NULL, NULL
+ );
+#endif // FEATURE_COMINTEROP
+
+ case VTHACK_NONBLITTABLERECORD:
+ RETURN_MARSHALER(
+ NULL, NULL, NULL,
+ MarshalNonBlittableRecordArrayOleToCom,
+ MarshalNonBlittableRecordArrayComToOle,
+ ClearNonBlittableRecordArray
+ );
+
+ case VTHACK_BLITTABLERECORD:
+ RETURN NULL; // Requires no marshaling
+
+ case VTHACK_WINBOOL:
+ RETURN_MARSHALER(
+ MarshalWinBoolVariantOleToCom,
+ MarshalWinBoolVariantComToOle,
+ MarshalWinBoolVariantOleRefToCom,
+ MarshalWinBoolArrayOleToCom,
+ MarshalWinBoolArrayComToOle,
+ NULL
+ );
+
+ case VTHACK_CBOOL:
+ RETURN_MARSHALER(
+ MarshalCBoolVariantOleToCom,
+ MarshalCBoolVariantComToOle,
+ MarshalCBoolVariantOleRefToCom,
+ MarshalCBoolArrayOleToCom,
+ MarshalCBoolArrayComToOle,
+ NULL
+ );
+
+ case VTHACK_ANSICHAR:
+ RETURN_MARSHALER(
+ MarshalAnsiCharVariantOleToCom,
+ MarshalAnsiCharVariantComToOle,
+ MarshalAnsiCharVariantOleRefToCom,
+ MarshalAnsiCharArrayOleToCom,
+ MarshalAnsiCharArrayComToOle,
+ NULL
+ );
+
+ case VT_LPSTR:
+ RETURN_MARSHALER(
+ NULL, NULL, NULL,
+ MarshalLPSTRArrayOleToCom,
+ MarshalLPSTRRArrayComToOle,
+ ClearLPSTRArray
+ );
+
+ case VT_LPWSTR:
+ RETURN_MARSHALER(
+ NULL, NULL, NULL,
+ MarshalLPWSTRArrayOleToCom,
+ MarshalLPWSTRRArrayComToOle,
+ ClearLPWSTRArray
+ );
+
+#ifdef FEATURE_CLASSIC_COMINTEROP
+ case VT_RECORD:
+ RETURN_MARSHALER(
+ MarshalRecordVariantOleToCom,
+ MarshalRecordVariantComToOle,
+ MarshalRecordVariantOleRefToCom,
+ MarshalRecordArrayOleToCom,
+ MarshalRecordArrayComToOle,
+ ClearRecordArray
+ );
+#endif
+
+ case VT_CARRAY:
+ case VT_USERDEFINED:
+ if (fThrow)
+ {
+ COMPlusThrow(kArgumentException, IDS_EE_COM_UNSUPPORTED_SIG);
+ }
+ else
+ {
+ RETURN NULL;
+ }
+
+ default:
+ RETURN NULL;
+ }
+} // OleVariant::Marshaler *OleVariant::GetMarshalerForVarType()
+
+#ifndef CROSSGEN_COMPILE
+
+#ifdef FEATURE_COMINTEROP
+
+/*==================================NewVariant==================================
+**N.B.: This method does a GC Allocation. Any method calling it is required to
+** GC_PROTECT the OBJECTREF.
+**
+**Actions: Allocates a new Variant and fills it with the appropriate data.
+**Returns: A new Variant with all of the appropriate fields filled out.
+**Exceptions: OutOfMemoryError if v can't be allocated.
+==============================================================================*/
+void VariantData::NewVariant(VariantData * const& dest, const CVTypes type, INT64 data
+ DEBUG_ARG(BOOL bDestIsInterior))
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ // Don't pass an object in for Empty.
+ PRECONDITION(CheckPointer(dest));
+ PRECONDITION((bDestIsInterior && IsProtectedByGCFrame ((OBJECTREF *) &dest))
+ || (!bDestIsInterior && IsProtectedByGCFrame (dest->GetObjRefPtr ())));
+ PRECONDITION((type == CV_EMPTY) || (type == CV_NULL) || (type == CV_U4) || (type == CV_U8));
+ }
+ CONTRACTL_END;
+
+ //If both arguments are null or both are specified, we're in an illegal situation. Bail.
+ //If all three are null, we're creating an empty variant
+ if ( (type != CV_EMPTY) && (type != CV_NULL) && (type != CV_U4) && (type != CV_U8) )
+ {
+ COMPlusThrow(kArgumentException);
+ }
+
+ //Fill in the data.
+ dest->SetType(type);
+
+ switch (type)
+ {
+ case CV_U4:
+ dest->SetObjRef(NULL);
+ dest->SetDataAsUInt32((UINT32)data);
+ break;
+
+ case CV_U8:
+ dest->SetObjRef(NULL);
+ dest->SetDataAsInt64(data);
+ break;
+
+ case CV_NULL:
+ {
+ FieldDesc * pFD = MscorlibBinder::GetField(FIELD__NULL__VALUE);
+ _ASSERTE(pFD);
+
+ pFD->CheckRunClassInitThrowing();
+
+ OBJECTREF obj = pFD->GetStaticOBJECTREF();
+ _ASSERTE(obj!=NULL);
+
+ dest->SetObjRef(obj);
+ dest->SetDataAsInt64(0);
+ break;
+ }
+
+ case CV_EMPTY:
+ {
+ dest->SetObjRef(NULL);
+ break;
+ }
+
+ default:
+ // Did you add any new CVTypes?
+ COMPlusThrow(kNotSupportedException, W("Arg_InvalidOleVariantTypeException"));
+ }
+}
+
+void SafeVariantClearHelper(VARIANT* pVar)
+{
+ STATIC_CONTRACT_SO_INTOLERANT;
+ WRAPPER_NO_CONTRACT;
+
+ BEGIN_SO_TOLERANT_CODE(GetThread());
+ VariantClear(pVar);
+ END_SO_TOLERANT_CODE;
+}
+
+class OutOfMemoryException;
+
+void SafeVariantClear(VARIANT* pVar)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ if (pVar)
+ {
+ GCX_PREEMP();
+ SCAN_EHMARKER();
+ PAL_CPP_TRY
+ {
+ // These are holders to tell the contract system that we're catching all exceptions.
+ SCAN_EHMARKER_TRY();
+ CLR_TRY_MARKER();
+
+ // Most of time, oleaut32.dll is loaded already when we get here.
+ // Sometimes, CLR initializes Variant without loading oleaut32.dll, e.g. VT_BOOL.
+ // It is better for performance with EX_TRY than
+
+ SafeVariantClearHelper(pVar);
+
+ SCAN_EHMARKER_END_TRY();
+ }
+ PAL_CPP_CATCH_DERIVED(OutOfMemoryException, obj)
+ {
+ SCAN_EHMARKER_CATCH();
+
+#if defined(STACK_GUARDS_DEBUG)
+ // Catching and just swallowing an exception means we need to tell
+ // the SO code that it should go back to normal operation, as it
+ // currently thinks that the exception is still on the fly.
+ GetThread()->GetCurrentStackGuard()->RestoreCurrentGuard();
+#endif
+
+ SCAN_EHMARKER_END_CATCH();
+ }
+ PAL_CPP_ENDTRY;
+
+ FillMemory(pVar, sizeof(VARIANT), 0x00);
+ }
+}
+
+FORCEINLINE void EmptyVariant(VARIANT* value)
+{
+ WRAPPER_NO_CONTRACT;
+ SafeVariantClear(value);
+}
+
+class VariantEmptyHolder : public Wrapper<VARIANT*, ::DoNothing<VARIANT*>, EmptyVariant, NULL>
+{
+public:
+ VariantEmptyHolder(VARIANT* p = NULL) :
+ Wrapper<VARIANT*, ::DoNothing<VARIANT*>, EmptyVariant, NULL>(p)
+ {
+ WRAPPER_NO_CONTRACT;
+ }
+
+ FORCEINLINE void operator=(VARIANT* p)
+ {
+ WRAPPER_NO_CONTRACT;
+
+ Wrapper<VARIANT*, ::DoNothing<VARIANT*>, EmptyVariant, NULL>::operator=(p);
+ }
+};
+
+FORCEINLINE void RecordVariantRelease(VARIANT* value)
+{
+ if (value)
+ {
+ WRAPPER_NO_CONTRACT;
+
+ if (V_RECORD(value))
+ V_RECORDINFO(value)->RecordDestroy(V_RECORD(value));
+ if (V_RECORDINFO(value))
+ V_RECORDINFO(value)->Release();
+ }
+}
+
+class RecordVariantHolder : public Wrapper<VARIANT*, ::DoNothing<VARIANT*>, RecordVariantRelease, NULL>
+{
+public:
+ RecordVariantHolder(VARIANT* p = NULL)
+ : Wrapper<VARIANT*, ::DoNothing<VARIANT*>, RecordVariantRelease, NULL>(p)
+ {
+ WRAPPER_NO_CONTRACT;
+ }
+
+ FORCEINLINE void operator=(VARIANT* p)
+ {
+ WRAPPER_NO_CONTRACT;
+ Wrapper<VARIANT*, ::DoNothing<VARIANT*>, RecordVariantRelease, NULL>::operator=(p);
+ }
+};
+#endif // FEATURE_COMINTEROP
+
+/* ------------------------------------------------------------------------- *
+ * Boolean marshaling routines
+ * ------------------------------------------------------------------------- */
+
+#ifdef FEATURE_COMINTEROP
+
+void OleVariant::MarshalBoolVariantOleToCom(VARIANT *pOleVariant,
+ VariantData *pComVariant)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(pComVariant));
+ PRECONDITION(CheckPointer(pOleVariant));
+ }
+ CONTRACTL_END;
+
+ *(INT64*)pComVariant->GetData() = V_BOOL(pOleVariant) ? 1 : 0;
+}
+
+#endif // FEATURE_COMINTEROP
+
+void OleVariant::MarshalBoolArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray,
+ MethodTable *pInterfaceMT)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pComArray);
+
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+
+ VARIANT_BOOL *pOle = (VARIANT_BOOL *) oleArray;
+ VARIANT_BOOL *pOleEnd = pOle + elementCount;
+
+ UCHAR *pCom = (UCHAR *) (*pComArray)->GetDataPtr();
+
+ while (pOle < pOleEnd)
+ {
+ static_assert_no_msg(sizeof(VARIANT_BOOL) == sizeof(UINT16));
+ (*(pCom++)) = MAYBE_UNALIGNED_READ(pOle, 16) ? 1 : 0;
+ pOle++;
+ }
+}
+
+void OleVariant::MarshalBoolArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
+ MethodTable *pInterfaceMT, BOOL fBestFitMapping,
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pComArray);
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+
+ VARIANT_BOOL *pOle = (VARIANT_BOOL *) oleArray;
+ VARIANT_BOOL *pOleEnd = pOle + elementCount;
+
+ UCHAR *pCom = (UCHAR *) (*pComArray)->GetDataPtr();
+
+ while (pOle < pOleEnd)
+ {
+ static_assert_no_msg(sizeof(VARIANT_BOOL) == sizeof(UINT16));
+ MAYBE_UNALIGNED_WRITE(pOle, 16, *pCom ? VARIANT_TRUE : VARIANT_FALSE);
+ pOle++; pCom++;
+ }
+}
+
+/* ------------------------------------------------------------------------- *
+ * WinBoolean marshaling routines
+ * ------------------------------------------------------------------------- */
+
+#ifdef FEATURE_COMINTEROP
+void OleVariant::MarshalWinBoolVariantOleToCom(VARIANT *pOleVariant,
+ VariantData *pComVariant)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ _ASSERTE(!"Not supposed to get here.");
+}
+
+void OleVariant::MarshalWinBoolVariantComToOle(VariantData *pComVariant,
+ VARIANT *pOleVariant)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ _ASSERTE(!"Not supposed to get here.");
+}
+
+void OleVariant::MarshalWinBoolVariantOleRefToCom(VARIANT *pOleVariant,
+ VariantData *pComVariant)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ _ASSERTE(!"Not supposed to get here.");
+}
+#endif // FEATURE_COMINTEROP
+
+void OleVariant::MarshalWinBoolArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray,
+ MethodTable *pInterfaceMT)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pComArray);
+
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+
+ BOOL *pOle = (BOOL *) oleArray;
+ BOOL *pOleEnd = pOle + elementCount;
+
+ UCHAR *pCom = (UCHAR *) (*pComArray)->GetDataPtr();
+
+ while (pOle < pOleEnd)
+ {
+ static_assert_no_msg(sizeof(BOOL) == sizeof(UINT32));
+ (*(pCom++)) = MAYBE_UNALIGNED_READ(pOle, 32) ? 1 : 0;
+ pOle++;
+ }
+}
+
+void OleVariant::MarshalWinBoolArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
+ MethodTable *pInterfaceMT, BOOL fBestFitMapping,
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pComArray);
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+
+ BOOL *pOle = (BOOL *) oleArray;
+ BOOL *pOleEnd = pOle + elementCount;
+
+ UCHAR *pCom = (UCHAR *) (*pComArray)->GetDataPtr();
+
+ while (pOle < pOleEnd)
+ {
+ static_assert_no_msg(sizeof(BOOL) == sizeof(UINT32));
+ MAYBE_UNALIGNED_WRITE(pOle, 32, *pCom ? 1 : 0);
+ pOle++; pCom++;
+ }
+}
+
+/* ------------------------------------------------------------------------- *
+ * CBool marshaling routines
+ * ------------------------------------------------------------------------- */
+
+#ifdef FEATURE_COMINTEROP
+void OleVariant::MarshalCBoolVariantOleToCom(VARIANT* pOleVariant, VariantData* pComVariant)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ _ASSERTE(!"Not supposed to get here.");
+}
+
+void OleVariant::MarshalCBoolVariantComToOle(VariantData* pComVariant, VARIANT* pOleVariant)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ _ASSERTE(!"Not supposed to get here.");
+}
+
+void OleVariant::MarshalCBoolVariantOleRefToCom(VARIANT* pOleVariant, VariantData* pComVariant)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ _ASSERTE(!"Not supposed to get here.");
+}
+#endif // FEATURE_COMINTEROP
+
+void OleVariant::MarshalCBoolArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray,
+ MethodTable* pInterfaceMT)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pComArray);
+
+ _ASSERTE((*pComArray)->GetArrayElementType() == ELEMENT_TYPE_BOOLEAN);
+
+ SIZE_T cbArray = (*pComArray)->GetNumComponents();
+
+ BYTE *pOle = (BYTE *) oleArray;
+ BYTE *pOleEnd = pOle + cbArray;
+
+ UCHAR *pCom = (UCHAR *) (*pComArray)->GetDataPtr();
+
+ while (pOle < pOleEnd)
+ {
+ (*pCom) = (*pOle ? 1 : 0);
+ pOle++; pCom++;
+ }
+}
+
+void OleVariant::MarshalCBoolArrayComToOle(BASEARRAYREF* pComArray, void* oleArray,
+ MethodTable* pInterfaceMT, BOOL fBestFitMapping,
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pComArray);
+
+ _ASSERTE((*pComArray)->GetArrayElementType() == ELEMENT_TYPE_BOOLEAN);
+
+ SIZE_T cbArray = (*pComArray)->GetNumComponents();
+ BYTE *pOle = (BYTE *) oleArray;
+ BYTE *pOleEnd = pOle + cbArray;
+
+ UCHAR *pCom = (UCHAR *) (*pComArray)->GetDataPtr();
+
+ while (pOle < pOleEnd)
+ {
+ *pOle = (*pCom ? 1 : 0);
+ pOle++; pCom++;
+ }
+}
+
+/* ------------------------------------------------------------------------- *
+ * Ansi char marshaling routines
+ * ------------------------------------------------------------------------- */
+
+#ifdef FEATURE_COMINTEROP
+void OleVariant::MarshalAnsiCharVariantOleToCom(VARIANT *pOleVariant,
+ VariantData *pComVariant)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ _ASSERTE(!"Not supposed to get here.");
+}
+
+void OleVariant::MarshalAnsiCharVariantComToOle(VariantData *pComVariant,
+ VARIANT *pOleVariant)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ _ASSERTE(!"Not supposed to get here.");
+}
+
+void OleVariant::MarshalAnsiCharVariantOleRefToCom(VARIANT *pOleVariant,
+ VariantData *pComVariant)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ _ASSERTE(!"Not supposed to get here.");
+}
+#endif // FEATURE_COMINTEROP
+
+void OleVariant::MarshalAnsiCharArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray,
+ MethodTable *pInterfaceMT)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pComArray);
+
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+
+ WCHAR *pCom = (WCHAR *) (*pComArray)->GetDataPtr();
+
+ if (0 == elementCount)
+ {
+ *pCom = '\0';
+ return;
+ }
+
+ if (0 == MultiByteToWideChar(CP_ACP,
+ MB_PRECOMPOSED,
+ (const CHAR *)oleArray,
+ (int)elementCount,
+ pCom,
+ (int)elementCount))
+ {
+ COMPlusThrowWin32();
+ }
+}
+
+void OleVariant::MarshalAnsiCharArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
+ MethodTable *pInterfaceMT, BOOL fBestFitMapping,
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ }
+ CONTRACTL_END;
+
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+
+ const WCHAR *pCom = (const WCHAR *) (*pComArray)->GetDataPtr();
+
+ if (!FitsIn<int>(elementCount))
+ COMPlusThrowHR(COR_E_OVERFLOW);
+
+ int cchCount = (int)elementCount;
+ int cbBuffer;
+
+ if (!ClrSafeInt<int>::multiply(cchCount, GetMaxDBCSCharByteSize(), cbBuffer))
+ COMPlusThrowHR(COR_E_OVERFLOW);
+
+ InternalWideToAnsi((WCHAR*)pCom, cchCount, (CHAR*)oleArray, cbBuffer,
+ fBestFitMapping, fThrowOnUnmappableChar);
+}
+
+/* ------------------------------------------------------------------------- *
+ * Interface marshaling routines
+ * ------------------------------------------------------------------------- */
+
+#ifdef FEATURE_COMINTEROP
+void OleVariant::MarshalInterfaceVariantOleToCom(VARIANT *pOleVariant,
+ VariantData *pComVariant)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pOleVariant));
+ PRECONDITION(CheckPointer(pComVariant));
+ }
+ CONTRACTL_END;
+
+ IUnknown *unk = V_UNKNOWN(pOleVariant);
+
+ OBJECTREF obj = NULL;
+ if (unk != NULL)
+ {
+ GCPROTECT_BEGIN(obj);
+ GetObjectRefFromComIP(&obj, V_UNKNOWN(pOleVariant));
+ GCPROTECT_END();
+ }
+
+ pComVariant->SetObjRef(obj);
+}
+
+void OleVariant::MarshalInterfaceVariantComToOle(VariantData *pComVariant,
+ VARIANT *pOleVariant)
+
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pOleVariant));
+ PRECONDITION(CheckPointer(pComVariant));
+ }
+ CONTRACTL_END;
+
+ OBJECTREF *obj = pComVariant->GetObjRefPtr();
+ VARTYPE vt = pComVariant->GetVT();
+
+ ASSERT_PROTECTED(obj);
+
+ if (*obj == NULL)
+ {
+ // If there is no VT set in the managed variant, then default to VT_UNKNOWN.
+ if (vt == VT_EMPTY)
+ vt = VT_UNKNOWN;
+
+ V_UNKNOWN(pOleVariant) = NULL;
+ V_VT(pOleVariant) = vt;
+ }
+ else
+ {
+#ifdef FEATURE_COMINTEROP
+ ComIpType FetchedIpType = ComIpType_None;
+ ComIpType ReqIpType;
+
+ if (vt != VT_EMPTY)
+ {
+ // We are dealing with an UnknownWrapper or DispatchWrapper.
+ // In this case, we need to respect the VT.
+ _ASSERTE(vt == VT_DISPATCH || vt == VT_UNKNOWN);
+ ReqIpType = vt == VT_DISPATCH ? ComIpType_Dispatch : ComIpType_Unknown;
+ }
+ else
+ {
+ // We are dealing with a normal object so we can give either
+ // IDispatch or IUnknown out depending on what it supports.
+ ReqIpType = ComIpType_Both;
+ }
+
+ IUnknown *unk = GetComIPFromObjectRef(obj, ReqIpType, &FetchedIpType);
+ BOOL ItfIsDispatch = FetchedIpType == ComIpType_Dispatch;
+
+ V_UNKNOWN(pOleVariant) = unk;
+ V_VT(pOleVariant) = static_cast<VARTYPE>(ItfIsDispatch ? VT_DISPATCH : VT_UNKNOWN);
+#else // FEATURE_COMINTEROP
+ V_UNKNOWN(pOleVariant) = GetComIPFromObjectRef(obj);
+ V_VT(pOleVariant) = VT_UNKNOWN;
+#endif // FEATURE_COMINTEROP
+ }
+}
+
+void OleVariant::MarshalInterfaceVariantOleRefToCom(VARIANT *pOleVariant,
+ VariantData *pComVariant)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pOleVariant));
+ PRECONDITION(CheckPointer(pComVariant));
+ }
+ CONTRACTL_END;
+
+ IUnknown *unk = V_UNKNOWN(pOleVariant);
+
+ OBJECTREF obj = NULL;
+ if (unk != NULL)
+ {
+ GCPROTECT_BEGIN(obj);
+ GetObjectRefFromComIP(&obj, *V_UNKNOWNREF(pOleVariant));
+ GCPROTECT_END();
+ }
+
+ pComVariant->SetObjRef(obj);
+}
+
+void OleVariant::MarshalInterfaceArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray,
+ MethodTable *pElementMT)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pComArray);
+
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+
+ IUnknown **pOle = (IUnknown **) oleArray;
+ IUnknown **pOleEnd = pOle + elementCount;
+
+ BASEARRAYREF unprotectedArray = *pComArray;
+ OBJECTREF *pCom = (OBJECTREF *) unprotectedArray->GetDataPtr();
+
+#if CHECK_APP_DOMAIN_LEAKS
+ AppDomain *pDomain = unprotectedArray->GetAppDomain();
+#endif // CHECK_APP_DOMAIN_LEAKS
+
+ OBJECTREF obj = NULL;
+ GCPROTECT_BEGIN(obj)
+ {
+ while (pOle < pOleEnd)
+ {
+ IUnknown *unk = *pOle++;
+
+ if (unk == NULL)
+ obj = NULL;
+ else
+ GetObjectRefFromComIP(&obj, unk);
+
+ //
+ // Make sure the object can be cast to the destination type.
+ //
+
+ if (pElementMT != NULL && !CanCastComObject(obj, pElementMT))
+ {
+ StackSString ssObjClsName;
+ StackSString ssDestClsName;
+ obj->GetMethodTable()->_GetFullyQualifiedNameForClass(ssObjClsName);
+ pElementMT->_GetFullyQualifiedNameForClass(ssDestClsName);
+ COMPlusThrow(kInvalidCastException, IDS_EE_CANNOTCAST,
+ ssObjClsName.GetUnicode(), ssDestClsName.GetUnicode());
+ }
+
+ //
+ // Reset pCom pointer only if array object has moved, rather than
+ // recomputing every time through the loop. Beware implicit calls to
+ // ValidateObject inside OBJECTREF methods.
+ //
+
+ if (*(void **)&unprotectedArray != *(void **)&*pComArray)
+ {
+ SIZE_T currentOffset = ((BYTE *)pCom) - (*(Object **) &unprotectedArray)->GetAddress();
+ unprotectedArray = *pComArray;
+ pCom = (OBJECTREF *) (unprotectedArray->GetAddress() + currentOffset);
+ }
+
+ SetObjectReference(pCom++, obj, pDomain);
+ }
+ }
+ GCPROTECT_END();
+}
+
+void OleVariant::MarshalIUnknownArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
+ MethodTable *pElementMT, BOOL fBestFitMapping,
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+{
+ WRAPPER_NO_CONTRACT;
+
+ MarshalInterfaceArrayComToOleHelper(pComArray, oleArray, pElementMT, FALSE);
+}
+
+void OleVariant::ClearInterfaceArray(void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(oleArray));
+ }
+ CONTRACTL_END;
+
+ IUnknown **pOle = (IUnknown **) oleArray;
+ IUnknown **pOleEnd = pOle + cElements;
+
+ GCX_PREEMP();
+ while (pOle < pOleEnd)
+ {
+ IUnknown *pUnk = *pOle++;
+
+ if (pUnk != NULL)
+ {
+ ULONG cbRef = SafeReleasePreemp(pUnk);
+ LogInteropRelease(pUnk, cbRef, "VariantClearInterfacArray");
+ }
+ }
+}
+
+
+/* ------------------------------------------------------------------------- *
+ * BSTR marshaling routines
+ * ------------------------------------------------------------------------- */
+
+void OleVariant::MarshalBSTRVariantOleToCom(VARIANT *pOleVariant,
+ VariantData *pComVariant)
+{
+ CONTRACTL
+ {
+ WRAPPER(THROWS);
+ WRAPPER(GC_TRIGGERS);
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(pOleVariant));
+ PRECONDITION(CheckPointer(pComVariant));
+ }
+ CONTRACTL_END;
+
+ BSTR bstr = V_BSTR(pOleVariant);
+
+ STRINGREF stringObj = NULL;
+ GCPROTECT_BEGIN(stringObj)
+ {
+ ConvertBSTRToString(bstr, &stringObj);
+ pComVariant->SetObjRef((OBJECTREF) stringObj);
+ }
+ GCPROTECT_END();
+
+ pComVariant->SetObjRef((OBJECTREF) stringObj);
+}
+
+void OleVariant::MarshalBSTRVariantComToOle(VariantData *pComVariant,
+ VARIANT *pOleVariant)
+{
+ CONTRACTL
+ {
+ THROWS;
+ WRAPPER(GC_TRIGGERS);
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(pOleVariant));
+ PRECONDITION(CheckPointer(pComVariant));
+ }
+ CONTRACTL_END;
+
+ STRINGREF stringObj = (STRINGREF) pComVariant->GetObjRef();
+ GCPROTECT_BEGIN(stringObj)
+ {
+ V_BSTR(pOleVariant) = ConvertStringToBSTR(&stringObj);
+ }
+ GCPROTECT_END();
+}
+
+void OleVariant::MarshalBSTRArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray,
+ MethodTable *pInterfaceMT)
+{
+ CONTRACTL
+ {
+ WRAPPER(THROWS);
+ WRAPPER(GC_TRIGGERS);
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ }
+ CONTRACTL_END;
+
+ STRINGREF stringObj = NULL;
+ GCPROTECT_BEGIN(stringObj)
+ {
+ ASSERT_PROTECTED(pComArray);
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+
+ BSTR *pOle = (BSTR *) oleArray;
+ BSTR *pOleEnd = pOle + elementCount;
+
+ BASEARRAYREF unprotectedArray = *pComArray;
+ STRINGREF *pCom = (STRINGREF *) unprotectedArray->GetDataPtr();
+
+#if CHECK_APP_DOMAIN_LEAKS
+ AppDomain *pDomain = unprotectedArray->GetAppDomain();
+#endif // CHECK_APP_DOMAIN_LEAKS
+
+ while (pOle < pOleEnd)
+ {
+ BSTR bstr = *pOle++;
+
+ ConvertBSTRToString(bstr, &stringObj);
+
+ //
+ // Reset pCom pointer only if array object has moved, rather than
+ // recomputing it every time through the loop. Beware implicit calls to
+ // ValidateObject inside OBJECTREF methods.
+ //
+
+ if (*(void **)&unprotectedArray != *(void **)&*pComArray)
+ {
+ SIZE_T currentOffset = ((BYTE *)pCom) - (*(Object **) &unprotectedArray)->GetAddress();
+ unprotectedArray = *pComArray;
+ pCom = (STRINGREF *) (unprotectedArray->GetAddress() + currentOffset);
+ }
+
+ SetObjectReference((OBJECTREF*) pCom++, (OBJECTREF) stringObj, pDomain);
+ }
+ }
+ GCPROTECT_END();
+}
+
+void OleVariant::MarshalBSTRArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
+ MethodTable *pInterfaceMT, BOOL fBestFitMapping,
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+{
+ CONTRACTL
+ {
+ THROWS;
+ WRAPPER(GC_TRIGGERS);
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ }
+ CONTRACTL_END;
+
+ STRINGREF stringObj = NULL;
+ GCPROTECT_BEGIN(stringObj)
+ {
+ ASSERT_PROTECTED(pComArray);
+
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+
+ BSTR *pOle = (BSTR *) oleArray;
+ BSTR *pOleEnd = pOle + elementCount;
+
+ STRINGREF *pCom = (STRINGREF *) (*pComArray)->GetDataPtr();
+
+ while (pOle < pOleEnd)
+ {
+ stringObj = *pCom++;
+ BSTR bstr = ConvertStringToBSTR(&stringObj);
+
+ //
+ // We aren't calling anything which might cause a GC, so don't worry about
+ // the array moving here.
+ //
+
+ *pOle++ = bstr;
+ }
+ }
+ GCPROTECT_END();
+}
+
+void OleVariant::ClearBSTRArray(void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(oleArray));
+ }
+ CONTRACTL_END;
+
+ BSTR *pOle = (BSTR *) oleArray;
+ BSTR *pOleEnd = pOle + cElements;
+
+ while (pOle < pOleEnd)
+ {
+ BSTR bstr = *pOle++;
+
+ if (bstr != NULL)
+ SysFreeString(bstr);
+ }
+}
+#endif // FEATURE_COMINTEROP
+
+
+
+/* ------------------------------------------------------------------------- *
+ * Structure marshaling routines
+ * ------------------------------------------------------------------------- */
+void OleVariant::MarshalNonBlittableRecordArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray,
+ MethodTable *pInterfaceMT)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ PRECONDITION(CheckPointer(pInterfaceMT));
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pComArray);
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+ SIZE_T elemSize = pInterfaceMT->GetNativeSize();
+
+ BYTE *pOle = (BYTE *) oleArray;
+ BYTE *pOleEnd = pOle + elemSize * elementCount;
+
+ SIZE_T dstofs = ArrayBase::GetDataPtrOffset( (*pComArray)->GetMethodTable() );
+ while (pOle < pOleEnd)
+ {
+ LayoutUpdateCLR( (LPVOID*)pComArray, dstofs, pInterfaceMT, pOle );
+ dstofs += (*pComArray)->GetComponentSize();
+ pOle += elemSize;
+ }
+}
+
+void OleVariant::MarshalNonBlittableRecordArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
+ MethodTable *pInterfaceMT, BOOL fBestFitMapping,
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ PRECONDITION(CheckPointer(pInterfaceMT));
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pComArray);
+
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+ SIZE_T elemSize = pInterfaceMT->GetNativeSize();
+
+ BYTE *pOle = (BYTE *) oleArray;
+ BYTE *pOleEnd = pOle + elemSize * elementCount;
+
+ if (!fOleArrayIsValid)
+ {
+ // field marshalers assume that the native structure is valid
+ FillMemory(pOle, pOleEnd - pOle, 0);
+ }
+
+ SIZE_T srcofs = ArrayBase::GetDataPtrOffset( (*pComArray)->GetMethodTable() );
+ while (pOle < pOleEnd)
+ {
+ LayoutUpdateNative( (LPVOID*)pComArray, srcofs, pInterfaceMT, pOle, NULL );
+ pOle += elemSize;
+ srcofs += (*pComArray)->GetComponentSize();
+ }
+}
+
+void OleVariant::ClearNonBlittableRecordArray(void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pInterfaceMT));
+ }
+ CONTRACTL_END;
+
+ SIZE_T elemSize = pInterfaceMT->GetNativeSize();
+ BYTE *pOle = (BYTE *) oleArray;
+ BYTE *pOleEnd = pOle + elemSize * cElements;
+ while (pOle < pOleEnd)
+ {
+ LayoutDestroyNative(pOle, pInterfaceMT);
+ pOle += elemSize;
+ }
+}
+
+
+/* ------------------------------------------------------------------------- *
+ * LPWSTR marshaling routines
+ * ------------------------------------------------------------------------- */
+
+void OleVariant::MarshalLPWSTRArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray,
+ MethodTable *pInterfaceMT)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pComArray);
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+
+ LPWSTR *pOle = (LPWSTR *) oleArray;
+ LPWSTR *pOleEnd = pOle + elementCount;
+
+ BASEARRAYREF unprotectedArray = *pComArray;
+ STRINGREF *pCom = (STRINGREF *) unprotectedArray->GetDataPtr();
+
+#if CHECK_APP_DOMAIN_LEAKS
+ AppDomain *pDomain = unprotectedArray->GetAppDomain();
+#endif // CHECK_APP_DOMAIN_LEAKS
+
+ while (pOle < pOleEnd)
+ {
+ LPWSTR lpwstr = *pOle++;
+
+ STRINGREF string;
+ if (lpwstr == NULL)
+ string = NULL;
+ else
+ string = StringObject::NewString(lpwstr);
+
+ //
+ // Reset pCom pointer only if array object has moved, rather than
+ // recomputing it every time through the loop. Beware implicit calls to
+ // ValidateObject inside OBJECTREF methods.
+ //
+
+ if (*(void **)&unprotectedArray != *(void **)&*pComArray)
+ {
+ SIZE_T currentOffset = ((BYTE *)pCom) - (*(Object **) &unprotectedArray)->GetAddress();
+ unprotectedArray = *pComArray;
+ pCom = (STRINGREF *) (unprotectedArray->GetAddress() + currentOffset);
+ }
+
+ SetObjectReference((OBJECTREF*) pCom++, (OBJECTREF) string, pDomain);
+ }
+}
+
+void OleVariant::MarshalLPWSTRRArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
+ MethodTable *pInterfaceMT, BOOL fBestFitMapping,
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pComArray);
+
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+
+ LPWSTR *pOle = (LPWSTR *) oleArray;
+ LPWSTR *pOleEnd = pOle + elementCount;
+
+ STRINGREF *pCom = (STRINGREF *) (*pComArray)->GetDataPtr();
+
+ while (pOle < pOleEnd)
+ {
+ //
+ // We aren't calling anything which might cause a GC, so don't worry about
+ // the array moving here.
+ //
+
+ STRINGREF stringRef = *pCom++;
+
+ LPWSTR lpwstr;
+ if (stringRef == NULL)
+ {
+ lpwstr = NULL;
+ }
+ else
+ {
+ // Retrieve the length of the string.
+ int Length = stringRef->GetStringLength();
+ int allocLength = (Length + 1) * sizeof(WCHAR);
+ if (allocLength < Length)
+ ThrowOutOfMemory();
+
+ // Allocate the string using CoTaskMemAlloc.
+ lpwstr = (LPWSTR)CoTaskMemAlloc(allocLength);
+ if (lpwstr == NULL)
+ ThrowOutOfMemory();
+
+ // Copy the COM+ string into the newly allocated LPWSTR.
+ memcpyNoGCRefs(lpwstr, stringRef->GetBuffer(), (Length + 1) * sizeof(WCHAR));
+ lpwstr[Length] = 0;
+ }
+
+ *pOle++ = lpwstr;
+ }
+}
+
+void OleVariant::ClearLPWSTRArray(void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(oleArray));
+ }
+ CONTRACTL_END;
+
+ LPWSTR *pOle = (LPWSTR *) oleArray;
+ LPWSTR *pOleEnd = pOle + cElements;
+
+ while (pOle < pOleEnd)
+ {
+ LPWSTR lpwstr = *pOle++;
+
+ if (lpwstr != NULL)
+ CoTaskMemFree(lpwstr);
+ }
+}
+
+/* ------------------------------------------------------------------------- *
+ * LPWSTR marshaling routines
+ * ------------------------------------------------------------------------- */
+
+void OleVariant::MarshalLPSTRArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray,
+ MethodTable *pInterfaceMT)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pComArray);
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+
+ LPSTR *pOle = (LPSTR *) oleArray;
+ LPSTR *pOleEnd = pOle + elementCount;
+
+ BASEARRAYREF unprotectedArray = *pComArray;
+ STRINGREF *pCom = (STRINGREF *) unprotectedArray->GetDataPtr();
+
+#if CHECK_APP_DOMAIN_LEAKS
+ AppDomain *pDomain = unprotectedArray->GetAppDomain();
+#endif // CHECK_APP_DOMAIN_LEAKS
+
+ while (pOle < pOleEnd)
+ {
+ LPSTR lpstr = *pOle++;
+
+ STRINGREF string;
+ if (lpstr == NULL)
+ string = NULL;
+ else
+ string = StringObject::NewString(lpstr);
+
+ //
+ // Reset pCom pointer only if array object has moved, rather than
+ // recomputing it every time through the loop. Beware implicit calls to
+ // ValidateObject inside OBJECTREF methods.
+ //
+
+ if (*(void **)&unprotectedArray != *(void **)&*pComArray)
+ {
+ SIZE_T currentOffset = ((BYTE *)pCom) - (*(Object **) &unprotectedArray)->GetAddress();
+ unprotectedArray = *pComArray;
+ pCom = (STRINGREF *) (unprotectedArray->GetAddress() + currentOffset);
+ }
+
+ SetObjectReference((OBJECTREF*) pCom++, (OBJECTREF) string, pDomain);
+ }
+}
+
+void OleVariant::MarshalLPSTRRArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
+ MethodTable *pInterfaceMT, BOOL fBestFitMapping,
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pComArray);
+
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+
+ LPSTR *pOle = (LPSTR *) oleArray;
+ LPSTR *pOleEnd = pOle + elementCount;
+
+ STRINGREF *pCom = (STRINGREF *) (*pComArray)->GetDataPtr();
+
+ while (pOle < pOleEnd)
+ {
+ //
+ // We aren't calling anything which might cause a GC, so don't worry about
+ // the array moving here.
+ //
+ STRINGREF stringRef = *pCom++;
+
+ CoTaskMemHolder<CHAR> lpstr(NULL);
+ if (stringRef == NULL)
+ {
+ lpstr = NULL;
+ }
+ else
+ {
+ // Retrieve the length of the string.
+ int Length = stringRef->GetStringLength();
+ int allocLength = Length * GetMaxDBCSCharByteSize() + 1;
+ if (allocLength < Length)
+ ThrowOutOfMemory();
+
+ // Allocate the string using CoTaskMemAlloc.
+ lpstr = (LPSTR)CoTaskMemAlloc(allocLength);
+ if (lpstr == NULL)
+ ThrowOutOfMemory();
+
+ // Convert the unicode string to an ansi string.
+ InternalWideToAnsi(stringRef->GetBuffer(), Length, lpstr, allocLength, fBestFitMapping, fThrowOnUnmappableChar);
+ lpstr[Length] = 0;
+ }
+
+ *pOle++ = lpstr;
+ lpstr.SuppressRelease();
+ }
+}
+
+void OleVariant::ClearLPSTRArray(void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(oleArray));
+ }
+ CONTRACTL_END;
+
+ LPSTR *pOle = (LPSTR *) oleArray;
+ LPSTR *pOleEnd = pOle + cElements;
+
+ while (pOle < pOleEnd)
+ {
+ LPSTR lpstr = *pOle++;
+
+ if (lpstr != NULL)
+ CoTaskMemFree(lpstr);
+ }
+}
+
+/* ------------------------------------------------------------------------- *
+ * Date marshaling routines
+ * ------------------------------------------------------------------------- */
+
+#ifdef FEATURE_COMINTEROP
+void OleVariant::MarshalDateVariantOleToCom(VARIANT *pOleVariant,
+ VariantData *pComVariant)
+{
+ WRAPPER_NO_CONTRACT;
+
+ *(INT64*)pComVariant->GetData() = COMDateTime::DoubleDateToTicks(V_DATE(pOleVariant));
+}
+
+void OleVariant::MarshalDateVariantComToOle(VariantData *pComVariant,
+ VARIANT *pOleVariant)
+{
+ WRAPPER_NO_CONTRACT;
+
+ V_DATE(pOleVariant) = COMDateTime::TicksToDoubleDate(*(INT64*)pComVariant->GetData());
+}
+
+void OleVariant::MarshalDateVariantOleRefToCom(VARIANT *pOleVariant,
+ VariantData *pComVariant)
+{
+ WRAPPER_NO_CONTRACT;
+
+ *(INT64*)pComVariant->GetData() = COMDateTime::DoubleDateToTicks(*V_DATEREF(pOleVariant));
+}
+#endif // FEATURE_COMINTEROP
+
+void OleVariant::MarshalDateArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray,
+ MethodTable *pInterfaceMT)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pComArray);
+
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+
+ DATE *pOle = (DATE *) oleArray;
+ DATE *pOleEnd = pOle + elementCount;
+
+ INT64 *pCom = (INT64 *) (*pComArray)->GetDataPtr();
+
+ //
+ // We aren't calling anything which might cause a GC, so don't worry about
+ // the array moving here.
+ //
+
+ while (pOle < pOleEnd)
+ *pCom++ = COMDateTime::DoubleDateToTicks(*pOle++);
+}
+
+void OleVariant::MarshalDateArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
+ MethodTable *pInterfaceMT, BOOL fBestFitMapping,
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pComArray);
+
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+
+ DATE *pOle = (DATE *) oleArray;
+ DATE *pOleEnd = pOle + elementCount;
+
+ INT64 *pCom = (INT64 *) (*pComArray)->GetDataPtr();
+
+ //
+ // We aren't calling anything which might cause a GC, so don't worry about
+ // the array moving here.
+ //
+
+ while (pOle < pOleEnd)
+ *pOle++ = COMDateTime::TicksToDoubleDate(*pCom++);
+}
+
+/* ------------------------------------------------------------------------- *
+ * Decimal marshaling routines
+ * ------------------------------------------------------------------------- */
+
+#ifdef FEATURE_COMINTEROP
+
+void OleVariant::MarshalDecimalVariantOleToCom(VARIANT *pOleVariant,
+ VariantData *pComVariant)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(pOleVariant));
+ PRECONDITION(CheckPointer(pComVariant));
+ }
+ CONTRACTL_END;
+
+ OBJECTREF pDecimalRef = AllocateObject(MscorlibBinder::GetClass(CLASS__DECIMAL));
+
+ DECIMAL* pDecimal = (DECIMAL *) pDecimalRef->UnBox();
+ *pDecimal = V_DECIMAL(pOleVariant);
+ // Mashaling uses the reserved value to store the variant type, so clear it out when marshaling back
+ pDecimal->wReserved = 0;
+
+ pComVariant->SetObjRef(pDecimalRef);
+}
+
+void OleVariant::MarshalDecimalVariantComToOle(VariantData *pComVariant,
+ VARIANT *pOleVariant)
+{
+ CONTRACTL
+ {
+ WRAPPER(THROWS);
+ WRAPPER(GC_TRIGGERS);
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pOleVariant));
+ PRECONDITION(CheckPointer(pComVariant));
+ }
+ CONTRACTL_END;
+
+ VARTYPE vt = V_VT(pOleVariant);
+ _ASSERTE(vt == VT_DECIMAL);
+ V_DECIMAL(pOleVariant) = * (DECIMAL*) pComVariant->GetObjRef()->UnBox();
+ V_VT(pOleVariant) = vt;
+}
+
+void OleVariant::MarshalDecimalVariantOleRefToCom(VARIANT *pOleVariant,
+ VariantData *pComVariant )
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(pOleVariant));
+ PRECONDITION(CheckPointer(pComVariant));
+ }
+ CONTRACTL_END;
+
+ OBJECTREF pDecimalRef = AllocateObject(MscorlibBinder::GetClass(CLASS__DECIMAL));
+
+ DECIMAL* pDecimal = (DECIMAL *) pDecimalRef->UnBox();
+ *pDecimal = *V_DECIMALREF(pOleVariant);
+ // Mashaling uses the reserved value to store the variant type, so clear it out when marshaling back
+ pDecimal->wReserved = 0;
+
+ pComVariant->SetObjRef(pDecimalRef);
+}
+#endif // FEATURE_COMINTEROP
+
+/* ------------------------------------------------------------------------- *
+ * Record marshaling routines
+ * ------------------------------------------------------------------------- */
+
+#ifdef FEATURE_CLASSIC_COMINTEROP
+void OleVariant::MarshalRecordVariantOleToCom(VARIANT *pOleVariant,
+ VariantData *pComVariant)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(pOleVariant));
+ PRECONDITION(CheckPointer(pComVariant));
+ }
+ CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+ IRecordInfo *pRecInfo = V_RECORDINFO(pOleVariant);
+ if (!pRecInfo)
+ COMPlusThrow(kArgumentException, IDS_EE_INVALID_OLE_VARIANT);
+
+ OBJECTREF BoxedValueClass = NULL;
+ GCPROTECT_BEGIN(BoxedValueClass)
+ {
+ LPVOID pvRecord = V_RECORD(pOleVariant);
+ if (pvRecord)
+ {
+ // Go to the registry to find the value class associated
+ // with the record's guid.
+ GUID guid;
+ IfFailThrow(pRecInfo->GetGuid(&guid));
+ MethodTable *pValueClass = GetValueTypeForGUID(guid);
+ if (!pValueClass)
+ COMPlusThrow(kArgumentException, IDS_EE_CANNOT_MAP_TO_MANAGED_VC);
+
+ Module* pModule = pValueClass->GetModule();
+ if (!Security::CanCallUnmanagedCode(pModule))
+ {
+ COMPlusThrow(kArgumentException, IDS_EE_VTRECORD_SECURITY);
+ }
+
+ // Now that we have the value class, allocate an instance of the
+ // boxed value class and copy the contents of the record into it.
+ BoxedValueClass = AllocateObject(pValueClass);
+ FmtClassUpdateCLR(&BoxedValueClass, (BYTE*)pvRecord);
+ }
+
+ pComVariant->SetObjRef(BoxedValueClass);
+ }
+ GCPROTECT_END();
+}
+
+void OleVariant::MarshalRecordVariantComToOle(VariantData *pComVariant,
+ VARIANT *pOleVariant)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pOleVariant));
+ PRECONDITION(CheckPointer(pComVariant));
+ }
+ CONTRACTL_END;
+
+ OBJECTREF BoxedValueClass = pComVariant->GetObjRef();
+ GCPROTECT_BEGIN(BoxedValueClass)
+ {
+ _ASSERTE(BoxedValueClass != NULL);
+ Module* pModule = BoxedValueClass->GetMethodTable()->GetModule();
+ if (!Security::CanCallUnmanagedCode(pModule))
+ {
+ COMPlusThrow(kArgumentException, IDS_EE_VTRECORD_SECURITY);
+ }
+
+ ConvertValueClassToVariant(&BoxedValueClass, pOleVariant);
+ }
+ GCPROTECT_END();
+}
+
+void OleVariant::MarshalRecordVariantOleRefToCom(VARIANT *pOleVariant,
+ VariantData *pComVariant)
+{
+ WRAPPER_NO_CONTRACT;
+
+ // The representation of a VT_RECORD and a VT_BYREF | VT_RECORD VARIANT are
+ // the same so we can simply forward the call to the non byref API.
+ MarshalRecordVariantOleToCom(pOleVariant, pComVariant);
+}
+#endif // FEATURE_CLASSIC_COMINTEROP
+
+void OleVariant::MarshalRecordArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray,
+ MethodTable *pElementMT)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ PRECONDITION(CheckPointer(pElementMT));
+ }
+ CONTRACTL_END;
+
+ Module* pModule = pElementMT->GetModule();
+ if (!Security::CanCallUnmanagedCode(pModule))
+ {
+ COMPlusThrow(kArgumentException, IDS_EE_VTRECORD_SECURITY);
+ }
+
+ if (pElementMT->IsBlittable())
+ {
+ // The array is blittable so we can simply copy it.
+ _ASSERTE(pComArray);
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+ SIZE_T elemSize = pElementMT->GetNativeSize();
+ memcpyNoGCRefs((*pComArray)->GetDataPtr(), oleArray, elementCount * elemSize);
+ }
+ else
+ {
+ // The array is non blittable so we need to marshal the elements.
+ _ASSERTE(pElementMT->HasLayout());
+ MarshalNonBlittableRecordArrayOleToCom(oleArray, pComArray, pElementMT);
+ }
+}
+
+void OleVariant::MarshalRecordArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
+ MethodTable *pElementMT, BOOL fBestFitMapping,
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ PRECONDITION(CheckPointer(pElementMT));
+ }
+ CONTRACTL_END;
+
+ Module* pModule = pElementMT->GetModule();
+ if (!Security::CanCallUnmanagedCode(pModule))
+ {
+ COMPlusThrow(kArgumentException, IDS_EE_VTRECORD_SECURITY);
+ }
+
+ if (pElementMT->IsBlittable())
+ {
+ // The array is blittable so we can simply copy it.
+ _ASSERTE(pComArray);
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+ SIZE_T elemSize = pElementMT->GetNativeSize();
+ memcpyNoGCRefs(oleArray, (*pComArray)->GetDataPtr(), elementCount * elemSize);
+ }
+ else
+ {
+ // The array is non blittable so we need to marshal the elements.
+ _ASSERTE(pElementMT->HasLayout());
+ MarshalNonBlittableRecordArrayComToOle(pComArray, oleArray, pElementMT, fBestFitMapping, fThrowOnUnmappableChar, fOleArrayIsValid);
+ }
+}
+
+
+void OleVariant::ClearRecordArray(void *oleArray, SIZE_T cElements, MethodTable *pElementMT)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pElementMT));
+ }
+ CONTRACTL_END;
+
+ if (!pElementMT->IsBlittable())
+ {
+ _ASSERTE(pElementMT->HasLayout());
+ ClearNonBlittableRecordArray(oleArray, cElements, pElementMT);
+ }
+}
+
+#ifdef FEATURE_COMINTEROP
+
+// Warning! VariantClear's previous contents of pVarOut.
+void OleVariant::MarshalOleVariantForObject(OBJECTREF * const & pObj, VARIANT *pOle)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pObj));
+ PRECONDITION(*pObj == NULL || (IsProtectedByGCFrame (pObj)));
+
+ PRECONDITION(CheckPointer(pOle));
+ }
+ CONTRACTL_END;
+
+#ifdef FEATURE_CORECLR
+ if (AppX::IsAppXProcess())
+ {
+ COMPlusThrow(kPlatformNotSupportedException, IDS_EE_BADMARSHAL_TYPE_VARIANTASOBJECT);
+ }
+#endif // FEATURE_CORECLR
+
+ SafeVariantClear(pOle);
+
+#ifdef _DEBUG
+ FillMemory(pOle, sizeof(VARIANT),0xdd);
+ V_VT(pOle) = VT_EMPTY;
+#endif
+
+ // For perf reasons, let's handle the more common and easy cases
+ // without transitioning to managed code.
+ if (*pObj == NULL)
+ {
+ // null maps to VT_EMPTY - nothing to do here.
+ }
+ else
+ {
+ MethodTable *pMT = (*pObj)->GetMethodTable();
+ if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_I4))
+ {
+ V_I4(pOle) = *(LONG*)( (*pObj)->GetData() );
+ V_VT(pOle) = VT_I4;
+ }
+ else if (pMT == g_pStringClass)
+ {
+ if (*(pObj) == NULL)
+ {
+ V_BSTR(pOle) = NULL;
+ }
+ else
+ {
+ STRINGREF stringRef = (STRINGREF)(*pObj);
+ V_BSTR(pOle) = SysAllocStringLen(stringRef->GetBuffer(), stringRef->GetStringLength());
+ if (NULL == V_BSTR(pOle))
+ COMPlusThrowOM();
+ }
+
+ V_VT(pOle) = VT_BSTR;
+ }
+ else if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_I2))
+ {
+ V_I2(pOle) = *(SHORT*)( (*pObj)->GetData() );
+ V_VT(pOle) = VT_I2;
+ }
+ else if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_I1))
+ {
+ V_I1(pOle) = *(CHAR*)( (*pObj)->GetData() );
+ V_VT(pOle) = VT_I1;
+ }
+ else if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_U4))
+ {
+ V_UI4(pOle) = *(ULONG*)( (*pObj)->GetData() );
+ V_VT(pOle) = VT_UI4;
+ }
+ else if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_U2))
+ {
+ V_UI2(pOle) = *(USHORT*)( (*pObj)->GetData() );
+ V_VT(pOle) = VT_UI2;
+ }
+ else if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_U1))
+ {
+ V_UI1(pOle) = *(BYTE*)( (*pObj)->GetData() );
+ V_VT(pOle) = VT_UI1;
+ }
+ else if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_R4))
+ {
+ V_R4(pOle) = *(FLOAT*)( (*pObj)->GetData() );
+ V_VT(pOle) = VT_R4;
+ }
+ else if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_R8))
+ {
+ V_R8(pOle) = *(DOUBLE*)( (*pObj)->GetData() );
+ V_VT(pOle) = VT_R8;
+ }
+ else if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_BOOLEAN))
+ {
+ V_BOOL(pOle) = *(U1*)( (*pObj)->GetData() ) ? VARIANT_TRUE : VARIANT_FALSE;
+ V_VT(pOle) = VT_BOOL;
+ }
+ else if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_I))
+ {
+ *(LPVOID*)&(V_INT(pOle)) = *(LPVOID*)( (*pObj)->GetData() );
+ V_VT(pOle) = VT_INT;
+ }
+ else if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_U))
+ {
+ *(LPVOID*)&(V_UINT(pOle)) = *(LPVOID*)( (*pObj)->GetData() );
+ V_VT(pOle) = VT_UINT;
+ }
+ else
+ {
+ MethodDescCallSite convertObjectToVariant(METHOD__VARIANT__CONVERT_OBJECT_TO_VARIANT);
+
+ VariantData managedVariant;
+ FillMemory(&managedVariant, sizeof(managedVariant), 0);
+ GCPROTECT_BEGIN_VARIANTDATA(managedVariant)
+ {
+ ARG_SLOT args[] = {
+ ObjToArgSlot(*pObj),
+ PtrToArgSlot(&managedVariant),
+ };
+
+ convertObjectToVariant.Call(args);
+
+ OleVariant::MarshalOleVariantForComVariant(&managedVariant, pOle);
+ }
+ GCPROTECT_END_VARIANTDATA();
+ }
+ }
+}
+
+void OleVariant::MarshalOleRefVariantForObject(OBJECTREF *pObj, VARIANT *pOle)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pObj));
+ PRECONDITION(IsProtectedByGCFrame (pObj));
+ PRECONDITION(CheckPointer(pOle));
+ PRECONDITION(V_VT(pOle) & VT_BYREF);
+ }
+ CONTRACTL_END;
+
+#ifdef FEATURE_CORECLR
+ if (AppX::IsAppXProcess())
+ {
+ COMPlusThrow(kPlatformNotSupportedException, IDS_EE_BADMARSHAL_TYPE_VARIANTASOBJECT);
+ }
+#endif // FEATURE_CORECLR
+
+ HRESULT hr = MarshalCommonOleRefVariantForObject(pObj, pOle);
+
+ if (FAILED(hr))
+ {
+ if (hr == DISP_E_BADVARTYPE)
+ {
+ COMPlusThrow(kInvalidOleVariantTypeException, IDS_EE_INVALID_OLE_VARIANT);
+ }
+ else if (hr == DISP_E_TYPEMISMATCH)
+ {
+ COMPlusThrow(kInvalidCastException, IDS_EE_CANNOT_COERCE_BYREF_VARIANT);
+ }
+ else
+ {
+ MethodDescCallSite castVariant(METHOD__VARIANT__CAST_VARIANT);
+
+ // MarshalOleRefVariantForObjectNoCast has checked that the variant is not an array
+ // so we can use the marshal cast helper to coerce the object to the proper type.
+ VariantData vd;
+ FillMemory(&vd, sizeof(vd), 0);
+ VARTYPE vt = V_VT(pOle) & ~VT_BYREF;
+
+ GCPROTECT_BEGIN_VARIANTDATA(vd);
+ {
+ ARG_SLOT args[3];
+ args[0] = ObjToArgSlot(*pObj);
+ args[1] = (ARG_SLOT)vt;
+ args[2] = PtrToArgSlot(&vd);
+ castVariant.Call(args);
+ VARIANT vtmp;
+ VariantInit(&vtmp);
+ OleVariant::MarshalOleVariantForComVariant(&vd, &vtmp);
+
+ // If the variant types are still not the same then call VariantChangeType to
+ // try and coerse them.
+ if (V_VT(&vtmp) != vt)
+ {
+ VARIANT vtmp2;
+ memset(&vtmp2, 0, sizeof(VARIANT));
+
+ // The type of the variant has changed so attempt to change
+ // the type back.
+ hr = SafeVariantChangeType(&vtmp2, &vtmp, 0, vt);
+ if (FAILED(hr))
+ {
+ if (hr == DISP_E_TYPEMISMATCH)
+ COMPlusThrow(kInvalidCastException, IDS_EE_CANNOT_COERCE_BYREF_VARIANT);
+ else
+ COMPlusThrowHR(hr);
+ }
+
+ // Copy the converted variant back into the original variant and clear the temp.
+ InsertContentsIntoByrefVariant(&vtmp2, pOle);
+ SafeVariantClear(&vtmp);
+ }
+ else
+ {
+ InsertContentsIntoByrefVariant(&vtmp, pOle);
+ }
+ }
+ GCPROTECT_END_VARIANTDATA();
+ }
+ }
+}
+
+HRESULT OleVariant::MarshalCommonOleRefVariantForObject(OBJECTREF *pObj, VARIANT *pOle)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pObj));
+ PRECONDITION(IsProtectedByGCFrame (pObj));
+ PRECONDITION(CheckPointer(pOle));
+ PRECONDITION(V_VT(pOle) & VT_BYREF);
+ }
+ CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+
+ // Let's try to handle the common trivial cases quickly first before
+ // running the generalized stuff.
+ MethodTable *pMT = (*pObj) == NULL ? NULL : (*pObj)->GetMethodTable();
+ 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)) )
+ {
+ // deallocation of old value optimized away since there's nothing to
+ // deallocate for this vartype.
+
+ *(V_I4REF(pOle)) = *(LONG*)( (*pObj)->GetData() );
+ }
+ 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)) )
+ {
+ // deallocation of old value optimized away since there's nothing to
+ // deallocate for this vartype.
+
+ *(V_I2REF(pOle)) = *(SHORT*)( (*pObj)->GetData() );
+ }
+ 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)) )
+ {
+ // deallocation of old value optimized away since there's nothing to
+ // deallocate for this vartype.
+
+ *(V_I1REF(pOle)) = *(CHAR*)( (*pObj)->GetData() );
+ }
+ else if ( V_VT(pOle) == (VT_BYREF | VT_R4) && pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_R4) )
+ {
+ // deallocation of old value optimized away since there's nothing to
+ // deallocate for this vartype.
+
+ *(V_R4REF(pOle)) = *(FLOAT*)( (*pObj)->GetData() );
+ }
+ else if ( V_VT(pOle) == (VT_BYREF | VT_R8) && pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_R8) )
+ {
+ // deallocation of old value optimized away since there's nothing to
+ // deallocate for this vartype.
+
+ *(V_R8REF(pOle)) = *(DOUBLE*)( (*pObj)->GetData() );
+ }
+ else if ( V_VT(pOle) == (VT_BYREF | VT_BOOL) && pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_BOOLEAN) )
+ {
+ // deallocation of old value optimized away since there's nothing to
+ // deallocate for this vartype.
+
+ *(V_BOOLREF(pOle)) = ( *(U1*)( (*pObj)->GetData() ) ) ? VARIANT_TRUE : VARIANT_FALSE;
+ }
+ 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)) )
+ {
+ // deallocation of old value optimized away since there's nothing to
+ // deallocate for this vartype.
+
+ *(V_INTREF(pOle)) = *(LONG*)( (*pObj)->GetData() );
+ }
+ else if ( V_VT(pOle) == (VT_BYREF | VT_BSTR) && pMT == g_pStringClass )
+ {
+ if (*(V_BSTRREF(pOle)))
+ {
+ SysFreeString(*(V_BSTRREF(pOle)));
+ *(V_BSTRREF(pOle)) = NULL;
+ }
+
+ *(V_BSTRREF(pOle)) = ConvertStringToBSTR((STRINGREF*)pObj);
+ }
+ // Special case VT_BYREF|VT_RECORD
+ else if (V_VT(pOle) == (VT_BYREF | VT_RECORD))
+ {
+ // We have a special BYREF RECORD - we cannot call VariantClear on this one, because the caller owns the memory,
+ // so we will call RecordClear, then write our data into the same location.
+ hr = ClearAndInsertContentsIntoByrefRecordVariant(pOle, pObj);
+ goto Exit;
+ }
+ else
+ {
+ VARIANT vtmp;
+ VARTYPE vt = V_VT(pOle) & ~VT_BYREF;
+
+ ExtractContentsFromByrefVariant(pOle, &vtmp);
+ SafeVariantClear(&vtmp);
+
+ if (vt == VT_VARIANT)
+ {
+ // Since variants can contain any VARTYPE we simply convert the object to
+ // a variant and stuff it back into the byref variant.
+ MarshalOleVariantForObject(pObj, &vtmp);
+ InsertContentsIntoByrefVariant(&vtmp, pOle);
+ }
+ else if (vt & VT_ARRAY)
+ {
+ // Since the marshal cast helper does not support array's the best we can do
+ // is marshal the object back to a variant and hope it is of the right type.
+ // If it is not then we must throw an exception.
+ MarshalOleVariantForObject(pObj, &vtmp);
+ if (V_VT(&vtmp) != vt)
+ {
+ hr = DISP_E_TYPEMISMATCH;
+ goto Exit;
+ }
+ InsertContentsIntoByrefVariant(&vtmp, pOle);
+ }
+ else if ( (*pObj) == NULL &&
+ (vt == VT_BSTR ||
+ vt == VT_DISPATCH ||
+ vt == VT_UNKNOWN ||
+ vt == VT_PTR ||
+ vt == VT_CARRAY ||
+ vt == VT_SAFEARRAY ||
+ vt == VT_LPSTR ||
+ vt == VT_LPWSTR) )
+ {
+ // Have to handle this specially since the managed variant
+ // conversion will return a VT_EMPTY which isn't what we want.
+ V_VT(&vtmp) = vt;
+ V_UNKNOWN(&vtmp) = NULL;
+ InsertContentsIntoByrefVariant(&vtmp, pOle);
+ }
+ else
+ {
+ hr = E_FAIL;
+ }
+ }
+Exit:
+ return hr;
+}
+
+void OleVariant::MarshalObjectForOleVariant(const VARIANT * pOle, OBJECTREF * const & pObj)
+{
+ CONTRACT_VOID
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(pOle));
+ PRECONDITION(CheckPointer(pObj));
+ PRECONDITION(*pObj == NULL || (IsProtectedByGCFrame (pObj)));
+ }
+ CONTRACT_END;
+
+#ifdef FEATURE_CORECLR
+ if (AppX::IsAppXProcess())
+ {
+ COMPlusThrow(kPlatformNotSupportedException, IDS_EE_BADMARSHAL_TYPE_VARIANTASOBJECT);
+ }
+#endif // FEATURE_CORECLR
+
+#ifdef MDA_SUPPORTED
+ MdaInvalidVariant* pProbe = MDA_GET_ASSISTANT(InvalidVariant);
+ if (pProbe && !CheckVariant((VARIANT*)pOle))
+ pProbe->ReportViolation();
+#endif
+
+ // if V_ISBYREF(pOle) and V_BYREF(pOle) is null then we have a problem,
+ // unless we're dealing with VT_EMPTY or VT_NULL in which case that is ok??
+ VARTYPE vt = V_VT(pOle) & ~VT_BYREF;
+ if (V_ISBYREF(pOle) && !V_BYREF(pOle) && !(vt == VT_EMPTY || vt == VT_NULL))
+ COMPlusThrow(kArgumentException, IDS_EE_INVALID_OLE_VARIANT);
+
+ switch (V_VT(pOle))
+ {
+ case VT_EMPTY:
+ SetObjectReference( pObj,
+ NULL,
+ GetAppDomain() );
+ break;
+
+ case VT_I4:
+ case VT_INT:
+ SetObjectReference( pObj,
+ AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_I4)),
+ GetAppDomain() );
+ *(LONG*)((*pObj)->GetData()) = V_I4(pOle);
+ break;
+
+ case VT_BYREF|VT_I4:
+ case VT_BYREF|VT_INT:
+ SetObjectReference( pObj,
+ AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_I4)),
+ GetAppDomain() );
+ *(LONG*)((*pObj)->GetData()) = *(V_I4REF(pOle));
+ break;
+
+ case VT_UI4:
+ case VT_UINT:
+ SetObjectReference( pObj,
+ AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_U4)),
+ GetAppDomain() );
+ *(ULONG*)((*pObj)->GetData()) = V_UI4(pOle);
+ break;
+
+ case VT_BYREF|VT_UI4:
+ case VT_BYREF|VT_UINT:
+ SetObjectReference( pObj,
+ AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_U4)),
+ GetAppDomain() );
+ *(ULONG*)((*pObj)->GetData()) = *(V_UI4REF(pOle));
+ break;
+
+ case VT_I2:
+ SetObjectReference( pObj,
+ AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_I2)),
+ GetAppDomain() );
+ (*(SHORT*)((*pObj)->GetData())) = V_I2(pOle);
+ break;
+
+ case VT_BYREF|VT_I2:
+ SetObjectReference( pObj,
+ AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_I2)),
+ GetAppDomain() );
+ *(SHORT*)((*pObj)->GetData()) = *(V_I2REF(pOle));
+ break;
+
+ case VT_UI2:
+ SetObjectReference( pObj,
+ AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_U2)),
+ GetAppDomain() );
+ *(USHORT*)((*pObj)->GetData()) = V_UI2(pOle);
+ break;
+
+ case VT_BYREF|VT_UI2:
+ SetObjectReference( pObj,
+ AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_U2)),
+ GetAppDomain() );
+ *(USHORT*)((*pObj)->GetData()) = *(V_UI2REF(pOle));
+ break;
+
+ case VT_I1:
+ SetObjectReference( pObj,
+ AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_I1)),
+ GetAppDomain() );
+ *(CHAR*)((*pObj)->GetData()) = V_I1(pOle);
+ break;
+
+ case VT_BYREF|VT_I1:
+ SetObjectReference( pObj,
+ AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_I1)),
+ GetAppDomain() );
+ *(CHAR*)((*pObj)->GetData()) = *(V_I1REF(pOle));
+ break;
+
+ case VT_UI1:
+ SetObjectReference( pObj,
+ AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_U1)),
+ GetAppDomain() );
+ *(BYTE*)((*pObj)->GetData()) = V_UI1(pOle);
+ break;
+
+ case VT_BYREF|VT_UI1:
+ SetObjectReference( pObj,
+ AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_U1)),
+ GetAppDomain() );
+ *(BYTE*)((*pObj)->GetData()) = *(V_UI1REF(pOle));
+ break;
+
+ case VT_R4:
+ SetObjectReference( pObj,
+ AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_R4)),
+ GetAppDomain() );
+ *(FLOAT*)((*pObj)->GetData()) = V_R4(pOle);
+ break;
+
+ case VT_BYREF|VT_R4:
+ SetObjectReference( pObj,
+ AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_R4)),
+ GetAppDomain() );
+ *(FLOAT*)((*pObj)->GetData()) = *(V_R4REF(pOle));
+ break;
+
+ case VT_R8:
+ SetObjectReference( pObj,
+ AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_R8)),
+ GetAppDomain() );
+ *(DOUBLE*)((*pObj)->GetData()) = V_R8(pOle);
+ break;
+
+ case VT_BYREF|VT_R8:
+ SetObjectReference( pObj,
+ AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_R8)),
+ GetAppDomain() );
+ *(DOUBLE*)((*pObj)->GetData()) = *(V_R8REF(pOle));
+ break;
+
+ case VT_BOOL:
+ SetObjectReference( pObj,
+ AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_BOOLEAN)),
+ GetAppDomain() );
+ *(VARIANT_BOOL*)((*pObj)->GetData()) = V_BOOL(pOle) ? 1 : 0;
+ break;
+
+ case VT_BYREF|VT_BOOL:
+ SetObjectReference( pObj,
+ AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_BOOLEAN)),
+ GetAppDomain() );
+ *(VARIANT_BOOL*)((*pObj)->GetData()) = *(V_BOOLREF(pOle)) ? 1 : 0;
+ break;
+
+ case VT_BSTR:
+ ConvertBSTRToString(V_BSTR(pOle), (STRINGREF*)pObj);
+ break;
+
+ case VT_BYREF|VT_BSTR:
+ ConvertBSTRToString(*(V_BSTRREF(pOle)), (STRINGREF*)pObj);
+ break;
+
+ default:
+ {
+ MethodDescCallSite convertVariantToObject(METHOD__VARIANT__CONVERT_VARIANT_TO_OBJECT);
+
+ VariantData managedVariant;
+ FillMemory(&managedVariant, sizeof(managedVariant), 0);
+ GCPROTECT_BEGIN_VARIANTDATA(managedVariant)
+ {
+ OleVariant::MarshalComVariantForOleVariant((VARIANT*)pOle, &managedVariant);
+ ARG_SLOT args[] = { PtrToArgSlot(&managedVariant) };
+ SetObjectReference( pObj,
+ convertVariantToObject.Call_RetOBJECTREF(args),
+ GetAppDomain() );
+ }
+ GCPROTECT_END_VARIANTDATA();
+ }
+ }
+ RETURN;
+ }
+
+/* ------------------------------------------------------------------------- *
+ * Byref variant manipulation helpers.
+ * ------------------------------------------------------------------------- */
+
+void OleVariant::ExtractContentsFromByrefVariant(VARIANT *pByrefVar, VARIANT *pDestVar)
+{
+ CONTRACT_VOID
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(pByrefVar));
+ PRECONDITION(CheckPointer(pDestVar));
+ }
+ CONTRACT_END;
+
+ VARTYPE vt = V_VT(pByrefVar) & ~VT_BYREF;
+
+ // VT_BYREF | VT_EMPTY is not a valid combination.
+ if (vt == 0 || vt == VT_EMPTY)
+ COMPlusThrow(kInvalidOleVariantTypeException, IDS_EE_INVALID_OLE_VARIANT);
+
+ switch (vt)
+ {
+ case VT_RECORD:
+ {
+ // VT_RECORD's are weird in that regardless of is the VT_BYREF flag is set or not
+ // they have the same internal representation.
+ V_RECORD(pDestVar) = V_RECORD(pByrefVar);
+ V_RECORDINFO(pDestVar) = V_RECORDINFO(pByrefVar);
+
+ // Set the variant type of the destination variant.
+ V_VT(pDestVar) = vt;
+
+ break;
+ }
+
+ case VT_VARIANT:
+ {
+ // A byref variant is not allowed to contain a byref variant.
+ if (V_ISBYREF(V_VARIANTREF(pByrefVar)))
+ COMPlusThrow(kInvalidOleVariantTypeException, IDS_EE_INVALID_OLE_VARIANT);
+
+ // Copy the variant that the byref variant points to into the destination variant.
+ // This will replace the VARTYPE of pDestVar with the VARTYPE of the VARIANT being
+ // pointed to.
+ memcpyNoGCRefs(pDestVar, V_VARIANTREF(pByrefVar), sizeof(VARIANT));
+ break;
+ }
+
+ case VT_DECIMAL:
+ {
+ // Copy the value that the byref variant points to into the destination variant.
+ // Decimal's are special in that they occupy the 16 bits of padding between the
+ // VARTYPE and the intVal field.
+ memcpyNoGCRefs(&V_DECIMAL(pDestVar), V_DECIMALREF(pByrefVar), sizeof(DECIMAL));
+
+ // Set the variant type of the destination variant.
+ V_VT(pDestVar) = vt;
+
+ break;
+ }
+
+ default:
+ {
+ // Copy the value that the byref variant points to into the destination variant.
+ SIZE_T sz = OleVariant::GetElementSizeForVarType(vt, NULL);
+ memcpyNoGCRefs(&V_INT(pDestVar), V_INTREF(pByrefVar), sz);
+
+ // Set the variant type of the destination variant.
+ V_VT(pDestVar) = vt;
+
+ break;
+ }
+ }
+
+ RETURN;
+}
+
+void OleVariant::InsertContentsIntoByrefVariant(VARIANT *pSrcVar, VARIANT *pByrefVar)
+{
+ CONTRACT_VOID
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(pByrefVar));
+ PRECONDITION(CheckPointer(pSrcVar));
+ }
+ CONTRACT_END;
+
+ _ASSERTE(V_VT(pSrcVar) == (V_VT(pByrefVar) & ~VT_BYREF) || V_VT(pByrefVar) == (VT_BYREF | VT_VARIANT));
+
+
+ VARTYPE vt = V_VT(pByrefVar) & ~VT_BYREF;
+
+ // VT_BYREF | VT_EMPTY is not a valid combination.
+ if (vt == 0 || vt == VT_EMPTY)
+ COMPlusThrow(kInvalidOleVariantTypeException, IDS_EE_INVALID_OLE_VARIANT);
+
+ switch (vt)
+ {
+ case VT_RECORD:
+ {
+ // VT_RECORD's are weird in that regardless of is the VT_BYREF flag is set or not
+ // they have the same internal representation.
+ V_RECORD(pByrefVar) = V_RECORD(pSrcVar);
+ V_RECORDINFO(pByrefVar) = V_RECORDINFO(pSrcVar);
+ break;
+ }
+
+ case VT_VARIANT:
+ {
+ // Copy the variant that the byref variant points to into the destination variant.
+ memcpyNoGCRefs(V_VARIANTREF(pByrefVar), pSrcVar, sizeof(VARIANT));
+ break;
+ }
+
+ case VT_DECIMAL:
+ {
+ // Copy the value inside the source variant into the location pointed to by the byref variant.
+ memcpyNoGCRefs(V_DECIMALREF(pByrefVar), &V_DECIMAL(pSrcVar), sizeof(DECIMAL));
+ break;
+ }
+
+ default:
+ {
+ // Copy the value inside the source variant into the location pointed to by the byref variant.
+
+ SIZE_T sz = OleVariant::GetElementSizeForVarType(vt, NULL);
+ memcpyNoGCRefs(V_INTREF(pByrefVar), &V_INT(pSrcVar), sz);
+ break;
+ }
+ }
+ RETURN;
+}
+
+void OleVariant::CreateByrefVariantForVariant(VARIANT *pSrcVar, VARIANT *pByrefVar)
+{
+ CONTRACT_VOID
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(pByrefVar));
+ PRECONDITION(CheckPointer(pSrcVar));
+ }
+ CONTRACT_END;
+
+ // Set the type of the byref variant based on the type of the source variant.
+ VARTYPE vt = V_VT(pSrcVar);
+
+ // VT_BYREF | VT_EMPTY is not a valid combination.
+ if (vt == VT_EMPTY)
+ COMPlusThrow(kInvalidOleVariantTypeException, IDS_EE_INVALID_OLE_VARIANT);
+
+ if (vt == VT_NULL)
+ {
+ // VT_BYREF | VT_NULL is not a valid combination either but we'll allow VT_NULL
+ // to be passed this way (meaning that the callee can change the type and return
+ // data), note that the VT_BYREF flag is not added
+ V_VT(pByrefVar) = vt;
+ }
+ else
+ {
+ switch (vt)
+ {
+ case VT_RECORD:
+ {
+ // VT_RECORD's are weird in that regardless of is the VT_BYREF flag is set or not
+ // they have the same internal representation.
+ V_RECORD(pByrefVar) = V_RECORD(pSrcVar);
+ V_RECORDINFO(pByrefVar) = V_RECORDINFO(pSrcVar);
+ break;
+ }
+
+ case VT_VARIANT:
+ {
+ V_VARIANTREF(pByrefVar) = pSrcVar;
+ break;
+ }
+
+ case VT_DECIMAL:
+ {
+ V_DECIMALREF(pByrefVar) = &V_DECIMAL(pSrcVar);
+ break;
+ }
+
+ default:
+ {
+ V_INTREF(pByrefVar) = &V_INT(pSrcVar);
+ break;
+ }
+ }
+
+ V_VT(pByrefVar) = vt | VT_BYREF;
+ }
+
+ RETURN;
+}
+
+/* ------------------------------------------------------------------------- *
+ * Variant marshaling
+ * ------------------------------------------------------------------------- */
+
+//
+// MarshalComVariantForOleVariant copies the contents of the OLE variant from
+// the COM variant.
+//
+
+void OleVariant::MarshalComVariantForOleVariant(VARIANT *pOle, VariantData *pCom)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pOle));
+ PRECONDITION(CheckPointer(pCom));
+ }
+ CONTRACTL_END;
+
+ BOOL byref = V_ISBYREF(pOle);
+ VARTYPE vt = V_VT(pOle) & ~VT_BYREF;
+
+ // Note that the following check also covers VT_ILLEGAL.
+ if ((vt & ~VT_ARRAY) >= 128 )
+ COMPlusThrow(kInvalidOleVariantTypeException, IDS_EE_INVALID_OLE_VARIANT);
+
+ if (byref && !V_BYREF(pOle) && !(vt == VT_EMPTY || vt == VT_NULL))
+ COMPlusThrow(kArgumentException, IDS_EE_INVALID_OLE_VARIANT);
+
+ if (byref && vt == VT_VARIANT)
+ {
+ pOle = V_VARIANTREF(pOle);
+ byref = V_ISBYREF(pOle);
+ vt = V_VT(pOle) & ~VT_BYREF;
+
+ // Byref VARIANTS are not allowed to be nested.
+ if (byref)
+ COMPlusThrow(kInvalidOleVariantTypeException, IDS_EE_INVALID_OLE_VARIANT);
+ }
+
+ CVTypes cvt = GetCVTypeForVarType(vt);
+ const Marshaler *marshal = GetMarshalerForVarType(vt, TRUE);
+
+ pCom->SetType(cvt);
+ pCom->SetVT(vt); // store away VT for return trip.
+ if (marshal == NULL || (byref
+ ? marshal->OleRefToComVariant == NULL
+ : marshal->OleToComVariant == NULL))
+ {
+ if (cvt==CV_EMPTY)
+ {
+ if (V_ISBYREF(pOle))
+ {
+ // Must set ObjectRef field of Variant to a specific instance.
+#ifdef _WIN64
+ VariantData::NewVariant(pCom, CV_U8, (INT64)(size_t)V_BYREF(pOle));
+#else // _WIN64
+ VariantData::NewVariant(pCom, CV_U4, (INT32)(size_t)V_BYREF(pOle));
+#endif // _WIN64
+ }
+ else
+ {
+ VariantData::NewVariant(pCom, cvt, NULL);
+ }
+ }
+ else if (cvt==CV_NULL)
+ {
+ VariantData::NewVariant(pCom, cvt, NULL);
+ }
+ else
+ {
+ pCom->SetObjRef(NULL);
+ if (byref)
+ {
+ INT64 data = 0;
+ CopyMemory(&data, V_R8REF(pOle), GetElementSizeForVarType(vt, NULL));
+ pCom->SetData(&data);
+ }
+ else
+ pCom->SetData(&V_R8(pOle));
+ }
+ }
+ else
+ {
+ if (byref)
+ marshal->OleRefToComVariant(pOle, pCom);
+ else
+ marshal->OleToComVariant(pOle, pCom);
+ }
+}
+
+//
+// MarshalOleVariantForComVariant copies the contents of the OLE variant from
+// the COM variant.
+//
+
+void OleVariant::MarshalOleVariantForComVariant(VariantData *pCom, VARIANT *pOle)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pCom));
+ PRECONDITION(CheckPointer(pOle));
+ }
+ CONTRACTL_END;
+
+ SafeVariantClear(pOle);
+
+ VariantEmptyHolder veh;
+ veh = pOle;
+
+ VARTYPE vt = GetVarTypeForComVariant(pCom);
+ V_VT(pOle) = vt;
+
+ const Marshaler *marshal = GetMarshalerForVarType(vt, TRUE);
+
+ if (marshal == NULL || marshal->ComToOleVariant == NULL)
+ {
+ *(INT64*)&V_R8(pOle) = *(INT64*)pCom->GetData();
+ }
+ else
+ {
+ marshal->ComToOleVariant(pCom, pOle);
+ }
+
+ veh.SuppressRelease();
+}
+
+void OleVariant::MarshalInterfaceArrayComToOleHelper(BASEARRAYREF *pComArray, void *oleArray,
+ MethodTable *pElementMT, BOOL bDefaultIsDispatch)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pComArray));
+ PRECONDITION(CheckPointer(oleArray));
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pComArray);
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+
+ BOOL bDispatch = bDefaultIsDispatch;
+ BOOL bHeterogenous = (pElementMT == NULL);
+
+ // If the method table is for Object then don't consider it.
+ if (pElementMT == g_pObjectClass)
+ pElementMT = NULL;
+
+ // If the element MT represents a class, then we need to determine the default
+ // interface to use to expose the object out to COM.
+ if (pElementMT && !pElementMT->IsInterface())
+ {
+ pElementMT = GetDefaultInterfaceMTForClass(pElementMT, &bDispatch);
+ }
+
+ // Determine the start and the end of the data in the OLE array.
+ IUnknown **pOle = (IUnknown **) oleArray;
+ IUnknown **pOleEnd = pOle + elementCount;
+
+ // Retrieve the start of the data in the managed array.
+ BASEARRAYREF unprotectedArray = *pComArray;
+ OBJECTREF *pCom = (OBJECTREF *) unprotectedArray->GetDataPtr();
+
+ OBJECTREF TmpObj = NULL;
+ GCPROTECT_BEGIN(TmpObj)
+ {
+ MethodTable *pLastElementMT = NULL;
+
+ while (pOle < pOleEnd)
+ {
+ TmpObj = *pCom++;
+
+ IUnknown *unk;
+ if (TmpObj == NULL)
+ unk = NULL;
+ else
+ {
+ if (bHeterogenous)
+ {
+ // Inspect the type of each element separately (cache the last type for perf).
+ if (TmpObj->GetMethodTable() != pLastElementMT)
+ {
+ pLastElementMT = TmpObj->GetMethodTable();
+ pElementMT = GetDefaultInterfaceMTForClass(pLastElementMT, &bDispatch);
+ }
+ }
+
+ if (pElementMT)
+ {
+ // Convert to COM IP based on an interface MT (a specific interface will be exposed).
+ unk = GetComIPFromObjectRef(&TmpObj, pElementMT);
+ }
+ else
+ {
+ // Convert to COM IP exposing either IDispatch or IUnknown.
+ unk = GetComIPFromObjectRef(&TmpObj, (bDispatch ? ComIpType_Dispatch : ComIpType_Unknown), NULL);
+ }
+ }
+
+ *pOle++ = unk;
+
+ if (*(void **)&unprotectedArray != *(void **)&*pComArray)
+ {
+ SIZE_T currentOffset = ((BYTE *)pCom) - (*(Object **) &unprotectedArray)->GetAddress();
+ unprotectedArray = *pComArray;
+ pCom = (OBJECTREF *) (unprotectedArray->GetAddress() + currentOffset);
+ }
+ }
+ }
+ GCPROTECT_END();
+}
+
+// Used by customer checked build to test validity of VARIANT
+
+BOOL OleVariant::CheckVariant(VARIANT* pOle)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(pOle));
+ }
+ CONTRACTL_END;
+
+ BOOL bValidVariant = FALSE;
+
+ // We need a try/catch here since VariantCopy could cause an AV if the VARIANT isn't valid.
+ EX_TRY
+ {
+ VARIANT pOleCopy;
+ SafeVariantInit(&pOleCopy);
+
+ GCX_PREEMP();
+ if (SUCCEEDED(VariantCopy(&pOleCopy, pOle)))
+ {
+ SafeVariantClear(&pOleCopy);
+ bValidVariant = TRUE;
+ }
+ }
+ EX_CATCH
+ {
+ }
+ EX_END_CATCH(SwallowAllExceptions);
+
+ return bValidVariant;
+}
+
+HRESULT OleVariant::ClearAndInsertContentsIntoByrefRecordVariant(VARIANT* pOle, OBJECTREF* pObj)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ if (V_VT(pOle) != (VT_BYREF | VT_RECORD))
+ return DISP_E_BADVARTYPE;
+
+ // Clear the current contents of the record.
+ {
+ GCX_PREEMP();
+ V_RECORDINFO(pOle)->RecordClear(V_RECORD(pOle));
+ }
+
+ // Ok - let's marshal the returning object into a VT_RECORD.
+ if ((*pObj) != NULL)
+ {
+ VARIANT vtmp;
+ SafeVariantInit(&vtmp);
+
+ MarshalOleVariantForObject(pObj, &vtmp);
+
+ {
+ GCX_PREEMP();
+
+ // Verify that we have a VT_RECORD.
+ if (V_VT(&vtmp) != VT_RECORD)
+ {
+ SafeVariantClear(&vtmp);
+ return DISP_E_TYPEMISMATCH;
+ }
+
+ // Verify that we have the same type of record.
+ if (! V_RECORDINFO(pOle)->IsMatchingType(V_RECORDINFO(&vtmp)))
+ {
+ SafeVariantClear(&vtmp);
+ return DISP_E_TYPEMISMATCH;
+ }
+
+ // Now copy the contents of the new variant back into the old variant.
+ HRESULT hr = V_RECORDINFO(pOle)->RecordCopy(V_RECORD(&vtmp), V_RECORD(pOle));
+ if (hr != S_OK)
+ {
+ SafeVariantClear(&vtmp);
+ return DISP_E_TYPEMISMATCH;
+ }
+ }
+ }
+ return S_OK;
+}
+
+void OleVariant::MarshalIDispatchArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
+ MethodTable *pElementMT, BOOL fBestFitMapping,
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+{
+ WRAPPER_NO_CONTRACT;
+
+ MarshalInterfaceArrayComToOleHelper(pComArray, oleArray, pElementMT, TRUE);
+}
+
+
+/* ------------------------------------------------------------------------- *
+ * Currency marshaling routines
+ * ------------------------------------------------------------------------- */
+
+void OleVariant::MarshalCurrencyVariantOleToCom(VARIANT *pOleVariant,
+ VariantData *pComVariant)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(pOleVariant));
+ PRECONDITION(CheckPointer(pComVariant));
+ }
+ CONTRACTL_END;
+
+ OBJECTREF pDecimalRef = AllocateObject(MscorlibBinder::GetClass(CLASS__DECIMAL));
+ DECIMAL DecVal;
+
+ // Convert the currency to a decimal.
+ HRESULT hr = VarDecFromCy(V_CY(pOleVariant), &DecVal);
+ IfFailThrow(hr);
+
+ if (FAILED(DecimalCanonicalize(&DecVal)))
+ COMPlusThrow(kOverflowException, W("Overflow_Currency"));
+
+ // Store the value into the unboxes decimal and store the decimal in the variant.
+ *(DECIMAL *) pDecimalRef->UnBox() = DecVal;
+ pComVariant->SetObjRef(pDecimalRef);
+}
+
+void OleVariant::MarshalCurrencyVariantComToOle(VariantData *pComVariant,
+ VARIANT *pOleVariant)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pOleVariant));
+ PRECONDITION(CheckPointer(pComVariant));
+ }
+ CONTRACTL_END;
+
+ CURRENCY CyVal;
+
+ // Convert the decimal to a currency.
+ HRESULT hr = VarCyFromDec((DECIMAL*)pComVariant->GetObjRef()->UnBox(), &CyVal);
+ IfFailThrow(hr);
+
+ // Store the currency in the VARIANT and set the VT.
+ V_CY(pOleVariant) = CyVal;
+}
+
+void OleVariant::MarshalCurrencyVariantOleRefToCom(VARIANT *pOleVariant,
+ VariantData *pComVariant)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(pOleVariant));
+ PRECONDITION(CheckPointer(pComVariant));
+ }
+ CONTRACTL_END;
+
+ OBJECTREF pDecimalRef = AllocateObject(MscorlibBinder::GetClass(CLASS__DECIMAL));
+ DECIMAL DecVal;
+
+ // Convert the currency to a decimal.
+ HRESULT hr = VarDecFromCy(*V_CYREF(pOleVariant), &DecVal);
+ IfFailThrow(hr);
+
+ if (FAILED(DecimalCanonicalize(&DecVal)))
+ COMPlusThrow(kOverflowException, W("Overflow_Currency"));
+
+ // Store the value into the unboxes decimal and store the decimal in the variant.
+ *(DECIMAL *) pDecimalRef->UnBox() = DecVal;
+ pComVariant->SetObjRef(pDecimalRef);
+}
+
+void OleVariant::MarshalCurrencyArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray,
+ MethodTable *pInterfaceMT)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pComArray);
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+
+ CURRENCY *pOle = (CURRENCY *) oleArray;
+ CURRENCY *pOleEnd = pOle + elementCount;
+
+ DECIMAL *pCom = (DECIMAL *) (*pComArray)->GetDataPtr();
+
+ while (pOle < pOleEnd)
+ {
+ IfFailThrow(VarDecFromCy(*pOle++, pCom));
+ if (FAILED(DecimalCanonicalize(pCom)))
+ COMPlusThrow(kOverflowException, W("Overflow_Currency"));
+
+ pCom++;
+ }
+}
+
+void OleVariant::MarshalCurrencyArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
+ MethodTable *pInterfaceMT, BOOL fBestFitMapping,
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pComArray);
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+
+ CURRENCY *pOle = (CURRENCY *) oleArray;
+ CURRENCY *pOleEnd = pOle + elementCount;
+
+ DECIMAL *pCom = (DECIMAL *) (*pComArray)->GetDataPtr();
+
+ while (pOle < pOleEnd)
+ IfFailThrow(VarCyFromDec(pCom++, pOle++));
+}
+
+
+/* ------------------------------------------------------------------------- *
+ * Variant marshaling routines
+ * ------------------------------------------------------------------------- */
+
+void OleVariant::MarshalVariantArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray,
+ MethodTable *pInterfaceMT)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pComArray);
+
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+
+ VARIANT *pOle = (VARIANT *) oleArray;
+ VARIANT *pOleEnd = pOle + elementCount;
+
+ BASEARRAYREF unprotectedArray = *pComArray;
+ OBJECTREF *pCom = (OBJECTREF *) unprotectedArray->GetDataPtr();
+
+ AppDomain *pDomain = unprotectedArray->GetAppDomain();
+
+ OBJECTREF TmpObj = NULL;
+ GCPROTECT_BEGIN(TmpObj)
+ {
+ while (pOle < pOleEnd)
+ {
+ // Marshal the OLE variant into a temp managed variant.
+ MarshalObjectForOleVariant(pOle++, &TmpObj);
+
+ // Reset pCom pointer only if array object has moved, rather than
+ // recomputing it every time through the loop. Beware implicit calls to
+ // ValidateObject inside OBJECTREF methods.
+ if (*(void **)&unprotectedArray != *(void **)&*pComArray)
+ {
+ SIZE_T currentOffset = ((BYTE *)pCom) - (*(Object **) &unprotectedArray)->GetAddress();
+ unprotectedArray = *pComArray;
+ pCom = (OBJECTREF *) (unprotectedArray->GetAddress() + currentOffset);
+ }
+ SetObjectReference(pCom++, TmpObj, pDomain);
+ }
+ }
+ GCPROTECT_END();
+}
+
+void OleVariant::MarshalVariantArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
+ MethodTable *pInterfaceMT, BOOL fBestFitMapping,
+ BOOL fThrowOnUnmappableChar, BOOL fOleArrayIsValid)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ }
+ CONTRACTL_END;
+
+
+ MarshalVariantArrayComToOle(pComArray, oleArray, pInterfaceMT, fBestFitMapping, fThrowOnUnmappableChar, FALSE, fOleArrayIsValid);
+}
+
+
+void OleVariant::MarshalVariantArrayComToOle(BASEARRAYREF *pComArray, void *oleArray,
+ MethodTable *pInterfaceMT, BOOL fBestFitMapping,
+ BOOL fThrowOnUnmappableChar, BOOL fMarshalByrefArgOnly,
+ BOOL fOleArrayIsValid, int nOleArrayStepLength)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(oleArray));
+ PRECONDITION(CheckPointer(pComArray));
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pComArray);
+
+ SIZE_T elementCount = (*pComArray)->GetNumComponents();
+
+ VARIANT *pOle = (VARIANT *) oleArray;
+ VARIANT *pOleEnd = pOle + elementCount * nOleArrayStepLength;
+
+ BASEARRAYREF unprotectedArray = *pComArray;
+ OBJECTREF *pCom = (OBJECTREF *) unprotectedArray->GetDataPtr();
+
+ OBJECTREF TmpObj = NULL;
+ GCPROTECT_BEGIN(TmpObj)
+ {
+ while (pOle != pOleEnd)
+ {
+ // Reset pCom pointer only if array object has moved, rather than
+ // recomputing it every time through the loop. Beware implicit calls to
+ // ValidateObject inside OBJECTREF methods.
+ if (*(void **)&unprotectedArray != *(void **)&*pComArray)
+ {
+ SIZE_T currentOffset = ((BYTE *)pCom) - (*(Object **) &unprotectedArray)->GetAddress();
+ unprotectedArray = *pComArray;
+ pCom = (OBJECTREF *) (unprotectedArray->GetAddress() + currentOffset);
+ }
+ TmpObj = *pCom++;
+
+ // Marshal the temp managed variant into the OLE variant.
+ if (fOleArrayIsValid)
+ {
+ // We firstly try MarshalCommonOleRefVariantForObject for VT_BYREF variant because
+ // MarshalOleVariantForObject() VariantClear the variant and does not keep the VT_BYREF.
+ // For back compating the old behavior(we used MarshalOleVariantForObject in the previous
+ // version) that casts the managed object to Variant based on the object's MethodTable,
+ // MarshalCommonOleRefVariantForObject is used instead of MarshalOleRefVariantForObject so
+ // that cast will not be done based on the VT of the variant.
+ if (!((pOle->vt & VT_BYREF) &&
+ SUCCEEDED(MarshalCommonOleRefVariantForObject(&TmpObj, pOle))))
+ if (pOle->vt & VT_BYREF || !fMarshalByrefArgOnly)
+ MarshalOleVariantForObject(&TmpObj, pOle);
+ }
+ else
+ {
+ // The contents of pOle is undefined, don't try to handle byrefs.
+ MarshalOleVariantForObject(&TmpObj, pOle);
+ }
+
+ pOle += nOleArrayStepLength;
+ }
+ }
+ GCPROTECT_END();
+}
+
+void OleVariant::ClearVariantArray(void *oleArray, SIZE_T cElements, MethodTable *pInterfaceMT)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(oleArray));
+ }
+ CONTRACTL_END;
+
+ VARIANT *pOle = (VARIANT *) oleArray;
+ VARIANT *pOleEnd = pOle + cElements;
+
+ while (pOle < pOleEnd)
+ SafeVariantClear(pOle++);
+}
+
+
+/* ------------------------------------------------------------------------- *
+ * Array marshaling routines
+ * ------------------------------------------------------------------------- */
+#ifdef FEATURE_CLASSIC_COMINTEROP
+
+void OleVariant::MarshalArrayVariantOleToCom(VARIANT *pOleVariant,
+ VariantData *pComVariant)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pOleVariant));
+ PRECONDITION(CheckPointer(pComVariant));
+ }
+ CONTRACTL_END;
+
+ SAFEARRAY *pSafeArray = V_ARRAY(pOleVariant);
+
+ VARTYPE vt = V_VT(pOleVariant) & ~VT_ARRAY;
+
+ if (pSafeArray)
+ {
+ if (vt == VT_EMPTY)
+ COMPlusThrow(kInvalidOleVariantTypeException, IDS_EE_INVALID_OLE_VARIANT);
+
+ MethodTable *pElemMT = NULL;
+ if (vt == VT_RECORD)
+ pElemMT = GetElementTypeForRecordSafeArray(pSafeArray).GetMethodTable();
+
+ BASEARRAYREF pArrayRef = CreateArrayRefForSafeArray(pSafeArray, vt, pElemMT);
+ pComVariant->SetObjRef((OBJECTREF) pArrayRef);
+ MarshalArrayRefForSafeArray(pSafeArray, (BASEARRAYREF *) pComVariant->GetObjRefPtr(), vt, pElemMT);
+ }
+ else
+ {
+ pComVariant->SetObjRef(NULL);
+ }
+}
+
+void OleVariant::MarshalArrayVariantComToOle(VariantData *pComVariant,
+ VARIANT *pOleVariant)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pOleVariant));
+ PRECONDITION(CheckPointer(pComVariant));
+ }
+ CONTRACTL_END;
+
+ SafeArrayPtrHolder pSafeArray = NULL;
+ BASEARRAYREF *pArrayRef = (BASEARRAYREF *) pComVariant->GetObjRefPtr();
+ MethodTable *pElemMT = NULL;
+
+ _ASSERTE(pArrayRef);
+
+ VARTYPE vt = GetElementVarTypeForArrayRef(*pArrayRef);
+ if (vt == VT_ARRAY)
+ vt = VT_VARIANT;
+
+ pElemMT = GetArrayElementTypeWrapperAware(pArrayRef).GetMethodTable();
+
+ if (*pArrayRef != NULL)
+ {
+ pSafeArray = CreateSafeArrayForArrayRef(pArrayRef, vt, pElemMT);
+ MarshalSafeArrayForArrayRef(pArrayRef, pSafeArray, vt, pElemMT);
+ }
+ V_ARRAY(pOleVariant) = pSafeArray;
+ pSafeArray.SuppressRelease();
+}
+
+void OleVariant::MarshalArrayVariantOleRefToCom(VARIANT *pOleVariant,
+ VariantData *pComVariant)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pOleVariant));
+ PRECONDITION(CheckPointer(pComVariant));
+ }
+ CONTRACTL_END;
+
+ SAFEARRAY *pSafeArray = *V_ARRAYREF(pOleVariant);
+
+ VARTYPE vt = V_VT(pOleVariant) & ~(VT_ARRAY|VT_BYREF);
+
+ if (pSafeArray)
+ {
+ MethodTable *pElemMT = NULL;
+ if (vt == VT_RECORD)
+ pElemMT = GetElementTypeForRecordSafeArray(pSafeArray).GetMethodTable();
+
+ BASEARRAYREF pArrayRef = CreateArrayRefForSafeArray(pSafeArray, vt, pElemMT);
+ pComVariant->SetObjRef((OBJECTREF) pArrayRef);
+ MarshalArrayRefForSafeArray(pSafeArray, (BASEARRAYREF *) pComVariant->GetObjRefPtr(), vt, pElemMT);
+ }
+ else
+ {
+ pComVariant->SetObjRef(NULL);
+ }
+}
+#endif //FEATURE_CLASSIC_COMINTEROP
+
+
+/* ------------------------------------------------------------------------- *
+ * Error marshaling routines
+ * ------------------------------------------------------------------------- */
+
+void OleVariant::MarshalErrorVariantOleToCom(VARIANT *pOleVariant,
+ VariantData *pComVariant)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(pOleVariant));
+ PRECONDITION(CheckPointer(pComVariant));
+ }
+ CONTRACTL_END;
+
+ // Check to see if the variant represents a missing argument.
+ if (V_ERROR(pOleVariant) == DISP_E_PARAMNOTFOUND)
+ {
+ pComVariant->SetType(CV_MISSING);
+ }
+ else
+ {
+ pComVariant->SetDataAsInt32(V_ERROR(pOleVariant));
+ }
+}
+
+void OleVariant::MarshalErrorVariantOleRefToCom(VARIANT *pOleVariant,
+ VariantData *pComVariant)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(pOleVariant));
+ PRECONDITION(CheckPointer(pComVariant));
+ }
+ CONTRACTL_END;
+
+ // Check to see if the variant represents a missing argument.
+ if (*V_ERRORREF(pOleVariant) == DISP_E_PARAMNOTFOUND)
+ {
+ pComVariant->SetType(CV_MISSING);
+ }
+ else
+ {
+ pComVariant->SetDataAsInt32(*V_ERRORREF(pOleVariant));
+ }
+}
+
+void OleVariant::MarshalErrorVariantComToOle(VariantData *pComVariant,
+ VARIANT *pOleVariant)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(pOleVariant));
+ PRECONDITION(CheckPointer(pComVariant));
+ }
+ CONTRACTL_END;
+
+ if (pComVariant->GetType() == CV_MISSING)
+ {
+ V_ERROR(pOleVariant) = DISP_E_PARAMNOTFOUND;
+ }
+ else
+ {
+ V_ERROR(pOleVariant) = pComVariant->GetDataAsInt32();
+ }
+}
+
+
+/* ------------------------------------------------------------------------- *
+ * Safearray allocation & conversion
+ * ------------------------------------------------------------------------- */
+
+//
+// CreateSafeArrayDescriptorForArrayRef creates a SAFEARRAY descriptor with the
+// appropriate type & dimensions for the given array ref. No memory is
+// allocated.
+//
+// This function is useful when you want to allocate the data specially using
+// a fixed buffer or pinning.
+//
+
+SAFEARRAY *OleVariant::CreateSafeArrayDescriptorForArrayRef(BASEARRAYREF *pArrayRef, VARTYPE vt,
+ MethodTable *pInterfaceMT)
+{
+ CONTRACT (SAFEARRAY*)
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pArrayRef));
+ PRECONDITION(!(vt & VT_ARRAY));
+ POSTCONDITION(CheckPointer(RETVAL));
+ }
+ CONTRACT_END;
+
+ ASSERT_PROTECTED(pArrayRef);
+
+ ULONG nElem = (*pArrayRef)->GetNumComponents();
+ ULONG nRank = (*pArrayRef)->GetRank();
+
+ SafeArrayPtrHolder pSafeArray = NULL;
+ SafeComHolder<ITypeInfo> pITI = NULL;
+ SafeComHolder<IRecordInfo> pRecInfo = NULL;
+
+ IfFailThrow(SafeArrayAllocDescriptorEx(vt, nRank, &pSafeArray));
+
+ switch (vt)
+ {
+ case VT_VARIANT:
+ {
+ // OleAut32.dll only sets FADF_HASVARTYPE, but VB says we also need to set
+ // the FADF_VARIANT bit for this safearray to destruct properly. OleAut32
+ // doesn't want to change their code unless there's a strong reason, since
+ // it's all "black magic" anyway.
+ pSafeArray->fFeatures |= FADF_VARIANT;
+ break;
+ }
+
+ case VT_BSTR:
+ {
+ pSafeArray->fFeatures |= FADF_BSTR;
+ break;
+ }
+
+ case VT_UNKNOWN:
+ {
+ pSafeArray->fFeatures |= FADF_UNKNOWN;
+ break;
+ }
+
+ case VT_DISPATCH:
+ {
+ pSafeArray->fFeatures |= FADF_DISPATCH;
+ break;
+ }
+
+ case VT_RECORD:
+ {
+ pSafeArray->fFeatures |= FADF_RECORD;
+ break;
+ }
+ }
+
+ //
+ // Fill in bounds
+ //
+
+ SAFEARRAYBOUND *bounds = pSafeArray->rgsabound;
+ SAFEARRAYBOUND *boundsEnd = bounds + nRank;
+ SIZE_T cElements;
+
+ if (!(*pArrayRef)->IsMultiDimArray())
+ {
+ bounds[0].cElements = nElem;
+ bounds[0].lLbound = 0;
+ cElements = nElem;
+ }
+ else
+ {
+ const INT32 *count = (*pArrayRef)->GetBoundsPtr() + nRank - 1;
+ const INT32 *lower = (*pArrayRef)->GetLowerBoundsPtr() + nRank - 1;
+
+ cElements = 1;
+ while (bounds < boundsEnd)
+ {
+ bounds->lLbound = *lower--;
+ bounds->cElements = *count--;
+ cElements *= bounds->cElements;
+ bounds++;
+ }
+ }
+
+ pSafeArray->cbElements = (unsigned)GetElementSizeForVarType(vt, pInterfaceMT);
+
+ // If the SAFEARRAY contains VT_RECORD's, then we need to set the
+ // IRecordInfo.
+ if (vt == VT_RECORD)
+ {
+ IfFailThrow(GetITypeInfoForEEClass(pInterfaceMT, &pITI));
+ IfFailThrow(GetRecordInfoFromTypeInfo(pITI, &pRecInfo));
+ IfFailThrow(SafeArraySetRecordInfo(pSafeArray, pRecInfo));
+ }
+
+ pSafeArray.SuppressRelease();
+ RETURN pSafeArray;
+}
+
+//
+// CreateSafeArrayDescriptorForArrayRef creates a SAFEARRAY with the appropriate
+// type & dimensions & data for the given array ref. The data is initialized to
+// zero if necessary for safe destruction.
+//
+
+SAFEARRAY *OleVariant::CreateSafeArrayForArrayRef(BASEARRAYREF *pArrayRef, VARTYPE vt,
+ MethodTable *pInterfaceMT)
+{
+ CONTRACT (SAFEARRAY*)
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pArrayRef));
+// PRECONDITION(CheckPointer(*pArrayRef));
+ PRECONDITION(vt != VT_EMPTY);
+ }
+ CONTRACT_END;
+ ASSERT_PROTECTED(pArrayRef);
+
+ // Validate that the type of the managed array is the expected type.
+ if (!IsValidArrayForSafeArrayElementType(pArrayRef, vt))
+ COMPlusThrow(kSafeArrayTypeMismatchException);
+
+ // For structs and interfaces, verify that the array is of the valid type.
+ if (vt == VT_RECORD || vt == VT_UNKNOWN || vt == VT_DISPATCH)
+ {
+ if (pInterfaceMT && !GetArrayElementTypeWrapperAware(pArrayRef).CanCastTo(TypeHandle(pInterfaceMT)))
+ COMPlusThrow(kSafeArrayTypeMismatchException);
+ }
+
+ SAFEARRAY *pSafeArray = CreateSafeArrayDescriptorForArrayRef(pArrayRef, vt, pInterfaceMT);
+
+ HRESULT hr = SafeArrayAllocData(pSafeArray);
+ if (FAILED(hr))
+ {
+ SafeArrayDestroy(pSafeArray);
+ COMPlusThrowHR(hr);
+ }
+
+ RETURN pSafeArray;
+}
+
+//
+// CreateArrayRefForSafeArray creates an array object with the same layout and type
+// as the given safearray. The variant type of the safearray must be passed in.
+// The underlying element method table may also be specified (or NULL may be passed in
+// to use the base class method table for the VARTYPE.
+//
+
+BASEARRAYREF OleVariant::CreateArrayRefForSafeArray(SAFEARRAY *pSafeArray, VARTYPE vt,
+ MethodTable *pElementMT)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(pSafeArray));
+ PRECONDITION(vt != VT_EMPTY);
+ }
+ CONTRACTL_END;
+
+ TypeHandle arrayType;
+ INT32 *pAllocateArrayArgs;
+ int cAllocateArrayArgs;
+ int Rank;
+ VARTYPE SafeArrayVT;
+
+ // Validate that the type of the SAFEARRAY is the expected type.
+ if (SUCCEEDED(ClrSafeArrayGetVartype(pSafeArray, &SafeArrayVT)) && (SafeArrayVT != VT_EMPTY))
+ {
+ if ((SafeArrayVT != vt) &&
+ !(vt == VT_INT && SafeArrayVT == VT_I4) &&
+ !(vt == VT_UINT && SafeArrayVT == VT_UI4) &&
+ !(vt == VT_I4 && SafeArrayVT == VT_INT) &&
+ !(vt == VT_UI4 && SafeArrayVT == VT_UINT) &&
+ !(vt == VT_UNKNOWN && SafeArrayVT == VT_DISPATCH) &&
+ !(SafeArrayVT == VT_RECORD)) // Add this to allowed values as a VT_RECORD might represent a
+ // valuetype with a single field that we'll just treat as a primitive type if possible.
+ {
+ COMPlusThrow(kSafeArrayTypeMismatchException);
+ }
+ }
+ else
+ {
+ UINT ArrayElemSize = SafeArrayGetElemsize(pSafeArray);
+ if (ArrayElemSize != GetElementSizeForVarType(vt, NULL))
+ {
+ COMPlusThrow(kSafeArrayTypeMismatchException, IDS_EE_SAFEARRAYTYPEMISMATCH);
+ }
+ }
+
+ // Determine if the input SAFEARRAY can be converted to an SZARRAY.
+ if ((pSafeArray->cDims == 1) && (pSafeArray->rgsabound->lLbound == 0))
+ {
+ // The SAFEARRAY maps to an SZARRAY. For SZARRAY's AllocateArrayEx()
+ // expects the arguments to be a pointer to the cound of elements in the array
+ // and the size of the args must be set to 1.
+ Rank = 1;
+ cAllocateArrayArgs = 1;
+ pAllocateArrayArgs = (INT32 *) &pSafeArray->rgsabound[0].cElements;
+ }
+ else
+ {
+ // The SAFEARRAY maps to an general array. For general arrays AllocateArrayEx()
+ // expects the arguments to be composed of the lower bounds / element count pairs
+ // for each of the dimensions. We need to reverse the order that the lower bounds
+ // and element pairs are presented before we call AllocateArrayEx().
+ Rank = pSafeArray->cDims;
+ cAllocateArrayArgs = Rank * 2;
+ pAllocateArrayArgs = (INT32*)_alloca(sizeof(INT32) * Rank * 2);
+ INT32 * pBoundsPtr = pAllocateArrayArgs;
+
+ // Copy the lower bounds and count of elements for the dimensions. These
+ // need to copied in reverse order.
+ for (int i = Rank - 1; i >= 0; i--)
+ {
+ *pBoundsPtr++ = pSafeArray->rgsabound[i].lLbound;
+ *pBoundsPtr++ = pSafeArray->rgsabound[i].cElements;
+ }
+ }
+
+ // Retrieve the type of the array.
+ arrayType = GetArrayForVarType(vt, pElementMT, Rank);
+
+ // Allocate the array.
+ return (BASEARRAYREF) AllocateArrayEx(arrayType, pAllocateArrayArgs, cAllocateArrayArgs);
+}
+
+/* ------------------------------------------------------------------------- *
+ * Safearray marshaling
+ * ------------------------------------------------------------------------- */
+
+//
+// MarshalSafeArrayForArrayRef marshals the contents of the array ref into the given
+// safe array. It is assumed that the type & dimensions of the arrays are compatible.
+//
+void OleVariant::MarshalSafeArrayForArrayRef(BASEARRAYREF *pArrayRef,
+ SAFEARRAY *pSafeArray,
+ VARTYPE vt,
+ MethodTable *pInterfaceMT,
+ BOOL fSafeArrayIsValid /*= TRUE*/)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pSafeArray));
+ PRECONDITION(CheckPointer(pArrayRef));
+// PRECONDITION(CheckPointer(*pArrayRef));
+ PRECONDITION(vt != VT_EMPTY);
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pArrayRef);
+
+ // Retrieve the size and number of components.
+ SIZE_T dwComponentSize = GetElementSizeForVarType(vt, pInterfaceMT);
+ SIZE_T dwNumComponents = (*pArrayRef)->GetNumComponents();
+ BASEARRAYREF Array = NULL;
+
+ GCPROTECT_BEGIN(Array)
+ {
+ // Retrieve the marshaler to use to convert the contents.
+ const Marshaler *marshal = GetMarshalerForVarType(vt, TRUE);
+
+ // If the array is an array of wrappers, then we need to extract the objects
+ // being wrapped and create an array of those.
+ BOOL bArrayOfInterfaceWrappers;
+ if (IsArrayOfWrappers(pArrayRef, &bArrayOfInterfaceWrappers))
+ {
+ Array = ExtractWrappedObjectsFromArray(pArrayRef);
+ }
+ else
+ {
+ Array = *pArrayRef;
+ }
+
+ if (marshal == NULL || marshal->ComToOleArray == NULL)
+ {
+ if (pSafeArray->cDims == 1)
+ {
+ // If the array is single dimensionnal then we can simply copy it over.
+ memcpyNoGCRefs(pSafeArray->pvData, Array->GetDataPtr(), dwNumComponents * dwComponentSize);
+ }
+ else
+ {
+ // Copy and transpose the data.
+ TransposeArrayData((BYTE*)pSafeArray->pvData, Array->GetDataPtr(), dwNumComponents, dwComponentSize, pSafeArray, FALSE);
+ }
+ }
+ else
+ {
+ {
+ PinningHandleHolder handle = GetAppDomain()->CreatePinningHandle((OBJECTREF)Array);
+
+ if (bArrayOfInterfaceWrappers)
+ {
+ _ASSERTE(vt == VT_UNKNOWN || vt == VT_DISPATCH);
+ // Signal to code:OleVariant::MarshalInterfaceArrayComToOleHelper that this was an array
+ // of UnknownWrapper or DispatchWrapper. It shall use a different logic and marshal each
+ // element according to its specific default interface.
+ pInterfaceMT = NULL;
+ }
+ marshal->ComToOleArray(&Array, pSafeArray->pvData, pInterfaceMT, TRUE, FALSE, fSafeArrayIsValid);
+ }
+
+ if (pSafeArray->cDims != 1)
+ {
+ // The array is multidimensionnal we need to transpose it.
+ TransposeArrayData((BYTE*)pSafeArray->pvData, (BYTE*)pSafeArray->pvData, dwNumComponents, dwComponentSize, pSafeArray, FALSE);
+ }
+ }
+ }
+ GCPROTECT_END();
+}
+
+//
+// MarshalArrayRefForSafeArray marshals the contents of the safe array into the given
+// array ref. It is assumed that the type & dimensions of the arrays are compatible.
+//
+
+void OleVariant::MarshalArrayRefForSafeArray(SAFEARRAY *pSafeArray,
+ BASEARRAYREF *pArrayRef,
+ VARTYPE vt,
+ MethodTable *pInterfaceMT)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pSafeArray));
+ PRECONDITION(CheckPointer(pArrayRef));
+ PRECONDITION(*pArrayRef != NULL);
+ PRECONDITION(vt != VT_EMPTY);
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(pArrayRef);
+
+ // Retrieve the number of components.
+ SIZE_T dwNumComponents = (*pArrayRef)->GetNumComponents();
+
+ // Retrieve the marshaler to use to convert the contents.
+ const Marshaler *marshal = GetMarshalerForVarType(vt, TRUE);
+
+ if (marshal == NULL || marshal->OleToComArray == NULL)
+ {
+ SIZE_T dwManagedComponentSize = (*pArrayRef)->GetComponentSize();
+
+#ifdef _DEBUG
+ {
+ // If we're blasting bits, this better be a primitive type. Currency is
+ // an I8 on managed & unmanaged, so it's good enough.
+ TypeHandle th = (*pArrayRef)->GetArrayElementTypeHandle();
+
+ if (!CorTypeInfo::IsPrimitiveType(th.GetInternalCorElementType()))
+ {
+ _ASSERTE(!strcmp(th.AsMethodTable()->GetDebugClassName(),
+ "System.Currency"));
+ }
+ }
+#endif
+ if (pSafeArray->cDims == 1)
+ {
+ // If the array is single dimensionnal then we can simply copy it over.
+ memcpyNoGCRefs((*pArrayRef)->GetDataPtr(), pSafeArray->pvData, dwNumComponents * dwManagedComponentSize);
+ }
+ else
+ {
+ // Copy and transpose the data.
+ TransposeArrayData((*pArrayRef)->GetDataPtr(), (BYTE*)pSafeArray->pvData, dwNumComponents, dwManagedComponentSize, pSafeArray, TRUE);
+ }
+ }
+ else
+ {
+ CQuickArray<BYTE> TmpArray;
+ BYTE* pSrcData = NULL;
+ SIZE_T dwNativeComponentSize = GetElementSizeForVarType(vt, pInterfaceMT);
+
+ if (pSafeArray->cDims != 1)
+ {
+ TmpArray.ReSizeThrows(dwNumComponents * dwNativeComponentSize);
+ pSrcData = TmpArray.Ptr();
+ TransposeArrayData(pSrcData, (BYTE*)pSafeArray->pvData, dwNumComponents, dwNativeComponentSize, pSafeArray, TRUE);
+ }
+ else
+ {
+ pSrcData = (BYTE*)pSafeArray->pvData;
+ }
+
+ PinningHandleHolder handle = GetAppDomain()->CreatePinningHandle((OBJECTREF)*pArrayRef);
+
+ marshal->OleToComArray(pSrcData, pArrayRef, pInterfaceMT);
+ }
+}
+
+void OleVariant::ConvertValueClassToVariant(OBJECTREF *pBoxedValueClass, VARIANT *pOleVariant)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pBoxedValueClass));
+ PRECONDITION(CheckPointer(pOleVariant));
+ }
+ CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+ SafeComHolder<ITypeInfo> pTypeInfo = NULL;
+ RecordVariantHolder pRecHolder = pOleVariant;
+
+ BOOL bSuccess = FALSE;
+
+ // Initialize the OLE variant's VT_RECORD fields to NULL.
+ V_RECORDINFO(pRecHolder) = NULL;
+ V_RECORD(pRecHolder) = NULL;
+
+ // Retrieve the ITypeInfo for the value class.
+ MethodTable *pValueClassMT = (*pBoxedValueClass)->GetMethodTable();
+ IfFailThrow(GetITypeInfoForEEClass(pValueClassMT, &pTypeInfo, TRUE, TRUE, 0));
+
+ // Convert the ITypeInfo to an IRecordInfo.
+ hr = GetRecordInfoFromTypeInfo(pTypeInfo, &V_RECORDINFO(pRecHolder));
+ if (FAILED(hr))
+ {
+ // An HRESULT of TYPE_E_UNSUPFORMAT really means that the struct contains
+ // fields that aren't supported inside a OLEAUT record.
+ if (TYPE_E_UNSUPFORMAT == hr)
+ COMPlusThrow(kArgumentException, IDS_EE_RECORD_NON_SUPPORTED_FIELDS);
+ else
+ COMPlusThrowHR(hr);
+ }
+
+ // Allocate an instance of the record.
+ V_RECORD(pRecHolder) = V_RECORDINFO(pRecHolder)->RecordCreate();
+ IfNullThrow(V_RECORD(pRecHolder));
+
+ // Marshal the contents of the value class into the record.
+ FmtClassUpdateNative(pBoxedValueClass, (BYTE*)V_RECORD(pRecHolder), NULL);
+
+ pRecHolder.SuppressRelease();
+}
+
+void OleVariant::TransposeArrayData(BYTE *pDestData, BYTE *pSrcData, SIZE_T dwNumComponents, SIZE_T dwComponentSize, SAFEARRAY *pSafeArray, BOOL bSafeArrayToMngArray)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(pDestData));
+ PRECONDITION(CheckPointer(pSrcData));
+ PRECONDITION(CheckPointer(pSafeArray));
+ }
+ CONTRACTL_END;
+
+ int iDims;
+ DWORD *aDestElemCount = (DWORD*)_alloca(pSafeArray->cDims * sizeof(DWORD));
+ DWORD *aDestIndex = (DWORD*)_alloca(pSafeArray->cDims * sizeof(DWORD));
+ BYTE **aDestDataPos = (BYTE **)_alloca(pSafeArray->cDims * sizeof(BYTE *));
+ SIZE_T *aDestDelta = (SIZE_T*)_alloca(pSafeArray->cDims * sizeof(SIZE_T));
+ CQuickArray<BYTE> TmpArray;
+
+ // If there are no components, then there we are done.
+ if (dwNumComponents == 0)
+ return;
+
+ // Check to see if we are transposing in place or copying and transposing.
+ if (pSrcData == pDestData)
+ {
+ TmpArray.ReSizeThrows(dwNumComponents * dwComponentSize);
+ memcpyNoGCRefs(TmpArray.Ptr(), pSrcData, dwNumComponents * dwComponentSize);
+ pSrcData = TmpArray.Ptr();
+ }
+
+ // Copy the element count in reverse order if we are copying from a safe array to
+ // a managed array and in direct order otherwise.
+ if (bSafeArrayToMngArray)
+ {
+ for (iDims = 0; iDims < pSafeArray->cDims; iDims++)
+ aDestElemCount[iDims] = pSafeArray->rgsabound[pSafeArray->cDims - iDims - 1].cElements;
+ }
+ else
+ {
+ for (iDims = 0; iDims < pSafeArray->cDims; iDims++)
+ aDestElemCount[iDims] = pSafeArray->rgsabound[iDims].cElements;
+ }
+
+ // Initalize the indexes for each dimension to 0.
+ memset(aDestIndex, 0, pSafeArray->cDims * sizeof(int));
+
+ // Set all the destination data positions to the start of the array.
+ for (iDims = 0; iDims < pSafeArray->cDims; iDims++)
+ aDestDataPos[iDims] = (BYTE*)pDestData;
+
+ // Calculate the destination delta for each of the dimensions.
+ aDestDelta[pSafeArray->cDims - 1] = dwComponentSize;
+ for (iDims = pSafeArray->cDims - 2; iDims >= 0; iDims--)
+ aDestDelta[iDims] = aDestDelta[iDims + 1] * aDestElemCount[iDims + 1];
+
+ // Calculate the source data end pointer.
+ BYTE *pSrcDataEnd = pSrcData + dwNumComponents * dwComponentSize;
+ _ASSERTE(pDestData < pSrcData || pDestData >= pSrcDataEnd);
+
+ // Copy and transpose the data.
+ while (TRUE)
+ {
+ // Copy one component.
+ memcpyNoGCRefs(aDestDataPos[0], pSrcData, dwComponentSize);
+
+ // Update the source position.
+ pSrcData += dwComponentSize;
+
+ // Check to see if we have reached the end of the array.
+ if (pSrcData >= pSrcDataEnd)
+ break;
+
+ // Update the destination position.
+ for (iDims = 0; aDestIndex[iDims] >= aDestElemCount[iDims] - 1; iDims++);
+
+ _ASSERTE(iDims < pSafeArray->cDims);
+
+ aDestIndex[iDims]++;
+ aDestDataPos[iDims] += aDestDelta[iDims];
+ for (--iDims; iDims >= 0; iDims--)
+ {
+ aDestIndex[iDims] = 0;
+ aDestDataPos[iDims] = aDestDataPos[iDims + 1];
+ }
+ }
+}
+
+BOOL OleVariant::IsArrayOfWrappers(BASEARRAYREF *pArray, BOOL *pbOfInterfaceWrappers)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ TypeHandle hndElemType = (*pArray)->GetArrayElementTypeHandle();
+
+ if (!hndElemType.IsTypeDesc())
+ {
+ if (hndElemType == TypeHandle(MscorlibBinder::GetClass(CLASS__DISPATCH_WRAPPER)) ||
+ hndElemType == TypeHandle(MscorlibBinder::GetClass(CLASS__UNKNOWN_WRAPPER)))
+ {
+ *pbOfInterfaceWrappers = TRUE;
+ return TRUE;
+ }
+
+ if (hndElemType == TypeHandle(MscorlibBinder::GetClass(CLASS__ERROR_WRAPPER)) ||
+ hndElemType == TypeHandle(MscorlibBinder::GetClass(CLASS__CURRENCY_WRAPPER)) ||
+ hndElemType == TypeHandle(MscorlibBinder::GetClass(CLASS__BSTR_WRAPPER)))
+ {
+ *pbOfInterfaceWrappers = FALSE;
+ return TRUE;
+ }
+ }
+
+ *pbOfInterfaceWrappers = FALSE;
+ return FALSE;
+}
+
+BASEARRAYREF OleVariant::ExtractWrappedObjectsFromArray(BASEARRAYREF *pArray)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pArray));
+ }
+ CONTRACTL_END;
+
+ TypeHandle hndWrapperType = (*pArray)->GetArrayElementTypeHandle();
+ TypeHandle hndElemType;
+ TypeHandle hndArrayType;
+ BOOL bIsMDArray = (*pArray)->IsMultiDimArray();
+ unsigned rank = (*pArray)->GetRank();
+ BASEARRAYREF RetArray = NULL;
+
+ // Retrieve the element type handle for the array to create.
+ if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__DISPATCH_WRAPPER)))
+ hndElemType = TypeHandle(g_pObjectClass);
+
+ else if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__UNKNOWN_WRAPPER)))
+ hndElemType = TypeHandle(g_pObjectClass);
+
+ else if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__BSTR_WRAPPER)))
+ hndElemType = TypeHandle(g_pStringClass);
+
+ else if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__ERROR_WRAPPER)))
+ hndElemType = TypeHandle(MscorlibBinder::GetClass(CLASS__INT32));
+
+ else if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__CURRENCY_WRAPPER)))
+ hndElemType = TypeHandle(MscorlibBinder::GetClass(CLASS__DECIMAL));
+
+ else
+ _ASSERTE(!"Invalid wrapper type");
+
+ // Retrieve the type handle that represents the array.
+ if (bIsMDArray)
+ {
+ hndArrayType = ClassLoader::LoadArrayTypeThrowing(hndElemType, ELEMENT_TYPE_ARRAY, rank);
+ }
+ else
+ {
+ hndArrayType = ClassLoader::LoadArrayTypeThrowing(hndElemType, ELEMENT_TYPE_SZARRAY);
+ }
+ _ASSERTE(!hndArrayType.IsNull());
+
+ // Set up the bounds arguments.
+ DWORD numArgs = rank*2;
+ INT32* args = (INT32*) _alloca(sizeof(INT32)*numArgs);
+
+ if (bIsMDArray)
+ {
+ const INT32* bounds = (*pArray)->GetBoundsPtr();
+ const INT32* lowerBounds = (*pArray)->GetLowerBoundsPtr();
+ for(unsigned int i=0; i < rank; i++)
+ {
+ args[2*i] = lowerBounds[i];
+ args[2*i+1] = bounds[i];
+ }
+ }
+ else
+ {
+ numArgs = 1;
+ args[0] = (*pArray)->GetNumComponents();
+ }
+
+ // Extract the values from the source array and copy them into the destination array.
+ BASEARRAYREF DestArray = (BASEARRAYREF)AllocateArrayEx(hndArrayType, args, numArgs);
+ GCPROTECT_BEGIN(DestArray)
+ {
+ SIZE_T NumComponents = (*pArray)->GetNumComponents();
+ AppDomain *pDomain = DestArray->GetAppDomain();
+
+ if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__DISPATCH_WRAPPER)))
+ {
+ DISPATCHWRAPPEROBJECTREF *pSrc = (DISPATCHWRAPPEROBJECTREF *)(*pArray)->GetDataPtr();
+ DISPATCHWRAPPEROBJECTREF *pSrcEnd = pSrc + NumComponents;
+ OBJECTREF *pDest = (OBJECTREF *)DestArray->GetDataPtr();
+ for (; pSrc < pSrcEnd; pSrc++, pDest++)
+ SetObjectReference(pDest, (*pSrc) != NULL ? (*pSrc)->GetWrappedObject() : NULL, pDomain);
+ }
+ else if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__UNKNOWN_WRAPPER)))
+ {
+ UNKNOWNWRAPPEROBJECTREF *pSrc = (UNKNOWNWRAPPEROBJECTREF *)(*pArray)->GetDataPtr();
+ UNKNOWNWRAPPEROBJECTREF *pSrcEnd = pSrc + NumComponents;
+ OBJECTREF *pDest = (OBJECTREF *)DestArray->GetDataPtr();
+ for (; pSrc < pSrcEnd; pSrc++, pDest++)
+ SetObjectReference(pDest, (*pSrc) != NULL ? (*pSrc)->GetWrappedObject() : NULL, pDomain);
+ }
+ else if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__ERROR_WRAPPER)))
+ {
+ ERRORWRAPPEROBJECTREF *pSrc = (ERRORWRAPPEROBJECTREF *)(*pArray)->GetDataPtr();
+ ERRORWRAPPEROBJECTREF *pSrcEnd = pSrc + NumComponents;
+ INT32 *pDest = (INT32 *)DestArray->GetDataPtr();
+ for (; pSrc < pSrcEnd; pSrc++, pDest++)
+ *pDest = (*pSrc) != NULL ? (*pSrc)->GetErrorCode() : NULL;
+ }
+ else if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__CURRENCY_WRAPPER)))
+ {
+ CURRENCYWRAPPEROBJECTREF *pSrc = (CURRENCYWRAPPEROBJECTREF *)(*pArray)->GetDataPtr();
+ CURRENCYWRAPPEROBJECTREF *pSrcEnd = pSrc + NumComponents;
+ DECIMAL *pDest = (DECIMAL *)DestArray->GetDataPtr();
+ for (; pSrc < pSrcEnd; pSrc++, pDest++)
+ {
+ if (*pSrc != NULL)
+ memcpyNoGCRefs(pDest, &(*pSrc)->GetWrappedObject(), sizeof(DECIMAL));
+ else
+ memset(pDest, 0, sizeof(DECIMAL));
+ }
+ }
+ else if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__BSTR_WRAPPER)))
+ {
+ BSTRWRAPPEROBJECTREF *pSrc = (BSTRWRAPPEROBJECTREF *)(*pArray)->GetDataPtr();
+ BSTRWRAPPEROBJECTREF *pSrcEnd = pSrc + NumComponents;
+ OBJECTREF *pDest = (OBJECTREF *)DestArray->GetDataPtr();
+ for (; pSrc < pSrcEnd; pSrc++, pDest++)
+ SetObjectReference(pDest, (*pSrc) != NULL ? (*pSrc)->GetWrappedObject() : NULL, pDomain);
+ }
+ else
+ {
+ _ASSERTE(!"Invalid wrapper type");
+ }
+
+ // GCPROTECT_END() will wack NewArray so we need to copy the OBJECTREF into
+ // a temp to be able to return it.
+ RetArray = DestArray;
+ }
+ GCPROTECT_END();
+
+ return RetArray;
+}
+
+TypeHandle OleVariant::GetWrappedArrayElementType(BASEARRAYREF *pArray)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pArray));
+ }
+ CONTRACTL_END;
+
+ TypeHandle hndWrapperType = (*pArray)->GetArrayElementTypeHandle();
+ TypeHandle pWrappedObjType;
+
+ if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__DISPATCH_WRAPPER)) ||
+ hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__UNKNOWN_WRAPPER)))
+ {
+ // There's no need to traverse the array up front. We'll use the default interface
+ // for each element in code:OleVariant::MarshalInterfaceArrayComToOleHelper.
+ pWrappedObjType = TypeHandle(g_pObjectClass);
+ }
+ else if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__ERROR_WRAPPER)))
+ {
+ pWrappedObjType = TypeHandle(MscorlibBinder::GetClass(CLASS__INT32));
+ }
+ else if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__CURRENCY_WRAPPER)))
+ {
+ pWrappedObjType = TypeHandle(MscorlibBinder::GetClass(CLASS__DECIMAL));
+ }
+ else if (hndWrapperType == TypeHandle(MscorlibBinder::GetClass(CLASS__BSTR_WRAPPER)))
+ {
+ pWrappedObjType = TypeHandle(g_pStringClass);
+ }
+ else
+ {
+ _ASSERTE(!"Invalid wrapper type");
+ }
+
+ return pWrappedObjType;
+}
+
+
+TypeHandle OleVariant::GetArrayElementTypeWrapperAware(BASEARRAYREF *pArray)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(pArray));
+ }
+ CONTRACTL_END;
+
+ BOOL bArrayOfInterfaceWrappers;
+ if (IsArrayOfWrappers(pArray, &bArrayOfInterfaceWrappers))
+ {
+ return GetWrappedArrayElementType(pArray);
+ }
+ else
+ {
+ return (*pArray)->GetArrayElementTypeHandle();
+ }
+}
+
+#ifdef FEATURE_CLASSIC_COMINTEROP
+TypeHandle OleVariant::GetElementTypeForRecordSafeArray(SAFEARRAY* pSafeArray)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pSafeArray));
+ }
+ CONTRACTL_END;
+
+ HRESULT hr = S_OK;
+ SafeComHolder<IRecordInfo> pRecInfo = NULL;
+
+ GUID guid;
+ IfFailThrow(SafeArrayGetRecordInfo(pSafeArray, &pRecInfo));
+ IfFailThrow(pRecInfo->GetGuid(&guid));
+ MethodTable *pValueClass = GetValueTypeForGUID(guid);
+ if (!pValueClass)
+ COMPlusThrow(kArgumentException, IDS_EE_CANNOT_MAP_TO_MANAGED_VC);
+
+ return TypeHandle(pValueClass);
+}
+#endif //FEATURE_CLASSIC_COMINTEROP
+
+void OleVariant::AllocateEmptyStringForBSTR(BSTR bstr, STRINGREF *pStringObj)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(bstr));
+ PRECONDITION(CheckPointer(pStringObj));
+ }
+ CONTRACTL_END;
+
+ // The BSTR isn't null so allocate a managed string of the appropriate length.
+ ULONG length = SysStringByteLen(bstr);
+
+ if (length > MAX_SIZE_FOR_INTEROP)
+ COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG);
+
+ // Check to see if the BSTR has trailing odd byte.
+ BOOL bHasTrailByte = ((length%sizeof(WCHAR)) != 0);
+ length = length / sizeof(WCHAR);
+ SetObjectReference((OBJECTREF*)pStringObj, (OBJECTREF)StringObject::NewString(length, bHasTrailByte), GetAppDomain());
+}
+
+void OleVariant::ConvertContentsBSTRToString(BSTR bstr, STRINGREF *pStringObj)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(bstr));
+ PRECONDITION(CheckPointer(pStringObj));
+ }
+ CONTRACTL_END;
+
+ // this is the right thing to do, but sometimes we
+ // end up thinking we're marshaling a BSTR when we're not, because
+ // it's the default type.
+ ULONG length = SysStringByteLen((BSTR)bstr);
+ if (length > MAX_SIZE_FOR_INTEROP)
+ COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG);
+
+ ULONG charLength = length/sizeof(WCHAR);
+ BOOL hasTrailByte = (length%sizeof(WCHAR) != 0);
+
+ memcpyNoGCRefs((*pStringObj)->GetBuffer(), bstr, charLength*sizeof(WCHAR));
+
+ if (hasTrailByte)
+ {
+ BYTE* buff = (BYTE*)bstr;
+ //set the trail byte
+ (*pStringObj)->SetTrailByte(buff[length-1]);
+ }
+
+ // null terminate the StringRef
+ WCHAR* wstr = (WCHAR *)(*pStringObj)->GetBuffer();
+ wstr[charLength] = '\0';
+}
+
+void OleVariant::ConvertBSTRToString(BSTR bstr, STRINGREF *pStringObj)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(bstr, NULL_OK));
+ PRECONDITION(CheckPointer(pStringObj));
+ }
+ CONTRACTL_END;
+
+ // Initialize the output string object to null to start.
+ *pStringObj = NULL;
+
+ // If the BSTR is null then we leave the output string object set to null.
+ if (bstr == NULL)
+ return;
+
+ AllocateEmptyStringForBSTR(bstr, pStringObj);
+ ConvertContentsBSTRToString(bstr, pStringObj);
+}
+
+BSTR OleVariant::AllocateEmptyBSTRForString(STRINGREF *pStringObj)
+{
+ CONTRACT(BSTR)
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pStringObj));
+ PRECONDITION(*pStringObj != NULL);
+ POSTCONDITION(RETVAL != NULL);
+ }
+ CONTRACT_END;
+
+ ULONG length = (*pStringObj)->GetStringLength();
+ if (length > MAX_SIZE_FOR_INTEROP)
+ COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG);
+
+ length = length*sizeof(WCHAR);
+ if ((*pStringObj)->HasTrailByte())
+ {
+ length += 1;
+ }
+ BSTR bstr = SysAllocStringByteLen(NULL, length);
+ if (bstr == NULL)
+ ThrowOutOfMemory();
+
+ RETURN bstr;
+}
+
+void OleVariant::ConvertContentsStringToBSTR(STRINGREF *pStringObj, BSTR bstr)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pStringObj));
+ PRECONDITION(*pStringObj != NULL);
+ PRECONDITION(CheckPointer(bstr));
+ }
+ CONTRACTL_END;
+
+ DWORD length = (DWORD)(*pStringObj)->GetStringLength();
+ if (length > MAX_SIZE_FOR_INTEROP)
+ COMPlusThrow(kMarshalDirectiveException, IDS_EE_STRING_TOOLONG);
+
+ BYTE *buff = (BYTE*)bstr;
+ ULONG byteLen = length * sizeof(WCHAR);
+
+ memcpyNoGCRefs(bstr, (*pStringObj)->GetBuffer(), byteLen);
+
+ if ((*pStringObj)->HasTrailByte())
+ {
+ BYTE b;
+ BOOL hasTrailB;
+ hasTrailB = (*pStringObj)->GetTrailByte(&b);
+ _ASSERTE(hasTrailB);
+ buff[byteLen] = b;
+ }
+ else
+ {
+ // copy the null terminator
+ bstr[length] = W('\0');
+ }
+}
+
+BSTR OleVariant::ConvertStringToBSTR(STRINGREF *pStringObj)
+{
+ CONTRACT(BSTR)
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(pStringObj));
+
+ // A null BSTR should only be returned if the input string is null.
+ POSTCONDITION(RETVAL != NULL || *pStringObj == NULL);
+}
+ CONTRACT_END;
+
+ // Initiatilize the return BSTR value to null.
+ BSTR bstr = NULL;
+
+ // If the string object isn't null then we convert it to a BSTR. Otherwise we will return null.
+ if (*pStringObj != NULL)
+ {
+ bstr = AllocateEmptyBSTRForString(pStringObj);
+ ConvertContentsStringToBSTR(pStringObj, bstr);
+ }
+
+ RETURN bstr;
+}
+#endif // FEATURE_COMINTEROP
+
+#endif // CROSSGEN_COMPILE