Copyright: Copyright © 2001 Borland Software Corporation.                      All rights reserved.                                                 This Help file was compiled on   Friday, May 18, 2001 15:40:59.


Overview of COM Technologies
 DevGuide: Developing COM-based applications

Overview of COM Technologies

Topic groups	See also

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 clients or servers that implement COM objects, Automation servers (including Active Server Objects), ActiveX controls, or ActiveForms.

Note:	COM components such as those on the ActiveX, COM+, and Servers tabs of the Component palette are not available for use in CLX applications. This technology is for use on Windows only and is not cross-platform.

COM is a language-independent software component model that enables interaction between software components and applications running on a Windows platform. 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 for those features.

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

COM as a specification and implementation

COM is both a specification and an implementation. The COM specification defines how objects are created and how they communicate with each other. 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 built into the Win32 subsystem, 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.

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 in the AxCtrls unit.

Note:	Delphi’s interfaces and language follow the COM specification. Delphi implements objects conforming to the COM spec using a set of classes called the Delphi ActiveX framework (DAX). These classes are found in the AxCtrls, OleCtrls, and OleServer units. In addition, the Pascal interface to the COM API is in ActiveX.pas and ComSvcs.pas.

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 Documents, and Active Directories. For details on COM extensions, see COM extensions.

In addition, when working in a large, distributed environment, you can create transactional COM objects. Prior to Windows 2000, these objects were not architecturally part of COM, but rather ran in the Microsoft Transaction Server (MTS) environment. With the advent of Windows 2000, this support is integrated into COM+.

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
 DevGuide: Developing COM-based applications

Parts of a COM application

Topic groups

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 and properties. Note that COM properties are not identical to properties on VCL objects. COM properties always use read and write access methods.
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. Delphi eases the process in creating a client by letting you 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
 DevGuide: Developing COM-based applications

COM Interfaces

Topic groups	See also

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 as follows:

A COM interface

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

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:

Once published, interfaces are immutable; that is, they do not change. You can rely on an interface to provide a specific set of functions. Additional functionality is provided by additional interfaces.

By convention, COM interface identifiers begin with a capital I and a symbolic name that defines the interface, such as IMalloc or IPersist.

Interfaces are guaranteed to have a unique identification, called a Globally Unique Identifier (GUID), which is a 128-bit randomly generated number. Interface GUIDs are called Interface Identifiers (IIDs). This eliminates naming conflicts between different versions of a product or different products.

Interfaces are language independent. You can use any language to implement a COM interface as long as the language supports a structure of pointers, and can call a function through a pointer either explicitly or implicitly.

Interfaces are not objects themselves; they provide a way to access an object. Therefore, clients do not access data directly; clients access data through an interface pointer. Windows 2000 adds an additional layer of indirection known as an interceptor through which it provides COM+ features such as just-in-time activation and object pooling.

Interfaces are always inherited from the fundamental interface, IUnknown.

Interfaces can be redirected by COM through proxies to enable interface method calls to call between threads, processes, and networked machines, all without the client or server objects ever being aware of the redirection. For more information, see in-process, out-of-process, and remote servers.


The fundamental COM interface, IUnknown
 DevGuide: Developing COM-based applications

The fundamental COM interface, IUnknown

Topic groups	See also

All COM objects must support the fundamental interface, called IUnknown, a typedef to the base interface type IInterface. IUnknown 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
 DevGuide: Developing COM-based applications

COM interface pointers

Topic groups	See also

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 Object Pascal. Because of this similarity, the compiler can resolve calls to methods on the interface the same way it resolves calls to methods on Object Pascal classes.

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.

Interface vtable

In Windows 2000 and subsequent versions of Windows, when an object is running under COM+, an added level of indirection is provided between the interface pointer and the vtable pointer. The interface pointer available to the client points at an interceptor, which in turn points at the vtable. This allows COM+ to provide such services as just-in-time activation, whereby the server can be deactivated and reactivated dynamically in a way that is opaque to the client. To achieve this, COM+ guarantees that the interceptor behaves as if it were an ordinary vtable pointer.


COM servers
 DevGuide: Developing COM-based applications

COM servers

Topic groups	See also

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 and methods.

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.

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 identifies a COM object. COM uses this CLSID, which is registered in the system registry, to locate the appropriate server implementation. Once the server is located, COM brings the code into memory, and has the server instantiate an object instance for the client. This process is handled indirectly, through a special object called a class factory (based on interfaces) that creates instances of objects on demand.

As a minimum, a COM server must perform the following:

Register entries in the system registry that associate the server module with the class identifier (CLSID).

Implement a class factory object, which manufactures another object of a particular CLSID.

Expose the class factory to COM.

Provide an unloading mechanism through which a server that is not servicing clients can be removed from memory.

Note:	Delphi wizards automate the creation of COM objects and servers.


CoClasses and class factories
 DevGuide: Developing COM-based applications

Class factories

Topic groups	See also

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 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 an object instance for that particular client. Typically, if another client requests the object’s services, the class factory creates another object instance to service the second client. (Clients can also bind to running COM objects that register themselves to support it.)

A CoClass must have a class factory and a class identifier (CLSID) so that it 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 assigning class identifiers and of implementing and instantiating class factories.


In-process, out-of-process, and remote servers
 DevGuide: Developing COM-based applications

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

Topic groups	See also

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) to access interfaces and communicate with the application server.
As shown in the following figure, 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.

In-process servers

Note:	This is not always true under COM+. When a client makes a call to an object in a different context, COM+ intercepts the call so that it behaves like a call to an out-of-process server (see below), even if the server is in-process.

As shown in the following figure, 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.

Out-of-process and remote servers

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. DCOM transparently transfers a local object request to the remote object running on a different machine.

Note:	For remote procedure calls, DCOM uses the RPC protocol provided by Open Group’s Distributed Computing Environment (DCE). For distributed security, DCOM uses the NT LAN Manager (NTLM) security protocol. For directory services, DCOM uses the Domain Name System (DNS).


The marshaling mechanism
 DevGuide: Developing COM-based applications

The marshaling mechanism

Topic groups	See also

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

Takes an interface pointer in the server’s process and makes a proxy pointer available to code in the client process.

Transfers the arguments of an interface call as passed from the client and places the arguments into the remote object’s process space.

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 Automation Interfaces. Even if the object does not implement IDispatch, if it limits itself to automation-compatible types and has a registered type library, COM automatically provides marshaling support.

Applications that do not limit themselves to automation-compatible types or register a type library must provide their own marshaling. Marshaling is provided either through an implementation of the IMarshal interface, or by using a separately generated proxy/stub DLL. Delphi does not support the automatic generation of proxy/stub DLLs.


Aggregation
 DevGuide: Developing COM-based applications

Aggregation

Topic groups	See also

Sometimes, a server object makes use of another COM object to perform some of its functions. For example, an inventory management object might make use of a separate invoicing object to handle customer invoices. If the inventory management object wants to present the invoice interface to clients, however, there is a problem: Although a client that has the inventory interface can call QueryInterface to obtain the invoice interface, when the invoice object was created it did not know about the inventory management object and can’t return an inventory interface in response to a call to QueryInterface. A client that has the invoice interface can’t get back to the inventory interface.

To avoid this problem, some COM objects support aggregation. When the inventory management object creates an instance of the invoice object, it passes it a copy of its own IUnknown interface. The invoice object can then use that IUnknown interface to handle any QueryInterface calls that request an interface, such as the inventory interface, that it does not support. When this happens, the two objects together are called an aggregate. The invoice object is called the inner, or contained object of the aggregate, and the inventory object is called the outer object.

Note:	In order to act as the outer object of an aggregate, a COM object must create the inner object using the Windows API CoCreateInstance or CoCreateInstanceEx, passing its IUnknown pointer as a parameter that the inner object can use for QueryInterface calls.

In order to create an object that can act as the inner object of an aggregate, it must descend from TContainedObject. When the object is created, the IUnknown interface of the outer object is passed to the constructor so that it can be used by the QueryInterface method on calls that the inner object can’t handle.


COM clients
 DevGuide: Developing COM-based applications

COM Clients

Topic groups	See also

Clients can always query the interfaces of a COM object to determine what it is capable of providing. All COM objects allow clients to request known interfaces. In addition, if the server supports the IDispatch interface, clients can query the server for information about what methods the interface supports. Server objects have no expectations about the client using its objects. Similarly, clients don’t need to know how (or even where) an object provides the services; they simply rely on server objects to provide the services they advertise through their interfaces.

There are two types of COM clients, controllers and containers. Controllers launch the server and interact with it through its interface. They request services from the COM object or drive it as a separate process. Containers host visual controls or objects that appear in the container’s user interface. They use predefined interfaces to negotiate display issues with server objects. It is impossible to have a container relationship over DCOM; for example, visual controls that appear in the container's user interface must be located locally. This is because the controls are expected to paint themselves, which requires that they have access to local GDI resources.

Delphi makes it easier for you to develop COM clients by letting you import a type library or ActiveX control into a component wrapper so that server objects look like other VCL components. For details on this process, see Creating COM clients.


COM extensions
 DevGuide: Developing COM-based applications

COM extensions

Topic groups

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.

The following lists some of the services COM extensions currently provide.

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.
ActiveX controls	ActiveX controls are specialized in-process servers, typically intended for embedding in a client application. The controls offer both design and runtime behaviors as well as events.
Active Server Pages	Active Server Pages are scripts that generate HTML pages. The scripting language includes constructs for creating and running Automation objects. That is, the Active Server Page acts as an Automation controller.
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.
Transactional objects	Objects that include additional support for responding to large numbers of clients. This includes features such as just-in-time activation, transactions, resource pooling, and security services. These features were originally handled by MTS but have been built into COM with the advent of COM+.
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, ActiveX controls, and transactional objects expect type information to be available.
The following diagram illustrates the relationship of the COM extensions and how they are built upon COM:

COM 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. The following table 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.

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
MTS or COM+	Occasionally	In-process for MTS, any for COM+	Automatically marshaled via a type library	Required
In-process custom interface object	Optionally	In-process	No marshaling required for in-process servers	Recommended
Other 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
 DevGuide: Developing COM-based applications

Automation

Topic groups	See also

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 server object being manipulated is called the Automation object, and the client of the Automation object is referred to as an Automation controller.

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

Automation is characterized by two key points:

The Automation object defines a set of properties and commands, and describes their capabilities through type descriptions. In order to do this, it must have a way to provide information about its interfaces, the interface methods, and those methods’ arguments. Typically, this information is available in a type library. The Automation server can also generate type information dynamically when queried via its IDispatch interface (see following).

Automation objects make their methods accessible so that other applications can use them. For this, they implement the IDispatch interface. Through this interface an object can expose all of its methods and properties. Through the primary method of this interface, the object’s methods can be invoked, once having been identified through type information.

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 Valid types.


Active Server Pages
 DevGuide: Developing COM-based applications

Active Server Pages

Topic groups	See also

The Active Server Page (ASP) technology lets you write simple scripts, called Active Server Pages, that can be launched by clients via a Web server. Unlike ActiveX controls, which run on the client, Active Server Pages run on the server, and return a resulting HTML page to clients.

Active Server Pages are written in Jscript or VB script. The script runs every time the server loads the Web page. That script can then launch an embedded Automation server (or Enterprise Java Bean). For example, you can write an Automation server, such as one to create a bitmap or connect to a database, and this server accesses data that gets updated every time a client loads the Web page.

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

Delphi wizards let you create an Active Server Object, which is an Automation object specifically designed to work with an Active Server Page.


ActiveX controls
 DevGuide: Developing COM-based applications

ActiveX controls

Topic groups

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.

ActiveX controls are visual controls that run only as 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 have a visible user interface, and rely on predefined interfaces to negotiate I/O and display issues with their host containers.

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.

One use of ActiveX controls is on a Web site as interactive objects in a Web page. As such, ActiveX is a standard that targets 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.


Active Documents
 DevGuide: Developing COM-based applications

Active Documents

Topic groups

Active Documents (previously referred to as OLE documents) are a set of COM services that support linking and embedding, drag-and-drop, and visual editing. Active Documents can seamlessly incorporate data or objects of different formats, such as 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. Thus, 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 of existing Active Documents.

You can also use TOleContainer as a basis for an Active Document container. To create objects for Active Document servers, use the COM object wizard and add the appropriate interfaces, 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 in 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 such as window handles, menu handles, and so on.


Transactional objects
 DevGuide: Developing COM-based applications

Transactional objects

Topic groups	See also

Delphi uses the term “transactional objects” to refer to objects that take advantage of the transaction services, security, and resource management supplied by Microsoft Transaction Server (MTS) (for versions of Windows prior to Windows 2000) or COM+ (for Windows 2000 and later). These objects are designed to work in a large, distributed environment.

The transaction services provide robustness so that activities are always completed or rolled back (the server never partially completes an activity). The security services allow you to expose different levels of support to different classes of clients. The resource management allows an object to handle more clients by pooling resources or keeping objects active only when they are in use. To enable the system to provide these services, the object must implement the IObjectControl interface. To access the services, transactional objects use an interface called IObjectContext, which is created on their behalf by MTS or COM+.

Under MTS, the server object must be built into a library (DLL), which is then installed in the MTS runtime environment. That is, the server object is an in-process server that runs in the MTS runtime process space. Under COM+, this restriction does not apply because all COM calls are routed through an interceptor. To clients, the difference between MTS and COM+ is transparent.

MTS or COM+ servers group transactional objects that run in the same process space. Under MTS, this group is called an MTS package, while under COM+ it is called a COM+ application. A single machine can be running several different MTS packages (or COM+ applications), where each one is running in a separate process space.

To clients, the transactional object may appear like any other COM server object. The client need never know about transactions, security, or just-in-time activation unless it is initiating a transaction itself.

Both MTS and COM+ provide a separate tool for administering transactional objects. This tool lets you configure objects into packages or COM+ applications, view the packages or COM+ applications installed on a computer, view or change the attributes of the included objects, monitor and manage transactions, make objects available to clients, and so on. Under MTS, this tool is the MTS Explorer. Under COM+ it is the COM+ Component Manager.


Type libraries
 DevGuide: Developing COM-based applications

Type libraries

Topic groups	See also

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, ActiveX controls, and transactional objects expect type information to be available. All of Delphi’s wizards generate a type library automatically, although the COM object wizard makes this optional. You can view or edit this type information by using the Type Library Editor.

The following topics provide more details about type libraries:

Contents of type libraries

Creating type libraries

When to use type libraries

Accessing type libraries

Benefits of using type libraries

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:

Descriptions of custom type information associated with custom interfaces

Routines that are exported by the Automation or ActiveX server, but that are not interface methods

Information about enumeration, record (structures), unions, alias, and module data types

References to type descriptions from other type libraries

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 you create a COM object (including ActiveX controls, Automation objects, remote data modules, and so on) using any of the wizards on the ActiveX or Multitier page of the new items dialog. (You can opt not to create a type library when using the COM object wizard.) You can also create a type library by choosing from the main menu, File|New|Other, select the ActiveX tab, and choose Type Library.

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 corresponding .tlb file (binary type library file) when the type library is saved. For any changes to Interfaces and CoClasses that were created using a wizard, the Type Library editor also updates your implementation files.

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,

ActiveX controls require a type library, which must be included as a resource in the DLL that contains the ActiveX controls.

Exposed objects that support vtable binding of custom interfaces must be described in a type library because vtable references are bound at compile time. Clients import information about the interfaces from the type library and use that information to compile. For more information about vtable and compile time binding, see Automation interfaces.

Applications that implement Automation servers should provide a type library so that clients can early bind to it.

Objects instantiated from classes that support the IProvideClassInfo interface, such as all descendants of the VCL TTypedComObject class, must have a type library.

Type libraries are not required, but are useful for identifying the objects used with OLE drag-and-drop.

When defining interfaces for internal use only (within an application) you do not need to create a type library. For more information on how to define an interface directly in Object Pascal, see Interface types.

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. When included in a resource file, the type library can be bound into a server (.dll, .ocx, or .exe).

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.
ITypeLib2	Augments ITypeLib to include support for documentation strings, custom data, and statistics about the type library.
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.
ITypeInfo2	Augments ITypeInfo to access additional type library information, including methods for accessing custom data elements.
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 by choosing Project|Import Type Library. 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:

Type checking can be performed at compile time.

You can use early binding with Automation, and controllers that do not support vtables or dual interfaces can encode dispIDs at compile time, improving runtime performance.

Type browsers can scan the library, so clients can see the characteristics of your objects.

The RegisterTypeLib function can be used to register your exposed objects in the registration database.

The UnRegisterTypeLib function can be used to completely uninstall an application’s type library from the system registry.

Local server access is improved because Automation uses information from the type library to package the parameters that are passed to an object in another process.

Using type library tools

The tools for working with type libraries are listed below.

The TLIBIMP (Type Library Import) tool, which takes existing type libraries and creates Delphi Interface files (_TLB.pas files), is incorporated into the Type Library editor. TLIBIMP provides additional configuration options not available inside the Type Library editor.

TRegSvr is a tool for registering and unregistering servers and type libraries, which comes with Delphi. The source to TRegSvr is available as an example in the Demos directory.

The Microsoft IDL compiler (MIDL) compiles IDL scripts to create a type library.

RegSvr32.exe is a tool for registering and unregistering servers and type libraries, which is a standard Windows utility.

OLEView is a type library browser tool, found on Microsoft’s Web site.


Implementing COM objects with Wizards
 DevGuide: Developing COM-based applications

Implementing COM objects with wizards

Topic groups	See also

Delphi makes it easier to write COM server applications by providing wizards that handle many of the details involved. Delphi provides separate wizards to create the following:

A simple COM object

An Automation object

An Active Server Object (for embedding in an Active Server page)

An ActiveX control

An ActiveX Form

A transactional object

A Property page

A Type library

An ActiveX library

The wizards handle many of the tasks involved in creating each type of COM object. They provide the required COM interfaces for each type of object. With  a simple COM object, the wizard implements the one required COM interface, IUnknown, which provides an interface pointer to the object.

Simple COM object interface

The COM object wizard also provides an implementation for IDispatch if you specify that you are creating an object that supports an IDispatch descendant.

For Automation and Active Server objects, the wizard implements IUnknown and IDispatch, which provides automatic marshaling.

Automation object interface

For ActiveX control objects and ActiveX forms, 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.

ActiveX control interface

The following table lists the various wizards and the interfaces they implement:

Wizard	Implemented interfaces	What the wizard does
COM server	IUnknown (and IDispatch if you select a default interface that descends from IDispatch)	Exports routines that handle server registration, class registration, loading and unloading the server, and object instantiation.  Creates and manages class factories for objects implemented on the server.  Provides registry entries for the object that specify the selected threading model. Declares the methods that implement a selected interface, providing skeletal implementations for you to complete. Provides a type library, if requested. Allows you to select an arbitrary interface that is registered in the type library and implement it. If you do this, you must use a type library.
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 server-side support for generating events, if requested. Provides a type library automatically.
Active Server Object	IUnknown, IDispatch, (IASPObject)	Performs the tasks of an Automation object wizard (described above) and optionally 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. Surfaces the ASP intrinsics as properties so that you can easily obtain information about the ASP application and the HTTP messages that launched it.
ActiveX Control	IUnknown, IDispatch, IPersistStreamInit, IOleInPlaceActiveObject, IPersistStorage, IViewObject, IOleObject, IViewObject2, IOleControl, IPerPropertyBrowsing, IOleInPlaceObject, ISpecifyPropertyPages	Performs the tasks of the Automation server wizard (described above), plus: Generates a CoClass that corresponds to the VCL control on which the ActiveX control is based and which implements all the ActiveX interfaces. Leaves you in the source code editor so that you can modify the implementation class.
ActiveForm	Same interfaces as ActiveX Control	Performs the tasks of the ActiveX control wizard, plus: Creates a TActiveForm descendant that takes the place of the pre-existing VCL class in the ActiveX control wizard. This new class lets you design the Active Form the same way you design a form in a Windows application.
Transactional object	IUnknown, IDispatch, IObjectControl	Adds a new unit to the current project containing the MTS or COM+ object definition. It inserts proprietary GUIDs into the type library so that Delphi can install the object properly, and leaves you in the Type Library editor so that you can define the interface that the object exposes to clients. You must install the object separately after it is built.
Property Page	IUnknown, IPropertyPage	Creates a new property page that you can design in the Forms designer.
COM+ Event object	None, by default	Creates a COM+ event object that you can define using the Type Library editor. Unlike the other object wizards, the COM+ Event object wizard does not create an implementation unit because event objects have no implementation (it is provided by client sinks).
Type Library	None, by default	Creates a new type library and associates it with the active project.
ActiveX library	None, by default	Creates a new ActiveX or Com server DLL and exposes the necessary export functions.
You can add additional COM objects or reimplement an existing implementation. To add a new object, it is easiest to use the wizard a second time. This is because the wizard sets up an association between the type library and an implementation class, so that changes you make in the type library editor are automatically applied to your implementation object.


Code generated by wizards
 DevGuide: Developing COM-based applications

Code generated by wizards

Topic groups

Delphi’s wizards generate classes that are derived from the Delphi ActiveX framework (DAX). Despite its name, the Delphi ActiveX framework supports all types of COM objects, not just ActiveX controls. The classes in this framework provide the underlying implementation of the standard COM interfaces for the objects you create using a wizard. The following figure illustrates the objects in the Delphi ActiveX framework:

Delphi ActiveX framework

Each wizard generates an implementation unit that implements your COM server object. The COM server object (the implementation object) descends from one of the classes in DAX:

Wizard	Base class from DAX	Inherited support
COM server	TTypedCOMObject	Support for IUnknown and ISupportErrorInfo interfaces. Support for aggregation, OLE exception handling, and safecall calling convention on dual interfaces.  Support for reading type library information.
Automation server or Active Server Object	TAutoObject	Everything provided by TTypedCOMObject, plus: Support for the IDispatch interface. Auto-marshaling support.
ActiveX Control	TActiveXControl	Everything provided by TAutoObject, plus: Support for embedding in a container. Support for in-place activation. Support for properties and property pages. The ability to delegate to an associated windowed control that it creates.
ActiveForm	TActiveFormControl	Everything provided by TAutoObject, except that it works with a descendant of TActiveForm rather than another windowed control class.
MTS object	TMTSAutoObject	Everything provided by TAutoObject, plus: Support for the IObjectControl interface.
Property Page	TPropertyPage	Support for IUnknown and ISupportErrorInfo interfaces. Support for aggregation, OLE exception handling, and safecall calling convention on dual interfaces.  Support for the IPropertyPage interface.
Corresponding to the classes in DAX is a hierarchy of class factory objects that handle the creation of these COM objects. The wizard adds code to the initialization section of your implementation unit that instantiates the appropriate class factory for your implementation class.

The wizards also generate a type library and its associated unit, which has a name of the form Project1_TLB. The Project1_TLB unit includes the definitions your application needs to use the type definitions and interfaces defined in the type library. For more information on the contents of this file, see Code generated when you import type library information.

You can modify the interface generated by the wizard using the type library editor. When you do this, the implementation class is automatically updated to reflect those changes. You need only fill in the bodies of the generated methods to complete the implementation.


Working with type libraries: Overview
 DevGuide: Developing COM-based applications

Working with type libraries

Topic groups	See also

Type libraries are files that include information about data types, interfaces, member functions, and object classes exposed by a COM object. They provide a way to identify what types of objects and interfaces are available on a server. For a detailed overview on why and when to use type libraries, see Type libraries.

A type library can contain any and all of the following:

Information about custom data types such as aliases, enumerations, structures, and unions.

Descriptions of one or more COM elements, such as an interface, dispinterface, or CoClass. Each of these descriptions is commonly referred to as type information.

Descriptions of constants and methods defined in external units.

References to type descriptions from other type libraries.

By including a type library with your COM application or ActiveX library, you make information about the objects in your application available to other applications and programming tools through COM’s type library tools and interfaces.

With traditional development tools, you create type libraries by writing scripts in the Interface Definition Language (IDL) or the Object Description Language (ODL), then run that script through a compiler. The Type Library editor automates some of this process, easing the burden of creating and modifying your own type libraries.

When you create a COM server of any type (ActiveX control, Automation object, remote data module, and so on) using Delphi’s wizards, the wizard automatically generates a type library for you (although in the case of the COM object wizard, this is optional). Most of the work you do in customizing the generated object starts with the type library, because that is where you define the properties and methods it exposes to clients: you change the interface of the CoClass generated by the wizard, using the Type Library editor. The Type Library editor automatically updates the implementation unit for your object, so that all you need do is fill in the bodies of the generated methods.

You can also use the Delphi Type Library Editor in the development of Common Object Request Broker Architecture (CORBA) applications. With traditional CORBA tools, you must define object interfaces separately from your application, using the CORBA Interface Definition Language (IDL). You then run a utility that generates stub-and-skeleton code from that definition. However, Delphi generates the stub, skeleton, and IDL for you automatically. You can easily edit your interface using the Type Library editor and Delphi automatically updates the appropriate source files.


Type Library editor
 DevGuide: Developing COM-based applications

Type Library editor

Topic groups	See also

The Type Library editor enables developers to examine and create type information for COM objects. Using the Type Library editor can greatly simplify the task of developing COM objects by centralizing the tasks of defining interfaces, CoClasses, and types, obtaining GUIDs for new interfaces, associating interfaces with CoClasses, updating implementation units, and so on.

Note:	The Type Library editor is also used to define CORBA interfaces in projects that use the CORBA Object or CORBA Data Module wizard.

The Type Library editor outputs two types of file that represent the contents of the type library:

File	Description
.TLB file	The binary type library file. By default, you do not need to use this file, because the type library is automatically compiled into the application as a resource. However, you can use this file to explicitly compile the type library into another project or to deploy the type library separately from the .exe or .ocx. For more information, see Opening an existing type library and Deploying type libraries. Note: When using the Type Library editor for CORBA interfaces, the Type Library editor does not create the .tlb file.
_TLB unit	This unit interprets the contents of the type library for use by your application. It contains all the declarations your application needs to use the elements defined in the type library. Although you can open this file in the code editor, you should never edit it—it is maintained by the Type Library editor, so any changes you make will be overwritten by the Type Library editor. For more details on the contents of this file, see Code generated when you import type library information Note: When using the Type Library editor for CORBA interfaces, this unit defines the stub and skeleton objects required by the CORBA application.
The following topics describe the Type Library editor in greater detail:

Parts of the Type Library editor

Using the Type Library editor


Parts of the Type Library editor
 DevGuide: Developing COM-based applications

Parts of the Type Library editor

Topic groups	See also

The main elements of the Type Library editor are described in the following table:

