RunTime COM Object Inspection





4.00/5 (4 votes)
Oct 10, 2003
3 min read

72922

2223
How to inspect COM object contents at runtime.
Introduction
Probably, everyone knows how it is delightful to create a watch for an object, inspecting its properties and so on.. Anyway, you've probably noticed that VB forgets among different sessions what you were watching, so the obvious idea is to build up a custom debug form which shows what you need. But there is a problem, which is that you can inspect easily default types, but for COM objects it's a completely different matter. My small and stupid control takes care of this thing, as it lets you to inspect all run-time properties of a generic COM object using a TreeView
control.
Using the code
The usage is quite simple:
- You create a form
- You add an
ObjView
control to the form - You start your program,
- While running, you can:
- Add an object to inspection through the
Add
method of the control. Note that you need to provide a string which will identify your object in a unique way. - Remove an object from the inspection using the
Remove
method. - Refresh the values of all the objects under inspection through the
Refresh
method. - Refresh a single object through the
RefreshOBJ
method, which requires as a first parameter a reference to the object, and as a second, the identifier of the object which you gave to the control when adding the object itself.
- Add an object to inspection through the
All the inspection stuff is done using the TypeLib Information library (tlbinf32.dll), which exposes various classes and methods. Note that a VB COM object cannot expose more than an interface for each class (or at least I did not find any object which does this thing), the idea is simple:
- Get the Interface descriptor of the given object
Dim tliApp as TLI.TLIApplication Dim tliIrf as TLI.InterfaceInfo Set tliApp = new TLI.TLIApplication Set tliIrf = tliApp.InterfaceInfoFromObject(< object variable > )
- Examine the
Members
collection of thetliIrf
variable, which contains all the public members exposed from the classDim tliMI as TLI.MemberInfo For Each tliMi In tliIrf.Members ... Next
Each
MemberInfo
class contains data which refers to the public members (functions, subs, variables, properties ...) of the selected interface. The relevant fields are:Name:
it is the name of the member, which is used to retrieve the value.Parameters:
it is a collection ofParameterInfo
which contains info about the parameters of the selected method.InvokeKind:
it is an enumerated typeInvokeKinds
which tells what kind of member is it.ReturnType:
it is aVarTypeInfo
class which contains info about the returned type
- As I wanted to create a debug-like object, I did the following assumptions:
- If it is a collection, or an object which implements a collection, analyze each item. To discover if it a collection, the control uses the following procedure:
Private Function IsCollection(v As Variant) As Boolean Dim tlApp As TLI.TLIApplication Dim tlIrf As TLI.InterfaceInfo Dim tlmi As TLI.MemberInfo Dim Obj As Object If IsObject(v) Then If TypeName(v) = "Collection" Then IsCollection = True End If Set Obj = v Set tlApp = New TLI.TLIApplication Set tlIrf = tlApp.InterfaceInfoFromObject(Obj) For Each tlmi In tlIrf.Members If LCase$(tlmi.Name) = "item" Then IsCollection = True Exit For End If Next End If Set tlmi = Nothing Set tlIrf = Nothing Set tlApp = Nothing End Function
So, if the object does not have an
Item
method, it will not be recognized as a collection, which is coherent with the VB behavior. - If it is not a collection, every member is parsed using the following tables:
InvokeKind
: if it is not aGet
(INVOKE_PROPERTYGET
), discard it.- If it has 1 parameter or more, discard it.
- As regards the return type:
- It uses the
CallByName
statement to get the current value of the selected member. - If it is an object, it will recurse over this object.
- If not, it will display a string Member Name = Member Value
- It uses the
- If it is a collection, or an object which implements a collection, analyze each item. To discover if it a collection, the control uses the following procedure:
Points of interest
An interesting point is how the TypeInfo library manages enumerated types. It does not treat them as long, but instead it fills the TypeInfo.Members
collection of the ReturnType
member with as much items as the enumerated type has, so each item is a TypeInfo
with:
Value
the numeric value of the enumeration item.Name
the symbolic name associated to it.
So, using a For ... Each
control block, it's easy to find the symbolic name which represents a given numeric value, which usually is also better understood by the developer.
History
- 12/10/2003: First version released to the public.