Informant Spotlight

Delphi 3.01/ ActiveX

 

By Dan Miser

 

Deploying ActiveX Controls

Techniques for Testing, Deployment, Security, and More

 

This article will demonstrate how to deploy those controls to a Web site, as well as how to debug your ActiveX controls.

 

Deploying ActiveX Controls

Deploying an ActiveX control to a Web server is straightforward, but one wrong move and people won’t be able to use the ActiveX control from their browser. Fortunately, everything you need to make your ActiveX deployment successful is wrapped up in one dialog box. If you have an ActiveX project open, you can select the menu item Project | Web Deploy Options to display the dialog box shown in Figure 1. The options set here reflect a typical installation of Microsoft’s Personal Web Server, which runs under Windows 95.

 


Figure 1: The Web Deployment Options dialog box.

 

Note: If you fully qualify your URL with the domain name, you must specify the protocol (i.e. http://) in the Target URL edit box, or the control will fail to download properly. Alternatively, you can designate that the control is in the same directory by placing “./” in Target URL.

 

Packages. The footprint required to create even a minimal ActiveX control is a couple of hundred kilobytes. We can reduce the size, however, by using run-time packages. This way, the user must only download the run-time packages once, and can gain substantial download savings each time they download any Delphi control compiled with run-time packages.

 

Using run-time packages for an ActiveX control is as simple as using run-time packages for an application. Select Project | Options, then select the Build with runtime packages check box on the Packages page of the Project Options dialog box. Once you’ve compiled your project with run-time packages, you can enable the deployment of those packages by checking the Deploy required packages check box on the Project tab of the Web Deployment Options dialog box.

 

Installing multiple files with your ActiveX control will require you to use some combination of an .INF file and a .CAB file. An .INF file is an installation script that points to the locations of all the files needed to make your ActiveX installation complete. .CAB files allow multiple files to be distributed over the Internet in compressed form, much like a .ZIP file. If you distribute many files, or if the file sizes are large, you may want to distribute the files in compressed mode via the .CAB file.

 

Borland has code-signed some of their run-time packages and placed them in .CAB files on their Web site (http://www.borland.com). Code-signing these packages proves that the run-time package files the end user receives are the same ones that Borland developed (see Figure 2).

 

[Add.Code]

packages.ocx=packages.ocx

VCL30.dpl=VCL30.dpl

 

[packages.ocx]

file=http://dmiser.comps.com/delphi/packages.ocx

clsid={ 03B3F168-C13B-11D0-9BB9-00A024604D21 }

RegisterServer=yes

FileVersion=1,0,0,0

 

[VCL30.dpl]

file=http://www.borland.com/vcl30.cab

FileVersion=3,0,5,53

Figure 2: Sample .INF file for an ActiveX control built with run-time packages.

 

Code-signing. ActiveX controls pose a potential security risk to clients who download them. For this reason, Microsoft has proposed a technology called Authenticode. Authenticode assures end users of the ActiveX control’s origin, and that it hasn’t been tampered with since the control has been signed. While this is not foolproof, it does provide some degree of accountability for the majority of cases.

 

To obtain certification for your control, you must contact an authorized Certification Authority (one such company is VeriSign; http://www.verisign.com). You can apply for a certificate; upon acceptance, the authorized Certification Authority will return a certificate file you can use to sign a control.

 

For any serious ActiveX development, you must obtain the ActiveX SDK from Microsoft. In the ActiveX SDK you’ll find documentation, online resources, and a suite of programs to help develop ActiveX content. For example, the program MAKECER generates test certificates you can use for local testing. For more information, visit http://www.microsoft.com/activex.

 

Deploy. When all the options have been properly set, select Project | Web Deploy to execute the deployment. This will copy the ActiveX control, an .INF file and .CAB file if appropriate, and a skeleton HTML file to the directory specified. If your Web site isn’t hosted locally, you can still deploy all the files to a local directory and use the same method of moving the files to your host directory after deployment.

 

One more note: Writing an ActiveX control or ActiveForm that accesses a database requires the client machine to have a copy of the BDE (Borland Database Engine) installed. Furthermore, the client machine must be able to physically connect to the database. For this reason, database applications are best suited to intranet deployment. If you do choose to deploy an ActiveX control that needs database access, Delphi 3.01 includes a .CAB file and an .INF file to take care of the BDE installation process. See the file BDEINST.TXT on the Delphi 3.01 CD for more information on how to do this. On the other hand, if you want a true thin-client solution over the Internet, you will need to use MIDAS.

 

Using ActiveX in HTML

HTML syntax. ActiveX controls are frequently used in HTML pages. The <OBJECT> tag is used to identify the control to the browser. In addition, several attributes are used for this tag to help the browser display the proper ActiveX control to the client:

          CLASSID: CLSID registered to the ActiveX control

          CODEBASE: URL used by the browser to download the control to the client

 

For more information on this tag, see the HTML working draft at http://www.w3.org/pub/WWW/TR/WDobject.html.

 

Version control. If you deploy your ActiveX control with version information enabled, the browser will automatically detect whether it needs to update the control. The syntax of the HTML to take advantage of version control is to append the version number to the CODEBASE attribute. For example, the following HTML code will only download the control if the version number of the control is later than 1.1:

 

<OBJECT

  CLASSID="clsid:7FD22F02-C0E1-11D0-9BB9-00A024604D21"

  CODEBASE=

"http://dmiser.comps.com/calendarx.ocx#version=1,1,0,0”

 

Once the ActiveX control is deployed to a client, there will be two glaring features that need to be addressed:

1)       How to use property names in HTML

2)       Safety warnings when using the ActiveX control in HTML

 

Assigning property names. Delphi-created ActiveX controls implement the saving and restoring of property values through a standard persistence model. This provides a way for the ActiveX control to tell others about its properties. For example, the HTML listing in Figure 3 is the result of adding a Delphi-created ActiveX control to an HTML page using Microsoft ActiveX Control Pad.

 

<OBJECT ID="CalendarX1" WIDTH=320 HEIGHT=120

  CLASSID="CLSID:7FD22F05-C0E1-11D0-9BB9-00A024604D21"

DATA="DATA:application/x-oleobject;BASE64,BS/Sf+HA0BGbuQCgJ

GBNIVRQRjAJVENhbGVuZGFyAARMZWZ0AgADVG9wAgAFV2lkdGgDQAEGSGVp

Z2h0AngLU3RhcnRPZldlZWsCAAAASA=">

</OBJECT>

Figure 3: An <OBJECT> tag for imported ActiveX control. (Note: There cannot be carriage returns in the actual DATA string; they were added here for formatting purposes.)

 

All the properties are set in the DATA element of this tag; however, there is no easy way to look at this data to determine what the value of a given property is. In addition, by using this method, the ActiveX control is more difficult to control in an HTML scripting environment, such as VBScript or JavaScript.

 

Microsoft defined the IPersistPropertyBag interface to turn the unreadable data into human-readable properties. To implement this interface, we simply need to add the two key methods, Load and Save, to our existing ActiveX implementation. However, because the IPersistPropertyBag interface already defines these methods, we must use Delphi’s method resolution clauses to make our implementation work (see Figure 4). For more information on this topic, look up “Method resolution clauses” in Delphi’s online Help.

 

TCalendarX = class(TActiveXControl, ICalendarX,

                   IPersistPropertyBag)

  function IPersistPropertyBag.Load =

             PersistPropertyBagLoad;

  function IPersistPropertyBag.Save =

             PersistPropertyBagSave;

  function PersistPropertyBagLoad(

    const pPropBag: IPropertyBag;

    const pErrorLog: IErrorLog): HResult; stdcall;

  function PersistPropertyBagSave(

    const pPropBag: IPropertyBag; ClearDirty: BOOL;

    fSaveAllProperties: BOOL): HResult; stdcall;

end;

Figure 4: Implementation of TCalendarX.IPersistPropertyBag.

 

The IPersistPropertyBag interface referenced in the Load and Save methods is the interface responsible for reading and writing individual properties. You can find the helper routines ReadPropFromBag and PutPropInBag in \Delphi 3\SOURCE\RTL\SYS\comobj.pas. These procedures make it easy to implement an IPersistPropertyBag interface for any ActiveX control (see Figure 5).

 

function TCalendarX.PersistPropertyBagSave(

  const pPropBag: IPropertyBag; fClearDirty: BOOL;

  fSaveAllProperties: BOOL): HResult; stdcall;

begin

  PutPropInBag(pPropBag, 'Color', FDelphiControl.Color);

  Result := S_OK;

end;

Figure 5: The IPersistPropertyBag.Save function.

 

Each item you add to the property bag in this function will show up as a <PARAM> for the <OBJECT> tag. This provides another level of HTML interactivity by allowing the use of these properties in an HTML script (see Figure 6).

 

<OBJECT ID="CalendarX1" WIDTH=320 HEIGHT=120

CLASSID="CLSID:7FD22F05-C0E1-11D0-9BB9-00A024604D21">

  <PARAM NAME="BorderStyle" VALUE="1">

  <PARAM NAME="CalendarDate" VALUE="5/29/97">

  <PARAM NAME="Color" VALUE="-2147483643">

  <PARAM NAME="Ctl3d" VALUE="-1">

  <PARAM NAME="Cursor" VALUE="0">

  <PARAM NAME="Day" VALUE="29">

  <PARAM NAME="Enabled" VALUE="-1">

  <PARAM NAME="FontName" VALUE="0">

  <PARAM NAME="FontSize" VALUE="8">

  <PARAM NAME="GridLineWidth" VALUE="3">

  <PARAM NAME="Month" VALUE="5">

  <PARAM NAME="ParentColor" VALUE="0">

  <PARAM NAME="ReadOnly" VALUE="0">

  <PARAM NAME="StartOfWeek" VALUE="0">

  <PARAM NAME="UseCurrentDate" VALUE="-1">

  <PARAM NAME="Visible" VALUE="-1">

  <PARAM NAME="Year" VALUE="1997">

</OBJECT>

Figure 6: An <OBJECT> tag with IPersistPropertyBag implemented.

 

Automating persistence. We can borrow some logic to implement this interface in a more generic manner by looking at the demonstration application Pbag.dpr found in the \Delphi 3\Demos\Activex\Propbag directory. This demonstration was included in the Delphi 3.01 update. In it, the IPersistPropertyBag interface reads and writes the properties of the control using RTTI (Run-Time Type Information). Using this method ensures we won’t forget any properties that need to be streamed.

 

It would be nice to use Borland’s implementation of IPersistPropertyBag in all our controls. However, because COM only allows interface inheritance, we have but two options:

1)       Place the common code in a separate unit and implement the interface for every ActiveX control that requires the IPersistPropertyBag interface.

