You are on page 1of 43

April 2001, Volume 7, Number 4

Cover Art By: Arthur Dugoni

ON THE COVER
5 First Look 26 Dynamic Delphi
It’s Kylix! — Cary Jensen, Ph.D. ISAPI Development: Part III — Shiv Kumar
Cary Jensen unveils Borland’s “Delphi for Linux” product. Is it Linux’ Shiv Kumar completes his series by demonstrating how to efficiently
“killer app?” Only time will tell, but to date, there’s certainly no deliver graphics to a Web browser, including how to reduce their size
Linux-based IDE remotely as productive. and bandwidth requirements on the fly.

34 From the Palette


FEATURES Excel Server Components — Ron Gray and Steven McPherson
9 Kylix Quickstart Ron Gray and Steven McPherson team up to demonstrate how to
The Linux Desktop — Charlie Calvert create reports and charts using Microsoft Excel as an Automation
Charlie Calvert kicks off his new Kylix column by starting at the server.
beginning; it’s an introduction to the component parts of the Linux
desktop, for the uninitiated.
REVIEW
13 Greater Delphi 38 Wise for Windows Installer 3.0
Better UI Design: Part III — Robert Leahey Product Review by Bill Todd
Robert Leahey finishes his series by sharing a complete set of classes
for saving user settings. Now if only Microsoft had used them for the DEPARTMENTS
Windows Find applet!
2 Delphi Tools
20 Informant Spotlight 42 File | New by Alan C. Moore, Ph.D.
Decision 2001 — David Riggs
Delphi Informant Managing Editor David Riggs delivers the latest
election results regarding your favorite Delphi third-party products —
with nary a butterfly ballot.

1 April 2001 Delphi Informant Magazine


Delphi Cytron Research Releases Visual VCL Help 1.0
Cytron Research has released
T O O L S Visual VCL Help 1.0, a
program for Delphi and
New Products C++Builder that lets VCL
and Solutions component authors rapidly
generate help files utilizing a
simple point-and-click visual
interface.
Visual VCL Help employs
a single project to simultane-
ously generate both Delphi and
C++Builder VCL help files,
thus minimizing the effort
required to produce VCL com-
ponents for the Delphi and
C++Builder environments. In Help builds up an internal dic- of Delphi or C++Builder. The
Book Picks addition, by parsing all the rel- tionary of elements obtained dictionary holds classes, class
evant source files, Visual VCL during the parsing of the methods, class properties and
Help generates the standard relevant source files and of events, type descriptors, stand-
Apache Desktop Reference
Help topic pages associated those elements manually added alone procedures, and func-
Ralf S. Engelschall with a VCL component as well as references to third-party tions, as well as examples and
Addison-Wesley as browse groups, pop-up win- help files. general help topics.
dows, and hyperlinks. This dictionary is then
Designed to simplify the employed to generate relevant Cytron Research
construction of Help files for topic pages, pop-up windows, Price: Single-user license, US$57.
different versions of Delphi browse groups, and hyperlinks Contact: Info@CytronResearch.co.uk
and C++Builder, Visual VCL for the user-selectable target Web Site: http://www.CytronResearch.co.uk

Cocolsoft Computer Solutions Releases Cogencee 2.0


Cocolsoft Computer Solu- Delphi Grammar Component, Guide and two technical papers,
tions announced the release of the source to the component a set of examples with full source
ISBN: 0-201-60470-1 Cogencee 2.0, a compiler gen- (ColDelphi.pas), a help file, code giving the grammar, the
Cover Price: US$39.95
erator for Delphi. Cogencee and six demonstration pro- generated Delphi code, the main
(184 pages)
2.0 allows you to produce grams with source. Running unit, and executable.
scanners, parsers, compilers, Cogencee allows you to alter
interpreters, language checkers, the grammar behind the com- Cocolsoft Computer Solutions
Professional XML Databases natural language processors, ponent or change its function- Price: Cogencee Standard, US$180;
Kevin Williams et al. expert system shells, scripting ality. Cogencee Professional, US$300.
Wrox
languages, and calculators. Cogencee ships with an Contact: info@coolsoft.com.au
Cogencee 2.0, written in 80-page manual with a User Web Site: http://www.coolsoft.com.au
Delphi, generates Delphi code.
Cocol (the compiler language
behind Cogencee) was used to
American Cybernetics Releases Multi-Edit 9
generate itself. American Cybernetics Inc. VCS support, a tree-view
Cogencee is available for released Multi-Edit 9, a pro- function browser, color print-
32-bit platforms in two grammer text editor. Multi- ing, multiple clipboards, and
versions — Standard and Edit 9 is a professional- numerous user interface
ISBN: 1-861003-58-7
Professional. Cogencee 2.0 strength programming improvements.
Cover Price: US$49.99 Professional includes the environment running on Multi-Edit 9 now includes
(1,007 pages) source code with an Obfus- Windows 95/98/NT/2000 that support for many of the newer
cator program, hashing tools, integrates with several popular languages being used in Inter-
and class TColMStack, Cocol- RAD development environ- net site development, including
soft’s multi-stack class, which ments such as Borland’s Delphi PHP, MIVA, Progress, SQL,
combines the functionality of and C++Builder, and now PYTHON, AutoLisp, TCL,
a stack and a doubly linked Microsoft Visual Studio and VHDL, Eiffel, REBOL, LaTex,
list. This class has been used Allaire’s ColdFusion Studio. and HTMLScript.
in the scanner generator for the Multi-Edit 9 features include
‘Cocolsoft Delphi Grammar’. enhanced HTML support, American Cybernetics Inc.
TColMStack comes with a test CSE HTML Validator integra- Price: Downloadable version with full docu-
bed program. tion, improved embedded lan- mentation in .pdf format, US$129.
Cogencee 2.0 includes guage handling, a redesigned Contact: sales@multiedit.com
TColDelphi, the Cocolsoft Project Manager, improved Web Site: http://www.multiedit.com

2 April 2001 Delphi Informant Magazine


Delphi NAG Software Solutions Releases NAG Components 2.0
NAG Software Solutions
T O O L S announced the release of NAG
Components for Delphi 2.0, a
New Products multi-platform, one-stop suite
and Solutions of over 70 native components
for Delphi, including many
new visual and non-visual
components, in addition to which are fully supported by all NAG Components for Delphi
a package of 15 data-aware the visual controls. runs on all Windows operating
controls. NAG Components for Delphi systems, enabling developers to
NAG Components for Delphi 2.0 features include fully cus- produce cross-platform appli-
2.0 also showcases reusable tomizable buttons; flat buttons, cations from their favorite
procedures and functions for lists, edit boxes, and memos; Windows operating system. All
ease of use. Enhanced property more than 10 border styles for NAG Software components
editors for classes such as visual and data-aware controls; adapt themselves at run-time
TStrings and TCaption have hardware and system access pro- to run under Windows 95, 98,
Book Picks been added for editing of string vided by non-visual compo- Me, NT, and 2000.
lists and multi-line captions — nents; and screen saver creation.
NAG Software Solutions
AbriaSoft Releases Abria SQL Standard 2.1 Price: US$89.95
XML Developer’s Guide
AbriaSoft, a provider of Open 4, Apache Web Server 1.3.14, Contact: sales@nagsoftware.com
Fabio Arciniegas
Osborne/McGraw-Hill Source software, released Abria and Webmin; secure 128-bit Web Site: http://www.nagsoftware.com
SQL Standard 2.1 for Red Hat Apache server with open SSL
Linux and Microsoft Windows support; GUI and text mode Griffin Technologies
platforms. Abria SQL Standard intelligent installer; PHP sup- Introduces SmartID
2.1 integrates the secure ‘SSL’ port for IMAP, LDAP, GD, and
flavor of Apache, a Web server XML; PHPMyAdmin, PHP Griffin Technologies, LLC
with MySQL. The Windows support for PostgreSQL; Abri- introduced SmartID, a two-factor
version of Abria SQL Standard amenu full documentation for authentication solution for infor-
2.1 also includes Apache/SSL all included software; libraries mation security.
and ODBC connectivity to — open LDAP, GD, T1Lib, SmartID is a combination
ISBN: 0-07-212648-5 enable the creation of appli- MM; free service updates and of a hardware token, a key-like
Cover Price: US$59.99
cations using software such patches for registered users; device that can be carried on
(682 pages, CD-ROM) a key-ring and simply plugged
as Microsoft Access, FoxPro, 30-day e-mail installation sup-
Visual Basic, and Clarion as port; and a 500-page O’Reilly into the USB port, and a pass-
front ends for MySQL. book, MySQL and mSQL by word for a particular person
WAP Development with WML
Abria SQL Standard 2.1 Randy Jay Yarger et al [O’Reilly at a particular workstation.
and WMLScript SmartID’s encryption is inside
Ben Forta et al. includes Red Hat 7.0 support; & Associates, 1999].
SAMS supports Red Hat Linux 6.x on the key to guarantee that only
Intel platform, Red Hat Linux AbriaSoft the person with the password
6.2 on Sparc, and YDL Cham- Price: Linux V.2.1, US$109; Windows and SmartID key can log in.
pion server 1.2 on PowerPC; V.2.1, US$129; save US$20 on download- SmartID is available in three
offers a turnkey installation of able versions. modules that enable access to
MySQL 3.23.27 b, Perl 5.6, Contact: sales@abriasoft.com secure information and data over
Perl DBI 1.14, PHP 3 & Web Site: http://www.abriasoft.com three main modes. The Local/
Network Login module allows
each authorized person access
to a designated workstation and
ISBN: 0-672-31946-2 specified information in the net-
Cover Price: US$54.99
(586 pages, CD-ROM)
work. Another module provides
Internet Content Protection for
data and/or software stored on
a server and accessed through a
browser. For off-site employees,
the module features Remote
Access Login.

Griffin Technologies, LLC


Price: Software, US$499; US$35 per token.
Contact: (800) 986-6578 ext. 203,
rbregman@griftech.com
Web Site: http://www.griftech.com

3 April 2001 Delphi Informant Magazine


Delphi FMS Offers Total ZipCode Database
FMS, Inc., in conjunction with
T O O L S the US Postal Service (USPS),
announced Total ZipCode Data-
New Products base, a monthly subscription to
and Solutions the official USPS ZIP code data-
base. Total ZipCode Database
provides users with a database
of more than 50,000 records for
every valid ZIP code, city, and
state name across the US.
Total ZipCode Database allows
users to simplify data entry by
automatically filling city and
state fields when a ZIP code is
entered.
There are over 42,000 unique Total ZipCode Database the USPS requires that you
Book Picks ZIP codes, each with a primary Access databases include addi- update your ZIP code database
city and state name. But some tional resources such as a table at least once a year. Total Zip-
ZIP codes have more than one with a list of all countries; Code Database provides you
acceptable city. This database a table with a list of state with the ZIP code database as a
Cryptography and E-Commerce gives you all the acceptable city abbreviations for US, Canada, subscription entitling you to the
Jon C. Graff names, plus the county name Mexico, and Australia; a way current copy plus 11 monthly
Wiley
and number. Total ZipCode to create a ZIP code table of updates. Total ZipCode Data-
Database lets your users choose just the official city names for base is distributed electronically.
without spelling a city name or each ZIP code; and a sample
state abbreviation ever again. form with source code showing FMS, Inc.
You can integrate Total Zip- how to automatically fill the Price: Includes 12-month rental fee and 12
Code Database data into your city and state when a user updates: one license, US$99; five licenses,
applications. The data is pro- enters a ZIP code. US$299; 25 licenses, US$999.
vided in three formats: Access Because ZIP codes are Contact: sales@fmsinc.com
97, Access 2000, and ASCII file. added and modified regularly, Web Site: http://www.fmsinc.com
ISBN: 0-471-40574-4
Cover Price: US$29.99 combit Releases combit List & Label 7.0 in Japanese
(222 pages)
combit GmbH released combit developers to develop in their code will integrate it in Delphi
List & Label 7.0, a report genera- own language. List & Label 7.0 or Visual Basic 6.0. The real
tor, in Japanese. List & Label is Japanese contains complete docu- data preview can be used with
PostgreSQL: Introduction and
a database-independent compo- mentation in Japanese. Internet/intranet applications and
Concepts nent for developers who want List & Label lets developers the Designer component can be
Bruce Momjian to arm their applications with equip their applications with passed on to the end-user with no
Addison-Wesley general output and reporting functions for creating reports, added royalty fees.
capability. List & Label 7.0 Jap- lists, forms, and labels. A few List & Label is also available
anese, developed in cooperation lines of code will integrate the in English and German — lan-
with AG-Tech Corp. in Nagoya, report generator into the user’s guage kits for the Designer
Japan, enables Japanese-speaking application, and a single line of component are available in 17
languages. A special Unicode/
Multibyte module that processes
character sets of most languages is
also available.
List & Label 7.0 is 32-bit and
ISBN: 0-201-70331-9 available for all DLL-compatible
Cover Price: US$44.95 programming languages, as well as
(462 pages) for Delphi and Visual Basic. It
includes a programmer’s manual,
tutorial, programming examples,
end-user manual, and online help.

combit GmbH
Price: Full developer version including
unlimited run-time license, US$490; Visual
Basic-only or Delphi-only version, US$350.
Contact: sales@combit.net
Web Site: http://www.combit.net

4 April 2001 Delphi Informant Magazine


First Look
Kylix / Linux / CLX / Qt Libraries

By Cary Jensen, Ph.D.

It’s Kylix!
Borland Ships the First RAD Tool for Linux

S ince September of 1999, when Borland announced they would produce a version
of Delphi for the Linux operating system, Kylix (the project’s code name and
now its shipping name) has been one of the most anticipated products in Borland’s
history. Now the long wait is over. By the time you read this, Kylix will be available
to developers everywhere.

Originally, the Kylix project was reported to So what exactly is Kylix, and who is likely to use
include both Delphi for Linux and C++Builder it? This article will attempt to answer these ques-
for Linux. However, the latest word from Borland tions, and more. Note, however, that the following
marketing is that the name Kylix will apply to the descriptions are based on a pre-release version of
Pascal flavor of the product, with another name Kylix. Screen images and features of the shipping
being used for the one that uses C++. That ver- version of this product may differ.
sion, by the way, is scheduled to be released some
time later this year. Overview
To put it simply, Kylix is a version of Delphi that
runs on Linux. Anyone who might have worked
with a product that has been developed to run on
two or more operating systems might be a little
skeptical about this statement (remember Paradox
for DOS and Paradox for Windows), but in this
case, it’s true. Over the past half year I have partici-
pated in a number of conferences and seminars
where Delphi developers got a good look at pre-
release versions of Kylix. The most frequent com-
ment I’ve heard is a surprised “Hey, that’s Delphi!”

To see for yourself, take a look at Figure 1. Among


the only clues that Figure 1 is not a screenshot
of Delphi 5 are the presence of the GNOME desk-
top, and a couple of oddly named units appearing
in the default project’s uses clause. Otherwise,
there can be no mistaking this product for any-
thing other than Delphi.

Yet important differences exist. Specifically,


Kylix compiles Executable and Linking Format
(ELF) files, a 32-bit industry standard object file
Figure 1: Kylix running on Red Hat Linux 7.0. format developed and published by the UNIX

5 April 2001 Delphi Informant Magazine


First Look
Systems Laboratory, as opposed to Delphi, which produces Por- BaseCLX. BaseCLX includes the core class definitions and run-time
table Executable (PE) files, the standard for Windows applica- library (RTL) functions. This part of Kylix is nearly indistinguishable
tions. By default, the applications created by Kylix can be run from the corresponding parts of Delphi. Units that contain the
on either KDE (K Desktop Environment) or GNOME (GNU BaseCLX definitions include System, SysUtils, and Classes. For the
Network Object Model Environment, pronounced gah-Nome) most part, the symbols that appear in these units are indistinguishable
desktops. (Kylix applications are designed to run on both KDE from their Delphi counterparts.
and GNOME, but technically only require an X server.) Alter-
natively, you can create console applications that can be run VisualCLX. VisualCLX, as the name implies, contains those symbols
from a shell prompt (such as the BASH shell), either by using that constitute the visual elements of your application’s user interface.
the Console Wizard in the Object Repository, or by adding the As mentioned earlier, because many of the VCL’s visual controls
{$APPTYPE CONSOLE} compiler directive to your application. are based on Windows controls, significant changes appear in the
VisualCLX units. For example, the TWinControl class, which makes
I suspect that most developers are shocked by the similarities between extensive use of the Windows message queue to receive messages
Delphi and Kylix, because of the former’s close binding to the Win- from the operating system, has been replaced by the TWidgetControl
dows operating system. Specifically, Delphi applications rely almost class, which encapsulates a Qt widget. Understandably, all visual
exclusively on the Windows message queue for message handling and components of CLX descend from TWidgetControl.
inter-component communication. Similarly, many of Delphi’s visual
components are subclassed Windows controls. These two facts led Fortunately, one important element of VisualCLX that is almost
many to conclude that porting Delphi to another platform would be identical to its VCL counterpart is TCanvas. Most code you’ve
nearly impossible. written that involves writing to a TCanvas, including the manipu-
lation of fonts and brushes, will work correctly in Kylix. By
There are two primary technologies that contributed to the suc- comparison, if your Delphi code made use of Windows API calls
cessful development of Kylix. The first is the introduction of an and device contexts to draw, that code will have to be replaced for
entirely new compiler, a predecessor that debuted at the 10th you to migrate your applications to Kylix.
Annual Borland Conference held in July 1999 in Philadelphia.
The second is the implementation of a new component library, Unlike BaseCLX, which does a good job of maintaining many of the
named Component Library Cross-platform, formally known as same classes and declarations as its corresponding units in the VCL,
CLX (pronounced clicks), which is used in place of the Visual VisualCLX contains substantial differences from the VCL, primarily
Component Library (VCL). While the VCL is tightly bound to with respect to the properties the various classes posses. As a result,
the Windows operating system, CLX is a platform-independent VisualCLX units and their VCL counterparts have been given differ-
layer that sits on top of the Qt (pronounced cute) libraries. The ent names. For example, the Controls unit in the VCL corresponds to
Qt libraries are written in C++, and define an object-oriented set the QControls unit in VisualCLX. Similarly, the Dialogs unit in the
of graphical user interface (GUI) classes. VCL corresponds to the QDialogs unit in VisualCLX.

The Qt libraries, which were also used to program the KDE This unit name distinction is particularly beneficial when you
desktop, have several characteristics that make them a sound choice are writing a single-source application that makes use of CLX
for CLX. First, the Qt visual classes, called “widgets,” map very on Linux and the VCL on Windows. In short, using conditional
nicely to the visual controls subclassed by Delphi’s VCL. Specifi- defines you can instruct the compiler to use the units whose
cally, Qt widgets and Windows controls share a large number of classes are appropriate for the platform for which you’re compil-
similar properties. Likewise, they share a number of comparable ing. In fact, Kylix includes the conditional symbol LINUX, which
events, although these are implemented in Qt through signals and is automatically defined when you are compiling with Kylix. You
slots, using Qt nomenclature. As a result, many of the classes in typically use this symbol with the new MSWINDOWS symbol,
CLX are immediately recognizable to Delphi developers, thereby which is reportedly going to be automatically defined in Delphi
reducing the number of changes necessary to convert VCL applica- 6. The following is an example of how these conditional symbols
tions to CLX. can be used:

Another advantage of Qt is that Qt libraries exist for both Linux uses


and Windows, as well as a large number of Unix variations, { $IFDEF MSWINDOWS }
Windows, Controls
including Solaris, HP-UX, and FreeBSD, to name of few. As
{ $ENDIF }
a result, CLX is being developed simultaneously for Linux and { $IFDEF LINUX }
Windows, and could possibly be ported to other Qt-supporting Types, Libc, QControls,
platforms if sufficient demand develops. As an immediately practi- { $ENDIF }
cal result, CLX is slated to be available in Delphi 6, the newest SysUtils;

