如何从运行时可调用包装类的 CLSID 获取其 System.Type?

2024-01-17

Note:有关背景信息,请参阅此相关问题:如何获取 LINQPad 到 Dump() System.__ComObject 引用? https://stackoverflow.com/q/14716871/386205

我能够检索与 COM 对象对应的 RCW 类的 CLSID(从另一个 COM 对象获得,not由我的代码初始化)使用IPersist.GetClassID() http://msdn.microsoft.com/en-us/library/windows/desktop/ms688664%28v=vs.85%29.aspx.

Type.GetTypeFromCLSID() http://msdn.microsoft.com/en-us/library/980t1w1t%28v=vs.100%29.aspx总是返回弱类型System.__ComObject, not强类型 RCW 类。

我需要得到System.Type http://msdn.microsoft.com/en-us/library/42892f65%28v=vs.100%29.aspx强类型 RCW 类能够使用它包装 COM 对象Marshal.CreateWrapperOfType() http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.createwrapperoftype%28v=vs.100%29.aspx.

这是可能的还是由于 COM 互操作的工作原理而无法启动?


好吧,这就是我最终作为概念证明而整理出来的内容,实际上只是一些扩展方法。这依赖于 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(我的原问题 https://stackoverflow.com/q/14716871/386205).

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何从运行时可调用包装类的 CLSID 获取其 System.Type? 的相关文章

随机推荐