Part	Description
Toolbar	Includes buttons to add new types, CoClasses, interfaces, and interface members to your type library. The toolbar also includes buttons for refreshing your implementation unit, registering the type library, and saving an IDL file with the information in your type library.
Object list pane	Displays all the existing elements in the type library. When you click on an item in the object list pane, it displays pages valid for that object.
Status bar	Displays syntax errors if you try to add invalid types to your type library.
Pages	Display information about the selected object. Which pages appear here depends on the type of object selected.
These parts are illustrated in the following table, which shows the Type Library editor displaying type information for a COM object named cyc.


Toolbar
 DevGuide: Developing COM-based applications

Toolbar

Topic groups	See also

The Type Library editor’s toolbar located at the top of the Type Library Editor, contains buttons that you click to add new objects into your type library.

The first group of buttons let you add elements to the type library. When you click a toolbar button, the icon for that element appears in the object list pane. You can then customize its attributes in the right pane. Depending on the type of icon you select, different pages of information appear to the right.

The following table lists the elements you can add to your type library:

Icon	Meaning
	An interface description.
	A dispinterface description. (not used for CORBA interface definitions)
	A CoClass.
	An enumeration.
	An alias.
	A record.
	A union.
	A module.
When you select one of the elements listed above in the object list pane, the second group of buttons displays members that are valid for that element. For example, when you select Interface, the Method and Property icons in the second box become enabled because you can add methods and properties to your interface definition. When you select Enum, the second group of buttons changes to display the Const member, which is the only valid member for Enum type information.

The following table lists the members that can be added to elements in the object list pane:

Icon	Meaning
	A method of the interface, dispinterface, or an entry point in a module.
	A property on an interface or dispinterface.
	A write-only property. (available from the drop-down list on the property button)
	A read-write property. (available from the drop-down list on the property button)
	A read-only property. (available from the drop-down list on the property button)
	A field in a record or union.
	A constant in an enum or a module.
In the third box, you can choose to refresh, register, or export your type library (save it as an IDL file).


Object list pane
 DevGuide: Developing COM-based applications

Object list pane

Topic groups	See also

The Object list pane displays all the elements of the current type library in a tree view. The root of the tree represents the type library itself, and appears as the following icon:

Descending from the type library node are the elements in the type library:

When you select any of these elements (including the type library itself), the pages of type information to the right change to reflect only the relevant information for that element. You can use these pages to edit the definition and properties of the selected element.

You can manipulate the elements in the object list pane by right clicking to get the object list pane context menu. This menu includes commands that let you use the Windows clipboard to move or copy existing elements as well as commands to add new elements or customize the appearance of the Type Library editor.


Status bar
 DevGuide: Developing COM-based applications

Status bar

Topic groups	See also

When editing or saving a type library, syntax, translation errors, and warnings are listed in the Status bar pane.

For example, if you specify a type that the Type Library editor does not support, you will get a syntax error. For a complete list of types supported by the Type Library editor, see Valid types.


Pages of type information
 DevGuide: Developing COM-based applications

Pages of type information

Topic groups	See also

When you select an element in the object list pane, pages of type information appear in the Type Library editor that are valid for the selected element. Which pages appear depends on the element selected in the object list panel, as follows:

Type Info element	Page of type information	Contents of page
Type library	Attributes	Name, version, and GUID for the type library, as well as information linking the type library to help.
	Uses	List of other type libraries that contain definitions on which this one depends.
	Flags	Flags that determine how other applications can use the type library.
	Text	All definitions and declarations defining the type library itself (see discussion below).
Interface	Attributes	Name, version, and GUID for the interface, the name of the interface from which it descends, and information linking the interface to help.
	Flags	Flags that indicate whether the interface is hidden, dual, Automation-compatible, and/or extensible.
	Text	The definitions and declarations for the Interface (see discussion below).
Dispinterface	Attributes	Name, version, and GUID for the interface, and information linking it to help.
	Flags	Flags that indicate whether the Dispinterface is hidden, dual, and/or extensible.
	Text	The definitions and declarations for the Dispinterface. (see discussion below).
CoClass	Attributes	Name, version, and GUID for the CoClass, and information linking it to help.
	Implements	A List of interfaces that the CoClass implements, as well as their attributes.
	COM+	The attributes of transactional objects, such as the transaction model, call synchronization, just-in-time activation, object pooling, and so on. Also includes the attributes of COM+ event objects.
	Flags	Flags that indicate various attributes of the CoClass, including how clients can create and use instances, whether it is visible to users in a browser, whether it is an ActiveX control, and whether it can be aggregated (act as part of a composite).
	Text	The definitions and declarations for the CoClass (see discussion below).
Enumeration	Attributes	Name, version, and GUID for the enumeration, and information linking it to help.
	Text	The definitions and declarations for the enumerated type (see discussion below).
Alias	Attributes	Name, version, and GUID for the enumeration, the type the alias represents, and information linking it to help.
	Text	The definitions and declarations for the alias (see discussion below).
Record	Attributes	Name, version, and GUID for the record, and information linking it to help.
	Text	The definitions and declarations for the record (see discussion below).
Union	Attributes	Name, version, and GUID for the union, and information linking it to help.
	Text	The definitions and declarations for the union (see discussion below).
Module	Attributes	Name, version, GUID, and associated DLL for the module, and information linking it to help.
	Text	The definitions and declarations for the module (see discussion below).
Method	Attributes	Name, dispatch ID or DLL entry point, and information linking it to help.
	Parameters	Method return type, and a list of all parameters with their types and any modifiers.
	Flags	Flags to indicate how clients can view and use the method, whether this is a default method for the interface, and whether it is replaceable.
	Text	The definitions and declarations for the method (see discussion below).
Property	Attributes	Name, dispatch ID, type of property access method (getter vs. setter), and information linking it to help.
	Parameters	Property access method return type, and a list of all parameters with their types and any modifiers.
	Flags	Flags to indicate how clients can view and use the property, whether this is a default for the interface, whether the property is replaceable, bindable, and so on.
	Text	The definitions and declarations for the property access method (see discussion below).
Const	Attributes	Name, value, type (for module consts), and information linking it to help.
	Flags	Flags to indicate how clients can view and use the constant, whether this represents a default value, whether the constant is bindable, and so on.
	Text	The definitions and declarations for the constant (see discussion below).
Field	Attributes	Name, type, and information linking it to help.
	Flags	Flags to indicate how clients can view and use the field, whether this represents a default value, whether the field is bindable, and so on.
	Text	The definitions and declarations for the field (see discussion below).
You can use each of the pages of type information to view or edit the values it displays. Most of the pages organize the information into a set of controls so that you can type in values or select them from a list without requiring that you know the syntax of the corresponding declarations. This can prevent many small mistakes such as typographic errors when specifying values from a limited set. However, you may find it faster to type in the declarations directly. To do this, use the Text page.

All type library elements have a text page that displays the syntax for the element. This syntax appears in an IDL subset of Microsoft Interface Definition Language, or Object Pascal. See Using Object Pascal or IDL syntax for details. Any changes you make in other pages of the element are reflected on the text page. If you add code directly in the text page, changes are reflected in the other pages of the Type Library editor.

The Type Library editor generates syntax errors if you add identifiers that are currently not supported by the editor; the editor currently supports only those identifiers that relate to type library support (not RPC support or constructs used by the Microsoft IDL compiler for C++ code generation or marshaling support).


Pages of type information
 DevGuide: Developing COM-based applications

Pages of type information

Topic groups	See also

The Type Library interface can seem overwhelmingly complicated at first. This is because it represents information about a great number of elements, each of which has its own characteristics. However, many of these characteristics are common to all elements. For example, every element (including the type library itself) has the following:

A Name, which is used to describe the element and which is used when referring to the element in code.

A GUID (globally unique identifier), which is a globally unique 128-bit value that COM uses to identify the element. This should always be supplied for the type library itself and for CoClasses and interfaces. It is optional otherwise.

A Version number, which distinguishes between multiple versions of the element. This is always optional, but should be provided for CoClasses and interfaces, because some tools can’t use them without a version number.

Information linking the element to a Help topic. These include a Help String, and Help Context or Help String Context value. The Help Context is used for a traditional Windows Help system where the type library has a stand-alone Help file. The Help String Context is used when help is supplied by a separate DLL instead. The Help Context or Help String Context refers to a Help file or DLL that is specified on the type library’s Attributes page. This is always optional.

Interfaces

An interface describes the methods (and any properties expressed as ‘get’ and ‘set’ functions) for an object that must be accessed through a virtual function table (VTable). If an interface is flagged as dual, a dispinterface is also implied and can be accessed through OLE automation. By default, the type library flags all interfaces you add as dual.

Interfaces can be assigned members: methods and properties. These appear in the object list pane as children of the interface node. Properties for interfaces are represented by the ‘get’ and ‘set’ methods used to read and write the property’s underlying data. They are represented in the tree view using special icons that indicate their purpose.

	A write (set, put) by value property function.
	A read (get) |write (set, put)|write by reference property function.
	A read (get) property function.
Note:	When a property is specified as Write By Reference, it means it is passed as a pointer rather than by value. Some applications, such a Visual Basic, use Write By Reference, if it is present, to optimize performance. To pass the property only by reference rather than by value, use the property type By Reference Only. To pass the property by reference as well as by value, select Read|Write|Write By Ref. To invoke this menu, go to the toolbar and select the arrow next to the property icon.

Once you add the properties or methods using the toolbar button or the object list pane context menu, you desribe their syntax and attributes by selecting the property or method and using the pages of type information.

The Attributes page lets you give the property or method a name and dispatch ID (so that it can be called using IDispatch). For properties, you also assign a type. The function signature is created using the Parameters page, where you can add, remove, and rearrange parameters, set their type and any modifiers, and specify function return types.

Note:	Members of interfaces that need to raise exceptions should return an HRESULT and specify a return value parameter (PARAM_RETVAL) for the actual return value. Declare these methods using the safecall calling convention.

Note that when you assign properties and methods to an interface, they are implicitly assigned to its associated CoClass. This is why the Type Library editor does not let you add properties and methods directly to a CoClass.

Dispinterfaces

Interfaces are more commonly used than dispinterfaces to describe the properties and methods of an object. Dispinterfaces are only accessible through dynamic binding, while interfaces can have static binding through a vtable.

You can add methods and properties to dispinterfaces in the same way you add them to interfaces. However, when you create a property for a dispinterface, you can’t specify a function kind or parameter types.

CoClasses

A CoClass describes a unique COM object that implements one or more interfaces. When defining a CoClass, you must specify which implemented interface is the default for the object, and optionally, which dispinterface is the default source for events. Note that you do not add properties or methods to a CoClass in the Type Library editor. Properties and methods are exposed to clients by interfaces, which are associated with the CoClass using the Implements page.

Type definitions

Enumerations, aliases, records, and unions all declare types that can then be used elsewhere in the type library.

Enums consist of a list of constants, each of which must be numeric. Numeric input is usually an integer in decimal or hexadecimal format. The base value is zero by default. You can add constants to your enumeration by selecting the enumeration in the object list pane and clicking the Const button on the toolbar or selecting New|Const command from the object list pane context menu.

Note:	It is strongly recommended that you provide help strings for your enumerations to make their meaning clearer. The following is a sample entry of an enumeration type for a mouse button and includes a help string for each enumeration element.

mbLeft = 0 [helpstring 'mbLeft'];

mbRight = 1 [helpstring 'mbRight'];

mbMiddle = 3 [helpstring 'mbMiddle'];

An alias creates an alias (type definition) for a type. You can use the alias to define types that you want to use in other type info such as records or unions. Associate the alias with the underlying type definition by setting the Type attribute on the Attributes page.

A record consists of a list of structure members or fields. A union is a record with only a variant part. Like a record, a union consists of a list of structure members or fields. However, unlike the members of records, each member of a union occupies the same physical address, so that only one logical value can be stored.

Add the fields to a record or union by selecting it in the object list pane and clicking the field button in the toolbar or right clicking and choosing field from the object list pane context menu. Each field has a name and a type, which you assign by selecting the field and assigning values using the Attributes page. Records and unions can be defined with an optional tag.

Members can be of any built-in type, or you can specify a type using alias before you define the record.

Modules

A module defines a group of functions, typically a set of DLL entry points. You define a module by

Specifying a DLL that it represents on the attributes page.

Adding methods and constants using the toolbar or the object list pane context menu. For each method or constant, you must then define its attributes by selecting the it in the object list pane and setting the values on the Attributes page.

For module methods, you must assign a name and DLL entry-point using the attributes page. Declare the function’s parameters and return type using the parameters page.

For module constants, use the Attributes page to specify a name, type, and value.

Note:	The Type Library editor does not generate any declarations or implementation related to a module. The specified DLL must be created as a separate project.


Using the Type Library editor
 DevGuide: Developing COM-based applications

Using the Type Library editor

Topic groups	See also

Using the type library editor, you can create new type libraries or edit existing ones. Typically, an application developer uses a wizard to create the objects that are exposed in the type libarary, letting Delphi generate the type library automatically. Then, the automatically-generated type library is opened in the Type Library editor so that the interfaces can be defined (or modified), type definitions added, and so on.

However, even if you are not using a wizard to define the objects, you can use the Type Library editor to define a new type library. In this case, you must create any implementation classes yourself, because the Type Library editor does not generate code for CoClasses that were not associated with a type library by a wizard.

The editor supports a subset of valid types in a type library

The following topics describe how to:

Create a new type library

Open an existing type library

Add an interface to the type library

Modify an interface

Add properties and methods to the type library

Add a CoClass to the type library

Add an interface to a CoClass

Add an enumeration to the type library

Add an alias to the type library

Add a record or union to the type library

Add a module to the type library

Save and register type library information


Valid types
 DevGuide: Developing COM-based applications

Valid types

Topic groups	See also

In the Type Library editor, you use different type identifiers, depending on whether you are working in IDL or Object Pascal. Specify the language you want to use in the Environment options dialog.

The following types are valid in a type library for COM development. The Automation compatible column specifies whether the type can be used by an interface that has its Automation or Dispinterface flag checked. These are the types that COM can marshal via the type library automatically.

Pascal type	IDL type	variant type	Automation compatible	Description
Smallint	short	VT_I2	Yes	2-byte signed integer
Integer	long	VT_I4	Yes	4-byte signed integer
Single	single	VT_R4	Yes	4-byte real
Double	double	VT_R8	Yes	8-byte real
Currency	CURRENCY	VT_CY	Yes	currency
TDateTime	DATE	VT_DATE	Yes	date
WideString	BSTR	VT_BSTR	Yes	binary string
IDispatch	IDispatch	VT_DISPATCH	Yes	pointer to IDispatch interface
SCODE	SCODE	VT_ERROR	Yes	Ole Error Code
WordBool	VARIANT_BOOL	VT_BOOL	Yes	True = -1, False = 0
OleVariant	VARIANT	VT_VARIANT	Yes	Ole Variant
IUnknown	IUnknown	VT_UNKNOWN	Yes	pointer to IUnknown interface
Shortint	byte	VT_I1	No	1 byte signed integer
Byte	unsigned char	VT_UI1	Yes	1 byte unsigned integer
Word	unsigned short	VT_UI2	Yes*	2 byte unsigned integer
LongWord	unsigned long	VT_UI4	Yes*	4 byte unsigned integer
Int64	__int64	VT_I8	No	8 byte signed integer
Largeuint	uint64	VT_UI8	No	8 byte unsigned integer
SYSINT	int	VT_INT	Yes*	system dependent integer (Win32=Integer)
SYSUINT	unsigned int	VT_UINT	Yes*	system dependent unsigned integer
HResult	HRESULT	VT_HRESULT	No	32 bit error code
Pointer		VT_PTR -> VT_VOID	No	untyped pointer
SafeArray	SAFEARRAY	VT_SAFEARRAY	No	OLE Safe Array
PChar	LPSTR	VT_LPSTR	No	pointer to Char
PWideChar	LPWSTR	VT_LPWSTR	No	pointer to WideChar
* Word, LongWord, SYSINT, and SYSUINT may be Automation-compatible with some applications.

See safe arrays for more information about the SAFEARRAY Variant type.

Note:	The Byte (VT_UI1) is Automation-compatible, but is not allowed in a Variant or OleVariant since many Automation servers do not handle this value correctly.

Defining Object Interfaces.Besides these IDL types, any interfaces and types defined in the library or defined in referenced libraries can be used in a type library definition.

The Type Library editor stores type information in the generated type library (.TLB) file in binary form.

If a parameter type is specified as a Pointer type, the Type Library editor usually translates that type into a variable parameter. When the type library is saved, the variable parameter’s associated ElemDesc’s IDL flags are marked IDL_FIN or IDL_FOUT.

Often, ElemDesc IDL flags are not marked by IDL_FIN or IDL_FOUT when the type is preceded with a Pointer. Or, in the case of dispinterfaces, IDL flags are not typically used. In these cases, you may see a comment next to the variable identifier such as {IDL_None} or {IDL_In}. These comments are used when saving a type library to correctly mark the IDL flags.


SafeArrays
 DevGuide: Developing COM-based applications

SafeArrays

Topic groups	See also

COM requires that arrays be passed via a special data type known as a SafeArray. You can create and destroy SafeArrays by calling special COM functions to do so, and all elements within a SafeArray must be valid automation-compatible types. The Delphi compiler has built-in knowledge of COM SafeArrays and automatically calls the COM API to create, copy, and destroy SafeArrays.

In the Type Library editor, a SafeArray must specify the type of its elements. For example, the following line from the text page declares a method with a parameter that is a SafeArray with an element type of Integer:

procedure HighLightLines(Lines: SafeArray of Integer);

Note:	Although you must specify the element type when declaring a SafeArray type in the Type Library editor, the declaration in the generated _TLB unit does not indicate the element type.


Using Object Pascal or IDL syntax
 DevGuide: Developing COM-based applications

Using Object Pascal or IDL syntax

Topic groups	See also

The Text page of the Type Library editor displays your type information in one of two ways:

Using an extension of Object Pascal syntax.

Using the Microsoft IDL.

Note:	When working on a CORBA object, you use neither of these on the text page. Instead, you must use the CORBA IDL.

You can select which language you want to use by changing the setting in the Environment Options dialog. Choose Tools|Environment Options, and specify either Pascal or IDL as the Language on the Type Library page of the dialog.

Note:	The choice of Object Pascal or IDL syntax also affects the choices available on the parameters attributes page.

Like Object Pascal applications in general, identifiers in type libraries are case insensitive. They can be up to 255 characters long, and must begin with a letter or an underscore (_).

Attribute specifications

Object Pascal has been extended to allow type libraries to include attribute specifications. Attribute specifications appear enclosed in square brackets and separated by commas. Each attribute specification consists of an attribute name followed (if appropriate) by a value.

The following table lists the attribute names and their corresponding values.

Attribute name	Example	Applies to
aggregatable	[aggregatable]	typeinfo
appobject	[appobject]	CoClass typeinfo
bindable	[bindable]	members except CoClass members
control	[control]	type library, typeinfo
custom	[custom '{7B5687A1-F4E9-11D1-92A8-00C04F8C8FC4}' 0]	anything
default	[default]	CoClass members
defaultbind	[defaultbind]	members except CoClass members
defaultcollection	[defaultcollection]	members except CoClass members
defaultvtbl	[defaultvtbl]	CoClass members
dispid	[dispid]	members except CoClass members
displaybind	[displaybind]	members except CoClass members
dllname	[dllname 'Helper.dll']	module typeinfo
dual	[dual]	interface typeinfo
helpfile	[helpfile 'c:\help\myhelp.hlp']	type library
helpstringdll	[helpstringdll 'c:\help\myhelp.dll']	type library
helpcontext	[helpcontext 2005]	anything except CoClass members and parameters
helpstring	[helpstring 'payroll interface']	anything except CoClass members and parameters
helpstringcontext	[helpstringcontext $17]	anything except CoClass members and parameters
hidden	[hidden]	anything except parameters
immediatebind	[immediatebind]	members except CoClass members
lcid	[lcid $324]	type library
licensed	[licensed]	type library, CoClass typeinfo
nonbrowsable	[nonbrowsable]	members except CoClass members
nonextensible	[nonextensible]	interface typeinfo
oleautomation	[oleautomation]	interface typeinfo
predeclid	[predeclid]	typeinfo
propget	[propget]	members except CoClass members
propput	[propput]	members except CoClass members
propputref	[propputref]	members except CoClass members
public	[public]	alias typeinfo
readonly	[readonly]	members except CoClass members
replaceable	[replaceable]	anything except CoClass members and parameters
requestedit	[requestedit]	members except CoClass members
restricted	[restricted]	anything except parameters
source	[source]	all members
uidefault	[uidefault]	members except CoClass members
usesgetlasterror	[usesgetlasterror]	members except CoClass members
uuid	[uuid '{7B5687A1-F4E9-11D1-92A8-00C04F8C8FC4}' ]	type library, typeinfo (required)
vararg	[vararg]	members except CoClass members
version	[version 1.1]	type library, typeinfo
Interface syntax

The Object Pascal syntax for declaring interface type information has the form

interfacename = interface[(baseinterface)] [attributes]

functionlist

[propertymethodlist]

end;

For example, the following text declares an interface with two methods and one property:

Interface1 = interface (IDispatch)

  [uuid '{7B5687A1-F4E9-11D1-92A8-00C04F8C8FC4}', version 1.0]

  function Calculate(optional seed:Integer=0): Integer;

  procedure Reset;

  procedure PutRange(Range: Integer) [propput, dispid $00000005]; stdcall;

  function GetRange: Integer;[propget, dispid $00000005]; stdcall;

end;

The corresponding syntax in Microsoft IDL is

[uuid '{5FD36EEF-70E5-11D1-AA62-00C04FB16F42}',version 1.0]

interface Interface1 :IDispatch

{

  long Calculate([in, optional, defaultvalue(0)] long seed);

  void Reset(void);

  [propput, id(0x00000005)] void _stdcall PutRange([in] long Value);

  [propput, id(0x00000005)] void _stdcall getRange([out, retval] long *Value);

};

Dispatch interface syntax

The Object Pascal syntax for declaring dispinterface type information has the form

dispinterfacename = dispinterface [attributes]

functionlist

[propertylist]

end;

For example, the following text declares a dispinterface with the same methods and property as the previous interface:

MyDispObj = dispinterface

[uuid '{5FD36EEF-70E5-11D1-AA62-00C04FB16F42}',

  version 1.0,

  helpstring 'dispatch interface for MyObj']

  function Calculate(seed:Integer): Integer [dispid 1];

  procedure Reset [dispid 2];

  property Range: Integer [dispid 3];

end;

The corresponding syntax in Microsoft IDL is

[uuid '{5FD36EEF-70E5-11D1-AA62-00C04FB16F42}',

  version 1.0,

  helpstring "dispatch interface for MyObj"]

dispinterface Interface1

{

  methods:

    [id(1)] intCalculate([in] int seed);

    [id(2)] void Reset(void);

  properties:

    [id(3)] int Value;

};

CoClass syntax

The Object Pascal syntax for declaring CoClass type information has the form

classname = coclass(interfacename[interfaceattributes], ...); [attributes];

For example, the following text declares a coclass for the interface IMyInt and dispinterface DmyInt:

myapp = coclass(IMyInt [source], DMyInt);

[uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}',

  version 1.0,

  helpstring 'A class',

  appobject]

The corresponding syntax in Microsoft IDL is

[uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}',

  version 1.0,

  helpstring 'A class',

  appobject]

coclass myapp

{

  methods:

  [source] interfaceIMyInt);

  dispinterface DMyInt;

};

Enum syntax

The Object Pascal syntax for declaring Enum type information has the form

enumname = ([attributes] enumlist);

For example, the following text declares an enumerated type with three values:

location = ([uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}',

         helpstring 'location of booth']

  Inside = 1 [helpstring 'Inside the pavillion'];

  Outside = 2 [helpstring 'Outside the pavillion'];

  Offsite = 3 [helpstring 'Not near the pavillion'];);

The corresponding syntax in Microsoft IDL is

[uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}',

        helpstring 'location of booth']

typedef enum

{

  [helpstring 'Inside the pavillion'] Inside = 1,

  [helpstring 'Outside the pavillion'] Outside = 2,

  [helpstring 'Not near the pavillion'] Offsite = 3

} location;

Alias syntax

The Object Pascal syntax for declaring Alias type information has the form

aliasname = basetype[attributes];

For example, the following text declares DWORD as an alias for integer:

DWORD = Integer [uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}'];

The corresponding syntax in Microsoft IDL is

[uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}'] typedef long DWORD;

Record syntax

The Object Pascal syntax for declaring Record type information has the form

recordname = record [attributes] fieldlist end;

For example, the following text declares a record:

Tasks = record [uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}',

                helpstring 'Task description']

  ID: Integer;

  StartDate: TDate;

  EndDate: TDate;

  Ownername: WideString;

  Subtasks: safearray of Integer;

end;

 The corresponding syntax in Microsoft IDL is

[uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}',

        helpstring 'Task description']

typedef struct

{

  long ID;

  DATE StartDate;

  DATE EndDate;

  BSTR Ownername;

  SAFEARRAY (int) Subtasks;

} Tasks;

Union syntax

The Object Pascal syntax for declaring Union type information has the form

unionname = record [attributes]

case Integer of

  0: field1;

  1: field2;

  ...

end;

For example, the following text declares a union:

MyUnion = record [uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}',

                  helpstring 'item description']

case Integer of

  0: (Name: WideString);

  1: (ID: Integer);

  3: (Value: Double);

end;

The corresponding syntax in Microsoft IDL is

[uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}',

        helpstring 'item description']

typedef union

{

  BSTR Name;

  long ID;

  double Value;

  } MyUnion;

Module syntax

The Object Pascal syntax for declaring Module type information has the form

modulename = module constants entrypoints end;

For example, the following text declares the type information for a module:

MyModule = module [uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}',

                   dllname 'circle.dll']

  PI: Double = 3.14159;

  function area(radius: Double): Double [ entry 1 ]; stdcall;

  function circumference(radius: Double): Double [ entry 2 ]; stdcall;

end;

The corresponding syntax in Microsoft IDL is

[uuid '{2MD36ABF-90E3-11D1-AA75-02C04FB73F42}',

        dllname("circle.dll")]

module MyModule

{

  double PI = 3.14159;

  [entry(1)] double _stdcall area([in] double radius);

  [entry(2)] double _stdcall circumference([in] double radius);

};


Creating a new type library
 DevGuide: Developing COM-based applications

Creating a new type library

Topic groups	See also

You may want to create a type library that is independent of a particular COM object. For example, you might want to define a type library that contains type definitions that you use in several other type libraries. You can then create a type library of basic definitions and add it to the uses page of other type libraries.

