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

标签 c# com com-interop rcw

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

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

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

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

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

最佳答案

这就是我最终作为概念证明放在一起的东西,实际上只是一些扩展方法。这依赖于 COM 对象实现 IPersist 并在当前 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)让这个发挥得很好。

关于c# - 如何从其 CLSID 获取运行时可调用包装类的 System.Type?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14756823/

相关文章:

windows - 在同一台机器上创建对象时 CoCreateInstance() 和 CoGetClassObject() 有什么区别?

.net - Excel Interop 在禁用宏的情况下打开 Excel

c# - 在 Visual Studio 2013 中运行单元测试时运行其他项目

c# - 在 ASP.net 网页中嵌入 Windows 窗体

c# - 无法进行传出调用,因为应用程序正在调度输入同步调用

delphi - 需要读取所有出现的 Recurring Outlook Appt

c++ - COM 方法调用在传递 BSTR 时返回灾难性故障

c# - EPPlus 设置整个工作表的背景颜色

c# - 从表中获取 auto_increment id

installation - 回滚时在WIX中注销COM组件,有必要吗?