ereas property editors don''''t usually edit multiple properties.
No smart linking of components into the executable
ActiveX controls are independent OLE libraries (usually, DLLs), which means they can''''t be linked into your program and must be registered separately. This can make them inconvenient to install and makes yet another thing the end user must think about when uninstalling. It also leaves a possible installation conflict, if two programs install two different versions of the same library, and the two libraries are inadvertently incompatible with each other.
Perhaps more importantly, once the ActiveX libraries are linked you carry all the code around in the DLL even if your program doesn''''t use it all. When you use Delphi''''s native VCL controls, the smart linker will remove unused code, slimming the resulting executable significantly.
The Structure of an ActiveX Server Library
For the purposes of this class, an ActiveX server library is really just a Windows DLL, with some specific requirements:
1. It must export the following functions: DllRegisterServer, DllUnregisterServer, DllGetClassObject and DllCanUnloadNow. Any other functions are allowed, too.
2. The server contains class factories, one per component class. An application asks for the appropriate factory by calling the DllGetClassObject function.
3. It provides the object implementations. Each factory has a CreateObject method that creates and returns an instance of a component. The code to implement the component is contained in the DLL.
4. It contains some special resources in the same DLL. These are:
- a small bitmap that is used to represent the control on a tool palette.
- A type library.
- Version information.
5. The DLL optionally is stamped with a code signature identifying the control''''s author.
Libraries, Controls, and Multi-control libraries
Delphi gives you three options when creating an ActiveX control. You can create a blank library with no controls, add a control to an existing library, or combine both steps and create an ActiveX library with an initial control. The reason for this is that while it is convenient to produce the library and the control in the same step, you may want to insert multiple controls into the same library. Also, an ActiveX server library can contain other kinds of OLE objects besides controls, including property pages, automation objects, etc.
The first steps are the easiest: Generating an ActiveX Library Using the ActiveX Control Wizards
Since the Delphi Components and ActiveX components share many semantics and differ only in implementation, making an ActiveX Control out of a VCL is really just a matter of making a translation layer on top of the VCL implementation. This layer makes Delphi properties and methods look like OLE automation methods, makes Delphi events look like OLE Object events, and makes a VCL control look like an ActiveX server.
The conversion process involves specifying the automation and event interfaces and the object''''s ClassID, and then wrapping the whole thing up in an ActiveX server library. It also involves writing short adapter routines for each of the properties, methods and events to convert OLE-style calls to Delphi and vice versa. This part is not intellectually challenging but can become time consuming if your control has a 50-100 properties, methods and events as many do.
Fortunately, Borland provides an wizard to automate the entire production of an ActiveX Control from the Delphi VCL. The wizard uses CodeInsight™ technology to parse out the properties, methods and events from a VCL control, then generates appropriate code for their ActiveX versions.
Thanks to a few new wizards, generating an ActiveX control is very simple. The basic steps are:
- Build a normal Delphi component, based on TWinControl. Make sure the control is installed in your control palette.
- Go to the ActiveX wizards page in the Object Repository (see Figure 1) and choose "ActiveX Control." Delphi presents you with a wizard page (see Figure 2) where you choose the VCL control to derive from and fill in other information. For the VCL class name, choose the class you just installed. The dialog also presents a number of checkbox options.
- When you press OK, the wizard generates the code needed to implement the ActiveX control and adds the code to a project. If the current project is already an ActiveX library, then the wizard adds the control to the current project. If the current project is not an ActiveX project, then the wizard offers to create a new project to contain the ActiveX control.
- Build the project. You now have an ActiveX control.
- Register the control in the system, using the Run|Register ActiveX Server command. Registering is something you only need to do when you first create the control, or when you change the control''''s information that would be stored in the registry,
Figure 1. The ActiveX page of the Object Repository
Figure 2. The ActiveX Control Wizard dialog box
A First Example: Making TButton into an ActiveX control.
In order to explain the code generated by the ActiveX wizard, we first have to have an example control to examine. In the following sections, I''''ll use TButton as a simple example. Applying the above steps for creating an ActiveX control to the TButton control yields the following steps:
- Make sure TButton is installed on the palette. This is easy since it''''s the way Delphi comes installed.
- Choose File|New, select the ActiveX page and choose ActiveX Control. Press OK. In the wizard dialog, choose TButton as the VCL class name. The wizard automatically fills in the ActiveX name as ButtonX, the implementation unit as ButtonImpl1.pas, and the project name as ButtonXControl.dpr. The control options are all unchecked. Accept these defaults and press the OK button.
- The wizard informs you that since the current project is not an ActiveX project, it needs to create a new project. Answer OK. Now the wizard generates all the code for your project and control.
- Build the project. There is now a file called "ButtonXControl.ocx" on your machine.
- Register the control in the system, using the Run|Register ActiveX Server command. If successful, Delphi pops up a message saying "Successfully registered ActiveX server, ''''c:\delphi3\ButtonXControl.ocx.''''"
What the Wizard Generates
To understand what the ActiveX control hierarchy and the wizard actually do, I''''ll walk through the code generated by the wizard when you make a new control out of a TButton component. The wizard generates:
- A project file (ButtonXControl.dpr).
- An ActiveX server implementation file that contains:
- Automation interfaces and method implementations for the ActiveX control. The interfaces and methods map to those properties and methods of the VCL control that can be mapped to OLE.
- Event interfaces and proxy implementations that map from the VCL events to the ActiveX protocols.
- Class registry information and a factory object that allows the object to be registered and created by COM.
- A type library (.tlb) file that is imported into the project.
- A Pascal version of the type library.
The ActiveX Project File
The wizard generates the project file, ButtonXControl.dpr, shown here. I''''ve inserted commentary into the code, so the best way to proceed is to read through the code from top to bottom. library ButtonXControl;
The library clause defines that the project produces a DLL file called ''''ButtonXControl''''. uses ComServ, ButtonImpl1 in ''''ButtonImpl1.pas'''' {ButtonX: CoClass};
Since the library implements an ActiveX component called ''''ButtonX'''', the line tells Delphi to include the control''''s implementation in the project DLL. The {ButtonX: CoClass} comment tells Delphi that ButtonImpl1 contains a class implementation that implements the CoClass ''''ButtonX'''' from the type library. This comment helps the Delphi IDE keep the type library and the object''''s implementation in sync when you edit the type library. exports DllGetClassObject, DllCanUnloadNow, DllRegisterServer, DllUnregisterServer;
This clause specifies that the library exports the standard ActiveX server functions. These functions are implemented in ComServ, listed above in the uses clause, so you don''''t have to worry about implementing them. {$R *.TLB}
The {$ *.TLB} directive tells the linker to include the type library file as a resource into the DLL. {$R *.RES}
This tells the linker to include the project''''s resources. This includes at least one toolbar bitmap and optionally a version information resource. {$E ocx}
The {$E ocx} directive tells the linker that the output filename''''s extension should be ".OCX". begin
end.
The DAX Architecture
Before diving into the actual ActiveX control implementation, it would be worthwhile to describe the general architectural model used to implement an ActiveX control. In the DAX model, an ActiveX control is really built with three cooperating objects: the factory, an ActiveX controller object, and the VCL control. These objects in turn interact with objects they find in their environment:
|