2)       Create a new component derived from TActiveXControl that implements the IPersistPropertyBag interface. By doing this, all that must be changed is the inheritance of your new ActiveX control from TActiveXControl to TActiveXPropBag. This will allow your control to automatically receive the IPersistPropertyBag implementation.

 

By descending from Delphi’s object reference, as opposed to COM’s interface reference, we can achieve implementation inheritance.

 

Marking the ActiveX control as safe. When using an ActiveX control in a script, Microsoft Internet Explorer (IE) will check if the control can be safely scripted. If the control is not deemed safe, a warning message will be displayed (see Figure 7).

 


Figure 7: The error displayed when a control is not marked safe for scripting.

 

By default, any control in a script will generate this warning. According to the ActiveX SDK documentation, there are three ways to suppress this warning message:

1)       Turn off the security checking option for all scripts in IE.

2)       Register the control as “safe for scripting” in the Windows registry.

3)       Implement the IObjectSafety interface.

 

Let’s examine the implications of each scenario.

 

Marking all controls as “safe for scripting” in IE isn’t a very secure way to stop these messages from occurring. Some controls might really be unsafe for scripting, and the user should be warned about those instances. Implementing the IObjectSafety interface is overkill for most ActiveX controls, as a control is usually either safe or unsafe in its entirety. Therefore, let’s concentrate on the second option — marking the control as safe in the registry.

 