Windows version of Delphi, due some time this spring. Conse-


quently, developers will have the option to build their applications The differences in supported properties between the VCL and CLX
entirely based on CLX instead of VCL, making it possible to has an additional impact. Specifically, the design-time property set-
create a single source application that can be compiled for either tings streamed to the form file are different, depending on whether
Linux or Windows. the VCL or CLX was used. Borland responded to this by giving
the form file in Kylix the .xfm file extension, as opposed to the
More about CLX .dfm extension used by Delphi. Consequently, when creating a single
Based on their functionality, the units of CLX can be logically source application that can be compiled in both Windows and Linux,
divided into four groups: BaseCLX, VisualCLX, DataCLX, and conditional compiler directives can again be used to instruct the
NetCLX. Each of these is discussed briefly in the following section. linker to use the xfm or dfm resources.

6 April 2001 Delphi Informant Magazine


First Look

Figure 2: The Kylix Object Repository.

DataCLX. DataCLX is composed of the classes and other facilities


Figure 3: The Project Options dialog box.
that permit you to create data-aware applications. There are two
parts to DataCLX. The first is a small but well-rounded collection
of data-aware controls. The DataCLX data-aware controls, like their The second set of classes in NetCLX are the WebBroker components.
VCL counterparts, require a data source component, which in turn WebBroker, which originally appeared in Delphi 3, gives you the tools
is connected to a DataCLX TDataSet descendant. Using these data- to quickly create Web server extensions. Web server extensions provide
aware controls, you can quickly build user interfaces that permit users you with a mechanism for dynamically creating the HTML that’s
to view, navigate, and edit data. returned to a Web browser, based on data provided in the HTTP
request. In this first release of Kylix, both common gateway interface
The second part of DataCLX is dbExpress. As you learned in (CGI) stand-alone executables and Apache dynamic shared object
Bill Todd’s article in the March 2001 issue of Delphi Informant (DSO) libraries are supported. (Apache DSOs are somewhat analo-
Magazine, dbExpress provides data access components and drivers gous to ISAPI/NSAPI server extensions on the Windows platform.)
that enable you to read and write databases. The components
include a connection component, which you use to access a data- The features of WebBroker found in Kylix are nearly identical
base server or engine; a SQL monitor; and a number of TDataSet to those available in Delphi. Consequently, most Web developers
descendants, which you use to select, store, and modify data. One should have little trouble converting existing Web server extensions
major feature that distinguishes dbExpress components from their to compile in Kylix.
Delphi 5 counterparts is that dbExpress components don’t rely on
the Borland Database Engine. Instead, they make use of vendor The Kylix Feature Set
libraries and special drivers that conform to an open specification Because Kylix has a new component library, it’s not surprising that the
published by Borland. Kylix feature set more closely resembles that of Delphi 1 — in terms
of number of components and wizards — than the current version of
Importantly, DataCLX data access components are TDataSet descen- Delphi. In Figure 1 you’ll notice the Component palette contains a
dants. As a result, current Delphi database developers will already relatively small number of tabs. Likewise, the Object Repository, shown
be familiar with much of the DataCLX data-related interface. Specifi- in Figure 2, has fewer tabs, as well as fewer wizards overall. Nonetheless,
cally, methods such as Open, Close, First, Next, Filter, and so forth, are many of Delphi’s advanced features have found their way into Kylix.
all found in DataCLX data access components. These include action lists, frames, Code Insight, threads, run-time and
design-time packages, and visual form inheritance (VFI).
In short, dbExpress is a lightweight, cross-platform data access layer
that provides for dynamic SQL processing using SQL queries and Other advanced features from Delphi have made their way into Kylix.
stored procedures. Alone, dbExpress produces a unidirectional cursor, For example, Kylix supports variant types, as well as interfaces. These
and does no caching of its own. However, DataCLX also comes with features were originally added to Delphi to support Microsoft COM
a TClientDataSet class, formally only available as part of MIDAS (component object model) programming. They have been carried
(Multi-tier Distributed Application Services). TClientDataSet pro- over into Kylix because they provide Object Pascal with modern
vides for all of the caching, delayed updates, and navigational capa- features to support advanced, object-oriented programming.
bilities database developers need. The result is fast, flexible, and much
easier to install than BDE-based applications. Although there are a limited number of components, Kylix does include
some features that won’t appear in Delphi until version 6 ships. These
NetCLX. NetCLX contains classes that permit you to build internet- include dbExpress and Internet Direct, a well-rounded set of networking
working applications. These classes can be divided into two groups. components that evolved from the WinShoes open source project.
The first is a small collection of socket classes that provide you
with the greatest flexibility for creating client-server applications in a Components and wizards aside, Kylix is accompanied by a set of
network environment. developer support features as complete as that found in Delphi 5. For

7 April 2001 Delphi Informant Magazine


First Look
Server Developer Desktop Developer Open Edition
Apache server application development GUI application development GPL free software development only
Oracle and IBM DB2 connectivity XML, MySQL, and InterBase GUI application development
MySQL and InterBase connectivity connectivity MySQL and InterBase connectivity
GUI application development Custom component development Custom component development
Custom component development Proprietary and GPL licensing
Proprietary and GPL licensing Available mid-2001
US$1,999 with special pricing for US$999 with special pricing for Free download / US$99 retail box
Delphi owners Delphi owners

Figure 4: Kylix will be available in three editions.

example, the integrated debugger in Kylix is almost indistinguishable which WebBroker permits developers to create Web server exten-
from that found in the Windows version. Likewise, Kylix includes sions, Kylix will immediately become one of the tools of choice for
nearly all of the configuration dialog boxes and windows supported creating dynamic, data-aware Web sites residing on Linux servers.
by Delphi 5 for configuring and examining both projects and the
development environment. For example, Figure 3 shows the Project Another group likely to be early adopters are those developers
Options dialog box, which you use to define the setting used for interested in building end-user applications for Linux desktop
compiling your applications. You display this dialog box by selecting workstations. Again, Kylix’s RAD tools and powerful support
Project | Options, just as you do in Delphi 5. for database development will make it a singularly attractive
choice for developers. Even those developers not requiring data-
Just as Delphi, Kylix will be available in multiple versions (see Figure 4). base access will benefit. Because of the ease with which you can
The initial release is expected to consist of two versions. As of press time, build GUI applications with Kylix, even mundane tasks such as
Borland was planning on naming these the Desktop Developer modifying Linux conf (configuration) files will be valid applica-
and Server Developer editions. The Desktop Developer edition will tions for Kylix development.
include tools for creating desktop applications, including database
applications. The Server Developer edition will include all of The problem with this second group of developers is that there is
the features of the Desktop Developer edition plus those for currently little need for desktop applications for Linux workstations.
creating Web server extensions, including Apache DSO extensions. Linux is used primarily for servers, and Microsoft continues to rule
A limited feature edition, called Kylix Open Edition, intended for GPL the desktop. One argument states that the lack of decent tools for
free software development only, is reportedly scheduled for release in building Linux desktop applications is to blame. Maybe so, but only
the second quarter. Please visit http://www.borland.com/kylix for the time will tell. Now that Kylix has shipped, we’re likely to see a steady
latest information. stream of new applications appear on the Linux desktop. If Kylix
itself is to be as big a hit as Borland expects, an increase in the
Who Will Use Kylix? adoption of Linux as a workstation platform must follow. ∆
The simple answer to this question is: Anyone who wants a powerful,
rapid application development (RAD) environment for building Linux
applications. This isn’t a very satisfying answer, however, because it
still leaves us wondering just who these developers are. The answer is
complicated, and you can bet that Borland is keenly aware of this. Cary Jensen is president of Jensen Data Systems, Inc., a Houston-based database
development company. Co-author of 17 books, including Oracle JDeveloper
There is one group of developers who are without a doubt going [Oracle Press, 1998], JBuilder Essentials [Osborne/McGraw-Hill, 1998], and
to be immediately interested in using Kylix. These are the Web Delphi in Depth [Osborne/McGraw-Hill, 1996], Cary is currently writing a Kylix
developers who want to be able to use Kylix’s substantial support for book to be published by Osborne/McGraw-Hill. He is a Contributing Editor of Delphi
database development to create Web server extensions for Apache. Informant Magazine, and an internationally respected trainer of Delphi and Java.
Delphi has always provided powerful support for database applica- For more information, visit http://www.jensendatasystems.com, or e-mail Cary at
tions, and Kylix continues this tradition. And given the ease with cjensen@compuserve.com.

8 April 2001 Delphi Informant Magazine


Kylix Quickstart
Linux / KDE / GNOME / X Window System

By Charlie Calvert

The Linux Desktop


X, Window Managers, Widget Sets, et cetera

I f the greatest fear of a Puritan is that somebody, somewhere, is having a good time,
then the greatest fear of a Windows programmer is that those people who are having
a good time are all using Linux. The purpose of this article is to determine just how
much fun Linux programmers are having, and whether any of us are smart enough to
figure out how to join them.

This is the first in a series of articles on Linux and pieces of software. Though not perfect, most of
Kylix. These articles are designed to get you up to these tools are at least as good as their commercial
speed on Kylix, the Linux operating system, and counterparts.
Linux culture.
Larger-than-life programmers with intriguing
Linux culture is considerably more interesting theories about the computer world often per-
than Windows culture. You have to be something form all this coding. Richard Stallman created
of a business fanatic to really care about the inter- an organization with the unlikely name of GNU,
nal politics of Microsoft. There just aren’t that dedicated to the absurd goal of creating free
many people who wake up wondering what Steve software. This is the kind of thing that college
Ballmer said on the previous day. When Microsoft sophomores try, only to give up on the project
creates a new technology, the only real excitement within six months. But Stallman started work
involves guessing what the marketing department more than 15 years ago, and his organization has
calls it today, and how long it will be until the changed the face of computing.
product finally works.
You would think Stallman is the overlord of the
On the other hand, the Linux world is full of Linux world; instead, he’s one of many figures. His
colorful characters, passionate debates, and daring friend, rival, and fellow eccentric Eric Raymond
technologies. The key figures in the Linux world often engages him in loud, passionate conflict. The
are often off on truly quixotic quests that have a friendly, reassuring, almost paternal voice of Linus
high enough probability of failure to keep us inter- Torvalds can also often be heard on the scene.
ested. In fact, it’s arguable that the whole enterprise
never should have worked. What do you mean?! All of these characters and technologies will
They corralled a group of volunteers and created an appear in this series of articles. I’ll begin with
operating system? Come on! We all know it takes the Linux desktop, which has special significance
big companies like Microsoft or IBM, and millions to Kylix programmers. Kylix is about creating
of dollars — in some cases over a billion — to GUI applications that run on the Linux desktop,
create an operating system. You can’t create one for so the logical place to begin this series is with
free. Sancho Panza could tell you that much. the desktop itself.

The somewhat disturbing facts, however, are that Understanding the Linux Desktop
Linux does exist, that it was created for free by This article explains the Linux desktop from a
volunteers, and that it actually works. The open programmer’s point of view. It’s aimed primarily
source movement has also created Web servers, at programmers new to Linux, or people who
editors, source repositories, and innumerable other have studied Linux only from a user’s, rather

9 April 2001 Delphi Informant Magazine


Kylix Quickstart
than a programmer’s, perspective. The text
focuses on the layers of the Linux desktop,
including the X Window System, window
managers, and widget sets. You’ll first see
an overview of the entire architecture, and
then an analysis of each component. The
majority of this article is dedicated to
studying X.

Linux desktops. From an architectural


point of view, the GUI application devel-
opment environment for Linux is more
complex than it is for Windows. In particu-
lar, it has three different parts:
1) X
2) The window manager
3) Toolkit or widget set

In Linux terminology, the desktop is the


most prominent part of the GUI front end.
The launch bar at the bottom of the main
window and the taskbar, which appears by
default at the top, are part of the desktop.
The broad empty space behind these items
is also part of the desktop.

The two primary competing desktops are


called KDE and GNOME. Figure 1 shows
the KDE desktop; Figure 2 shows the
GNOME desktop. Other desktops, such as
Another Level, are also popular, but not to
the same degree as KDE or GNOME.

Anatomy of a desktop. Unlike the Win-


dows desktop, the Linux desktop is not
a single, homogenous entity. It’s made up
of several parts: the X Window System,
windows managers, the toolkit or widget
set, and the desktop.

The X Window System is the part of


the GUI that allows you to go into graph-
ics mode and create windows. It handles
mouse and keyboard input, and allows you
to print text and show bitmaps. It can also
do some fancy networking tricks. However,
Figure 1 (Top): The standard look of the KDE desktop. Almost everything you see is part
X can do nothing more than these few vital
of the desktop. Figure 2 (Bottom): The standard look of a recent version of the GNOME
feats. It takes a while to grasp the restric-
desktop. Again, almost everything you see is part of the desktop.
tions in the X Window System. By itself,
X doesn’t really take you very far down the
road from text mode to a full desktop.
The desktop itself is made up of all three of the layers just men-
Window managers allow you to arrange windows on the desktop. For tioned. It adds the ability to easily launch programs from a menu,
example, the layering or tiling of windows is handled by the window and the ability to drop icons on the desktop. Most desktops, such
manager. It also paints the border around a window, adds the icons as KDE and GNOME, also come with a suite of tools for perform-
that decorate the edges of windows, and gives users the ability to ing key system tasks. For example, most desktops contain tools for
maximize or minimize a window. If you put the X Window System editing files, browsing the file system, adding and deleting users,
and a window manager together, however, you’re still only about a etc. In short, the creators of the desktop use the first three tools in
quarter of the way from text mode to a full desktop. this list to create a graphical interface for the Linux OS.

The toolkit or widget set provides the controls that are placed on It’s important to understand that each of these layers can be replaced.
windows. Buttons and listboxes are examples of tools that are part None of them are part of the operating system, and they’re all
of the widget set. designed to conform to public standards. In short, there’s more than

10 April 2001 Delphi Informant Magazine