You can also create a type library for an object that is not yet implemented. Once the type library contains the interface definition, you can use the COM object wizard to generate a CoClass and implementation.

To create a new type library,

1	Choose File|New|Other to open the New Items dialog box.

2	Choose the ActiveX page.

3	Select the Type Library icon.

4	Choose OK.

The Type Library editor opens with a prompt to enter a name for the type library.

5	Enter a name for the type library. Continue by adding elements to your type library.


Opening an existing type library
 DevGuide: Developing COM-based applications

Opening an existing type library

Topic groups	See also

When you use the wizards to create an ActiveX control, Automation object, Active form, Active Server Page object, COM object, transactional object, remote data module, or transactional data module, a type library is automatically created with an implementation unit. In addition, you may have type libraries that are associated with other products (servers) that are available on your system.

To open a type library that is not currently part of your project,

1	Choose File|Open from the main menu in the IDE.

2	In the Open dialog box, set the File Type to type library.

3	Navigate to the desired type library files and choose Open.

To open a type library associated with the current project,

1	Choose View|Type Library.

Note:	When you use the CORBA Object wizard, you can also choose View|Type Library to edit the CORBA Object interfaces. What you see is not, technically speaking, a type library, but you can use it in much the same way.

Now, you can add interfaces, CoClasses, and other elements of the type library such as enumerations, properties, and methods.

Note:	Changes you make to any type library information with the Type Library editor can be automatically reflected in the associated implementation class. If you want to review the changes before they are added, be sure that the Apply Updates dialog is on. It is on by default and can be changed in the setting, “Display updates before refreshing,” on the Tools|Environment Options|Type Library page.

Tip:	When writing client applications, you do not need to open the type library. You only need the Project_TLB unit that the Type Library editor creates from a type library, not the type library itself. You can add this file directly to a client project, or, if the type library is registered on your system, you can use the Import Type Library dialog (Project|Import Type Library).


Adding an interface to the type library
 DevGuide: Developing COM-based applications

Adding an interface to the type library

Topic groups	See also

To add an interface,

1	On the toolbar, click on the interface icon.

An interface is added to the object list pane prompting you to add a name.

2	Type a name for the interface.

The new interface contains default attributes that you can modify as needed.

You can add properties (represented by getter/setter functions) and methods to suit the purpose of the interface.


Modifying an interface using the type library
 DevGuide: Developing COM-based applications

Modifying an interface using the type library

Topic groups	See also

There are several ways to modify an interface or dispinterface once it is created.

You can change the interface’s attributes using the page of type information that contains the information you want to change. Select the interface in the object list pane and then use the controls on the appropriate page of type information. For example, you may want to change the parent interface using the attributes page, or use the flags page to change whether or not it is a dual interface.

You can edit the interface declaration directly by selecting the interface in the object list pane and then editing the declarations on the Text page.

You can Add properties and methods to the interface.

You can modify the properties and methods already in your interface by changing their type information.

You can associate it with a CoClass by selecting the CoClass in the object list pane, right-clicking on the Implements page, and choosing Insert Interface.

Note:	When using the type library to add a CORBA interface, most of the information on the attributes page is irrelevent. You will also not need the Flags page.

If the interface is associated with a CoClass that was generated by a wizard, you can tell the Type Library editor to apply your changes to the implementation file by clicking the Refresh button on the toolbar. If you have the Apply Updates dialog enabled, the Type Library editor notifies you before updating the sources and warns you of potential problems. For example, if you rename an event interface by mistake, you may get a warning in your source file that looks like this:

Because of the presence of instance variables in your implementation file,

Delphi was not able to update the file to reflect the change in your event

interface name. As Delphi has updated the type library for you, however, you

must update the implementation file by hand.

You also get a TODO comment in your source file immediately above it.

Warning:	If you ignore this warning and TODO comment, the code will not compile.


Adding properties and methods to the type library
 DevGuide: Developing COM-based applications

Adding properties and methods to the type library

Topic groups	See also

To add properties or methods to an interface or dispinterface,

1	Select the interface, and choose either a property or method icon from the toolbar. If you are adding a property, you can click directly on the property icon to create a read/write property (with both a getter and a setter), or click the down arrow to display a menu of property types.

The property access method members or method member is added to the object list pane, prompting you to add a name.

2	Type a name for the member.

The new member contains default settings on its attributes, parameters, and flags pages that you can modify to suit the member. For example, you will probably want to assign a type to a property on the attributes page. If you are adding a method, you will probably want to specify its parameters on the parameters page.

As an alternate approach, you can add properties and methods by typing directly into the text page using Pascal or IDL syntax. For example, if you are working in Pascal syntax, you can type the following property declarations into the text page of an interface:

Interface1 = interface(IDispatch)

  [ uuid '{5FD36EEF-70E5-11D1-AA62-00C04FB16F42}',

    version 1.0,

    dual,

    oleautomation ]

 function AutoSelect: Integer [propget, dispid $00000002]; safecall; // Add this

 function AutoSize: WordBool [propget, dispid $00000001]; safecall; // And this

 procedure AutoSize(Value: WordBool) [propput, dispid $00000001]; safecall; // And this

end;

If you are working in IDL, you can add the same declarations as follows:

[

  uuid(5FD36EEF-70E5-11D1-AA62-00C04FB16F42),

  version(1.0),

  dual,

  oleautomation

]

interface Interface1: IDispatch

{ // Add everything between the curly braces

[propget, id(0x00000002)]

  HRESULT _stdcall AutoSelect([out, retval] long Value );

  [propget, id(0x00000003)]

  HRESULT _stdcall AutoSize([out, retval] VARIANT_BOOL Value );

  [propput, id(0x00000003)]

  HRESULT _stdcall AutoSize([in] VARIANT_BOOL Value );

};

After you have added members to an interface using the interface text page, the members appear as separate items in the object list pane, each with its own attributes, flags, and parameters pages. You can modify each new property or method by selecting it in the object list pane and using these pages, or by making edits directly in the text page.

If the interface is associated with a CoClass that was generated by a wizard, you can tell the Type Library editor to apply your changes to the implementation file by clicking the Refresh button on the toolbar. The Type Library editor adds new methods to your implementation class to reflect the new members. You can then locate the new methods in implementation unit’s source code and fill in their bodies to complete the implementation.

If you have the Apply Updates dialog enabled, the Type Library editor notifies you of all changes before updating the sources and warns you of potential problems.


Adding a CoClass to the type library
 DevGuide: Developing COM-based applications

Adding a CoClass to the type library

Topic groups	See also

The easiest way to add a CoClass to your project is to choose File|New|Other from the main menu in the IDE and use the appropriate wizard on the ActiveX or Multitier page of the New Items dialog. The advantage to this approach is that, in addition to adding the CoClass and its interface to the type library, the wizard adds an implementation unit and updates the project file to include the new implementation unit in its uses clause.

If you are not using a wizard, however, you can create a CoClass by clicking the CoClass icon on the toolbar and then specifying its attributes. You will probably want to give the new CoClass a name (on the Attributes page), and may want to use the Flags page to indicate information such as whether the CoClass is an application object, whether it represents an ActiveX control, and so on.

Note:	When you add a CoClass to a type library using the toolbar instead of a wizard, you must generate the implementation for the CoClass yourself and update it by hand every time you change an element on one of the CoClass’s interfaces. You can’t add members directly to a CoClass. Instead, you implicitly add members when you add an interface to the CoClass.


Adding an interface to a CoClass
 DevGuide: Developing COM-based applications

Adding an interface to a CoClass

Topic groups	See also

CoClasses are defined by the interfaces they present to clients. While you can add any number of properties and methods to the implementation class of a CoClass, clients can only see those properties and methods that are exposed by interfaces associated with the CoClass.

To associate an interface with a CoClass, right-click in the Implements page for the class and choose Insert Interface to display a list of interfaces from which you can choose. The list includes interfaces that are defined in the current type library and those defined in any type libraries that the current type library references. Choose an interface you want the class to implement. The interface is added to the page with its GUID and other attributes.

If the CoClass was generated by a wizard, the Type Library editor automatically updates the implementation class to include skeletal methods for the methods (including property access methods) of any interfaces you add this way.If you have the Apply Updates dialog enabled, the Type Library editor notifies you before updating the sources and warns you of potential problems.


Adding an enumeration to the type library
 DevGuide: Developing COM-based applications

Adding an enumeration to the type library

Topic groups	See also

To add enumerations to a type library,

1	On the toolbar, click on the enum icon.

An enum type is added to the object list pane prompting you to add a name.

2	Type a name for the enumeration.

The new enum is empty and contains default attributes in its attributes page for you to modify.

Add values to the enum by clicking on the New Const button. Then, select each enumerated value and assign it a name (and possibly a value) using the attributes page.

Once you have added an enumeration, the new type is available for use by the type library or any other type library that references it from its uses page. For example, you can use the enumeration as the type for a property or parameter.


Adding an alias to the type library
 DevGuide: Developing COM-based applications

Adding an alias to the type library

Topic groups	See also

To add an alias to a type library,

1	On the toolbar, click on the alias icon.

An alias type is added to the object list pane prompting you to add a name.

2	Type a name for the alias.

By default, the new alias stands for an Integer type. Use the Attributes page to change this to the type you want the alias to represent.

Once you have added an alias, the new type is available for use by the type library or any other type library that references it from its uses page. For example, you can use the alias as the type for a property or parameter.


Adding a record or union to the type library
 DevGuide: Developing COM-based applications

Adding a record or union to the type library

Topic groups	See also

To add a record or union to a type library,

1	On the toolbar, click on the record icon or the union icon.

The selected type element is added to the object list pane prompting you to add a name.

2	Type a name for the record or union.

At this point, the new record or union contains no fields.

3	With the record or union selected in the object list pane, click on the field icon in the toolbar. Specify the field’s name and type, using the Attributes page.

4	Repeat step 3 for as many fields as you need.

Once you have defined the record or union, the new type is available for use by the type library or any other type library that references it from its uses page. For example, you can use the record or union as the type for a property or parameter.


Adding a module to the type library
 DevGuide: Developing COM-based applications

Adding a record or union to the type library

Topic groups	See also

To add a module to a type library,

1	On the toolbar, click on the module icon.

The selected module is added to the object list pane prompting you to add a name.

2	Type a name for the module.

3	On the Attributes page, specify the name of the DLL whose entry points the Module represents.

4	Add any methods from the DLL you specified in step 3 by clicking on the Method icon in the toolbar and then using the attributes pages to describe the method.

5	Add any constants you want the module to define by clicking on the Const icon on the toolbar. For each constant, specify a name, type, and value.


Saving and registering type library information
 DevGuide: Developing COM-based applications

Saving and registering type library information

Topic groups	See also

After modifying your type library, you’ll want to save and register the type library information.

Saving the type library automatically updates:

The binary type library file (.tlb extension).

The Project_TLB unit that represents its contents

The implementation code for any CoClasses that were generated by a wizard.

Note:	The type library is stored as a separate binary (.TLB) file, but is also linked into the server (.EXE, DLL, or .OCX).

Note:	When using the Type Library editor for CORBA interfaces, the Project_TLB.pas unit defines the stub and skeleton objects required by the CORBA application.

The Type Library editor gives you options for storing your type library information. Which way you choose depends on what stage you are at in implementing the type library:

Save, to save both the .TLB and the Project_TLB unit to disk.

Refresh, to update the type library units in memory only.

Register, to add an entry for the type library in your system’s Windows registry. This is done automatically when the server with which the .TLB is associated is itself registered.

Export, to save a .IDL file that contains the type and interface definitions in IDL syntax.

All the above methods perform syntax checking. When you refresh, register, or save the type library, Delphi automatically updates the implementation unit of any CoClasses that were created using a wizard. Optionally, you can review these updates before they are committed, if you have the Type Library editor option, Apply Updates on.


Apply Updates dialog
 DevGuide: Developing COM-based applications

Apply Updates dialog

Topic groups	See also

The Apply Updates dialog appears when you refresh, register, or save the type library if you have selected “Display updates before refreshing’ in the Tools|Environment Options|Type Library page (which is on by default).

Without this option, the Type Library editor automatically updates the sources of the associated object when you make changes in the editor. With this option, you have a chance to veto the proposed changes when you attempt to refresh, save, or register the type library.

The Apply Updates dialog will warn you about potential errors, and will insert TODO comments in your source file. For example, if you rename an event by mistake, you will get a warning in your source file that looks like this:

Because of the presence of instance variables in your implementation file,

Delphi was not able to update the file to reflect the change in your event

interface name. As Delphi has updated the type library for you, however, you

must update the implementation file by hand.

You will also get a TODO comment in your source file immediately above it.

Note:	If you ignore this warning and TODO comment, the code will not compile.


Saving a type library
 DevGuide: Developing COM-based applications

Saving a type library

Topic groups	See also

Saving a type library

Performs a syntax and validity check.

Saves information out to a .TLB file.

Saves information out to the Project_TLB unit.

Notifies the IDE’s module manager to update the implementation, if the type library is associated with a CoClass that was generated by a wizard.

To save the type library, choose File|Save from the Delphi main menu.


Refreshing the type library
 DevGuide: Developing COM-based applications

Refreshing the type library

Topic groups	See also

Refreshing the type library

Performs a syntax check.

Regenerates the Delphi type library units in memory only. It does not save any files to disk.

Notifies the IDE’s module manager to update the implementation, if the type library is associated with a CoClass that was generated by a wizard.

To refresh the type library choose the Refresh icon on the Type Library editor toolbar.

Note:	If you have renamed items in the type library, refreshing the implementation may create duplicate entries. In this case, you must move your code to the correct entry and delete any duplicates. Similarly, if you delete items in the type library, refreshing the implementation does not remove them from CoClasses (under the assumption that you are merely removing them from visibility to clients). You must delete these items manually in the implementation unit if they are no longer needed.


Registering the type library
 DevGuide: Developing COM-based applications

Registering the type library

Topic groups	See also

Typically, you do not need to explicitly register a type library because it is registered automatically when you register your COM server application (see Registering a COM object). However, when you create a type library using the Type Library wizard, it is not associated with a server object. In this case, you can register the type library directly using the toolbar.

Registering the type library,

Performs a syntax check

Adds an entry to the Windows Registry for the type library

To register the type library, choose the Register icon on the Type Library editor toolbar.


Exporting an IDL file
 DevGuide: Developing COM-based applications

Exporting an IDL file

Topic groups	See also

Exporting the type library,

Performs a syntax check.

Creates an IDL file that contains the type information declarations. This file describes the type information in either CORBA IDL or Microsoft IDL.

To export the type library, choose the Export icon on the Type Library editor toolbar.


Deploying type libraries
 DevGuide: Developing COM-based applications

Deploying type libraries

Topic groups	See also

By default, when you have a type library that was created as part of an ActiveX or Automation server project, the type library is automatically linked into the .DLL, .OCX, or EXE as a resource.

You can, however, deploy your application with the type library as a separate .TLB, as Delphi maintains the type library, if you prefer.

Historically, type libraries for Automation applications were stored as a separate file with the .TLB extension. Now, typical Automation applications compile the type libraries into the .OCX or .EXE file directly. The operating system expects the type library to be the first resource in the executable (.DLL, .OCX, or .EXE) file.

When you make type libraries other than the primary project type library available to application developers, the type libraries can be in any of the following forms:

A resource. This resource should have the type TYPELIB and an integer ID. If you choose to build type libraries with a resource compiler, it must be declared in the resource (.RC) file as follows:

1 typelib mylib1.tlb

2 typelib mylib2.tlb

There can be multiple type library resources in an ActiveX library. Application developers use the resource compiler to add the .TLB file to their own ActiveX library.

Stand-alone binary files. The .TLB file output by the Type Library editor is a binary file.


Creating COM clients: Overview
 DevGuide: Developing COM-based applications

Creating COM clients

Topic groups	See also

COM clients are applications that make use of a COM object implemented by another application or library. The most common types are applications that control an Automation server (Automation controllers) and applications that host an ActiveX control (ActiveX containers).

At first glance these two types of COM client are very different: The typical Automation controller launches an external server EXE and issues commands to make that server perform tasks on its behalf. The Automation server is usually nonvisual and out-of-process. The typical ActiveX client, on the other hand, hosts a visual control, using it much the same way you use any control on the Component palette. ActiveX servers are always in-process servers.

However, the task of writing these two types of COM client is remarkably similar: The client application obtains an interface for the server object and uses its properties and methods. Delphi makes this particularly easy by letting you wrap the server CoClass in a component on the client, which you can even install on the Component palette. Samples of such component wrappers appear on two pages of the Component palette: sample ActiveX wrappers appear on the ActiveX page and sample Automation objects appear on the Servers page.

When writing a COM client, you must understand the interface that the server exposes to clients, just as you must understand the properties and methods of a component from the Component palette to use it in your application. This interface (or set of interfaces) is determined by the server application, and typically published in a type library. For specific information on a particular server application’s published interfaces, you should consult that application’s documentation.

Even if you do not choose to wrap a server object in a component wrapper and install it on the Component palette, you must make its interface definition available to your application. To do this, you can import the server’s type information.

Once you have imported the type information, you can write code to control the imported object.

Note:	You can also query the type information directly using COM APIs, but Delphi provides no special support for this.

Some older COM technologies, such as object linking and embedding (OLE), do not provide type information in a type library. Instead, they rely on a standard set of predefined interfaces. These are discussed in Creating Clients for servers that do not have a type library.


Importing type library information
 DevGuide: Developing COM-based applications

Importing type library information

Topic groups	See also

To make information about the COM server available to your client application, you must import the information about the server that is stored in the server’s type library. Your application can then use the resulting generated classes to control the server object.

There are two ways to import type library information:

You can use the Import Type Library dialog to import all available information about the server types, objects, and interfaces. This is the most general method, because it lets you import information from any type library and can optionally generate component wrappers for all creatable CoClasses in the type library that are not flagged as Hidden, Restricted, or PreDeclID.

You can use theImport ActiveX dialog if you are importing from the type library of an ActiveX control. This imports the same type information, but only creates component wrappers for CoClasses that represent ActiveX controls.

You can use the command line utility tlibimp.exe which provides additional configuration options not available from within the IDE.

A type library generated using a wizard is automatically imported using the same mechanism as the import type library menu item.

Regardless of which method you choose to import type library information, the resulting dialog creates a unit with the name TypeLibName_TLB, where TypeLibName is the name of the type library. This file contains declarations for the classes, types, and interfaces defined in the type library. By including it in your project, those definitions are available to your application so that you can create objects and call their interfaces. This file may be recreated by the IDE from time to time; as a result, making manual changes to the file is not recommended.

In addition to adding type definitions to the TypeLibName_TLB unit, the dialog can also create VCL class wrappers for any CoClasses defined in the type library. When you use the Import Type Library dialog, these wrappers are optional. When you use the Import ActiveX dialog, they are always generated for all CoClasses that represent controls.

The generated class wrappers represent the CoClasses to your application, and expose the properties and methods of its interfaces. If a CoClass supports the interfaces for generating events (IConnectionPointContainer and IConnectionPoint), the VCL class wrapper creates an event sink so that you can assign event handlers for the events as simply as you can for any other component. If you tell the dialog to install the generated VCL classes on the Component palette, you can use the Object Inspector to assign property values and event handlers.

Note:	The Import Type Library dialog does not create class wrappers for COM+ event objects. To write a client that responds to events generated by a COM+ event object, you must create the event sink programmatically. This process is described in Handling COM+ events.

For more details about the code generated when you import a type library, see Code generated when you import type library information.


Using the Import Type Library dialog
 DevGuide: Developing COM-based applications

Using the Import Type Library dialog

Topic groups	See also

To import a 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. This registers the type library, making it available. Then repeat step 2. Note that the type library could be a stand-alone type library file (.tlb, .olb), or a server that provides a type library (.dll, .ocx, .exe).

3	If you want to generate a VCL component that wraps a CoClass in the type library, check Generate Component Wrapper. If you do not generate the component, you can still use the CoClass by using the definitions in the TypeLibName_TLB unit. However, you will have to write your own calls to create the server object and, if necessary, to set up an event sink.

The Import Type Library dialog only imports CoClasses that are have the CanCreate flag set and that do not have the Hidden, Restricted, or PreDeclID flags set. These flags can be overridden using the command-line utility tlibimp.exe.

4	If you do not want to install a generated component wrapper on the Component palette, choose Create Unit. This generates the TypeLibName_TLB unit and, if you checked Generate Component Wrapper in step 3, adds the declaration of the component wrapper. This exits the Import Type Library dialog.

5	If you want to install the generated component wrapper on the Component palette, select the Palette page on which this component will reside and then choose Install. This generates the TypeLibName_TLB unit, like the Create Unit button, and then displays the Install component dialog, letting you specify the package where the components should reside (either an existing package or a new one). This button is grayed out if no component can be created for the type library.

When you exit the Import Type Library dialog, the new TypeLibName_TLB unit appears in the directory specified by the Unit dir name control. This file contains declarations for the elements defined in the type library, as well as the generated component wrapper if you checked Generate Component Wrapper.

In addition, if you installed the generated component wrapper, a server object that the type library described now resides on the Component palette. You can use the Object Inspector to set properties or write an event handler for the server. If you add the component to a form or data module, you can right-click on it at design time to see its property page (if it supports one).

Note:	The Servers page of the Component palette contains a number of example Automation servers that were imported this way for you.


Using the Import ActiveX dialog
 DevGuide: Developing COM-based applications

Using the Import ActiveX dialog

Topic groups	See also

To import an ActiveX control,

1	Choose Component|Import ActiveX Control.

2	Select the type library from the list.

The dialog lists all the registered libraries that define ActiveX controls. (This is a subset of the libraries listed in the Import Type Library dialog.) If the type library is not in the list, choose the Add button, find and select the type library file, choose OK. This registers the type library, making it available. Then repeat step 2. Note that the type library could be a stand-alone type library file (.tlb, .olb), or an ActiveX server (.dll, .ocx).

3	If you do not want to install the ActiveX control on the Component palette, choose Create Unit. This generates the TypeLibName_TLB unit and adds the declaration of its component wrapper. This exits the Import ActiveX dialog.

4	If you want to install the ActiveX control on the Component palette, select the Palette page on which this component will reside and then choose Install. This generates the TypeLibName_TLB unit, like the Create Unit button, and then displays the Install component dialog, letting you specify the package where the components should reside (either an existing package or a new one).

When you exit the Import ActiveX dialog, the new TypeLibName_TLB unit appears in the directory specified by the Unit dir name control. This file contains declarations for the elements defined in the type library, as well as the generated component wrapper for the ActiveX control.

Note:	Unlike the Import Type Library dialog where it is optional, the import ActiveX dialog always generates a component wrapper. This is because, as a visual control, an ActiveX control needs the additional support of the component wrapper so that it can fit in with VCL forms.

If you installed the generated component wrapper, an ActiveX control now resides on the Component palette. You can use the Object Inspector to set properties or write event handlers for this control. If you add the control to a form or data module, you can right-click on it at design time to see its property page (if it supports one).

Note:	The ActiveX page of the Component palette contains a number of example ActiveX controls that were imported this way for you.


Code generated when you import type library information
 DevGuide: Developing COM-based applications

Code generated when you import type library information

Topic groups	See also

Once you import a type library, you can view the generated TypeLibName_TLB unit. At the top, you will find the following:

Constant declarations giving symbolic names to the GUIDS of the type library and its interfaces and CoClasses. The names for these constants are generated as follows:

The GUID for the type library has the form LBID_TypeLibName, where TypeLibName is the name of the type library.

The GUID for an interface has the form IID_InterfaceName, where InterfaceName is the name of the interface.

The GUID for a dispinterface has the form DIID_InterfaceName, where InterfaceName is the name of the dispinterface.

The GUID for a CoClass has the form CLASS_ClassName, where ClassName is the name of the CoClass.

Declarations for the CoClasses in the type library. These map each CoClass to its default interface.

Declarations for the interfaces and dispinterfaces in the type library.

Declarations for a creator class for each CoClass whose default interface supports Vtable binding. The creator class has two class methods, Create and CreateRemote, that can be used to instantiate the CoClass locally (Create) or remotely (CreateRemote).These methods return the default interface for the CoClass.

These declarations provide you with what you need to create instances of the CoClass and access its interface. All you need do is add the generated TypeLibName_TLB.pas file to the uses clause of the unit where you wish to bind to a CoClass and call its interfaces.

Note:	This portion of the TypeLibName_TLB unit is also generated when you use the Type Library editor or the command-line utility TLIBIMP.

If you want to use an ActiveX control, you also need the generated VCL wrapper in addition to the declarations described above. The VCL wrapper handles window management issues for the control. You may also have generated a VCL wrapper for other CoClasses in the Import Type Library dialog. These VCL wrappers simplify the task of creating server objects and calling their methods. They are especially recommended if you want your client application to respond to events.

The declarations for generated VCL wrappers appear at the bottom of the interface section. Component wrappers for ActiveX controls are descendants of TOleControl. Component wrappers for Automation objects descend from TOleServer. The generated component wrapper adds the properties, events, and methods exposed by the CoClass’s interface. You can use this component like any other VCL component.

Warning:	You should not edit the generated TypeLibName_TLB unit. It is regenerated each time the type library is refreshed, so any changes will be overwritten.

Note:	For the most up-to-date information about the generated code, refer to the comments in the automatically-generated TypeLibName_TLB unit.


Controlling an imported object
 DevGuide: Developing COM-based applications

Controlling an imported object

Topic groups	See also

After importing type library information, you are ready to start programming with the imported objects. How you proceed depends in part on the objects, and in part on whether you have chosen to create component wrappers. There are two basic approaches:

Using component wrappers.

Writing client code based on type library definitions.


Using component wrappers
 DevGuide: Developing COM-based applications

Using component wrappers

Topic groups	See also

If you generated a component wrapper for your server object, writing your COM client application is not very different from writing any other application that contains VCL components. The server object’s properties, methods, and events are already encapsulated in the VCL component. You need only assign event handlers, set property values, and call methods.

To use the properties, methods, and events of the server object, see the documentation for your server. The component wrapper automatically provides a dual interface where possible. Delphi determines the VTable layout from information in the type library.

In addition, your new component inherits certain important properties and methods from its base class.

ActiveX wrappers

You should always use a component wrapper when hosting ActiveX controls, because the component wrapper integrates the control’s window into the VCL framework.

The properties and methods an ActiveX control inherits from TOleControl allow you to access the underlying interface or obtain information about the control. Most applications, however, do not need to use these. Instead, you use the imported control the same way you would use any other VCL control.

Typically, ActiveX controls provide a property page that lets you set their properties. Property pages are similar to the component editors some components display when you double-click on them in the form designer. To display an ActiveX control’s property page, right click and choose Properties.