IE will check for the existence of two specific registry entries for every control that is placed in a script (see Figure 8).

 


Figure 8: Regedit displaying a safe control.

 

If these entries exist, IE knows the author has marked the control as safe, and will not display a warning. The two registry entries are CATID_SafeForScripting and CATID_SafeForInitializing. The entries are special because they are defined as Category IDs. A Category ID is created to group components into a particular category. To belong to these categories, the author of the control must believe the control will not harm your system — no matter how the ActiveX control is used in the script.

 

TActiveXControlFactory is the class factory responsible for creating and registering ActiveX controls. In this class factory, there is a method called UpdateRegistry that maintains registry settings for an ActiveX control. This seems like a logical place to add the registry entries that will mark this control as safe. Creating our class factory is as easy as descending the TActiveXControlFactory class and manipulating the registry settings in the overridden UpdateRegistry method:

 

TActiveXSafeFactory = class(TActiveXControlFactory)

  procedure UpdateRegistry(Register: Boolean); override;

end;

 

After implementing this class, change the TActiveXControlFactory.Create statement in the initialization section of the project to TActiveXSafeFactory.Create. Then, every time the control gets registered or unregistered, the registry settings that belong to the control will be automatically updated as well.

 

Testing ActiveX Controls

DLL debugging. Previous versions of Delphi required you to buy Borland’s add-on package, Turbo Debugger for Windows (TDW), to debug DLLs. Delphi 3 allows you to debug the currently loaded DLL inside the Delphi IDE. To accomplish this, you need to open the DLL project file, then specify an .EXE that will use this DLL. This is known as the host application. Select Run | Parameters to bring up a dialog box where you can specify a host application and any command-line criteria for that application. Select Run | Run to start the host application. If you have a breakpoint set in the DLL source files, Delphi will stop execution of the host application and pass control to the Delphi IDE, where you can evaluate variables and step through code.

 

