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;
20 using System.Collections.Generic;
21 using System.Diagnostics.CodeAnalysis;
23 using System.Linq.Expressions;
25 using Microsoft.Linq.Expressions;
27 using System.Security;
28 using System.Security.Permissions;
31 [assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "System.Dynamic")]
33 [assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "Microsoft.Scripting")]
37 namespace System.Dynamic {
39 namespace Microsoft.Scripting {
43 /// Provides helper methods to bind COM objects dynamically.
45 public static class ComBinder {
48 /// Determines if an object is a COM object.
50 /// <param name="value">The object to test.</param>
51 /// <returns>true if the object is a COM object, false otherwise.</returns>
52 public static bool IsComObject(object value) {
53 return ComObject.IsComObject(value);
57 /// Tries to perform binding of the dynamic get member operation.
59 /// <param name="binder">An instance of the <see cref="GetMemberBinder"/> that represents the details of the dynamic operation.</param>
60 /// <param name="instance">The target of the dynamic operation. </param>
61 /// <param name="result">The new <see cref="DynamicMetaObject"/> representing the result of the binding.</param>
62 /// <param name="delayInvocation">true if member evaluation may be delayed.</param>
63 /// <returns>true if operation was bound successfully; otherwise, false.</returns>
65 [SecurityCritical, SecurityTreatAsSafe]
67 [SecuritySafeCritical]
69 public static bool TryBindGetMember(GetMemberBinder binder, DynamicMetaObject instance, out DynamicMetaObject result, bool delayInvocation) {
70 ContractUtils.RequiresNotNull(binder, "binder");
71 ContractUtils.RequiresNotNull(instance, "instance");
73 if (TryGetMetaObject(ref instance)) {
75 // Demand Full Trust to proceed with the binding.
78 new PermissionSet(PermissionState.Unrestricted).Demand();
80 var comGetMember = new ComGetMemberBinder(binder, delayInvocation);
81 result = instance.BindGetMember(comGetMember);
82 if (result.Expression.Type.IsValueType) {
83 result = new DynamicMetaObject(
84 Expression.Convert(result.Expression, typeof(object)),
96 /// Tries to perform binding of the dynamic get member operation.
98 /// <param name="binder">An instance of the <see cref="GetMemberBinder"/> that represents the details of the dynamic operation.</param>
99 /// <param name="instance">The target of the dynamic operation. </param>
100 /// <param name="result">The new <see cref="DynamicMetaObject"/> representing the result of the binding.</param>
101 /// <returns>true if operation was bound successfully; otherwise, false.</returns>
102 public static bool TryBindGetMember(GetMemberBinder binder, DynamicMetaObject instance, out DynamicMetaObject result) {
103 return TryBindGetMember(binder, instance, out result, false);
107 /// Tries to perform binding of the dynamic set member operation.
109 /// <param name="binder">An instance of the <see cref="SetMemberBinder"/> that represents the details of the dynamic operation.</param>
110 /// <param name="instance">The target of the dynamic operation.</param>
111 /// <param name="value">The <see cref="DynamicMetaObject"/> representing the value for the set member operation.</param>
112 /// <param name="result">The new <see cref="DynamicMetaObject"/> representing the result of the binding.</param>
113 /// <returns>true if operation was bound successfully; otherwise, false.</returns>
114 #if MICROSOFT_DYNAMIC
115 [SecurityCritical, SecurityTreatAsSafe]
117 [SecuritySafeCritical]
119 public static bool TryBindSetMember(SetMemberBinder binder, DynamicMetaObject instance, DynamicMetaObject value, out DynamicMetaObject result) {
120 ContractUtils.RequiresNotNull(binder, "binder");
121 ContractUtils.RequiresNotNull(instance, "instance");
122 ContractUtils.RequiresNotNull(value, "value");
124 if (TryGetMetaObject(ref instance)) {
126 // Demand Full Trust to proceed with the binding.
129 new PermissionSet(PermissionState.Unrestricted).Demand();
131 result = instance.BindSetMember(binder, value);
140 /// Tries to perform binding of the dynamic invoke operation.
142 /// <param name="binder">An instance of the <see cref="InvokeBinder"/> that represents the details of the dynamic operation.</param>
143 /// <param name="instance">The target of the dynamic operation. </param>
144 /// <param name="args">An array of <see cref="DynamicMetaObject"/> instances - arguments to the invoke member operation.</param>
145 /// <param name="result">The new <see cref="DynamicMetaObject"/> representing the result of the binding.</param>
146 /// <returns>true if operation was bound successfully; otherwise, false.</returns>
147 #if MICROSOFT_DYNAMIC
148 [SecurityCritical, SecurityTreatAsSafe]
150 [SecuritySafeCritical]
152 public static bool TryBindInvoke(InvokeBinder binder, DynamicMetaObject instance, DynamicMetaObject[] args, out DynamicMetaObject result) {
153 ContractUtils.RequiresNotNull(binder, "binder");
154 ContractUtils.RequiresNotNull(instance, "instance");
155 ContractUtils.RequiresNotNull(args, "args");
157 if (TryGetMetaObject(ref instance)) {
159 // Demand Full Trust to proceed with the binding.
162 new PermissionSet(PermissionState.Unrestricted).Demand();
164 result = instance.BindInvoke(binder, args);
173 /// Tries to perform binding of the dynamic invoke member operation.
175 /// <param name="binder">An instance of the <see cref="InvokeMemberBinder"/> that represents the details of the dynamic operation.</param>
176 /// <param name="instance">The target of the dynamic operation. </param>
177 /// <param name="args">An array of <see cref="DynamicMetaObject"/> instances - arguments to the invoke member operation.</param>
178 /// <param name="result">The new <see cref="DynamicMetaObject"/> representing the result of the binding.</param>
179 /// <returns>true if operation was bound successfully; otherwise, false.</returns>
180 #if MICROSOFT_DYNAMIC
181 [SecurityCritical, SecurityTreatAsSafe]
183 [SecuritySafeCritical]
185 public static bool TryBindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject instance, DynamicMetaObject[] args, out DynamicMetaObject result) {
186 ContractUtils.RequiresNotNull(binder, "binder");
187 ContractUtils.RequiresNotNull(instance, "instance");
188 ContractUtils.RequiresNotNull(args, "args");
190 if (TryGetMetaObject(ref instance)) {
192 // Demand Full Trust to proceed with the binding.
195 new PermissionSet(PermissionState.Unrestricted).Demand();
197 result = instance.BindInvokeMember(binder, args);
206 /// Tries to perform binding of the dynamic get index operation.
208 /// <param name="binder">An instance of the <see cref="GetIndexBinder"/> that represents the details of the dynamic operation.</param>
209 /// <param name="instance">The target of the dynamic operation. </param>
210 /// <param name="args">An array of <see cref="DynamicMetaObject"/> instances - arguments to the invoke member operation.</param>
211 /// <param name="result">The new <see cref="DynamicMetaObject"/> representing the result of the binding.</param>
212 /// <returns>true if operation was bound successfully; otherwise, false.</returns>
213 #if MICROSOFT_DYNAMIC
214 [SecurityCritical, SecurityTreatAsSafe]
216 [SecuritySafeCritical]
218 public static bool TryBindGetIndex(GetIndexBinder binder, DynamicMetaObject instance, DynamicMetaObject[] args, out DynamicMetaObject result) {
219 ContractUtils.RequiresNotNull(binder, "binder");
220 ContractUtils.RequiresNotNull(instance, "instance");
221 ContractUtils.RequiresNotNull(args, "args");
223 if (TryGetMetaObject(ref instance)) {
225 // Demand Full Trust to proceed with the binding.
228 new PermissionSet(PermissionState.Unrestricted).Demand();
230 result = instance.BindGetIndex(binder, args);
239 /// Tries to perform binding of the dynamic set index operation.
241 /// <param name="binder">An instance of the <see cref="SetIndexBinder"/> that represents the details of the dynamic operation.</param>
242 /// <param name="instance">The target of the dynamic operation. </param>
243 /// <param name="args">An array of <see cref="DynamicMetaObject"/> instances - arguments to the invoke member operation.</param>
244 /// <param name="value">The <see cref="DynamicMetaObject"/> representing the value for the set index operation.</param>
245 /// <param name="result">The new <see cref="DynamicMetaObject"/> representing the result of the binding.</param>
246 /// <returns>true if operation was bound successfully; otherwise, false.</returns>
247 #if MICROSOFT_DYNAMIC
248 [SecurityCritical, SecurityTreatAsSafe]
250 [SecuritySafeCritical]
252 public static bool TryBindSetIndex(SetIndexBinder binder, DynamicMetaObject instance, DynamicMetaObject[] args, DynamicMetaObject value, out DynamicMetaObject result) {
253 ContractUtils.RequiresNotNull(binder, "binder");
254 ContractUtils.RequiresNotNull(instance, "instance");
255 ContractUtils.RequiresNotNull(args, "args");
256 ContractUtils.RequiresNotNull(value, "value");
258 if (TryGetMetaObject(ref instance)) {
260 // Demand Full Trust to proceed with the binding.
263 new PermissionSet(PermissionState.Unrestricted).Demand();
265 result = instance.BindSetIndex(binder, args, value);
274 /// Tries to perform binding of the dynamic Convert operation.
276 /// <param name="binder">An instance of the <see cref="ConvertBinder"/> that represents the details of the dynamic operation.</param>
277 /// <param name="instance">The target of the dynamic operation.</param>
278 /// <param name="result">The new <see cref="DynamicMetaObject"/> representing the result of the binding.</param>
279 /// <returns>true if operation was bound successfully; otherwise, false.</returns>
280 #if MICROSOFT_DYNAMIC
281 [SecurityCritical, SecurityTreatAsSafe]
283 [SecuritySafeCritical]
285 public static bool TryConvert(ConvertBinder binder, DynamicMetaObject instance, out DynamicMetaObject result) {
286 ContractUtils.RequiresNotNull(binder, "binder");
287 ContractUtils.RequiresNotNull(instance, "instance");
289 if (IsComObject(instance.Value)) {
291 // Demand Full Trust to proceed with the binding.
294 new PermissionSet(PermissionState.Unrestricted).Demand();
296 // Converting a COM object to any interface is always considered possible - it will result in
297 // a QueryInterface at runtime
298 if (binder.Type.IsInterface) {
299 result = new DynamicMetaObject(
304 BindingRestrictions.GetExpressionRestriction(
306 typeof(ComObject).GetMethod("IsComObject", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic),
307 Helpers.Convert(instance.Expression, typeof(object))
320 /// Gets the member names associated with the object.
321 /// This function can operate only with objects for which <see cref="IsComObject"/> returns true.
323 /// <param name="value">The object for which member names are requested.</param>
324 /// <returns>The collection of member names.</returns>
325 #if MICROSOFT_DYNAMIC
326 [SecurityCritical, SecurityTreatAsSafe]
328 [SecuritySafeCritical]
330 public static IEnumerable<string> GetDynamicMemberNames(object value) {
331 ContractUtils.RequiresNotNull(value, "value");
332 ContractUtils.Requires(IsComObject(value), "value", Strings.ComObjectExpected);
335 // Demand Full Trust to proceed with the binding.
338 new PermissionSet(PermissionState.Unrestricted).Demand();
340 return ComObject.ObjectToComObject(value).GetMemberNames(false);
344 /// Gets the member names of the data-like members associated with the object.
345 /// This function can operate only with objects for which <see cref="IsComObject"/> returns true.
347 /// <param name="value">The object for which member names are requested.</param>
348 /// <returns>The collection of member names.</returns>
349 #if MICROSOFT_DYNAMIC
350 [SecurityCritical, SecurityTreatAsSafe]
352 [SecuritySafeCritical]
354 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
355 internal static IList<string> GetDynamicDataMemberNames(object value) {
356 ContractUtils.RequiresNotNull(value, "value");
357 ContractUtils.Requires(IsComObject(value), "value", Strings.ComObjectExpected);
360 // Demand Full Trust to proceed with the binding.
363 new PermissionSet(PermissionState.Unrestricted).Demand();
365 return ComObject.ObjectToComObject(value).GetMemberNames(true);
369 /// Gets the data-like members and associated data for an object.
370 /// This function can operate only with objects for which <see cref="IsComObject"/> returns true.
372 /// <param name="value">The object for which data members are requested.</param>
373 /// <param name="names">The enumeration of names of data members for which to retrieve values.</param>
374 /// <returns>The collection of pairs that represent data member's names and their data.</returns>
375 [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
376 [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
377 #if MICROSOFT_DYNAMIC
378 [SecurityCritical, SecurityTreatAsSafe]
380 [SecuritySafeCritical]
382 internal static IList<KeyValuePair<string, object>> GetDynamicDataMembers(object value, IEnumerable<string> names) {
383 ContractUtils.RequiresNotNull(value, "value");
384 ContractUtils.Requires(IsComObject(value), "value", Strings.ComObjectExpected);
387 // Demand Full Trust to proceed with the binding.
390 new PermissionSet(PermissionState.Unrestricted).Demand();
392 return ComObject.ObjectToComObject(value).GetMembers(names);
395 private static bool TryGetMetaObject(ref DynamicMetaObject instance) {
396 // If we're already a COM MO don't make a new one
397 // (we do this to prevent recursion if we call Fallback from COM)
398 if (instance is ComUnwrappedMetaObject) {
402 if (IsComObject(instance.Value)) {
403 instance = new ComMetaObject(instance.Expression, instance.Restrictions, instance.Value);
411 /// Special binder that indicates special semantics for COM GetMember operation.
413 internal class ComGetMemberBinder : GetMemberBinder {
414 private readonly GetMemberBinder _originalBinder;
415 internal bool _CanReturnCallables;
417 internal ComGetMemberBinder(GetMemberBinder originalBinder, bool CanReturnCallables) :
418 base(originalBinder.Name, originalBinder.IgnoreCase) {
419 _originalBinder = originalBinder;
420 _CanReturnCallables = CanReturnCallables;
423 public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion) {
424 return _originalBinder.FallbackGetMember(target, errorSuggestion);
427 public override int GetHashCode() {
428 return _originalBinder.GetHashCode() ^ (_CanReturnCallables ? 1 : 0);
431 public override bool Equals(object obj) {
432 ComGetMemberBinder other = obj as ComGetMemberBinder;
433 return other != null &&
434 _CanReturnCallables == other._CanReturnCallables &&
435 _originalBinder.Equals(other._originalBinder);