[Contents] [Prev] [Next]

Step 16: Making an OLE automation server

An OLE automation server exposes functionality to other applications in the form of properties and methods. A property is analogous to a C++ data member; a method is analogous to a C++ member function. An application that uses the properties and methods of an OLE automation server is called an OLE automation controller.

In this step, you'll expose some of the functionality of the drawing application, making it possible for OLE automation controllers to open new drawing documents, set pen attributes, and add lines.

It's a relatively simple task to turn a regular OLE server into an OLE automation server. You just make small changes to the application, document, and view classes.

Changing the application class

To change the application class, follow these steps.

  1. Include the automation and Step 16 header files.
  2. Add the /automation command-line switch to the application registration table.
  3. Declare and implement member functions that can be exposed as properties and methods.
  4. Expose member functions as properties and methods.

Including the automation and Step 16 header files

Take the #include listing from the step15.cpp file and make the following changes:

  1. Add the ocf/automacr.h header file.
  2. Add the Step 16 resource (.RC), source (.CPP), and header (.H) files.
  3. Remove the Step 15 header files.
Note: In Step 16, the header file (step16.h) is separate from the source file (step16.cpp) for the application class.

Add the /automation command-line switch to the application registration table

An OLE automation server must register itself with the /automation command-line switch. Therefore, you must add the /automation switch to the application registration table using the cmdline keyword.

For the drawing application, you should also modify the description so it says ``..Automation Server'' instead of ``...Server.''

Your new registration table should look something like this:

BEGIN_REGISTRATION(AppReg)
  REGDATA(clsid, "{5E4BD320-8ABC-101B-A23B-CE4E85D07ED2}")
  REGDATA(description,"OWL Drawing Pad Automation Server")
  REGDATA(cmdline, "/automation")
END_REGISTRATION
Note: Remember, never use a GUID or program identifier that another application uses.

Declaring and implementing member functions that can be exposed as properties and methods

Although you can expose the data members of the application class directly, you may want to implement one member function (for read-only or write-only properties) or two member functions (for read/write properties) that handle the tasks of getting and setting values. In this way, you can validate the data being transferred, preventing possible errors.

In addition, for each member function that has parameters with one or more complex data types, you should create a new member function that has parameters with only basic data types. The new function should perform the necessary conversions between data types and then call the original function. By exposing member functions that take only basic data types, you make it easier for an automation controller to use them.

Finally, most OLE automation servers expose a set of standard properties and methods, including the following:

You should declare and implement member functions for each of the standard properties and methods.

For example, the step16.h file contains declarations for the standard properties and methods in the private section of the TDrawApp class:

void SetShow(bool visible); // Sets the Visible property value.
bool GetShow();             // Gets the Visible property value.
TDrawDocument* OpenDoc;     // Opens or creates a document.
Note: You don't need to declare or implement a member function for the Quit method since these tasks are handled automatically by ObjectComponents if you use the EXPOSE_QUIT macro, as shown in the next section.

The step16.cpp file contains the implementations of these functions:

