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.Collections.Generic;
21 using System.Diagnostics;
23 using System.Linq.Expressions;
25 using Microsoft.Linq.Expressions;
27 using System.Reflection;
28 using System.Runtime.InteropServices;
29 using System.Security;
30 using System.Security.Permissions;
33 namespace System.Dynamic {
35 namespace Microsoft.Scripting {
38 /// This is a helper class for runtime-callable-wrappers of COM instances. We create one instance of this type
39 /// for every generic RCW instance.
41 internal class ComObject : IDynamicMetaObjectProvider {
43 /// The runtime-callable wrapper
45 private readonly object _rcw;
47 internal ComObject(object rcw) {
48 Debug.Assert(ComObject.IsComObject(rcw));
52 internal object RuntimeCallableWrapper {
58 private readonly static object _ComObjectInfoKey = new object();
61 /// This is the factory method to get the ComObject corresponding to an RCW
63 /// <returns></returns>
65 [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
68 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes")]
69 public static ComObject ObjectToComObject(object rcw) {
70 Debug.Assert(ComObject.IsComObject(rcw));
72 // Marshal.Get/SetComObjectData has a LinkDemand for UnmanagedCode which will turn into
73 // a full demand. We could avoid this by making this method SecurityCritical
74 object data = Marshal.GetComObjectData(rcw, _ComObjectInfoKey);
76 return (ComObject)data;
79 lock (_ComObjectInfoKey) {
80 data = Marshal.GetComObjectData(rcw, _ComObjectInfoKey);
82 return (ComObject)data;
85 ComObject comObjectInfo = CreateComObject(rcw);
86 if (!Marshal.SetComObjectData(rcw, _ComObjectInfoKey, comObjectInfo)) {
87 throw Error.SetComObjectDataFailed();
94 // Expression that unwraps ComObject
95 internal static MemberExpression RcwFromComObject(Expression comObject) {
96 Debug.Assert(comObject != null && typeof(ComObject).IsAssignableFrom(comObject.Type), "must be ComObject");
98 return Expression.Property(
99 Helpers.Convert(comObject, typeof(ComObject)),
100 typeof(ComObject).GetProperty("RuntimeCallableWrapper", BindingFlags.NonPublic | BindingFlags.Instance)
104 // Expression that finds or creates a ComObject that corresponds to given Rcw
105 internal static MethodCallExpression RcwToComObject(Expression rcw) {
106 return Expression.Call(
107 typeof(ComObject).GetMethod("ObjectToComObject"),
108 Helpers.Convert(rcw, typeof(object))
112 private static ComObject CreateComObject(object rcw) {
113 IDispatch dispatchObject = rcw as IDispatch;
114 if (dispatchObject != null) {
115 // We can do method invocations on IDispatch objects
116 return new IDispatchComObject(dispatchObject);
119 // There is not much we can do in this case
120 return new ComObject(rcw);
123 internal virtual IList<string> GetMemberNames(bool dataOnly) {
124 return new string[0];
127 internal virtual IList<KeyValuePair<string, object>> GetMembers(IEnumerable<string> names) {
128 return new KeyValuePair<string, object>[0];
131 DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) {
132 return new ComFallbackMetaObject(parameter, BindingRestrictions.Empty, this);
135 private static readonly Type ComObjectType = typeof(object).Assembly.GetType("System.__ComObject");
137 internal static bool IsComObject(object obj) {
138 // we can't use System.Runtime.InteropServices.Marshal.IsComObject(obj) since it doesn't work in partial trust
139 return obj != null && ComObjectType.IsAssignableFrom(obj.GetType());