Kylix Quickstart
one window manager, toolkit, and desktop. (Even X itself is replace- distributions use an open source implementation of X called XFree86
able, though the XFree86 implementation of the X Window System (http://www.xfree86.org). The current version of XFree86 at the time
is extremely popular, and all but ubiquitous, in the Linux world.) of this writing is 4.0.1. You can find out the version you have on your
system by typing X -showconfig at a shell prompt.
The diversity represented by the competing window managers, tool-
kits, and desktops allows users a considerable degree of choice that’s X and its name. Formally, it’s called the X Window System, and as
not available on the Windows platform. Programmers are presented you may have guessed, informally it’s X. The API that drives X is
with the source to all the pieces of the OS, and they’re free to modify called the X library, or Xlib.
them to suit their purposes. In some cases, you can even get your
changes folded back into the standard distributions of the OS itself. X windows, with a small “dubya,” are the windows created by X.
There’s no such thing as X Windows, with a capital “dubya” like they
However, there’s a price to be paid for that freedom and opportunity. use in Redmond. Microsoft Windows is a registered trademark, and
In particular, any weak link in the chain can cause problems that are it’s not considered cricket to call the X Window System something
ultimately capable of destabilizing the entire desktop. as common as X Windows. (Remember, the big dubyas belong to
Microsoft Windows and the Bush family, the little dubyas belong to
Windows is homogenous where Linux is diverse. The Windows Linux and Richard Stallman.)
GUI consists of a single entity created by the hard-working elves
in Redmond. This homogeneity helps guarantee that the Windows There have been many versions of X. The current version was created
desktop functions as a whole. At the same time, however, it robs the in September of 1987, and bears the version number 11. Thus, you’ll
environment of the richness and diversity found in Linux. sometimes see X referred to as X11. There are multiple releases of
X11, including release 5, which occurred in 1991.
Quite literally, Linux is diverse, open, full of interesting experiments,
frequently difficult, and — at times — more than a bit dangerous. What’s the X Window System? The X Window System is a piece of
Windows is closed, homogenous, restrictive, and fairly safe. Linux is software for handling the keyboard, mouse, and one or more screens.
designed to be free and flexible, and as a result it’s often difficult to Taken together, these items are called a display.
use or understand. Windows is designed to be easy to use, but you
lose freedom and flexibility along the way. X allows you to create windows shown onscreen. In this sense of the
word, a screen is not the same thing as a monitor, or a tube found in
So, Linux is dangerous and Windows is safe. The irony, of course, a monitor. In X, there can be multiple windows in one screen, and
is that when something does go wrong in Windows, the whole OS multiple screens in one display. You can have more than one monitor
can crash or become destabilized. In Linux, it doesn’t really matter attached to a single machine, and each monitor can be displaying
if the whole GUI crashes to the ground and leaves you back at different windows. In a two-monitor setup, you can move the mouse
the command prompt. Nothing will shake the core OS architecture. back and forth freely between the windows displayed on one monitor
It’s rock solid. The GUI crashes, but the servers operating in the and the windows displayed on a second monitor.
background continue running unharmed.
Displays can also be spread across a network. For example, you can
Summary of the Linux environment. Hopefully, most programmers sign on to a remote Linux machine and see its X display on your
find the Linux desktop environment to be varied, exciting, and full computer. How X interacts with networks will be discussed more in
of possibilities. Seems like a lot of windows are flung open in Linux the sections on the X client/server model and the X protocol.
that are snapped closed in Windows. Someone, somewhere, is almost
certainly pursuing a type of Linux development that you’ll find There are two kinds of displays on a typical Linux PC. One is the
attractive. Linux has an open architecture that gives you the freedom command-line display, which runs in text mode. The second kind is a
to try new ideas and get things done the way you want. Linux’s open bitmapped graphics display. X is concerned with the latter type of display,
and diverse architecture will give you the freedom to pursue your although it’s possible to run a command-line view in an X window.
interests in any way you want.
A bitmapped graphics display uses pixels to draw images onscreen. The
Kylix is designed to give you entrance into most aspects of Linux pixels are usually drawn using raster graphics. In raster graphics, a single
development. From my point of view, it’s a very exciting prospect, pixel is drawn in the upper left-hand corner of the screen, then one more
and I’ve had a great time exploring Linux and learning to leverage it. pixel to the right of it, then one more to the right of it, and so on to the
end of a line. The operation then moves back to the far left of the screen,
Now that you understand the basics of the Linux desktop, the next and draws the next line. The process continues until the bottom of the
step is to dig into the Linux environment and realize how it works. screen is reached, at which point everything begins again at the top.
I’ll begin by examining the X Window System. From there, I’ll work
my way up through the layers, back to the desktop. Typical resolutions for raster displays on computers are 640 by 480,
800 by 600, 1024 by 768, and so on. In 1024 by 768 mode, there
X Architectural Overview are 1,024 pixels in each row and 768 rows onscreen. This means that
This section describes the windowing system used on most Linux 786,432 (1,024 multiplied by 768) pixels are drawn to fill an entire
machines. Here you’ll read a definition of the X Window System, screen. Today, a typical computer will draw a screen between 60 and
see a few comments on its name, and learn about the X client/server 80 times a second.
model, the X protocol, and X toolkits.
Networks and the X-client/server model. In X there’s no identity
X was created at MIT. In March of 1988, its development was passed between an application you create and the display the user sees. The
from MIT to the X Consortium (http://www.x.org). Most Linux display of your program is handled by X. Your program is involved in

11 April 2001 Delphi Informant Magazine


Kylix Quickstart
a relationship between you, the client, and X, which is the server. As By default, the DISPLAY variable is set to :0, meaning the first
the client, your program makes a contract with X to use its services display of the local host. In this case, the hostname is implicit. You
to display graphics to the user. can find out the name of the display on your system by typing echo
$DISPLAY at the shell prompt. Or, if you prefer, you can see the entire
This concept can take a moment to grasp, so let me repeat it in a environment for your system by typing set at the shell prompt. If
slightly different way. The X Window System works on a client/server you want to scroll through the environment, type: set | less.
model. The server is X itself, while the client is your program. The
server is sometimes referred to as an X-server, while the client is called To find out many interesting facts about the current screen, type
an X-client. xdpyinfo at the command prompt. The xdpyinfo utility provides
information about the screen’s resolution, dimensions, bit depth, etc.
This is an inversion of what we would see in a normal client/server
relationship. Here, the X-server is not in the back room. Instead, The format for a server name is host:server.screen. For instance,
it’s what the user actually sees, and it’s your application that rohan:0.0 would mean that you wanted to connect to server 0 on
runs in the back room. The X-server is what the user actually the host named rohan and view screen 0. You might need to set
engages. X then passes on the events generated by the user to your information like this in the environment if you were logged on to a
program. In most cases, the connection between your app and the remote machine and wanted to run an X program there.
X-server is run over TCP/IP. In a typical scenario, the connection
is to localhost, 127.0.0.1. However, you can attach a server to a For security reasons, X will need authorization to display on another
remote host. machine. To give authorization you run the command xhost +
[remotemachine]. For instance, at the frack command prompt, type:
If you haven’t heard this before, and you’re not saying to yourself, xhost + frick.
“Wow! This is amazing!” then you either don’t get it yet, or
else you’re totally bored with computers and should find another You can run a complete desktop remotely. For this you need to run
profession. The point here is that your application can be running the naked X server with the command: X -query [remotehost], for
on one computer, and the user interface can exist on an entirely example: X -query frick.
different computer.
You can have more than one display at a time on a single machine.
The slim pipe between an X-server and X-client. The language In other words, you can run multiple X servers simultaneously. To
spoken over the TCP/IP connection between an X-server and see how to do this, let’s first have two X displays running on one
X-client is called the X protocol. As a rule, you don’t have to machine. After you learn how to do that, I’ll demonstrate how to have
understand anything about how the X protocol works any more a local X display a remote X display on the same machine.
than you have to understand how TCP/IP works. These are just
services that you can plug into automatically. Here is how to log into two local instances of the X server on a single
machine. From X, press CA2 to start a text mode console.
The information sent back and forth over the pipe from the X-server You will need to log in. Once you’re in, type the following at the
to the X-client are things like mouse and key down events. The command prompt: startx -- :1. This command tells X to run
application, in its turn, can send information back to the X-server. again, but this time on another display ID.
For example, it can request that a window be displayed, or moved
from one place to another. Now you’re ready to learn how to run a remote X desktop in addition
to your local one. Go to a free virtual screen (CAFx), just as
The X-server and X-client need not be on the same machine, so you you did in the previous example. After logging in, type the following:
could have an X-server on a Windows machine talking to an X-client X :1 -query remotehost. After a delay, you should see the login
back on a Linux machine. Or you could have three terminals of any and the desktop. I am told that this will allow you to run a Solaris
type that supports X-servers talking to a single Linux machine. desktop on a Linux box.

The problem with this system is that the pipe is small. Sending large Conclusion
chunks of data, such as bitmaps, back and forth can be expensive. As a That’s all there’s room for in this article. The next article in this series will
result, it’s best to avoid sending large chunks of data through this pipe. show you how to create an X application in Kylix using the low-level Xlib
API. The programs I’ll show you won’t use QT, but will instead write
Big chunks of data such as large bitmaps are typically loaded by the low-level X code of the kind usually seen in a C program. ∆
client, and then sent to the X-server one time. The X-server then passes
back a handle to the resource. The resource stays on the X-server, and
you manipulate it through a handle that’s kept in a device context. This
scenario should be familiar to Windows programmers.

Attaching to a Remote Server


To attach to a remote server you can telnet to a remote machine,
and then run a program. X will check an environment variable
designating which display you want to use. The variable is called
DISPLAY and it lists the hostname and its display. Suppose you have Charlie Calvert is the author of eight books, including the best-selling Delphi
two machines, called frick and frack. You telnet frick, log in, and then Unleashed series. A speaker at eight Borland conferences, Charlie has also given
enter the command: export DISPLAY=frack:0. If you now run an courses at many other sites around the globe.
X-based program it will run on frick and display on frack.

12 April 2001 Delphi Informant Magazine


Greater Delphi
User Interface Issues / Persistent User Settings

By Robert Leahey

Better UI Design
Part III: Persistent User Settings

I f it’s worth asking the user, it’s worth the program remembering. This is one of Alan
Cooper’s axioms of user interaction design, from his book, About Face: The Essentials of
User Interface Design [Hungry Minds, Inc., 1995].

For the last two months, this column has me want to scream. I’ve almost decided to write my
addressed some of the common problems of bad own, just to reclaim some productivity.
user interaction design. If the goal of user inter-
action design is to make the user more produc- The Find applet is a utility that I use probably
tive, then there are many problems we must two or three times a week. Imagine the frustration
overcome that can easily hinder achieving that of users who face this kind of incompetence all
goal. Last month we looked at the problem day, every day. How do we respond to coworkers
of excessive message dialogs and created some who can’t seem to remember how to do their tasks?
classes to address the issue. This month we What if an executive had to remind an assistant
examine the problem of lack of persistence of where to file a document every time the assistant
settings; in other words, the problem of pro- performed that simple task? Worse than these anal-
grams that don’t remember what their users have ogies, the lack of persistence shown by some soft-
done. Imbecilic programs such as this force work ware is tantamount to an employee who has to be
to be repeated — how does that promote pro- shown to his or her desk every morning.
ductivity? One need not look far to see an
example of the problem Thankfully, there are applications that display some
— the Window’s Find minor elements of awareness. Many programs’ File
applet shown in Figure 1 menus feature a recent files list, or retain the last
is a perfect example. position of their windows. However, in many cases,
this only brings to light more shortcomings: My
Since the applet’s debut wife and I have both done page layout, and we still
in Windows 95, I’ve have occasion to use our favorite page layout soft-
never used it without ware. It does remember some user preferences from
having to resize the session to session, but this feature usually serves to
window to a usable state. remind me that my wife and I use the application
In addition, the applica- in completely different ways. The single-minded
tion has no recollection nature of the settings persistence of our software
that 90 percent of the ends up being as bad as no persistence at all when
time I search some subset my wife uses the application after I have gotten
of the same limited set through with it. What we need is for the software
of directories; I must to remember both how I use it and how my wife
specify them every time. uses it.
Figure 1: 357x44? Are you kidding me? If the Find I actually go out of my
applet can’t remember how I left it, can’t it at least way to avoid using the So we have a challenge. We need to create a means
detect that I’m running my monitor at 1600x1200? utility, because it makes by which we can store and retrieve preferences and

13 April 2001 Delphi Informant Magazine


Greater Delphi
function TbuiSettingsStorage.AddSetting( Custom Solutions
aSettingClass: TbuiCustomSettingClass;
const aSettingName: string): TbuiCustomSetting; Do you read this or Cooper’s work and get the impression that
begin better interaction design involves catering to each and every indi-
if (aSettingClass <> nil) then
vidual user? That’s not the case. We’re not talking about providing
begin
if (SettingExists(aSettingName)) then custom solutions for every user — that’s simply not realistic.
Result := Settings[aSettingName] Rather, the idea is to design software that is easier to use for
else everyone. It’s possible to apply design ideas to our applications that
begin will, obviously, make it smarter, less rude, competent, and easier to
Result := aSettingClass.Create;
Result.Name := aSettingName;
use in general without customizing the code for each user.
Result.OnValueChanged := SettingUpdatedEvent;
FSettings.Add(Result); — Robert Leahey
end;
end
else § TbuiCustomSettingList (declared in buiSetting) is a descendant
Result := nil; of TbuiCustomSetting and introduces the ability to store
end;
lists of data in one setting object. This allows us to
store more complex data in a list. Example descendants of
TbuiCustomSetting = class(TObject)
TbuiCustomSettingList are TbuiFontSetting and
private TbuiRectangleSetting, declared in buiExtendedSettings.
FName: string;
FOnValueChanged: TbuiSettingUpdatedEvent; We’ll go over class implementations in a bit, but for now here’s a
procedure SetValue(aValue: Variant);
quick description of how to use the classes.
protected
procedure DoOnValueChanged(aSetting: TbuiCustomSetting);
function GetAsString: string; virtual; abstract; Setting up TbuiSettingsStorage. Our application will own and create
function GetValue: Variant; virtual; abstract; an instance of TbuiSettingsStorage. This object manages the settings
function GetValueCount: Integer; virtual; and their storage, so we tell it where to store the data by setting its
procedure InternalSetValue(aValue: Variant);
virtual; abstract;
RegistryKey property to an appropriate key in the Windows registry.
procedure SetAsString(const aValue: string); If your experience with the registry and Delphi’s TRegistry class is
virtual; abstract; limited, now might be a good time to read about them, but such
public knowledge isn’t required to use these classes. This class handles read-
constructor Create; virtual;
ing and writing to the registry for you. By convention, an appropriate
property AsString: string
read GetAsString write SetAsString; value for RegistryKey will be in the format: Software\MyCompany\
property Name: string read FName write FName; MyAppName. Software is a string literal while MyCompany and
property OnValueChanged: TbuiSettingUpdatedEvent MyAppName should be replaced with appropriate values.
read FOnValueChanged write FOnValueChanged;
property Value: Variant read GetValue write SetValue;
property ValueCount: Integer read GetValueCount;
To do something with the data retrieved by TbuiSettingsStorage, we
end; need to implement an event handler for its AfterSettingsRetrieved
event. This event will fire each time the object retrieves its settings
from the registry; this happens when the current user changes or
Figure 2 (Top): The implementation of AddSetting. when we call RetrieveSettings. If we update our application’s settings,
Figure 3 (Bottom): TbuiCustomSetting declaration. such as form position, when this event fires, we’ll be able to customize
the application for our current user.
settings, thus achieving a state where we need not ask a user to
specify his or her desires more than once, and we need to be able to Adding Settings. To add a setting to the SettingsStorage object, we call
catalog and restore these settings by user (so my settings don’t annoy TbuiSettingsStorage.AddSetting. We pass in a class of the type of setting
my wife). Additionally, we need to make this process simple for the we want (e.g. if we want to store a string, we pass in TbuiStringSetting)
programmer, so that storing a setting is fairly automated. and a name for the new setting. AddSetting takes care of creating
a setting of the type we indicated, names it, and passes it back as
Having established our requirements, let’s examine some classes that I a TbuiCustomSetting. If a setting of the given name already exists,
propose as a starting point for better persistence of user settings. TbuiSettingsStorage returns the existing object rather than creating a
new one. Because AddSetting returns a TbuiCustomSetting, we need to
Classes Overview typecast the result to use it in the manner we expect. Here’s an example:
I’ve adopted the prefix of “bui” for “Better UI” for the code presented
in this series of articles. The following classes make up our settings procedure TForm1.StoreBooleanSetting(
persistence system: const aSettingName: string; aValue: Boolean);

§ TbuiSettingsStorage (declared in buiSettingsStorage) is the man- var


lBoolSetting: TbuiBooleanSetting;
ager of our settings. This class knows how, where, and when — begin
but not what — to store and retrieve. { Call AddSetting to create new TbuiCustomSetting,
§ TbuiCustomSetting (declared in buiSetting) is the base class for a set but typecast result as TbuiBooleanSetting. }
of classes, which represent specific settings we wish to store. Objects lBoolSetting := TbuiBooleanSetting(FSettingsStorage.
AddSetting(TbuiBooleanSetting, aSettingName);
of these types will provide the “what” to store. Some example { Now that we have the setting, we set its value. }
descendants of TbuiCustomSetting are declared in buiSetting; they lBoolSetting.Value := Variant(aValue);
are TbuiBooleanSetting, TbuiIntegerSetting, and TbuiStringSetting. end;

14 April 2001 Delphi Informant Magazine


Greater Delphi
In this example, FSettingsStorage is a private field that contains our § RegistryKey, finally, is the string value of the key in the registry in
SettingsStorage object. By calling AddSetting, the newly created set- which you wish to store settings. The RootKey property defaults
ting object is added to FSettingsStorage and its data is gathered and to HKEY_CURRENT_USER so the value of RegistryKey can
stored each time FSettingsStorage stores the data to the registry. simply be a subkey, such as Software\MyCompany\MyAppName.
For this reason, you should take care not to free settings that you
create by calling AddSetting. They are freed by the SettingsStorage Next, we will look at the public members of TbuiSettingsStorage; first
object. the properties:
§ Users is an indexed property containing the names of users
Restoring Settings. Retrieving settings that have been stored by the that have been added to this object. When settings are
SettingsStorage object is as simple as creating them. TbuiSettingsStorage stored for a given user, they are stored in a subkey of
maintains a list of the settings objects it owns in its indexed Settings RegistryKey as \RegistryKey\UserName\SettingName. Thus,
property. We can access the objects via this property to find out what when the SettingsStorage object needs to retrieve a list of users,
their current value is. Here’s an example: it enumerates the subkeys of RegistryKey.
§ The Settings property is a listing of all settings currently owned by
procedure TForm1.RestoreInitialDirSetting; the SettingsStorage object.
var § RootKey is an HKEY and corresponds directly to the RootKey of
lStringSetting: TbuiStringSetting;
the Windows registry where TbuiSettingsStorage should store its
begin
{ Access the Settings property, data. RootKey defaults to HKEY_CURRENT_USER.
typecasting it as TbuiStringSetting. } § Set the CurrentUserIndex to specify a new user. Commonly, when
lStringSetting := TbuiStringSetting( setting CurrentUserIndex, you should call StoreSettings before and
FSettingsStorage.Settings['LastDirectory']); RetrieveSettings after. This way you can store and retrieve settings
{ Now that we have the setting, access its value. }
OpenDialog1.InitialDir := lStringSetting.AsString;
for particular users.
end;
The public methods of TbuiSettingsStorage are as follows:
You can see that using these classes is fairly simple. New classes can be AddSetting is the method you can call to add a new setting object
defined to handle more complex settings (we’ll discuss TbuiFontSetting to TbuiSettingsStorage. Note that AddSetting expects a
later). Once you understand the architecture, you’ll be able to create TbuiCustomSettingClass as a parameter. Basically you’re telling your
settings classes to handle just about any data. SettingsStorage object that you want it to create a new setting of type
aSettingClass, it should be named aSettingName, and you want it
Storing and Retrieving Data. While the SettingsStorage object is returned to you. Figure 2 shows the implementation of AddSetting.
maintaining a list of settings, this list means nothing unless we
actually store those values to the registry and retrieve them again. Note that if a setting with the given name already exists, it is returned
For this we use TbuiSettingsStorage’s methods, StoreSettings and instead of a new setting. This saves you from checking for its existence
RetrieveSettings. Typically, you might call StoreSettings when the when adding the setting. If a new setting is created, it’s created as
application is closing or as a new user logs on. Likewise, you could the given class, its name is set, and it’s added to the FSettings list (a
call RetrieveSettings when you start your application, or after a new TClassList object). In addition, its OnValueChanged event is assigned to
user is logged on. the SettingUpdatedEvent. This method in turn fires TbuiSettingsStorage’s
OnSettingUpdated event. AddSetting returns a TbuiCustomSetting.
Class Implementations
Listing One (on page 19) is a partial code listing of the classes just AddUser, DeleteUser, and RemoveUser allow you to manipulate the user
described, showing the declaration of TbuiSettingsStorage as it appears list of the SettingsStorage object, while GetUserList will cause the object
in the buiSettingsStorage unit. To examine the full implementation, to refresh its list of users from the registry. SetUserByName allows you to
check out the accompanying demonstration project (the source code is set the current user by name, rather than by setting CurrentUserIndex.
available for download; see end of article for details).
TbuiSettingsStorage is designed to only create instances of settings for
While there isn’t room to discuss all the members of this class, we’ll whom their class type has been registered with the SettingsStorage
try to gain a working knowledge of its purpose. That, combined with object. To register a setting class, call RegisterSettingClass. This must
the source code, should be enough for you to begin using these classes be done before attempting to add any settings of the class. Likewise,
in your applications. to unregister a class call UnregisterSettingClass.

Let’s begin our examination with the published members: The SettingExists method allows you to check for the existence of a
§ As noted before, AfterSettingsRetrieved is an event that fires when setting by name.
TbuiSettingsStorage has retrieved values from the registry. You
should implement an event handler for this event to update your The key methods of TbuiSettingsStorage are RetrieveSettings,
application settings when new values are available. StoreSettings, and StoreSetting. RetrieveSettings will cause
§ BeforeSettingsStored is an event that fires just before values are TbuiSettingsStorage to get the current value of all stored settings for
stored in the registry. If you implement an event handler for the current user. Likewise, StoreSettings will cause all settings to be
BeforeSettingsStored, you can abort the storage process by setting stored. The StoreSetting method allows you to force a single setting
aAllow to False. to be stored to the registry.
§ The OnSettingUpdated event fires any time one of
TbuiSettingsStorage’s owned TbuiCustomSetting objects’ value The remaining protected and private members can be examined in
is changed. You can implement this event if you want to take the source code, but the preceding overview should give you a good
special action when a specific setting is changed. idea of how to put this class to use.

15 April 2001 Delphi Informant Magazine


Greater Delphi

TbuiBooleanSetting = class(TbuiCustomSetting) be unique, but this is not managed by TbuiCustomSetting; rather


private TbuiSettingsStorage will not allow two settings to be added with
FValue: Boolean; the same name.
protected
function GetAsString: string; override;
function GetValue: Variant; override;
OnValueChanged is an event that will fire any time the Value of the
procedure InternalSetValue(aValue: Variant); override; setting object changes. Note that OnValueChanged should remain
procedure SetAsString(const aValue: string); override; unassigned, as TbuiSettingsStorage will reassign OnValueChanged
public when it creates a new instance of TbuiCustomSetting.
constructor Create; override;
end;
The ValueCount property is introduced, in part, to support descen-
dant classes like TbuiCustomSettingList that may store more than one
value. ValueCount for TbuiCustomSetting returns a value of 1 via
constructor TbuiBooleanSetting.Create; GetValueCount. Make sure you override GetValueCount if you create
begin
a new setting class that stores multiple values. If you descend from
inherited Create;
FValue := False;
TbuiCustomSettingList, this is implemented for you.
end;
When you create custom descendants of TbuiCustomSetting, make
function TbuiBooleanSetting.GetAsString: string; sure you implement the abstract methods, GetAsString, GetValue,
begin
if (FValue) then
InternalSetValue, and SetAsString. Since TbuiCustomSetting has no
Result := 'True' built-in ability to store the value it’s given, your descendant must
else provide the ability to store the value. An example of TbuiBooleanSetting
Result := 'False'; is shown in Figure 4.
end;

function TbuiBooleanSetting.GetValue: Variant;


Notice that this class implements a simple Boolean field, FValue,
begin as its means to store its value. This is common to most simple
Result := Variant(FValue); value storage classes. You should be able to simply declare a field
end; to store the value, then implement the four abstract methods previ-
procedure TbuiBooleanSetting.InternalSetValue(
ously mentioned to read and write to it. Figure 5 shows the entire
aValue: Variant); implementation of TbuiBooleanSetting so you can see more clearly the
begin use of these methods.
FValue := Boolean(aValue);
end;
This is one of the simplest implementations of TbuiCustomSetting.
procedure TbuiBooleanSetting.SetAsString(
Notice that when we get or set the value of AsString (via GetAsString
const aValue: string); and SetAsString) we’re simply using string representations of the value.
begin For GetValue and InternalSetValue, we’re converting FValue to and
if (Uppercase(aValue) = 'TRUE') then from a Variant.
Value := Variant(True)
else
Value := Variant(False); Why do we implement InternalSetValue instead of SetValue? This
end; is because TbuiCustomSetting.SetValue calls DoOnValueChanged to
fire the OnValueChanged event, and then calls InternalSetValue
to execute our code there. We could have simply made SetValue
Figure 4 (Top): TbuiBooleanSetting declaration.
Figure 5 (Bottom): Implementing TbuiBooleanSetting.
virtual and overridden that, but using the abstract InternalSetValue
method forces us to implement the method — a safer way to
go since our descendants are useless without some value-setting
implementation.
Now we’ll have a look at the various settings classes.
And why is SetAsString setting Value instead of FValue. This answer
TbuiCustomSetting. TbuiCustomSetting is an abstract base class is related to the last one. By setting Value, we cause SetValue
intended to be extended. All functional setting classes should be to be called, which in turn fires the OnValueChanged event. If
descendants, even for simple values like Boolean. To realize the full SetAsString set FValue instead, it would be possible to set the value
power of this system, you can design your own custom setting classes of TbuiBooleanSetting.AsString and never cause the OnValueChanged
like TbuiFontSetting to handle more complex types of data, but you event to fire. Keep that in mind when implementing complex
can still accomplish a great deal with just the classes we’ll cover here. SetAsString methods. If you aren’t setting Value, you may need to call
Figure 3 shows the definition of TbuiCustomSetting as it appears in DoOnValueChanged yourself.
the buiSetting unit.
TbuiIntegerSetting and TbuiStringSetting are largely similar to
As you can see, TbuiCustomSetting offers two methods for accessing TbuiBooleanSetting so we won’t examine them here. We’ll move
data: as a Variant or via the AsString property. This means that your on instead to the more sophisticated TbuiCustomSettingList and
descendant classes can either use Variants, or override GetAsString and descendants.
SetAsString to manipulate a string value.
TbuiCustomSettingList. Storing simple values is great, but sometimes
Name is the name of the setting object, and will be used to we need to be able to store more complex data. Take a font, for
access the setting within TbuiSettingsStorage objects. Name must instance. While it would be possible to store all its information as

16 April 2001 Delphi Informant Magazine


Greater Delphi

TbuiCustomSettingList = class(TbuiCustomSetting) TbuiValueSetting = class(TObject)


private private
FValues: TObjectList; FValue: Variant;
function GetValueAsString(const aValueName: string): FValueName: string;
string; protected
function GetValueByName(const aName: string): function GetValueAsString: string; virtual;
TbuiValueSetting; procedure SetValueAsString(const aValue: string);
function GetValueNames(aIndex: Integer): string; virtual;
function GetValues(const aValueName: string): Variant; public
procedure SetValueAsString(const aValueName: string; property Value: Variant read FValue write FValue;
const aValue: string); property ValueAsString: string
procedure SetValueNames(aIndex: Integer; read GetValueAsString write SetValueAsString;
const aValueName: string); property ValueName: string
procedure SetValues(const aValueName: string; read FValueName write FValueName;
aValue: Variant); end;
protected
function GetAsString: string; override;
function GetValue: Variant; override; Figure 7: TbuiValueSetting declaration.
function GetValueCount: Integer; override;
procedure InternalSetValue(aValue: Variant); override;
procedure SetAsString(const aValue: string); override;
That’s all there is to it. To use this setting class, send it a font value
public
constructor Create; override; you want to store via SetFont, or retrieve a font via GetValues. Note that
destructor Destroy; override; in the constructor, we initialize our value list by calling AddValue for
function AddValue(const aName: string; aValue: Variant): each value we want stored. In GetValues, the method we call to restore a
Integer; virtual; font from the values in the registry, we take the TFont object that’s been
procedure DeleteValue(aIndex: Integer); virtual;
function IndexOf(const aValueName: string): Integer;
passed in, and set its properties according to the values in our value list.
procedure RemoveValue(const aValueName: string); virtual; Likewise, in SetFont, the method we call to store a font to the registry,
function ValueExists(const aValueName: string): Boolean; we take the TFont object that’s passed in, and set our values from its
property ValueAsString[const aValueName: string]: string properties. If you follow this model for your own SettingList classes, you
read GetValueAsString write SetValueAsString;
can easily store complex information using this system.
property ValueNames[aIndex: Integer]: string
read GetValueNames write SetValueNames;
property Values[const aValueName: string]: Variant A Quick Recap
read GetValues write SetValues; We’ve covered a lot of ground and a lot of code, so let’s regroup a
end; bit. What are we doing here? We’re creating a system to allow you
to store all kinds of information about how individual users use your
Figure 6: TbuiCustomSettingList declaration. application. We want to be able to use the system with a minimum of
effort so it’s somewhat automated.
multiple settings, it’d be nice to be able to store it all in one opera-
tion. This is where TbuiCustomSettingList comes in. Its declaration is The main class, TbuiSettingsStorage, manages a list of TbuiCustomSetting
shown in Figure 6. descendants, storing their values to the Windows registry and retrieving
them when requested. This allows you to read these values and restore
Basically, TbuiCustomSettingList is designed to store a set of values in your application to previous states. By creating custom descendants
a list by name, yet still be able to present itself to TbuiSettingsStorage of TbuiCustomSetting and TbuiCustomSettingList, you can create your
as a TbuiCustomSetting descendant. To do this, TbuiCustomSettingList setting classes to store custom data.
stores instances of TbuiValueSetting; a simple class designed to hold a
value and have a name, as shown in Figure 7. What does this gain you? Happier users. There are few things more frus-
trating in the computer world than an application that can’t remember
By using TbuiCustomSettingList’s Values property, you can add what it’s been told. By using this system, you can provide your users
various values to the list that will all be stored to the with a smarter application that remembers how they like to use it.
registry when TbuiSettingsStorage streams all its owned settings.
TbuiCustomSettingList knows how to retrieve these values by name, Counting the Cost of Better UI Design
so in your descendant classes, you can reconstruct whatever complex As we’ve seen in the past installments of this series, better user interac-
data you’re trying to store. Perhaps the best way to explain this class tion design isn’t attained for free. The work required to make an appli-
is to examine a descendant, TbuiFontSetting. Here is its declaration: cation smarter and easier to use is often significant, and is definitely
something to be considered when starting a project. However, decid-
TbuiFontSetting = class(TbuiCustomSettingList) ing not to do the work has its own penalties, as maintaining the status
public quo can result in unhappy users who buy other products.
constructor Create; override;
procedure GetValues(aFont: TFont); virtual;
procedure SetFont(aFont: TFont); virtual; In the case of settings persistence, however, the cost is fairly minimal.
end; Implementing these classes will take very little effort and your appli-
cations will be much better for it.

Seems simple enough. Well, most of the work is done in Where Do We Go from Here?
TbuiCustomSettingList, so creating your own descendants will be This user setting persistence system is incomplete. Yes, it will store
rather painless. You can see the implementation in Listing Two our settings quite ably for us, giving our applications some long-
(on page 19). term memory, but it lacks real smarts. What this system needs is

17 April 2001 Delphi Informant Magazine


Greater Delphi
artificial intelligence, and you’re just the developer to provide it.
Two things that could be used to improve this system are Smart
Persistence and Discernment.

By Smart Persistence, I mean the ability to track a user’s past choices


and determine by probability what they want. For instance, let’s
say I’m designing a page layout. The last 42 times I’ve formatted a
headline I’ve used Arial, 16 point for the font. But just once, most
recently, I’ve formatted a headline using Garamond Bold, 14 point.
What font am I probably going to want to use next time? Dumb
persistence will say it’s the Garamond font, but a more intelligent
system will see that I’ve selected Arial nine times out of the last 10,
and will therefore suggest Arial.

Discernment, on the other hand, will figure out what your users
like by their actions. Every time I select Draw Table in Microsoft
Word, I’m thrown into Page Layout view, which I don’t like. Every
time that happens, I immediately switch back to Normal view.
I’d like it if the software were smart enough to see that I don’t
like that “feature” and would stop invoking it. Microsoft hasn’t
done that, but with a little effort — and these classes — you
could build your applications to detect things like that, adapt the
application’s behavior, and your users will be happy they bought
your software.

Conclusion
While this is the third and final installment of this series, the
series isn’t done. There’s always more we could talk about to
improve the user interaction design of our software. If you like
what you’ve read here, make sure you read Alan Cooper, Donald
Norman, and Edward R. Tufte (for suggested reading see the first
installment of this article series in the February 2001 issue of
Delphi Informant Magazine). If you’re really interested, push the
cause of interaction design. Build in better interaction from the
beginning of a project. Create a position on your team for an
Interaction Designer (look for a usability expert rather than a
programmer). Make better software. ∆

The files referenced in this article are available on the Delphi


Informant Magazine Complete Works CD located in INFORM\2001\
APR\DI200104RL.

Robert is Director of Product Management - ReportBuilder for Digital Metaphors


Corp. He graduated with a degree in Music Theory from the University of North
Texas, but has been writing code since his Apple II+ and AppleBasic days. He has
been programming in Object Pascal since Delphi 1 and currently resides in Texas
with his wife and daughters.

18 April 2001 Delphi Informant Magazine


Greater Delphi

Begin Listing One — TbuiSettingsStorage declaration end;


read FRegistryKey write FRegistryKey;

TbuiSettingsStorage = class(TComponent)
private End Listing One
FAfterSettingsRetrieved: TbuiNotifyEvent;
FBeforeSettingsStored: TbuiAllowActionEvent;
FCurrentUserIndex: Integer; Begin Listing Two — TbuiFontSetting implementation
FOnSettingUpdated: TbuiSettingUpdatedEvent;
const
FRegisteredSettingClasses: TClassList;
csFontName = 'FontName';
FRegistry: TRegistry;
csFontSize = 'FontSize';
FRegistryKey: string;
csFontBold = 'FontBold';
FSettings: TObjectList;
csFontItalic = 'FontItalic';
FUsers: TStrings;
csFontUnder = 'FontUnder';
procedure ClearSettings;
csFontColor = 'FontColor';
function GetRootKey: HKEY;
function GetSettingByName(const aName: string):
constructor TbuiFontSetting.Create;
TbuiCustomSetting;
begin
function GetSettings(const aName: string):
inherited Create;
TbuiCustomSetting;
AddValue(csFontName, Variant('Arial'));
function GetUsers(aIndex: Integer): string;
AddValue(csFontSize, Variant(10));
procedure RetrieveUsers;
AddValue(csFontBold, Variant(False));
procedure SetCurrentUserIndex(aValue: Integer);
AddValue(csFontItalic, Variant(False));
procedure SetRootKey(aValue: HKEY);
AddValue(csFontUnder, Variant(False));
procedure SetSettings(const aName: string;
AddValue(csFontColor, Variant(clBlack));
aValue: TbuiCustomSetting);
end;
procedure StoreUsers;
protected
procedure TbuiFontSetting.GetValues(aFont: TFont);
function CreateSettingByName(const aClassName: string):
begin
TbuiCustomSetting; virtual;
aFont.Name := string(Values[csFontName]);
procedure DoAfterSettingsRetrieved(Sender: TObject);
aFont.Size := Integer(Values[csFontSize]);
procedure DoBeforeSettingsStored(Sender: TObject;
aFont.Color := TColor(Values[csFontColor]);
var aAllow: Boolean);
if (Boolean(Values[csFontBold])) then
procedure DoOnSettingUpdated(
aFont.Style := aFont.Style + [fsBold];
aSetting: TbuiCustomSetting);
if (Boolean(Values[csFontItalic])) then
procedure PopulateSetting(aSetting: TbuiCustomSetting;
aFont.Style := aFont.Style + [fsItalic];
const aSettingName: string); virtual;
if (Boolean(Values[csFontUnder])) then
procedure SettingUpdatedEvent(
aFont.Style := aFont.Style + [fsUnderline];
aSetting: TbuiCustomSetting); virtual;
end;
public
constructor Create(AOwner: TComponent); override;
procedure TbuiFontSetting.SetFont(aFont: TFont);
destructor Destroy; override;
begin
function AddSetting(
Values[csFontName] := Variant(aFont.Name);
aSettingClass: TbuiCustomSettingClass;
Values[csFontSize] := Variant(aFont.Size);
const aSettingName: string): TbuiCustomSetting;
Values[csFontColor] := Variant(aFont.Color);
virtual;
if (fsBold in aFont.Style) then
procedure AddUser(const aUserName: string); virtual;
Values[csFontBold] := Variant(True)
procedure DeleteUser(aIndex: Integer); virtual;
else
procedure GetUserList(aList: TStrings); virtual;
Values[csFontBold] := Variant(False);
procedure RegisterSettingClass(
if (fsItalic in aFont.Style) then
aSettingClass: TbuiCustomSettingClass); virtual;
Values[csFontItalic] := Variant(True)
procedure RemoveUser(const aUserName: string); virtual;
else
procedure RetrieveSettings; virtual;
Values[csFontItalic] := Variant(False);
function SettingExists(const aSettingName: string):
if (fsUnderline in aFont.Style) then
Boolean; virtual;
Values[csFontUnder] := Variant(True)
procedure SetUserByName(const aName: string); virtual;
else
procedure StoreSetting(aSetting: TbuiCustomSetting);
Values[csFontUnder] := Variant(False);
virtual;
end;
procedure StoreSettings; virtual;
procedure UnregisterSettingClass( End Listing Two
aSettingClass: TbuiCustomSettingClass); virtual;
property CurrentUserIndex: Integer
read FCurrentUserIndex write SetCurrentUserIndex;
property RootKey: HKEY read GetRootKey write SetRootKey;
property Settings[const aName: string]: TbuiCustomSetting
read GetSettings write SetSettings;
property Users[aIndex: Integer]: string read GetUsers;
published
property AfterSettingsRetrieved: TbuiNotifyEvent
read FAfterSettingsRetrieved
write FAfterSettingsRetrieved;
property BeforeSettingsStored: TbuiAllowActionEvent
read FBeforeSettingsStored write FBeforeSettingsStored;
property OnSettingUpdated: TbuiSettingUpdatedEvent
read FOnSettingUpdated write FOnSettingUpdated;
property RegistryKey: string

19 April 2001 Delphi Informant Magazine


Informant Spotlight

By David Riggs

Decision 2001
Delphi Informant Magazine Readers Choice Awards

N o chads. No dimples. No butterfly ballots. You voted, we tallied. There were no


lawsuits, no recounts. We even eschewed the hand count in favor of our automated
system. Go figure — a system that works, in this day and age.

A benefit to all involved, this year marks the first aid of the Supreme Court, lobbyists, or manual
time we’ve conducted the Delphi Informant Mag- recounts.
azine readers choice balloting completely online.
There were no physical ballot boxes to “mis- Reflecting the spirit of its audience, the Delphi
place” or stuff (not that some of you didn’t try third-party market is ever changing, reacting to
— you know who you are). With the ease of myriad influences in the industry. This year’s ballot
voting quickly and conveniently on the Web, reflects those changes with new products and new
there was no electoral dysfunction, no premature categories. The result is an interesting mix of old
congratulations from any of the runners-up. and new, and exhibits an exciting dynamic that
Put simply, we know who won without the we’ve come to expect in the Delphi community.

DECISION 2 0 0 1

Best Accounting Package


What better way to kick off tallying the Delphi BEST ACCOUNTING PACKAGE
Informant Magazine Readers Choice Awards PRODUCT COMPANY %
Accounting for Delphi ColumbuSoft 39
than with your choice for best accounting
package? After tying for second place last year, BS/1 Professional Davis Business Systems 21
Accounting for Delphi by ColumbuSoft is the Bravo Bravosoft 19
first winner in this year’s balloting, garnering AdaptAccounts Adapta Software 17
39 percent of the popular vote. A very respect- Other 4
able second place went to newcomer BS/1 Source: www.DelphiZine.com
Professional by Davis Business Systems, which
received 21 percent of the votes.

DECISION 2 0 0 1

Best Add-in
BEST ADD-IN
Replicating last year’s results, CodeRush PRODUCT COMPANY %
from Eagle Software attained top honors CodeRush Eagle Software 52
with 52 percent of the votes, while Multi- Multi-Edit American Cybernetics 17
Edit from American Cybernetics took Other 31
second with 17 percent. There seems to be Source: www.DelphiZine.com
a trend here.

20 April 2001 Delphi Informant Magazine


Informant Spotlight

Best Book Best Database Connectivity


It was a slow year for Delphi books; only four were published Duplicating last year’s results, this category was again won by
since last year’s Awards. With 43 percent of the votes, you placed IB Objects from Jason Wharton, with 27 percent of the votes,
Delphi in a Nutshell by the venerable Ray Lischner (O’Reilly & followed by ASTA Technology Group’s ASTA, with 20 percent.
Assoc.) at the top of the stack. Second was Delphi COM by These two perennial favorites are establishing quite a rivalry. Can
Eric Harmon (Macmillan) with 35 percent. Let’s hope that 2001 ASTA turn it up a notch in the coming year to get that last little
brings far more titles. boost it needs to grab top honors?

DECISION 2 0 0 1

DECISION 2 0 0 1

BEST BOOK
PRODUCT COMPANY % BEST DATABASE CONNECTIVITY
Delphi in a Nutshell Ray Lischner, O’Reilly & Associates 43 PRODUCT COMPANY %
Delphi COM Eric Harmon, Macmillan 35 IB Objects Jason Wharton 27
Advanced Delphi Alex Fedorov and Natalia Elmanova, 18 ASTA ASTA Technology Group 20
Developer’s Guide Wordware Direct Oracle Access Component Set Allround Automations 13
Learn Object Pascal with Delphi Warren Rachele, Wordware 4 Other 40
Source: www.DelphiZine.com Source: www.DelphiZine.com

Best Charting/Mapping Tool Best Database Engine

Blazing a trail for the second consecutive year, teeChartPro from Coming off a third-place finish last year, Advantage Database Server
Steema Software took top honors. A perennial favorite (they also from Extended Systems grabbed 28 percent of the votes to win top
won this category in 1999 when it was Best Charting/Imaging Tool), honors. Improving on last year’s fourth-place finish, and coming in
teeChartPro was again the runaway winner on 65 percent of the a close second with 25 percent of the votes, was DBISAM Database
ballots cast. Making a respectable second-place showing in its debut System from Elevate Software. The competition in this category is
on the ballot was ExpressOrgChart Suite from Developer Express stiff, so these two companies obviously did something right to post
with 16 percent of the votes. that much improvement.

DECISION 2 0 0 1

BEST DATABASE ENGINE


DECISION 2 0 0 1

PRODUCT COMPANY %
BEST CHARTING/MAPPING TOOL Advantage Database Server Extended Systems 28
PRODUCT COMPANY % DBISAM Database System Elevate Software 25
teeChartPro Steema Software 65 FlashFiler TurboPower Software 23
ExpressOrgChart Suite Developer Express 16 Apollo Vista Software 11
Other 19 Other 13
Source: www.DelphiZine.com Source: www.DelphiZine.com

Best Communications Tool Best Database Tool

Leading the way by exhibiting consistency, Async Professional For the second consecutive year, top honors for best database
by TurboPower Software certainly is the communications tool to tool go to InfoPower from Woll2Woll Software. InfoPower
beat. Making a statement with a comfortable 56 percent of the decisively collected 49 percent of the votes in this competitive
votes, Async Professional wins this category for the third year run- category. An impressive second place goes to ballot newcomer,
ning (this is the second year on the ballot for this category in this ExpressDBTree Suite from Developer Express, which took 18
permutation; three years ago it was known as Best Connectivity percent of your votes.
Tool). With 28 percent of the votes, a surprise second place goes
to Indy by Chad Z. Hower. This newcomer is sending a message:
No lead is safe.

DECISION 2 0 0 1

DECISION 2 0 0 1

BEST DATABASE TOOL


BEST COMMUNICATIONS TOOL PRODUCT COMPANY %
PRODUCT COMPANY % InfoPower Woll2Woll Software 49
Async Professional TurboPower Software 56 ExpressDBTree Suite Developer Express 18
Indy Chad Z. Hower 28 Rubicon Full Text Search Tamarack Associates 12
Other 16 Other 21
Source: www.DelphiZine.com Source: www.DelphiZine.com

21 April 2001 Delphi Informant Magazine


Informant Spotlight

Best Globalization Tool Best Installation Package


It’s certainly a small world — and getting smaller all the time. To stay
competitive in today’s international market requires globalization soft- A challenge will often bring out the best. That seems to be
ware. Recognizing this trend, this year marks the first Award for Best the case in this category; moving up from second place in last
Globalization Tool. By grabbing 45 percent of the votes, the inaugural year’s competition, InstallShield Express from InstallShield Soft-
award goes to MULTILIZER VCL Edition by MULTILIZER Ltd. ware received 40 percent of your votes to take the top prize. Wise
Fittingly, the company is itself international, headquartered in Espoo for Windows Installer from Wise Solutions came in a close second
(“Wireless Finland”), with partners in 14 countries. Second place goes with 35 percent of the votes.
to MultLang Suite from Europe-based Lingscape, with 22 percent of
the votes.

DECISION 2 0 0 1 DECISION 2 0 0 1
™ ™

BEST GLOBALIZATION TOOL BEST INSTALLATION PACKAGE


PRODUCT COMPANY % PRODUCT COMPANY %
MULTILIZER VCL Edition MULTILIZER Ltd. 45 InstallShield Express InstallShield Software 40
MultLang Suite Lingscape 22 Wise for Windows Installer Wise Solutions 35
TsiLand Components Suite SiComponents 16 Inno Setup Jordan Russell’s Software 15
Other 17 Other 10
Source: www.DelphiZine.com Source: www.DelphiZine.com

Best Help-authoring Package Best Library

Needing no assistance, HelpScribble from JGSoft collected 31 per- There are no secrets when it comes to your choice for best library:
cent of the votes to win this category for the third straight year. Also SysTools from TurboPower has won for the second consecutive
three-peating, in second place, was RoboHELP Office from eHelp, year. SysTools ran away with 53 percent of the votes, followed
with 23 percent of the votes. The consistent quality exhibited by by ExpressBars Suite from Developer Express, which garnered
these two products shows why they are your perennial favorites. 31 percent.

DECISION 2 0 0 1

BEST HELP-AUTHORING PACKAGE


DECISION 2 0 0 1

PRODUCT COMPANY %
HelpScribble JGsoft 31 BEST LIBRARY
RoboHELP Office eHelp Corp. 23 PRODUCT COMPANY %
Help & Manual EC Software 14 SysTools TurboPower Software 53
ForeHelp ForeFront, Inc. 12 ExpressBars Suite Developer Express 31
Other 20 Other 16
Source: www.DelphiZine.com Source: www.DelphiZine.com

Best Imaging Tool Best Modeling/CASE Tool

Not liking the view from behind, ImageLib Corporate Suite from This is the second year for this category on our ballot, and it marks
SkyLine Tools Imaging pulled up from a respectable second-place the first appearance for both the winner and runner-up. In a close
finish in last year’s balloting to capture this year’s top prize with contest, ModelMaker from ModelMaker used its 27 percent of the
33 percent of the votes. Improving on last year’s third-place finish, votes to edge the 22 percent attained by Rational Rose from Rational
LEADTOOLS Imaging Toolkit from LEAD Technologies got 29 Software. In a wide-open field, these newcomers made a strong show-
percent of the votes to grab second. This is a good example of two ing. Only the next year will determine if they have what it takes to
companies improving their products to better serve their clients. maintain the excellence they have achieved this year.

DECISION 2 0 0 1 DECISION 2 0 0 1
™ ™

BEST IMAGING TOOL BEST MODELING/CASE TOOL


PRODUCT COMPANY % PRODUCT COMPANY %
ImageLib Corporate Suite SkyLine Tools Imaging 33 ModelMaker ModelMaker 27
LEADTOOLS Imaging Toolkit LEAD Technologies 29 Rational Rose Rational Software 22
Envision Image Library Interval Software 12 CDK Eagle Software 16
Other 26 Other 35
Source: www.DelphiZine.com Source: www.DelphiZine.com

22 April 2001 Delphi Informant Magazine


Informant Spotlight

Best Reporting Tool Best Utility


If only the California power companies were as reliable as all the
Overwhelming the competition (again!) with 57 percent of the votes, Delphi utilities. This category was well represented, and many of
ReportBuilder from Digital Metaphors is your choice as best report- the entrants were in the showing. But in the end it was OnGuard
ing tool. But the results were too close to call for — an albeit distant by TurboPower Software that won, with 31 percent of the votes.
— second place. ReportPrinter Pro from Nevrona Designs repeats ASPack by ASPack Software came in second, with 24 percent. Both
its second place finish of last year, joined by FastReport courtesy of newcomers are to be commended.
Russia’s Alexander Tzyganenko, each with 12 percent of the vote.

DECISION 2 0 0 1

BEST UTILITY
DECISION 2 0 0 1

PRODUCT COMPANY %
BEST REPORTING TOOL OnGuard TurboPower Software 31
PRODUCT COMPANY % ASPack ASPack Software 24
ReportBuilder Digital Metaphors 57
VCLZip KpGb 13
ReportPrinter Pro Nevrona Designs 12
Other 32
FastReport Alexander Tzyganenko 12 Source: www.DelphiZine.com
Other 19
Source: www.DelphiZine.com

Best VCL Component


Best Testing/Debugging Tool
Riding the wave of last year’s closest race, ExpressQuantumGrid from
It’s always best if you find your mistakes before your users do. This Developer Express improved on last year’s second-place finish by
is the second year on the ballot for this category, and nothing much taking 35 percent of the votes. In second with 16 percent was last
has changed. Sleuth QA Suite from TurboPower and CodeSite from year’s winner, Abbrevia from TurboPower Software. These see-saw
Raize Software finished one-two, with 45 and 23 percent of the votes, results have the makings of a great rivalry.
respectively. Shall we go for three in a row?

DECISION 2 0 0 1

DECISION 2 0 0 1

BEST VCL COMPONENT


PRODUCT COMPANY %
BEST TESTING/DEBUGGING TOOL ExpressQuantumGrid Developer Express 35
PRODUCT COMPANY %
Abbrevia TurboPower Software 16
Sleuth QA Suite TurboPower Software 45
TAdvSpreadGrid TMS Software 10
CodeSite Raize Software 23
Other 39
QTime AutomatedQA 10
Source: www.DelphiZine.com
Other 22
Source: www.DelphiZine.com

Best Training Best VCL Component Set

In one of the closest finishes on this year’s ballot, InfoCan Manage- In another category with many qualified and deserving entrants,
ment’s 22 percent of the popular vote narrowly edged Database RX Library from RxLib.com emerged as the leader of the pack,
Programmers Retreat’s 20 percent. This is a repeat performance for receiving 19 percent of the vote. Last year’s winner, Orpheus from
InfoCan being voted as your favorite training company. In fact, TurboPower Software, got 15 percent of the votes to take a close
they’ve won this category an unprecedented four times. Database second. This is an impressive debut for RX Library.
Programmers Retreat should be proud as well; they improved on their
third-place finish of a year ago.
DECISION 2 0 0 1

DECISION 2 0 0 1

BEST VCL COMPONENT SET


BEST TRAINING PRODUCT COMPANY %
COMPANY % RX Library RxLib.com 19
InfoCan Management 22 Orpheus TurboPower Software 15
Database Programmers Retreat 20 ExpressQuantumPack Developer Express 13
Delphi Development Seminars 13 1stClass Woll2Woll Software 11
Keystone Learning Systems 11 Raize Components Raize Software 10
Other 34 Other 32
Source: www.DelphiZine.com Source: www.DelphiZine.com

23 April 2001 Delphi Informant Magazine


Informant Spotlight

Best Web Development Tool


Conclusion
The third-party offerings for the Delphi community have again
Reflecting the ever-increasing interest in Web programming, and the exceeded our expectations. Vendors have again met the challenge
burgeoning availability of specific Web development products, we’re and provided new and improved products for our favorite devel-
proud to debut this category on this year’s ballot. The inaugural opment environment. And despite the rolling blackouts we experi-
winner is Internet Professional from TurboPower Software, which enced in California during the balloting and tabulating processes,
received 40 percent of the votes. ASP Express from Marotz Delphi we managed to get accurate results without any manual recounts,
Group had a respectable second place showing with 24 percent. lawsuits, or trips to the Supreme Court.

We’d like to extend a special “thank you” to all the participants


DECISION 2 0 0 1

on this year’s ballot. Their dedication to the Delphi community


BEST WEB DEVELOPMENT TOOL and their vision of the future of Delphi development is unparal-
PRODUCT COMPANY % leled. Without their innovative products and continued dedica-
Internet Professional TurboPower Software 40 tion to improvement, there would obviously be no Readers Choice
ASP Express Marotz Delphi Group 24 Awards. The very existence of such a diverse and powerful third-
WebHub HREF Tools 14 party tools community is also a testament to the appeal and
CGI Expert L.A. Software 11 endurance of Delphi itself.
Other 11
Source: www.DelphiZine.com Finally, we appreciate those of you who took time to visit our
Web site and vote for your favorite products. You provide valuable
feedback to the participating companies, enabling them to continue
improving their products. Your opinions also guide other Delphi
Best Open Source and Freeware Products developers when choosing the products they need to be as efficient
and productive as possible. ∆
As often happens, we had an unexpected result in this year’s balloting
that warrants special attention. Last year, one company, TurboPower
Software, dominated the results so strongly that we decided to recog-
nize them in a special Company of the Year category. The surprising
story this year is the healthy showing by free software. One open David Riggs is Managing Editor for Delphi Informant Magazine.
source tool was preeminent, GExperts, an add-in to the Delphi IDE
from GExperts.org. By far the strongest freeware showing was made
by Internet Component Suite from Francois Piette of Belgium.

Product of the Year


Capping this year’s exciting balloting is the coveted Delphi Informant
Magazine Readers Choice Award for Product of the Year. It’s quite
an honor, but this year’s winner is accustomed to the accolades.
Garnering the top spot for the third straight year is ReportBuilder
from Digital Metaphors, with 10 percent of the votes. This three-peat
performance is a tribute to the consistent quality of ReportBuilder.
It’s a wide-open category, however, with many competitors making a
good showing. This year’s runner-up, Advantage Database Server by
Extended Systems, ran a close second with 7 percent of the votes.

DECISION 2 0 0 1

PRODUCT OF THE YEAR


PRODUCT COMPANY %
ReportBuilder Digital Metaphors 10
Advantage Database Server Extended Systems 7
ExpressQuantumGrid Developer Express 5
GExperts GExperts.org 4
Other 74
Source: www.DelphiZine.com

Company of the Year


Although there is no Company of the Year category on the ballot,
the winner of this honorary award is clear again. Special congratula-
tions go to TurboPower Software, who placed first in five categories
and second in two. This is a testament to their ability to maintain
excellence through diversity.

24 April 2001 Delphi Informant Magazine


Informant Spotlight

Contacting the Winners

Best Accounting Package Best Database Engine Best Library Best VCL Component
Accounting for Delphi Advantage Database Server SysTools ExpressQuantumGrid
ColumbuSoft Extended Systems TurboPower Software Developer Express
Phone: (800) 692-2150 E-Mail: info@extendsys.com Phone: (800) 333-4160 E-Mail: info@devexpress.com
Web Site: http:// Web Site: http:// Web Site: http:// Web Site: http://
www.columbusoft.com www.extendsys.com/ads www.turbopower.com www.devexpress.com

Best Add-in Best Database Tool Best Modeling/CASE Tool Best VCL Component Set
CodeRush InfoPower ModelMaker RX Library
Eagle Software Woll2Woll Software ModelMaker RxLib.com
Phone: (888) 324-5363 Phone: (800) 965-2965 E-Mail: E-Mail: fkozh@iname.com
Web Site: http:// Web Site: http:// support@modelmaker.demon.nl Web Site: http://www.RxLib.com
www.eagle-software.com www.Woll2Woll.com Web Site: http://
www.modelmaker.demon.nl Best Web Development Tool
Best Book Best Globalization Tool Internet Professional
Delphi in a Nutshell MULTILIZER VCL Edition Best Reporting Tool TurboPower Software
By Ray Lischner MULTILIZER Ltd. ReportBuilder Phone: (800) 333-4160
O’Reilly & Associates E-Mail: info@multilizer.com Digital Metaphors Web Site: http://
Phone: (800) 775-7731 Web Site: http:// E-Mail: info@digital- www.turbopower.com
Web Site: http://www.oreilly.com www.multilizer.com metaphors.com
Web Site: http://www.Digital- Best Open Source Product
Best Charting/Mapping Tool Best Help-authoring Package Metaphors.com GExperts
teeChartPro HelpScribble GExperts.org
Steema Software JGSoft Best Testing/Debugging Tool E-Mail: eberry@gexperts.org
E-Mail: info@steema.com E-Mail: sales@jgsoft.com Sleuth QA Suite Web Site: http://
Web Site: http:// Web Site: http://www.jgsoft.com TurboPower Software www.GExperts.org
www.steema.com Phone: (800) 333-4160
Best Imaging Tool Web Site: http:// Best Freeware
Best Communications Tool ImageLib Corporate Suite www.turbopower.com Internet Component Suite
Async Professional SkyLine Tools Imaging Francois Piette
TurboPower Software Phone: (818) 346-4200 Best Training E-Mail:
Phone: (800) 333-4160 Web Site: http:// InfoCan Management francois.piette@pophost.eunet.be
Web Site: http:// www.imagelib.com Phone: (888) INFOCAN (463-6226) Web Site: http://users.swing.be/
www.turbopower.com Web Site: http:// francois.piette/indexuk.htm
Best Installation Package www.InfoCan.com
Best Database Connectivity InstallShield Express Product of the Year
IB Objects InstallShield Software Best Utility ReportBuilder
Jason Wharton Phone: (847) 240-9111 OnGuard Digital Metaphors
E-Mail: jwharton@ibobjects.com Web Site: http:// TurboPower Software E-Mail: info@digital-
Web Site: http:// www.InstallShield.com Phone: (800) 333-4160 metaphors.com
www.ibobjects.com Web Site: http:// Web Site: http://www.Digital-
www.turbopower.com Metaphors.com

25 April 2001 Delphi Informant Magazine


Dynamic Delphi
ISAPI / NSAPI / CGI / Web Development / Delphi 3-5

By Shiv Kumar

ISAPI Development
Part III: Working with Graphics

L ast month, in Part II of this series, you learned how to store and access information
in a database table from within an ISAPI application. That data was text-only. This
month, you’ll learn how to access and display BLOb (Binary Large Object) data from
a database.

You’ll send images extracted from a database to a add a Query component to it, and change its
Web browser, and explore the QueryTableProducer name to qryData. Set its DatabaseName property
component (part of Delphi’s Web Broker technol- to DBDEMOS, its SQL property to SELECT * FROM
ogy) to help you publish database information on BIOLIFE, and its Active property to True. Place
the Web. HTML tags and frames will also be used. a QueryTableProducer component on the Web
In addition, because images tend to need a lot of Module, and set its Query property to qryData.
bandwidth to be displayed over the Internet, you’ll
find out how to reduce their size and bandwidth Double-click on the Web Module (or right-click it
requirements on the fly. and choose Action editor) and create a new action
item. Set the PathInfo property of this action item
It’s assumed that you’ve read the first two parts of to /data, the Name property to waData, the
this series in the February and March 2001 issues. Default property to True, and the Producer property
Many essential concepts were explained that won’t to QueryTableProducer1. Then drop a Session
be covered here. component on the Web Module and set its
AutoSessionName property to True. Finally, set
Sending Data the Output directory to C:\inetpub\scripts on
Delphi makes sending data really simple; you don’t the Directories/Conditionals page of the Project
need to write any code for this part. Start by creat- Options dialog box (or set it to the scripts folder of
ing a new ISAPI Web Server Application. Then your Web server). Your Object Inspector and Web
Module should look like Figure 1.

Note that there can be only one action item per


Web server extension application with its default
property set to True. This allows you to call your
ISAPI/CGI application from a browser without
specifying an action in the URL. For example,
instead of typing:

http://www.mydomain.com/scripts/
myserverextension.dll/data

where the PathInfo, /data, is the default, you can


Figure 1: The Object Inspector and Web Module thus far. just enter:

26 April 2001 Delphi Informant Magazine


Dynamic Delphi
http://www.mydomain.com/scripts/myserverextension.dll

Setting the Producer property of the action item to


QueryTableProducer1 causes the Response.Content property of the
Web Module to be automatically set to QueryTableProducer1.Content
in the OnAction event. To achieve the same result without setting the
Producer property, you can use the following code:

Response.Content := QueryTableProducer1.Content;

Another interesting item is QueryTableProducer’s MaxRows property.


By default, this property is set to 20. See Delphi’s online help for
a good explanation of this property. Other properties to note are
Caption, Header, and Footer.

Every request from the Web server causes your ISAPI application to
Figure 2: Output generated by the QueryTableProducer component.
spawn a new thread within which a new instance of the Web Module
is created. To allow for multiple simultaneous access to a database, use
a Session component and set its AutoSessionName property to True
so it generates a unique session name for every session (thread). This
isn’t required for CGI applications, because every request from the
Web server creates a new instance of your CGI application (simulat-
ing multiple simultaneous users, each using a separate instance of
your application). When using non-BDE datasets, you should use a
transaction component or something similar to perform the function
of the Session component.

Viewing the Output


Save your project as Biolife.dpr and compile your application. This
should create a DLL named Biolife.dll in the scripts folder of your
Web server. Type http://mypcname/scripts/biolife.dll in your
browser to see the result, as shown in Figure 2. Remember to replace
mypcname with localhost, or the IP address/machine name of the
machine running the Web server. (Note: Those using WinNT/2000 Figure 3: The QueryTableProducer1 object’s Response editor.
may need to give write access for the Internet Guest Account
(IUSR_<machinename>) to the WinNT\System32 folder. This needs the Notes and Graphic fields in the browser. Also set the Border
to be done only when using the BDE with Paradox/dBASE databases.) property of the table to 1. You should see the results of these steps
in the Response editor.
Notice that the Notes field has the word “MEMO” instead of the
actual text, and the Graphic field shows the word “GRAPHIC” Viewing the Notes Field
instead of the graphic. The rest of this article explains how to correct To see the Notes field in your browser, you need to write code
this problem. First, you need to remove unnecessary fields with in the OnFormatCell event of the QueryTableProducer1 component.
QueryTableProducer. This process will also demonstrate how you can At this point, you have the ability to change the content of the
reorder the output fields using the TxxxTableProducer components cell, background color, horizontal and vertical alignment of the cell
provided with Delphi. contents, etc.

Using QueryTableProducer To show the contents of the Notes field, you need to change the
First, set qryData’s Active property to True, and then double-click value of the CellData variable to the contents of that field. Before
on the QueryTableProducer1 component to view its Response writing any code, create the field objects for the qryData dataset
editor (or you can right-click on it and choose Response editor (see Figure 4). You aren’t required to instantiate field objects for
from the shortcut menu). The Response editor should look like things to work, but in this case you’ll create field objects only for
Figure 3. the fields in which you’re interested.

Before you can start manipulating fields, you need to first add all Now in the OnFormatCell event, write the code shown in Figure 5.
fields (similar to instantiating fields of a dataset). To do this, click
on the Add All Fields button in the Response editor. You can drag Re-compile your project and refresh your browser. (See the previ-
and drop, or use the up and down arrow buttons to reorder the ous articles for help with re-compiling.) Notice that the Notes
fields, and select each field in turn and set its properties listed in field now shows contents rather than the word “MEMO”.
the Object Inspector.
Viewing the Graphic Field
You can also set table properties using the Response editor. For this Having graphics appear with data is a bit trickier. The CellData
example, delete the following fields: Length(cm), Length_In, and parameter in the OnFormatCell event for the Graphic field needs
Common_Name. This should give you some extra space to show to be set by QueryTableProducer. If you change the value of the

27 April 2001 Delphi Informant Magazine


Dynamic Delphi
CellData parameter for the Graphic field to an image <img> tag, procedure TWebModule1.QueryTableProducer1FormatCell(
Sender: TObject; CellRow, CellColumn: Integer;
then you should see an image instead of the word. The catch,
var BgColor: THTMLBgColor; var Align: THTMLAlign;
however, is that you need to extract the image from the database var VAlign: THTMLVAlign;
table to show it. The <img> tag supports the following attributes: var CustomAttrs, CellData: string);
§ src: The source or URL where the image can be found. begin
§ border: A value of 0 indicates no border. A value greater than 0 // Row 0 is the column header, so check for CellRow > 0.
if (CellRow > 0) and (CellColumn = 4) then
puts a border around the image. CellData := qryDataNotes.Value; // Memo field data.
§ alt: Means alternate. In browsers that are capable of showing end;
images, the alt attribute essentially shows a hint. In browsers
that can’t show images, you’d see the alternate text instead. Figure 5: The OnFormatCell event handler.

You can write a procedure in your ISAPI application to extract the image procedure TWebModule1.QueryTableProducer1FormatCell(
from the table for a given record. This image then needs to be streamed Sender: TObject; CellRow, CellColumn: Integer;
to the browser. To get the browser to load the image, you simply set the var BgColor: THTMLBgColor; var Align: THTMLAlign;
var VAlign: THTMLVAlign;
src attribute of the <img> tag as an action item. The action will then have var CustomAttrs, CellData: string);
the responsibility of sending back the corresponding image. First, write begin
the code shown in Figure 6 to change CellData to an <img> tag. // Row 0 is the column header, so check for CellRow > 0.
if (CellRow > 0) and (CellColumn = 4) then
CellData := qryDataNotes.Value; // Memo Field data.
The result of the Format procedure and the value of the CellData
// Change the CellData from (GRAPHIC) to an <img> tag.
variable will be something like: if (CellRow > 0) and (CellColumn = 5) then
CellData := Format('<img src="%s/image?No=%s">',
<img src="/biolife.dll/image?No=90020"> [Request.ScriptName, qryDataSpeciesNo.AsString]);
end;

Notice that there’s a reference to an /image


action item in your code. You don’t have Figure 6: Changing CellData to an <img> tag.
this action item as of yet, but you’ll create
it soon. The parameter that you’ll send as
a Name=Value pair to this action item is
No=90020. 90020 is the Species No value
(which happens to be the unique identifier
for this table) for the first record in the Bio-
life table. This parameter will change to cor-
respond with each record’s Species No value.

In your /image action item’s OnAction event,


you can extract this parameter using the Request
Figure 4: The fields object’s QueryFields property. Using the Species
instantiated in No value, you can then zero in on the required
qryData’s fields editor. Figure 7: The Action editor with the new waImage action item.
record, extract the image from the field, and
send it back to the browser as a response.
of the SQL statement used to connect to the correct record. Next,
To create an /image action item, set the PathInfo property to /image you extract the graphic from this record and assign it to a TBitmap
and name it waImage, as shown in Figure 7. Then compile your object. The graphic in the example table happens to be a bitmap. To
application and refresh your browser to see the output shown in convert the bitmap to a JPEG image, simply assign the bitmap to the
Figure 8. Actual images aren’t shown because you haven’t written code TJPEGImage object. To be able to stream the image, save the JPEG
in the waImage action item’s OnAction event, but “GRAPHIC” has image to a memory stream object.
been replaced with an image place holder.
Before you can send back the stream, you need to let the browser
Now add the Graphic and JPEG unit to the uses clause of the know what kind of data to expect. Do this by setting the Response
interface section of the Web Module, and place another Query object’s ContentType to image/JPEG. This is one of the many MIME
component. Set the Name property to qryImage, the DatabaseName types a browser is aware of per W3C (World Wide Web Consortium)
property to DBDEMOS, and the SQL property to: specifications. (The default MIME type in Delphi’s Web Broker is
text/HTML.) Once you’ve done this, send the response using the
SELECT Graphic FROM BIOLIFE SendResponse method of the Response object.
WHERE BIOLIFE."Species No" = :SpeciesNo

You’ll notice in Listing One that the TMemoryStream variable


You’ll stream the image out as a JPEG and use another Query MemStrm is not freed in the end. This is because the Web server
component, qryImage, to connect to the record with the Species No will free memory allocated to MemStrm, so remember not to free
value. Enter the code in the OnAction event of the waImage action memory allocated to objects that are being sent to the Web server
item from Listing One (on page 32). as a response.

In this code, you extract the Species No value from the QueryFields Re-compile your application and refresh your browser. The Notes and
property of the Request object and assign it to the SpeciesNo parameter Graphic fields are shown along with the other fields.

28 April 2001 Delphi Informant Magazine


Dynamic Delphi
You should understand that there will be a number of requests made
on your ISAPI application by the Web browser: One request for the
actual HTML, and then one additional request for each <img> tag
it encounters. Notice that you had to send the No=90020 parameter
one step in advance, so you must be thinking ahead when building
Web applications.

Web application design concerns. On a slow network, this ISAPI appli-


cation could take a long time to process because there are a large number
of images. There are a number of approaches to circumvent this problem.
You could change the application to first show hyperlinked names of
each species. Then, when a visitor clicks on these links, he’d be shown
the Notes and Graphic fields either in a separate browser window or in
frames in the same window, but in the bottom half. You could also show
the Notes and Graphic fields in another page, although the user would
need to hit the Back button on the browser to see the list of species names
again. The advantage to these approaches is that the user isn’t forced to
download all images, but rather only the images in which he’s interested.
You could also go a step further and show thumbnail images instead of Figure 8: Image place holders appear in the Graphic field.
the full-size image. If the user is interested in seeing the larger image,
he can then click on the thumbnail. Needless to say, your knowledge of
HTML plays a big role in a well-designed Web site. A solid understand-
ing of HTML is imperative when developing browser-based applications.

Adding to Your ISAPI Application


The next step is to create a page that contains only the
Common_Name field of the table with hyperlinks. When you click
on a hyperlink, the Notes and Graphic fields for the record in ques-
tion will appear on another page.

Drop another QueryTableProducer component on the form, and


set its Query property to qryData. Double-click on it to open the
Response editor, click on the Add All Fields button, and then
delete all fields except for the Common_Name field. Select the
Common_Name field, and set its Align property to haLeft in the
Object Inspector. In the Web Module, create a new action item, and
set its Name property to waNames, PathInfo property to /names, and
Producer property to QueryTableProducer2.

Now you’ve linked a second QueryTableProducer component to


your qryData Query component, and made sure that only the
Common_Name field is produced in the output. Re-compile
your ISAPI application, and change the URL in your browser to
http://myservername/scripts/biolife.dll/names to see a page similar
to Figure 9.
Figure 9: The result of the /names action of your ISAPI DLL.
The names are not yet hyperlinked. To do this, generate the
OnFormatCell event of QueryTableProducer2 and write the code
procedure TWebModule1.QueryTableProducer2FormatCell(
in Figure 10. Sender: TObject; CellRow, CellColumn: Integer;
var BgColor: THTMLBgColor; var Align: THTMLAlign;
The result of the Format function will look like this: var VAlign: THTMLVAlign;
var CustomAttrs, CellData: string);
begin
<a href="/scripts/biolife.dll/Details?No=90020">
if (CellRow > 0) and (CellColumn = 0) then
Clown Triggerfish</a>
CellData := Format('<a href="%s/Details?No=%s">%s</a>',
[Request.ScriptName, qryDataSpeciesNo.AsString,
Re-compile your application and refresh your browser to see the qryDataSpeciesName.AsString]);
activated hyperlinks. If you move your mouse over each of these end;

hyperlinks, you should see that each species has its associated Species
No value in the status bar of the browser. Figure 10: OnFormatCell event handler of QueryTableProducer2.

Notice you referenced an action item with a PathInfo of /Details in created an action item with a PathInfo of /details. Create it now by
the code, which expects to see a parameter named No. If you click setting a new action item’s PathInfo property to /details and Name
on any of the hyperlinks now, you’ll get an error since you have not property to waDetails. Drop another Query component on the

29 April 2001 Delphi Informant Magazine


Dynamic Delphi

procedure TWebModule1.WebModule1waMainAction(
Sender: TObject; Request: TWebRequest;
Response: TWebResponse; var Handled: Boolean);
begin
Response.Content := '<html>'#13#10 + '<head>'#13#10 +
'<title>Biolife ISAPI Project</title>'#13#10 +
'</head>'#13#10 + '<frameset cols="200,*" border="0">'
#13#10 +'<frame name="MenuFrame" src="' +
Request.ScriptName + '/names"' +
' marginwidth="10" marginheight="5" scrolling="auto"' +
' frameborder="no">'#13#10 +
'<frame name="DetailFrame" src="" marginwidth="10" ' +
'marginheight="10"' +
' scrolling="auto" frameborder="no">'#13#10 +
'</frameset>'#13#10 + '</html>';
end;
Figure 11: The Notes and Graphic fields using frames.

Figure 13: OnAction event handler for waMain event.


<html>
<head>
<title>Biolife ISAPI Project</title> procedure TWebModule1.QueryTableProducer2FormatCell(
</head> Sender: TObject; CellRow, CellColumn: Integer;
<frameset cols="200,*" border="0"> var BgColor: THTMLBgColor; var Align: THTMLAlign;
<frame name="MenuFrame" var VAlign: THTMLVAlign;
src="http://localhost/scripts/biolife.dll/names" var CustomAttrs, CellData: string);
marginwidth="10" marginheight="5" scrolling="auto" begin
frameborder="no"> if (CellRow > 0) and (CellColumn = 0) then
<frame name="DetailFrame" src="" marginwidth="10" CellData := Format('<a href="%s/Details?No=%s" ' +
marginheight="10" scrolling="auto" frameborder="no"> 'target="DetailFrame">%s</a>', [Request.ScriptName,
</frameset> qryDataSpeciesNo.AsString,
</html> qryDataSpeciesName.AsString]);
end;

Figure 12: Sample frames code.


Figure 14: Modifying the OnFormatCell event handler of
Web Module, and set its Name property to qryNotes, DatabaseName QueryTableProducer2.
property to DBDEMOS, and SQL property to:
Before you create frames for your own ISAPI application, take a
SELECT Notes FROM BIOLIFE look at the code snippet in Figure 12. A frameset can comprise any
WHERE BIOLIFE."Species No" = :SpeciesNo number of frames. You can also have nested framesets.

You’ll use this Query component to connect to the required record In Figure 12, the first line of code tells the browser that you want a
and get the value of the Notes field to be displayed in the browser. frameset split into columns. The first column is 200 pixels wide and the
In the OnAction event of the waDetails action item, write the second column is the remaining width. Within this frameset, you have
code shown in Listing Two (beginning on page 32). You’ll find two frames. The <frame> tag has a number of attributes. Of these, the
the full explanation of the code in the comments. Just as you did most important attributes are name and src. Each frame is a separate
previously, set the src attribute of the <img> tag to your waImage HTM file or URL. The src attribute of the <frame> tag tells the browser
action item (PathInfo of /image). This action item can extract the where to get the page, and it can be a valid URL to an actual HTM file
graphic and stream it out to the browser when given the Species or an action in an ISAPI/CGI application. The name attribute is used to
No value. Re-compile your application, refresh your browser, and identify the frame, and is case-sensitive. The name is generally used as the
click on a hyperlink to see both the Notes and Graphic fields. value for the target attribute of an anchor <a> tag, image map, or form. If
Notice that you have to click on the Back button of your browser you don’t specify a target attribute for an <a> tag, the linked page appears
to see the list of Common_Names again. in the same frame like it would in a browser window that’s not split into
multiple frames. Now that you’ve learned a little about frames, use them
You’ve done quite a bit to your application, but there’s more in your project to see how they work.
you can do to improve it. Before you do so, here’s a recap of
what you’ve learned so far. You’ve discovered how to use the The HTML for the frameset in Figure 12 can be a physical HTM file
QueryTableProducer component and the OnFormatCell event to on your hard drive or it can be generated by an action in your ISAPI.
change output, and how to extract an image from a database table To follow this example, take the second alternative. First, create a new
and stream it out to a Web browser. You’ve also found out how action item, set the PathInfo to /main, name it waMain, and set its
to create hyperlinks. default property to True. In the OnAction event of this action item,
write the code in Figure 13.
Extending the Application
The back and forth between Web pages can get quite tiring for As shown in Figure 13, waMain generates the frameset. The
visitors to your Web site. Frames give you the ability to split a MenuFrame’s src value points the browser to an action, PathInfo of
browser window into multiple windows, so you can have a list of /names, in your ISAPI, and it sends back an HTML page with a
hyperlinks on the left side of the browser and fields, like the Notes list of Common_Names that are hyperlinked. The DetailFrame’s
and Graphic fields, on the right side, as shown in Figure 11. src attribute has no value. This is intentional because you don’t

30 April 2001 Delphi Informant Magazine


Dynamic Delphi

procedure TWebModule1.ReduceBitmap(var smBitmap: TBitmap;


orgBitmap: TBitmap; Reduction: Integer = 1);
var
Rect : TRect;
begin
smBitmap.Width := orgBitmap.Width div Reduction;
smBitmap.Height := orgBitmap.Height div Reduction;
Rect.Top := 0;
Rect.Left := 0;
Rect.Right := smBitmap.Width;
Rect.Bottom := smBitmap.Height;
smBitmap.Canvas.StretchDraw(Rect,orgBitmap);
end;

Figure 15: Creating thumbnail images on the fly.

procedure TWebModule1.QueryTableProducer1FormatCell(
Sender: TObject; CellRow, CellColumn: Integer;
var BgColor: THTMLBgColor; var Align: THTMLAlign;
Figure 17: The ISAPI application with thumbnail images instead
var VAlign: THTMLVAlign;
of full-size images.
var CustomAttrs, CellData: string);
begin
// Row 0 is the column header, so check for CellRow > 0.
if (CellRow > 0) and (CellColumn = 4) then
CellData := qryDataNotes.Value; // Memo Field data.
You need to make a few changes to implement thumbnails in your
// Change the CellData from (GRAPHIC) to an <img> tag. project. However, please note that you’ll only implement thumbnails
if (CellRow > 0) and (CellColumn = 5) then for the waData action item. The URL will be: http://mypcname/
CellData := Format('<a href="%s/image?No=%s&Size=1">' + scripts/biolife.dll/data.
'<img src="%s/image?No=%s&Size=2" border="0"></a>',
[Request.ScriptName, qryDataSpeciesNo.AsString,
Request.ScriptName, qryDataSpeciesNo.AsString]); Make the required changes in the waImage action item’s OnAction
end; event by entering the code from Listing Three (on page 33). Notice
that before you assign the bitmap to the JPEG image, you reduce
Figure 16: Specifying the Size parameter. the image by a factor you extract from the QueryFields property of
the Request object:
really want to show anything in this frame at the onset, although
you do want to show the Notes and Graphic fields in this frame ReduceBitmap(smBitmap, Bitmap, StrToIntDef(
when you click on any of the hyperlinks on the left. Request.QueryFields.Values['Size'], 1));

Check the output of waMain. If you click on the hyperlinks now, Now, you need to specify the Size parameter by modifying the
you’ll notice that the Notes and Graphic fields are shown in the same QueryTableProducer1’s OnFormatCell event, as shown in Figure 16.
frame, the frame named MenuFrame. This isn’t what you want. You’d (Keep in mind there’s no problem if the Size parameter doesn’t exist
like the Notes and Graphic fields to be shown in the DetailFrame. in Delphi 4 and 5 because the ReduceBitmap procedure uses a default
To get your ISAPI application to do this, you need to set the parameter; Delphi 3 doesn’t support default parameters.)
target attribute’s value for each of the hyperlinks to DetailFrame by
modifying the OnFormatCell event of QueryTableProducer2 to the The <img> tag’s src attribute sends two parameters, No and Size. Size
code shown in Figure 14. has a value of two; the image will be half its full size. The <img> tag
is surrounded by an <a> tag, so you’ll get a full-sized image when
Basically, you’re just changing the format string from: an image is clicked. The <a> tag’s href attribute sends two parameters
as well, because it calls the same action, /image, which expects two
<a href="%s/Details?No=%s">%s</a> parameters. But in this case, Size has a value of one, meaning full
size. The result of the Format function shown in Figure 16 should
to be something like:

<a href="%s/Details?No=%s" target="DetailFrame">%s</a> <a href="/scripts/biolife.dll/image?No=90020&Size=1">


<img src="/scripts/biolife.dll/image?No=90020&Size=2"

Creating Thumbnail Images border="0"></a>

Due to speed considerations, many people like to create thumb-


nail images to send to a browser, giving the user the option of Re-compile your project, and enter the URL http://mypcname/scripts/
seeing an image in full size. Delphi makes it simple to create biolife.dll/data in your browser. The resulting page should look like
thumbnail images on the fly, as shown in Figure 15. Figure 17. The images are now half the size. You have effectively
reduced the response time of this page by almost half. Also, you should
Two bitmap objects are sent to this procedure. smBitmap contains the notice that each image is hyperlinked. Clicking on any of the images
reduced bitmap and orgBitmap contains the bitmap to be reduced. will show you a page containing the full-size version of that image.
Reduction is the factor by which to reduce the bitmap. Reducing an
image this way also reduces the file size, and thus the amount of data Creating thumbnails in this fashion is extremely handy, because you
downloaded to a user’s machine. don’t need to maintain two or more versions of each image being

31 April 2001 Delphi Informant Magazine


Dynamic Delphi
used in your Web applications. In cases where used images reside on
your hard disk as JPEG files, Delphi’s TJPEGImage class makes it a Begin Listing One — OnAction event handler of
breeze to create thumbnails. Simply setting the scale property does the waImage
trick. Well, almost. Also keep in mind that you can create grayscale procedure TWebModule1.WebModule1waImageAction(
versions of images by setting the GrayScale property (objects of type Sender: TObject; Request: TWebRequest;
Response: TWebResponse; var Handled: Boolean);
TJPEGImage have this property) to True. This will further reduce the
var
size of the image and the response times of your Web pages. JPEG : TJPEGImage;
MemStrm : TMemoryStream;
Conclusion Bitmap : TBitmap;
In this article, you learned how to use the QueryTableProducer compo- begin
{ In this action event, extract the SpeciesNo parameter
nent to publish database tables on the Web. You discovered how to from the QueryFields property of the Request object and
extract images stored in a database table and stream them out to a use it to get the image from the table. Then, stream out
browser, and a little about frames and how to use them in your ISAPI the image as a JPEG image. }
applications. Lastly, you found out how to reduce the size of images on try
JPEG := TJPEGImage.Create;
the fly to help improve the response times of your ISAPI applications. ∆
MemStrm := TMemoryStream.Create;
Bitmap := TBitmap.Create;
The files referenced in this article are available on the Delphi try
Informant Magazine Complete Works CD located in INFORM\2001\ with qryImage do begin
APR\DI200104SK. { Assign the SpeciesNo parameter the value received
in the Request object's QueryFields property.
Remember it comes as No=90020. }
Close;
Params[0].AsInteger :=
Shiv Kumar works in R&D at DataSource Inc. He develops new product ideas, StrToInt(Request.QueryFields.Values['No']);
Prepare;
prototypes them, and leads the implementation effort. Shiv, an ex-VB programmer, Open;
has used Delphi exclusively since Delphi 1. His hobbies include electronics and { Assign the image from the database to a Bitmap
photography, and he loves to ride his CBR 1100XX at every opportunity. You can object since the field type is a TGraphicField. }
contact Shiv at shiv@matlus.com. Bitmap.Assign(FieldByName('GRAPHIC'));
JPEG.Assign(Bitmap);
{ Save the JPEG image to memory stream object. }
JPEG.SaveToStream(MemStrm);
{ Set the position of the stream to the start. }
MemStrm.Position := 0;
{ The content type needs to be set to image/JPEG.
Default is text/HTML. }
Response.ContentType := 'image/jpeg';
Response.ContentStream := MemStrm;
{ Send the response. }
Response.SendResponse;
Unprepare;
Close;
end;
finally
JPEG.Free;
{ Don't Free MemStrm. The Web server will take care
of that. }
Bitmap.Free;
end;
except
on E : Exception do begin
Response.ContentType := 'text/html';
Response.Content :=
'<B>ERROR</B><BR>' + #13#10 + E.Message;
end;
end;
end;

End Listing One


Begin Listing Two — OnAction event handler of
waDetails
procedure TWebModule1.WebModule1waDetailsAction(
Sender: TObject; Request: TWebRequest;
Response: TWebResponse; var Handled: Boolean);
begin
{ Manually create an HTML table with two columns.
Populate the first one with the contents of the Notes
field. The second column will contain graphics. Here,
only put an <img> tag with the correct URL to extract
the required image from the table using the SpeciesNo
parameter sent in the QueryFields property of the

32 April 2001 Delphi Informant Magazine


Dynamic Delphi

Request object. } try


Response.Content := '<html>'#13#10 + ' <head>'#13#10 + JPEG := TJPEGImage.Create;
' <title>Biolife Details</title>'#13#10 + MemStrm := TMemoryStream.Create;
' </head>'#13#10 + '<body>'#13#10 + Bitmap := TBitmap.Create;
'<table border="1">'#13#10 + ' <tr>'#13#10 + smBitmap := TBitmap.Create;
' <td>'; try
{ Zero in on the correct record in the table. } with qryImage do begin
with qryNotes do begin { Assign the SpeciesNo parameter the value received
{ Assign the SpeciesNo parameter the value received in in the Request object's QueryFields property.
the Request object's QueryFields property. Remember Remember it comes as No=90020. }
it comes as No=90020. } Close;
Close; Params[0].AsInteger :=
Params[0].AsInteger := StrToInt(Request.QueryFields.Values['No']);
StrToInt(Request.QueryFields.Values['No']); Prepare;
Prepare; Open;
Open; { Assign the image from the database to a Bitmap
Response.Content := Response.Content + object since the field type is a TGraphicField. }
{ Put the value of the Notes field in first cell. } Bitmap.Assign(FieldByName('GRAPHIC'));
qryNotes.FieldByName('Notes').AsString + { Reduce the image size. }
'</td>'#13#10 + ReduceBitmap(smBitmap, Bitmap, StrToIntDef(
{ Put an <img> tag in the second cell and set its src Request.QueryFields.Values['Size'],1));
attribute's value to the waImage action item's JPEG.Assign(smBitmap);
PathInfo, sending it the SpeciesNo received in the { Save the JPEG image to memory stream object. }
Request object's QueryFields property. } JPEG.SaveToStream(MemStrm);
' <td><img src="' + Request.ScriptName + { Set the position of the stream to the start. }
'/image?No=' + Request.QueryFields.Values['No'] + MemStrm.Position := 0;
'"></td>'#13#10 + ' </tr>'#13#10 + '</table>'; { The content type needs to be set to image/JPEG.
Close; Default is text/HTML. }
UnPrepare; Response.ContentType := 'image/jpeg';
end; Response.ContentStream := MemStrm;
Response.Content := { Send the response. }
Response.Content + '</body>'#13#10 + '</html>'; Response.SendResponse;
end; Unprepare;
Close;
End Listing Two end;
finally
Begin Listing Three — waImage’s OnAction event JPEG.Free;
{ Don't Free MemStrm. The Web server will take
handler care of that. }
procedure TWebModule1.WebModule1waImageAction( Bitmap.Free;
Sender: TObject; Request: TWebRequest; smBitmap.Free;
Response: TWebResponse; var Handled: Boolean); end;
var except
JPEG : TJPEGImage; on E : Exception do begin
MemStrm : TMemoryStream; Response.ContentType := 'text/html';
Bitmap : TBitmap; Response.Content :=
smBitmap: TBitmap; '<B>ERROR</B><BR>' + #13#10 + E.Message;
begin end;
{ In this action event, extract the SpeciesNo parameter end;
from the QueryFields property of the Request object and end;
use it to get the image from the table. Then, stream
out the image as a JPEG image. }
End Listing Three

33 April 2001 Delphi Informant Magazine


From the Palette
Automation / Excel 97, 2000 / Delphi 5

By Ron Gray and Steven McPherson

Excel Server Components


Creating Excel Reports and Charts via Automation

C ould your application use a solid component that offers powerful features for
analyzing, reporting, and graphing data? The Excel Automation server components
in Delphi 5 let you directly manipulate Excel to export data, insert formulas, and draw
graphs to create new views of your application’s data.

Delphi 5 wraps Office 97 and Office 2000 in a to the DBDEMOS tables installed with Delphi.
set of components that greatly facilitate Automa- Although this application was created with the Excel
tion. Using the components might appear difficult 97 components, it also runs under Excel 2000.
at first because they aren’t documented. Their use is
straightforward however, and the Excel object model Working with Automation Objects
is well documented. Using any Automation server Automation is a technology that enables one appli-
requires a basic understanding of the two topics: cation (the controller) to directly manipulate the
§ Automation and how to use Automation objects of another application (the server). In other
objects in Delphi. words, a Delphi application can control Excel
§ The object model of the Automation server — to perform everything that can be accomplished
Excel, in this case. through the user interface. This is possible because
Excel is truly object-oriented. All content and
The demonstration application accompanying this functionality in Excel is defined through objects,
article (available for download; see end of article for which are exposed through COM interfaces so
details) uses Excel to create a report and chart of other applications can manipulate them. (A more
monthly sales (see Figure 1). It requires a BDE alias detailed discussion of Automation appeared in the
“Word Control: Part I” article in the September
2000 issue.)

Delphi can support run-time Automation (also


known as late binding), or compile-time Auto-
mation (early binding). To support early binding,
type information about the server must be com-
piled into the application. Automation servers usu-
ally provide type information about their exposed
objects through type files that can be imported into
Delphi using the Import Type Library tool. Excel
type files have already been imported in Delphi 5
as Excel97.pas and Excel2000.pas (located in the
\ocx\servers directory).

A wrapper class is automatically created for each


Figure 1: The demonstration application uses Excel to produce a monthly CoClass defined in the type library. A CoClass is a
sales report. class that implements an interface that is defined in

34 April 2001 Delphi Informant Magazine


From the Palette
the type library. It is instantiated using a CoClass client proxy class. try
Fortunately, understanding this level of detail is no longer necessary ExcelApplication1.Connect;
because Delphi 5 further encapsulated complexity by wrapping each except
CoClass in a component, thus: on E: Exception do begin
E.Message := 'Excel unavailable.';
Raise;
ExcelQueryTable = _QueryTable; end;
ExcelApplication = _Application; end;
ExcelChart = _Chart; ExcelApplication1.Visible[0] := True;
ExcelWorksheet = _Worksheet;
ExcelWorkbook = _Workbook;
ExcelOLEObject = _OLEObject; Figure 2: Connect to an Automation server in a try..except
statement.

Delphi’s Office Automation components descend from TOleServer,


an abstract class that represents an imported COM server. It
implements abstract methods and properties that are common
to all Automation servers, such as establishing a connection and
responding to events. This means that, except for their specific
functionality, all Automation objects work the same way. To use them
requires knowing how to connect to servers and other Automation
components, and how to work with parameters.

Connecting to an Automation Server


Before using the Excel components, a connection must be established
with the Excel application. An explicit connection can be made using
the Connect method. The component could fail to connect to the
server for a number of reasons. Therefore, always wrap the connec-
tion in a try..except statement, as shown in Figure 2.
Figure 3: The Excel help file doesn’t always list the correct
How the connection is established depends on two important proper- parameters, but the Code Completion window does.
ties of TOleServer. First, use AutoConnect to automatically connect
to the server when the application is started. This is useful to shift to the correct CoClass. The following example connects to the first
load time when Excel is always needed in the application. Second, worksheet by casting the return value to _Worksheet:
ConnectKind determines how the connection is established and has
the following possibilities: ExcelWorksheet1.ConnectTo(
§ ckRunningOrNew attaches to an existing server or, if there’s not a ExcelWorkbook1.Sheets[1] as _Worksheet);

running server, creates a new instance.


§ ckNewInstance always creates a new instance of the server. This is The ConnectTo method is used to connect to the other Excel compo-
useful if you need exclusive access without user intervention. nents as well. Workbooks, worksheets, and charts can, and should, be
§ ckRunningInstance only connects to a running server. connected to each other.
§ ckRemote binds to a remote instance of the server located on the
machine RemoteMachineName. Passing Parameters to Automation Servers
§ ckAttachToInterface doesn’t bind to the server. Instead, the appli- Once the object is valid, its properties and methods can be
cation supplies an interface using the ConnectTo method. invoked. When working with parameters, most Automation serv-
ers use the variant — a data type that contains another type.
A connection can also be made implicitly by simply invoking a The controlling application passes parameters as variants, and the
method or property of the server. In other words, simply setting server application converts them to the proper data type. Variants
the Visible property automatically establishes a connection, even if consume more memory, and are slower than other data types,
the Connect method has not been called. By the way, the Visible but they’re a necessary evil. Not only are they flexible, they allow
property must be set to True to display the Excel application. applications to communicate even when they don’t support the
This means the application can remain hidden if processing doesn’t same data types.
require the user interface.
Some parameters might need to be cast to variants, either within the
Excel components can be connected using the ConnectTo method. function call or declared as a variant variable. Sometimes this is neces-
The following example connects the ExcelWorkbook object to a new sary, but often it’s just to remove compiler warnings. For example, to
workbook created with the ExcelApplication object: create a new workbook, the Add method expects a constant for the
template to use. To avoid compiler warnings, cast the constant to the
ExcelWorkbook1.ConnectTo( expected data type:
ExcelApplication1.Workbooks.Add(EmptyParam, 0));

ExcelApplication1.Workbooks.Add(
The ExcelWorkbook object can connect directly to the return value OleVariant(xlWBATWorksheet), 0);

of the Add method because the Excel import files were modified to
rename references to the workbook to ExcelWorkbook. However, some Use the EmptyParam variable to represent unused or default param-
properties and methods return references to objects that must be cast eters that are OleVariants:

35 April 2001 Delphi Informant Magazine


From the Palette
ExcelApplication1.Workbooks.Add(EmptyParam, 0); iRow := 1;
while not Query1.Eof do begin
In addition to variants, many Excel methods take an LCID parameter ExcelWorksheet1.Cells.Item[iRow + 1,1] :=
(like the Add method above and the Visible method used earlier). Query1.FieldByName('SaleDate').AsString;
ExcelWorksheet1.Cells.Item[iRow + 1,2] := FloatToStr(
This identifies the locale for national language support. For example, Query1.FieldByName('ItemsTotal').AsCurrency);
the Locale ID can be used to override the Regional Settings in the ExcelWorksheet1.Cells.Item[iRow + 1,2].Style :=
Control Panel to force a different locale. Unless the application has 'currency';
international requirements, use an LCID of zero, which is assumed to Inc(iRow);
Query1.Next;
be the default locale for the system and not a user.
end;

The Excel Object Model Figure 4: Looping through a query, and writing into worksheet
The next step is to get into the Excel object model. To successfully columns.
use the Excel components, it’s important to understand how Excel’s
content and functionality are defined in the object. The Excel object saved workbook. An earlier example uses the Workbooks object to create
model is documented in the Microsoft Excel Objects help file vbaxl8.hlp a new workbook and connect to it. Existing workbooks that are open in
(or vbaxl9.chm for Office 2000), which is on the Office CD, but Excel can be accessed by name, index, or the ActiveWorkbook property,
not installed by default. To install it, run the Microsoft Office Setup like this:
program, and select Add/Remove components. Select Help for Visual Basic
under the Help options (or under the Office Tools option in Office 2000). ExcelWorkbook1.ConnectTo(ExcelApplication1.ActiveWorkbook);

Please note the help file is not current with the type library, so the This example opens an existing workbook and connects to it:
parameters described in the help file aren’t always accurate. The actual
declarations can be found in the imported files (Excel97.pas and ExcelWorkbook1.ConnectTo(ExcelApplication1.Workbooks.Open(
Excel2000.pas), or use the Code completion (Cm) and Code 'c:\code\excel\book1.xls', EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam, EmptyParam,
parameters (CVm) features to show the expected parameters.
EmptyParam, EmptyParam, EmptyParam, EmptyParam,
Figure 3 shows the difference between the help file and the Code EmptyParam, EmptyParam, 0));
parameters output.

All of the Office applications follow common naming conventions You can access worksheets in the same manner. The example above
and standards. The Application object is the top-level object and shows how to connect to the first worksheet by index. This example
provides a reference to the application itself. Objects are often acces- connects to a worksheet by name:
sible only through other objects in a parent-child relationship, and
child objects can have children of their own. Another convention is ExcelWorksheet1.ConnectTo(
the use of Collection objects that contain a set of related objects. The ExcelWorkbook1.Sheets['sheet1'] as _Worksheet);

name of the Collection object is the plural of the object the collection
contains. For example, the WorkSheets collection contains WorkSheet With a reference to a worksheet, data can be entered in the cells.
objects. Most collections provide a Count property and Item and Add
methods to navigate and select specific objects. Entering Data and Formulas
There are a variety of ways to move data from a Delphi application to
In Excel, documents are called workbooks. A workbook is a collection Excel. If the data can be accessed using ODBC, the ExcelQueryTable
of worksheets and sheets. Each worksheet contains cells that are used to component is best for loading data directly into a worksheet. Excel
store and identify data and formulas in a workbook. Each cell can have can also directly open comma-delimited files, so a Delphi application
associated formatting such as fonts, colors, and layout options. The Range might write the data to a file, and then open it with Excel. However,
object is used to identify a cell or range of cells in a contiguous block. smaller amounts of data can be written directly to each cell. The
example in Figure 4, taken from the demonstration application, loops
The overall structure of the object model resembles the user interface, through a query, and writes the sale date in the first column and the
so performing an action programmatically usually requires the same amount in the second column.
steps as in the user interface. For example, to insert text into a cell,
first open Excel, and then use the existing workbook or create a new Formulas can also be entered in the same manner. The following
one. Next, use an existing worksheet, or create a new one. Finally, example places a formula at the bottom of the second column to
select a cell, and enter text. total all sales:

These steps can be accomplished using just the ExcelApplication ExcelWorksheet1.Cells.Item[iRow + 2,2] :=
component, but it would require making calls to objects several '=SUM(B1:B' + IntToStr(iRow) + ')';

levels deep. It’s much easier to use the other components along
with the ExcelApplication object. For example, to perform the same Working with Charts
actions programmatically, drop ExcelApplication, ExcelWorkbook, and Use the ExcelChart object to create or access a chart in a work-
ExcelWorksheet components on the form, and connect each of them book. The chart can be either an embedded chart in an existing
as described in the following section. sheet, or a separate chart sheet. The following example uses the
Sheets object to create a chart worksheet:
Using Workbooks and Worksheets
There are several ways to connect to a workbook: access a workbook ExcelChart1.ConnectTo(ExcelWorkbook1.Sheets.Add(EmptyParam,
that’s currently open, create a new workbook, or open a previously EmptyParam, 1, Variant(xlChart), 0) as _Chart)

36 April 2001 Delphi Informant Magazine


From the Palette

var
oRange: Variant;
begin
// Define a range for the source of data.
oRange := ExcelWorksheet1.Range['A1', 'B13'];
// Use the ChartWizard method.
ExcelChart1.ChartWizard(
oChartRange, // Source.
Variant(xl3DColumn), // Gallery.
4, // Format.
Variant(xlRows), // PlotBy.
0, // CategoryLabels.
1, // SeriesLabels.
True, // HasLegend.
'Monthly Sales', // Title.
'Month', // CategoryTitle.
EmptyParam, // ValueTitle.
EmptyParam, // ExtraTitle.
0); // LCID.
end;
Figure 6: Use TExcelChart to create a graph. Here, the
ChartWizard method is used to chart monthly sales.

Figure 5: Using the ChartWizard method.

There are dozens of properties that can be set to create a chart, but the spreadsheets and charts to be saved as interactive Web pages), and
minimum required properties can be set using the ChartWizard method, Web page scripting. All of the new features are well-documented
as shown in Figure 5. The first parameter of this method is the range in the Excel VBA help file.
that contains the source data for the chart. This requires creating a range
object as a variant and defining its values. The first column of the range Conclusion
contains the names of the months, and the second column has the total This article covers some basics of Automation and presents the
sales amount for that month. The PlotBy property is set to xlRows, and Excel object model. However, there are many other topics for
SeriesLabels is set to one because the data is labeled in one column. This which space doesn’t permit a discussion. For example, Object
method creates the chart in the chart sheet shown in Figure 6. Linking and Embedding (OLE) allows Delphi applications to
contain Excel objects. (The demonstration application copies the
The ExcelChart object has plenty of events that allow the develop- chart shown in Figure 6 into Delphi.) A more detailed discussion
ment of truly interactive charts. The demonstration application also of OLE 2 was presented in “Automating Word: Part II,” which
provides an example of embedding a chart in an existing worksheet. appeared in the October 2000 issue. ∆

Using Excel 2000 The sample application referenced in this article are available on the
By default, the server components included with Delphi are for Office Delphi Informant Magazine Complete Works CD located in INFORM\
97. However, code written with these components will also run on 2001\APR\DI200104RG.
Office 2000 because Microsoft provided backward compatibility, and
the servers point to the same class ID. Therefore, unless the application
specifically requires Excel 2000, the 97 components should work fine
under 2000. However, to take advantage of the new features in Excel
2000, the Excel 2000 server components must be installed. Since the
97 and 2000 classes use the same names, they can’t both be installed Ron Gray is a software developer specializing in business database applications.
at the same time. First, select Install Package from the Component menu He’s written numerous articles using different languages and is the author of
in Delphi and remove the Office 97 components (DclAxServer50.bpl). LookUp Manager, a collection of components for visually managing lookup codes
Next, add the package Dcloffice2k50.bpl in the /bin directory to and abbreviations in applications. He can be reached at rgray@compuserve.com.
register the Office 2000 components.
Steven McPherson lives in Atlanta with his wife, Kelly, and daughter, Sarah. He’s a
The Excel 2000 object model includes many changes, which show programmer for an Atlanta-based insurance adjusting company. He started writing
in the size of the imported type library: 4,915KB as compared code as a hobby five years ago and has turned it into his full-time career. He has
to 1,830KB for Excel97.pas. Primary additions include direct experience with Visual Basic and Delphi, and is currently learning Java. Steven can
support of ADO (which is the preferred data access method in be reached at smcpherson2002@yahoo.com.
Excel 2000), the Office 2000 Web components (which allows

37 April 2001 Delphi Informant Magazine


New & Used
By Bill Todd

Wise for Windows Installer 3.0


The Must-have Installation Tool for Windows Installer

W ise for Windows Installer 3.0 is the latest version of Wise Solutions, Inc.’s installation
tool for Windows Installer. If you’ve used other Wise installation products, you’ll feel
right at home with Wise for Windows Installer 3.0. If not, you’re in for a surprise.
When you start Wise for Windows Installer for the to move easily through the six major steps of creat-
first time you’re presented with the New Installation ing your installation. However, unlike most Win-
File dialog box (see Figure 1). This is the same dows experts or wizards that require you to move
dialog box you’ll see if you choose File | New. Here from step to step by clicking Next and Previous
you can choose to start a new empty project; start buttons, the Wise UI lets you see all the buttons
with an empty merge module; create a new trans- concurrently so you can jump to any step simply
form; import a Wise script that was created with by clicking the appropriate button.
Wise InstallMaster, InstallBuilder, or InstallManager;
import a VB project; run the Application Watch Each button contains a list of functions you can
wizard; or run the SetupCapture wizard. Also, a pair perform as part of that step. For example, in step
of radio buttons let you choose whether you want one you can create or edit features, add files to
to create a standard Windows Installer file or a Wise features, define which features are included in each
project file. I can’t think of a reason not to create a installation type, and add any merge modules that
Wise project file since the project files are smaller and need to be run as part of your installation. You
allow you to create multiple product releases from a have two choices when you click a button. You can
single project. A standard Windows Installer MSI file click the right side of the button and automatically
is automatically created when you compile a release. go to the first function in the list for that step or
you can place the mouse cursor over one of the
Exploring the Installation Expert functions listed so it appears underlined, click, and
You’ll see the main Wise Installation Expert jump directly to the screen for that function. To
screen shown in Figure 2 when you start a new the right of each of the functions listed inside the
empty project. One of the unique things about button is a small recessed square. The square will
Wise products is that appear darkened if you have made any changes.
the Installation Expert This lets you see at a glance where you have
doesn’t use the standard customized the installation and allows you to go
Windows user interface. directly to that function or feature.
Wise had the courage
and the talent to create Another impressive aspect of the Wise Installation
a unique UI that’s more Expert is its power. The problem with experts or
powerful and easier to wizards in most programs that let you perform
use than had they tried complex tasks is that they let you perform only
to mimic something one small part of the task in each wizard, or the
more familiar that wasn’t wizard only lets you build the shell of whatever
specifically designed for you are doing and you must do a lot of customiza-
creating software instal- tion outside the wizard to finish the job. As you’ll
lations. The heart of the see, this is not the case with the Wise Installation
expert’s UI is the row of Expert. For the most part, it allows you to do the
buttons, numbered one whole job from within the expert.
through six, at the top
of the screen (Figure 3 Building an Installation
provides a closer look). To give you a better understanding of what it’s like
Figure 1: The New Installation File dialog box. These buttons allow you to work with the Installation Expert, let’s take a

38 April 2001 Delphi Informant Magazine


New & Used

Figure 4: An installation with four features.

Figure 2 (Top): The Wise Installation Expert.


Figure 3 (Bottom): The Installation Expert buttons.

look at building an installation for a Delphi application. The first


step when creating an installation that uses Microsoft’s Windows
Installer technology is to define the features that comprise your
application. A feature is a file or collection of files that are installed
as a unit. In an accounting system, for example, you might have
features for the system manager, general ledger, accounts payable,
accounts receivable, and payroll. Figure 4 shows a project with four
features defined. When you first select Features, you’ll see a single
feature named Complete under Installation Features. You can rename
it by clicking the Details button. Select Installation Features or one
of the existing features, and click the Add button to add a new
Figure 5: Adding files to features.
feature under the one you selected. When you add or edit a feature,
the Feature Details dialog box lets you set the name, title, and
other properties of the feature, such as the directory to which it is in your installation or files that are already on the user’s system, such
installed, whether it is required, and whether it will be advertised. as NOTEPAD.EXE. The Registry option displays a screen very much
like the one for files, except the top tree is the registry on your system
Figure 5 illustrates how the screen will look after you select files. The top and the bottom one is the registry on the target system. Here you
tree view shows the directory tree on your computer, and the bottom one can define all of the registry keys that need to be created or modified.
shows the directory tree on the destination computer. Before selecting Choosing INI Files lets you create or modify INI files on the target
files use the Feature drop-down box to select the feature to which you system. The Services option under step two lets you start, stop, install,
want to add files, then select the destination folder and source folder, or remove services on the target system if the target system is running
select the files, and click the Add button. You can also select entire folders Windows NT or 2000. The last option in step two, ODBC, lets you
from the source computer and click the Add Contents button to add install or remove ODBC drivers, DSNs, and translators.
the files to the target computer. When you do, you have the option of
using wildcards to determine which files will be added, the option to Step three lets you define checks that will be performed on the target
include subdirectories, and the option to have the installation updated system before the installation begins. The Configuration option lets
automatically as files are added to, or removed from, the source directory. you check the Windows or Windows NT version, screen resolution
and color depth, and Internet Explorer and Windows Installer ver-
Wise for Windows Installer lets you define three installation types: sions. You can compose the error message the user will see for each
Typical, Complete, and Custom. The Installation Types option lets you check that you implement. Under Previous Version you can check for
define which features are included in each installation type. Merge the existence on the target computer of one or more files, directories,
Modules lets you include merge modules in your installation. When INI files, registry entries, or components. Again, you can enter the
you click the Add button you can choose from a list of more than error message the user will see if the required item is not present. In
50 merge modules included with Wise, or you can click the Browse all cases, the installation terminates if a required check fails.
button to easily add any other merge module on your system.
Step four lets you define the dialog boxes that will be displayed
Step two in the Installation Expert starts by letting you define the during the installation. For those who require text such as the License
shortcuts you want created on the target system, and the folder in dialog box or the ReadMe dialog box, you can enter the text directly
which to put the shortcuts. You can create shortcuts for files included into Wise or import it from any text or RTF file.

39 April 2001 Delphi Informant Magazine


New & Used

Wise for Windows Installer 3.0 is the best installation tool I have seen for building
Windows Installer setups. The Installation Expert is a superior marriage of power
and ease of use. In most cases, you’ll be able to build all but the most complex
installations without ever leaving the expert. If you need to build installations
using Windows installer you can’t go wrong with Wise for Windows Installer 3.0.

Wise Solutions, Inc.


5880 North Canton Center Road, Suite 450
Canton, MI 48187

Phone: (734) 456-2100


Fax: (734) 456-2345
E-Mail: info@wisesolutions.com
Web Site: http://www.wisesolutions.com
Price: Wise for Windows Installer Standard 3.0, US$449; Wise for
Windows Installer Professional 3.0, US$899; Wise for Windows Installer
Figure 6: The Setup Editor. Language Pack, US$795.

The fifth step is where you define the releases for your application.
Every installation must have at least one release, but you can have
as many as you wish. For example, if you have a professional ver- Using the Setup Editor
sion of your application that includes all features and a standard The Setup Editor, shown in Figure 6, provides a completely different
version that includes only some of the features, you need to define view of your installation, as well as the ability to edit the Windows
two releases. Other reasons for multiple releases include support Installer database tables directly. This screen is divided into three panes.
for multiple languages and different distribution media. When
you define a release, you also decide whether to create only an The left pane contains six tabs that correspond to the types of informa-
MSI file or to create an EXE that will install Windows installer if tion with which you can work. A different tree view appears for each tab.
it isn’t already on the target computer. Selecting the Build option The upper-right pane displays the detailed values for the selected item in
enables the Release combo box near the upper-right corner of the the left pane. For example, if you select the Product tab, the left pane
screen. Here you select each release, then choose the features that contains Launch Conditions, Properties, and Summary. Select Properties to
will be included. The Media option lets you set the properties of display all the properties and their values in the upper-right pane. The
the distribution media for each release, and the Languages option lower-right pane contains help about the selected item in the left pane.
lets you choose the languages for each release. Wise for Windows
Installer ships with five built-in languages; the optional language Properties and Summary information have already been described.
pack offers an additional 20. Selecting Launch Conditions lets you create conditions that must be
true for the installation to run. For example, you could require that
Step six is where you finish, and includes options for project informa- the user be logged on as Administrator to install your application.
tion, summary information, upgrades, code signing, and Windows Wise for Windows Installer makes creating launch conditions easy
2000. The Project option lets you enter the name, version number, by providing a Condition Builder, which lets you build conditional
and manufacturer information. You can also change the default instal- expressions by making point-and-click choices from lists.
lation directory here. The Summary option allows you to enter all the
information you want users to see when they right-click the setup file The Features and Dialogs tabs let you define your features and
in Windows Explorer and choose Properties. Using the Upgrades option, control which dialog boxes are displayed during installation. You can
you can enter information about previous versions of your product that create your own custom dialog boxes or customize any of the built-in
this installation will upgrade. If the previous installation doesn’t exist, dialog boxes using the dialog editor. The Actions tab lets you edit
this installation will not work. The Code Signing option allows you to existing actions or add custom actions. While it’s not likely that you’ll
create a code-signed installation file. Finally, the Windows 2000 option need to change any existing actions, there are times when you will
lets you set how your application is displayed in the Windows 2000 and want to add custom actions. Custom actions let you run an EXE
Windows Me Add/Remove Programs Control Panel applet. or call DLL functions as part of your installation. You can even
run VBScript or JScript files. The Tables tab lets you edit Windows
When you’ve finished creating your installation, use the Compile, Test, Installer database tables directly and is for those who are intimately
Debug, Run, and Distribute buttons at the bottom-right (again, see familiar with the Windows Installer SDK.
Figure 5) to test, debug, and distribute your installation. The Compile
button creates your setup file, which will either be an EXE or MSI What’s New?
file (depending on the options you chose). The Test button allows If you’ve used version 2 of Wise for Windows Installer, here’s a sum-
you to run your installation and see exactly what the end user will mary of the new features in version 3. Editing Windows Installer
see without making any changes to your system. The Debug button database tables is now easier. You can add new rows to any table;
opens the debugger for Windows Installer, which lets you single-step show or hide empty tables; search the entire database for validation
through your installation, set breakpoints, and examine values. The errors; or search and replace strings in the entire database, a single
Run button runs the installation and installs the software on your table, or a single column. You can also add your own tables to the
system. In addition to distributing your application to removable Windows Installer database to store data used by custom actions.
media or a network share, the Distribute button also lets you distribute Support for undo, redo, cut, copy, and paste has been added to
your setup via FTP. the Setup Editor. The Previous Version and Installation Types options

40 April 2001 Delphi Informant Magazine


New & Used
in the Installation Expert, described earlier, are new in version 3.
The Setup Editor now lets you move all of the components of
a feature to a merge module. When you do, the components are
automatically replaced in your installation by the merge module.

If you use VBScript or JScript to write code for custom actions or


write macros to customize the IDE, you’ll like the new color syntax
highlighting in the code editor. The PDF manuals and the online help
have been rewritten with step-by-step instructions for common tasks
and more detailed technical information. The optional Language Pack
adds pre-translated strings for 20 additional languages to make it easier
to internationalize your applications. Finally, the debugger adds the
ability to step through your installation and troubleshoot problems.

Documentation
The documentation for Wise for Windows Installer 3.0 is extensive
and excellent. The product ships with a Getting Started Guide in both
hard copy and PDF formats. The guide steps you through installing
the product and has chapters that introduce you to Windows Installer
and provide a tour of Wise for Windows Installer and the basics
of creating setups. In addition, the 544-page Reference Manual is
included in PDF format. Coupled with the extensive online help,
these manuals should provide answers to all your questions.

If you want more information to help determine if Wise for


Windows Installer 3.0 is right for you, download the Evaluator’s
Guide. There’s also has a free Windows Installer Resource
Kit. If you are new to Microsoft’s Windows Installer, you’ll
find the Resource Kit worth having. Both are available at
http://www.wisesolutions.com/wisewin.htm.

Versions
Wise for Windows installer is available in Standard and Professional edi-
tions. In addition to the features in the Standard edition, the Professional
edition includes the debugger, macro editor, transform creation wizard,
the ability to create patches, automation support, and the ability to create
custom actions from Wise Installation System 8.0 or higher scripts.

Conclusion
Wise for Windows Installer 3.0 is the best installation tool I have
seen for building Windows Installer setups. The Installation Expert
is a superior marriage of power and ease of use. You’ll be able to
build all but the most complex installations without ever leaving
the expert. However, if you need to create more sophisticated
setups, the Setup Editor provides absolute power by letting you
edit every table in the Windows Installer database. Even in the
Setup Editor, Wise for Windows Installer is easier to use than other
products I’ve seen — thanks to the well-organized tabs and tree
view and the help pane that provides detailed information about
the area of your setup in which you are working. If you need to
build installations using Windows Installer, you can’t go wrong with
Wise for Windows Installer 3.0. ∆

Bill Todd is president of The Database Group, Inc., a database consulting and
development firm based near Phoenix. He is co-author of four database program-
ming books, author of more than 60 articles, a contributing editor to Delphi
Informant Magazine, and a member of Team Borland, providing technical support
on Borland Internet newsgroups. He is a frequent speaker at Borland Developer
Conferences in the US and Europe. Bill is also a nationally-known trainer, and has
taught Delphi programming classes across the country and overseas. Bill can be
reached at billtodd_az@qwest.net.

41 April 2001 Delphi Informant Magazine


File | New
Directions / Commentary

Quality First, Revisited: Part I

I n the July 1998 issue of Delphi Informant Magazine I wrote a column entitled “Quality First: A Challenge to RAD?”
in which I concluded there was no inherent conflict between rapid development and a quality-centered approach to
writing software. I ended that column stating that “by keeping us focused on robustness and fixing errors early [the
Quality First Model] increases our productivity and makes RAD workable.” In examining a new book by Steve McConnell,
I found my view vindicated. Furthermore, the approach to programming articulated by Bertrand Meyer (IEEE’s Computer
Magazine, May 1997) in his Quality First Model seems even more timely today. Therefore, I concluded it was time to
write more about this important topic.

In this two-part column, we’ll discuss three books that help us As the book continues, it considers larger issues of software devel-
understand why and how to put more quality in our development opment, examining the entire profession while providing insight-
projects, and share some of the insights included in those sources. ful analysis and suggestions about its future. Among the topics
These books include two by McConnell: his new book, After the discussed are programming as a profession and the personality
Gold Rush [Microsoft Press, 1999], and his classic, Code Complete traits and training of programmers. In this column, we’ll concen-
[Microsoft Press, 1993]; and an early entry in the Software Qual- trate on what McConnell says concerning quality software (which
ity Institute Series entitled Constructing Superior Software [Mac- he discussed from a different viewpoint in Code Complete).
millan Technical Publishing, 1999, Paul C. Clements, ed.]. After
a capsule review of each of the sources, I’ll share what the authors McConnell’s first work, Code Complete, has become a recognized
have to say about quality in the beginning, quality in the middle, classic in programming literature. Considering the wealth of excel-
and quality at the end. lent information and advice within its pages, this work could
justifiably be titled The Coder’s Bible. While the focus is on writing
This month, we’ll discuss the sources in detail and explore quality good code, other aspects of the development cycle are discussed.
in the beginning. Next month, we’ll delve further and discuss Of course, parts of the book are now dated, because it was written
quality in the middle and quality at the end. There is one theme before the great revolution in design patterns and modeling that
that should resonate throughout: Regardless of one’s particular emerged in the mid-1990s. Still, much of the advice is as relevant
role in software development — independent developer, program- today as when it was written. One aspect I especially like is that
ming team member, team leader, quality assurance specialist, or the coding examples are not just in C/C++; many are in Pascal. If
project manager — these are issues about which we should all be you’ve never read it, you need to.
concerned. Why? Because by engaging them we can learn to work
smarter, as opposed to simply working harder. For managing software projects, Constructing Superior Software is
particularly practical. Each of the three sections focuses on a
The sources. In his latest work, After the Gold Rush, McConnell uses different general theme: Part One, “Quality Systems,” lays the
the analogy of the 1849 California Gold Rush to demonstrate some foundation for creating an effective environment in which to
of the pitfalls for entrepreneurial developers in emerging technologies. create software, with strong arguments for emphasis on reliability
In software “gold rushes” there are opportunities for a handful of and a user-centered development strategy. Part Two, “Quality
bright, hard-working, and — yes — lucky developers to become Design,” discusses software architecture in general, explaining how
extraordinarily successful. Of course you immediately think of a to develop a well-documented, rational design, then plan the
certain Mogul of Redmond. However, McConnell makes it clear why implementation of that design using a component-based approach.
this is such an exception. He spends a good deal of time attacking the Part Three, “Quality Projects,” covers the essential topics of creat-
“code-and-fix” approach favored by hero programmers who prefer to ing and managing software teams, applying measurement to soft-
dive head first into ferocious coding without any benefit of planning ware development, and selecting tools. Part One will be most
or design. He warns against the deceptively impressive initial progress helpful to managers; the last two parts speak more directly to
sometimes found with this approach, calling it “fool’s gold,” because developers. McConnell provides strong arguments as to why you
it can produce a plethora of defects that eventually place us in what should manage software projects intelligently; Constructing Superior
he calls the “Tar Pit.” I’ll have more to say about these issues later. Software explains how.

42 April 2001 Delphi Informant Magazine


File | New
Quality in the beginning. Quality in the beginning equals good
planning. Each of the books puts a great deal of emphasis on
this indispensable stage of software development. In After the
Gold Rush, planning and process management are central themes.
McConnell repeatedly attacks what he calls the “code-and-fix”
approach in which a project’s start is characterized by eager “hero
programmers” who jump straight into coding. Much of the book
provides arguments and data showing why this approach — start-
ing to code before you have half a notion of what you’re doing
— actually delays the completion of the project and negatively
impacts its quality.

Even in his first book, Code Complete, McConnell emphasizes atten-


tion to quality and planning from the beginning, stating on page
51 that “attention to quality at the beginning has a greater influence
on product quality than at the end.” In Chapter 3 of Constructing
Superior Software, the contributors recommend a spiral approach,
wherein developers return to the earlier phases of planning, analysis,
and design when circumstances demand it. This particular chapter
also advocates a user-centered approach to design and development.
The contributors divide the planning stage into the tasks of model-
ing, design, prototyping, and, of course, continually evaluating
each phase. McConnell divides the early stage into requirements,
architecture, and detailed design phases.

As the contributors point out in Chapter 4 of Constructing Supe-


rior Software, for a long time attention to software architecture
was an important missing link between the requirements of gath-
ering and analysis and the detailed design stages of development.
They point out that although architectural design may not be
needed in small and medium-sized projects, it is crucial for large,
complex projects. Architectural design can be applied to various
aspects of a project, such as its functionality, its physical charac-
teristics, and the organization of code. Clearly, incorporating an
architectural design phase as part of the early planning of a large
project can be beneficial in planning the entire project, establish-
ing teams and communication links between teams, and laying a
powerful foundation for building the detail design of the project.
To ensure equality, every stage in the process — including archi-
tectural design — must be put under the microscope of evalua-
tion. Before proceeding, you must be certain that the architecture
meets the needs of the project.

We’ll resume our visit to “Quality First” next month by examining


quality in the middle and ending stages of developing a software
project. Until then ... ∆

— Alan C. Moore, Ph.D.

Alan Moore is a Professor of Music at Kentucky State University, specializing in


music composition and music theory. He has been developing education-related
applications with the Borland languages for more than 15 years. He is the
author of The Tomes of Delphi: Win32 Multimedia API [Wordware Publishing,
2000] and co-author (with John Penman) of an upcoming book in the Tomes
series on Communications APIs. He has also published a number of articles
in various technical journals. Using Delphi, he specializes in writing custom com-
ponents and implementing multimedia capabilities in applications, particularly
sound and music. You can reach Alan on the Internet at acmdoc@aol.com.

43 April 2001 Delphi Informant Magazine

You might also like