Teach Yourself Borland Delphi 4 in 21 Days

Previous chapterNext chapterContents


- 15 -

COM and ActiveX


OLE, ActiveX, COM, DCOM, VCL, CORBA, MTS. . . the industry certainly doesn't lack for acronyms when it comes to the subject of component architecture! In this chapter, I explain some of these acronyms and at least mention the others in passing. I'll explain what these terms mean and try to shed some light on the often-confusing world of COM and ActiveX. Specifically, I cover

I'd be lying if I said that COM, ActiveX, and OLE are easy to understand. They are not. It can be very confusing at first. I can't do justice to this subject in one chapter. My goal for this chapter is to give you enough of a background on these architectures so that you can better understand the acronyms you see bandied about these days. You will also get some good hands-on training in creating COM and ActiveX controls. Fortunately, Delphi takes a great deal of the pain out of dealing with these APIs.

Understanding COM

You can't talk about OLE and ActiveX without talking about COM, which stands for Component Object Model.

New Term: COM (Component Object Model) is a Microsoft specification for creating and implementing reusable components.

"Components? I thought Delphi used VCL components." Certainly VCL components are the most effective use of components in Delphi. They aren't the only possibility, though. As you work through this hour, you will get a clearer picture of how COM and ActiveX work with Delphi.

COM is the basis for both OLE and ActiveX. An analogy might be the TObject class in VCL. All classes in VCL are ultimately inherited from TObject. Derived classes automatically get the properties and methods of TObject. They then add their own properties and methods to provide additional functionality. Similarly, OLE and ActiveX are built on top of COM. COM is the foundation for all OLE and ActiveX objects.

As a component architecture, COM has two primary benefits:


NOTE: One major drawback to COM is that it is heavily tied to the WinTel (Windows/Intel) platform. So although you can use a COM object in many different Windows programming environments, you can't necessarily use that COM object in a UNIX programming environment. Recently Microsoft has tried to move COM to non-Windows platforms, but it remains to be seen whether this attempt will ultimately succeed. This chapter deals only with COM and ActiveX as they exist in the Win32 programming environment.

You can use a number of different languages and environments to write COM objects. You can create COM objects with Delphi, C++Builder, Visual C++, Visual Basic, and probably a few ot her development environments. When created, a COM object can be used in an even wider variety of development environments. A COM object created in Delphi can be used by a VB programmer, a C++Builder programmer, or even a Visual dBASE or PowerBuilder programmer.

A COM object is typically contained in a DLL. The DLL might have an extension of .DLL or it might have an extension of .OCX. A single library file (DLL or OCX) can contain an individual COM object or can contain several COM objects.

COM Terminology

COM is full of confusing terminology. The following sections explain some of the terms used in COM and how the many pieces of COM fit together. All of these pieces are interrelated, so you'll have to read the entire section to get the big picture.

COM Objects

New Term: A COM object is a piece of binary code that performs a particular function.

A COM object exposes certain methods to enable applications to access the functionality of the COM object. These methods are made available via COM interfaces. A COM object might contain just one interface, or it might contain several interfaces. To a programmer, COM objects work a lot like Object Pascal classes.

COM Interfaces

Access to a COM object is through the COM object's interface.

New Term: A COM interface is the means by which the user of a COM object accesses that object's functionality.

A COM interface is used to access a COM object; to use the object, if you will. The interface in effect advertises what the COM object has to offer. A COM object might have just one interface, or it might have several. In addition, one COM interface might implement one or more additional COM interfaces.

COM interfaces typically start with the letter I. The Windows shell, for example, implements interfaces called IShellLink, IShellFolder, and IShellExtInit. Although you can use any naming convention you like, t he leading I universally and immediately identifies the class as a COM interface to other programmers.

COM interfaces are managed internally by Windows according to their interface identifiers (IIDs). An IID is a numerical value contained in a data structure (a record). The IID uniquely identifies an interface.

COM Classes

New Term: A COM class (also known as a coclass) is a class that contains one or more COM interfaces.

You can't use a COM interface directly. Instead, you access the interface through a coclass. A coclass includes a class factory that creates the requested interface and returns a pointer to the interface. COM classes are identified by class identifiers (CLSIDs). A CLSID, like an IID, is a numerical value that uniquely identifies a COM class.

GUIDs

COM objects must be registered with Windows. This is where CLSIDs and IIDs come into play. CLSIDs and IIDs are really just different names for the same base data structure: the Globally Unique Identifier (GUID).

New Term: A GUID is a unique 128-bit (16-byte) value.

GUIDs are created by a special COM library function called CoCreateGUID. This function generates a GUID that is virtually guaranteed to be unique. CoCreateGUID uses a combination of your machine information, random number generation, and a time stamp to create GUIDs. Although it is possible that CoCreateGUID might generate two GUIDs that are identical, it is highly unlikely (more like a statistical impossibility).

Thankfully, Delphi programmers don't have to worry about creating GUIDs. Delphi automatically generates a GUID when you create a new automation object, COM object, ActiveX control, or ActiveForm control. GUIDs in Delphi are defined by the TGUID record. TGUID is declared in System.pas as follows:

TGUID = record
  D1: Integer;
  D2: Word;
  D3: Word;
  D4: array[0..7] of Byte;
end;
When you create a new COM object, Delphi automatic


