An OLE Automation controller is simply a client of automation objects—that is, a client that uses an object's services by calling the member functions of IDispatch, particularly IDispatch::Invoke. A general purpose controller, which might be a development tool such as Microsoft Visual Basic, will have some sort of integrated programming language. Different syntax structures of this programming language each correspond to a method call, a property get, or a property put operation, where method calls might include optional and named arguments as well. The general syntax structures work in conjunction with an object's type information, which the controller can use to ensure that methods and properties exist and that the types involved are compatible with those types specified in type information.
A general controller such as this also needs syntax structures for object creation and object destruction. Creation of objects can include user interfaces for browsing available objects as well as their type information. A controller can, of course, load an object's type information without having to instantiate the object itself.
A controller, or any client of IDispatch, does not necessarily have to involve a complex programming environment. Any code that calls IDispatch members in any capacity is a simple controller. For example, OLE controls typically use dispinterfaces for their event sets, so in order to fire events, such controls have to know how to call IDispatch::Invoke. This chapter examines how to call Invoke from a client's perspective for the various operations: property put, property get, and method calls with fixed, optional, and named arguments. All these constructs are demonstrated using a sample named AutoCli, which works with any of the Beeper objects from Chapter 14. AutoCli also demonstrates a controller's handling of exceptions, displaying the necessary information to the user and invoking the object's help file if necessary.
This chapter also spends a few pages examining the relationship between an automation object and a controller, which raises a number of important questions to do with design. How much should an object do? How much work can a controller do? Is a feature best implemented as an object service or as part of a controller? Pondering such questions can lead to valuable insights and more robust designs, creating an optimal partnership of controllers and objects.