如何从它的CLSID运行时可调用包装类的System.Type? [英] How to get the System.Type of a Runtime Callable Wrapper class from its CLSID?
问题描述
注意:有关背景信息,请参阅此相关的问题:如何获得LINQPad转储()系统.__ ComObject引用?
Note: For background information please see this related question: How to get LINQPad to Dump() System.__ComObject references?
我能够检索对应于一个COM对象的RCW类的CLSID(从另一个COM对象获得的不的使用的 IPersist.GetClassID()
I am able to retrieve the CLSID of the RCW class corresponding to a COM object (obtained from another COM object, not initialized by my code) using IPersist.GetClassID()
.
的 Type.GetTypeFromCLSID()
一>总是返回弱类型系统.__ ComObject
的不的强类型RCW类。
Type.GetTypeFromCLSID()
always returns the weakly-typed System.__ComObject
, not the strongly-typed RCW class.
我需要得到 的System.Type
强类型的RCW类能够与使用的 Marshal.CreateWrapperOfType()
。
I need to get the System.Type
of the strongly-typed RCW class to be able to wrap the COM object with it using Marshal.CreateWrapperOfType()
.
这是可能的,或者这是一个非首发因如何COM互操作工作的?
Is this possible or is this a non-starter due to how COM interop works?
推荐答案
那么这里是我最后决定将一起作为概念的证明,只是一个扩展方法屈指可数,真的。这在当前的AppDomain
加载PIA的一个依靠实施的IPersist
有一个RCW类的COM对象和。
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);
}
}
}
用于这样的:
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
这是所需结果。现在,让这个发挥好与LINQPad(我的原来的问题)。
Which was the desired result. Now to make this play nice with LINQPad (my original question).
这篇关于如何从它的CLSID运行时可调用包装类的System.Type?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!