The way you use most imported ActiveX controls is determined by the server application. However, ActiveX controls use a standard set of notifications when they represent the data from a database field. See Using data-aware ActiveX controls for information on how to host such ActiveX controls.

Automation object wrappers

The wrappers for Automation objects let you control how you want to form the connection to your server object:

The ConnectKind property indicates whether the server is local or remote and whether you want to connect to a server that is already running or if a new instance should be launched. When connecting to a remote server, you must specify the machine name using the RemoteMachineName property.

Once you have specified the ConnectKind, there are three ways you can connect your component to the server:

you can explicitly connect to the server by calling the component’s Connect method.

You can tell the component to connect automatically when your application starts up by setting the AutoConnect property to True.

You do not need to explicitly connect to the server. The component automatically forms a connection when you use one of the server’s properties or methods using the component.

Calling methods or accessing properties is the same as using any other component:

TServerComponent1.DoSomething;

Handling events is easy, because you can use the Object Inspector to write event handlers. Note, however, that the event handler on your component may have slightly different parameters than those defined for the event in the type library. Specifically, pointer types (var parameters and interface pointers) are changed to Variants. You must explicitly cast var parameters to the underlying type before assigning a value. Interface pointers can be cast to the appropriate interface type using the as operator.For example, the following code shows an event handler for the ExcelApplication event, OnNewWorkBook. The event handler has a parameter that provides the interface of another CoClass (ExcelWorkbook). However, the interface is not passed as an ExcelWorkbook interface pointer, but rather as an OleVariant.

procedure TForm1.XLappNewWorkbook(Sender: TObject; var Wb:OleVariant);

begin

  { Note how the OleVariant for the interface must be cast to the correct type }

  ExcelWorkbook1.ConnectTo((iUnknown(wb) as ExcelWorkbook));

end;

In this example, the event handler assigns the workbook to an ExcelWorkbook component (ExcelWorkbook1). This demonstrates how to connect a component wrapper to an existing interface by using the ConnectTo method. The ConnectTo method is added to the generated code for the component wrapper.

Servers that have an application object expose a Quit method on that object to let clients terminate the connection. Quit typically exposes functionality that is equivalent to using the File menu to quit the application. Code to call the Quit method is generated in your component’s Disconnect method. If it is possible to call the Quit method with no parameters, the component wrapper also has an AutoQuit property. AutoQuit causes your controller to call Quit when the component is freed. If you want to disconnect at some other time, or if the Quit method requires parameters, you must call it explicitly. Quit appears as a public method on the generated component.

For an example of importing an using a component wrapper for an Automation object, see Printing a document with Microsoft Word.


Using data-aware ActiveX controls
 DevGuide: Developing COM-based applications

Using data-aware ActiveX controls

Topic groups	See also

When you use a data-aware ActiveX control in a Delphi application, you must associate it with the database whose data it represents. To do this, you need adata source component, just as you need a data source for any data-aware VCL control.

After you place the data-aware ActiveX control in the form designer, assign its DataSource property to the data source that represents the desired dataset. Once you have specified a data source, you can use the Data Bindings editor to link the control’s data-bound property to a field in the dataset.

To display the Data Bindings editor, right-click the data-aware ActiveX control to display a list of options. In addition to the basic Form context menu options, the additional Data Bindings item appears. Select this item to see the Data Bindings editor, which lists the names of fields in the dataset and the bindable properties of the ActiveX control.

To bind a field to a property,

1	In the ActiveX Data Bindings Editor dialog, select a field and a property name.

Field Name lists the fields of the database and Property Name lists the ActiveX control properties that can be bound to a database field. The dispID of the property is in parentheses, for example, Value(12).

2	Click Bind and OK.

Note:	If no properties appear in the dialog, the ActiveX control contains no data-aware properties. To enable simple data binding for a property of an ActiveX control, use the type library.

The following example walks you through the steps of using a data-aware ActiveX control in the Delphi container. This example uses the Microsoft Calendar Control, which is available if you have Microsoft Office 97 installed on your system.

1	From the Delphi main menu, choose Component|Import ActiveX Control.

2	Select a data-aware ActiveX control, such as the Microsoft Calendar control 8.0, change its class name to TCalendarAXControl, and click Install.

3	In the Install dialog, click OK to add the control to the default user package, which makes the control available on the Palette.

4	Choose Close All and File|New|Application to begin a new application.

5	From the ActiveX tab, drop a TCalendarAXControl object, which you just added to the Palette, onto the form.

6	From the Data Access tab, drop a DataSource and Table object onto the form.

7	Select the DataSource object and set its DataSet property to Table1.

8	Select the Table object and do the following:

Set the DatabaseName property to DBDEMOS

Set the TableName property to EMPLOYEE.DB

Set the Active property to True

9	Select the TCalendarAXControl object and set its DataSource property to DataSource1.

10	Select the TCalendarAXControl object, right-click, and choose Data Bindings to invoke the ActiveX Control Data Bindings Editor.

Field Name lists all the fields in the active database. Property Name lists those properties of the ActiveX Control that can be bound to a database field. The dispID of the property is in parentheses.

11	Select the HireDate field and the Value property name, choose Bind, and OK.

The field name and property are now bound.

12	From the Data Controls tab, drop a DBGrid object onto the form and set its DataSource property to DataSource1.

13	From the Data Controls tab, drop a DBNavigator object onto the form and set its DataSource property to DataSource1.

14	Run the application.

15	Test the application as follows:

With the HireDate field displayed in the DBGrid object, navigate through the database using the Navigator object. The dates in the ActiveX control change as you move through the database.


Example: Printing a document with Microsoft Word
 DevGuide: Developing COM-based applications

Example: Printing a document with Microsoft Word

Topic groups	See also

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 see how to 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	For 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 the button object as described in the next step.

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

By dropping an instance of the WordApplication object onto your form, you can easily access the control using a VTable interface object. You simply call on methods of the class you just created. For Word, this is the TWordApplication class.

1	Select the button, double-click its OnClick event handler and supply the following event handling code:

procedure TForm1.Button1Click(Sender: TObject);

var

FileName: OleVariant;

begin

 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);

   end;

end;

2	Build and run the program. By clicking the button, Word prompts you for a file to print.

Using a dispatch interface object

As an alternate, you can use a dispatch interface for late binding. To use a dispatch interface object, you create and initialize the Application object using the _ApplicationDisp dispatch wrapper class as follows. Notice that dispinterface methods are “documented” by the source as returning Vtable interfaces, but, in fact, you must cast them to dispatch interfaces.

1	Select the button, double-click its OnQuit event handler and supply the following event handling code:

procedure TForm1.Button1Click(Sender: TObject);

var

MyWord : _ApplicationDisp;

FileName : OleVariant;

begin

  if OpenDialog1.Execute then

  begin

    FileName := OpenDialog1.FileName;

    MyWord := CoWordApplication.Create as

        _ApplicationDisp;

    (MyWord.Documents asDocumentsDisp).Open(FileName,EmptyParam,

        EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,

        EmptyParam,EmptyParam,EmptyParam);

    (MyWord.ActiveDocument as _DocumentDisp).PrintOut(EmptyParam,

        EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,

        EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,

        EmptyParam,EmptyParam,EmptyParam);

    MyWord.Quit(EmptyParam,EmptyParam,EmptyParam);

  end;

end;

2	Build and run the program. By clicking the button, Word prompts you for a file to print.

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:

Choose Component|Install Packages.

From the list, select the WordExample package and click remove.

Click Yes to the message box asking for confirmation.

Exit the Install Packages dialog by clicking OK.

2	Return the Borland Sample Automation Server Components package:

Choose Component|Install Packages.

Click the Add button.

In the resulting dialog, choose dclaxserver50.bpl.

Exit the Install Packages dialog by clicking OK.


Writing client code based on type library definitions
 DevGuide: Developing COM-based applications

Writing client code based on type library definitions

Topic groups	See also

Although you must use a component wrapper for hosting an ActiveX control, you can write an Automation controller using only the definitions from the type library that appear in the TypeLibName_TLB unit. This process is a bit more involved that letting a component do the work, especially if you need to respond to events.

The following topics describe how to implement the various actions your Automation controller needs to perform:

Connect to the server.

Control the Automation server using a dual interface.

Control the Automation server using a dispinterface.

Respond to events generated by the Automation server.


Connecting to a server
 DevGuide: Developing COM-based applications

Connecting to a server

Topic groups	See also

Before you can drive an Automation server from your controller application, you must obtain a reference to an interface it supports. Typically, you connect to a server through its main interface. For example, you connect to Microsoft Word through the WordApplication component.

If the main interface is a dual interface, you can use the creator objects in the TypeLibName_TLB.pas file. The creator classes have the same name as the CoClass, with the prefix “Co” added. You can connect to a server on the same machine by calling the Create method, or a server on a remote machine using the CreateRemote method. Because Create and CreateRemote are class methods, you do not need an instance of the creator class to call them.

MyInterface := CoServerClassName.Create;

MyInterface := CoServerClassName.CreateRemote('Machine1');

Create and CreateRemote return the default interface for the CoClass.

If the default interface is a dispatch interface, then there is no Creator class generated for the CoClass. Instead, you can call the global CreateOleObject function, passing in the GUID for the CoClass (there is a constant for this GUID defined at the top of the _TLB unit). CreateOleObject returns an IDispatch pointer for the default interface.


Controlling an Automation server using a Dual interface
 DevGuide: Developing COM-based applications

Controlling an Automation server using a dual interface

Topic groups	See also

After using the automatically generated creator class to connect to the server, you call methods of the interface. For example,

var

  MyInterface : _Application;

begin

  MyInterface := CoWordApplication.Create;

  MyInterface.DoSomething;

The interface and creator class are defined in the TypeLibName_TLB unit that is generated automatically when you import a type library.


Controlling an Automation server using a dispatch interface
 DevGuide: Developing COM-based applications

Controlling an Automation server using a dispatch interface

Topic groups	See also

Typically, you use the dual interface to control the Automation server. However, you may find a need to control an Automation server with a dispatch interface because no dual interface is available.

To call the methods of a dispatch interface,

1	Connect to the server, using the global CreateOleObject function.

2	Use the as operator to cast the IDispatch interface returned by CreateOleObject to the dispinterface for the CoClass. This dispinterface type is declared in the TypeLibName_TLB unit.

3	Control the Automation server by calling methods of the dispinterface.

Another way to use dispatch interfaces is to assign them to a Variant. By assigning the interface returned by CreateOleObject to a Variant, you can take advantage of the Variant type’s built-in support for interfaces. Simply call the methods of the interface, and the Variant automatically handles all IDispatch calls, fetching the dispatch ID and invoking the appropriate method. The Variant type includes built-in support for calling dispatch interfaces, through its var.

  V: Variant;

begin

  V:= CreateOleObject('TheServerObject');

  V.MethodName; { calls the specified method }

  ...

An advantage of using Variants is that you do not need to import the type library, because Variants use only the standard IDispatch methods to call the server. The trade-off is that Variants are slower, because they use dynamic binding at runtime.


Handling events in an Automation Controller
 DevGuide: Developing COM-based applications

Handling events in an Automation Controller

Topic groups	See also

When you generate a Component wrapper for an object whose type library you import, you can respond to events simply using the events that are added to the generated component. If you do not use a Component wrapper, however, (or if the server uses COM+ events), you must write the event sink code yourself.

Handling Automation events programmatically

Before you can handle events, you must define an event sink. This is a class that implements the event dispatch interface that is defined in the server’s type library.

To write the event sink, create an object that implements the event dispatch interface:

TServerEventsSink = class(TObject, _TheServerEvents)

...{ declare the methods of _TheServerEvents here }

end;

Once you have an instance of your event sink, you must inform the server object of its existence so that the server can call it. To do this, you call the global InterfaceConnect procedure, passing it

The interface to the server that generates events.

The GUID for the event interface that your event sink handles.

An IUnknown interface for your event sink.

A variable that receives a Longint that represents the connection between the server and your event sink.

{MyInterface is the server interface you got when you connected to the server }

InterfaceConnect(MyInterface, DIID_TheServerEvents,

                 MyEventSinkObject as IUnknown, cookievar);

After calling InterfaceConnect, your event sink is connected and receives calls from the server when events occur.

You must terminate the connection before you free your event sink. To do this, call the global InterfaceDisconnect procedure, passing it all the same parameters except for the interface to your event sink (and the final parameter is ingoing rather than outgoing):

InterfaceDisconnect(MyInterface, DIID_TheServerEvents, cookievar);

Note:	You must be certain that the server has released its connection to your event sink before you free it. Because you don’t know how the server responds to the disconnect notification initiated by InterfaceDisconnect, this may lead to a race condition if you free your event sink immediately after the call. The easiest way to guard against problems is to have your event sink maintain its own reference count that is not decremented until the server releases the event sink’s interface.

Handling COM+ events

Under COM+, servers use a special helper object to generate events rather than a set of special interfaces (IConnectionPointContainer and IConnectionPoint). Because of this, you can’t use an event sink that descends from TEventDispatcher. TEventDispatcher is designed to work with those interfaces, not COM+ event objects.

Instead of defining an event sink, your client application defines a subscriber object. Subscriber objects, like event sinks, provide the implementation of the event interface. They differ from event sinks in that they subscribe to a particular event object rather than connecting to a server’s connection point.

To define a subscriber object, use the COM Object wizard, selecting the event object’s interface as the one you want to implement. The wizard generates an implementation unit with skeletal methods that you can fill in to create your event handlers.

Note:	You may need to add the event object’s interface to the registry using the wizard if it does not appear in the list of interfaces you can implement.

Once you create the subscriber object, you must subscribe to the event object’s interface or to individual methods (events) on that interface. There are three types of subscriptions from which you can choose:

Transient subscriptions. Like traditional event sinks, transient subscriptions are tied to the lifetime of an object instance. When the subscriber object is freed, the subscription ends and COM+ no longer forwards events to it.

Persistent subscriptions. These are tied to the object class rather than a specific object instance. When the event occurs, COM locates or launches an instance of the subscriber object and calls its event handler. In-process objects (DLLs) use this type of subscription.

Per-user subscriptions. These subscriptions provide a more secure version of transient subscriptions. Both the subscriber object and the server object that fires events must be running under the same user account on the same machine.

Note:	Objects that subscribe to COM+ events must be installed in a COM+ application.


Creating clients for servers that do not have a type library
 DevGuide: Developing COM-based applications

Creating clients for servers that do not have a type library

Topic groups	See also

Some older COM technologies, such as object linking and embedding (OLE), do not provide type information in a type library. Instead, they rely on a standard set of predefined interfaces. To write clients that host such objects, you can use the TOleContainer component. This component appears on the System page of the Component palette.

TOleContainer acts as a host site for an Ole2 object. It implements the IOleClientSite interface and, optionally, IOleDocumentSite. Communication is handled using OLE verbs.

To use TOleContainer,

1	Place a TOleContainer component on your form.

2	Set the AllowActiveDoc property to True if you want to host an Active document.

3	Set the AllowInPlace property to indicate whether the hosted object should appear in the TOleContainer, or in a separate window.

4	Write event handlers to respond when the object is activated, deactivated, moved, or resized.

5	To bind the TOleContainer object at design time, right click and choose Insert Object. In the Insert Object dialog, choose a server object to host.

6	To bind the TOleContainer object at runtime, you have several methods to choose from, depending on how you want to identify the server object. These include CreateObject, which takes a program id, CreateObjectFromFile, which takes the name of a file to which the object has been saved, CreateObjectFromInfo, which takes a record containing information on how to create the object, or CreateLinkToFile, which takes the name of a file to which the object was saved and links to it rather than embeds it.

7	Once the object is bound, you can access its interface using the OleObjectInterface property. However, because communication with Ole2 objects was based on OLE verbs, you will most likely want to send commands to the server using the DoVerb method.

8	When you want to release the server object, call the DestroyObject method.


Creating simple COM servers: overview
 DevGuide: Developing COM-based applications

Creating simple COM servers

Topic groups	See also

Delphi provides wizards to help you create various COM objects. The simplest COM objects are servers that expose properties and methods (and possibly events) through a default interface that clients can call.

Note:	COM servers and Automation is not available for use in CLX applications. This technology is for use on Windows only and is not cross-platform.

Two wizards, in particular, ease the process of creating simple COM objects:

The COM Object wizard builds a lightweight COM object whose default interface descends from IUnknown or that implements an interface already registered on your system. This wizard provides the most flexibility in the types of COM objects you can create.

The Automation Object wizard creates a simple Automation object whose default interface descends from IDispatch. IDispatch introduces a standard marshaling mechanism and support for late binding of interface calls.

Note:	COM defines many standard interfaces and mechanisms for handling specific situations. The Delphi wizards automate the most common tasks. However, some tasks, such as custom marshaling, are not supported by any Delphi wizards. For information on that and other technologies not explicitly supported by Delphi, refer to the Microsoft Developer’s Network (MSDN) documentation. The Microsoft Web site also provides current information on COM support.

Overview of creating a COM object

Whether you use the Automation object wizard to create a new Automation server or the COM object wizard to create some other type of COM object, the process you follow is the same. It involves these steps:

1	Design the COM object.

2	Use the COM Object wizard or the Automation Object wizard to create the server object.

3	Define the interface that the object exposes to clients.

4	Register the COM object.

5	Test and debug the application.


Designing a COM object
 DevGuide: Developing COM-based applications

Designing a COM object

Topic groups

When designing the COM object, you need to decide what COM interfaces you want to implement. You can write a COM object to implement an interface that has already been defined, or you can define a new interface for your object to implement. In addition, you can have your object support more than one interface. For information about standard COM interfaces that you might want to support, see the MSDN documentation.

To create a COM object that implements an existing interface, use the COM Object wizard.

To create a COM object that implements a new interface that you define, use either the COM Object wizard or the Automation Object wizard. The COM object wizard can generate a new default interface that descends from IUnknown, and the Automation object gives your object a default interface that descends from IDispatch. No matter which wizard you use, you can always use the Type Library editor later to change the parent interface of the default interface that the wizard generates.

In addition to deciding what interfaces to support, you must decide whether the COM object is an in-process server, out-of-process server, or remote server. For in-process servers and for out-of-process and remote servers that use a type library, COM marshals the data for you. Otherwise, you must consider how to marshal the data to out-of-process servers.


Using the COM object wizard
 DevGuide: Developing COM-based applications

Using the COM object wizard

Topic groups	See also

The COM object wizard performs the following tasks:

Creates a new unit.

Defines a new class that descends from TCOMObject and sets up the class factory constructor. For more information on the base class, see Code generated by wizards.

Optionally, adds a type library to your project and adds your object and its interface to the type library.

Before you create a COM object, create or open the project for the application containing functionality that you want to implement. The project can be either an application or ActiveX library, depending on your needs.

To bring up the COM object wizard,

1	Choose File|New|Other to open the New Items dialog box.

2	Select the tab labeled, ActiveX.

3	Double-click the COM object icon.

In the wizard, you must specify the following:

CoClass name: This is the name of the object as it appears to clients. The class created to implement your object has this name with a ‘T’ prepended. If you do not choose to implement an existing interface, the wizard gives your CoClass a default interface that has this name with an ‘I’ prepended.

Interface to implement: By default, the wizard gives your object a default interface that descends from IUnknown. After exiting the wizard, you can then use the Type Library editor to add properties and methods to this interface. However, you can also select a pre-defined interface for your object to implement. Click the List button in the COM object wizard to bring up the Interface Selection wizard, where you can select any dual or custom interface defined in a type library registered on your system. The interface you select becomes the default interface for your new CoClass. The wizard adds all the methods on this interface to the generated implementation class, so that you only need to fill in the bodies of the methods in the implementation unit. Note that if you select an existing interface, the interface is not added to your project’s type library. This means that when deploying your object, you must also deploy the type library that defines the interface.

Instancing: Unless you are creating an in-process server, you need to indicate how COM launches the application that houses your COM object. If your application implements more than one COM object, you should specify the same instancing for all of them.

Threading Model: Typically, client requests to your object enter on different threads of execution. You can specify how COM serializes these threads when it calls your object. Your choice of threading model determines how the object is registered. You are responsible for providing any threading support implied by the model you choose. For information on how to provide thread support to your application, see Writing multi-threaded applications

Type Library: You can choose whether you want to include a type library for your object. This is recommended for two reasons: it lets you use the Type Library editor to define interfaces, thereby updating much of the implementation, and it gives clients an easy way to obtain information about your object and its interfaces. If you are implementing an existing interface, Delphi requires your project to use a type library. This is the only way to provide access to the original interface declaration.

Marshaling: If you have opted to create a type library and are willing to confine yourself to Automation-compatible types, you can let COM handle the marshaling for you when you are not generating an in-process server. By marking your object’s interface as OleAutomation in the type library, you enable COM to set up the proxies and stubs for you and handles passing parameters across process boundaries. You can only specify whether your interface is Automation-compatible if you are generating a new interface. If you select an existing interface, its attributes are already specified in its type library. If your object’s interface is not marked as OleAutomation, you must either create an in-process server or write your own marshaling code.

You can optionally add a description of your COM object. This description appears in the type library for your object if you create one.


Using the Automation object wizard
 DevGuide: Developing COM-based applications

Using the Automation object wizard

Topic groups	See also

The Automation object wizard performs the following tasks:

Creates a new unit.

Defines a new class that descends from TAutoObject and sets up the class factory constructor. For more information on the base class, see Code generated by wizards.

Adds a type library to your project and adds your object and its interface to the type library.

Before you create an Automation object, create or open the project for an application containing functionality that you want to expose. The project can be either an application or ActiveX library, depending on your needs.

To display the Automation wizard:

1	Choose File|New|Other.

2	Select the tab labeled, ActiveX.

3	Double-click the Automation Object icon.

In the wizard dialog, specify the following:

CoClass name: This is the name of the object as it appears to clients. Your object’s default interface is created with a name based on this CoClass name with an ‘I’ prepended, and the class created to implement your object has this name with a ‘T’ prepended.

Instancing: Unless you are creating an in-process server, you need to indicate how COM launches the application that houses your COM object. If your application implements more than one COM object, you should specify the same instancing for all of them.

Threading Model: Typically, client requests to your object enter on different threads of execution. You can specify how COM serializes these threads when it calls your object. Your choice of threading model determines how the object is registered. You are responsible for providing any threading support implied by the model you choose. For information on how to provide thread support to your application, see Writing multi-threaded applications.

Event support: You must indicate whether you want your object to generate events to which clients can respond. The wizard can provide support for the interfaces required to generate events and the dispatching of calls to client event handlers.

You can optionally add a description of your COM object. This description appears in the type library for your object.

The Automation object implements a dual interface, which supports both early (compile-time) binding through the VTable and late (runtime) binding through the IDispatch interface.


COM object instancing types
 DevGuide: Developing COM-based applications

COM object instancing types

Topic groups

Many of the COM wizards require you to specify an instancing mode for the object. Instancing determines how many instances of your object clients can create in a single executable. If you specify a Single Instance model, for example, then COM once a client has instantiated your object, COM removes the application from view so that other clients must launch their own instances of the application. Because this affects the visibility of your application as a whole, the instancing mode must be consistent across all objects in your application that can be instantiated by clients. That is, you should not create one object in your application that uses Single Instance mode and another in the same application that uses Multiple Instance mode.

Note:	Instancing is ignored when your COM object is used only as an in-process server.

When the wizard creates a new COM object, it can have any of the following instancing types:

Instancing	Meaning
Internal	The object can only be created internally. An external application cannot create an instance of the object directly, although your application can create the object hand pass an interface for it to clients.
Single Instance	Allows clients to create only a single instance of the object for each executable (application), so creating multiple instances results in launching multiple instances of the application. Each client has its own dedicated instance of the server application.
Multiple Instances	Specifies that multiple clients can create instances of the object in the same process space.


Choosing a threading model
 DevGuide: Developing COM-based applications

Choosing a threading model

Topic groups	See also

When creating an object using a wizard, you select a threading model that your object agrees to support. By adding thread support to your COM object, you can improve its performance, because multiple clients can access your application at the same time.

The following table lists the different threading models you can specify.

Threading model	Description	Implementation pros and cons
Single	The server provides no thread support. COM serializes client requests so that the application receives one request at a time.	Clients are handled one at a time so no threading support is needed. No performance benefit.
Apartment (or Single-threaded apartment)	COM ensures that only one client thread can call the object at a time. All client calls use the thread in which the object was created.	Objects can safely access their own instance data, but global data must be protected using critical sections or some other form of serialization. The thread’s local variables are reliable across multiple calls. Some performance benefits.
Free (also called multi-threaded apartment)	Objects can receive calls on any number of threads at any time.	Objects must protect all instance and global data using critical sections or some other form of serialization. Thread local variables are not reliable across multiple calls.
Both	This is the same as the Free-threaded model except that outgoing calls (for example, callbacks) are guaranteed to execute in the same thread.	Maximum performance and flexibility. Does not require the application to provide thread support for parameters supplied to outgoing calls.
Neutral	Multiple clients can call the object on different threads at the same time, but COM ensures that no two calls conflict.	You must guard against thread conflicts involving global data and any instance data that is accessed by multiple methods. This model should not be used with objects that have a user interface (visual controls). This model is only available under COM+. Under COM, it is mapped to the Apartment model.
Note:	Local variables (except those in callbacks) are always safe, regardless of the threading model. This is because local variables are stored on the stack and each thread has its own stack. Local variables may not be safe in callbacks when using free-threading.

The threading model you choose in the wizard determines how the object is registered in the system Registry. You must make sure that your object implementation adheres to the threading model you have chosen. For general information on writing thread-safe code, see Writing multi-threaded applications.

For more details on writing objects to support different threading models, see

Writing an object that supports the free threading model

Writing an object that supports the apartment threading model

Writing an object that supports the neutral threading model

For in-process servers, setting the threading model in the wizard sets the threading model key in the CLSID registry entry.

Out-of-process servers are registered as EXE, and Delphi initializes COM for the highest threading model required. For example, if an EXE includes a free-threaded object, it is initialized for free threading, which means that it can provide the expected support for any free-threaded or apartment-threaded objects contained in the EXE. To manually override threading behavior in EXEs, use the CoInitFlags variable.

Writing an object that supports the free threading model

Use the free threading (or both) model rather than apartment threading whenever the object needs to be accessed from more than one thread. A common example is a client application connected to an object on a remote machine. When the remote client calls a method on that object, the server receives the call on a thread from the thread pool on the server machine. This receiving thread makes the call locally to the actual object; and, because the object supports the free threading model, the thread can make a direct call into the object.

If the object supported the apartment threading model instead, the call would have to be transferred to the thread on which the object was created, and the result would have to be transferred back into the receiving thread before returning to the client. This approach requires extra marshaling.

