Chapter 46
Creating an Automation controller

Automation is a COM protocol that defines how one application accesses an object that resides within another application or DLL. An Automation controller is a client application that controls an Automation server through one or more server-provided objects which implement the IDispatch interface.

Automation controllers can be written in any language for which an implementation of COM and Automation is provided. Most automation controllers are currently written in C++, Object Pascal (Delphi), or Visual Basic.

Examples of Automation servers include Microsoft Word, Microsoft Excel, and Internet Explorer. These applications can be controlled by Delphi applications or by other Automation controllers.

Delphi gives you the flexibility to integrate applications and DLLs with a variety of applications as either Automation servers or as controllers.

This chapter describes how to create an Automation controller in the Delphi environment. It is not intended to provide complete details of controller application development for every type of server. For specific information on a server application, you should consult that application's documentation.

For information about creating an Automation server, see Chapter 47, "Creating an Automation server."

In Delphi, you create an Automation controller by importing an Automation server's type library and installing it on the Component palette.

Creating an Automation controller by importing a type library

You can create an Automation controller by importing an Automation server's type library and using the automatically generated classes to control the Automation server. With the Import Type Library dialog, you install the server that the type library describes to the Component palette, which allows you to connect to the server and hook up its events using the Object Inspector. You can then manipulate the server properties programmatically.

To import an Automation controller's type library,

  1. Choose Project|Import Type Library.
  2. Select the type library from the list.

    The dialog lists all the libraries registered on this system. If the type library is not in the list, choose the Add button, find and select the type library file, choose OK, and repeat step 2. Note that the type library could be a standalone type library file (.TLB, .OLB), or a server that provides a type library (.DLL, .OCX, .EXE).

  3. Choose the Palette page on which this server will reside.
  4. Check Generate Component Wrapper, which creates a TComponent wrapper that allows you to install the server that the type library describes on the Component palette.
  5. Choose Install.

    Specify where you want the type library to reside, either in an existing package or new package. This button is grayed out if no component can be created for that type library.

A server that the type library described now resides on the Component palette. You can use the Object Inspector to write an event handler for the server.

To control the Automation server through this controller, you add code to the implementation unit to provide support for early (VTable) binding and late (dispatch) binding. The unit that you just created includes interface wrappers for both VTable binding for all exposed interfaces, and dispatch binding for dual and dispatch interfaces.

Handling events in an automation controller

Once you have installed a server on the Component palette, you can use the Object Inspector to write an event handler.

To support events,

  1. From the Component palette, drop the desired server component onto your form.
  2. Select the component, and click the Events tab on the Object Inspector. You'll see a list of the object's events.
  3. Double-click in the space to the right of an event and Delphi opens the Code editor, displaying the skeleton event handler for you to complete.

After implementing your event handler, you can connect to a server.

Connecting to and disconnecting from a server

Typically, you connect to a server through its main interface. For example, you would connect to Microsoft Word through the WordApplication component. Once you've connected to the main interface, you can connect to any of the application's components (such as a WordDocument or WordParagraphFormat) by using the ConnectTo method.

Here is the event handler for the ExcelApplication event, OnNewWorkBook. In it, we are assigning the workbook to the ExcelWorkbook component.

procedure TForm1.XLappNewWorkbook(Sender: TObject; var Wb:OleVariant);
begin
  ExcelWorkbook1.ConnectTo((iUnknown(wb) as ExcelWorkBook));
end;

After importing the type library, add code to the implementation unit to control the server with either a dual interface (most typical) or a dispatch interface.

Note: The import files created when a type library is imported (libname_TLB.CPP and libname_TLB.H) should be considered to be read-only, and are not intended for modification of any kind. These files are regenerated each time the type library is refreshed, so any changes are overwritten.

For servers that expose a Quit method (such as WordApplication and ExcelApplication), code is generated to call this method in the Disconnect method. Quit typically exposes functionality that is equivalent to clicking on File to quit the application. If AutoConnect is set to True, the application server will Quit when the client exits. Therefore, hitting F1 when AutoQuit is highlighted in the Object Inspector does nothing.

Controlling an Automation server using a dual interface

When you create an Automation controller by selecting an object from the Component Palette, it automatically provides a dual interface because Delphi can determine the VTable layout from information in the type library. Calling a method on the class automatically connects to an instance of Word.

For example, for a Word server, you call on a method of class TWordApplication as follows:

foo := TWordapplication
foo.DoSomething;

Of course, the former way of controlling an Automation server with a dual interface still works, but it is more cumbersome. You must first, declare an interface and initialize it with the Create method of a CoClass client proxy class. Then you call methods of the smart interface object. For example,

foo : _Application
foo := CoWordApplication.Create
foo.DoSomething;

The interface and CoClass client proxy class are defined in the unit that is generated automatically when you import a type library. The names of smart interfaces start with "I". For example, the main smart interface for Microsoft Word is "IWordBasic". The names of the CoClass client proxy classes start with "Co". For example, the main CoClass client proxy class for Microsoft Word is CoApplication.

For information about dual interfaces, see "Automation interfaces".

Controlling an Automation server using a dispatch interface

Typically, you will use the dual interface to control the Automation server, as described above. However, you may find a need to control an Automation server with a smart dispatch interface object. To do so,

  1. In the Automation controller's implementation unit, declare a dispinterface.
  2. Control the Automation server by calling methods of the dispatch interface object.

