Esempio n. 1
0
        /// <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(s_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);
            }
        }
Esempio n. 2
0
        internal Expression Clear()
        {
            if (IsByRef)
            {
                if (_argBuilder is StringArgBuilder)
                {
                    Debug.Assert(TempVariable != null);
                    return(Expression.Call(typeof(Marshal).GetMethod(nameof(Marshal.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(nameof(Variant.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(nameof(Variant.Clear))));

            default:
                Debug.Assert(Variant.IsPrimitiveType(_targetComType), "Unexpected VarEnum");
                return(null);
            }
        }
Esempio n. 3
0
        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);
            }
        }