ally creates the GUID for you. For example, here's the GUID for a test COM object I created:
Class_Test: TGUID = `{F34107A1-ECCF-11D1-B47A-0040052A81F8}';

Because GUIDs are handled for you by Delphi, you won't typically have to worry very much about GUIDs. You will, however, see GUIDs a lot as you create and use COM objects (including ActiveX controls).


TIP: If you need to generate a GUID manually, you can type Ctrl+Shift+G in the Code Editor. Delphi will generate a GUID for you and insert it at the cursor point.

Type Libraries

COM objects often use a type library.

New Term: A type library is a special file that contains information about a COM object. This information includes a list of the properties, methods, interfaces, structures, and other elements that the control contains. The type library also provides information about the data types of each property and the return type and parameters of the object's methods.

This information includes the data types in the object, the methods and properties of the object, the version information, interfaces in the object, and so on. Type libraries can be contained in the COM object as resources or as a standalone file. Type library files have a .TLB extension. A type library is necessary if other developers are going to use your COM objects as development tools. A COM object's type library contains more information about the object than is available by simply querying the object for its interfaces. The Delphi IDE, for example, uses the information found in type libraries to display an ActiveX control on the Component palette. Users of a COM object can examine the type library to see exactly what methods and interfaces the object contains.

DCOM

Distributed COM (DCOM) is a subset of COM that provides the capability to use COM objects across networks or across the Internet. DCOM extends COM to provide the mechani sm for using COM in a networking environment. A detailed discussion of DCOM is beyond the scope of this book, but note that DCOM is definitely prevalent in certain types of network programming.


NOTE: CORBA (Common Object Request Broker Architecture) is a competing technology to DCOM. CORBA is platform-independent, which makes it more desirable than DCOM in many ways. In addition, CORBA is an open architecture supported by a consortium of software companies (unlike DCOM, which is a Microsoft-specific solution). Fortunately, Delphi gives you the option of creating both DCOM and CORBA objects.

Reference Counting

Every COM object has a reference count. The reference count, naturally, contains the number of processes that are currently using the COM object. A process is any application or DLL that uses a COM object. Because a COM object can be used by any number of processes at one time, reference counting is used to determine when the COM object is no longer needed in memory.

When a COM object is created, its reference count is initialized to 1. The reference count is incremented by one each time a process attaches to the COM object. When a process detaches from the COM object, the reference count is decremented by one. When the reference count gets to 0, the COM object is freed from memory.

The IUnknown Interface

All COM interfaces descend from a base interface called IUnknown. Table 15.1 lists the methods of IUnknown.

TABLE 15.1. IUnknown METHODS.

Method Description
QueryInterface Queries the interface to obtain a list of supported interfaces.
AddRef Increments the interface's reference count.
Release Decrements the interface's reference count. When the reference count reaches 0, the object is freed from memory.

I mention IUnknown primarily for historical reasons. Delphi programmers don't really have to worry much about IUnknown as other programmers do. Delphi takes care of handling reference counting and freeing the memory for the COM object. Delphi also elevates dealing with COM objects to a level that makes an intimate knowledge of IUnknown all but obsolete.

Creating a COM Object

To help bring this into perspective, let's create a COM object. This COM object will be ridiculously simple but should illustrate how to use and build COM objects in Delphi. The COM object you create will have these characteristics:

Type Name Description
property X The first number to multiply.
property Y The second number to multiply.
method DoIt A method that multiplies the two numbers and returns the result.

The following sections explain the process of creating the COM object.

Creating an ActiveX Library

The first step in creating a COM object is to create a DLL project that will contain the COM object's code. Delphi uses the term "ActiveX Library" to refer to all COM library projects. This description isn't entirely accurate, but it's close enough. Perform these steps to create an Acti veX Library:

1. Close all projects. Choose File|New from the main menu to display the Object Repository.

2. Click on the ActiveX tab to show the ActiveX page (see Figure 15.1). Double-click the ActiveX Library icon.

Figure 15.1. The Object Repository's ActiveX page.

3. Choose File|Save and save the project as ComTest.

That's all there is to this particular step. Delphi creates a DLL project for you and is waiting for your next move.

Creating the Actual Object

The next step is to create the COM object itself. This step is also relatively simple. Perform these steps to do so:

1. Choose File|New from the Delphi main menu. The Object Repository is displayed. Click on the ActiveX page.

2. Double-click on the COM Object icon. Delphi displays the COM Object Wizard, as shown in Figure 15.2.

FIGURE 15.2. The COM Object Wizard.



THE COM OBJECT WIZARD


Let me take a moment to talk about the COM Object Wizard. The Class Name field is used to specify the class name for your COM object. Type the class name here, but don't prepend the class name with either a T as you would for a Delphi class, nor an I as is customary for interfaces. Delphi will take care of creating the class and interface names automatically.

The Instancing field is used to control how multiple instances of the COM object are handled. Choices include Internal, Single Instance, or Multiple Instance. See the "COM object wizard" topic in the Delphi help for descriptions of these instancing options (you can click the Help button on the COM Object Wizard to display the correct help topic).

The Threadi ng Model field is used to specify how client applications can call your COM object. Choices include Single, Apartment, Free, or Both. Again, see the Delphi help for descriptions of the threading models.

The Implemented Interfaces field is where you add the names of any interfaces that your COM object will implement. If you have an interface called IMyFileIO and you want to use that interface in your new COM object, you would type IMyFileIO in this field.

The Description field is used to supply a description for the COM object. The description is optional, but it's a good idea to provide one.
When the Include Type Library check box is checked, Delphi will create a type library for the COM object. Creating a type library enables your COM object to be used by client applications.


Okay, let's get back to work:

3. Enter Multiply in the Class Name field.

4. Enter Test COM Object in the Description field.

5. Check the Include Type Library check box. The other fields on the dialog box can be left at their default values.

6. Click OK to close the dialog box.

When you click the OK button, Delphi creates a unit for the COM object's class and displays the Type Library Editor, as shown in Figure 15.3. Before continuing, I need to take a moment to talk about the Type Library Editor.

Using the Type Library Editor

The Type Library Editor is used to manipulate a type library. The Type Library Editor enables you to add or remove interfaces, add properties and methods to interfaces, remove elements from interfaces, and create host of other COM elements such as enumerations, records, or coclasses. The Type Library Editor makes it easy to add elements to a type library. You'll learn about adding elements in the next section when you add properties and a method to the COM object.

On the left side of the Type Library Editor is the Object pane. The Object pane contains a tree view control. At the top of the tree view hierarchy is the type library itself. Below the type library are elements contained in the type library. In Figure 15.3, you see two elements: the IMultiply interface and the Multiply coclass.

On the right side of the Type Library Editor is the Information pane. This pane provides information about the object currently selected in the Object pane. The information presented in the information pane varies with the type of object selected. The Attributes page shows the type library name, its GUID, version, help string, help file, and so on.


NOTE: Remember earlier when I said that Delphi programmers don't need to worry much about GUIDs? The COM object you just created already has a GUID, as does the type library itself. Delphi creates these GUIDs for you automatically. As I said before, you'll see GUIDs a lot as you work with COM objects, but you don't have to worry about creating them.

When the type library node is selected, the Information pane shows a tab labeled Uses. When you click on this tab you will see a list of type libraries that this type library relies on. In almost all cases, this list will include the OLE Automation library, but it can contain others as well. The exact libraries a particular type library relies on depends on the type and complexity of the COM object the type library describes.

The Text page shows the type library definitions in IDL syntax. IDL is sort of a scripting language used to create binary type library files. You shouldn't change any of the text on this tab unless you know exactly what you are doing. You might, however, refer to the Text page for reference. This is probably of more value to experienced programmers than to beginners.

Other pages might be displayed in the Information pane depending on the type of object selected. For complete details, be sure to read the "T ype Library Editor" help topic in the Delphi help.

You will learn more about the Type Library Editor as you work through the rest of the chapter. Now let's get back to creating the COM object.

Adding Properties and Methods to the COM Object

Before going further, you should save the project again. You didn't realize it, but Delphi created a new unit when you created the COM object in the previous step. Choose File|Save All from the main menu and save the unit as MultiplyU.

Now you are ready to make the COM object do something. Remember, this COM object is incredibly simplistic, so it won't do much, but it will at least do something.


ADDING PROPERTIES

First you will add properties to the COM object. Here are the steps:

1. Click on the IMultiply node in the Type Library Editor's Object pane. Notice that the Information pane shows the interface's name, GUID, and version. Notice also that the Parent Interface field shows the ancestor of IMultiply as IUnknown. If you recall, I said earlier that IUnknown is the base (or parent) interface from which all other interfaces are derived. Delphi automatically assumes a base interface of IUnknown. You can change the base interface to some other interface if you want by choosing an interface from the list of available interfaces. Other interfaces in the list are themselves derived from IUnknown or one of its descendants.

2. Right-click and choose New|Property from the context menu. The Type Library Editor adds two new nodes to the Objects pane under the IMulitply interface. The cursor is in editing mode so that you can type the name of the new property.

3. Type X for the property name and then press the Enter key. Both of the new nodes change to X. There are two nodes to each property because, by default, a property is assumed to be a read/write property. COM requires a Get method to read a property and a Put method to write to a property, hence the two entries. Click on either of the two nodes labeled X. Notice the Invoke Kind field in the Information pane as you select first one X node and then the other. Notice that the field changes from Property Set to Property Get.

4. Notice in the Information pane that the Type field says Integer. That's the data type you want for this property, so you don't need to change the type.

5. Create another new property but this time use a different approach. Locate the New Property button on the Type Library Editor toolbar. Click the drop-down arrow next to the New Property button. Choose Read|Write from the list of property types. The Type Library Editor creates the new property. Name this property Y. You can accept the default data type of Integer for this property as well. Behind the scenes Delphi is adding code to the project's units as you add elements.

Adding a Method

Next, you add a method. Perform these steps:

1. Select the IMultiply object in the Object pane and click the New Method button on the Type Library Editor toolbar.

2. Name the method DoIt. Notice that the Invoke Kind field says Function (as opposed to Property Get and Property Set).

Next you must set the method's parameters. The method will have this syntax:

function DoIt : Integer;


3. Click on the Parameters tab in the Information pane. Change the Return Type field to Integer (choose Integer from the combo box). This method doesn't have any parameters, so you can leave the Parameters list empty. After you have set the return type, click the Attributes tab to display the Attributes page. This step isn't strictly necessary, but does serve the purpose of taking you back to where you started.

4. Click the Refresh Implementation button on the Type Library Editor toolbar.

Now that you have added the two properties and methods, it's time to see what Delphi has been doing behind the scenes. Listing 15.1 shows the class's unit as it appears after performing the steps up to this point. (Don't worry if your unit doesn't look exactly like Listing 15.1. My version of Delphi might have added code in a slightly different order than yours.)

LISTING 15.1. MultiplyU AFTER ADDING PROPERTIES AND A METHOD.

unit MultiplyU;
interface
uses
  Windows, ActiveX, ComObj, ComTest_TLB;
type
  TMultiply = class(TTypedComObject, IMultiply)
  protected
    function DoIt: Integer; stdcall;
    function Get_X: Integer; stdcall;
    function Get_Y: Integer; stdcall;
    procedure Set_X(Value: Integer); stdcall;
    procedure Set_Y(Value: Integer); stdcall;
    {Declare IMultiply methods here}
  end;
implementation
uses ComServ;
function TMultiply.DoIt: Integer;
begin
end;
function TMultiply.Get_X: Integer;
begin
end;
function TMultiply.Get_Y: Integer;
begin
end;
procedure TMultiply.Set_X(Value: Integer);
begin
end;
procedure TMultiply.Set_Y(Value: Integer);
begin
end;
initialization
  TTypedComObjectFactory.Create(ComServer, TMultiply, Class_Multiply,
    ciMultiInstance, tmSingle);
end. 

This is the shell of the COM object. Notice that the TMultiply class is derived from both TTypedComObject and IMultiply. (To C++ programmers, this might look like multiple inheritance. It's not exactly multiple inheritance, but it is similar in some ways.) You haven't seen the IMultiply class yet, but you will a bit later. You must fill out this shell in order to make the COM object do something. You will do that next.

Adding Code

You will now add code to the TMultiply class to make the COM object functional. Perform these steps (refer to Listing 15.2 if necessary):

1. Display the MuliplyU.pas unit in t he Code Editor. Add these lines to the TMultiply class declaration, just above the protected keyword:

private
  FX : Integer;
  FY : Integer;


These are the declarations for the data fields that will hold the X and Y property values.

2. Scroll down into the implementation section and locate the Get_X method (use the Code Explorer if you like). Type this line of code in the method:

Result := FX;


3. Locate the Get_Y method and add this line:

Result := FY;


4. Locate the DoIt method and add this line of code:

Result := FX * FY;


This line of code multiplies the value of FX and FY and returns the result.

5. Scroll down further until you see the Set_X method. Type this line of code in the Set_X method:

FX := Value;


6. Locate the Set_Y method and add this line:

FY := Value;

That's all you need to do. Your code should now look like Listing 15.2.

LISTING 15.2. THE COMPLETED MultiplyU UNIT.

unit MultiplyU;
interface
uses
  Windows, ActiveX, ComObj, ComTest_TLB;
type
  TMultiply = class(TTypedComObject, IMultiply)
  private
    FX : Integer;
    FY : Integer;
  protected
    function DoIt: Integer; stdcall;
    function Get_X: Integer; stdcall;
    function Get_Y: Integer; stdcall;
    procedure Set_X(Value: Integer); stdcall;
    procedure Set_Y(Value: Integer); stdcall;
    {Declare IMultiply methods here}
  end;
implementation
uses ComServ;
function TMultiply.DoIt: Integer;
begin
  Result := FX * FY;
end; 
function T


Multiply.Get_X: Integer;
begin
  Result := FX;
end;
function TMultiply.Get_Y: Integer;
begin
  Result := FY;
end;
procedure TMultiply.Set_X(Value: Integer);
begin
  FX := Value;
end;
procedure TMultiply.Set_Y(Value: Integer);
begin
  FY := Value;
end;
initialization
  TTypedComObjectFactory.Create(ComServer, TMultiply, Class_Multiply,
    ciMultiInstance, tmSingle);
end.

Although you were working on the MulitplyU unit, Delphi was busy building the type library and a unit to contain the type library code. The unit has the same name as the project with a trailing _TLB. This project is named ComTest. The full unit name for the type library unit, then, is ComTest_TLB.pas. Listing 15.3 shows this unit as it exists at this point. Remember, your unit might not look exactly like Listing 15.3.

LISTING 15.3. THE ComTest_TLB.pas UNIT.

unit ComTest_TLB;
// ******************************************************************** //
// WARNING                                                              //
// -------                                                              //
// The types declared in this file were generated from data read from a //
// Type Library. If this type library is explicitly or indirectly (via  //
// another type library referring to this type library) reimported, or  //
// the `Refresh' command of the Type Library Editor activated while   //
// editing the Type Library, the contents of this file will be        //
// regenerated and all manual modifications will be lost.               //
// ******************************************************************** //
// PASTLWTR : $Revision:   1.11.1.55  $
// File generated on 6/8/98 7:16:51 PM from Type Library described below.
// ******************************************************************** //
// Type Lib: D:\Borland\D4\Bin\ComTest.tlb
// IID\LCID: {7CDAFB76-FF36-11D1-81F1-0040052A83C4}\0
// Helpfile: 
// HelpString: ComTest Library
// Version:    1.0
// ***************************************


