Table of Contents

The SWinTypeLibs package
Functions/Methods
COMIDispatch objects
Future Work/"To do"
Bibliography

The SWinTypeLibs package

This package allows R users to explore type information coming from either type libraries or COM objects. The functions provide information about a class in terms of its properties; methods and their argument and return types; the names and values of enumerated types, and fields in structures and unions. One can find type information by loading a type library or by obtaining a reference to a COM object. Suppose we have the ADO (ActiveX Data Object) library on our system at it is located at C:/Program Files/Common Files/system/ado/msado15.dll. (On your machine, it may be named and located differently or simply not present at all.) We load that library using LoadTypeLib()
lib = LoadTypeLib("C:/Program Files/Common Files/system/ado/msado15.dll")
The resulting lib is a reference or handle to the C-level structure that identifies the object. We can use this to examine the different elements about which the library provides type information. When we are finished with it, we can release the library and free the resources it uses using UnloadTypeLib() .

(Not implemented yet.)

Essentially we can treat the type library as a named list. Each element is an object of type ITypeInfo in our world. This provides a reference to the elemenet in the type library and from that we can find out most things about that type.

Since the library reference is equivalent to a list in S, we can find out the names of the different elements it contains using
names(lib)
As one might expect, we can extract elements from the type library in the S style using the usual list subsetting operators:
 lib[[1]]  # Single element.
 lib[1:4]  # Returns a list, not a sub-ITypeLib

 lib[["CursorTypeEnum"]] # By type name 
 lib[[names(lib)[1]]]    # Same thing.
 lib$CursorTypeEnum      # Same thing.

Now that we know how to navigate the elements of the type library, we can examine its elements. We can also find out the types of these different elements in the library using \SFunction{getTypeLibTypes}.
getTypeLibTypes(lib)
This describes the type of each element in the library by its type name such as dispatch, coclass, enum, interface, alias, module, union, record/structure. These are indexed by the names of the type. If one wants to get the actual numeric type rather than the text descriptions (so that they can be used within the C code), use the byName argument and specify FALSE.

This information is convenient for being able to get a big picture view of what the type library contains. We can see what are enumerated constants, what are types with methods (dispatch), and so on. We can identify the elements that might be of interest based on their name and/or type. We can then ``zoom in'' and look at the type information for individual elements of the type library. We get a reference to the underlying C <c:struct>ITypeInfo</c:struct> object using the overloaded [[ we discussed above. One can index the type library reference either by the name or position of the desired element.
cmd = lib[["Command"]]
or
cmd = lib[[91]]
We can then get the details of the type of this element using this R object. For example, we can find the collection of values in the enumeration <com:type>BookMarkEnum</com:type>.
getEnum(cmd)
Suppose we wanted to find all the enumerations within a library and obtain their definitions as a name-value vector for each enum type. We can do this in two steps
types = getTypeLibTypes(lib)
enums = which(types == "enum")

lapply(enums, function(x) getEnum(lib[[x]]))
If an element in the type library is a coclass type info object, then it can represent multiple interfaces. We get a list of the ITypeInfo objects for each of these interfaces by calling getElements() . We can the operate on each of these ITypeInfo elements as we do above. The getElements() function has a recursive argument.

Functions/Methods

An IDispatch type (or type "dispatch") is a class that contains methods that one can invoke dynamically. The type library provides a description of each of these methods. Let's consider the Excel class Workbooks. We load the Excel type library, e.g.
 lib = LoadTypeLib("c:/Micrsoft Office/OFFICE11/Excel.exe") 
or referencing the appropriate file. To get the Workbooks class, we use the command
 workbooks = lib[["Workbooks"]]
. This is an object of class ITypeInfoDispatch indicating that it is indeed describing an IDispatch class. So from this we can directly get the list of functions defined by that particular IDispatch class:
 funs = getFuncs(workbooks) 
This is a regular list in R. The names of the elements are the names of the functions/operations.
 
 names(funs)
The first seven entries are common to all IDispatch objects. These provide ways to query the object and dynamically invoking methods and accessing properties. The remaining elements are more interesting from the user's perspective. These tell us what we can do with this class of object.

Some of the names have a curious _ and __ in front of them. For instance, we have an OpenText, _OpenText and __OpenText entries! If we look at the number of parameters in each function, we get
sapply(funcs[grep("OpenText", names(funcs))],
        function(x) length(x@parameters))

__OpenText _OpenText  OpenText
      14      16       18
The _ and __ suggest somehow that these are not necessarily part of the user-level interface. They are somehow being obfuscated or obscured. Indeed, if we look at the hidden field of each of these function descriptions, we see that the first two are indeed hidden.
sapply(funcs[grep("OpenText", names(funcs))],
          function(x) x@hidden

THIS IS INCORRECT. Everything seems to be hidden,i.e. every function in every type.

. Let's look at the Open method.
 open = funcs$Open
This is an instance of the FunctionInvokeDescription. We can find out more about this class using
getSlots(class(open))
We see that we have all of the essential ingredients of a function, and a few more. The name, the return type, the list of parameters are all of the things we need to make sense of the function so that we can invoke it. The invokeType, hidden and memid (and kind) values are internal information that help in actually implementing the call. . The invokeType tells us whether we are dealing with getting or setting a property (propertyget or propertyput or propertyref) or invoking a method (func). These different types of methods are identified by different classes of object in R. We have FunctionInvokeDescription, PropertyGetDescription, PropertySetDescription, PropertySetRefDescription. Accessors that are hidden should not be invoked. .

COMIDispatch objects

If we have a COM object, we might want to find out about its available methods. For example, if we are not certain what we have, we may want to get its type to determine what we can do with it. Or we may want to explicitly generate an interface to all the functions for that object. We can use many of the functions we discussed earlier with a COMIDispatch object. For instance, we can ask for the ITypeInfo for the COMIDispatch object using
getTypeInfo(obj)
Similarly, we can get the ITypeLib from the object using
getTypeLib
. We can also call getFuncs() on the object to get the collection of functions.

Future Work/"To do"

  • Record classes
  • Check the number of names of the parameters is what we expect and not one less for PROPERTY_PUT methods.

Bibliography

See http://archive.devx.com/upload/free/features/vcdj/2000/03mar00/fg0300/fg0300.asp for an article describing aspects of type libraries. Gone now (June '05) http://www.geocities.com/cool_ranju/tlibs.html