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

C# 如何从CLSID获取运行时可调用包装类的System.Type?,c#,com,com-interop,rcw,C#,Com,Com Interop,Rcw,注意:有关背景信息,请参阅此相关问题: 我能够使用检索对应于COM对象的RCW类的CLSID(从另一个COM对象获得,不是由我的代码初始化的) 始终返回弱类型的系统。uu ComObject,而不是强类型的RCW类 我需要获得强类型RCW类的名称,以便能够使用包装COM对象 这是可能的,还是由于COM互操作的工作方式而无法启动?Type.GetTypeFromCLSID()只返回一个动态COM包装器 强类型RCW必须在.NET空间中定义。必须是用..装饰的类。NET无法在hihilo之外自动创建

注意:有关背景信息,请参阅此相关问题:

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

始终返回弱类型的
系统。uu ComObject
,而不是强类型的RCW类

我需要获得强类型RCW类的名称,以便能够使用包装COM对象


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

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

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


如果您有这些类型可用,您可以做的是扫描一组已定义的名称空间,然后从中构建一个
字典。

好的,这里是我最后总结的概念证明,实际上只是一些扩展方法。这依赖于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);
        }
    }
}
我得到以下输出:

ESRI.ArcGIS.Geometry.PointClass System.__ComObject ESRI.ArcGIS.Geometry.EnvelopeClass ESRI.ArcGIS.Geometry.PointClass 系统。共对象 ESRI.ArcGIS.Geometry.EnveloperClass
这是理想的结果。现在,为了更好地使用LINQPad(my)。

传递给CreateWrapperOfType的第二个参数需要在.NET空间中定义(使用ComImport属性等),因此如果不以某种方式定义此类型(使用C代码、tlbimp或反射发射),它将无法工作。我定义了带有RCW的PIA(有关更多信息,请参阅相关问题)。是的,这并没有改变答案:-)提供类型仍然是您的工作,因为在.NET空间中可以有无限多个类型来定义相应的COM对象。因此,如果您有PIA,您可以浏览PIA名称空间中的所有类(例如使用反射),构建一个
字典
,并在您有guid时提供此字典中的类型。我也这么认为,这是我在认为有更好的方法之前就开始研究的。GetTypeFromCLSID函数激发了我的希望,当我读到它总是返回
系统时,它就把希望抛在了脑后。\uu ComObject
:p考虑到我正在使用的对象库有多大,这可能不可行。这个问题看起来很相关:我只是想说这很有用,谢谢。我认为在我的例子中,CLSID保证唯一地绑定到特定的强类型RCW——但我首先只能在COM对象实现
IPersist
的情况下获得CLSID(我正在使用的库中有相当一部分是这样的,否则我不会麻烦)。不过,如果有一个预定义的机制就好了。您还可以检查COM对象是否实现了IProvideClassInfo:。从那里你可以得到一个ITypeInfo,从那里你可以得到类型GUID:,但是你必须在你的代码中定义所有这些接口:-)是的,不幸的是没有一个实现IProvideClassInfo,只有少数实现IDispatch。我从哪里得到IPersist定义? ESRI.ArcGIS.Geometry.PointClass System.__ComObject ESRI.ArcGIS.Geometry.EnvelopeClass