Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

RunTime COM Object Inspection

0.00/5 (No votes)
9 Oct 2003 1  
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.

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:

  1. 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 > )
  2. Examine the Members collection of the tliIrf variable, which contains all the public members exposed from the class
    Dim 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 of ParameterInfo which contains info about the parameters of the selected method.
    • InvokeKind: it is an enumerated type InvokeKinds which tells what kind of member is it.
    • ReturnType: it is a VarTypeInfo class which contains info about the returned type
  3. 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 a Get (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

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here