// Get the Visible property value.
TDrawApp::SetShow(bool visible)
{
  TFrameWindow* frame = GetMainWindow();
  if (frame && frame->IsWindow()) {
    unsigned flags = visible ? SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|
      SWP_SHOWWINDOW : SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|
      SWP_HIDEWINDOW;
    frame->SetWindowPos(HWND_TOP, 0,0,0,0, flags);
}

// Set the Visible property value.
bool TDrawApp::GetShow()
{
  TFrameWindow* frame = GetMainWindow();
  return (frame && frame->IsWindow() && frame->IsWindowVisible());
}

// Get the Fullname property value.
const char far* TDrawApp::GetPath()
{
  static char buf[_MAX_PATH];
  GetModuleFileName(buf, sizeof(buf)-1);
  return buf;
}

// Open or create a document.
extern TDocTemplate drawTpl;
TDrawDocument* TDrawApp::OpenDoc(const char far* name)
{
  long flags = name ? 0 : dtNewDoc;
  TDocManager* docManager = GetDocManager();
  if (!docManager)
  return 0;
 HWND hWnd = ::GetFocus();
 TDocument* doc = GetDocManager()->CreateDoc(&drawTpl, name, 0, flags);
 ::SetFocus(hWnd);
 return dynamic_cast<TDrawDocument*>(doc);
}

Exposing properties and methods to other applications

You expose properties and methods by declaring and defining them.

Declaring properties and methods

To declare properties and methods for the application class, add the DECLARE_AUTOAGGREGATE macro to the end of the application class declaration.

The step16.h file contains declarations of the properties and methods for the application class of the drawing application:

DECLARE_AUTOAGGREGATE(TDrarwApp)
  AUTOPROP   (Visible, GetShow, SetShow, TBool)
  AUTOFUNC0  (NewDoc, OpenDoc, TAutoObject<TDrawDocument>,)
  AUTOFUNC1  (OpenDoc, OpenDoc, TAutoObject<TDrawDocument>, TAutoString,)
  AUTOPROPRO (AppName, GetName, TAutoString,)
  AUTOPROPRO (FullName, GetPath, TAutoString,)

Defining properties and methods

To define properties and methods, use the DEFINE_AUTOAGGREGATE macro.

The step16.cpp file contains definitions of the properties and methods for the application class of the drawing application:

DEFINE_AUTOAGGREGATE(TDrawApp, OcApp->Aggregate)
  EXPOSE_PROPRW(Visible, TAutoBool,     "Visible",      "Main window shown", 0)
  EXPOSE_METHOD(NewDoc,  TDrawDocument, "NewDocument",  "Create new document", 0)
  EXPOSE_METHOD(OpenDoc  TDrawDocument, "OpenDocument", "Open existing document", 0)
    REQUIRED_ARG(        TAutoString,   "Name")
  EXPOSE_PROPRO(AppName, TAutoString,   "Name",         "Application name", 0)
  EXPOSE_PROPRO(FullName,TAutoString,   "FullName",   "Complete path to application", 0)
  EXPOSE_APPLICATION(TDrawApp,          "Application",  "Application object", 0)
  EXPOSE_QUIT(                          "Quit",         "Shutdown application", 0)
END_AUTOAGGREGATE(TDrawApp,tfAppObject|tfCanCreate,"TDrawApp","Application class", 0)

Changing the document class

The changes you make to the document class are very similar to the changes you make to the application class:

  1. Include the automation and Step 16 header files.
  2. Update the document registration table.
  3. Declare and implement member functions that can be exposed as properties and methods.
  4. Update the constructor and destructor of the document class.
  5. Expose member functions as properties and methods.

Including the automation and Step 16 header files

Take the #include listing from the step15dv.cpp file and make the following changes:

  1. Add the ocf/automacr.h header file.
  2. Add the Step 16 resource (.RC), source (.CPP), and header (.H) files.
  3. Remove the Step 15 header files.
Note: In Step 16, the header file (step16dv.h) is separate from the source file (step16dv.cpp) for the document class.

Update the document registration table

To update the document registration table, change the description to ``...Automation Server...'' from ...``Server...''

Declaring and implementing member functions that can be exposed as properties and methods

Although you can expose the data members of the document class directly, you may want to implement one member function (for read-only or write-only properties) or two member functions (for read/write properties) that handle the tasks of getting and setting values. In this way, you can validate the data being transferred, preventing errors.

In addition, for each member function that has parameters with one or more complex data types, you should create a new member function that has parameters with only basic data types. The new function should perform the necessary conversions between data types and then call the original function. By exposing member functions that take only basic data types, you make it easier for an automation controller to use them.

When you create new member functions, you may find that you need new data members as well.

For example, the step16dv.h file contains the declarations and implementations of eight new member functions of the document class:

long GetPenColor() // PenColor property.
{
 return AutoPenColor;
}

void SetPenColor(long color) // PenColor property.
{
 AutoPenColor = color;
 AutoLine->SetPen(TColor(color));
}

short GetPenSize() // PenSize property.
{
 return AutoPenSize;
}

void SetPenSize(short penSize) // PenSize property.
{
 AutoPenSize = penSize;
 AutoLine->SetPen(penSize);
}

void AddPoint(short x, short y) // AddPoint method.
{
 AutoLine->Add(TPoint(x,y));
}

void AddLine()
{
 AddLine(*AutoLine);
      ClearLine();
}

void ClearLine() // ClearLine method.
{

 delete AutoLine;
 AutoLine = new TLine(AutoPenColor, AutoPenSize);
}

In addition, the step16dv.h file contains the declarations of three new data members of the document class:


TLine*  AutoLine;
long    AutoPenColor;
short   AutoPenSize;

Updating the constructor and destructor of the document class

When you create new data members and member functions of the document class, you may need to update the document class constructor and destructor.

For example, the step16dv.h file contains new lines of code in the constructor and destructor that initialize and destroy the new data members:


TDrawDocument::TDrawDocument(TDocument* parent)
  : TOleDocument(parent), UndoLine(0), UndoState(UndoNone)
{
  Lines         = new TLines(100, 0, 5);
  AutoPenSize   = 1;
  AutoPenColor  = RGB(0, 0, 0);
  AutoLine      = new TLine(AutoPenColor, AutoPenSize);
}

TDrawDocument::~TDrawDocument()
{
  delete AutoLine;
  delete Lines;
  delete UndoLine;
}

Exposing properties and methods to other applications

You expose properties and methods by declaring and defining them.

Declaring properties and methods

To declare properties and methods for the document class, add the DECLARE_AUTOCLASS macro to the end of the document class declaration.

The step16dv.h file contains declarations of the properties and methods for the document class of the drawing application:


DECLARE_AUTOCLASS(TDrawDocument)
 AUTOPROP(PenSize,    GetPenSize,  SetPenSize,  short, )
 AUTOPROP(PenColor,   GetPenColor, SetPenColor, long, )
 AUTOFUNC2V(AddPoint, AddPoint,    short,       short, )
 AUTOFUNC0V(AddLine,  AddLine, )
 AUTOFUNC0V(ClearLine,ClearLine, )
To define properties and methods for the document class, use the DEFINE_AUTOCLASS macro.

Defining properties and methods

The step16.cpp file contains definitions of the properties and methods for the document class of the drawing application:


DEFINE_AUTOCLASS(TDrawDocument)
  EXPOSE_PROPRW(PenSize,     TAutoShort, "PenSize",    "Current pen size", 0)
  EXPOSE_PROPRW(PenColor,    TAutoLong,  "PenColor",   "Current pen color", 0)
  EXPOSE_METHOD(AddPoint,    TAutoVoid,  "AddPoint",   "Add a point to the 
                                                        current line", 0)
    REQUIRED_ARG(            TAutoShort, "X")
    REQUIRED_ARG(            TAutoShort, "Y")
  EXPOSE_METHOD(AddLine,     TAutoVoid,  "AddLine",    "Add current line into 
                                                        drawing", 0)
  EXPOSE_METHOD(ClearLine,   TAutoVoid,  "ClearLine",  "Erases current line", 0)
  EXPOSE_APPLICATION(        TDrawApp,   "Application","Application object", 0)
END_AUTOCLASS(TDrawDocument, tfNormal,   "TDrawDoc",   "Draw document class", 0)


[Contents] [Prev] [Next]
Last Modified: 02:16pm , April 29, 1997