/IronPython_Main/Runtime/Microsoft.Dynamic/ComInterop/ComEventSinkProxy.cs
C# | 129 lines | 64 code | 19 blank | 46 comment | 6 complexity | bf3f2e3e2956ec051728cc69c705b0ae MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, CPL-1.0, CC-BY-SA-3.0, BSD-3-Clause, ISC, AGPL-3.0, LGPL-2.1, Apache-2.0
- /* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Apache License, Version 2.0, please send an email to
- * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Apache License, Version 2.0.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
-
- #if !SILVERLIGHT // ComObject
-
- using System;
- using System.Globalization;
- using System.Reflection;
- using System.Runtime.InteropServices;
- using System.Runtime.Remoting;
- using System.Runtime.Remoting.Messaging;
- using System.Runtime.Remoting.Proxies;
- using System.Security;
- using System.Security.Permissions;
- using Microsoft.Scripting.Utils;
-
- namespace Microsoft.Scripting.ComInterop {
- /// <summary>
- /// ComEventSinkProxy class is responsible for handling QIs for sourceIid
- /// on instances of ComEventSink.
- ///
- /// Background: When a COM even sink advises to a connection point it is
- /// supposed to hand over the dispinterface. Now, some hosts will trust
- /// the COM client to pass the correct pointer, but some will not.
- /// E.g. Excel's implementation of Connection Points will not cause a
- /// QI on the pointer that has been passed, however Word will QI the
- /// pointer to return the required interface.
- ///
- /// ComEventSink does not, strongly speaking, implements the interface
- /// that it claims to implement - it is just "faking" it by using IReflect.
- /// Thus, Word's QIs on the pointer passed to ICP::Advise would fail. To
- /// prevent this we take advangate of RealProxy's ability of
- /// "dressing up" like other classes and hence successfully respond to QIs
- /// for interfaces that it does not really support( it is OK to say
- /// "I implement this interface" for event sinks only since the common
- /// practice is to use IDistpach.Invoke when calling into event sinks).
- /// </summary>
- internal sealed class ComEventSinkProxy : RealProxy {
-
- private Guid _sinkIid;
- private ComEventSink _sink;
- private static readonly MethodInfo _methodInfoInvokeMember = typeof(ComEventSink).GetMethod("InvokeMember", BindingFlags.Instance | BindingFlags.Public);
-
- #region ctors
-
- private ComEventSinkProxy() {
- }
-
- public ComEventSinkProxy(ComEventSink sink, Guid sinkIid)
- : base(typeof(ComEventSink)) {
- _sink = sink;
- _sinkIid = sinkIid;
- }
-
- #endregion
-
- #region Base Class Overrides
-
- public override IntPtr SupportsInterface(ref Guid iid) {
- // if the iid is the sink iid, we ask the base class for an rcw to IDispatch
- if (iid == _sinkIid) {
- IntPtr retVal = IntPtr.Zero;
- retVal = Marshal.GetIDispatchForObject(_sink);
- return retVal;
- }
-
- return base.SupportsInterface(ref iid);
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
- public override IMessage Invoke(IMessage msg) {
- ContractUtils.RequiresNotNull(msg, "msg");
-
- //Only know how to handle method calls (property and fields accessors count as methods)
- IMethodCallMessage methodCallMessage = msg as IMethodCallMessage;
- if (methodCallMessage == null)
- throw new NotSupportedException();
-
- // ComEventSink.InvokeMember is handled specially.
- // The reason we need to do that is due to how namedParameters arg (7th element in the IMethodCallMessage.Args array)
- // is marshalled when called through RealProxy.Invoke.
- // In RealProxy.Invoke namedParameters is typed as object[], while InvokeMember expects it to be string[].
- // If we simply let this call go through (with RemotingServices.ExecuteMessage)
- // we get an InvalidCastException when Remoting tries to pass namedParameters (of type object[])
- // to InvokeMember (which expects namedParameters to be string[]).
- // Since we don't use namedParameters in ComEventSink.InvokeMember - we simply ignore it here
- // and pass-in null.
- MethodInfo methodInfo = (MethodInfo)methodCallMessage.MethodBase;
- if (methodInfo == _methodInfoInvokeMember) {
- object retVal = null;
-
- try {
- // InvokeMember(string name, BindingFlags bindingFlags, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters)
- retVal = ((IReflect)_sink).InvokeMember(
- /*name*/ methodCallMessage.Args[0] as string,
- /*bindingFlags*/ (BindingFlags)methodCallMessage.Args[1],
- /*binder*/ methodCallMessage.Args[2] as Binder,
- /*target*/ null,
- /*args*/ methodCallMessage.Args[4] as object[],
- /*modifiers*/ methodCallMessage.Args[5] as ParameterModifier[],
- /*culture*/ methodCallMessage.Args[6] as CultureInfo,
- /*namedParameters*/ null);
- } catch (Exception ex) {
- return new ReturnMessage(ex.InnerException, methodCallMessage);
- }
-
- return new ReturnMessage(retVal, methodCallMessage.Args, methodCallMessage.ArgCount, null, methodCallMessage);
- }
-
- return RemotingServices.ExecuteMessage(_sink, methodCallMessage);
- }
-
- #endregion
- }
- }
-
- #endif