Note: For background information please see this related question: How to get LINQPad to Dump() System.__ComObject references?
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()
always returns the weakly-typed System.__ComObject
, not the strongly-typed RCW class.
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()
.
Is this possible or is this a non-starter due to how COM interop works?
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).