InternalDispatchObject.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / MS / Internal / Interop / InternalDispatchObject.cs / 1305600 / InternalDispatchObject.cs

                            //------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// Description:
//      InternalDispatchObject facilitates implementing a COM dispinterface using a non-public 
//      corresponding managed interface definition (of type ComInterfaceType.InterfaceIsIDispatch). 
//      (For example, we use this to implement DWebBrowserEvents2 without making it a public interface
//      type in the framework.) 
//
//      If a public managed interface definition is available, CLR's built-in implementation of
//      IDispatch suffices. It maps IDispatch calls to Reflection calls. But reflecting on non-public
//      members causes a demand for ReflectionPermission/MemberAccess against the caller of the 
//      Reflection API. In a partial-trust AppDomain, and oddly only with some particular transitions
//      between managed-native-managed stack frames, this demand fails. Given that this occurs with 
//      substantially equivalent callstacks in terms of CAS (Asserts) and managed<->native transitions, 
//      there is probably an obscure CLR bug somewhere at the intersection of its IDispatch
//      implementation, Reflection and CAS. And there seems to be no explicit suggestion in 
//      documentation that this scenario is supported in the first place.
//
//      By implementing IReflect, any object can provide its own reflection implementation. And it
//      turns out CLR's IDispatch "front end" will happily use such an implementation. We don't need 
//      to explicitly assert any ReflectionPermission in this arrangement as long as we are targeting
//      an internally visible interface type. (The built-in reflection system performs the equivalent 
//      of a LinkDemand against the caller of the reflection API.) This, however, creates a potentially 
//      dangerous security situation.
// 
//      CAUTION!!! Do not expose any InternalDispatchObject-derived object instance to untrusted code,
//          unless the implementation of the dispinterface is entirely safe. Such objects should be
//          passed only to native code, to be invoked via IDispatch.
// 
//          Because IReflect is a public interface and has no (link)demands on it and because
//          InternalDispatchObject's internal invocation of relection satisfies the reflection system's 
//          ReflectionPermission demand, the implementaiton of the given dispinterface effectively 
//          becomes publicly accessible. (Putting a LinkDemand on InternalDispatchObject.InvokeMember()
//          would have no effect because it can be called via IReflect, and LinkDemands are evaluated 
//          based on static type info. And putting a full Demand would defeat the whole purpose of
//          InternalDispatchObject.)
//
// History 
//      04/30/08 - [....] - Created
// 
//----------------------------------------------------------------------------- 

using System; 
using System.Security;
using System.Reflection;
using System.Collections.Generic;
using System.Runtime.InteropServices; 
using System.Globalization;
 
namespace MS.Internal.Interop 
{
 
/// 
/// InternalDispatchObject-derived objects are potentially unsafe to expose to untrusted code.
/// The IDispInterface implementation members should be treated as publicly accessible.
///  
internal abstract class InternalDispatchObject : IReflect
{ 
    ///  
    /// DISPID->MethodInfo map used by InvokeMember()
    ///  
    private Dictionary _dispId2MethodMap;

    /// 
    /// Critical - to help ensure whoever creates an instance of this class doesn't expose it. 
    /// 
    [SecurityCritical] 
    protected InternalDispatchObject() 
    {
        // Populate _dispId2MethodMap with the MethodInfos for the interface, keyed by DISPID. 
        // There is no support for properties (yet).
        MethodInfo[] methods = typeof(IDispInterface).GetMethods();
        _dispId2MethodMap = new Dictionary(methods.Length);
        foreach (MethodInfo method in methods) 
        {
            int dispid = ((DispIdAttribute[])method.GetCustomAttributes(typeof(DispIdAttribute), false))[0].Value; 
            _dispId2MethodMap[dispid] = method; 
        }
    } 

