All Manuals > LispWorks COM/Automation User Guide and Reference Manual > 3 Using Automation

NextPrevUpTopContentsIndex

3.3 Calling Automation methods

Automation methods can be called either with or without a compiled type library. In both cases, arguments and return values are converted according to the types specified by the method's definition.

3.3.1 Calling Automation methods using a type library

To use this approach, you must have the type library available at compile-time (see Generating FLI definitions from COM definitions). Information from the type library is built into your application, which makes method calling more efficient. However, it also makes it less dynamic, because the library at the time the application is run must match.

There are three kinds of Automation method, each of which is called using macros designed for the purpose.

To use these macros, you need to specify the interface name, the method name, a COM interface pointer for the i-dispatch interface and suitable arguments. The interface and method names are given as symbols named as in The mapping from COM names to Lisp symbols and the COM interface pointer is a foreign pointer of type com-interface. In all the macros, the args and values are as specified in the Data conversion when calling Automation methods.

The with-dispatch-interface macro is useful when several methods are being called with the same COM interface pointer, because it establishes a local macro that takes just the method name and arguments.

3.3.2 Calling Automation methods without a type library

This approach is useful if the type library is not available at compile time or you want to allow methods to be called dynamically without knowing the interface pointer type at compile-time. It can be less efficient than using the approach in Calling Automation methods using a type library, but is often the simplest approach, especially if the Automation component was written to be called from a language like Visual Basic.

There are three kinds of Automation method, each of which is called using functions designed for the purpose.

To use these functions, you need to specify a COM interface pointer for the i-dispatch interface, the method name and suitable arguments. The method name is given as a string or integer and the COM interface pointer is a foreign pointer of type com-interface. In all the functions, the args and values are as specified in the Data conversion when calling Automation methods.

3.3.3 Data conversion when calling Automation methods

The arguments and return values to Automation methods are restricted to a small number of simple types, which map to Lisp types as follows:

Automation types, VT codes and their corresponding Lisp types

Automation type

VT code

Lisp type

null value

VT_NULL

the symbol :null

empty value

VT_EMPTY

the symbol :empty

SHORT

VT_I2

integer

LONG

VT_I4

integer

FLOAT

VT_R4

single-float

DOUBLE

VT_R8

double-float

CY

VT_CY

not supported

DATE

VT_DATE

not supported

BSTR

VT_BSTR

string

IDispatch*

VT_DISPATCH

FLI (:pointer i-dispatch)

SCODE

VT_ERROR

integer

VARIANT_BOOL

VT_BOOL

nil or t

VARIANT*

VT_VARIANT

recursively convert

IUnknown*

VT_UNKNOWN

FLI (:pointer i-unknown)

DECIMAL

VT_DECIMAL

not supported

BYTE

VT_UI1

integer

SAFEARRAY

VT_ARRAY

array

dynamic

dynamic

lisp-variant

When an Automation argument is a lisp-variant object, its type is used to set the VT code. See make-lisp-variant and set-variant.

In and in-out parameters are passed as positional arguments in the calling forms and out and in-out parameters are returned as additional values. If there is an argument with the retval attribute then it is returned as the first value.

Optional parameters can be passed as :not-specified if they are not needed. Alternatively, they can be omitted if all remaining optional arguments are also omitted.

3.3.4 Using collections

The macro do-collection-items can be used to iterate over the items or an interface that implements the Collection protocol. If the collection items are interface pointers, they must be released when not needed.

For example, to iterate over the Table objects from the Tables collection of a MyDocument interface pointer

(with-temp-interface (tables)
    (call-dispatch-get-property
       (doc my-document tables))
  (do-collection-items (table tables)
    (inspect-the-table table)
    (release table)))

3.3.5 Using connection points

Event sink interfaces can be connected and disconnected using the functions interface-connect and interface-disconnect.

For example, the following macro connects a sink interface pointer event-handler to a source of i-clonable-events events clonable for the duration of its body.

(defmacro handling-clonable-events ((clonable event-handler)
                                    &body body)
  (lw:with-unique-names (cookie)
    (lw:rebinding (clonable event-handler)
      `(let ((,cookie nil))
         (unwind-protect
             (progn
               (setq ,cookie
                     (interface-connect ,clonable
                                        'i-clonable-events
                                        ,event-handler))
               ,@body)
           (when ,cookie
             (interface-disconnect ,clonable
                                   'i-clonable-events
                                   ,cookie)))))))

3.3.6 Error handling

When an Automation server returns an error code, the calling macros such as call-dispatch-method signal an error of type com-error. The error message will contain the source and description fields from the error.

For example, if pp is a dispatch pointer to i-test-suite-1:

CL-USER 184 > (call-dispatch-method
                (pp nil i-test-suite-1 fx))
"in fx"            ;; implementation running
Error: COM IDispatch::Invoke Exception Occurred (0 "fx") : foo
  1 (abort) Return to level 0.
  2 Return to top loop level 0.
 
Type :b for backtrace, :c <option number> to proceed,  or :? for other options

LispWorks COM/Automation User Guide and Reference Manual - 14 Feb 2015

NextPrevUpTopContentsIndex