PageRenderTime 11ms CodeModel.GetById 2ms app.highlight 6ms RepoModel.GetById 0ms app.codeStats 1ms

/IronPython_Main/Runtime/Microsoft.Dynamic/ComInterop/ComObject.cs

#
C# | 137 lines | 82 code | 23 blank | 32 comment | 11 complexity | 997e56684acc1e7122818722c704cdcf MD5 | raw file
  1/* ****************************************************************************
  2 *
  3 * Copyright (c) Microsoft Corporation. 
  4 *
  5 * This source code is subject to terms and conditions of the Apache License, Version 2.0. 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  Apache License, Version 2.0, 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 Apache License, Version 2.0.
 10 *
 11 * You must not remove this notice, or any other, from this software.
 12 *
 13 *
 14 * ***************************************************************************/
 15
 16#if !SILVERLIGHT // ComObject
 17#if !CLR2
 18using System.Linq.Expressions;
 19#else
 20using Microsoft.Scripting.Ast;
 21#endif
 22
 23using System;
 24using System.Collections.Generic;
 25using System.Diagnostics;
 26using System.Reflection;
 27using System.Runtime.InteropServices;
 28using System.Security;
 29using System.Security.Permissions;
 30using System.Dynamic;
 31
 32namespace Microsoft.Scripting.ComInterop {
 33    /// <summary>
 34    /// This is a helper class for runtime-callable-wrappers of COM instances. We create one instance of this type
 35    /// for every generic RCW instance.
 36    /// </summary>
 37    internal class ComObject : IDynamicMetaObjectProvider {
 38        /// <summary>
 39        /// The runtime-callable wrapper
 40        /// </summary>
 41        private readonly object _rcw;
 42
 43        internal ComObject(object rcw) {
 44            Debug.Assert(ComObject.IsComObject(rcw));
 45            _rcw = rcw;
 46        }
 47
 48        internal object RuntimeCallableWrapper {
 49            get {
 50                return _rcw;
 51            }
 52        }
 53
 54        private readonly static object _ComObjectInfoKey = new object();
 55
 56        /// <summary>
 57        /// This is the factory method to get the ComObject corresponding to an RCW
 58        /// </summary>
 59        /// <returns></returns>
 60        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes")]
 61        public static ComObject ObjectToComObject(object rcw) {
 62            Debug.Assert(ComObject.IsComObject(rcw));
 63
 64            // Marshal.Get/SetComObjectData has a LinkDemand for UnmanagedCode which will turn into
 65            // a full demand. We could avoid this by making this method SecurityCritical
 66            object data = Marshal.GetComObjectData(rcw, _ComObjectInfoKey);
 67            if (data != null) {
 68                return (ComObject)data;
 69            }
 70
 71            lock (_ComObjectInfoKey) {
 72                data = Marshal.GetComObjectData(rcw, _ComObjectInfoKey);
 73                if (data != null) {
 74                    return (ComObject)data;
 75                }
 76
 77                ComObject comObjectInfo = CreateComObject(rcw);
 78                if (!Marshal.SetComObjectData(rcw, _ComObjectInfoKey, comObjectInfo)) {
 79                    throw Error.SetComObjectDataFailed();
 80                }
 81
 82                return comObjectInfo;
 83            }
 84        }
 85
 86        // Expression that unwraps ComObject
 87        internal static MemberExpression RcwFromComObject(Expression comObject) {
 88            Debug.Assert(comObject != null && typeof(ComObject).IsAssignableFrom(comObject.Type), "must be ComObject");
 89
 90            return Expression.Property(
 91                Helpers.Convert(comObject, typeof(ComObject)),
 92                typeof(ComObject).GetProperty("RuntimeCallableWrapper", BindingFlags.NonPublic | BindingFlags.Instance)
 93            );
 94        }
 95
 96        // Expression that finds or creates a ComObject that corresponds to given Rcw
 97        internal static MethodCallExpression RcwToComObject(Expression rcw) {
 98            return Expression.Call(
 99                typeof(ComObject).GetMethod("ObjectToComObject"),
100                Helpers.Convert(rcw, typeof(object))
101            );
102        }
103
104        private static ComObject CreateComObject(object rcw) {
105            IDispatch dispatchObject = rcw as IDispatch;
106            if (dispatchObject != null) {
107                // We can do method invocations on IDispatch objects
108                return new IDispatchComObject(dispatchObject);
109            }
110
111            // There is not much we can do in this case
112            return new ComObject(rcw);
113        }
114
115        internal virtual IList<string> GetMemberNames(bool dataOnly) {
116            return new string[0];
117        }
118
119        internal virtual IList<KeyValuePair<string, object>> GetMembers(IEnumerable<string> names) {
120            return new KeyValuePair<string, object>[0];
121        }
122
123        DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) {
124            return new ComFallbackMetaObject(parameter, BindingRestrictions.Empty, this);
125        }
126
127        private static readonly Type ComObjectType = typeof(object).Assembly.GetType("System.__ComObject");
128
129        internal static bool IsComObject(object obj) {
130            // we can't use System.Runtime.InteropServices.Marshal.IsComObject(obj) since it doesn't work in partial trust
131            return obj != null && ComObjectType.IsAssignableFrom(obj.GetType());
132        }
133
134    }
135}
136
137#endif