How to get the System.Type of a Runtime Callable Wrapper class from its CLSID?

你。 提交于 2019-12-05 15:11:30
blah238

Well here is what I ended up putting together as a proof of concept, just a handful of extension methods, really. This relies on the COM object implementing IPersist and having an RCW class in one of the PIAs loaded in the current 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);
        }
    }
}

Used like this:

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

I get the following output:

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

Which was the desired result. Now to make this play nice with LINQPad (my original question).

Type.GetTypeFromCLSID() just returns a dynamic COM wrapper.

Strongly-typed RCW must be defined in the .NET space. It must be classes that are decorated with the ComImportAttribute. .NET can't create these classes automatically ex-hihilo. They are defined manually (in .NET code), or by PIAs, or by tlbimp, or by Reflection Emit mechanism for example, like all .NET types. There is no preset relation between a COM CLSID and .NET corresponding classes for the reason there may be multiple .NET classes corresponding to the same CLSID.

If you have these types available, what you could do is scan a defined set of namespaces and build a Dictionary<Guid, Type> from it for example.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!