How does Visual Studio's debugger/interactive window dump the properties of COM Objects in .NET?
Asked Answered
D

1

10

In this related question, I noted that Visual Studio's debugger is able to enumerate the properties of System.__ComObject references, which is "a hidden type used when the wrapper type is ambiguous" -- e.g., the type of object you get when you obtain it from another COM object and don't instantiate it yourself:

COM Object Debug View

Additionally, if you simply write a COM object's identifier into the Immediate Window, its properties and values are similarly dumped:

COM Object Immediate Window

Note that this is separate from VS2010's "Dynamic View", which I believe uses IDispatch and COM reflection to enumerate the properties of COM objects without the use of PIAs and .NET reflection. The objects I am working with do not implement IDispatch (nor do they implement IProvideClassInfo for that matter), and as such, "Dynamic View" is not able to obtain any information about them:

Dynamic View

Interestingly, SharpDevelop's debugger is not able to list the members of System.__Comobjects (e.g. point.Envelope), only strongly-typed RCWs (e.g. point).

SharpDevelop debugger

So how is Visual Studio able to do it?

I believe in this case, it is because Primary Interop Assemblies exist with definitions for the interfaces supported by these objects, and Visual Studio is likely using reflection to enumerate the supported interfaces and properties. Is that accurate? And if so, how does it work?

For starters, how does it access the PIAs? Does it only look at currently loaded PIAs or does it dynamically load them (and if so, how)? How does it determine which interface, of which there can be many, to enumerate the properties of? It only seems to use one, and not necessarily the first. From the documentation of the API I'm working with (ArcObjects), the default interface for these objects is IUnknown, so it's not just using the default interface either.

In the example in the screenshots, the interface it is enumerating the members of is the IEnvelope interface, which inherits from the IGeometry interface. How does VS2010 know not to enumerate the members of IGeometry instead, which, in my testing, appears first if you just enumerate all the interface types in the PIA? Something very clever going on or perhaps I am missing something obvious?

The reason I'm asking is that the developer of LINQPad appears willing to implement the same functionality if he knew how VS does it. So a good answer here could go a long ways to helping improve that very popular tool.

Deleterious answered 10/2, 2013 at 13:20 Comment(3)
Since the type of the Envelope property of the Point class is defined in the PIA as IEnvelope, VS is capable of dumping it, there's no need for a special mechanism.Peru
Hmm is it really that simple? Is this information only available at debug time? (How) can the same information be obtained at runtime? And why doesn't SharpDevelop's debugger do the same (perhaps they just don't care to).Deleterious
Yes it's very simple. It's more complicated when you only have System._ComObject, but when you can cast them as ComImport .NET interfaces, then you have access to these interfaces layout. It's available all time, including intellisense. I don't know about SharpDevelop.Peru
B
2

This is how to do it:

  • obtain COM object's IDispatch (alternative possible path is IDispatchEx)
  • obtain a reference to type library -- IDispatch::GetTypeInfo
  • load type library and enumerate properties
  • query real object for values for discovered properties

Additional enhancement oipions apply: query IPersist* family of interfaces or IProvideClassInfo to alternatively obtain a reference to typelibrary for the object and discover properties.

Benioff answered 10/2, 2013 at 13:49 Comment(7)
As I wrote, none of those interfaces are implemented by these objects. Actually some of them implement IPersist but not all. I'll have to check to see which ones do and don't and compare that with what VS2010 is able to find out about them.Deleterious
IDispatchEx, IProvideClassInfo2 (well, this one is the typical, not IProvideClassInfo) - there should be somethingBenioff
Nope, neither of those as well.Deleterious
Ahh, it must be IPersist. I tried with a different object that does not implement IPersist and VS shows nothing about it in debug view.Deleterious
I would say you are missing something here, and there is much less magic around obtaining type library reference. point.Envelope alone looks like type library enabled call, and as such its result should already have type info reference embedded into __ComObject.Benioff
I mistakenly had "embed interop types" checked for the assembly reference of the different object. After unchecking that, VS does show its members, even though it does not implement IPersist.Deleterious
Unfortunately I am nowhere nearer to understanding how VS is working its magic. You say it's because it's a type library enabled call, and that there should be type information embedded into __ComObject, but as far as I can tell there is not (envelope.GetType() just returns System.__ComObject). How can I enumerate the members like VS is doing?Deleterious

© 2022 - 2024 — McMap. All rights reserved.