***************************** //
interface
uses Windows, ActiveX, Classes, Graphics, OleCtrls, StdVCL; 
// *********************************************************************//
// GUIDS declared in the TypeLibrary. Following prefixes are used:      //
//   Type Libraries     : LIBID_xxxx                                    //
//   CoClasses          : CLASS_xxxx                                    //
//   DISPInterfaces     : DIID_xxxx                                     //
//   Non-DISP interfaces: IID_xxxx                                      //
// *********************************************************************//
const
  LIBID_ComTest: TGUID = `{7CDAFB76-FF36-11D1-81F1-0040052A83C4}';
  IID_IMultiply: TGUID = `{7CDAFB77-FF36-11D1-81F1-0040052A83C4}';
  CLASS_Multiply: TGUID = `{7CDAFB79-FF36-11D1-81F1-0040052A83C4}';
type
// *********************************************************************//
// Forward declaration of interfaces defined in Type Library            //
// *********************************************************************//
  IMultiply = interface;
// *********************************************************************//
// Declaration of CoClasses defined in Type Library                     //
// (NOTE: Here we map each CoClass to its Default Interface)            //
// *********************************************************************//
  Multiply = IMultiply;
// *********************************************************************//
// Interface: IMultiply
// Flags:     (0)
// GUID:      {7CDAFB77-FF36-11D1-81F1-0040052A83C4}
// *********************************************************************//
  IMultiply = interface(IUnknown)
    [`{7CDAFB77-FF36-11D1-81F1-0040052A83C4}']
    function Get_X: Integer; stdcall;
    procedure Set_X(Value: Integer); stdcall;
    function Get_Y: Integer; stdcall;
    procedure Set_Y(Value: Integer); stdcall;
    function DoIt: Integer; stdcall;
  end;
  CoMultiply = class
    class function Create: IMultiply;
    class function CreateRemote(con


st MachineName: string): IMultiply;
  end;
