How does Visual Studio's debugger/interactive

2019-03-19 00: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:

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

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:

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

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.

回答1:

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.