1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
5 * This source code is subject to terms and conditions of the Microsoft Public License. A
6 * copy of the license can be found in the License.html file at the root of this distribution. If
7 * you cannot locate the Microsoft Public License, please send an email to
8 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
9 * by the terms of the Microsoft Public License.
11 * You must not remove this notice, or any other, from this software.
14 * ***************************************************************************/
15 using System; using Microsoft;
18 #if !SILVERLIGHT // ComObject
20 using System.Diagnostics;
22 using System.Linq.Expressions;
24 using Microsoft.Linq.Expressions;
26 using System.Runtime.InteropServices;
29 namespace System.Dynamic {
31 namespace Microsoft.Scripting {
35 /// VariantBuilder handles packaging of arguments into a Variant for a call to IDispatch.Invoke
37 internal class VariantBuilder {
39 private MemberExpression _variant;
40 private readonly ArgBuilder _argBuilder;
41 private readonly VarEnum _targetComType;
42 internal ParameterExpression TempVariable { get; private set; }
44 internal VariantBuilder(VarEnum targetComType, ArgBuilder builder) {
45 _targetComType = targetComType;
46 _argBuilder = builder;
49 internal bool IsByRef {
50 get { return (_targetComType & VarEnum.VT_BYREF) != 0; }
53 internal Expression InitializeArgumentVariant(MemberExpression variant, Expression parameter) {
54 //NOTE: we must remember our variant
55 //the reason is that argument order does not map exactly to the order of variants for invoke
56 //and when we are doing clean-up we must be sure we are cleaning the variant we have initialized.
62 // paramVariants._elementN.SetAsByrefT(ref temp)
63 Debug.Assert(TempVariable == null);
64 var argExpr = _argBuilder.MarshalToRef(parameter);
66 TempVariable = Expression.Variable(argExpr.Type, null);
67 return Expression.Block(
68 Expression.Assign(TempVariable, argExpr),
71 Variant.GetByrefSetter(_targetComType & ~VarEnum.VT_BYREF),
77 Expression argument = _argBuilder.Marshal(parameter);
79 // we are forced to special case ConvertibleArgBuilder since it does not have
80 // a corresponding _targetComType.
81 if (_argBuilder is ConvertibleArgBuilder) {
82 return Expression.Call(
84 typeof(Variant).GetMethod("SetAsIConvertible"),
89 if (Variant.IsPrimitiveType(_targetComType) ||
90 (_targetComType == VarEnum.VT_DISPATCH) ||
91 (_targetComType == VarEnum.VT_UNKNOWN) ||
92 (_targetComType == VarEnum.VT_VARIANT) ||
93 (_targetComType == VarEnum.VT_RECORD) ||
94 (_targetComType == VarEnum.VT_ARRAY)){
95 // paramVariants._elementN.AsT = (cast)argN
96 return Expression.Assign(
99 Variant.GetAccessor(_targetComType)
105 switch (_targetComType) {
106 case VarEnum.VT_EMPTY:
109 case VarEnum.VT_NULL:
110 // paramVariants._elementN.SetAsNull();
111 return Expression.Call(variant, typeof(Variant).GetMethod("SetAsNull"));
114 Debug.Assert(false, "Unexpected VarEnum");
119 private static Expression Release(Expression pUnk) {
120 return Expression.Call(typeof(UnsafeMethods).GetMethod("IUnknownReleaseNotZero"), pUnk);
123 internal Expression Clear() {
125 if (_argBuilder is StringArgBuilder) {
126 Debug.Assert(TempVariable != null);
127 return Expression.Call(typeof(Marshal).GetMethod("FreeBSTR"), TempVariable);
128 } else if (_argBuilder is DispatchArgBuilder) {
129 Debug.Assert(TempVariable != null);
130 return Release(TempVariable);
131 } else if (_argBuilder is UnknownArgBuilder) {
132 Debug.Assert(TempVariable != null);
133 return Release(TempVariable);
134 } else if (_argBuilder is VariantArgBuilder) {
135 Debug.Assert(TempVariable != null);
136 return Expression.Call(TempVariable, typeof(Variant).GetMethod("Clear"));
142 switch (_targetComType) {
143 case VarEnum.VT_EMPTY:
144 case VarEnum.VT_NULL:
147 case VarEnum.VT_BSTR:
148 case VarEnum.VT_UNKNOWN:
149 case VarEnum.VT_DISPATCH:
150 case VarEnum.VT_ARRAY:
151 case VarEnum.VT_RECORD:
152 case VarEnum.VT_VARIANT:
153 // paramVariants._elementN.Clear()
154 return Expression.Call(_variant, typeof(Variant).GetMethod("Clear"));
157 Debug.Assert(Variant.IsPrimitiveType(_targetComType), "Unexpected VarEnum");
162 internal Expression UpdateFromReturn(Expression parameter) {
163 if (TempVariable == null) {
166 return Expression.Assign(
169 _argBuilder.UnmarshalFromRef(TempVariable),