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 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.
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"
When implementing a COM application, you supply the following:
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:
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:
All COM objects must support the fundamental interface, called IUnknown, which contains the following routines:
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).
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.
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".
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.
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:
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.
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.
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."
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 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.
The following diagram illustrates the relationship of the COM extensions and how they are built upon COM:
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.
Automatically marshaled using the IDispatch interface (for out-of process and remote servers) | ||||
Automatically marshaled via a type library; otherwise, manually marshaled using custom interfaces |
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 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 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.
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:
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."
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.
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:
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.
Even if your application does not require a type library, you can consider the following benefits of using one:
The tools for working with type libraries are listed below.
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 (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.
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.
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.
As shown inFigure 44.7, for Automation objects, the wizard implements IUnknown and IDispatch, which provides automatic marshaling.
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.
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:
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.
pubsweb@inprise.com
Copyright © 1999, Inprise Corporation. All rights reserved.