2009-07-11 Michael Barker <mike@middlesoft.co.uk>
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Dynamic / BoundDispEvent.cs
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 // ComObject
19
20 #if CODEPLEX_40
21 using System.Linq.Expressions;
22 #else
23 using Microsoft.Linq.Expressions;
24 #endif
25 using System.Runtime.CompilerServices;
26 #if !CODEPLEX_40
27 using Microsoft.Runtime.CompilerServices;
28 #endif
29
30 using System.Security;
31 using System.Security.Permissions;
32
33 #if CODEPLEX_40
34 namespace System.Dynamic {
35 #else
36 namespace Microsoft.Scripting {
37 #endif
38     internal sealed class BoundDispEvent : DynamicObject {
39         private object _rcw;
40         private Guid _sourceIid;
41         private int _dispid;
42
43         internal BoundDispEvent(object rcw, Guid sourceIid, int dispid) {
44             _rcw = rcw;
45             _sourceIid = sourceIid;
46             _dispid = dispid;
47         }
48
49         /// <summary>
50         /// Provides the implementation of performing AddAssign and SubtractAssign binary operations.
51         /// </summary>
52         /// <param name="binder">The binder provided by the call site.</param>
53         /// <param name="handler">The handler for the operation.</param>
54         /// <param name="result">The result of the operation.</param>
55         /// <returns>true if the operation is complete, false if the call site should determine behavior.</returns>
56         public override bool TryBinaryOperation(BinaryOperationBinder binder, object handler, out object result) {
57             if (binder.Operation == ExpressionType.AddAssign) {
58                 result = InPlaceAdd(handler);
59                 return true;
60             }
61
62             if (binder.Operation == ExpressionType.SubtractAssign) {
63                 result = InPlaceSubtract(handler);
64                 return true;
65             }
66
67             result = null;
68             return false;
69         }
70
71         private static void VerifyHandler(object handler) {
72             if (handler is Delegate && handler.GetType() != typeof(Delegate)) {
73                 return; // delegate
74             }
75
76             if (handler is IDynamicMetaObjectProvider) {
77                 return; // IDMOP
78             }
79
80             throw Error.UnsupportedHandlerType();
81         }
82
83         /// <summary>
84         /// Adds a handler to an event.
85         /// </summary>
86         /// <param name="handler">The handler to be added.</param>
87         /// <returns>The original event with handler added.</returns>
88 #if MICROSOFT_DYNAMIC
89         [SecurityCritical, SecurityTreatAsSafe]
90 #else
91         [SecuritySafeCritical]
92 #endif
93         private object InPlaceAdd(object handler) {
94             ContractUtils.RequiresNotNull(handler, "handler");
95             VerifyHandler(handler);
96
97             //
98             // Demand Full Trust to proceed with the operation.
99             //
100
101             new PermissionSet(PermissionState.Unrestricted).Demand();
102
103             ComEventSink comEventSink = ComEventSink.FromRuntimeCallableWrapper(_rcw, _sourceIid, true);
104             comEventSink.AddHandler(_dispid, handler);
105             return this;
106         }
107
108         /// <summary>
109         /// Removes handler from the event.
110         /// </summary>
111         /// <param name="handler">The handler to be removed.</param>
112         /// <returns>The original event with handler removed.</returns>
113 #if MICROSOFT_DYNAMIC
114         [SecurityCritical, SecurityTreatAsSafe]
115 #else
116         [SecuritySafeCritical]
117 #endif
118         private object InPlaceSubtract(object handler) {
119             ContractUtils.RequiresNotNull(handler, "handler");
120             VerifyHandler(handler);
121
122             //
123             // Demand Full Trust to proceed with the operation.
124             //
125
126             new PermissionSet(PermissionState.Unrestricted).Demand();
127
128             ComEventSink comEventSink = ComEventSink.FromRuntimeCallableWrapper(_rcw, _sourceIid, false);
129             if (comEventSink != null) {
130                 comEventSink.RemoveHandler(_dispid, handler);
131             }
132
133             return this;
134         }
135     }
136 }
137
138 #endif