To support free threading, you must consider how instance data can be accessed for each method. If the method is writing to instance data, you must use critical sections or some other form of serialization, to protect the instance data. Likely, the overhead of serializing critical calls is less than executing COM’s marshaling code.

Note that if the instance data is read-only, serialization is not needed.

Free-threaded in-process servers can improve performance by acting as the outer object in an aggregation with the free-threaded marshaler. The free-threaded marshaler provides a shortcut for COM’s standard thread handling when a free-threaded DLL is called by a host (client) that is not free-threaded.

To aggregate with the free threaded marshaler, you must

Call CoCreateFreeThreadedMarshaler, passing your object’s IUnknown interface for the resulting free-threaded marshaler to use:

CoCreateFreeThreadedMarshaler(self as IUnknown, FMarshaler);

This line assigns the interface for the free-threaded marshaler to a class member, FMarshaler.

Using the Type Library editor, add the IMarshal interface to the set of interfaces your CoClass implements.

In your object’s QueryInterface method, delegate calls for IDD_IMarshal to the free-threaded marshaler (stored as FMarshaler above).

Warning:	The free-threaded marshaler violates the normal rules of COM marshaling to provide additional efficiency. It should be used with care. In particular, it should only be aggregated with free-threaded objects in in-process servers, and should only be instantiated by the object that uses it (not another thread).

Writing an object that supports the apartment threading model

To implement the (single-threaded) apartment threading model, you must follow a few rules:

The first thread in the application that gets created is COM’s main thread. This is typically the thread on which WinMain was called. This must also be the last thread to uninitialize COM.

Each thread in the apartment threading model must have a message loop, and the message queue must be checked frequently.

When a thread gets a pointer to a COM interface, that pointer may only be used in that thread.

The single-threaded apartment model is the middle ground between providing no threading support and full, multi-threading support of the free threading model. A server committing to the apartment model promises that the server has serialized access to all of its global data (such as its object count). This is because different objects may try to access the global data from different threads. However, the object’s instance data is safe because the methods are always called on the same thread.

Typically, controls for use in Web browsers use the apartment threading model because browser applications always initialize their threads as apartment.

Writing an object that supports the neutral threading model

Under COM+, you can use another threading model that is in between free threading and apartment threading: the neutral model. Like the free-threading model, this model allows multiple threads to access your object at the same time. There is no extra marshaling to transfer to the thread on which the object was created. However, your object is guaranteed to receive no conflicting calls.

Writing an object that uses the neutral threading model follows much the same rules as writing an apartment-threaded object, except that you do need to guard instance data against thread conflicts if it can be accessed by different methods in the object’s interface. Any instance data that is only accessed by a single interface method is automatically thread-safe.


Defining a COM object's interface
 DevGuide: Developing COM-based applications

Defining a COM object’s interface

Topic groups	See also

When you use a wizard to create a COM object, the wizard automatically generates a type library (unless you specify otherwise in the COM object wizard). The type library provides a way for host applications to find out what the object can do. It also lets you define your object’s interface using the Type Library editor. The interfaces you define in the Type Library editor define what properties, methods, and events your object exposes to clients.

Note:	If you selected an existing interface in the COM object wizard, you do not need to add properties and methods. The definition of the interface is imported from the type library in which it was defined. Instead, simply locate the methods of the imported interface in the implementation unit and fill in their bodies.

Adding a property to the object’s interface

When you add a property to your object’s interface using the Type Library editor, it automatically adds a method to read the property’s value and/or a method to set the property’s value. The Type Library editor, in turn, adds these methods to your implementation class, and in your implementation unit creates empty method implementations for you to complete.

To add a property to your object’s interface,

1	In the type library editor, select the default interface for the object.

The default interface should be the name of the object preceded by the letter “I”. To determine the default, in the Type Library editor, choose the CoClass and Implements tab, and check the list of implemented interfaces for the one marked, “Default.”

2	To expose a read/write property, click the Property button on the toolbar; otherwise, click the arrow next to the Property button on the toolbar, and then click the type of property to expose.

3	In the Attributes pane, specify the name and type of the property.

4	On the toolbar, click the Refresh button.

A definition and skeletal implementations for the property access methods are inserted into the object’s implementation unit.

5	In the implementation unit, locate the access methods for the property. These have names of the form Get_PropertyName and Set_PropertyName. Add code that gets or sets the property value of your object. This code may simply call an existing function inside the application, access a data member that you add to the object definition, or otherwise implement the property.

Adding a method to the object’s interface

When you add a method to your object’s interface using the Type Library editor, the Type Library editor can, in turn, add the methods to your implementation class, and in your implementation unit create empty implementation for you to complete.

To expose a method via your object’s interface,

1	In the Type Library editor, select the default interface for the object.

The default interface should be the name of the object preceded by the letter “I”. To determine the default, in the Type Library editor, choose the CoClass and Implements tab, and check the list of implemented interfaces for the one marked, “Default.”

2	Click the Method button.

3	In the Attributes pane, specify the name of the method.

4	In the Parameters pane, specify the method’s return type and add the appropriate parameters.

5	On the toolbar, click the Refresh button.

A definition and skeletal implementation for the method is inserted into the object’s implementation unit.

6	In the implementation unit, locate the newly inserted method implementation. The method is completely empty. Fill in the body to perform whatever task the method represents.

Exposing events to clients

There are two types of events that a COM object can generate: traditional events and COM+ events.

COM+ events require that you create a separate event object using the event object wizard and add code to call that event object from your server object. For more information about generating COM+ events, see Generating events under COM+.

You can use the wizard to handle much of the work in generating traditional events. This process is described below.

Note:	The COM object wizard does not generate event support code. If you want your object to generate traditional events, you should use the Automation object wizard.

In order for an object to generate events, you need to do the following:

1	In the Automation wizard, check the box, Generate event support code.

The wizard creates an object that includes an Events interface as well as the default interface. This Events interface has a name of the form ICoClassnameEvents. It is an outgoing (source) interface, which means that it is not an interface your object implements, but rather is an interface that clients must implement and which your object calls. (You can see this by selecting your CoClass, going to the Implements page, and noting that the Source column on the Events interface says True.)

In addition to the Events interface, the wizard adds the IConnectionPointContainer interface to the declaration of your implementation class, and adds several class members for handling events. Of these new class members, the most important are FConnectionPoint and FConnectionPoints, which implement the IConnectionPoint and IConnectionPointContainer interfaces using built-in VCL classes. FConnectionPoint is maintained by another method that the wizard adds, EventSinkChanged.

2	In the Type Library editor, select the outgoing Events interface for your object. (This is the one with a name of the form ICoClassNameEvents)

3	Click the Method button from the Type Library toolbar. Each method you add to the Events interface represents an event handler that the client must implement.

4	In the Attributes pane, specify the name of the event handler, such as MyEvent.

5	On the toolbar, click the Refresh button.

Your object implementation now has everything it needs to accept client event sinks and maintain a list of interfaces to call when the event occurs. To call these interfaces, you can create a method to generate each event on clients.

6	In the Code Editor, add a method to your object for firing each event. For example,

unit ev;

interface

uses

ComObj, AxCtrls, ActiveX, Project1_TLB;

type

TMyAutoObject = class (TAutoObject,IConnectionPointContainer, IMyAutoObject)

private

.

.

.

public

procedure Initialize; override;

procedure Fire_MyEvent; 	{ Add a method to fire the event}

7	Implement the method you added in the last step so that it iterates through all the event sinks maintained by your object’s FConnectionPoint member:

procedure TMyAutoObject.Fire_MyEvent;

var

  I: Integer;

  EventSinkList: TList;

  EventSink: IMyAutoObjectEvents;

begin

  if FConnectionPoint <> nil then

  begin

    EventSinkList :=FConnectionPoint.SinkList; {get the list of client sinks }

    for I := 0 to EventSinkList.Count - 1 do

    begin

      EventSink := IUnknown(FEvents[I]) as IMyAutoObjectEvents;

      EventSink.MyEvent;

    end;

  end;

end;

8	Whenever you need to fire the event so that clients are informed of its occurrence, call the method that dispatches the event to all event sinks:

if EventOccurs thenFire_MyEvent; { Call method you created to fire events.}


Managing events in your Automation object
 DevGuide: Developing COM-based applications

Managing events in your Automation object

Topic groups	See also

The Automation wizard automatically generates event code if you check the option, Generate Support Code in the Automation Object wizard dialog box.

For a server to support traditional COM events, it must provide the definition of an outgoing interface which is implemented by a client. This outgoing interface includes all the event handlers the client must implement to respond to server events.

When a client has implemented the outgoing event interface, it registers its interest in receiving event notification by querying the server’s IConnectionPointContainer interface. The IConnectionPointContainer interface returns the server’s IConnectionPoint interface, which the client then uses to pass the server a pointer to its implementation of the event handlers (known as a sink).

The server maintains a list of all client sinks and calls methods on them when an event occurs.

When you select Generate Event Support Code, Delphi automatically generates the code necessary to support IConnectionPoint and IConnectionPointContainer. This support, and the way you can use it to generate events is described in Exposing events to clients.


Automation interfaces
 DevGuide: Developing COM-based applications

Automation interfaces

Topic groups

The Automation Object wizard implements a dual interface by default, which means that the Automation object supports both

Late binding at runtime, which is through the IDispatch interface. This is implemented as a dispatch interface, or dispinterface.

Early binding at compile-time, which is accomplished through directly calling one of the member functions in the object’s virtual function table (VTable). This is referred to as a custom interface.

Note:	Any interfaces generated by the COM object wizard that do not descend from IDispatch only support VTable calls.


Dual interfaces
 DevGuide: Developing COM-based applications

Dual interfaces

Topic groups

A dual interface is a custom interface and a dispinterface at the same time. It is implemented as a COM VTable interface that derives from IDispatch. For those controllers that can access the object only at runtime, the dispinterface is available. For objects that can take advantage of compile-time binding, the more efficient VTable interface is used.

Dual interfaces offer the following combined advantages of VTable interfaces and dispinterfaces:

For VTable interfaces, the compiler performs type checking and provides more informative error messages.

For Automation controllers that cannot obtain type information, the dispinterface provides runtime access to the object.

For in-process servers, you have the benefit of fast access through VTable interfaces.

For out-of-process servers, COM marshals data for both VTable interfaces and dispinterfaces. COM provides a generic proxy/stub implementation that can marshal the interface based on the information contained in a type library.

The first three entries of the VTable for a dual interface refer to the IUnknown interface, the next four entries refer to the IDispatch interface, and the remaining entries are COM entries for direct access to members of the custom interface.


Dispatch interfaces
 DevGuide: Developing COM-based applications

Dispatch interfaces

Topic groups

Automation controllers are clients that use the COM IDispatch interface to access the COM server objects. The controller must first create the object, then query the object’s IUnknown interface for a pointer to its IDispatch interface. IDispatch keeps track of methods and properties internally by a dispatch identifier (dispID), which is a unique identification number for an interface member. Through IDispatch, a controller retrieves the object’s type information for the dispatch interface and then maps interface member names to specific dispIDs. These dispIDs are available at runtime, and controllers get them by calling the IDispatch method, GetIDsOfNames.

Once it has the dispID, the controller can then call the IDispatch method, Invoke, to execute the appropriate code (property or method), packaging the parameters for the property or method into one of the Invoke parameters. Invoke has a fixed compile-time signature that allows it to accept any number of arguments when calling an interface method.

The Automation object’s implementation of Invoke must then unpackage the parameters, call the property or method, and be prepared to handle any errors that occur. When the property or method returns, the object passes its return value back to the controller.

This is called late binding because the controller binds to the property or method at runtime rather than at compile time.


Custom interfaces
 DevGuide: Developing COM-based applications

Custom interfaces

Topic groups

Custom interfaces are user-defined interfaces that allow clients to invoke interface methods based on their order in the VTable and knowledge of the argument types. The VTable lists the addresses of all the properties and methods that are members of the object, including the member functions of the interfaces that it supports. If the object does not support IDispatch, the entries for the members of the object’s custom interfaces immediately follow the members of IUnknown.

If the object has a type library, you can access the custom interface through its VTable layout, which you can get using the Type Library editor. If the object has a type library and also supports IDispatch, a client can also get the dispIDs of the IDispatch interface and bind directly to a VTable offset. Delphi’s type library importer (TLIBIMP) retrieves dispIDs at import time, so clients that use dispinterfaces can avoid calls to GetIDsOfNames; this information is already in the _TLB unit. However, clients still need to call Invoke.


Marshaling data
 DevGuide: Developing COM-based applications

Marshaling data

Topic groups	See also

For out-of-process and remote servers, you must consider how COM marshals data outside the current process. You can provide marshaling:

Automatically, using the IDispatch interface.

Automatically, by creating a type library with your server and marking the interface with the OLE Automation flag. COM knows how to marshal all the Automation-compatible types in the type library and can set up the proxies and stubs for you. Some type restrictions apply to enable automatic marshaling.

Manually by implementing all the methods of the IMarshal interface. This is called custom marshaling.

Note:	The first method (using IDispatch) is only available on Automation servers. The second method is automatically available on all objects that are created by wizards and which use a type library.

Automation compatible types

Function result and parameter types of the methods declared in dual and dispatch interfaces and interfaces that you mark as OLE Automation must be Automation-compatible types. The following types are OLE Automation-compatible:

The predefined valid types such as Smallint, Integer, Single, Double, WideString. For a complete list, see Valid types.

Enumeration types defined in a type library. OLE Automation-compatible enumeration types are stored as 32-bit values and are treated as values of type Integer for purposes of parameter passing.

Interface types defined in a type library that are OLE Automation safe, that is, derived from IDispatch and containing only OLE Automation compatible types.

Dispinterface types defined in a type library.

Any custom record type defined within the type library.

IFont, IStrings, and IPicture. Helper objects must be instantiated to map

an IFont to a TFont

an IStrings to a TStrings

an IPicture to a TPicture

The ActiveX control and ActiveForm wizards create these helper objects automatically when needed. To use the helper objects, call the global routines, GetOleFont, GetOleStrings, GetOlePicture, respectively.

Type restrictions for automatic marshaling

For an interface to support automatic marshaling (also called Automation marshaling or type library marshaling), the following restrictions apply. When you edit your object using the type library editor, the editor enforces these restrictions:

Types must be compatible for cross-platform communication. For example, you cannot use data structures (other than implementing another property object), unsigned arguments, AnsiStrings, and so on.

String data types must be transferred as wide strings (BSTR). PChar and AnsiString cannot be marshaled safely.

All members of a dual interface must pass an HRESULT as the function’s return value. If the method is declared using the safecall calling convention, this condition is imposed automatically, with the declared return type converted to an output parameter.

Members of a dual interface that need to return other values should specify these parameters as var or out, indicating an output parameter that returns the value of the function.

Note:	One way to bypass the Automation types restrictions is to implement a separate IDispatch interface and a custom interface. By doing so, you can use the full range of possible argument types. This means that COM clients have the option of using the custom interface, which Automation controllers can still access. In this case, though, you must implement the marshaling code manually.

Custom marshaling

Typically, you use automatic marshaling in out-of-process and remote servers because it is easier—COM does the work for you. However, you may decide to provide custom marshaling if you think you can improve marshaling performance. When implementing your own custom marshaling, you must support the IMarshal interface. For more information, on this approach, see the Microsoft documentation.


Registering a COM object
 DevGuide: Developing COM-based applications

Registering a COM object

Topic groups

You can register your server object as an in-process or an out-of-process server. For more information on the server types, see In-process, out-of-process, and remote servers.

Note:	Before you remove a COM object from your system, you should unregister it.

Registering an in-process server

To register an in-process server (DLL or OCX),

Choose Run|Register ActiveX Server.

To unregister an in-process server,

Choose Run|Unregister ActiveX Server.

Registering an out-of-process server

To register an out-of-process server,

Run the server with the /regserver command-line option.

You can set command-line options with the Run|Parameters dialog box.

You can also register the server by running it.

To unregister an out-of-process server,

Run the server with the /unregserver command-line option.

As an alternative, you can use the tregsvr command from the command line or run the regsvr32.exe from the operating system.

Note:	If the COM server is intended for use under COM+, you should install it in a COM+ application rather than register it. (Installing the object in a COM+ application automatically takes care of registration.) For information on how to install an object in a COM+ application, see Installing transactional objects.


Testing and debugging the application
 DevGuide: Developing COM-based applications

Testing and debugging the application

Topic groups	See also

To test and debug your COM server application,

1	Turn on debugging information using the Compiler tab on the Project|Options dialog box, if necessary. Also, turn on Integrated Debugging in the Tools|Debugger Options dialog.

2	For an in-process server, choose Run|Parameters, type the name of the Automation controller in the Host Application box, and choose OK.

3	Choose Run|Run.

4	Set breakpoints in the Automation server.

5	Use the Automation controller to interact with the Automation server.

The Automation server pauses when the breakpoints are reached.

Note:	As an alternate approach, if you are also writing the Automation controller, you can debug into an in-process server by enabling COM cross-process support. Use the General page of the Tools|Debugger Options dialog to enable cross-process support.


Creating Active Server Pages: Overview
 DevGuide: Developing COM-based applications

Creating an Active Server Page

Topic groups	See also

If you are using the Microsoft Internet Information Server (IIS) environment to serve your Web pages, you can use Active Server Pages (ASP) to create dynamic Web- based client-server applications. Active Server Pages let you write a script that gets called every time the server loads the Web page. This script can, in turn, call on Automation objects to obtain information that it includes in a generated HTML page. For example, you can write a Delphi Automation server, such as one to create a bitmap or connect to a database, and use this control to access data that gets updated every time the server loads the Web page.

On the client side, the ASP acts like a standard HTML document and can be viewed by users on any platform using any Web Browser.

ASP applications are analogous to applications you write using Delphi’s Web broker technology. For more information about the Web broker technology, see Creating Internet server applications  . ASP differs, however, in the way it separates the UI design from the implementation of business rules or complex application logic.

The UI design is managed by the Active Server Page. This is essentially an HTML document, but it can include embedded script that calls on Active Server objects to supply it with content that reflects your business rules or application logic.

The application logic is encapsulated by Active Server objects that expose simple methods to the Active Server Page, supplying it with the content it needs.

Note:	Although ASP provides the advantage of separating UI design from application logic, its performance is limited in scale. For Web sites that respond to extremely large numbers of clients, an approach based on the Web broker technology is recommended instead.

The script in your Active Server Pages and the Automation objects you embed in an active server page can make use of the ASP intrinsics  (built-in objects that provide information about the current application, HTTP messages from the browser, and so on).

The following topics show how to create an Active Server Object using the Delphi Active Server Object wizard. This special Automation control can then be called by an Active Server Page and supply it with content.

Here are the steps for creating an Active Server Object:

Create an Active Server Object for the application.

Define the Active Server Object’s interface.

Register the Active Server Object.

Test and debug the application.


Creating an Active Server Object
 DevGuide: Developing COM-based applications

Creating an Active Server Object

Topic groups	See also

An Active Server Object is an Automation object that has access to information about the entire ASP application and the HTTP messages it uses to communicate with browsers. It descends from TASPObject or TASPMTSObject (which is in turn a descendant of TAutoObject), and supports Automation protocols, exposing itself for other applications (or the script in the Active Server page) to use. You create an Active Server Object using the Active Server Object wizard.

Your Active Server Object project can be either an executable (exe) or library (dll), depending on your needs. However, you should be aware of the drawbacks of using an out-of-process server.

To display the Active Server Object wizard:

1	Choose File|New|Other.

2	Select the tab labeled, ActiveX.

3	Double-click the Active Server Object icon.

In the wizard, give your new Active Server Object a name, and specify the instancing  and threading models you want to support. These details influence the way your object can be called. You must write the implementation so that it adheres to the model (for example, avoiding thread conflicts). The thing that makes an Active Server Object unique is its ability to access information about the ASP application and the HTTP messages that pass between the Active Server page and client Web browsers. This information is accessed using the ASP intrinsics . In the wizard, you can specify how your object accesses these by setting the Active Server Type:

If you are working with IIS 3 or IIS 4, you use Page Level Event Methods. Under this model, your object implements the methods, OnStartPage and OnEndPage, which are called when the Active Server page loads and unloads. When your object is loaded, it automatically obtains an IScriptingContext interface, which it uses to access the ASP intrinsics. These interfaces are, in turn, surfaced as properties inherited from the base class (TASPObject).

If you are working with IIS5 or later, you use the Object Context type. Under this model, your object fetches an IObjectContext interface, which it uses to access the ASP intrinsics. Again, these interfaces are surfaced as properties in the inherited base class (TASPMTSObject). One advantage of this latter approach is that your object has access to all of the other services available through IObjectContext. To access the IObjectContext interface, simply call GetObjectContext (defined in the mtx unit) as follows:

ObjectContext := GetObjectContext;

For more information about the services available through IObjectContext, see Creating MTS or COM+ objects.

You can tell the wizard to generate a simple ASP page to host your new Active Server Object. The generated page provides a minimal script (written in VBScript) that creates your Active Server Object based on its ProgID, and indicates where you can call its methods. This script calls Server.CreateObject to launch your Active Server Object.

Note:	Although the generated test script uses VBScript, Active Server Pages also can be written using Jscript.

When you exit the wizard, a new unit is added to the current project that contains the definition for the Active Server Object. In addition, the wizard adds a type library project and opens the Type Library editor. Now you can expose the properties and methods of the interface through the type library as described in Defining a COM object’s interface As you write the implementation of your object’s properties and methods, you can take advantage of the ASP intrinsics  to obtain information about the ASP application and the HTTP messages it uses to communicate with browsers.

The Active Server Object, like any other Automation object, implements a dual interface, which supports both early (compile-time) binding through the VTable and late (runtime) binding through the IDispatch interface.


Using the ASP intrinsics
 DevGuide: Developing COM-based applications

Using the ASP intrinsics

Topic groups	See also

The ASP intrinsics are a set of COM objects supplied by ASP to the objects running in an Active Server Page. They let your Active Server Object access information that reflects the messages passing between your application and the Web browser, as well as a place to store information that is shared among Active Server Objects that belong to the same ASP application.

To make these objects easy to access, the base class for your Active Server Object surfaces them as properties. For a complete understanding of these objects, see the Microsoft documentation. However, the following topics provide a brief overview.

Application

The Application object is accessed through an IApplicationObject interface. It represents the entire ASP application, which is defined as the set of all .asp files in a virtual directory and its subdirectories. The Application object can be shared by multiple clients, so it includes locking support that you should use to prevent thread conflicts.

IApplicationObject includes the following:

Property, Method, or Event	Meaning
Contents property	Lists all the objects that were added to the application using script commands. This interface has two methods, Remove and RemoveAll, that you can use to delete one or all objects from the list.
StaticObjects property	Lists all the objects that were added to the application with the <OBJECT> tag.
Lock method	Prevents other clients from locking the Application object until you call Unlock. All clients should call Lock before accessing shared memory (such as the properties).
Unlock method	Releases the lock that was set using the Lock method.
Application_OnEnd event	Occurs when the application quits, after the Session_OnEnd event. The only intrinsics available are Application and Server. The event handler must be written in VBScript or JScript.
Application_OnStart event	Occurs before the new session is created (before Session_OnStart). The only intrinsics available are Application and Server. The event handler must be written in VBScript or JScript.
Request

The Request object is accessed through an IRequest interface. It provides information about the HTTP request message that caused the Active Server Page to be opened.

IRequest includes the following:

Property, Method, or Event	Meaning
ClientCertificate property	Indicates the values of all fields in the client certificate that is sent with the HTTP message.
Cookies property	Indicates the values of all Cookie headers on the HTTP message.
Form property	Indicates the values of form elements in the HTTP body. These can be accessed by name.
QueryString property	Indicates the values of all variables in the query string from the HTTP header.
ServerVariables property	Indicates the values of various environment variables. These variables represent most of the common HTTP header variables.
TotalBytes property	Indicates the number of bytes in the request body. This is an upper limit on the number of bytes returned by the BinaryRead method.
BinaryRead method	Retrieves the content of a Post message. Call the method, specifying the maximum number of bytes to read. The resulting content is returns as a Variant array of bytes. After calling BinaryRead, you can’t use the Form property.
Response

The Request object is accessed through an IResponse interface. It lets you specify information about the HTTP response message that is returned to the client browser.

IResponse includes the following:

Property, Method, or Event	Meaning
Cookies property	Determines the values of all Cookie headers on the HTTP message.
Buffer property	Indicates whether page output is buffered When page output is buffered, the server does not send a response to the client until all of the server scripts on the current page are processed.
CacheControl property	Determines whether proxy servers can cache the output in the response.
Charset property	Adds the name of the character set to the content type header.
ContentType property	Specifies the HTTP content type of the response message’s body.
Expires property	Specifies how long the response can be cached by a browser before it expires.
ExpiresAbsolute property	Specifies the date and time when the response expires.
IsClientConnected property	Indicates whether the client has disconnected from the server.
Pics property	Set the value for the pics-label field of the response header.
Status property	Indicates the status of the response. This is the value of an HTTP status header.
AddHeader method	Adds an HTTP header with a specified name and value.
AppendToLog method	Adds a string to the end of the Web server log entry for this request.
BinaryWrite method	Writes raw (uninterpreted) information to the body of the response message.
Clear method	Erases any buffered HTML output.
End method	Stops processing the .asp file and returns the current result.
Flush method	Sends any buffered output immediately.
Redirect method	Sends a redirect response message, redirecting the client browser to a different URL.
Write method	Writes a variable to the current HTTP output as a string.
Session

The Session object is accessed through the ISessionObject interface. It allows you to store variables that persist for the duration of a client’s interaction with the ASP application. That is, these variables are not freed when the client moves from page to page within the ASP application, but only when the client exits the application altogether.

ISessionObject includes the following:

Property, Method, or Event	Meaning
Contents property	Lists all the objects that were added to the session using the <OBJECT> tag. You can access any variable in the list by name, or call the Contents object’s Remove or RemoveAll method to delete values.
StaticObjects property	Lists all the objects that were added to the session with the <OBJECT> tag.
CodePage property	Specifies the code page to use for symbol mapping. Different locales may use different code pages.
LCID property	Specifies the locale identifier to use for interpreting string content.
SessionID property	Indicates the session identifier for the current client.
Timeout property	Specifies the time, in minutes, that the session persists without a request (or refresh) from the client until the application terminates.
Abandon method	Destroys the session and releases its resources.
Session_OnEnd event	Occurs when the session is abandoned or times out. The only intrinsics available are Application, Server, and Session. The event handler must be written in VBScript or JScript.
Session_OnStart event	Occurs when the server creates a new session is created (after Application_OnStart but before running the script on the Active Server Page). All intrinsics are available. The event handler must be written in VBScript or JScript.
Server

