4

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

可以使用IPersist.GetClassID().

Type.GetTypeFromCLSID()总是返回弱类型System.__ComObject而不是强类型 RCW 类。

我需要获取System.Type强类型 RCW 类的 ,以便能够使用它来包装 COM 对象Marshal.CreateWrapperOfType()

由于 COM 互操作的工作方式,这是可能的还是无法启动?

4

2 回答 2

2

好吧,这就是我最终作为概念证明而汇总的内容,实际上只是少数扩展方法。这依赖于 COM 对象实现IPersist并在当前加载的 PIA 中具有 RCW 类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);

我得到以下输出:

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

这是预期的结果。现在让 LINQPad 玩得更好(我原来的问题)。

于 2013-02-08T03:32:23.577 回答
1

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

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

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

于 2013-02-07T20:44:08.783 回答