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).
Dictionary<Guid, Type>
, and provide the type from this dictionary when you have the guid. – EyeleenSystem.__ComObject
:p This may not be workable given how large the object libraries I'm working with are. – Disreputable