The Server object is accessed through an IServer interface. It provides various utilities for writing your ASP application.

IServer includes the following:

Property, Method, or Event	Meaning
ScriptTimeout property	Same as the Timeout property on the Session object.
CreateObject method	Instantiates a specified Active Server Object.
Execute method	Executes the script in a specified .asp file.
GetLastError method	Returns an ASPError object that describes the error condition.
HTMLEncode method	Encodes a string for use in an HTML header, replacing reserved characters by the appropriate symbolic constants.
MapPath method	Maps a specified virtual path (an absolute path on the current server or a path relative to the current page) into a physical path.
Transfer method	Sends all of the current state information to another Active Server Page for processing.
URLEncode method	Applies URL encoding rules, including escape characters, to a specified string


Creating ASPs for in-process or out-of-process servers
 DevGuide: Developing COM-based applications

Creating ASPs for in-process or out-of-process servers

Topic groups	See also

You can use Server.CreateObject in an ASP page to launch either an in-process or out-of-process server, depending on your requirements. However, launching in-process servers is more common.

Unlike most in-process servers, an Active Server Object in an in-process server does not run in the client’s process space. Instead, it runs in the IIS process space. This means that the client does not need to download your application (as, for example, it does when you use ActiveX objects). In-process component DLLs are faster and more secure than out-of-process servers, so they are better suited for server-side use.

Because out-of-process servers are less secure, it is common for IIS to be configured to not allow out-of-process executables. In this case, creating an out-of-process server for your Active Server Object would result in an error similar to the following:

Server object error 'ASP 0196'

Cannot launch out of process component

/path/outofprocess_exe.asp, line 11

Also, out-of-process components often create individual server processes for each object instance, so they are slower than CGI applications. They do not scale as well as component DLLs.

If performance and scalability are priorities for your site, in-process servers are highly recommended. However, Intranet sites that receive moderate to low traffic may use an out-of-process component without adversely affecting the site's overall performance.


Registering an Active Server Object
 DevGuide: Developing COM-based applications

Registering an Active Server Object

Topic groups

You can register the Active Server Page as an in-process or an out-of-process server. However, in-process servers are more common.

Note:	When you want to remove the Active Server Page object from your system, you should first unregister it, removing its entries from the Windows registry.

Registering an in-process server

To register an in-process server (DLL or OCX),

Choose Run|Register ActiveX Server.

To unregister an in-process server,

Choose Run|Unregister ActiveX Server.

Registering an out-of-process server

To register an out-of-process server,

Run the server with the /regserver command-line option. (You can set command-line options with the Run|Parameters dialog box.)

You can also register the server by running it.

To unregister an out-of-process server,

Run the server with the /unregserver command-line option.


Testing and debugging the Active Server Page application
 DevGuide: Developing COM-based applications

Testing and debugging the Active Server Page application

Topic groups	See also

Debugging any in-process server such as an Active Server Object is much like debugging a DLL. You choose a host application that loads the DLL, and debug as usual. To test and debug an Active Server Object,

1	Turn on debugging information using the Compiler tab on the Project|Options dialog box, if necessary. Also, turn on Integrated Debugging in the Tools|Debugger Options dialog.

2	Choose Run|Parameters, type the name of your Web Server in the Host Application box, and choose OK.

3	Choose Run|Run.

4	Set breakpoints in the Active Server Object implementation.

5	Use the Web browser to interact with the Active Server Page.

The debugger pauses when the breakpoints are reached.


Creating an ActiveX control: Overview
 DevGuide: Developing COM-based applications

Creating an ActiveX control

Topic groups	See also

An ActiveX control is a software component that integrates into and extends the functionality of any host application that supports ActiveX controls, such as C++Builder, Delphi, Visual Basic, Internet Explorer, and (given a plug-in) Netscape Navigator. ActiveX controls implement a particular set of interfaces that allow this integration.

For example, Delphi comes with several ActiveX controls, including charting, spreadsheet, and graphics controls. You can add these controls to the component palette in the IDE, and then use them like any standard VCL component, dropping them on forms and setting their properties using the Object Inspector.

An ActiveX control can also be deployed on the Web, allowing it to be referenced in HTML documents and viewed with ActiveX-enabled Web browsers.

Delphi provides wizards that let you create two types of ActiveX controls:

ActiveX controls that wrap VCL classes. By wrapping a VCL class, you can convert existing components into ActiveX controls or create new ones, test them out locally, and then convert them into ActiveX controls. ActiveX controls are typically intended to be embedded in a larger host application.

Active forms. Active forms let you use the form designer to create a more elaborate control that acts like a dialog or like a complete application. You develop the Active form in much the same way that you develop a typical Delphi application. Active Forms are typically intended for deployment on the Web.

Overview of ActiveX control creation

Creating ActiveX controls using Delphi is very similar to creating ordinary controls or forms. This differs markedly from creating other COM objects, where you first define the object’s interface and then complete the implementation. To create ActiveX controls (other than Active Forms), you reverse this process, starting with the implementation of a VCL control, and then generating the interface and type library once the control is written. When creating Active Forms, the interface and type library are created at the same time as your form, and then you use the form designer to implement the form.

The completed ActiveX control consists of a VCL control that provides the underlying implementation, a COM object that wraps the VCL control, and a type library that lists the COM object’s properties, methods, and events. For details, see Elements of an ActiveX control.

To create a new ActiveX control (other than an Active Form), perform the following steps:

1	Design and create the custom VCL control that forms the basis of your ActiveX control.

2	Use the ActiveX control wizard to create an ActiveX control from the VCL control you created in step 1.

3	Use the Use the ActiveX property page wizard to create one or more property pages for the control (optional).

4	Associate a property page with an ActiveX control(optional).

5	Register an ActiveX control.

6	Test an ActiveX control with all potential target applications.

7	Deploy the ActiveX control on the Web. (optional)

To create a new Active Form, perform the following steps:

1	Use the ActiveForm wizard to create an Active Form, which appears as a blank form in the IDE, and an associated ActiveX wrapper for that form.

2	Use the form designer to add components to your Active Form and implement its behavior in the same way you create and implement an ordinary form using the form designer.

3	Follow steps 3-7 above to give your Active Form a property page, register it, and deploy it on the Web.


Elements of an ActiveX control
 DevGuide: Developing COM-based applications

Elements of an ActiveX control

Topic groups	See also

An ActiveX control involves many elements which each perform a specific function. The elements include a VCL control, a corresponding COM object wrapper that exposes properties, methods, and events, and one or more associated type libraries.

VCL control

The underlying implementation of an ActiveX control in Delphi is a VCL control. When you create an ActiveX control, you must first design or choose the VCL control from which you will make your ActiveX control.

The underlying VCL control must be a descendant of TWinControl, because it must have a window that can be parented by the host application. When you create an Active form, this object is a descendant of TActiveForm.

Note:	The ActiveX control wizard lists the available TWinControl descendants from which you can choose to make an ActiveX control. This list does not include all TWinControl descendants, however. Some controls, such as THeaderControl, are registered as incompatible with ActiveX (using the RegisterNonActiveX procedure) and do not appear in the list.

ActiveX wrapper

The actual COM object is an ActiveX wrapper object for the VCL control. For Active forms, this class is always TActiveFormControl. For other ActiveX controls, it has a name of the form TVCLClassX, where TVCLClass is the name of the VCL control class. Thus, for example, the ActiveX wrapper for TButton would be named TButtonX.

The wrapper class is a descendant of TActiveXControl, which provides support for the ActiveX interfaces. The ActiveX wrapper inherits this support, which allows it to forward Windows messages to the VCL control and parent its window in the host application.

The ActiveX wrapper exposes the VCL control’s properties and methods to clients via its default interface. The wizard automatically implements most of the wrapper class’s properties and methods, delegating method calls to the underlying VCL control. The wizard also provides the wrapper class with methods that fire the VCL control’s events on clients and assigns these methods as event handlers on the VCL control.

Type library

The ActiveX control wizards automatically generate a type library that contains the type definitions for the wrapper class, its default interface, and any type definitions that these require. This type information provides a way for your control to advertise its services to host applications. You can view and edit this information using the Type Library editor. Although this information is stored in a separate, binary type library file (.TLB extension), it is also automatically compiled into the ActiveX control DLL as a resource.

Property page

You can optionally give your ActiveX control a property page. The property page allows the user of a host (client) application to view and edit your control’s properties. You can group several properties on a page, or use a page to provide a dialog-like interface for a property. For information on how to create property pages, see Creating a property page for an ActiveX control.


Designing an ActiveX control
 DevGuide: Developing COM-based applications

Designing an ActiveX control

Topic groups	See also

When designing an ActiveX control, you start by creating a custom VCL control. This forms the basis of your ActiveX control. For information on creating custom controls, see the online manual, Creating custom components.

When designing the VCL control, keep in mind that it will be embedded in another application; this control is not an application in itself. For this reason, you probably do not want to use elaborate dialog boxes or other major user-interface components. Your goal is typically to make a simple control that works inside of, and follows the rules of the main application.

In addition, you should make sure that the types for all properties and methods you want your object to expose to clients are Automation-compatible, because the ActiveX control’s interface must support IDispatch. The wizard does not add any methods to the wrapper class’s interface that have parameters that are not Automation-compatible.

The wizards implement all the necessary ActiveX interfaces required using the COM wrapper class. They also surface all Automation-compatible properties, methods, and events through the wrapper class’s default interface. Once the wizard has generated the COM wrapper class and its interface, you can use the Type Library editor to modify the default interface or augment the wrapper class by implementing additional interfaces.


Generating an ActiveX control from a VCL control
 DevGuide: Developing COM-based applications

Generating an ActiveX control from a VCL control

Topic groups	See also

To generate an ActiveX control from a VCL control, use the ActiveX Control wizard. The properties, methods, and events of the VCL control become the properties, methods, and events of the ActiveX control.

Before using the ActiveX control wizard, you must decide what VCL control will provide the underlying implementation of the generated ActiveX control.

To bring up the ActiveX control wizard,

1	Choose File|New|Other to open the New Items dialog box.

2	Select the tab labeled ActiveX.

3	Double-click the ActiveX Control icon.

In the wizard, select the name of the VCL control that will be wrapped by the new ActiveX control. The dialog lists all available controls, which are descendants of TWinControl that are not registered as incompatible with ActiveX using the RegisterNonActiveX procedure.

Tip:	If you do not see the control you want in the drop-down list, check whether you have installed it in the IDE or added its unit to your project.

Once you have selected a VCL control, the wizard automatically generates a name for the CoClass, the implementation unit for the ActiveX wrapper, and the ActiveX library project. (If you currently have an ActiveX library project open, and it does not contain a COM+ event object, the current project is automatically used.) You can change any of these in the wizard (unless you have an ActiveX library project already open, in which case the project name is not editable).

The wizard always specifies Apartment as the threading model. This is not a problem if your ActiveX project usually contains only a single control. However, if you add additional objects to your project, you are responsible for providing thread support.

The wizard also lets you configure various options on your ActiveX control:

Enabling licensing: You can make your control licensed to ensure that users of the control can't open it either for design purposes or at runtime unless they have a license key for the control.

Including Version information: You can include version information, such as a copyright or a file description, in the ActiveX control. This information can be viewed in a browser. Some host clients, such as Visual Basic 4.0, require Version information or they will not host the ActiveX control. Specify version information by choosing Project|Options and selecting the Version Info page.

Including an About box: You can tell the wizard to generate a separate form that implements an About box for your control. Users of the host application can display this About box in a development environment. By default, the About box includes the name of the ActiveX control, an image, copyright information, and an OK button. You can modify this default form, which the wizard adds to your project.

When you exit the wizard, it generates the following:

An ActiveX Library project file, which contains the code required to start an ActiveX control. You usually don’t change this file.

A type library, which defines and CoClass for your control, the interface it exposes to clients, and any type definitions that these require. For more information about the type library, see Working with type libraries.

An ActiveX implementation unit, which defines and implements the ActiveX control, a descendant of TActiveXControl. This ActiveX control is a fully-functioning implementation that requires no additional work on your part. However, you can modify this class if you want to customize the properties, methods, and events that the ActiveX control exposes to clients.

An About box form and unit if you requested them.

A .LIC file if you enabled licensing.


Generating an ActiveX control based on a VCL form
 DevGuide: Developing COM-based applications

Generating an ActiveX control based on a VCL form

Topic groups	See also

Unlike other ActiveX controls, Active Forms are not first designed and then wrapped by an ActiveX wrapper class. Instead, the ActiveForm wizard generates a blank form that you design later when the wizard leaves you in the Form Designer.

When an ActiveForm is deployed on the Web, Delphi creates an HTML page to contain the reference to the ActiveForm and specify its location on the page. The ActiveForm can then displayed and run from a Web browser. Inside the browser, the form behaves just like a stand-alone Delphi form. The form can contain any VCL components or ActiveX controls, including custom-built VCL controls.

To start the ActiveForm wizard,

1	Choose File|New|Other to open the New Items dialog box.

2	Select the tab labeled ActiveX.

3	Double-click the ActiveForm icon.

The Active Form wizard looks just like the ActiveX control wizard, except that you can’t specify the name of the VCL class to wrap. This is because Active forms are always based on TActiveForm.

As in the ActiveX control wizard, you can change the default names for the CoClass, implementation unit, and ActiveX library project. Similarly, this wizard lets you indicate whether you want your Active Form to require a license, whether it should include version information, and whether you want an About box form.

When you exit the wizard, it generates the following:

An ActiveX Library project file, which contains the code required to start an ActiveX control. You usually don’t change this file.

A type library, which defines and CoClass for your control, the interface it exposes to clients, and any type definitions that these require. For more information about the type library, see Working with type libraries.

A form that descends from TActiveForm. This form appears in the form designer, where you can use it to visually design the Active Form that appears to clients. Its implementation appears in the generated implementation unit. In the initialization section of the implementation unit, a class factory is created, setting up TActiveFormControl as the ActiveX wrapper for this form.

An About box form and unit if you requested them.

A .LIC file if you enabled licensing.

At this point, you can add controls and design the form as you like.

After you have designed and compiled the ActiveForm project into an ActiveX library (which has the OCX extension), you can deploy the project to your Web server and Delphi creates a test HTML page with a reference to the ActiveForm.


Licensing ActiveX controls
 DevGuide: Developing COM-based applications

Licensing ActiveX controls

Topic groups	See also

Licensing an ActiveX control consists of providing a license key at design-time and supporting the creation of licenses dynamically for controls created at runtime.

To provide design-time licenses, the ActiveX wizard creates a key for the control, which it stores in a file with the same name as the project with the LIC extension. This .LIC file is added to the project. The user of the control must have a copy of the .LIC file to open the control in a development environment. Each control in the project that has Make Control Licensed checked has a separate key entry in the LIC file.

To support runtime licenses, the wrapper class implements two methods, GetLicenseString and GetLicenseFilename. These return the license string for the control and the name of the .LIC file, respectively. When a host application tries to create the ActiveX control, the class factory for the control calls these methods and compares the string returned by GetLicenseString with the string stored in the .LIC file.

Runtime licenses for the Internet Explorer require an extra level of indirection because users can view HTML source code for any Web page, and because an ActiveX control is copied to the user’s computer before it is displayed. To create runtime licenses for controls used in Internet Explorer, you must first generate a license package file (LPK file) and embed this file in the HTML page that contains the control. The LPK file is essentially an array of ActiveX control CLSIDs and license keys.

Note:	To generate the LPK file, use the utility, LPK_TOOL.EXE, which you can download from the Microsoft Web site (www.microsoft.com).

To embed the LPK file in a Web page, use the HTML objects, <OBJECT> and <PARAM> as follows:

<OBJECT CLASSID="clsid:6980CB99-f75D-84cf-B254-55CA55A69452">

    <PARAM NAME="LPKPath" VALUE="ctrllic.lpk">

</OBJECT>

The CLSID identifies the object as a license package and PARAM specifies the relative location of the license package file with respect to the HTML page.

When Internet Explorer tries to display the Web page containing the control, it parses the LPK file, extracts the license key, and if the license key matches the control’s license (returned by GetLicenseString), it renders the control on the page. If more than one LPK is included in a Web page, Internet Explorer ignores all but the first.

For more information, look for Licensing ActiveX Controls on the Microsoft Web site.


Customizing the ActiveX control's interface
 DevGuide: Developing COM-based applications

Customizing the ActiveX control’s interface

Topic groups	See also

The ActiveX Control and ActiveForm wizards generate a default interface for the ActiveX wrapper class. This default interface simply exposes the properties, methods, and events of the original VCL control or form, with the following exceptions:

Data-aware properties do not appear. Because ActiveX controls have a different mechanism for making controls data-aware than VCL controls, the wizards do not convert properties related to data. See Enabling simple data binding with the type library for information on how to make your ActiveX control data-aware.

Any property, method, or event that type that is not Automation-compatible does not appear. You may want to add these to the ActiveX control’s interface after the wizard has finished.

You can add, edit, and remove the properties, methods, and events in an ActiveX control by editing the type library. You can use the Type Library editor as described in Using the Type Library Editor. Remember that when you add events, they should be added to the Events interface, not the ActiveX control’s default interface.

Note:	You can add unpublished properties to your ActiveX control’s interface. Such properties can be set at runtime and will appear in a development environment, but changes made to them will not persist. That is, when the user of the control changes the value of a property at design time, the changes are not reflected when the control is run. If the source is a VCL object and the property is not already published, you can make properties persistent by creating a descendant of the VCL object and publishing the property in the descendant.

You may also choose not to expose all of the VCL control’s properties, methods, and events to host applications. You can use the Type Library editor to remove these from the interfaces that the wizard generated. When you remove properties and methods from an interface using the Type Library editor, the Type Library editor does not remove them from the corresponding implementation class. Edit the ActiveX wrapper class in the implementation unit to remove these after you have changed the interface in the Type Library editor.

Warning:	Any changes you make to the type library will be lost if you regenerate the ActiveX control from the original VCL control or form.

Tip:	It is a good idea to check the methods that the wizard adds to your ActiveX wrapper class. Not only does this give you a chance to note where the wizard omitted any data-aware properties or methods that were not Automation-compatible, it also lets you detect methods for which the wizard could not generate an implementation. Such methods appear with a comment in the implementation that indicates the problem.


Adding additional properties, methods, and events
 DevGuide: Developing COM-based applications

Adding additional properties, methods, and events

Topic groups	See also

You can add additional properties, methods, and events to the control using the type library editor. The declaration is automatically added to the control’s implementation unit, type library (TLB) file, and type library unit. The specifics of what Delphi supplies depends on whether you have added a property or method or whether you have added an event.


How Delphi adds properties
 DevGuide: Developing COM-based applications

How Delphi adds properties

Topic groups	See also

The ActiveX wrapper class implements properties in its interface using read and write access methods. That is, the wrapper class has COM properties, which appear on an interface as getter and/or setter methods. Unlike VCL properties, you do not see a “property” declaration on the interface for COM properties. Rather, you see methods that are flagged as property access methods. When you add a property to the ActiveX control’s default interface, the wrapper class definition (which appears in the _TLB unit that is updated by the Type Library editor) gains one or two new methods (a getter and/or setter) that you must implement, just as when you add a method to the interface, the wrapper class gains a corresponding method for you to implement. Thus, adding properties to the wrapper class’s interface is essentially the same as adding methods: the wrapper class definition gains new skeletal method implementations for you to complete.

Note:	For details on what appears in the generated _TLB unit, see Code generated when you import type library information.

For example, consider a Caption property, of type TCaption in the underlying VCL object. To Add this property to the object’s interface, you enter the following when you add a property to the interface via the type library editor:

property Caption: TCaption readGet_CaptionwriteSet_Caption;

Delphi adds the following declarations to the wrapper class:

function Get_Caption: WideString; safecall;

procedure Set_Caption(const Value: WideString); safecall;

In addition, it adds skeletal method implementations for you to complete:

function TButtonX.Get_Caption: WideString;

begin

end;

procedure TButtonX.Set_Caption(Value: WideString);

begin

end;

Typically, you can implement these methods by simply delegating to the associated VCL control, which can be accessed using the FDelphiControl member of the wrapper class:

function TButtonX.Get_Caption: WideString;

begin

  Result := WideString(FDelphiControl.Caption);

end;

procedure TButtonX.Set_Caption(const Value: WideString);

begin

  FDelphiControl.Caption := TCaption(Value);

end;

In some cases, you may need to add code to convert the COM data types to native Object Pascal types. The preceding example manages this with typecasting.

Note:	Because the Automation interface methods are declared safecall, you do not have to implement COM exception code for these methods—the Delphi compiler handles this for you by generating code around the body of safecall methods to catch Delphi exceptions and to convert them into COM error info structures and return codes.


How Delphi adds events
 DevGuide: Developing COM-based applications

How Delphi adds events

Topic groups	See also

The ActiveX control can fire events to its container in the same way that an automation object fires events to clients. This mechanism is described in Managing events in your Automation object.

If the VCL control you are using as the basis of your ActiveX control has any published events, the wizards automatically add the necessary support for managing a list of client event sinks to your ActiveX wrapper class and define the outgoing dispinterface that clients must implement to respond to events.

You add events to this outgoing dispinterface. To add an event in the type library editor, select the event interface and click on the method icon. Then manually add the list of parameters you want include using the parameter page.

Next, you must declare a method in your wrapper class that is of the same type as the event handler for the event in the underlying VCL control. This is not generated automatically, because Delphi does not know which event handler you are using:

  procedure KeyPressEvent(Sender: TObject; var Key: Char);

Implement this method to use the host application’s event sink, which is stored in the wrapper class’s FEvents member:

procedure TButtonX.KeyPressEvent(Sender: TObject; var Key: Char);

var

  TempKey: Smallint;

begin

    TempKey := Smallint(Key); {cast to an OleAutomation compatible type }

    ifFEvents <> nil then

      FEvents.OnKeyPress(TempKey)

    Key := Char(TempKey);

  end;

Note:	When firing events in an ActiveX control, you do not need to iterate through a list of event sinks because the control only has a single host application. This is simpler than the process for most Automation servers.

Finally, you must assign this event handler to the underlying VCL control, so that it is called when the event occurs. You make this assignment in the InitializeControl method:

procedure TButtonX.InitializeControl;

begin

  FDelphiControl := Control as TButton;

  FDelphiControl.OnClick := ClickEvent;

  FDelphiControl.OnKeyPress := KeyPressEvent;

end;


Enabling simple data binding with the type library
 DevGuide: Developing COM-based applications

Enabling simple data binding with the type library

Topic groups	See also

With simple data binding, you can bind a property of your ActiveX control to a field in a database. To do this, the ActiveX control must communicate with its host application about what value represents field data and when it changes. You enable this communication by setting the property’s binding flags using the Type Library editor.

By marking a property bindable, when a user modifies the property (such as a field in a database), the control notifies its container (the client host application) that the value has changed and requests that the database record be updated. The container interacts with the database and then notifies the control whether it succeeded or failed to update the record.

Note:	The container application that hosts your ActiveX control is responsible for connecting the data-aware properties you enable in the type library to the database. See Using data-aware ActiveX controls. for information on how to write such a container using Delphi.

Use the type library to enable simple data binding,

1	On the toolbar, click the property that you want to bind.

2	Choose the flags page.

3	Select the following binding attributes:

Binding attribute	Description
Bindable	Indicates that the property supports data binding. If marked bindable, the property notifies its container when the property value has changed.
Request Edit	Indicates that the property supports the OnRequestEdit notification. This allows the control to ask the container if its value can be edited by the user.
Display Bindable	Indicates that the container can show users that this property is bindable.
Default Bindable	Indicates the single, bindable property that best represents the object. Properties that have the default bind attribute must also have the bindable attribute. Cannot be specified on more than one property in a dispinterface.
Immediate Bindable	Allows individual bindable properties on a form to specify this behavior. When this bit is set, all changes will be notified. The bindable and request edit attribute bits need to be set for this new bit to have an effect.
4	Click the Refresh button on the toolbar to update the type library.

To test a data-binding control, you must register it first.

For example, to convert a TEdit control into a data-bound ActiveX control, create the ActiveX control from a TEdit and then change the Text property flags to Bindable, Display Bindable, Default Bindable, and Immediate Bindable. After the control is registered and imported, it can be used to display data.


Creating a property page for an ActiveX control
 DevGuide: Developing COM-based applications

Creating a property page for an ActiveX control

Topic groups	See also

A property page is a dialog box similar to the Delphi Object Inspector in which users can change the properties of an ActiveX control. A property page dialog allows you to group many properties for a control together to be edited at once. Or, you can provide a dialog box for more complex properties.

Typically, users access the property page by right-clicking the ActiveX control and choosing Properties.

The process of creating a property page is similar to creating a form, you

1	 Create a new property page.

2	Add controls to the property page.

3	Associate the controls the property page with the properties of an ActiveX control.

4	Connect the property page to the ActiveX control.

Note:	When adding properties to an ActiveX control or ActiveForm, you must publish the properties that you want to persist. If they are not published in the underlying VCL control, you must make a custom descendant of the VCL control that redeclares the properties as published and then use the ActiveX control wizard to create an ActiveX control from the descendant class.


Creating a new property page
 DevGuide: Developing COM-based applications

Creating a new property page

Topic groups	See also

You use the Property Page wizard to create a new property page.

To create a new property page,

1	Choose File|New|Other.

2	Select the ActiveX tab.

3	Double-click the Property Page icon.

The wizard creates a new form and implementation unit for the property page. The form is a descendant of TPropertyPage, which lets you associate the form with the ActiveX control whose properties it edits.


Adding controls to a property page
 DevGuide: Developing COM-based applications

Adding controls to a property page

Topic groups	See also

You must add a control to the property page for each property of the ActiveX control that you want the user to access.

For example, the following illustration shows a property page for setting the MaskEdit property of an ActiveX control.

Mask Edit property page in design mode

The list box allows the user to select from a list of sample masks. The edit controls allow the user to test the mask before applying it to the ActiveX control. You add controls to the property page the same as you would to a form.


Associating property page controls with ActiveX control properties
 DevGuide: Developing COM-based applications

Associating property page controls with ActiveX control properties

Topic groups	See also

After adding the controls you need to the property page, you must associate each control with its corresponding property. You make this association by adding code to the property page’s UpdatePropertyPage and UpdateObject methods.


Updating the property page
 DevGuide: Developing COM-based applications

Updating the property page

Topic groups	See also

Add code to the UpdatePropertyPage method to update the control on the property page when the properties of the ActiveX control change. You must add code to the UpdatePropertyPage method to update the property page with the current values of the ActiveX control’s properties.

You can access the ActiveX control using the property page’s OleObject property, which is an OleVariant that contains the ActiveX control’s interface.

