Microsoft's Visual Basic was the first program development environment to introduce the idea of supplying software components to the mass market, even if the concept of reusable software components is older than Visual Basic—it's well rooted in the theories of object-oriented programming (OOP). The first technical standard promoted by Visual Basic was VBX, a 16-bit specification that was fully available in Delphi 1. In moving to the 32-bit platforms, Microsoft replaced the VBX standard with the more powerful and more open ActiveX controls.
ActiveX controls used to be called OLE controls (or OCX). The name change reflects a new marketing strategy from Microsoft rather than a technical innovation. Not surprisingly, then, ActiveX controls are usually saved in files with the .ocx extension.
From a general perspective, an ActiveX control is not very different from a Windows control. The key difference is in the control's interface—the interaction between the control and the rest of the application. Typical Windows controls use a message-based interface; Automation objects and ActiveX controls use properties, methods, and events (like Delphi's own components).
Using COM jargon, an ActiveX control is a "compound document object which is implemented as an in-process server DLL and supports Automation, visual editing, and inside-out activation." Perfectly clear, right? Let's see what this definition means. COM servers can be implemented three ways:
As stand-alone applications (for example, Microsoft Excel)
As out-of-process servers—that is, executables files that cannot be run by themselves and can only be invoked by a server (for example, Microsoft Graph and similar applications)
As in-process servers, such as DLLs loaded into the same memory space as the program using them
ActiveX controls can only be implemented using the last technique, which is also the fastest: as in-process servers. Furthermore, ActiveX controls are Automation servers. This means you can access properties of these objects and call their methods. You can see an ActiveX control in the application that is using it and interact with it directly in the container application window. This is the meaning of the term visual editing, or in-place activation. A single click activates the control rather than the double-click used by OLE documents, and the control is active whenever it is visible (which is what the term inside-out activation means) without your having to double-click it.
In an ActiveX control, properties can identify states, but they can also activate methods. Properties can refer to aggregate values, arrays, subobjects, and so on. Properties can also be dynamic (or read-only, to use the Delphi term). The properties of an ActiveX control are divided into groups: stock properties that most controls need to implement; ambient properties that offer information about the container (similar to the ParentColor and ParentFont properties in Delphi); extended properties managed by the container, such as the position of the object; and custom properties, which can be anything.
Events and methods are, well, events and methods. Events relate to a mouse click, a key press, the activation of a component, and other specific user actions. Methods are functions and procedures related to the control. There is no major difference between the ActiveX and Delphi concepts of events and methods.
Before I show you how to use and write ActiveX controls in Delphi, let's go over some of the differences between the two kinds of controls. ActiveX controls are DLL-based: When you use them, you need to distribute their code (the OCX file) along with the application using them. In Delphi, the components' code can be statically linked to the executable file or dynamically linked to it using a run-time package, so you can always choose whether to deploy a single large file or many smaller modules.
Having a separate file allows you to share code among different applications, as DLLs usually do. If two applications use the same control (or run-time package), you need only one copy of it on the hard disk and a single copy in memory. The drawback, however, is that if the two programs have to use two different versions (or builds) of the ActiveX control, some compatibility problems may arise. An advantage of having a self-contained executable file is that you will also have fewer installation problems.
The drawback of using Delphi components is not that there are fewer Delphi components than ActiveX controls, but that if you buy a Delphi component, you'll only be able to use it in Delphi and Borland C++Builder. If you buy an ActiveX control, on the other hand, you'll be able to use it in multiple development environments from multiple vendors. Even so, if you develop mainly in Delphi and find two similar components based on the two technologies, I suggest you buy the Delphi component—it will be more integrated with your environment, and therefore easier for you to use. Also, the native Delphi component will probably be better documented (from the Delphi perspective), and it will take advantage of Delphi and its language features not available in the general ActiveX interface, which is traditionally based on C and C++.
In the .NET world, this situation will change completely. Not only will you be able to use any system component in a more seamless way, but you'll also be able to make Delphi components available to other .NET programming languages and tools.
Delphi comes with some preinstalled ActiveX controls, and you can buy and install more third-party ActiveX controls. After this description of how ActiveX controls work in general, I'll demonstrate one in an example.
The Delphi installation process is simple:
Select Component ® Import ActiveX Control in the Delphi menu to open the Import ActiveX dialog box, where you can see the list of ActiveX control libraries registered in Windows.
Choose one, and Delphi will read its type library, list its controls, and suggest a filename for its unit.
If the information is correct, click the Create Unit button to view the Delphi language source code file created by the IDE as a wrapper for the ActiveX control.
Click the Install button to add this new unit to a Delphi package and to the Component Palette.
To build an example, I've used a preinstalled ActiveX control available in Delphi. Unlike the third-party controls, it is not available in the ActiveX page of the palette, but in the Internet page. The control, called WebBrowser, is a wrapper around Microsoft's Internet Explorer engine. The WebDemo example is a very limited web browser; it has a TWebBrowser ActiveX control covering its client area, a control bar at the top, and a status bar at the bottom. To move to a given web page, a user can type a URL in the toolbar's combo box, select one of the visited URLs (saved in the combo box), or click the Open File button to select a local file. Figure 12.8 shows an example of this program.
The implementation of the code used to select a web or local HTML file is in the GotoPage method:
procedure TForm1.GotoPage(ReqUrl: string); begin WebBrowser1.Navigate (ReqUrl, EmptyParam, EmptyParam, EmptyParam, EmptyParam); end;
EmptyParam is a predefined OleVariant you can use to pass a default value as a reference parameter. This is a handy shortcut you can use to avoid creating an empty OleVariant variable each time you need a similar parameter. The program calls the GotoPage method when the user presses the Open File button, or when the user presses the Enter key while in the combo box or clicks the Go button, as you can see in the source code. The program also handles four events of the WebBrowser control. When the download operations ends, the program updates the text of the status bar and also the combo box's drop-down list:
procedure TForm1.WebBrowser1DownloadComplete(Sender: TObject); var NewUrl: string; begin StatusBar1.Panels.Text := 'Done'; // add URL to combo box NewUrl := WebBrowser1.LocationURL; if (NewUrl <> '') and (ComboURL.Items.IndexOf (NewUrl) < 0) then ComboURL.Items.Add (NewUrl); end;
Other useful events are the OnTitleChange, used to update the caption with the title of the HTML document, and the OnStatusTextChange event, used to update the second part of the status bar. This code basically duplicates the information displayed in the first part of the status bar by the previous two event handlers.