implementation
uses ComObj;
class function CoMultiply.Create: IMultiply;
begin
  Result := CreateComObject(CLASS_Multiply) as IMultiply;
end;
class function CoMultiply.CreateRemote(const MachineName: string): ÂIMultiply;
begin
  Result := CreateRemoteComObject(MachineName, CLASS_Multiply) as ÂIMultiply;
end;
end.

Notice that this unit contains the declaration for the IMultiply interface. As you can see, IMultiply is derived from IUnknown. Notice also that this unit contains the coclass Multiply.

It is important to understand that this unit is regenerated each time you compile an ActiveX library project. It is generated from the type library file. Note the warning at the top of the unit. The comments are telling you that any changes you make to this file will be lost the next time the COM object is rebuilt. It really doesn't do any good to modify the type library source file, because it will be regenerated automatically.

Building and Registering the COM Object

Now you are ready to compile the ActiveX library project. This step compiles the COM object and builds the DLL in which the COM object resides. After building the COM object, you can register it. Here are the steps:

1. Choose Project|Build ComTest from the main menu. Delphi will build the DLL containing the COM object.

2. Choose Run|Register ActiveX Server from the main menu. This step registers the COM object with Windows. If you fail to perform this step, you will get an exception that says, "Class not registered" when you attempt to access the COM object.

Delphi registers the COM object DLL with Windows. After the DLL has been registered, Delphi displays a message box, as shown in Figure 15.4.

FIGURE 15.4. Delphi reporting the COM object successfully registered.

Whe n Windows registers the COM object, it adds information about the object to the Registry. Figure 15.5 shows the Registry entry created when the COM object was registered with Windows.

FIGURE 15.5. The Registry key created when the COM object was registered.


NOTE: Delphi ships with a utility called TREGSVR.EXE that can be used to register an ActiveX control from the command line. To register a control called MYSTUFF.OCX, you would run TREGSVR from a command prompt like this:
tregsvr mystuff.ocx



To unregister an ActiveX, use the -u switch as follows:

tregsvr -u mystuff.ocx



Sometimes this is more convenient than loading an ActiveX project in Delphi and registering or unregistering the control from the IDE.




NOTE: In this exercise I had you create a COM object. You could also have used an automation object. An automation object derives from IDispatch rather than IUnknown. IDispatch provides the additional functionality required for a COM object to act as an automation server (an object that can control one application from another).

Your COM object is now ready to use.

Building an Application That Uses the COM Object

A COM object doesn't do you much good if you can't use it. In this step, you create an application that uses the COM object you just created. Follow these steps:

1. Create a new application. Place a Button component and a Label component on the form. Save the project as ComApp and the main form's unit as ComAppU.

2. Switch to the Code Editor and locate the uses list for the main unit. Add these units to the uses list:

ComObj
ComTest_TLB


This ensures that the code that references the COM object will compile.
3. Double-click the form's button to create an OnClick event handler. Modify the OnClick handler so that it looks like this:

procedure TForm1.Button1Click(Sender: TObject);
var
  Mult : IMultiply;
  Res  : Integer;
begin
  Mult := CreateComObject(CLASS_Multiply) as IMultiply;
  if Assigned(Mult) then begin
    Mult.Set_X (20);
    Mult.Set_Y (60);
    Res := Mult.DoIt;
    Label1.Caption := IntToStr(Res);
  end;
end;

This code first declares a pointer to the IMultiply interface called Mult and an Integer variable to hold the result. Next, the CreateComObject function is called with a parameter of CLASS_Multiply. CLASS_Multiply is a constant that contains the GUID for the COM object class (refer to Listing 15.3).

The return value from CreateComObject is assigned to the Mult pointer. Notice that I use the as operator to cast the return value to an IMultiply pointer. CreateComObject returns an IUnknown pointer, so the as operator is used to cast the IUnknown pointer to an IMultiply pointer.

After the COM object is created, I assign values to the X and Y properties. After that I call the DoIt method of the COM object and display the result in the Label component.


NOTE: In the real world, I would have written the preceding procedure differently. For example:
procedure TForm1.Button1Click(Sender: TObject);
begin
  with CreateComObject(CLASS_Multiply) as IMultiply do begin
    Set_X(20);
    Set_Y(60);
    Label1.Caption := IntToStr(DoIt);
  end;
