1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation.
4  *
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.
10  *
11  * You must not remove this notice, or any other, from this software.
12  *
13  *
14  * ***************************************************************************/
15 using System; using Microsoft;
16 
17 
18 #if !SILVERLIGHT
19 
20 #if CODEPLEX_40
21 using System.Linq.Expressions;
22 #else
23 using Microsoft.Linq.Expressions;
24 #endif
25 using System.Security;
26 using System.Security.Permissions;
27 
28 #if CODEPLEX_40
29 namespace System.Dynamic {
30 #else
31 namespace Microsoft.Scripting {
32 #endif
33     internal class DispCallableMetaObject : DynamicMetaObject {
34         private readonly DispCallable _callable;
35 
DispCallableMetaObject(Expression expression, DispCallable callable)36         internal DispCallableMetaObject(Expression expression, DispCallable callable)
37             : base(expression, BindingRestrictions.Empty, callable) {
38             _callable = callable;
39         }
40 
BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes)41         public override DynamicMetaObject BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes) {
42             return BindGetOrInvoke(indexes, binder.CallInfo) ??
43                 base.BindGetIndex(binder, indexes);
44         }
45 
BindInvoke(InvokeBinder binder, DynamicMetaObject[] args)46         public override DynamicMetaObject BindInvoke(InvokeBinder binder, DynamicMetaObject[] args) {
47             return BindGetOrInvoke(args, binder.CallInfo) ??
48                 base.BindInvoke(binder, args);
49         }
50 
51 #if CLR2
52         [SecurityCritical, SecurityTreatAsSafe]
53 #else
54         [SecuritySafeCritical]
55 #endif
BindGetOrInvoke(DynamicMetaObject[] args, CallInfo callInfo)56         private DynamicMetaObject BindGetOrInvoke(DynamicMetaObject[] args, CallInfo callInfo) {
57             //
58             // Demand Full Trust to proceed with the binding.
59             //
60 
61             new PermissionSet(PermissionState.Unrestricted).Demand();
62 
63             ComMethodDesc method;
64             var target = _callable.DispatchComObject;
65             var name = _callable.MemberName;
66 
67             if (target.TryGetMemberMethod(name, out method) ||
68                 target.TryGetMemberMethodExplicit(name, out method)) {
69 
70                 bool[] isByRef = ComBinderHelpers.ProcessArgumentsForCom(ref args);
71                 return BindComInvoke(method, args, callInfo, isByRef);
72             }
73             return null;
74         }
75 
76 #if CLR2
77         [SecurityCritical, SecurityTreatAsSafe]
78 #else
79         [SecuritySafeCritical]
80 #endif
BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value)81         public override DynamicMetaObject BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value) {
82             //
83             // Demand Full Trust to proceed with the binding.
84             //
85 
86             new PermissionSet(PermissionState.Unrestricted).Demand();
87 
88             ComMethodDesc method;
89             var target = _callable.DispatchComObject;
90             var name = _callable.MemberName;
91 
92             bool holdsNull = value.Value == null && value.HasValue;
93             if (target.TryGetPropertySetter(name, out method, value.LimitType, holdsNull) ||
94                 target.TryGetPropertySetterExplicit(name, out method, value.LimitType, holdsNull)) {
95 
96                 bool[] isByRef = ComBinderHelpers.ProcessArgumentsForCom(ref indexes);
97                 isByRef = isByRef.AddLast(false);
98                 var result = BindComInvoke(method, indexes.AddLast(value), binder.CallInfo, isByRef);
99 
100                 // Make sure to return the value; some languages need it.
101                 return new DynamicMetaObject(
102                     Expression.Block(result.Expression, Expression.Convert(value.Expression, typeof(object))),
103                     result.Restrictions
104                 );
105             }
106 
107             return base.BindSetIndex(binder, indexes, value);
108         }
109 
110         [SecurityCritical]
BindComInvoke(ComMethodDesc method, DynamicMetaObject[] indexes, CallInfo callInfo, bool[] isByRef)111         private DynamicMetaObject BindComInvoke(ComMethodDesc method, DynamicMetaObject[] indexes, CallInfo callInfo, bool[] isByRef) {
112             var callable = Expression;
113             var dispCall = Helpers.Convert(callable, typeof(DispCallable));
114 
115             return new ComInvokeBinder(
116                 callInfo,
117                 indexes,
118                 isByRef,
119                 DispCallableRestrictions(),
120                 Expression.Constant(method),
121                 Expression.Property(
122                     dispCall,
123                     typeof(DispCallable).GetProperty("DispatchObject")
124                 ),
125                 method
126             ).Invoke();
127         }
128 
129         [SecurityCritical]
DispCallableRestrictions()130         private BindingRestrictions DispCallableRestrictions() {
131             var callable = Expression;
132 
133             var callableTypeRestrictions = BindingRestrictions.GetTypeRestriction(callable, typeof(DispCallable));
134             var dispCall = Helpers.Convert(callable, typeof(DispCallable));
135             var dispatch = Expression.Property(dispCall, typeof(DispCallable).GetProperty("DispatchComObject"));
136             var dispId = Expression.Property(dispCall, typeof(DispCallable).GetProperty("DispId"));
137 
138             var dispatchRestriction = IDispatchMetaObject.IDispatchRestriction(dispatch, _callable.DispatchComObject.ComTypeDesc);
139             var memberRestriction = BindingRestrictions.GetExpressionRestriction(
140                 Expression.Equal(dispId, Expression.Constant(_callable.DispId))
141             );
142 
143             return callableTypeRestrictions.Merge(dispatchRestriction).Merge(memberRestriction);
144         }
145     }
146 }
147 
148 #endif
149