This section describes two techniques for implementing Automation interfaces in Lisp. The choice of technique usually depends on whether you are implementing a complete server or a simple event sink. The section then describes other kinds of interfaces that can be implemented and how to report errors to the caller of a method.
In the case where you are designing an set of COM interfaces and implementing a server to support them, you need to make a complete implementation in Lisp. This allows several Automation interfaces to be implemented by a single class and also supports dual interfaces.
The implementation defines an appropriate class, inheriting from the class standard-i-dispatch to obtain an implementation of the COM interface i-dispatch. This implementation of i-dispatch will automatically invoke the appropriate COM method.
For dual interfaces, the methods should be defined in the same way as described for COM interfaces in 1.9 Implementing COM interfaces in Lisp.
For dispinterfaces, the methods should be implemented using the macro define-dispinterface-method or by a specialized method of the generic function com-object-dispinterface-invoke.
To implement an Automation interface in Lisp with standard-i-dispatch, you need the following:
/RegServer
and /UnRegServer
.In the case where you are implementing a single dispinterface that was designed by someone else, for example an event sink, you can usually avoid needing to parse a type library or define a class to implement the interface.
Instead, you implement a dispinterface using the class simple-i-dispatch by doing the following:
Interfaces that support the Collection protocol can be implemented using the macro define-automation-collection. This defines a subclass of standard-automation-collection, which implements the minimal set of collection methods and calls Lisp functions to provide the items. If the collection items are interface pointers, appropriate reference counting must be observed.
See the example files here:
(example-edit-file "com/automation/collections/")
Lisp implementations can act as event sources via a built-in implementation of the IConnectionPointContainer
interface, which define-automation-component provides if source interfaces are specified. A built-in implementation of IConnectionPoint
handles connections for each interface and the macro do-connections can be used to iterate over the connections when firing the events.
Classes defined using define-automation-component allow extended error information to be returned for all Automation methods. Within the body of a define-com-method definition, the function set-error-info can be called to describe the error. In addition, this function returns the value of DISP_E_EXCEPTION
, which can be returned directly as the hresult from the method.
For example:
(define-com-method (i-test-suite-1 fx) ((this c-test-suite-1)) (print "in fx") (set-error-info :description "foo" :iid 'i-test-suite-1 :source "fx"))
If other applications need to be able to find one of your running objects from its coclass, then call register-active-object to register an interface pointer for the object in the system Running Object Table. Call revoke-active-object to remove the registration.
For an example of how to implement an Automation server that controls a CAPI application, see the file:
(example-edit-file "com/automation/capi-application/build")
COM/Automation User Guide and Reference Manual - 01 Dec 2021 19:38:41