如何从其CLSID获取Runtime Callable Wrapper类的System.Type?

时间:2013-02-07 17:06:17

标签: c# com com-interop rcw

注意:有关背景信息,请参阅此相关问题:How to get LINQPad to Dump() System.__ComObject references?

我能够使用IPersist.GetClassID()检索与COM对象(从另一个COM对象获取,不是,由我的代码初始化)对应的RCW类的CLSID。

Type.GetTypeFromCLSID()始终返回弱类型的System.__ComObject强类型的RCW类。

我需要获得强类型RCW类的System.Type才能使用Marshal.CreateWrapperOfType()将COM对象包装起来。

这是可能的还是由于COM互操作的工作方式,这是不起作用的?

2 个答案:

答案 0 :(得分:2)

这就是我最终把它作为一个概念证明,只是少数几种扩展方法。这依赖于实现IPersist的COM对象,并且在当前AppDomain中加载的一个PIA中具有RCW类。

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);

我得到以下输出:

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

这是理想的结果。现在,使用LINQPad(我的original question)来使这个游戏更好。

答案 1 :(得分:1)

Type.GetTypeFromCLSID()只返回一个动态COM包装器。

必须在.NET空间中定义强类型RCW。它必须是用ComImportAttribute修饰的类。 .NET无法自动创建这些类ex-hihilo。它们是手动定义的(在.NET代码中),或者由PIA定义,或者由tlbimp定义,或者通过Reflection Emit机制定义,例如所有.NET类型。 COM CLSID和.NET对应类之间没有预设关系,原因可能是多个.NET类对应于同一个CLSID。

如果您有这些类型可用,您可以做的是扫描一组已定义的命名空间并从中构建Dictionary<Guid, Type>