end;



I wrote the procedure the way I did to illustrate each step.


Run the program. When you click the form's button, the label should change to say "1200" (the product of 20 * 60). That's it! Your COM object works. This COM object can be used from Visual Ba sic, Visual C++, C++Builder, or any other development environment that supports COM.

Understanding ActiveX

ActiveX is a relatively new term for a technology that has been around for awhile. Originally ActiveX controls were called OCX controls. The term OCX is still widely used in some circles. An ActiveX control typically has a filename extension of either DLL or OCX.

An ActiveX control is essentially a COM object in disguise. The primary difference between an ActiveX control and a COM object is that an ActiveX control has a design-time interface. An ActiveX control also has code that enables it to be deployed on a Web page or over a network. ActiveX is a subset of COM, so everything you learned about COM objects in the first part of the chapter applies to ActiveX controls as well.

Using Third-Party ActiveX Controls

There isn't a lot to know about installing and using third-party ActiveX controls. All you have to do is import the ActiveX into the IDE and begin using the control. To see how this works, let's do a quick exercise. This exercise requires that you have Microsoft Internet Explorer installed on your system. If you don't have Internet Explorer installed, skip this exercise. (You won't be missing anything because I show you how to install an ActiveX control you have built in the section "Build, Register, and Install the Control.") Perform these steps:

1. Choose Component|Import ActiveX Control from the main menu. The Import ActiveX dialog box is displayed.

2. Scroll down through the list of installed components until you find Microsoft Internet Controls (the exact text of the item will depend on the version of Internet Explorer you have installed on your system). Select the item. Figure 15.6 shows the Import ActiveX dialog box after this step.

FIGURE 15.6. The Import ActiveX dialog box.

Notice the Class names list box in the middle of the page. This list box contains a list of ActiveX controls in the selected file (SHDOCVW.DLL in this case).

3. The Palette page field shows ActiveX. This is a the palette page where the new controls will be installed. Click on this field and type ActiveXTest.

4. Leave the Unit dir name and Search path fields on their default settings and click the Install button. The Install dialog box comes up and asks what package you want the controls installed into. (All controls, whether they are VCL or ActiveX, must be in a package.)

5. Click on the Into new package tab. Enter MSIE in the File name field and Internet Explorer Package in the Description field.

6. Click the OK button. Delphi creates a new package called MSIE.dpk and prompts you to build and install the package. Click Yes to install the package. After the package is built, Delphi displays a message box telling you which controls were added to the Component palette. Click Yes to dismiss the message box.

7. Scroll the Component palette to find the ActiveXText tab. You should see two or three controls on that page of the Component palette (again, depending on the version of Internet Explorer you have installed). The components are ready for use.

Experiment with the new controls and see how they work. You probably won't get very far without documentation, but at least you get a sense for how installing an ActiveX works. (For a more complete explanation of using Internet Explorer as an ActiveX, see the section, "Using Internet Explorer as an ActiveX Control" on the Bonus Day, "Building Internet Applications.")


NOTE: You must have a design-time license in order to use an installed ActiveX control. A design -time license is a file with an .LIC extension. In some cases you can import ActiveX controls to the Delphi Component palette without a design-time license, but you will get an error message when you attempt to place the control on your form.

To remove the Internet Explorer controls from the Component palette, choose Component|Install Packages from the main menu. Locate the Internet Explorer Package in the Design packages list box and click the Remove button. The ActiveXTest tab is removed from the Component palette.


NOTE: Deploying an application that uses ActiveX controls requires special attention. Deploying applications using ActiveX controls is covered in detail on the Bonus Day in the section "Deploying Internet Applications."

Creating New ActiveX Controls

There are two ways to create an ActiveX control in Delphi:

In this section, you create an ActiveX control using both of these methods.

Creating an ActiveX Control from an Existing VCL Component

Creating an ActiveX control from an existing VCL component is downright simple. After you create a component, you can turn it into an ActiveX control in no time at all. I haven't talked about creating components yet, so I don't want to go into a lot of detail on creating components now (covered on Day 20, "Creating Components"). What you will do, then, is create an ActiveX control from one of the VCL components provided by Borland.

Generate the ActiveX Project with the ActiveX Control Wizard

The first step is to generate the ActiveX project. As always, Delphi does most of the work for you. All you have to do is supply a few fields in the ActiveX Control Wizard. Here are the steps:

1. Choose File|Close All to close all projects and then choose File|New from the main menu. The Object Repository is displayed.

2. Click the ActiveX page and then double-click the ActiveX Control icon. The ActiveX Control Wizard is displayed (see Figure 15.7).

FIGURE 15.7. The ActiveX Control Wizard.

3. Select TButton from the list of classes in the VCL Class Name combo box. The next four fields are automatically filled in with default values. Because this is just a test, you can leave those fields on their default values. The fields are self-explanatory, so I don't need to go over each one.

4. The Threading Model is set to Apartment. Leave this setting as it is. Other threading models include Single, Free, and Both. See the Delphi help for more information on threading models.

5. Check the Include Design-Time License check box. When this option is checked, Delphi will create a design-time license for the control. The design-time license will prevent other programmers from using the control unless they have the license.

6. Check the Include Version Information check box. This will enable you to add version info to the control via the Project Options dialog box.

7. Check the Include About Box check box as well. When this box is checked, Delphi will automatically create an About dialog box for the control. Click OK to close the ActiveX Control Wizard.

Delphi will create a project file (ButtonXControl1.bpr) and three units for the project. The first unit is the TButtonX class unit (ButtonXImp1.pas). The second unit is the type library file for the control, named ButtonXControl1_TLB.pas. This file contains the information Delphi needs to create the type library for the control. The third file, About1.pas, is the unit for the About box. If you want to customize the About box, you can do that at this time. The About box is just another Delphi form, so feel free to customize it in any way you like.


NOTE: Version info is required in order for your ActiveX controls to work in Visual Basic.

Build, Register, and Install the Control

Because you aren't making any modifications to the control itself, you can jump right to building the control and registering it. This is the same process you went through when you registered the COM object you created earlier. An extra step is required when implementing ActiveX controls, though, because ActiveX controls have a design-time interface. Try this:

1. Choose Project|Build ButtonXControl1 from the main menu. Delphi builds the ActiveX project.

2. Choose Run|Register ActiveX Server from the main menu. The ActiveX control is registered and Delphi displays a message box telling you that the OCX is registered (ActiveX projects have a default extension of .OCX). Click OK to dismiss the message box.

3. Choose Component|Import ActiveX Control from the main menu. Choose ButtonXControl1 Library (Version 1.0) from the list of installed controls (had you not performed step 2, this entry would not have been present in the list of installed controls). The class name of the button, TButtonX, shows in the Class names list box.