    FieldInfo IReflect.GetField(string name, BindingFlags bindingAttr)
    {
        throw new NotImplementedException(); 
    }
    FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr) 
    { 
        return null;
    } 
    MemberInfo[] IReflect.GetMember(string name, BindingFlags bindingAttr)
    {
        throw new NotImplementedException();
    } 
    MemberInfo[] IReflect.GetMembers(BindingFlags bindingAttr)
    { 
        throw new NotImplementedException(); 
    }
    MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr) 
    {
        throw new NotImplementedException();
    }
    MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers) 
    {
        throw new NotImplementedException(); 
    } 
    MethodInfo[] IReflect.GetMethods(BindingFlags bindingAttr)
    { 
        // It doesn't help to return typeof(IDispInterface).GetMethods(), because the CLR's IDispatch layer
        // ignores non-visible MethodInfos (DispatchInfo::SynchWithManagedView(), in clr\src\VM\DispatchInfo.cpp).
        // For all "unknown" DISPIDs, IReflect.InvokeMember() is passed a method name like "[DISPID=]",
        // which we parse. 
        return null;
    } 
    PropertyInfo[] IReflect.GetProperties(BindingFlags bindingAttr) 
    {
        return null; 
    }
    PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers)
    {
        throw new NotImplementedException(); 
    }
    PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr) 
    { 
        throw new NotImplementedException();
    } 

    /// 
    /// Critical: Performs Reflection against a non-public type.
    /// NOT PublicOK! This method is intrinsically unsafe. Because it can be called via the public IReflect, 
    ///     instances of this class should not be exposed to untrusted code. (Full explanation above.)
    ///  
    [SecurityCritical] 
    object IReflect.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, System.Globalization.CultureInfo culture, string[] namedParameters)
    { 
        // We never expect to get a real method name here--see the explanation in GetMethods().
        if (name.StartsWith("[DISPID=", StringComparison.OrdinalIgnoreCase))
        {
            int dispid = int.Parse(name.Substring(8, name.Length-9), CultureInfo.InvariantCulture); 
            MethodInfo method;
            if (_dispId2MethodMap.TryGetValue(dispid, out method)) 
            { 
                return method.Invoke(this, invokeAttr, binder, args, culture);
            } 
        }
        // This exception can be thrown if IDispInterface doesn't declare a method with a particular DISPID,
        // but the real COM interface has it and the event source is trying to invoke it. For a call coming via
        // the native IDispatch, such an error is usually ignorable. 
        throw new MissingMethodException(GetType().Name, name);
        //return typeof(IDispInterface).InvokeMember(name, invokeAttr, binder, this, args, modifiers, culture, namedParameters); 
    } 

    Type IReflect.UnderlyingSystemType 
    {
        get { return typeof(IDispInterface); }
    }
}; 

}//namespace 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// Description:
//      InternalDispatchObject facilitates implementing a COM dispinterface using a non-public 
//      corresponding managed interface definition (of type ComInterfaceType.InterfaceIsIDispatch). 
//      (For example, we use this to implement DWebBrowserEvents2 without making it a public interface
//      type in the framework.) 
//
//      If a public managed interface definition is available, CLR's built-in implementation of
//      IDispatch suffices. It maps IDispatch calls to Reflection calls. But reflecting on non-public
//      members causes a demand for ReflectionPermission/MemberAccess against the caller of the 
//      Reflection API. In a partial-trust AppDomain, and oddly only with some particular transitions
//      between managed-native-managed stack frames, this demand fails. Given that this occurs with 
//      substantially equivalent callstacks in terms of CAS (Asserts) and managed<->native transitions, 
//      there is probably an obscure CLR bug somewhere at the intersection of its IDispatch
//      implementation, Reflection and CAS. And there seems to be no explicit suggestion in 
//      documentation that this scenario is supported in the first place.
//
//      By implementing IReflect, any object can provide its own reflection implementation. And it
//      turns out CLR's IDispatch "front end" will happily use such an implementation. We don't need 
//      to explicitly assert any ReflectionPermission in this arrangement as long as we are targeting
//      an internally visible interface type. (The built-in reflection system performs the equivalent 
//      of a LinkDemand against the caller of the reflection API.) This, however, creates a potentially 
//      dangerous security situation.
// 
//      CAUTION!!! Do not expose any InternalDispatchObject-derived object instance to untrusted code,
//          unless the implementation of the dispinterface is entirely safe. Such objects should be
//          passed only to native code, to be invoked via IDispatch.
// 
//          Because IReflect is a public interface and has no (link)demands on it and because
//          InternalDispatchObject's internal invocation of relection satisfies the reflection system's 
//          ReflectionPermission demand, the implementaiton of the given dispinterface effectively 
//          becomes publicly accessible. (Putting a LinkDemand on InternalDispatchObject.InvokeMember()
//          would have no effect because it can be called via IReflect, and LinkDemands are evaluated 
//          based on static type info. And putting a full Demand would defeat the whole purpose of
//          InternalDispatchObject.)
//
// History 
//      04/30/08 - [....] - Created
// 
//----------------------------------------------------------------------------- 