Remember that an ActiveX control is nothing more than a DLL. IE is an application that uses these special DLLs. Therefore, we can use the debugging technique previously described to debug our ActiveX controls.

 

Figure 9 shows the settings needed to debug the CalendarX project using IE as the host application. Place a breakpoint in the InitializeControl method in the unit CalImpl.pas. After modifying the run parameters for the project, execute the Run | Run command to launch IE. When the ActiveX control is loaded, the Delphi IDE will regain focus, and you can use the integrated debugger the same way you always have. To stop the debugging session, exit IE.

 


Figure 9: Setting run parameters to debug Personal Web Server.

 

Conclusion

These two articles have covered a lot of ground in the ActiveX arena. However, even this lengthy treatment only scratches the surface of things that can be done with this impressive component technology. To further understand ActiveX, read the ActiveX SDK documentation; it’s a price well worth paying as the line blurs between Delphi and ActiveX components.

 

The projects referenced in this article are available for download.

 

Dan Miser is a software developer residing in Southern California with his wife and daughter. He has been a Borland Certified Client/Server Developer since 1996, and is a frequent contributor to Delphi Informant. You can contact him at http://www.iinet.com/users/dmiser.

 

Swell! You’ve created an ActiveX control. Getting it “out there” to users, however, is another story. Mr Miser lays out the issues and their solutions when it comes to Web deployment.

 

Getting your ActiveX controls out there for your users.