4. Set the Palette page field to ActiveX. Click Install to continue.

5. The Install dialog box is displayed. You are going to install the control into the default Delphi user package DCLUSR40.BPL. The File name field should already contain this package. If it doesn't, choose it from the combo box. The Description field now says Delphi User's Components. Click the OK button to install the control.

6. Click Yes to the message box regarding building and installing DCLUSR40.BPL. Click OK when the mes sage box confirming the installation is displayed. The control is now installed.

Test the ActiveX Control

Now you can test your new ActiveX control. First, create a new project.


NOTE: When you create a new project, Delphi will prompt you to save the package file (DCLUSR40.DPK) and the ActiveX control project. Whether you save these files is up to you. My intention was to have you create a quick ActiveX. There's really no need to save the files. If, however, you think you might want to save the files to examine them later, save the files.

Now follow these steps:

1. Locate the ActiveX tab on the Component palette.

2. The last control in the list is the ButtonX control. Select it.

3. Place a ButtonX control on your form. Notice that the button doesn't have a default caption as a regular VCL button does.

4. Change the Caption property to Test. The button's caption changes just as a VCL button's caption would change.

Notice the list of properties in the Object Inspector. They are mostly the same properties you would see on a VCL button (the ActiveX was created from a VCL TButton after all), but you might have noticed that the Value column looks slightly different. Remember, this is an ActiveX control and is intended to be used in any environment that hosts ActiveX controls. For that reason, some of the property values are expressed in a more generic way.

5. Double-click the button and you will find that nothing happens. An ActiveX control doesn't have the capability to automatically create an event handler when you double-click the button like a VCL component does. Instead, switch to the Events page and double-click the Value column next to the OnClick event. An event handler is generated. Type this line of code:

MessageDlg(`Hey, it works!', mtInformation, [mbOK], 0);


6. Run the program and test the button to ensure that it works. When you have verified that the button works, close the program.

7. Bring up the form and right-click on the button. Choose About from the context menu. The control's About box is displayed. The About box is not customized in any way, but you can go back and do that later if you want (provided you saved the file earlier).


NOTE: The idea behind one-step ActiveX is to take a working VCL component and create an ActiveX control from that component. Most of the time, you won't have to modify the ActiveX code in any way. However, you certainly can modify the ActiveX code after it has been generated by Delphi if you so desire. Be aware, though, that if you regenerate the ActiveX code from your original VCL component, all changes made to the ActiveX source will be lost.
NOTE: You can create ActiveX controls only from windowed VCL controls (controls derived from TWinControl or one of its descendents). The list of VCL controls from which you can build an ActiveX control contains all installed components that specifically meet this criteria.

Unregister the ActiveX Control

After experimenting with your new ActiveX control, you should unregister it so that it doesn't occupy space in the Registry. To unregister the ActiveX control, do this:

1. Choose Component|Import ActiveX Control from the main menu.

2. Select the ActiveX in the list of installed ActiveX controls and click the Remove button.

3. Click Yes on the confirmation dialog box to have Delphi unregister the ActiveX.

Alternatively, you can load the ActiveX project (if you previously saved it) and choose Run|Unregister ActiveX Server from the main menu.


NOTE: If all else fails, you can always locate the ActiveX control in the Registry and delete the key for that control. Use the Registry Editor's find function to find the key (search for the control's name or its GUID). Naturally, you want to be careful when editing the Registry manually.

Creating ActiveForms

Creating an ActiveForm is almost as easy as creating an ActiveX from an existing VCL component. Naturally, you can create a complex ActiveX containing many components on a single form. Contrary to what its name implies, however, an ActiveForm can be used to create a simple ActiveX control from scratch (a colored button, for example). In other words, ActiveForms are not only for creating fancy forms with dozens of gadgets. They are for creating single-use ActiveX controls as well.

In this section, you will create an ActiveForm. The ActiveForm will have two edit controls, a label and a button. The button will take the contents of the two edit controls, multiply them together, and display the result in the label. Yes, I know it doesn't require a lot of imagination to stick with the "multiply two numbers" idea, but my goal is to show you how to create an ActiveForm with the minimum amount of code. Keeping the code to a minimum allows you to focus on the ActiveForm creation process without getting bogged down in code.

Create the ActiveForm

Creating an ActiveForm is so easy it's amazing. Follow these steps:

1. Close all projects and then choose File|New from the main menu. The Object Repository is displayed.

2. Double-click the ActiveForm icon. The ActiveForm Wizard is displayed. This dialog box is identical to the ActiveX Control Wizard except for the fact that the VCL Class Name field is grayed (it doesn't apply here).

3. Enter MyFormX in the New ActiveX Name field.

4. Change the Implementation Unit field to read MyFormImpl.pas.

5. Change the Project Name field to MyFormProj.dpr.

6. Leave the Thread Model set to Apartment. Check the Include Version Information check box.

7. Click the OK button to continue.

Delphi creates the required units and displays a form.

Create the Form

An ActiveForm form is just a regular form at this stage. You can add controls to the form, add code, and respond to events just like you do for a form that belongs to an application. The one difference is that the title bar on an ActiveForm does not appear on the control itself. It's just there at design time.

In this step, you will add components and code to make the ActiveForm functional. As you work through the steps, it might help to refer to Figure 15.8 later in the chapter, which shows the completed form. I'm going to give you the primary components in the following steps and let you finish the rest on your own. Perform these steps:

1. Size the form to approximately 175 (width) by 275 (height).

2. Add an Edit component near the top-center of the form (see Figure 15.8). Change its Name property to Num1Edit, its Text property to 0, and its Width to 50 or so (the exact width is not important). Change the AxBorderStyle property to afbRaised.

3. Click on the Edit component and copy it to the Clipboard; paste a new component from the Clipboard. Place the new component below the first. Change its Name property to Num2Edit.

4. Place a Label component below the two edit controls. This label will display the results. Change the label's Name property to ResultLbl and its Caption property to 0.

5. Place a Button component on the form to the right of the Edit components. Change its Name to GoButton and its Caption t o Go!.

6. Double-click the button and make the OnClick event handler look like this:

procedure TMyFormX.GoButtonClick(Sender: TObject);
begin
  try
    ResultLbl.Caption := IntToStr(
      StrToInt(Num1Edit.Text) * StrToInt(Num2Edit.Text));
  except
    on EConvertError do
      MessageDlg(`Oops! You entered an invalid value.',
        mtError, [mbOK], 0);
  end;
end;


This code simply extracts the values of the two edit controls, multiplies them together, and displays the result in the ResultLbl label. The exception handling code displays a message box if the user enters invalid values. An EConverError exception will be raised if the conversion from text to integer fails (if one of the edit controls contains text, for example).