using System; 
using System.Security;
using System.Reflection;
using System.Collections.Generic;
using System.Runtime.InteropServices; 
using System.Globalization;
 
namespace MS.Internal.Interop 
{
 
/// 
/// InternalDispatchObject-derived objects are potentially unsafe to expose to untrusted code.
/// The IDispInterface implementation members should be treated as publicly accessible.
///  
internal abstract class InternalDispatchObject : IReflect
{ 
    ///  
    /// DISPID->MethodInfo map used by InvokeMember()
    ///  
    private Dictionary _dispId2MethodMap;

    /// 
    /// Critical - to help ensure whoever creates an instance of this class doesn't expose it. 
    /// 
    [SecurityCritical] 
    protected InternalDispatchObject() 
    {
        // Populate _dispId2MethodMap with the MethodInfos for the interface, keyed by DISPID. 
        // There is no support for properties (yet).
        MethodInfo[] methods = typeof(IDispInterface).GetMethods();
        _dispId2MethodMap = new Dictionary(methods.Length);
        foreach (MethodInfo method in methods) 
        {
            int dispid = ((DispIdAttribute[])method.GetCustomAttributes(typeof(DispIdAttribute), false))[0].Value; 
            _dispId2MethodMap[dispid] = method; 
        }
    } 

    FieldInfo IReflect.GetField(string name, BindingFlags bindingAttr)
    {
        throw new NotImplementedException(); 
    }
    FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr) 
    { 
        return null;
    } 
    MemberInfo[] IReflect.GetMember(string name, BindingFlags bindingAttr)
    {
        throw new NotImplementedException();
    } 
    MemberInfo[] IReflect.GetMembers(BindingFlags bindingAttr)
    { 
        throw new NotImplementedException(); 
    }
    MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr) 
    {
        throw new NotImplementedException();
    }
    MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers) 
    {
        throw new NotImplementedException(); 
    } 
    MethodInfo[] IReflect.GetMethods(BindingFlags bindingAttr)
    { 
        // It doesn't help to return typeof(IDispInterface).GetMethods(), because the CLR's IDispatch layer
        // ignores non-visible MethodInfos (DispatchInfo::SynchWithManagedView(), in clr\src\VM\DispatchInfo.cpp).
        // For all "unknown" DISPIDs, IReflect.InvokeMember() is passed a method name like "[DISPID=]",
        // which we parse. 
        return null;
    } 
    PropertyInfo[] IReflect.GetProperties(BindingFlags bindingAttr) 
    {
        return null; 
    }
    PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers)
    {
        throw new NotImplementedException(); 
    }
    PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr) 
    { 
        throw new NotImplementedException();
    } 

    /// 
    /// Critical: Performs Reflection against a non-public type.
    /// NOT PublicOK! This method is intrinsically unsafe. Because it can be called via the public IReflect, 
    ///     instances of this class should not be exposed to untrusted code. (Full explanation above.)
    ///  
    [SecurityCritical] 
    object IReflect.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, System.Globalization.CultureInfo culture, string[] namedParameters)
    { 
        // We never expect to get a real method name here--see the explanation in GetMethods().
        if (name.StartsWith("[DISPID=", StringComparison.OrdinalIgnoreCase))
        {
            int dispid = int.Parse(name.Substring(8, name.Length-9), CultureInfo.InvariantCulture); 
            MethodInfo method;
            if (_dispId2MethodMap.TryGetValue(dispid, out method)) 
            { 
                return method.Invoke(this, invokeAttr, binder, args, culture);
            } 
        }
        // This exception can be thrown if IDispInterface doesn't declare a method with a particular DISPID,
        // but the real COM interface has it and the event source is trying to invoke it. For a call coming via
        // the native IDispatch, such an error is usually ignorable. 
        throw new MissingMethodException(GetType().Name, name);
        //return typeof(IDispInterface).InvokeMember(name, invokeAttr, binder, this, args, modifiers, culture, namedParameters); 
    } 

    Type IReflect.UnderlyingSystemType 
    {
        get { return typeof(IDispInterface); }
    }
}; 

}//namespace 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK