Chapter 44
Overview of COM technologies

Delphi provides wizards and classes to make it easy to implement applications based on the Component Object Model (COM) from Microsoft. With these wizards, you can create COM-based classes and components to use within applications or you can create fully functional COM objects, Automation servers and clients (controllers), Active Server Pages, ActiveX controls, or ActiveForms.

COM is a language independent software component model designed by Microsoft to enable interaction between software components and applications. Microsoft extends this technology with ActiveX, which is a primarily used for Intranet development.

The key aspect of COM is that it enables communication between components, between applications, and between clients and servers through clearly defined interfaces. Interfaces provide a way for clients to ask a COM component which features it supports at runtime. To provide additional features for your component, you simply add an additional interface to those features.

Applications can access COM components and their interfaces that exist on the same computer as the application, or that exist on another computer on the network using a mechanism called Distributed COM or DCOM. For more information on clients, servers, and interfaces see"Parts of a COM application".

This chapter provides a conceptual overview of the underlying technology on which Automation and ActiveX controls are built. Later chapters provide details on creating Automation objects and ActiveX controls in Delphi.

COM as a specification and implementation

COM is both a specification and an implementation. The COM specification defines object creation and communication between objects. According to this specification, COM objects can be written in different languages, run in different process spaces and on different platforms. As long as the objects adhere to the written specification, they can communicate. This allows you to integrate legacy code as a component with new components implemented in object-oriented languages.

The COM implementation is the COM library (including OLE32.dll and OLEAut32.dll), which provides a number of core services that support the written specification. The COM library contains a set of standard interfaces that define the core functionality of a COM object, and a small set of API functions designed for the purpose of creating and managing COM objects.

Note: Delphi's interface objects and language follow the COM specification. Delphi's implementation of the COM specification is called the Delphi ActiveX framework (DAX). Most of the implementation is found in the AxCtrls unit.

When you use Delphi wizards and VCL objects in your application, you are using Delphi's implementation of the COM specification. In addition, Delphi provides some wrappers for COM services for those features that it does not implement directly (such as Active Documents). You can find these wrappers defined in the ComObj unit and the API definitions are found in the AxCtrls unit.

COM extensions

As COM has evolved, it has been extended beyond the basic COM services. COM serves as the basis for other technologies such as Automation, ActiveX controls, Active Server Pages, and Active Documents. For details, see "COM extensions".

In addition, you can create a COM object that can work within the Microsoft Transaction Server (MTS) environment. MTS is a component-based transaction processing system for building, deploying, and managing large intranet and Internet server applications. Even though MTS is not architecturally part of COM, it is designed to extend the capabilities of COM in a large, distributed environment. For more information on MTS, see "Creating MTS objects."

Delphi provides wizards to easily implement applications that incorporate the above technologies in the Delphi environment. For details, see "Implementing COM objects with wizards"

Parts of a COM application

When implementing a COM application, you supply the following:

COM Interface

The way in which an object exposes its services externally to clients. A COM object provides an interface for each set of related methods (member functions) and properties (data members and or content).

COM server

A module, either an EXE, DLL, or OCX, that contains the code for a COM object. Object implementations reside in servers. A COM object implements one or more interfaces.

COM client

The code that calls the interfaces to get the requested services from the server. Clients know what they want to get from the server (through the interface); clients do not know the internals of how the server provides the services. The most common COM client to implement is an Automation controller. Delphi eases the process in creating a client by allowing you to install COM servers (such as a Word document or Powerpoint slide) as components on the Component Palette. This allows you to connect to the server and hook its events through the Object Inspector.

COM interfaces

COM clients communicate with objects through COM interfaces. Interfaces are groups of logically or semantically related routines which provide communication between a provider of a service (server object) and its clients. The standard way to depict a COM interface is shown in Figure 44.1:

Figure 44.1   A COM interface

For example, every COM object implements the basic interface, IUnknown, which tells the client what interfaces are available on the client.

Objects can have multiple interfaces, where each interface implements a feature. An interface provides a way to convey to the client what service it provides, without providing implementation details of how or where the object provides this service.

Key aspects of COM interfaces are as follows:

The fundamental COM interface, IUnknown

All COM objects must support the fundamental interface, called IUnknown, which contains the following routines:

QueryInterface

Provides pointers to other interfaces that the object supports.

AddRef and Release

Simple reference counting methods that keep track of the object's lifetime so that an object can delete itself when the client no longer needs its service.

Clients obtain pointers to other interfaces through the IUnknown method, QueryInterface. QueryInterface knows about every interface in the server object and can give a client a pointer to the requested interface. When receiving a pointer to an interface, the client is assured that it can call any method of the interface.

Objects track their own lifetime through the IUnknown methods, AddRef and Release, which are simple reference counting methods. As long as an object's reference count is nonzero, the object remains in memory. Once the reference count reaches zero, the interface implementation can safely dispose of the underlying object(s).

COM interface pointers

An interface pointer is a 32-bit pointer to an object instance that points, in turn, to the implementation of each method in the interface. The implementation is accessed through an array of pointers to these methods, which is called a vtable. Vtables are similar to the mechanism used to support virtual functions in ObjectPascal.

The vtable is shared among all instances of an object class, so for each object instance, the object code allocates a second structure that contains its private data. The client's interface pointer, then, is a pointer to the pointer to the vtable as shown in the following diagram.

Figure 44.2   Interface vtable

COM servers

A COM server is an application or a library that provides services to a client application or library. A COM server consists of one or more COM objects, where a COM object is a set of properties (data members or content) and methods (or member functions).

Clients do not know how a COM object performs its service; the object's implementation remains encapsulated. An object makes its services available through its interfaces as described previously.

In addition, clients do not need to know where a COM object resides. COM provides transparent access regardless of the object's location.

When a client requests a service from a COM object, the client passes a class identifier (CLSID) to COM. A CLSID is simply a GUID that references a COM object. COM uses this CLSID to locate the appropriate server implementation, brings the code into memory, and has the server instantiate an object instance for the client. Thus, a COM server must provide a class factory object (IClassFactory) that creates instances of objects on demand. (The CLSID is based on the interface's GUID.)

In general, a COM server must perform the following:

Note: Delphi wizards automate the creation of COM objects and servers as described in "Implementing COM objects with wizards".

CoClasses and class factories

A COM object is an instance of a CoClass, which is a class that implements one or more COM interfaces. The COM object provides the services as defined by its CoClass interfaces.

CoClasses are instantiated by a special type of object called a class factory. Whenever an object's services are requested by a client, a class factory creates and registers an object instance for that particular client. If another client requests the object's services, the class factory creates another object instance to service the second client.

A CoClass must have a class factory and a class identifier (CLSID) so that its COM object can be instantiated externally, that is, from another module. Using these unique identifiers for CoClasses means that they can be updated whenever new interfaces are implemented in their class. A new interface can modify or add methods without affecting older versions, which is a common problem when using DLLs.

Delphi wizards take care of implementing and instantiating class factories.

In-process, out-of-process, and remote servers

With COM, a client does not need to know where an object resides, it simply makes a call to an object's interface. COM performs the necessary steps to make the call. These steps differ depending on whether the object resides in the same process as the client, in a different process on the client machine, or in a different machine across the network. The different types of servers are known as:

In-process server

A library (DLL) running in the same process space as the client, for example, an ActiveX control embedded in a Web page viewed under Internet Explorer or Netscape. Here, the ActiveX control is downloaded to the client machine and invoked within the same process as the Web browser.

The client communicates with the in-process server using direct calls to the COM interface.

Out-of-process server (or local server)

Another application (EXE) running in a different process space but on the same machine as the client. For example, an Excel spreadsheet embedded in a Word document are two separate applications running on the same machine.

The local server uses COM to communicate with the client.

Remote server

A DLL or another application running on a different machine from that of the client. For example, a Delphi database application is connected to an application server on another machine in the network.

The remote server uses distributed COM (DCOM) interfaces to communicate with the application server.

As shown in Figure 44.3, for in-process servers, pointers to the object interfaces are in the same process space as the client, so COM makes direct calls into the object implementation.

Figure 44.3   In-process server

As shown in Figure 44.4, when the process is either in a different process or in a different machine altogether, COM uses a proxy to initiate remote procedure calls. The proxy resides in the same process as the client, so from the client's perspective, all interface calls look alike. The proxy intercepts the client's call and forwards it to where the real object is running. The mechanism that enables the client to access objects in a different process space, or even different machine, as if they were in their own process, is called marshaling.

The difference between out-of-process and remote servers is the type of interprocess communication used. The proxy uses COM to communicate with an out-of-process server, it uses distributed COM (DCOM) to communicate with a remote machine.

Figure 44.4   Out-of-process and remote servers

The marshaling mechanism

Marshaling is the mechanism that allows a client to make interface function calls to remote objects in another process or on a different machine. Marshaling

For any interface call, the client pushes arguments onto a stack and makes a function call through the interface pointer. If the call to the object is not in-process, the call gets passed to the proxy. The proxy packs the arguments into a marshaling packet and transmits the structure to the remote object. The object's stub unpacks the packet, pushes the arguments onto the stack, and calls the object's implementation. In essence, the object recreates the client's call in its own address space.

What type of marshaling occurs depends on what the COM object implements. Objects can use a standard marshaling mechanism provided by the IDispatch interface. This is a generic marshaling mechanism that enables communication through a system-standard remote procedure call (RPC). For details on the IDispatch interface, see "Creating an Automation server."

Note: Microsoft Transaction Server (MTS) provides additional support for remote objects. For details, see "Creating MTS objects."

COM clients

It is important to design a COM application where clients can query the interfaces of an object to determine what an object is capable of providing. Server objects should have no expectations about the client using its objects. The client can determine what an object can provide through its interfaces. In addition, clients don't need to know how (or even where) an object provides the services; it just needs to rely on the object to provide the service it advertised through the interface.

A typical COM client is the Automation Controller. An Automation controller is the part of the application that has the broad perspective of the application's intended use. It knows the kinds of information it needs from various objects on the server, and it requests services when necessary.

Delphi makes it easier for you to develop an Automation Controller by allowing you to import an Automation server's type library and install it on the Component palette.

For details in creating an Automation controller, see "Creating an Automation controller."

COM extensions

COM was originally designed to provide core communication functionality and to enable the broadening of this functionality through extensions. COM itself has extended its core functionality by defining specialized sets of interfaces for specific purposes.

ActiveX is a technology that allows COM components, especially controls, to be more compact and efficient. This is especially necessary for controls that are intended for Intranet applications that need to be downloaded by a client before they are used.

Microsoft is incorporating some of the MTS technologies for building complex Internet and intranet applications within the COM framework. This next evolution of COM, which also incorporates other new features, is currently called "COM+" (COM Plus) and should be available with the release of Windows 2000.

The following lists the vast array of services COM extensions currently provide. Subsequent sections describe these services in greater detail.

Automation servers

Automation refers to the ability of an application to control the objects in another application programmatically. Automation servers are the objects that can be controlled by other executables at runtime.

Automation controllers (or COM clients)

Clients of Automation servers. Controllers provide a programming environment in which a developer or user can write scripts (controls) to drive Automation servers.

ActiveX controls

ActiveX controls are specialized in-process COM servers, typically intended for embedding in a client application. The controls offer both design and runtime behaviors as well as events.

Type libraries

A collection of static data structures, often saved as a resource, that provides detailed type information about an object and its interfaces. Clients of Automation servers and ActiveX controls expect type information to be available.

Active Server Pages

Active Server Pages are ActiveX components that allow you to create dynamic Web pages.

Active Documents

Objects that support linking and embedding, drag-and-drop, visual editing, and in-place activation. Word documents and Excel spreadsheets are examples of Active Documents.

Visual cross-process objects

Objects that can be manipulated across different processes.

The following diagram illustrates the relationship of the COM extensions and how they are built upon COM:

Figure 44.5   COM-based technologies

Using COM objects introduces both features and restrictions. These objects can be visual or non-visual. Some must run in the same process space as their clients; others can run in different processes or remote machines, as long as the objects provide marshaling support.

Table 44.1 summarizes the types of COM objects that you can create, whether they are visual, process spaces they can run in, how they provide marshaling, and whether they require a type library.

Table 44.1   COM object requirements

Object

Visual Object?

Process space

Communication

Type library

Active Document

Usually

In-process, or out-of-process

OLE Verbs

No

Automation

Occasionally

In-process, out-of-process, or remote

Automatically marshaled using the IDispatch interface (for out-of process and remote servers)

Required for automatic marshaling

ActiveX Control

Usually

In-process

Automatically marshaled using the IDispatch interface

Required

Custom interface object

Optionally

In-process

No marshaling required for in-process servers

Recommended

Custom interface object

Optionally

In-process, out-of-process, or remote

Automatically marshaled via a type library; otherwise, manually marshaled using custom interfaces

Recommended

Automation servers and controllers

Automation refers to the ability of an application to control the objects in another application programmatically, like a macro that can manipulate more than one application at the same time. The client of an Automation object is referred to as an Automation controller, and the server object being manipulated is called the Automation object.

Automation can be used on in-process, local, and remote servers.

Automation is characterized by two key points:

Developers often use Automation to create and use non-visual OLE objects that run in any process space because the Automation IDispatch interface automates the marshaling process. Automation does, however, restrict the types that you can use.

For a list of types that are valid for type libraries in general, and Automation interfaces in particular, see the section on Valid Types in "Working with type libraries."

For details on writing an Automation controller, see "Creating an Automation controller." For information on writing an Automation server, see "Creating an Automation server."

ActiveX controls

ActiveX controls are visual controls that run only in in-process servers, and can be plugged into an ActiveX control container application. They are not complete applications in themselves, but can be thought of as prefabricated OLE controls that are reusable in various applications. ActiveX controls make use of Automation to expose their properties, methods, and events. Features of ActiveX controls include the ability to fire events, bind to data sources, and support licensing.

An increasingly common use of ActiveX controls is on a Web site as interactive objects in a Web page. As such, ActiveX has become a standard that has especially targeted interactive content for the World Wide Web, including the use of ActiveX Documents used for viewing non-HTML documents through a Web browser. For more information about ActiveX technology, see the Microsoft ActiveX Web site.

Delphi wizards allow you to easily create ActiveX controls. For more information about creating and using these types of objects, see "Creating an ActiveX control."

Type libraries

Type libraries provide a way to get more type information about an object than can be determined from an object's interface. The type information contained in type libraries provides needed information about objects and their interfaces, such as what interfaces exist on what objects (given the CLSID), what member functions exist on each interface, and what arguments those functions require.

You can obtain type information either by querying a running instance of an object or by loading and reading type libraries. With this information, you can implement a client which uses a desired object, knowing specifically what member functions you need, and what to pass those member functions.

Clients of Automation servers and ActiveX controls expect type information to be available. Automation and ActiveX wizards generate a type library automatically.You can view or edit this type information by using the Type Library Editor as described in "Working with type libraries."

This section describes what a type library contains, how it is created, when it is used, and how it is accessed. For developers wanting to share interfaces across languages, the section ends with suggestions on using type library tools.

The content of type libraries

Type libraries contain type information, which indicates which interfaces exist in which COM objects, and the types and numbers of arguments to the interface methods. These descriptions include the unique identifiers for the CoClasses (CLSIDs) and the interfaces (IIDs), so that they can be properly accessed, as well as the dispatch identifiers (dispIDs) for Automation interface methods and properties.

Type libraries can also contain the following information:

Creating type libraries

With traditional development tools, you create type libraries by writing scripts in the Interface Definition Language (IDL) or the Object Description Language (ODL), then running that script through a compiler. However, Delphi automatically generates a type library when for you when you use either the Automation server or ActiveX control wizard. (You can also create a type library by choosing from the main menu, File|New|ActiveX|Type Library.) Then you can view the type library using Delphi's Type Library editor. You can easily edit your type library using the Type Library editor and Delphi automatically updates the appropriate source files when the type library is saved.

The Type Library editor automatically generates a standard type library, typically as a resource, along with a Delphi Interface File (.PAS file) that contains the type declarations in Object Pascal syntax. For more information on using the Type Library editor to write interfaces and CoClasses, see "Working with type libraries."

When to use type libraries

It is important to create a type library for each set of objects that is exposed to external users, for example,

When defining interfaces for internal use only (within an application) you do not need to create a type library.

Accessing type libraries

The binary type library is normally a part of a resource file (.RES) or a stand-alone file with a .TLB file-name extension. Once a type library has been created, object browsers, compilers, and similar tools can access type libraries through special type interfaces:

Interface

Description

ITypeLib

Provides methods for accessing a library of type descriptions.

ITypeInfo

Provides descriptions of individual objects contained in a type library. For example, a browser uses this interface to extract information about objects from the type library.

ITypeComp

Provides a fast way to access information that compilers need when binding to an interface.

Delphi can import and use type libraries from other applications. Most of the VCL classes used for COM applications support the essential interfaces that are used to store and retrieve type information from type libraries and from running instances of an object. The VCL class TTypedComObject supports interfaces that provide type information, and is used as a foundation for the ActiveX object framework.

Benefits of using type libraries

Even if your application does not require a type library, you can consider the following benefits of using one:

Using type library tools

The tools for working with type libraries are listed below.

Active Server Pages

The Active Server Pages (ASP) technology allows you to build Web pages dynamically by using ActiveX server components. With Active Server Pages, you can embed ActiveX controls in a Web page that get called every time the server loads the Web page. For example, you can write an Object Pascal program, such as one to create a bitmap or connect to a database, and this control accesses data that gets updated every time the server loads the Web page.

Active Server Pages relies on the Microsoft Internet Information Server (IIS) environment to serve your Web pages.

On the server side, the Active Server Pages are ActiveX components which you can develop using Delphi or most other languages including C++, Java, or Visual Basic. On the client side, the ASP is a standard HTML document and can be viewed by users on any platform using any Web browser.

Delphi wizards allow you to easily create Active Server Pages. For more information about creating and using these types of objects, see "Creating an Active Server Page."

Active Documents

Active Documents (previously referred to as OLE documents) are a set of COM services that supports linking and embedding, drag-and-drop, and visual editing. Active Documents can seamlessly incorporate data or objects of different formats, for example, sound clips, spreadsheets, text, and bitmaps.

Unlike ActiveX controls, Active Documents are not limited to in-process servers; they can be used in cross-process applications.

Unlike Automation objects, which are almost never visual, Active Document objects can be visually active in another application. So, Active Document objects are associated with two types of data: presentation data, used for visually displaying the object on a display or output device, and native data, used to edit an object.

Active Document objects can be document containers or document servers. While Delphi does not provide an automatic wizard for creating Active Documents, you can use the VCL class, TOleContainer, to support linking and embedding in existing Active Documents.

You can also use TOleContainer as a basis for an Active Document container. To create objects for Active Document servers, use one of the VCL COM base classes and implement the appropriate interfaces for that object type, depending on the services the object needs to support. For more information about creating and using Active Document servers, see the Microsoft ActiveX Web site.

Note: While the specification for Active Documents has built-in support for marshaling for cross-process applications, Active Documents do not run on remote servers because they use types that are specific to a system on a given machine, for example, window handles, menu handles, and so on.

Visual cross-process objects

Automation objects, Active Documents and ActiveX controls are commonly used objects. Less common are OLE/ActiveX objects that are visually displayed and manipulated in a cross-process application. These types of objects are more difficult to create because the communication protocol involved in visually manipulating objects in cross-process applications is only standardized for visual objects that use Active Document interfaces. Therefore, you need to write one or more custom interfaces that your object implements, and then handle the marshaling interfaces yourself.

This can be done by either

Implementing COM objects with wizards

Delphi makes it easier to write COM applications by providing wizards to help create Delphi applications that run in the COM environment. It provides separate wizards to create the following:

The wizards automate the tasks involved in creating each type of COM object. They provide the required COM interfaces for each type of object. As shown in Figure 44.6, with a simple COM object, the wizard implements the one required COM interface, IUnknown, which provides an interface pointer to the object.

Figure 44.6   Simple COM object interface

As shown inFigure 44.7, for Automation objects, the wizard implements IUnknown and IDispatch, which provides automatic marshaling.

Figure 44.7   Automation object interface

As shown in Figure 44.8, for ActiveX control objects, the wizard implements all the required ActiveX control interfaces, from IUnknown, IDispatch, IOleObject, IOLEControl, and so on. For a complete list of interfaces, see the reference page for TActiveXControl object.

Figure 44.8   ActiveX object interface

You can think of the wizards as providing an increasing degree of implementation. As shown in Table 44.2, the various wizards implement the following COM interfaces:

Table 44.2   Delphi wizards for implementing COM, Automation, and ActiveX objects 

Wizard

Implemented interfaces

What the wizard does

COM server

IUnknown

Exports the necessary routines that handle server registration, class registration, loading and unloading the server, and object instantiation.

Creates and manages the class factories for objects implemented on the server.

Instructs COM to invoke object interfaces based on a specified threading model.

Provides a type library, if requested.

Automation server

IUnknown, IDispatch

Performs the tasks of a COM server wizard (described above), plus:

Implements the interface that you specify, either dual or dispatch.

Provides a type library automatically.

ActiveX Control

IUnknown, IDispatch, IPersistStreamInit, IOleInPlaceActiveObject, IPersistStorage, IViewObject, IOleObject, IViewObject2, IOleControl, IPerPropertyBrowsing, IOleInPlaceObject, ISpecifyPropertyPages

Performs the tasks of the COM server and Automation server wizards (described above), plus:

Implements the properties, methods, and events for all the interfaces in the TActiveXControl.

Leaves you in the source code editor so that you can modify the object.

ActiveForm

Same interfaces as ActiveX Control

Performs the tasks of the ActiveX control wizard, plus:

Implements the properties, methods, and events for all the interfaces in the TActiveXControl.

Leaves you with a form so that you can design an application.

Active Server Object

IUnknown, IDispatch

Performs the tasks of an Automation object wizard (described above) and generates an .ASP page which can be loaded into a Web browser. It leaves you in the Type Library editor so that you can modify the object's properties and methods if needed.

If you set the Active Server Type to Page-Level event methods, it implements OnStartPage and OnEndPage automatically for you.

ActiveX library

None, by default

Creates a new ActiveX or Com server DLL and exposes the necessary export functions.

Property Page

IUnknown, IPropertyPage

Creates a new property page that you can design in the Forms designer.

Type Library

None, by default

Creates a new type library and associates it with the active project.

MTS object

The IObjectControl interface methods, Activate, Deactivate, and CanBePooled.

Adds a new unit to the current project containing the MTS object definition, so that clients can access this server within the MTS runtime environment. It leaves you in the Type Library editor so that you can modify the object's properties and methods if needed.

If you want to add any additional COM objects (or reimplement any existing implementation), you can do so. To provide a new interface, you would create a descendant of the IDispatch interface and implement the needed methods in that descendant. To reimplement an interface, create a descendant of that interface and modify the descendant.