For example, the following code updates the property page’s edit control (InputMask) with the current value of the ActiveX control’s EditMask property:

procedure TPropertyPage1.UpdatePropertyPage;

begin

{ Update your controls from OleObject }

InputMask.Text := OleObject.EditMask;

end;

Note:	It is also possible to write a property page that represents more than one ActiveX control. In this case, you don’t use the OleObject property. Instead, you must iterate through a list of interfaces that is maintained by the OleObjects property.


Updating the object
 DevGuide: Developing COM-based applications

Updating the object

Topic groups	See also

Add code to the UpdateObject method to update the property when the user changes the controls on the property page. You must add code to the UpdateObject method in order to set the properties of the ActiveX control to their new values.

You use the OleObject property to access the ActiveX control.

For example, the following code sets the EditMask property of the ActiveX control using the value in the property page’s edit box control (InputMask):

procedure TPropertyPage1.UpdateObject;

begin

{Update OleObject from your control }

OleObject.EditMask := InputMask.Text;

end;


Connecting a property page to an ActiveX control
 DevGuide: Developing COM-based applications

Connecting a property page to an ActiveX control

Topic groups	See also

To connect a property page to an ActiveX control,

1	Add DefinePropertyPage with the GUID constant of the property page as the parameter to the DefinePropertyPages method implementation in the control’s implementation for the unit. For example,

procedure TButtonX.DefinePropertyPages(DefinePropertyPage: TDefinePropertyPage);

begin

DefinePropertyPage(Class_PropertyPage1);

end;

The GUID constant, Class_PropertyPage1, of the property page can be found in the property pages unit.

The GUID is defined in the property page’s implementation unit; it is generated automatically by the Property Page wizard.

2	Add the property page unit to the uses clause of the controls implementation unit.


Registering an ActiveX control
 DevGuide: Developing COM-based applications

Registering an ActiveX control

Topic groups

After you have created your ActiveX control, you must register it so that other applications can find and use it.

To register an ActiveX control:

Choose Run|Register ActiveX Server.

Note:	Before you remove an ActiveX control from your system, you should unregister it.

To unregister an ActiveX control:

Choose Run|Unregister ActiveX Server.

As an alternative, you can use the tregsvr command from the command line or run the regsvr32.exe from the operating system.


Testing an ActiveX control
 DevGuide: Developing COM-based applications

Testing an ActiveX control

Topic groups	See also

To test your control, add it to a package and import it as an ActiveX control. This procedure adds the ActiveX control to the Delphi component palette. You can drop the control on a form and test as needed.

Your control should also be tested in all target applications that will use the control.

To debug the ActiveX control, select Run|Parameters and type the client name in the Host Application edit box.

The parameters then apply to the host application. Selecting Run|Run will run the host or client application and allow you to set breakpoints in the control.


Deploying an ActiveX control on the Web
 DevGuide: Developing COM-based applications

Deploying an ActiveX control on the Web

Topic groups	See also

Before the ActiveX controls that you create can be used by Web clients, they must be deployed on your Web server. Every time you make a change to the ActiveX control, you must recompile and redeploy it so that client applications can see the changes.

Before you can deploy your ActiveX control, you must have a Web Server that will respond to client messages.

To deploy your ActiveX control, use the following steps:

1	Select Project|Web Deployment Options.

2	On the Project page, set the Target Dir to the location of the ActiveX control DLL as a path on the Web server. This can be a local path name or a UNC path, for example, C:\INETPUB\wwwroot.

3	Set the Target URL to the location as a Uniform Resource Locators (URL) of the ActiveX control DLL (without the file name) on your Web Server, for example, http://mymachine.inprise.com/. See the documentation for your Web Server for more information on how to do this.

4	Set the HTML Dir to the location (as a path) where the HTML file that contains a reference to the ActiveX control should be placed, for example, C:\INETPUB\wwwroot. This path can be a standard path name or a UNC path.

5	Set desired Web deployment options.

6	Choose OK.

7	Choose Project|Web Deploy.

This creates a deployment code base that contains the ActiveX control in an ActiveX library (with the OCX extension). Depending on the options you specify, this deployment code base can also contain a cabinet (with the CAB extension) or information (with the INF extension).

The ActiveX library is placed in the Target Directory you specified in step 2. The HTML file has the same name as the project file but with the HTM extension. It is created in the HTML Directory specified in step 4. The HTML file contains a URL reference to the ActiveX library at the location specified in step 3.

Note:	If you want to put these files on your Web server, use an external utility such as ftp.

8	Invoke your ActiveX-enabled Web browser and view the created HTML page.

When this HTML page is viewed in the Web browser, your form or control is displayed and runs as an embedded application within the browser. That is, the library runs in the same process as the browser application.


Setting Web deployment options
 DevGuide: Developing COM-based applications

Setting Web deployment options

Topic groups	See also

Before deploying an ActiveX control, specify the Web deployment options that should be followed when creating the ActiveX library.

Web deployment options include settings to allow you to set the following:

Including additional files: If your ActiveX control depends on any packages or other additional files, you can indicate that these should be deployed with the project. By default, these files use the same options that you specify for the entire project, but you can override these settings using the Packages or Additional files tab. When you include packages or additional files, Delphi creates a file with the .INF extension (for INFormation). This file specifies the various files that need to be downloaded and set up for the ActiveX library to run. The syntax of the INF file allows URLs pointing to packages or additional files to download.

CAB file compression: A cabinet is a single file, usually with a CAB file extension, that stores compressed files in a file library. Cabinet compression can dramatically decrease download time (up to 70%) of a file. During installation, the browser decompresses the files stored in a cabinet and copies them to the user’s system. Each file that you deploy can be CAB file compressed. You can specify that the ActiveX library use CAB file compression on the Project tab of the Web Deployment options dialog.

Version information: You can specify that you want version information included with your ActiveX control. This information is set in the VersionInfo page of the Project Options dialog. Part of this information is the release number, which you can have automatically updated every time you deploy your ActiveX control. If you include additional packages or files, their Version information resources can get added to the INF file as well.

Depending on whether you include additional files and whether you use CAB file compression, the resulting ActiveX library may be an OCX file, a CAB file containing an OCX file, or an INF file. The following table summarizes the results of choosing different combinations.

Packages and/or additional files	CAB file compression	Result
No	No	An ActiveX library (OCX) file.
No	Yes	A CAB file containing an ActiveX library file.
Yes	No	An INF file, an ActiveX library file, and any additional files and packages.
Yes	Yes	An INF file, a CAB file containing an ActiveX library, and a CAB file each for any additional files and packages.


Creating MTS or COM+ objects: Overview
 DevGuide: Developing COM-based applications

Creating MTS or COM+ objects

Topic groups	See also

Delphi uses the term transactional objects to refer to objects that take advantage of the transaction services, security, and resource management supplied by Microsoft Transaction Server (MTS) (for versions of Windows prior to Windows 2000) or COM+ (for Windows 2000 and later). These objects are designed to work in a large, distributed environment. They are not available for use in cross-platform applications due to their dependence on Windows-specific technology.

Delphi provides a wizard that creates transactional objects so that you can take advantage of the benefits of COM+ attributes or the MTS environment. These features make creating COM clients and servers, particularly remote servers, easier to implement.

Note:	For database applications, Delphi also provides a Transactional Data Module. For more information, see Creating multi-tiered applications.

Transactional objects make use of a number of low-level services, such as

Managing system resources, including processes, threads, and database connections so that your server application can handle many simultaneous users

Automatically initiating and controlling transactions so that your application is reliable.

Creating, executing, and deleting server components when needed.

Providing role-based security so that only authorized users can access your application.

Managing events so that clients can respond to conditions that arise on the server (COM+ only).

By letting MTS or COM+ provide these underlying services, you can concentrate on developing the specifics for your particular distributed application. Which technology you choose (MTS or COM+) depends on the server on which you choose to run your application. To clients, the difference between the two (or, for that matter, the fact that the server object uses any of these services) is transparent (unless the client explicitly manipulates transactional services via a special interface).


Understanding transactional objects
 DevGuide: Developing COM-based applications

Understanding transactional objects

Topic groups	See also

Typically, transactional objects are small, and are used for discrete business functions. They can implement an application’s business rules, providing views and transformations of the application state. Consider, for example, the case of a medical application. Medical records stored in various databases represent the persistent state of the application, such as a patient’s health history. Transactional objects update that state to reflect such changes as new patients, test results, and X-ray files.

Transactional objects are distinguished from other COM objects in that they use a set of attributes supplied by MTS or COM+ for handling issues that arise in a distributed computing environment. Some of these attributes require the transactional object to implement the IObjectControl interface. IObjectControl defines methods that are called when the object is activated or deactivated, where you can manage resources such as database connections. It also is required for object pooling.

Note:	If you are using MTS, your transactional objects must implement IObjectControl. Under COM+, IObjectControl is not required, but is highly recommended. The Transactional Object wizard provides an object that derives from IObjectControl.

A client of a transactional object is called a base client. From a base client’s perspective, a transactional object looks like any other COM object.

Under MTS, the transactional object must be built into a library (DLL), which is then installed in the MTS runtime environment (the MTS executive, mtxex.exe). That is, the server object runs in the MTS runtime process space. The MTS executive can be running in the same process as the base client, as a separate process on the same machine as the base client, or as a remote server process on a separate machine.

Under COM+, the server application need not be an in-process server. Because the various services are integrated into the COM libraries, there is no need for a separate MTS process to intercept calls to the server. Instead, COM itself (or, rather, COM+) provides the resource management, transaction support, and so on. However, the server application must still be installed, this time into a COM+ application.

See Requirements for a transactional object for a list of requirements for COM objects if they are to act as transactional objects.

The connection between the base client and the transactional object is handled by a proxy on the client and a stub on the server, just as with any out-of-process server. Connection information is maintained by the proxy. The connection between the base client and proxy remains open as long as the client requires a connection to the server, so it appears to the client that it has continued access to the server. In reality, though, the proxy may deactivate and reactivate the object, conserving resources so that other clients may use the connection. For details on activating and deactivating, see Just-in-time activation.


Understanding transactional objects
 DevGuide: Developing COM-based applications

Understanding transactional objects

Topic groups	See also

In addition to the COM requirements, a transactional object must meet the following requirements:

The object must have a standard class factory. This is automatically supplied by the wizard when you create the object.

The server must expose its class object by exporting the standard DllGetClassObject method. Code to do this is supplied by the wizard.

All object interfaces and CoClasses must be described by a type library, which is created automatically by the wizard. You can add methods and properties to interfaces in the type library by using the Type Library editor. The information in the type library is used by the MTS Explorer or COM+ Component Manager to extract information about the installed components at runtime.

The server must only export interfaces that use standard COM marshaling. This is automatically supplied by the Transactional Object wizard. Delphi’s support of transactional objects does not allow manual marshaling for custom interfaces. All interfaces must be implemented as dual interfaces that use COM’s automatic marshaling support.

The server must export the DllRegisterServer function and perform self-registration of its CLSID, ProgID, interfaces, and type library in this routine. This is provided by the Transactional Object wizard.

When using MTS rather than COM+, the following conditions apply as well:

MTS requires that the server be a dynamic-link library (DLL). Servers that are implemented as executable files (.EXE files) cannot execute in the MTS runtime environment.

The object must implement the IObjectControl interface. Support for this interface is automatically added by the Transactional Object wizard.

A server running in the MTS process space cannot aggregate with COM objects not running in MTS.


Managing resources
 DevGuide: Developing COM-based applications

Managing resources

Topic groups

Transactional objects can be administered to better manage the resources used by your application. These resources include everything from the memory for the object instances themselves to any resources they use (such as database connections).

In general, you configure how your application manages resources by the way you install and configure your object. You set your transactional object so that it takes advantage of the following:

Just-in-time activation

Resource pooling

Object pooling (COM+ only)

If you want your object to take full advantage of these services, however, it must use the IObjectContext interface to indicate when resources can safely be released.


Accessing the object context
 DevGuide: Developing COM-based applications

Accessing the object context

Topic groups	See also

As with any COM object, a transactional object must be created before it is used. COM clients create an object by calling the COM library function, CoCreateInstance.

Each transactional object must have a corresponding context object. This context object is implemented automatically by MTS or COM+ and is used to manage the transactional object. The context object’s interface is IObjectContext. To access most methods of the object context, you can use the ObjectContext property of the TMtsAutoObject object. For example, you can use the ObjectContext property as follows:

if ObjectContext.IsCallerInRole ('Manager') ...

Another way to access the Object context is to use methods in the TMtsAutoObject object:

if IsCallerInRole ('Manager') ...

You can use either of the above methods. However, there is a slight advantage of using the TMtsAutoObject methods rather than referencing the ObjectContext property when you are testing your application. For a discussion of the differences, see Debugging and testing MTS objects.


Just-in-time activation
 DevGuide: Developing COM-based applications

Just-in-time activation

Topic groups	See also

The ability for an object to be deactivated and reactivated while clients hold references to it is called just-in-time activation. From the client's perspective, only a single instance of the object exists from the time the client creates it to the time it is finally released. Actually, it is possible that the object has been deactivated and reactivated many times. By having objects deactivated, clients can hold references to the object for an extended time without affecting system resources. When an object is deactivated, all its resources can be released. For example, when an object is deactivated, it can release its database connection so that other objects can use it.

A transactional object is created in a deactivated state and becomes active upon receiving a client request. When the transactional object is created, a corresponding context object is also created. This context object exists for the entire lifetime of the transactional object, across one or more reactivation cycles. The context object, accessed by the IObjectContext interface, keeps track of the object during deactivation and coordinates transactions.

Transactional objects are deactivated as soon as it is safe to do so. This is called as-soon-as-possible deactivation. A transactional object is deactivated when any of the following occurs:

The object requests deactivation with SetComplete or SetAbort:  An object calls the IObjectContext SetComplete method when it has successfully completed its work and it does not need to save the internal object state for the next call from the client. An object calls SetAbort to indicate that it cannot successfully complete its work and its object state does not need to be saved. That is, the object’s state rolls back to the state prior to the current transaction. Often, objects can be designed to be stateless, which means that objects deactivate upon return from every method.

A transaction is committed or aborted:  When an object's transaction is committed or aborted, the object is deactivated. Of these deactivated objects, the only ones that continue to exist are the ones that have references from clients outside the transaction. Subsequent calls to these objects reactivate them and cause them to execute in a new transaction.

The last client releases the object:  Of course, when a client releases the object, the object is deactivated, and the object context is also released.

Note:	If you install the transactional object under COM+ from the IDE, you can specify whether object supports just-in-time activation using the COM+ page of the Type Library editor. Just select the object (CoClass) in the Type Library editor, go to the COM+ page, and check or uncheck the box for Just In Time Activation. Otherwise, a system administrator specifies this attribute using the COM+ Component Manager or MTS Explorer. (The system administrator can also override any settings you specify using the Type Library editor.)


Resource pooling
 DevGuide: Developing COM-based applications

Resource pooling

Topic groups	See also

Since idle system resources are freed during a deactivation, the freed resources are available to other server objects. For example, a database connection that is no longer used by a server object can be reused by another client. This is called resource pooling. Pooled resources are managed by a resource dispenser.

A resource dispenser caches resources, so that transactional objects that are installed together can share them. The resource dispenser also manages nondurable shared state information. In this way, resource dispensers are similar to resource managers such as the SQL Server, but without the guarantee of durability.

When writing your transactional object, you can take advantage of two types of resource dispenser that are provided for you already:

Database resource dispensers

Shared Property Manager

Before other objects can use pooled resources, you must explicitly release them.


Database resource dispensers
 DevGuide: Developing COM-based applications

Database resource dispensers

Topic groups	See also

Opening and closing connections to a database can be time-consuming. By using a resource dispenser to pool database connections, your object can reuse existing database connections rather than create new ones. For example, if you have a database lookup and a database update component running in a customer maintenance application, you can install those components together, and then they can share database connections. In this way, your application does not need as many connections and new object instances can access the data more quickly by using a connection that is already open but not in use.

If you are using BDE components to connect to your data, the resource dispenser is the Borland Database Engine (BDE). This resource dispenser is only available when your transactional object is installed with MTS. To enable the resource dispenser, use the BDE administrator to turn on MTS POOLING in the System/Init area of the configuration.

If you are using the ADO database components to connect to your data, the resource dispenser is provided by ADO.

Note:	There is no built-in resource pooling if you are using InterbaseExpress components for your database access.

For remote transactional data modules, connections are automatically enlisted on an object's transactions, and the resource dispenser can automatically reclaim and reuse connections.


Shared property manager
 DevGuide: Developing COM-based applications

Shared property manager

Topic groups	See also

The Shared Property Manager is a resource dispenser that you can use to share state among multiple objects within a server process. By using the Shared Property Manager, you avoid having to add a lot of code to your application for managing shared data: the Shared Property Manager handles it for you by implementing locks and semaphores to protect shared properties from simultaneous access. The Shared Property Manager eliminates name collisions by providing shared property groups, which establish unique name spaces for the shared properties they contain.

To use the Shared Property Manager resource, you first use the CreateSharedPropertyGroup helper function to create a shared property group. Then you can write all the properties to that group and read all the properties from that group. By using a shared property group, the state information is saved across all deactivations of a transactional object. In addition, state information can be shared among all transactional objects installed in the same MTS package or COM+ application. You can install transactional objects into a package as described in Installing transactional objects.

For objects to share state, they all must run in the same process. If you want instances of different components to share properties, you must install them in the same MTS package or COM+ application. Because there is a risk that administrators may move components from one package to another, it's safest to limit the use of a shared property group to instances of objects that are defined in the same DLL or EXE.

Objects sharing properties must have the same activation attribute. If two components in the same package have different activation attributes, they generally won't be able to share properties. For example, if one component is configured to run in a client's process and the other is configured to run in a server process, their objects will usually run in different processes, even though they're in the same MTS package or COM+ application.

The following example shows how to add code to support the Shared Property Manager in a transactional object:

Example: Sharing properties among transactional object instances

This example creates a property group called MyGroup to contain the properties to be shared among objects and object instances. In this example, there is a Counter property that is shared. It uses the CreateSharedPropertyGroup helper function to create the property group manager and property group, and then uses the CreateProperty method of the Group object to create a property called Counter.

To get the value of a property, you use the PropertyByName method of the Group object as shown below. You can also use the PropertyByPosition method.

unit Unit1;

interface

uses

  MtsObj, Mtx, ComObj, Project2_TLB;

type

  Tfoobar = class(TMtsAutoObject, Ifoobar)

  private

    Group: ISharedPropertyGroup;

  protected

    procedure OnActivate; override;

    procedure OnDeactivate; override;

    procedure IncCounter;

  end;

implementation

uses ComServ;

{ Tfoobar }

procedure Tfoobar.OnActivate;

var

  Exists: WordBool;

  Counter: ISharedProperty;

begin

  Group := CreateSharedPropertyGroup('MyGroup');

  Counter := Group.CreateProperty('Counter', Exists);

end;

procedure Tfoobar.IncCounter;

var

  Counter: ISharedProperty;

begin

  Counter := Group.PropertyByName['Counter'];

  Counter.Value := Counter.Value + 1;

end;

procedure Tfoobar.OnDeactivate;

begin

  Group := nil;

end;

initialization

  TAutoObjectFactory.Create(ComServer, Tfoobar, Class_foobar, ciMultiInstance, tmApartment);

end.


Releasing resources
 DevGuide: Developing COM-based applications

Releasing resources

Topic groups	See also

You are responsible for releasing resources of an object. Typically, you do this by calling the IObjectContext methods SetComplete and SetAbort after servicing a client request. These methods release the resources allocated by the resource dispenser.

At this same time, you must release references to all other resources, including references to other objects (including transactional objects and context objects) and memory held by any instances of the component (freeing the component).

The only time you would not include these calls is if you want to maintain state between client calls. For details, see  Stateful and stateless objects.


Object pooling
 DevGuide: Developing COM-based applications

Object pooling

Topic groups	See also

Just as you can pool resources, under COM+ you can also pool objects. When an object is deactivated, COM+ calls the IObjectControl interface method, CanBePooled, which indicates that the object can be pooled for reuse. If CanBePooled is returns True, then instead of being destroyed on deactivation, the object is moved to the object pool. It remains in the object pool for a specified timeout period, during which time it is available for use to any client requesting it. Only when the object pool is empty is a new instance of the object created. Objects that return False or that do not support the IObjectControl interface are destroyed when they are deactivated.

Note:	To take advantage of object pooling, you must use the “Both” threading model. For information on threading models, see Choosing a threading model for a transactional object.

Object pooling is not available under MTS. MTS calls CanBePooled as described, but no pooling takes place. If your object will only run under COM+ and you want to allow object pooling, set the object’s Pooledproperty to True.

Even if an object’s CanBePooled method returns True, it can be configured so that COM+ does not move it to the object pool. If you install the transactional object under COM+ from the IDE, you can specify whether COM+ tries to pool the object using the COM+ page of the Type Library editor. Just select the object (CoClass) in the type library editor, go to the COM+ page, and check or uncheck the box for Object Pooling. Otherwise, a system administrator specifies this attribute using the COM+ Component Manager or MTS Explorer.

Similarly, you can configure the time a deactivated object remains in the object pool before it is freed If you are installing from the IDE, you can specify this duration using the Creation Timeout setting on the COM+ page of the type library editor. Otherwise, a system administrator specifies this attribute using the COM+ Component Manager.


MTS and COM+ transaction support
 DevGuide: Developing COM-based applications

MTS and COM+ transaction support

Topic groups	See also

The transaction support that gives transactional objects their name lets you group actions into transactions. For example, in a medical records application, if you had a Transfer component to transfer records from one physician to another, you could include your Add and Delete methods in the same transaction. That way, either the entire Transfer works or it can be rolled back to its previous state. Transactions simplify error recovery for applications that must access multiple databases.

Transactions ensure that

All updates in a single transaction are either committed or get aborted and rolled back to their previous state. This is referred to as atomicity.

A transaction is a correct transformation of the system state, preserving the state invariants. This is referred to as consistency.

Concurrent transactions do not see each other's partial and uncommitted results, which might create inconsistencies in the application state. This is referred to as isolation. Resource managers use transaction-based synchronization protocols to isolate the uncommitted work of active transactions.

Committed updates to managed resources (such as database records) survive failures, including communication failures, process failures, and server system failures. This is referred to as durability. Transactional logging allows you to recover the durable state after disk media failures.

An object's associated context object indicates whether the object is executing within a transaction and, if so, the identity of the transaction. When an object is part of a transaction, the services that resource managers and resource dispensers perform on its behalf execute under the transaction as well. Resource dispensers use the context object to provide transaction-based services. For example, when an object executing within a transaction allocates a database connection by using the ADO or BDE resource dispenser, the connection is automatically enlisted on the transaction. All database updates using this connection become part of the transaction, and are either committed or aborted.

Work from multiple objects can be composed into a single transaction. Allowing an object to either live in its own transaction or be part of a larger group of objects that belong to a single transaction is a major advantage of MTS and COM+. It allows an object to be used in various ways, so that application developers can reuse application code in different applications without rewriting the application logic. In fact, developers can determine how objects are used in transactions when installing the transactional object. They can change the transaction behavior simply by adding an object to a different MTS package or COM+ application. For details about installing transactional objects, see Installing MTS objects.

The following topics provide more details about transactions under MTS and COM+:

Transaction attributes

Stateful and stateless objects

Influencing how transactions end

Initiating transactions

Transaction timeout

Managing transactions in multi-tiered applications


Transaction attributes
 DevGuide: Developing COM-based applications

Transaction attributes

Topic groups	See also

Every transactional object has a transaction attribute that is recorded in the MTS catalog or that is registered with COM+.

Delphi lets you set the transaction attribute at design time using the Transactional Object wizard or the Type Library editor.

Each transaction attribute can be set to these settings:

Requires a transaction	Objects must execute within the scope of a transaction. When a new object is created, its object context inherits the transaction from the context of the client. If the client does not have a transaction context, a new one is automatically created.
Requires a new transaction	Objects must execute within their own transactions. When a new object is created, a new transaction is automatically created for the object, regardless of whether its client has a transaction. An object never runs inside the scope of its client's transaction. Instead, the system always creates independent transactions for the new objects.
Supports transactions	Objects can execute within the scope of their client's transactions. When a new object is created, its object context inherits the transaction from the context of the client. This enables multiple objects to be composed in a single transaction. If the client does not have a transaction, the new context is also created without one.
Transactions Ignored	Objects do not run within the scope of transactions. When a new object is created, its object context is created without a transaction, regardless of whether the client has a transaction. This setting is only available under COM+.
Does not support transactions	The meaning of this setting varies, depending on whether you install the object under MTS or COM+. Under MTS, this setting has the same meaning as Transactions Ignored under COM+. Under COM+, not only is the object context created without a transaction, this setting prevents the object from being activated if the client has a transaction.


Setting the transaction attribute
 DevGuide: Developing COM-based applications

Setting the transaction attribute

Topic groups	See also

You can set a transaction attribute when you first create a transactional object using the Transactional Object wizard.

You can also set (or change) the transaction attribute using the Type Library editor. To change the transaction attribute in the Type Library editor,

1	Choose View|Type Library to open the Type Library editor.

2	Select the class corresponding to the transactional object.

3	Click the COM+ tab and choose the desired transaction attribute.

Warning:	When you set the transaction attribute, Delphi inserts a special GUID for the specified attribute as custom data in the type library. This value is not recognized outside of Delphi. Therefore, it only has an effect if you install the transactional object from the IDE. Otherwise, a system administrator must set this value using the MTS Explorer or COM+ Component Manager.

Note:	If the transactional object is already installed, you must first uninstall the object and reinstall it when changing the transaction attribute. Use Run|Install MTS objects or Run|Install COM+ objects to do so.


Stateful and stateless objects
 DevGuide: Developing COM-based applications

Stateful and stateless objects

Topic groups	See also

Like any COM object, transactional objects can maintain internal state across multiple interactions with a client. For example, the client could set a property value in one call, and expect that property value to remain unchanged when it makes the next call. Such an object is said to be stateful. Transactional objects can also be stateless, which means the object does not hold any intermediate state while waiting for the next call from a client.

When a transaction is committed or aborted, all objects that are involved in the transaction are deactivated, causing them to lose any state they acquired during the course of the transaction. This helps ensure transaction isolation and database consistency; it also frees server resources for use in other transactions. Completing a transaction enables the resources held by an object to be reclaimed when the object is deactivated. See Influencing how transactions end for information on how to control when the object’s state is released.

Maintaining state on an object requires the object to remain activated, holding potentially valuable resources such as database connections.


Influencing how transactions end
 DevGuide: Developing COM-based applications

Influencing how transactions end

Topic groups	See also