7. Add additional labels to match Figure 15.8.

8. Choose View|Type Library from the main menu. In the Information page, change the Help String field to My Test ActiveForm Library. This is the text that will be displayed in the Import ActiveX dialog box when you install the ActiveForm.

9. Save the project. Accept the default filenames. (You specified them in the ActiveForm Wizard.) Figure 15.8 shows the completed form.

FIGURE 15.8. The finished ActiveForm.

Build, Register, and Import the ActiveForm

Now you can build, register, and import the ActiveForm. When built, the ActiveForm is like any other ActiveX control. Because you've done this several times now, I'm not going to go over every step. Follow these steps:

1. Choose Project|Build MyFormProj from the main menu.

2. When the project is built, choose Run|Register ActiveX Server from the main menu.

3. Choose Component|Import ActiveX Control f rom the main menu. Install My Test ActiveForm Library (Version 1) into the DCLUSR40 package. Install to the ActiveX page or any other page you choose.

The ActiveForm is now installed as an ActiveX control.

Try the ActiveForm

Now it's time to take the ActiveForm for a test drive. This will be fairly simple:

1. Create a new application.

2. Click the ActiveX tab on the Component palette and choose MyFormX button (the one with the default Delphi icon).

3. Place a MyFormX control on your form.

4. Run the program and test out the ActiveX.

That's all there is to it. With Delphi, great-looking ActiveX controls are a breeze to create! There simply is no better development environment for creating ActiveX controls than Delphi, bar none.

Changing the ActiveX Palette Bitmap

Ultimately you will want to change the bitmap of the ActiveX from the default that Delphi provides to one of your own design. Changing the bitmap requires following these steps:

1. Create a binary resource file (.RES) with Image Editor.

2. Create a 24¥24 bitmap. Give the bitmap a numeric name (2 for example).

3. Link the resource file to the ActiveX project with the $R compiler directive. (Linking resources was discussed on Day 8, "Creating Applications in Delphi" and is discussed further on Day 20, "Creating Components.")

4. Modify the ActiveX class factory creation routine in the implementation unit (the ActiveForm's .PAS file). A typical class factory creation routine looks like this (it's in the initialization section at the bottom of the unit):