For information on dispatch interfaces, see "Automation interfaces".

Example: Printing a document with Microsoft Word

The following steps show how to create an Automation controller that prints a document using Microsoft Word 8 from Office 97.

Before you begin, create a new project that consists of a form, a button, and an open dialog box (TOpenDialog). These controls constitute the Automation controller.

Step 1: Prepare Delphi for this example

For your convenience, Delphi has provided many common servers, such as Word, Excel, and Powerpoint, on the Component Palette. To demonstrate how to import a server, we use Word. Since it already exists on the Component Palette, this first step asks you to remove the package containing Word so that you can install it on the palette. Step 4 describes how to return the Component Palette to its normal state.

To remove Word from the Component palette,

  1. Choose Component|Install packages.
  2. Click Borland Sample Automation Server components and choose Remove.

    The Servers page of the Component Palette no longer contains any of the servers supplied with Delphi. (If no other servers have been imported, the Servers page also disappears.)

Step 2: Import the Word type library

To import the Word type library,

  1. Choose Project|Import Type Library.
  2. In the Import Type Library dialog,

    1. Select Microsoft Office 8.0 Object Library.

      If Word (Version 8) is not in the list, choose the Add button, go to Program Files\Microsoft Office\Office, select the Word type library file, MSWord8.olb choose Add, and then select Word (Version 8) from the list.

    2. In Palette Page, choose Servers.
    3. Choose Install.

      The Install dialog appears. Select the Into New Packages tab and type WordExample to create a new package containing this type library.

  3. Go to the Servers Palette Page, select WordApplication and place it on a form.
  4. Write an event handler for each object by choosing the Events tab of the Object Inspector and double-clicking in the space beside each event, then editing the skeleton event handler in the Code editor. Supply the following information:

Step 3: Use a VTable or dispatch interface object to control Microsoft Word

You can use either a VTable or a dispatch object to control Microsoft Word.

Using a VTable interface object

To use a VTable interface object to control Microsoft Word, you add code to the OnClick event handler of the Automation controller's button. To do so, you simply call on methods of the class you just created. For Word, this is the TWordApplication class.

Note: : You must include the Word type library, Word_TLB, in the Uses clause of the Automation controller's implementation file.

  1. Create and initialize an Application object using the _Application VTable smart interface class as follows:
    var 
    FileName: OleVariant;
    begin 
        MyWord: _Application;
      WordApplication1.Create;
    
  2. Call the PrintOut method of the WordBasic object using the "." (period) operator, and free the object with Quit:
    if OpenDialog1.Execute then
      begin
        FileName := OpenDialog1.Filename;
        WordApplication1.Documents.Open(FileName,
            EmptyParam,EmptyParam,EmptyParam,EmptyParam,
            EmptyParam,EmptyParam,EmptyParam,EmptyParam,
            EmptyParam);
      WordApplication1.ActiveDocument.PrintOut(EmptyParam,
            EmptyParam,EmptyParam,EmptyParam,EmptyParam,
            EmptyParam,EmptyParam,EmptyParam,EmptyParam,
            EmptyParam,EmptyParam,EmptyParam,EmptyParam,
            EmptyParam);
      WordApplication1.Quit(EmptyParam,EmptyParam,EmptyParam);
      end;
    

Using a dispatch interface object

To use a dispatch interface object to control Microsoft Word, perform the following tasks, adding code to the OnClick event handler of the Automation controller's button:

  1. Create and initialize the Application object using the _ApplicationDisp smart dispatch wrapper class and one of its bind methods, as follows:
    var
      MyWord: _ApplicationDisp;
      FileName: OleVariant;
    begin
      MyWord:= CoApplication_.Create;
    

    Note: Go to the Uses clause of the automation controller's implementation file and add Word_TLB to include the Word type library.

  2. Call the Open, PrintOut, and Quit methods.
    if OpenDialog.Execute then
    begin
      FileName := OpenDialog1.Filename;
        MyWord.Documents.Open(FileName,
            EmptyParam,EmptyParam,EmptyParam,EmptyParam,
            EmptyParam,EmptyParam,EmptyParam,EmptyParam,
            EmptyParam);
        MyWord.ActiveDocument.PrintOut(EmptyParam,
            EmptyParam,EmptyParam,EmptyParam,EmptyParam,
            EmptyParam,EmptyParam,EmptyParam,EmptyParam,
            EmptyParam,EmptyParam,EmptyParam,EmptyParam,
            EmptyParam);
        MyWord.Quit(EmptyParam,EmptyParam,EmptyParam);
      end;
    

Step 4: Clean-up the example

After completing this example, you will want to restore Delphi to its original form.

  1. Delete the objects on this Servers page:

    1. Choose Component|Configure Palette and select the Servers Page.
    2. Select all objects on the page that you just added, choose Hide.
    3. Choose delete. The Servers page no longer appears.

  2. Return the Borland Sample Automation Server Components package:

    1. Choose Component|Install Packages.
    2. Click Add, browse to the Delphi bin directory, and select the Borland Sample Automation Server Components package. Choose Open.

Getting more information

For the most up-to-date information about the dispatch interface, dual interface, and CoClass client proxy classes, refer to the comments in the automatically-generated source file.