A transactional object uses the IObjectContext methods as shown in the following table to influence how a transaction completes. These methods, together with the object’s transaction attribute, allow you to enlist one or more objects into a single transaction.

Method	Description
SetComplete	Indicates that the object has successfully completed its work for the transaction. The object is deactivated upon return from the method that first entered the context. The object reactivates on the next call that requires object execution.
SetAbort	Indicates that the object's work can never be committed and the transaction should be rolled back. The object is deactivated upon return from the method that first entered the context. The object reactivates on the next call that requires object execution.
EnableCommit	Indicates that the object's work is not necessarily done, but that its transactional updates can be committed in their current form. Use this to retain state across multiple calls from a client while still allowing transactions to complete. The object is not deactivated until it calls SetComplete or SetAbort. EnableCommit is the default state when an object is activated. This is why an object should always call SetComplete or SetAbort before returning from a method, unless you want the object to maintain its internal state for the next call from a client.
DisableCommit	Indicates that the object's work is inconsistent and that it cannot complete its work until it receives further method invocations from the client. Call this before returning control to the client to maintain state across multiple client calls while keeping the current transaction active. DisableCommit prevents the object from deactivating and releasing its resources on return from a method call. Once an object has called DisableCommit, if a client attempts to commit the transaction before the object has called EnableCommit or SetComplete, the transaction will abort.


Initiating transactions
 DevGuide: Developing COM-based applications

Initiating transactions

Topic groups	See also

Transactions can be controlled in three ways:

They can be controlled by the client.

Clients can have direct control over transactions by using a transaction context object (using the ITransactionContext interface).

They can be controlled by the server.

Servers can control transactions explicitly creating an object context for them. When the server creates an object this way, the created object is automatically enlisted in the current transaction.

Transactions can occur automatically as a result of the object’s transaction attribute.

Transactional objects can be declared so that their objects always execute within a transaction, regardless of how the objects are created. This way, objects do not need to include any logic to handle transactions. This feature also reduces the burden on client applications. Clients do not need to initiate a transaction simply because the component that they are using requires it.


Setting up a transaction object on the client side
 DevGuide: Developing COM-based applications

Setting up a transaction object on the client side

Topic groups

A client-based application can control transaction context through the ITransactionContextEx interface. The following code example shows how a client application uses CreateTransactionContextEx to create the transaction context. This method returns an interface to this object.

This example wraps the call to the transaction context in a call to OleCheck which is necessary because the methods of IObjectContext are exposed by Windows directly and are therefore not declared as safecall.

procedure TForm1.MoveMoneyClick(Sender: TObject);

begin

  Transfer(CLASS_AccountA, CLASS_AccountB, 100);

end;

procedure TForm1.Transfer(DebitAccountId, CreditAccountId: TGuid; Amount: Currency);

var

  TransactionContextEx: ITransactionContextEx;

  CreditAccountIntf, DebitAccountIntf: IAccount;

begin

  TransactionContextEx := CreateTransactionContextEx;

  try

    OleCheck(TransactionContextEx.CreateInstance(DebitAccountId,

      IAccount, DebitAccountIntf));

    OleCheck(TransactionContextEx.CreateInstance(CreditAccountId,

      IAccount, CreditAccountIntf));

    DebitAccountIntf.Debit(Amount);

    CreditAccountIntf.Credit(Amount);

  except

    TransactionContextEx.Abort;

    raise;

  end;

  TransactionContextEx.Commit;

end;


Setting up a transaction object on the server side
 DevGuide: Developing COM-based applications

Setting up a transaction object on the server side

Topic groups

To control transaction context from the server side, you create an instance of ObjectContext. In the following example, the Transfer method is in the transactional object. In using ObjectContext this way, the instance of the object we are creating will inherit all the transaction attributes of the object that creates it. We wrap the call in a call to OleCheck because the methods of IObjectContext are exposed by Windows directly and are therefore not declared as safecall.

procedure TAccountTransfer.Transfer(DebitAccountId, CreditAccountId: TGuid;

 Amount: Currency);

var

  CreditAccountIntf, DebitAccountIntf: IAccount;

begin

  try

    OleCheck(ObjectContext.CreateInstance(DebitAccountId,

      IAccount, DebitAccountIntf));

    OleCheck(ObjectContext.CreateInstance(CreditAccountId,

      IAccount, CreditAccountIntf));

    DebitAccountIntf.Debit(Amount);

    CreditAccountIntf.Credit(Amount);

  except

    DisableCommit;

    raise;

  end;

  EnableCommit;

end;


Transaction timeout
 DevGuide: Developing COM-based applications

Transaction timeout

Topic groups	See also

The transaction timeout sets how long (in seconds) a transaction can remain active. The system automatically aborts transactions that are still alive after the timeout. By default, the timeout value is 60 seconds. You can disable transaction timeouts by specifying a value of 0, which is useful when debugging transactional objects.

To set the timeout value on your computer,

1	In the MTS Explorer or COM+ Component Manager, select Computer, My Computer.

By default, My Computer corresponds to the local computer.

2	Right-click and choose Properties and then choose the Options tab.

The Options tab is used to set the computer's transaction timeout property.

3	Change the timeout value to 0 to disable transaction timeouts.

4	Click OK to save the setting.


Role-based security
 DevGuide: Developing COM-based applications

Role-based security

Topic groups

MTS and COM+ provide role-based security where you assign a role to a logical group of users. For example, a medical information application might define roles for Physician, X-ray technician, and Patient.

You define authorization for each object and interface by assigning roles. For example, in the physicians’ medical application, only the Physician may be authorized to view all medical records; the X-ray Technician may view only X-rays; and Patients may view only their own medical record.

Typically, you define roles during application development and assign roles for each MTS package or COM+ Application. These roles are then assigned to specific users when the application is deployed. Administrators can configure the roles using the MTS Explorer or COM+ Component Manager.

If you want to control access to blocks of code rather than entire objects, you can provide more fine-grained security by using the IObjectContext method, IsCallerInRole. This method only works if security is enabled, which can be checked by calling the IObjectContext method IsSecurityEnabled. These methods are automatically added as methods to your transactional object. For example,

if IsSecurityEnabled then{check if security is enabled }

begin

  if IsCallerInRole('Physician') then { check caller's role }

  begin

    { execute the call normally }

  end

  else

    { not a physician, do something appropriate }

  end

end

else

  { no security enabled, do something appropriate }

end;

Note:	For applications that require stronger security, context objects implement the ISecurityProperty interface, whose methods allow retrieval of the Window’s security identifier (SID) for the direct caller and creator of the object, as well as the SID for the clients which are using the object.


Overview of creating transactional objects
 DevGuide: Developing COM-based applications

Overview of creating transactional objects

Topic groups	See also

The process of creating transactional object is as follows:

1	Use the Transactional Object wizard to create the transactional object.

2	Add methods and properties to the object’s interface using the Type Library editor. When implementing your object’s methods, you can use the IObjectContext interface to manage transactions, persistent state, and security. In addition, if you are passing object references, you will need to use extra care so that they are correctly handled.

3	Debug and test the transactional object.

4	Install the transactional object into an MTS package or COM+ application.

5	Administer your objects using the MTS Explorer or COM+ Component Manager.


Using the Transactional Object wizard
 DevGuide: Developing COM-based applications

Using the Transactional Object wizard

Topic groups	See also

Use the Transactional Object wizard to create a COM object that can take advantage of the resource management, transaction processing, and role-based security provided by MTS or COM+.

To bring up the Transactional Object wizard,

1	Choose File|New|Other.

2	Select the tab labeled Multitier.

3	Double-click the Transactional Object icon.

In the wizard, you must specify the following:

A threading model that indicates how client applications can call your object’s interface. The threading model determines how the object is registered. You are responsible for ensuring that the object’s implementation adheres to the selected model. .

A transaction model

An indication of whether your object notifies clients of events. Event support is only provided for traditional events, not COM+ events.

When you complete this procedure, a new unit is added to the current project that contains the definition for the transactional object. In addition, the wizard adds a type library to the project and opens it in the Type Library editor. Now you can expose the properties and methods of the interface through the type library. You define the interface as you would define any COM object as described in Defining a COM object’s interface.

The transactional object implements a dual interface, which supports both early (compile-time) binding through the vtable and late (runtime) binding through the IDispatch interface.

The generated transactional object implements the IObjectControl interface methods, Activate, Deactivate, and CanBePooled.

It is not strictly necessary to use the transactional object wizard. You can convert any Automation object into a COM+ transactional object (and any in-process Automation object into an MTS transactional object) by using the COM+ page of the Type Library editor and then installing the object into an MTS package or COM+ application. However, the transactional object wizard provides certain benefits:

It automatically implements the IObjectControl interface, adding OnActivate and OnDeactivate events to the object so that you can create event handlers that respond when the object is activated or deactivated.

It automatically generates an ObjectContext property so that it is easy for your object to access the IObjectContext methods to control activation and transactions.


Choosing a threading model for a transactional object
 DevGuide: Developing COM-based applications

Choosing a threading model for a transactional object

Topic groups

The MTS runtime environment or COM+ manages threads for you. Transactional objects should not create threads. They must also never terminate a thread that calls into a DLL.

When you specify the threading model using the Transactional object wizard, you specify how objects are assigned to threads for method execution.

Threading model	Description	Implementation pros and cons
Single	No thread support. Client requests are serialized by the calling mechanism. All objects of a single-threaded component execute on the main thread. This is compatible with the default COM threading model, which is used for components that do not have a Threading Model Registry attribute or for COM components that are not reentrant. Method execution is serialized across all objects in the component and across all components in a process.	Allows components to use libraries that are not reentrant. Very limited scalability. Single-threaded, stateful components are prone to deadlocks. You can eliminate this problem by using stateless objects and calling SetComplete before returning from any method.
Apartment  (or Single-threaded apartment)	Each object is assigned to a thread apartment, which lasts for the life of the object; however, multiple threads can be used for multiple objects. This is a standard COM concurrency model. Each apartment is tied to a specific thread and has a Windows message pump.	Provides significant concurrency improvements over the single threading model.  Two objects can execute concurrently as long as they are not in the same activity.  Similar to a COM apartment, except that the objects can be distributed across multiple processes.
Both	Same as Apartment, except that callbacks to clients are serialized.	Same advantages as Apartment. In addition, this model is required if you want to use Object Pooling.
Note:	These threading models are similar to those defined by COM objects. However, because the MTS and COM+ provide more underlying support for threads, the meaning of each threading model differs here. Also, the free threading model does not apply to transactional objects due to the built-in support for activities.


Activities
 DevGuide: Developing COM-based applications

Activities

Topic groups

In addition to the threading model, transactional objects achieve concurrency through activities. Activities are recorded in an object’s context, and the association between an object and an activity cannot be changed. An activity includes the transactional object created by the base client, as well as any transactional objects created by that object and its descendants. These objects can be distributed across one or more processes, executing on one or more computers.

For example, a physician’s medical application may have a transactional object to add updates and remove records to various medical databases, each represented by a different object. This record object may use other objects as well, such as a receipt object to record the transaction. This results in several transactional objects that are either directly or indirectly under the control of a base client. These objects all belong to the same activity.

MTS or COM+ tracks the flow of execution through each activity, preventing inadvertent parallelism from corrupting the application state. This feature results in a single logical thread of execution throughout a potentially distributed collection of objects. By having one logical thread, applications are significantly easier to write.

When a transactional object is created from an existing context, using either a transaction context object or an object context, the new object becomes a member of the same activity. In other words, the new context inherits the activity identifier of the context used to create it.

Only a single logical thread of execution is allowed within an activity. This is similar in behavior to a COM apartment threading model, except that the objects can be distributed across multiple processes. When a base client calls into an activity, all other requests for work in the activity (such as from another client thread) are blocked until after the initial thread of execution returns back to the client.

Under MTS, every transactional object belongs to one activity. Under COM+, you can configure the way the object participates in activities by setting the call synchronization. The following options are available:

Option	Meaning
Disabled	COM+ does not assign activities to the object but it may inherit them with the caller’s context. If the caller has no transaction or object context, the object is not assigned to an activity. The result is the same as if the object was not installed in a COM+ application. This option should not be used if any object in the application uses a resource manager or if the object supports transactions or just-in-time activation.
Not Supported	COM+ never assigns the object to an activity, regardless of the status of its caller. This option should not be used if any object in the application uses a resource manager or if the object supports transactions or just-in-time activation.
Supported	COM+ assigns the object to the same activity as its caller. If the caller does not belong to an activity, the object does not either. This option should not be used if any object in the application uses a resource manager or if the object supports transactions or just-in-time activation.
Required	COM+ always assigns the object to an activity, creating one if necessary. This option must be used if the transaction attribute is Supported or Required.
Requires New	COM+ always assigns the object to a new activity, which is distinct from its caller’s.


Generating events under COM+
 DevGuide: Developing COM-based applications

Generating events under COM+

Topic groups	See also

Before COM+, Automation servers used a set of special interfaces for generating events. COM+, however, introduces a new system for managing events. Instead of the server object managing events, keeping track of clients that need to be notified and calling their interfaces when events occur, the underlying system (COM+) manages this process.

Note:	Transactional objects installed under COM+ can still use the old system for managing events. However, letting COM+ handle the process provides greater flexibility. For example, when COM+ manages events, the client can be an in-process server that is launched by COM+ when the event occurs.

When a COM+ object generates events, it does not do so directly. Rather, it makes use of an associated event object that is specifically created to generate events. The COM+ object calls its event object when it wants to fire an event. When that happens, COM+ calls all clients that have registered an interest in the particular event object.

Using the Event Object wizard

You can create event objects using the Event Object wizard. The wizard first checks whether the current project contains any implementation code, because projects containing COM+ event objects do not include an implementation. They can only contain event object definitions. (You can, however, include multiple COM+ event objects in a single project.)

To bring up the Event Object wizard,

1	Choose File|New.

2	Select the tab labeled ActiveX.

3	Double-click the COM+ Event Object icon.

In the Event Object wizard, specify the name of the event object, the name of the interface that defines the event handlers, and (optionally) a brief description of the events.

When you exit, the wizard creates a project containing a type library that defines your event object and its interface. Use the Type Library editor to define the methods of that interface. These methods are the event handlers that clients implement to respond to events.

The Event object project includes the project file, _ATL unit to import the ATL template classes, and the _TLB unit to define the type library information. It does not include an implementation unit, however, because COM+ event objects have no implementation. The implementation of the interface is the responsibility of the client. When your server object calls a COM+ event object, COM+ intercepts the call and dispatches it to registered clients. Because COM+ event objects require no implementation object, all you need to do after defining the object’s interface in the Type Library editor is compile the project and install it with COM+

COM+ places certain restrictions on the interfaces of event objects. The interface you define in the Type Library editor for your event object must obey the following rules:

The event object’s interface must derive from IDispatch.

All method names must be unique across all interfaces of the event object.

All methods on the event object’s interface must return an HRESULT value.

The modifier for all parameters of methods must be blank.

Firing events using a COM+ event object

When an event occurs, your COM+ object must call the event object and tell it to fire the event on registered clients. It does this by creating an instance of the event object and calling the method that corresponds to the event:

Note:	Objects that fire COM+ events, like the event objects themselves, must be installed in a COM+ application.


Passing object references
 DevGuide: Developing COM-based applications

Passing object references

Topic groups

Under MTS, you can pass object references, (for example, for use as a callback) only in the following ways:

Through return from an object creation interface, such as CoCreateInstance (or its equivalent), ITransactionContext.CreateInstance, or IObjectContext.CreateInstance.

Through a call to QueryInterface.

Through a method that has called SafeRef to obtain the object reference.

An object reference that is obtained in the above ways is called a safe reference. Methods invoked using safe references are guaranteed execute within the correct context.

The MTS runtime environment requires calls to use safe references so that it can manage context switches and allows transactional objects to have lifetimes that are independent of client references. Safe references are not necessary under COM+.

Using the SafeRef method

An object can use the SafeRef function to obtain a reference to itself that is safe to pass outside its context. The unit that defines the SafeRef function is Mtx.

SafeRef takes as input

A reference to the interface ID (RIID) of the interface that the current object wants to pass to another object or client.

A reference to the current object’s IUnknown interface.

SafeRef returns a pointer to the interface specified in the RIID parameter that is safe to pass outside the current object's context. It returns nil if the object is requesting a safe reference on an object other than itself, or the interface requested in the RIID parameter is not implemented.

When an MTS object wants to pass a self-reference to a client or another object (for example, for use as a callback), it should always call SafeRef first and then pass the reference returned by this call. An object should never pass a self pointer, or a self-reference obtained through an internal call to QueryInterface, to a client or to any other object. Once such a reference is passed outside the object's context, it is no longer a valid reference.

Calling SafeRef on a reference that is already safe returns the safe reference unchanged, except that the reference count on the interface is incremented.

When a client calls QueryInterface on a reference that is safe, the reference returned to the client is also a safe reference.

An object that obtains a safe reference must release the safe reference when finished with it.

For details on SafeRef see the SafeRef topic in the Microsoft documentation.

Callbacks

Objects can make callbacks to clients and to other transactional objects. For example, you can have an object that creates another object. The creating object can pass a reference of itself to the created object; the created object can then use this reference to call the creating object.

If you choose to use callbacks, note the following restrictions:

Calling back to the base client or another package requires access-level security on the client. Additionally, the client must be a DCOM server.

Intervening firewalls may block calls back to the client.

Work done on the callback executes in the environment of the object being called. It may be part of the same transaction, a different transaction, or no transaction.

Under MTS, the creating object must call SafeRef and pass the returned reference to the created object in order to call back to itself.


Debugging and testing transactional objects
 DevGuide: Developing COM-based applications

Debugging and testing transactional objects

Topic groups	See also

You can debug local and remote transactional objects. When debugging transactional objects, you may want to turn off transaction timeouts.

The transaction timeout sets how long (in seconds) a transaction can remain active. Transactions that are still alive after the timeout are automatically aborted by the system. By default, the timeout value is 60 seconds. You can disable transaction timeouts by specifying a value of 0, which is useful when debugging.

When testing a transactional object that you intend to run under MTS, you may first want to test your object outside the MTS environment to simplify your test environment.

While developing your server, you cannot rebuild the server when it is still in memory. You may get a compiler error like, “Cannot write to DLL while executable is loaded.” To avoid this, you can set the MTS package or COM+ application properties to shut down the server when it is idle.

To shut down the server when idle,

1	In the MTS Explorer or COM+ Component Manager, right-click the MTS package or COM+ application in which your transactional object is installed and choose Properties.

2	Select the Advanced tab.

The Advanced tab determines whether the server process associated with a package always runs, or whether it shuts down after a certain period of time.

3	Change the timeout value to 0, which shuts down the server as soon as no longer has a client to service.

4	Click OK to save the setting.

Note:	When testing outside the MTS environment, you do not reference the ObjectProperty of TMtsObject directly. The TMtsObject implements methods such as SetComplete and SetAbort that are safe to call when the object context is nil.


Installing transactional objects
 DevGuide: Developing COM-based applications

Installing transactional objects

Topic groups	See also

MTS applications consist of a group of in-process MTS objects running in a single instance of the MTS executive (EXE). A group of COM objects that all run in the same process is called a package. A single machine can be running several different packages, where each package is running within a separate MTS EXE.

Under COM+, you work with a similar group, called a COM+ application. In a COM+ application, the objects need not be in-process, and there is no separate runtime environment.

You can group your application components into a single MTS package or COM+ application to be managed by a single process. You might want to distribute your components into different MTS packages or COM+ applications to partition your application across multiple processes or machines.

To install transactional objects into an MTS package or COM+ application,

1	If your system supports COM+, choose Run|Install COM+ objects. If your system does not support COM+ but you have MTS installed on your system, choose Run|Install MTS objects. If your system supports neither MTS nor COM+, you will not see a menu item for installing transactional objects.

2	In the Install Object dialog box, check the objects to be installed.

3	If you are installing MTS objects, click the Package button to get a list of MTS packages on your system. If you are installing COM+ objects, click the Application button. Indicate the MTS package or COM+ application into which you are installing your objects. You can choose Into New Package or Into New Application to create a new MTS package or COM+ application in which to install the object. You can choose Into Existing Package or Into Existing Application to install the object into an existing listed MTS package or COM+ application.

4	Choose OK to refresh the catalog, which makes the objects available at runtime.

MTS packages can contain components from multiple DLLs, and components from a single DLL can be installed into different packages. However, a single component cannot be distributed among multiple packages.

Similarly, COM+ applications can contain components from multiple executables and different components from a single executable can be installed into different COM+ applications.

Note:	You can also install your transactional object using the COM+ Component Manager or MTS Explorer. Be sure when installing the object with one of these tools that you apply the settings for the object that appear on the COM+ page of the Type Library editor. These settings are not applied automatically when you do not install from the IDE.


Administering transactional objects
 DevGuide: Developing COM-based applications

Administering transactional objects

Topic groups	See also

Once you have installed transactional objects, you can administer these runtime objects using the MTS Explorer (if they are installed into an MTS package) or the COM+ Component Manager (if they are installed into a COM+ application). Both tools are identical, except that the MTS Explorer operates on the MTS runtime environment and the COM+ Component Manager operates on COM+ objects.

The COM+ Component Manager and MTS Explorer have a graphical user interface for managing and deploying transactional objects. Using one of these tools, you can

Configure transactional objects, MTS packages or COM+ applications, and roles

View properties of components in an package or COM+ application and view the MTS packages or COM+ applications installed on a computer

Monitor and manage transactions for objects that comprise transactions

Move MTS packages or COM+ applications between computers

Make a remote transactional object available to a local client

For more details on these tools, see the appropriate Administrator’s Guide from Microsoft.


Related topic groups
Developing COM-based applications

•	Creating an Active Server Page

•	Creating properties

•	Creating methods

•	Object-oriented programming for component writers

•	Creating MTS automation objects

•	Overview of component creation

•	Working with type libraries


Creating an Active Server Page

Related topic groups

•	Creating Active Server Pages: Overview

•	Creating an Active Server Object

•	Using the ASP intrinsics

•	Creating ASPs for in-process or out-of-process servers

•	Registering an Active Server Object

•	Testing and debugging the Active Server Page application


Creating properties

Related topic groups

•	Creating COM clients: Overview

•	Importing type library information

•	Using the Import Type Library dialog

•	Using the Import ActiveX dialog

•	Code generated when you import type library information

•	Controlling an imported object

•	Using component wrappers

•	Using data-aware ActiveX controls

•	Example: Printing a document with Microsoft Word

•	Writing client code based on type library definitions

•	Connecting to a server

•	Controlling an Automation server using a Dual interface

•	Controlling an Automation server using a dispatch interface

•	Handling events in an Automation Controller

•	Creating clients for servers that do not have a type library


Creating methods

Related topic groups

•	Creating an ActiveX control: Overview

•	Elements of an ActiveX control

•	Designing an ActiveX control

•	Generating an ActiveX control from a VCL control

•	Generating an ActiveX control based on a VCL form

•	Licensing ActiveX controls

•	Customizing the ActiveX control's interface

•	Adding additional properties, methods, and events

•	How Delphi adds properties

•	How Delphi adds events

•	Enabling simple data binding with the type library

•	Creating a property page for an ActiveX control

•	Creating a new property page

•	Adding controls to a property page

•	Associating property page controls with ActiveX control properties

•	Updating the property page

•	Updating the object

•	Connecting a property page to an ActiveX control

•	Registering an ActiveX control

•	Testing an ActiveX control

•	Deploying an ActiveX control on the Web

•	Setting Web deployment options


Object-oriented programming for component writers

Related topic groups

•	Creating simple COM servers: overview

•	Designing a COM object

•	Using the COM object wizard

•	Using the Automation object wizard

•	COM object instancing types

•	Choosing a threading model

•	Defining a COM object's interface

•	Managing events in your Automation object

•	Automation interfaces

•	Dual interfaces

•	Dispatch interfaces

•	Custom interfaces

•	Marshaling data

•	Registering a COM object

•	Testing and debugging the application


Creating MTS automation objects

Related topic groups

•	Creating MTS or COM+ objects: Overview

•	Understanding transactional objects

•	Understanding transactional objects

•	Managing resources

•	Accessing the object context

•	Just-in-time activation

•	Resource pooling

•	Database resource dispensers

•	Shared property manager

•	Releasing resources

•	Object pooling

•	MTS and COM+ transaction support

•	Transaction attributes

•	Setting the transaction attribute

•	Stateful and stateless objects

•	Influencing how transactions end

•	Initiating transactions

•	Setting up a transaction object on the client side

•	Setting up a transaction object on the server side

•	Transaction timeout

•	Role-based security

•	Overview of creating transactional objects

•	Using the Transactional Object wizard

•	Choosing a threading model for a transactional object

•	Activities

•	Generating events under COM+

•	Passing object references

•	Debugging and testing transactional objects

•	Installing transactional objects

•	Administering transactional objects


Overview of component creation

Related topic groups

•	Overview of COM Technologies

•	Parts of a COM application

•	COM interfaces

•	The fundamental COM interface, IUnknown

•	COM interface pointers

•	COM servers

•	CoClasses and class factories

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

•	The marshaling mechanism

•	Aggregation

•	COM clients

•	COM extensions

•	Automation

•	Active Server Pages

•	ActiveX controls

•	Active Documents

•	Transactional objects

•	Type libraries

•	Implementing COM objects with Wizards

•	Code generated by wizards


Working with type libraries

Related topic groups

•	Working with type libraries: Overview

•	Type Library editor

•	Parts of the Type Library editor

•	Toolbar

•	Object list pane

•	Status bar

•	Pages of type information

•	Pages of type information

•	Using the Type Library editor

•	Valid types

•	SafeArrays

•	Using Object Pascal or IDL syntax

•	Creating a new type library

•	Opening an existing type library

•	Adding an interface to the type library

•	Modifying an interface using the type library

•	Adding properties and methods to the type library

•	Adding a CoClass to the type library

•	Adding an interface to a CoClass

•	Adding an enumeration to the type library

•	Adding an alias to the type library

•	Adding a record or union to the type library

•	Adding a module to the type library

•	Saving and registering type library information

•	Apply Updates dialog

•	Saving a type library

•	Refreshing the type library

•	Registering the type library

•	Exporting an IDL file

•	Deploying type libraries


Link not found

The topic you requested is either not available or not linked to this Help system. This can occur if you launched this Help file from a system on which Delphi has not yet been installed, or if the subject matter you are requesting is not available in your edition of Delphi.


The topic you requested is now loading. If it does not appear within a few seconds, the topic is either not available or not linked to this Help system. This can occur if you launched this Help file from a system on which Delphi has not yet been installed, or if the subject matter you are requesting is not available in your edition of Delphi.