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.
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.
setf
form of call-dispatch-method can be used to call property setter methods.setf
form of call-dispatch-get-property.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.
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.
setf
form of invoke-dispatch-method can be used to call property setter methods.setf
form of invoke-dispatch-get-property.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.
The arguments and return values to Automation methods are restricted to a small number of simple types, which map to Lisp types as follows:
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.
If there is a parameter marked with the vararg
attribute then any arguments after the last optional argument will be collected into an array and passed as the value of that parameter.
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)))
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)))))))
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 - 23 Mar 2017