TActiveFormFactory.Create(
    ComServer,
    TActiveFormControl,
    TMyFormX,
    Class_MyFormX,
    1,
    { Change this number. }
    `',
    OLEMISC_SIMPLEFRAME or OLEMISC_ACTSLIKELABEL,
    tmApartment);


Notice the line I have marked with a comment. This parameter of TActiveFormFactory.Create is the resource number of the bitmap you want displayed on the Component palette. If you saved the new bitmap with a name of 2, you would replace the 1 in this code snippet with a 2.

5. Rebuild, reregister, import, and install the ActiveForm again. The new bitmap should now show up in the Component palette.

Alternatively, you can modify the ActiveForm project's .RES file and change the bitmap named 1 to look like you want.

Web Deploying ActiveX Controls and ActiveForms

One of the great features of ActiveForms is that you can use them on a Web page. In order to use an ActiveForm on a Web page, you must use the Web Deploy option. Using Web Deploy requires a Web server, so I can't effectively walk you through the Web deployment process. I can, however, give you a little insight into the process. When you choose Web Deploy, Delphi performs two tasks:

The locations of these files is determined by the Web deployment options. Let's look at that next.

Web Deployment Options

Before you can use Web Deploy, you must set the Web deployment options. To set the Web deployment options, choose Project|Web Deployment Options from the main menu. The Web Deployment Options dialog box is displayed, as shown in Figure 15.9.

Figure 15.9. The Web Deployment Options dialog box.

At the bottom of the Web Deployment Options dialog box is a check box labeled Default. Check this box if you want the settings you have specified to be the new defaults for future projects. Most of the time, you will deploy to the same Web site, so you will probably want to set the defaults after you have everything set up just the way you want it.

Project Page: Directories and URLs Section

The Directories and URLs section is where you specify the target location for your ActiveX. The Target dir field is used to specify the directory where Delphi will copy the ActiveX after it is built. This field must be a directory--it cannot be an URL location.

If you are like me, you might not have direct access to the directory where your Web site is located. (TurboPower's Webster Royland keeps access pretty tightly controlled.) If that is the case, you will have to specify a local directory in this field and then later use your Web publishing software to publish the files to your Web site.

The Target URL field is used to specify the page where the ActiveX will reside on the server. This page is used by Delphi when it creates the HTML page that shows the control. For example, the HTML file that Delphi created for me is shown in Listing 15.4. (I had to break a couple of lines because they were too long for the page.)

LISTING 15.4. THE HTML CODE GENERATED BY DELPHI FOR THE ACTIVEX FILE.

<HTML>
<H1> Delphi 4 ActiveX Test Page </H1><p>
You should see your Delphi 4 forms or controls 
embedded in the form below.
<HR><center><P>
<OBJECT
  classid="clsid:52FB5B97-EDA3-11D1-B47B-0040052A81F8"
  codebase="http://www.home.turbopower.com/~kentr/test/MyFormProj.cab
    #version=1,0,0,0"
  width=275
  height=175
  align=center
  hspace=0
  vspace=0
>
</OBJECT>
</HTML>

Notice the URL in the codebase statement. This is the path I typed in the Target URL field of the Web Deployment Options dialog box. By the way, you can copy the entire OBJECT tag from the Delphi-generated HTML code directly to your Web p age's HTML source when you get ready to officially deploy your ActiveX code.


NOTE: The name of the HTML file created by Delphi is the project name with an extension of .htm.

The HTML dir field of the Web Deployment Options dialog box is used to specify the location where Delphi will place the HTML code it generates (refer to Listing 15.4). As with the Target dir field, if you don't have direct access to your Web site's directories, you will have to specify a local directory and then publish the HTML file to your Web site.

Project Page: General Options Section

This section is where you specify the global Web deployment options. The Use CAB file compression field determines whether the ActiveX is compressed. Compressing the ActiveX reduces the size of your ActiveX, making downloading the control that much faster. I used CAB compression on the ActiveForm created earlier in the project and the ActiveX size went from 312KB in OCX form to 204KB in CAB form. Windows takes care of automatically decompressing and registering the ActiveX, so there's no real disadvantage to using CAB compression.

The Include file version number indicates whether Delphi should include the version number in the codebase statement (again refer to Listing 15.4). The version tag is optional, so you don't specifically need it. Note, however, that some browsers won't load the ActiveX if the version tag is present (Netscape Navigator with an ActiveX plug-in, for example).

The Auto increment release number will automatically increment the version number in the ActiveX's version info each time the ActiveX is deployed.

The Code sign project option plays an important role in ActiveX deployment. When this option is on, Delphi will code sign the ActiveX. Code signing is the process of attaching a binary signature to a file. This binary signature identifies the company that created the ActiveX, among other information.

Code signi ng is important because Internet Explorer expects ActiveX controls to be code signed. If Internet Explorer's security level is set to High or Medium, any ActiveX controls that are not code signed will not load. Simply put, if you are going to deploy your ActiveX controls so that the public can use them, they must be code signed.

The Code Signing page of the Web Deployment Options dialog box contains the information needed to code sign the ActiveX. Delphi does not provide the credentials file or the private key needed to code sign files. To obtain a credentials file and private key, you will need to contact Microsoft. For more information, search the Microsoft Web site for the terms "Digital Signing" and "Certificate Authority."

The Deploy required packages and Deploy additional files options are used if you have built your ActiveX with runtime packages or if there are additional files that must ship with your control. If you choose either of these options, you must specify the packages or additional files on the Packages and Additional Files pages of the Web Deployment Options dialog box.


NOTE: When in doubt, click the Help button in the Web Deployment Options dialog box. Delphi help explains each of the pages of this dialog box.

Web Deploy

After you set the deployment options, you are ready to deploy your ActiveX. To deploy the ActiveX, simply load the ActiveX project and choose Project|Web Deploy from the Delphi main menu. Delphi will build the ActiveX and deploy it based on the settings in the Web Deployment Options dialog box. If you elected to use CAB compression, Delphi will compress the ActiveX into a CAB file as well. Remember, if you don't have direct access to your Web site's directories, you will have to publish the ActiveX and HTML file to your Web site before you can test the ActiveX.

The act of deploying the ActiveX is trivial--setting the Web deployment options is the hard part. Figure 15.10 shows the example ActiveForm created earlier running on a Web page.

FIGURE 15.10. The test ActiveForm running on a Web page.


NOTE: ActiveX controls have virtually no security restrictions. Be careful when downloading ActiveX controls from unknown (or unverified) sources. When downloaded, an ActiveX control has access to your entire system. Be equally careful when writing your own ActiveX controls. Make absolutely sure that your ActiveX control won't do anything to negatively impact other users' machines.

Summary

I won't lie to you--there's a lot more to COM and ActiveX than what is presented here. For example, I didn't talk about OLE. OLE, like ActiveX, is a subset of COM. OLE adds a layer to COM to enable applications to link and embed OLE automation servers in a container application. Still, you learned a great deal about COM and ActiveX today. Most importantly, you found out how to create COM objects, ActiveX controls, and ActiveForms. You also learned a bit about Web Deploy and how to use it to deploy your ActiveX controls on a Web page.

Workshop

The Workshop contains quiz questions to help you solidify your understanding of the material covered and exercises to provide you with experience in using what you have learned. You can find the answers to the quiz questions in Appendix A, "Answers to the Quiz Questions."

Q&A

Q Do I have to understand the inner workings of COM to write ActiveX controls in Delphi?

A Although some understanding of COM is certainly helpful, it is not vital to creating ActiveX controls with Delphi. Delphi makes it easy to create ActiveX controls without an in-depth understanding of COM.

Q What is a type library?

A A type library is a binary file that describes the interfaces, data types, methods, and classes in a COM library (including ActiveX).

Q Are OLE and COM the same thing?

A No. COM is the base upon which OLE is built. OLE is much more complex and convoluted than COM. Certainly OLE has more functionality, but OLE is a bloated beast that is best avoided if possible.

Q I noticed some nifty-looking ActiveX controls registered on my system, so I installed them on the Delphi Component palette. They show up on the Component palette but when I try to use one of the controls, I get an error message about a design-time license. Why is that?

A In short, you are not authorized to use those controls in a design environment (Delphi, for example). ActiveX users must deploy and register their ActiveX controls on every system that uses those controls. To prevent anyone from freely using those controls, the control vendors require a design-time license before the control can be used at design time. When you purchase an ActiveX control from a vendor, you get the design-time license.

Q I created an ActiveX control and placed it on my form. The program used to work fine, but now when I try to run the program I get an exception that says, Class not registered. Why is that?

A Every ActiveX control must be registered on the system on which it is being used. You might have inadvertently unregistered the ActiveX control on your system some time after you originally installed the control. To reregister the control, load the ActiveX project in Delphi and choose Run|Register ActiveX Server. Alternatively, you can register the OCX file with the TREGSVR.EXE utility.

Q I created and installed an ActiveForm and everything went fine. Later I wanted to change the ActiveForm. I couldn't compil e the ActiveForm project, though, because I kept getting an error, Could not create output file MyProj.OCX. What's wrong?

A You need to remove the ActiveForm control from the Delphi Component palette before you can rebuild the control. When the control is installed in Delphi, its OCX file is loaded by the Delphi IDE and cannot be overwritten.

Q Web Deploy confuses me. There are so many options. Am I the only one who doesn't understand this stuff?

A Certainly not. After you have worked through the Web Deploy process a few times, it's not nearly so daunting as it might appear the first time you try it.

Q I'm having problems getting my ActiveX to work on a Web page. I keep getting an error from Internet Explorer when I try to load the page. The error says, Your current settings prohibit ActiveX controls. What's wrong?

A Your ActiveX control is not code signed. An ActiveX control must be code signed before Internet Explorer will download the control when the user's security settings are set to either medium or high.

Quiz

1. What is the base (or parent) interface for all COM interfaces?

2. What is a GUID?

3. What happens when a COM object's reference count reaches 0?

4. What is the name of the Delphi utility used when working with type libraries?

5. How do you create GUIDs when writing COM objects in Delphi?

6. What do you choose from the Object Repository when creating an ActiveX from a VCL component?

7. Can you use Delphi-created ActiveX controls in Visual Basic?

8. After your ActiveX control is built and registered, how do you install it to the Delphi Component palette?

9 . How do you unregister an ActiveX that you have created?

10. Can you use the ActiveX controls created in Delphi on a Web page?

Exercises

1. Create a simple COM object from scratch. It isn't important what the COM object does, just that you go through the steps of creating it.

2. Write a Delphi application that uses the COM object created in exercise 1 (don't forget to register the COM object).

3. Create an ActiveX control from a VCL TEdit component. Install the control to the Delphi Component palette and use it on a form.

4. If you have access to Visual Basic, take the ActiveX created in exercise 3 and use it in a VB application.

5. Create an ActiveForm control of your own design.

6. If you have a Web site, deploy the ActiveForm created in step 5 and display it on a Web site page.

7. Extra Credit: Modify the ActiveForm control created in step 5 so that it uses a custom bitmap on the Delphi Component palette rather than the default bitmap.


Previous chapterNext chapterContents

© Copyright, Macmillan Computer Publishing. All rights reserved.