Name

tcom -- Access COM objects from Tcl

Synopsis

package require tcom ?3.10?
::tcom::ref createobject ?-inproc? ?-local? ?-remote? ?-clsid? progID ?hostName?
::tcom::ref getactiveobject ?-clsid? progID
::tcom::ref getobject pathName
::tcom::ref equal handle1 handle2
handle ?-call? method ?argument ...?
handle -namedarg method ?argumentName argumentValue ...?
handle ?-get? ?-set? property ?index ...? ?value?
::tcom::foreach varname collectionHandle body
::tcom::foreach varlist collectionHandle body
::tcom::bind handle command ?eventIID?
::tcom::unbind handle
::tcom::na
::tcom::info interface handle
::tcom::configure name ?value?
::tcom::import typeLibrary ?namespace?

Description

The tcom package provides commands to access COM objects through IDispatch and IUnknown derived interfaces.

Commands

::tcom::ref createobject ?-inproc? ?-local? ?-remote? ?-clsid? progID ?hostName?
::tcom::ref getactiveobject ?-clsid? progID

These commands return a handle representing a reference to a COM object through an interface pointer. The handle can be used as a Tcl command to invoke operations on the object. In practice, you should store the handle in a Tcl variable or pass it as an argument to another command.

References to COM objects are automatically released. If you store the handle in a local variable, the reference is released when execution leaves the variable's scope. If you store the handle in a global variable, you can release the reference by unsetting the variable, setting the variable to another value, or exiting the Tcl interpreter.

The createobject subcommand creates an instance of the object. The -inproc option requests the object be created in the same process. The -local option requests the object be created in another process on the local machine. The -remote option requests the object be created on a remote machine. The progID parameter is the programmatic identifier of the object class. Use the -clsid option if you want to specify the class using a class ID instead. The hostName parameter specifies the machine where you want to create the object instance.

The getactiveobject subcommand gets a reference to an already existing object.

::tcom::ref getobject pathName

This command returns a reference to a COM object from a file. The pathName parameter is the full path and name of the file containing the object.

::tcom::ref equal handle1 handle2

This command compares the interface pointers represented by two handles for COM identity, returning 1 if the interface pointers refer to the same COM object, or 0 if not.

handle ?-call? method ?argument ...?

This command invokes a method on the object represented by the handle. The return value of the method is returned as a Tcl value. A Tcl error will be raised if the method returns a failure HRESULT code. Parameters with the [in] attribute are passed by value. For each parameter with the [out] or [in, out] attributes, pass the name of a Tcl variable as the argument. After the method returns, the variables will contain the output values. In some cases where tcom cannot get information about the object's interface, you may have to use the -call option to specify you want to invoke a method.

handle -namedarg method ? argumentName argumentValue ...?

Use the -namedarg option to invoke a method with named arguments. This only works with objects that implement IDispatch. You specify arguments by passing name and value pairs.

handle ?-get? ?-set? property ?index ...? ?value?

This command gets or sets a property of the object represented by the handle. If you supply a value argument, this command sets the named property to the value, otherwise it returns the property value. For indexed properties, you must specify one or more index values. The command raises a Tcl error if you specify an invalid property name or if you try to set a value that cannot be converted to the property's type. In some cases where tcom cannot get information about the object's interface, you may have to use the -get or -set option to specify you want to get or set a property respectively.

::tcom::foreach varname collectionHandle body
::tcom::foreach varlist collectionHandle body

This command implements a loop where the loop variable(s) take on values from a collection object represented by collectionHandle. In the simplest case, there is one loop variable, varname. The body argument is a Tcl script. For each element of the collection, the command assigns the contents of the element to varname, then calls the Tcl interpreter to execute body.

In the general case, there can be more than one loop variable. During each iteration of the loop, the variables of varlist are assigned consecutive elements from the collection. Each element is used exactly once. The total number of loop iterations is large enough to use up all the elements from the collection. On the last iteration, if the collection does not contain enough elements for each of the loop variables, empty values are used for the missing elements.

The break and continue statements may be invoked inside body, with the same effect as in the for command. The ::tcom::foreach command returns an empty string.

::tcom::bind handle command ?eventIID?

This command specifies a Tcl command that will be executed when events are received from an object. The command will be called with additional arguments: the event name and the event arguments. By default, the event interface is the default event source interface of the object's class. Use the eventIID parameter to specify the IID of another event interface. If an error occurs while executing the command then the bgerror mechanism is used to report the error.

::tcom::unbind handle

This command tears down all event connections to the object that were set up by the ::tcom::bind command.

::tcom::na

Objects that implement the IDispatch interface allow some method parameters to be optional. This command returns a token representing a missing optional argument. In practice, you would pass this token as a method argument in place of a missing optional argument.

::tcom::info interface handle

This command returns a handle representing a description of the interface exposed by the object. The handle supports the following commands.

interfaceHandle iid

