如何从它的CLSID运行时可调用包装类的System.Type? [英] How to get the System.Type of a Runtime Callable Wrapper class from its CLSID?

查看:173
本文介绍了如何从它的CLSID运行时可调用包装类的System.Type?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:有关背景信息,请参阅此相关的问题:如何获得LINQPad转储()系统.__ ComObject引用?

Note: For background information please see this related question: How to get LINQPad to Dump() System.__ComObject references?

我能够检索对应于一个COM对象的RCW类的CLSID(从另一个COM对象获得的的使用的 IPersist.GetClassID()

I am able to retrieve the CLSID of the RCW class corresponding to a COM object (obtained from another COM object, not initialized by my code) using IPersist.GetClassID().

Type.GetTypeFromCLSID() 总是返回弱类型系统.__ ComObject 的强类型RCW类。

Type.GetTypeFromCLSID() always returns the weakly-typed System.__ComObject, not the strongly-typed RCW class.

我需要得到 的System.Type 强类型的RCW类能够与使用的 Marshal.CreateWrapperOfType()

I need to get the System.Type of the strongly-typed RCW class to be able to wrap the COM object with it using Marshal.CreateWrapperOfType().

这是可能的,或者这是一个非首发因如何COM互操作工作的?

Is this possible or is this a non-starter due to how COM interop works?

推荐答案

那么这里是我最后决定将一起作为概念的证明,只是一个扩展方法屈指可数,真的。这在当前的AppDomain 加载PIA的一个依靠实施的IPersist 有一个RCW类的COM对象和。

Well here is what I ended up putting together as a proof of concept, just a handful of extension methods, really. This relies on the COM object implementing IPersist and having an RCW class in one of the PIAs loaded in the current AppDomain.

internal static class ExtensionMethods
{
    internal static object ConvertToRCW(this object o)
    {
        var guid = o.GetCLSID();
        if (guid != Guid.Empty)
        {
            return Marshal.CreateWrapperOfType(o, o.GetTypeFromGuid(guid));
        }
        else
        {
            return o;
        }
    }

    internal static Guid GetCLSID(this object o)
    {
        Guid guid = Guid.Empty;
        var p = o as IPersist;
        if (p != null)
            p.GetClassID(out guid);
        return guid;
    }

    internal static Type GetTypeFromGuid(this object o, Guid guid)
    {
        var assemblies = AppDomain.CurrentDomain.GetAssemblies();
        foreach (var assembly in assemblies)
        {
            var types = assembly.GetLoadableTypes();
            foreach (var type in types)
            {
                if (type.GUID == guid)
                    return type;
            }
        }
        return o.GetType();
    }

    internal static IEnumerable<Type> GetLoadableTypes(this Assembly assembly)
    {
        try
        {
            return assembly.GetTypes();
        }
        catch (ReflectionTypeLoadException e)
        {
            return e.Types.Where(t => t != null);
        }
    }
}

用于这样的:

var point = new ESRI.ArcGIS.Geometry.Point();
point.PutCoords(1, 1);
Console.WriteLine(point.GetType().FullName);
Console.WriteLine(point.Envelope.GetType().FullName);
Console.WriteLine(point.Envelope.ConvertToRCW().GetType().FullName);



我得到以下的输出:

I get the following output:

ESRI.ArcGIS.Geometry.PointClass
System.__ComObject
ESRI.ArcGIS.Geometry.EnvelopeClass

这是所需结果。现在,让这个发挥好与LINQPad(我的原来的问题)。

Which was the desired result. Now to make this play nice with LINQPad (my original question).

这篇关于如何从它的CLSID运行时可调用包装类的System.Type?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