/// <summary> /// Gets the managed type that an object needs to be coverted to in order for it to be able /// to be represented as a Variant. /// /// In general, there is a many-to-many mapping between Type and VarEnum. However, this method /// returns a simple mapping that is needed for the current implementation. The reason for the /// many-to-many relation is: /// 1. Int32 maps to VT_I4 as well as VT_ERROR, and Decimal maps to VT_DECIMAL and VT_CY. However, /// this changes if you throw the wrapper types into the mix. /// 2. There is no Type to represent COM types. __ComObject is a private type, and Object is too /// general. /// </summary> internal static Type GetManagedMarshalType(VarEnum varEnum) { Debug.Assert((varEnum & VarEnum.VT_BYREF) == 0); if (varEnum == VarEnum.VT_CY) { return(typeof(CurrencyWrapper)); } if (Variant.IsPrimitiveType(varEnum)) { return(_ComToManagedPrimitiveTypes[varEnum]); } switch (varEnum) { case VarEnum.VT_EMPTY: case VarEnum.VT_NULL: case VarEnum.VT_UNKNOWN: case VarEnum.VT_DISPATCH: case VarEnum.VT_VARIANT: return(typeof(Object)); case VarEnum.VT_ERROR: return(typeof(ErrorWrapper)); default: throw Error.UnexpectedVarEnum(varEnum); } }
internal Expression Clear() { if (IsByRef) { if (_argBuilder is StringArgBuilder) { Debug.Assert(TempVariable != null); return(Expression.Call(typeof(Marshal).GetMethod("FreeBSTR"), TempVariable)); } if (_argBuilder is DispatchArgBuilder) { Debug.Assert(TempVariable != null); return(Release(TempVariable)); } if (_argBuilder is UnknownArgBuilder) { Debug.Assert(TempVariable != null); return(Release(TempVariable)); } if (_argBuilder is VariantArgBuilder) { Debug.Assert(TempVariable != null); return(Expression.Call(TempVariable, typeof(Variant).GetMethod("Clear"))); } return(null); } switch (_targetComType) { case VarEnum.VT_EMPTY: case VarEnum.VT_NULL: return(null); case VarEnum.VT_BSTR: case VarEnum.VT_UNKNOWN: case VarEnum.VT_DISPATCH: case VarEnum.VT_ARRAY: case VarEnum.VT_RECORD: case VarEnum.VT_VARIANT: // paramVariants._elementN.Clear() return(Expression.Call(_variant, typeof(Variant).GetMethod("Clear"))); default: Debug.Assert(Variant.IsPrimitiveType(_targetComType), "Unexpected VarEnum"); return(null); } }
internal Expression InitializeArgumentVariant(MemberExpression variant, Expression parameter) { //NOTE: we must remember our variant //the reason is that argument order does not map exactly to the order of variants for invoke //and when we are doing clean-up we must be sure we are cleaning the variant we have initialized. _variant = variant; if (IsByRef) { // temp = argument // paramVariants._elementN.SetAsByrefT(ref temp) Debug.Assert(TempVariable == null); var argExpr = _argBuilder.MarshalToRef(parameter); TempVariable = Expression.Variable(argExpr.Type, null); return(Expression.Block( Expression.Assign(TempVariable, argExpr), Expression.Call( variant, Variant.GetByrefSetter(_targetComType & ~VarEnum.VT_BYREF), TempVariable ) )); } Expression argument = _argBuilder.Marshal(parameter); // we are forced to special case ConvertibleArgBuilder since it does not have // a corresponding _targetComType. if (_argBuilder is ConvertibleArgBuilder) { return(Expression.Call( variant, typeof(Variant).GetMethod("SetAsIConvertible"), argument )); } if (Variant.IsPrimitiveType(_targetComType) || (_targetComType == VarEnum.VT_DISPATCH) || (_targetComType == VarEnum.VT_UNKNOWN) || (_targetComType == VarEnum.VT_VARIANT) || (_targetComType == VarEnum.VT_RECORD) || (_targetComType == VarEnum.VT_ARRAY)) { // paramVariants._elementN.AsT = (cast)argN return(Expression.Assign( Expression.Property( variant, Variant.GetAccessor(_targetComType) ), argument )); } switch (_targetComType) { case VarEnum.VT_EMPTY: return(null); case VarEnum.VT_NULL: // paramVariants._elementN.SetAsNull(); return(Expression.Call(variant, typeof(Variant).GetMethod("SetAsNull"))); default: Debug.Assert(false, "Unexpected VarEnum"); return(null); } }