This command returns an interface identifier code.

interfaceHandle methods

This command returns a list of method descriptions for methods defined in the interface. Each method description is a list. The first element is the member ID. The second element is the return type. The third element is the method name. The fourth element is a list of parameter descriptions.

interfaceHandle name

This command returns the interface's name.

interfaceHandle properties

This command returns a list of property descriptions for properties defined in the interface. Each property description is a list. The first element is the member ID. The second element is the property read/write mode. The third element is the property data type. The fourth element is the property name. If the property is an indexed property, there is a fifth element which is a list of parameter descriptions.

::tcom::configure name ?value?

This command sets and retrieves options for the package. If name is supplied but no value then the command returns the current value of the given option. If one or more pairs of name and value are supplied, the command sets each of the named options to the corresponding value; in this case the return value is an empty string.

-concurrency ?concurrencyModel?

This option sets the concurrency model, which can be apartmentthreaded or multithreaded. The default is apartmentthreaded. You must configure this option before performing any COM operations such as getting a reference to an object. After a COM operation has been done, changing this option has no effect.

Importing Type Library Information

::tcom::import typeLibrary ?namespace?

Use the ::tcom::import command to convert type information from a type library into Tcl commands to access COM classes and interfaces. The typeLibrary argument specifies a type library file. By default, the commands are defined in a namespace named after the type library, but you may specify another namespace by supplying a namespace argument. This command returns the library name stored in the type library file.

Commands

class ?-inproc? ?-local? ?-remote? ?hostName?

For each class in the type library, ::tcom::import defines a Tcl command with the same name as the class. The class command creates an object of the class and returns a handle representing an interface pointer to the object. The command accepts an optional hostName argument to specify the machine where you want to create the object. You can use the returned handle to invoke methods and access properties of the object. In practice, you should store this handle in a Tcl variable or pass it as an argument to a Tcl command.

interface handle

For each interface in the type library, ::tcom::import defines a Tcl command with the same name as the interface. The interface command queries the object represented by handle for an interface pointer to that specific interface. The command returns a handle representing the interface pointer. You can use the returned handle to invoke methods and access properties of the object. In practice, you should store this handle in a Tcl variable or pass it as an argument to a Tcl command.

Enumerations

The ::tcom::import command generates a Tcl array for each enumeration defined in the type library. The array name is the enumeration name. To get an enumerator value, use an enumerator name as an index into the array.

Tcl Value to VARIANT Mapping

Each Tcl value has two representations. A Tcl value has a string representation and also has an internal representation that can be manipulated more efficiently. For example, a Tcl list is represented as an object that holds the list's string representation as well as an array of pointers to the objects for each list element. The two representations are a cache of each other and are computed lazily. That is, each representation is only computed when necessary, is computed from the other representation, and, once computed, is saved. In addition, a change in one representation invalidates the other one. As an example, a Tcl program doing integer calculations can operate directly on a variable's internal machine integer representation without having to constantly convert between integers and strings. Only when it needs a string representing the variable's value, say to print it, will the program regenerate the string representation from the integer. The internal representations built into Tcl include boolean, integer and floating point types.

When invoking COM object methods, tcom tries to convert each Tcl argument to the parameter type specified by the method interface. For example, if a method accepts an int parameter, tcom tries to convert the argument to that type. If the parameter type is a VARIANT, the conversion has an extra complication because a VARIANT is designed to hold many different data types. One approach might be to simply copy the Tcl value's string representation to a string in the VARIANT, and hope the method's implementation can correctly interpret the string, but this doesn't work in general because some implementations expect certain VARIANT types.

Tcom uses the Tcl value's internal representation type as a hint to choose the resulting VARIANT type.

Tcl value to VARIANT mapping
Tcl internal representation VARIANT type
boolean VT_BOOL
int VT_I4
double VT_R8
list one-dimensional array of VT_VARIANT
bytearray one-dimensional array of VT_UI1
other VT_BSTR

Invoking Methods With VARIANT Parameters

The internal representation of a Tcl value may become significant when it is passed to a VARIANT parameter of a method. For example, the standard interface for COM collections defines the Item method for getting an element by specifying an index. Many implementations of the method allow the index to be an integer value (usually based from 1) or a string key. If the index parameter is a VARIANT, you must account for the internal representation type of the Tcl argument passed to that parameter.

# Assume $collection is a handle to a collection.
set element [$collection Item 1]

This command passes a string consisting of the single character "1" to the Item method. The method may return an error because it can't find an element with that string key.

set numElements [$collection Count]
for {set i 1} {$i <= $numElements} {incr i} {  ;# 1
    set element [$collection Item $i]  ;# 2
}

In line 1, the for command sets the internal representation of $i to an int type as a side effect of evaluating the condition expression {$i <= $numElements}. The command in line 2 passes the integer value in $i to the Item method, which should succeed if the method can handle integer index values.