Sie sind auf Seite 1von 38

September

2003

Volume 9 Number 9

INSIDE
ON THE COVER
Greater Delphi

Going Native

Need to communicate directly between Delphi and


Java apps? Keith Wood introduces the Java Native
Interface (JNI), which was developed specifically
to make such interaction possible, from creating,
updating, and inspecting Java objects from Delphi, to
calling methods within Java classes.

FEATURES
.NET Tech

13

Creating ASP.NET Apps: Part II

Alexei Fedorov and Natalia Elmanova demonstrate


how to create ASP.NET applications with the Delphi
Compiler for Microsoft .NET, with examples that
illustrate data binding using the Repeater, DataList,
and DataGrid controls, illustrating how to display,
highlight, select, edit, sort, and page data.

Product Review: ExpressQuantumGrid 4 from Developer Express

Delphi Informant

September 2003 vol. 9, no. 9

www.DelphiZine.com

The Complete Monthly Guide to Delphi Development

2003 Readers
Choice Awards
Special C# Magazine
Preview Inside!

Use Java
from Delphi
(and Vice Versa)

with the Java


Native Interface

ASP.NET Apps

with Data Binding Controls

Page 18

The Perils of

Weak Encapsulation

Page 28

Open Source
Resources

Page 48

Cover Art by Arthur A. Dugoni Jr.

In Development

21

The Nature of Encapsulation

Peter Gatis explores one of the three principles of


OOP, encapsulation, especially as its implemented
in the Delphi language. Encapsulation has been
given short shrift over the years, so you may be
surprised by just how difficult it is to achieve strong
encapsulation.

Informant Spotlight

27

Delphi Informant Magazine


Readers Choice Awards 2003

Editor-in-Chief Jerry Coffey reveals the results of


the 2003 Readers Choice Awards winners and
runners-up in 28 categories, including new winners
for Product of the Year and Company of the Year.

REVIEWS
32 ExpressQuantumGrid 4

Product Review by Alan C. Moore, Ph.D.

D E PA R T M E N T S
2 Symposium by Jerry Coffey
3 Toolbox
36 File | New by Alan C. Moore, Ph.D.

DELPHI INFORMANT MAGAZINE | September 2003

S Y M P O S I U M

100 and Going Strong

By Jerry Coffey

It cant possibly be true: 100 issues 100 months, more


or less. The first Delphi Informant hit the streets pretty
much when Delphi did in April 1995. So for more than
eight years now, Delphi and DI have both been making
their way in the world.
Id like to mark the occasion by thanking a select group
of people. First, I must thank those at Borland who created Delphi, sparking the fire that would become the Delphi community this magazine serves. I dont pretend to
know everyone responsible for the creation of Delphi, so
Ill thank the ones I do know about Anders Hejlsberg,
Zack Urlocker, Danny Thorpe, and Chuck Jazdzewski
and humbly apologize to the ones I dont.
Next, Id like to thank the writers. Over 200 authors have
been published in DI over the years, and Im grateful to every
one of them from those that wrote one book review, to the
stalwarts that have written columns for years on end.
Speaking of stalwarts, no one outside of ICG has done
more to shape DI than Alan C. Moore, Ph.D. For one thing,
Alan has been extremely prolific. As of this issue he has written at least 137 separate pieces for DI, including 31 product
reviews, 26 book reviews, and 8 feature articles. Hes also
written an astounding 71 of his popular File | New columns
(this month he tackles Open Source Resources); thats
one-a-month since February of 1998. More important is the
warmth and respect that Alan brings to his work and the
Delphi community. Thanks Alan; youre the heart of DI.
Coincidentally, Bill Todds article in this issue marks his
100th piece for DI. Bill is just the best. His material is always
rock solid; a technical edit is simply unnecessary. An editors
dream, Bill has a knack for picking reader-pleasing topics
and then nailing them so thoroughly and efficiently that his
articles are often the last word on a subject. His tally includes
34 product reviews, 2 book reviews, and a remarkable 64
feature-length articles. Bill is also a go-to guy who I can
rely on to tackle high-profile assignments.
Another go-to guy is Cary Jensen, Ph.D., whose work
is also always rock-solid. With 3 product reviews, 3 book
reviews, and 62 feature-length articles to his credit, Carys
sheer output is impressive, but its the clarity and organization of his work that separates him from most writers.
Thanks Cary; and thanks for being there in the early days of
Paradox Informant.
Unfortunately, I cant thank each writer, but Id be
remiss if I didnt call out a few more who have been
particularly important to this magazine. They are: Keith
Wood, Richard Wagner, Robert Vivrette, Ron Loewy,
Warren Rachele, Clay Shannon, Alexie Fedorov, Natalia
Elmanova, Mike Riley, Rick Spence, Robert Leahey, Dan
Miser, Rod Stephens, David Rippy, Fernando Vicaria, and
Bruno Sonnino. Thank you all!
2

DELPHI INFORMANT MAGAZINE | September 2003

Then there are the people here at ICG that make each
months issue of DI a reality. David Riggs started with
Informant within months of when Delphi 1 shipped, and
has been the magazines Managing Editor for most of
the time since. Dave is The Man. Besides being the best
proof reader Ive ever worked with if youre an editor be jealous, be very jealous Dave is the kind of guy
that holds a magazine together, doing the million-and-one
things it takes to produce a monthly publication. And he
makes it look easy.
One half of our mighty ICG Production Department
(with Diana Nishimura whose work graces our asp.netPRO
magazine), Art Dugoni designed the magazine youre holding, and laid in each article as he does every month. And
those awesome covers? Thats all Art.
A first-class Web site is a requirement for a publication such
as DI, and the man responsible for building and maintaining
DelphiZine.com is Bob Silva. If it takes chewing gum and bailing wire at 2AM on a weekend to keep the various systems up
and running here at ICG and sometimes it does! youll
find Bob in the server room, making things work for all of us.
And although he has been here at ICG a relatively short
time, acting CFO Ed Ring, has been instrumental in keeping this publication alive. Were it not for Ed, I wouldnt be
writing this now. Thanks Ed. Thank you also, Debbie Holmgren and Katie Sullivan, who have brought an incredible
professionalism and vigor to Sales. My only complaint: Why
werent you here sooner!
I especially want to thank Mitch and Nancy Koulouris, who
in 1990 had the vision, guts, grit, and wherewithal to launch a
little publication named Paradox Informant. Mitch invited me
to sign on as editor in 1991, so I decided to change careers and
gamble on a start up. Its been a wild ride ever since and weve
never looked back. Paradox Informant was the first of eight
magazines Mitch and I would launch (DI was the third), and
while some did better than others betcha dont remember
dBASE Informant each is now a treasured memory. There
have been plenty of ups and downs to be sure, but I wouldnt
trade the experience for anything.
Finally, I want to thank you the reader. Youre what this
magazine is all about, and youre foremost in our minds as
we put together issue 101.
Thanks for reading.

Jerry Coffey, Editor-in-Chief


jcoffey@DelphiZine.com

T O O L B O X
wPDF 2.10 and WPTools 4.11 Available
wpCubed released wPDF 2.10, a
PDF creation engine for Delphi and
C++Builder. This version has been
optimized for greater compatibility
with most drawing commands commonly found in Windows applications.
wPDF 2.10 has everything you need
to create PDF files from ReportBuilder,
RAVE, WPTools, THTMLView, ACEReporter, WPForm, QuickReport, FastReport, and ExpressPrinting System.
Ready to use sample code and filter
interfaces are included.
wPDF converts enhanced metafiles to
PDF while preserving the vector and
text information. This results in small
PDF files which can be printed at high
resolution. wPDF supports the usual
PDF features, including compression
and 128-bit encryption and it was the
first Delphi library to allow embedding
of font subsets to reduce file size.

WPTools 4.11 is
a word processing component
suite that has
been enhanced
to function well
with Unicode
characters and
allow table rows
to span multiple
pages. WPTools
4.11 provides a
word processing
component with
WYSIWYG page layout view, mail
merge, hyperlink handling, and the
full set of possible character and
paragraph attributes. The header and
footer handling and text numbering
in standard or outline mode has been
improved. Optional add-ons, such as
WPReporter or wPDF, make it possi-

Graphics Server Technologies Releases Graphics


Server 6.0 and Graphics Server .NET
Graphics Server Technologies
ematical models, flexible missing data
announced the availability of Graphics
options, fast-Fourier transform, and
Server 6.0 and Graphics Server .NET.
limit lines.
Graphics Server 6.0 is the latest ediThe interactive toolbar lets users custion of the companys graphing and
tomize and edit graph elements and
charting toolkit. Graphics Server adds
save customized graph elements as
graphs and charts to applications
templates for reuse with different sets
through the graph control or an extenof data. Interactive hot graphs with
sive API. Features include statistical
tooltips and point-and-click access to
functions, browser-independence, drillsecondary charts and statistical breakdown graphs, broad image support,
downs are also available.
ADO data binding, and comprehensive
Graphics Server 6.0 supports Delphi,
customization features.
Visual Basic, C++, Access, FoxPro,
New features include ADO support,
and Visual Studio.
direct Access and Excel file formats,
Graphics Server .NET is a new comConnect Strings, file format support, font ponent that provides 100 percent mansupport, image compression, gradient
aged code support for Microsofts .NET
fill for 2D graphs, modified color pallets,
development environment.
streamlined installation, and more.
Graphics Server .NET provides a comGraph types include area, pie, bar,
prehensive collection of core business
bubble, line, pareto, floating bar, surand scientific graphing features, includface, tape, time-series, candlestick, scating a variety of graph and chart types;
ter, polar, log/lin, log/log, open-highproperty pages to customize graphs;
low-close, and combination graphs.
statistical overlays; limit lines; mulGraphics Servers advanced data
tiple data sources in a graph or even a
features let you chart over 100,000
series; a resource center with extensive
dynamic data points in a single
Visual Basic and C# code examples;
graph. You can add curve-fitting,
and extensive documentation.
error bars, and trend lines to all log
Graphics Server Technologies, LP
and linear graph variants. Other
Price: Graphics Server 6.0, US$699; Graphics
Server .NET, US$$899. See Web site for upgrade,
advanced statistical functions include
bundle, and multi-license pricing.
maximum, minimum, mean, standard Contact: (206) 625-6900
Web Site: www.graphicsserver.com
deviation, curve fitting on 10 math3

DELPHI INFORMANT MAGAZINE | September 2003

ble to create contracts or similar texts


and export your end product and all
of its features (including hyperlinks
and bookmarks) directly to PDF.
wpCubed GmbH
Price: See the wpCubed Web site for details.
Contact: support@wptools.de
Web Site: www.wptools.de

Set Project Version


Information from the
Command Line
Tiriss announced version 1.0 of
ChangeRes. Using ChangeRes you
can change the version information of Delphi and C++Builder
projects from the command line or
batch file.
Because version information is
stored in the project .res file, which
is a binary file, there is no easy way
to update the version information
of a project if you try to automate
your build process using batch files.
Using ChangeRes, simply add a line
to your batch file and the version of
your project will be set.
Using ChangeRes you can also
update .dof (Delphi) or .bpk
(C++Builder) files with the correct version information; increase or
decrease version numbers; set other
version properties like ProductVersion, FileFlags, and FileDate; and set
version strings like CompanyName,
Copyright, etc.
ChangeRes supports Delphi 3-7
and C++Builder 3-6 project files.
Tiriss
Price: Single-user license, US$20; site license,
US$99.
Contact: info@tiriss.com
Web Site: www.tiriss.com

T O O L B O X
Embed TAPI ActiveX Objects in Delphi Apps

Pingram Marketing announced CT


Messenger 2.0 from Mint Components.
When imported into a Delphi project
this set of ActiveX objects behave as
if they were a Delphi component.
CT Messenger 2.0 provides a set of
scriptable COM objects that enable
a Windows or Web application to
bring important information to its
users in the form of text pages,
phone calls, or SMS messages via any
TAPI-compliant hardware, including
a voice modem or telephony card.
CT Messenger uses software DSP
algorithms for detecting the type of
response (busy, no answer, voice
answer). CT Messenger software
does not rely on the answer detection
capabilities of the underlying
hardware, and it works with
inexpensive voice modems.
Using CT Messenger, simply create
a call tree with a message consisting of some text or the names of
pre-recorded voice files (or both),
one or more numbers to call, call

time interval, etc., and submit it for


processing. The call will be scheduled and processed with a detailed
report generated automatically. A
report provides information on the
time and duration of the call, the
type of answer detected, and the keys
pressed by the recipient.
CT Messenger standard features
include: dialing-out over any TAPIcompliant voice modem or telephony
card; built-in call and page scheduling and processing; software answer
detection-identification (busy, no
answer, voice); built-in automatic
text-to-speech conversion; unlimited call tree depth; processing onemessage-to-many-phone-numbers
requests; merging pre-recorded voice
files and text messages; recognizing
buttons pressed by the recipient of
the call; sending text messages to
any pager or SMS-enabled cell phone;
generating detailed reports on calls
made/canceled/failed and pages sent;
using several voice modems and/or

Gnostice QuickReport Export 3.01 Released


Gnostice announced a new release of
customization in PDF, HTML, and
Gnostice QuickReport Export.
XHTML filters; an enhanced Excel
QuickReport Export is a suite of
filter, which saves to a Workbook
export filters for QuickReport. You
with the option to split report pages
can save your QuickReport reports
to separate Worksheets (the Excel
to PDF, RTF, HTML, XHTML, Excel,
filter saves images, shapes, RichText,
Text, GIF, JPEG, BMP, EMF, and WMF and text objects); intelligent cell
file formats. It is available for Delphi
formatting in Excel, which enables
4-7 and C++Builder 5 and 6.
cells to adopt the same data type as
Version 3.01 is 100% Native Delphi,
a QRDBTexts DataField, with supcompiles into your executable, and
port for Integer, Double, Currency,
doesnt require any additional softTime, Date and String types; continuware.
ous mode exporting support in Excel
Version 3.01 includes built-in
and Text filters enables multi-page
run-time configuration dialogs,
tabular reports to be exported in a
which give full control to the end
single flow, without headers and
user; built-in support for e-mailing
footers appearing for each page; and
exported documents; a PDF filter that
the ability to set background image/
supports compression, encryption,
watermark and background color for
TrueType font embedding, and encod- the exported document.
ing to support Eastern European,
Visit the Gnostice Web site for the
Greek, Chinese, Japanese, Korean,
complete feature list.
Russian, Thai, and other character
sets; the Export CompositeReport,
Gnostice Information Technologies
Price: Standard Edition, single-developer license,
which combines multiple reports into
US$119. Multi-developer license discounts are
a single file; automatic enabling of
available. Professional Edition, single-developer
hyperlinks in PDF, RTF, HTML, and
license, US$219. Multi-developer license discounts are available. See the Web site for comXHTML; enhanced presentation feaplete upgrade details.
tures, such as page transition effects,
Contact: info@gnostice.com
page autoscrolling, and viewer UI
Web Site: www.gnostice.com
4

DELPHI INFORMANT MAGAZINE | September 2003

telephony cards simultaneously; storing and manipulating pre-recorded


voice files; using one calling and paging server by a number of intranet
users concurrently; and more.
CT Messenger was tested using Delphi, C++Builder, Visual Basic, and
Visual C++.
Pingram Marketing
Price: 1-2 lines, US$99; 3 or more lines, US$69.
Contact: info@ivrsoft.com
Web Site: www.ivrsoft.com

Internet-aware
SkyDocImage 7 Available
SkyLine Tools Imaging announced
the shipping of SkyDocImage, Internet
Enhanced. This royalty-free document
imaging package comes complete
with full source code for Delphi.
New features include comprehensive
TIFF support; a fast TWAIN manager;
a powerful Expervision TypeReader
Pro or Enterprise OCR gateway; seven
anti-aliasing and scale-to-grey algorithms; zoom, scroll, and pan; a
thumbnail manager; and annotation
capabilities that allow users to mark
up images on screen and save them
either with or without the document.
The package features the original
executable as well as the complete
source code, so SkyDocImage can be
used out of the box as a stand-alone
document imaging solution or it can
be fully customized. With source
code included, developers can use
SkyDocImage as-is or modify features for specific development needs.
This Internet-aware version allows
developers and imaging professionals to easily send, receive, and view
scanned TIFF documents (as well
as other formats) across intranets,
extranets, and the Internet. Programmers who license SkyDocImage can send images to FTP sites
through standard TCP/IP connections. You can even scan directly
via FTP. End-users can receive and
view TIFF images from URLs and
FTP sites using TCP/IP.
SkyLine Tools Imaging
Price: Contact SkyLine Tools for details.
Contact: sales@imagelib.com
Web Site: www.imagelib.com

T O O L B O X
Hurricane Software Releases Hurricane Editor 3
Hurricane Software
announced Hurricane
Editor 3, a syntaxhighlighting editor
that supports more
than 40 file types,
including Delphi,
C/C++, and C#.
Designed to enhance
the productivity of
software developers, it integrates with
other Hurricane Software products.
Hurricane Editor 3
provides fully customizable syntax highlighting to quickly
distinguish elements
such as variables, literals, comments, and
primitives within source code. Syntax
highlighting improves productivity by
providing fast and easy recognition of
source code elements for maintenance
and debugging.
Other features include an integrated
file explorer for rapid point-and-click
access to files and directories; block
indent support to quickly perform
block editing tasks; support for Unix,
Mac, and DOS line ending file types to
accommodate todays heterogeneous

development environments; convenient reopen lists for quick access to


recently used files; editor pane management to simplify reordering of open
files; search and replace; word wrapping; a macro recorder; and more.
Hurricane Editor 3 supports Windows 95/98/NT/ME/2000/XP.
Hurricane Software, Inc.
Price: US$49 per seat.
Contact: mail@hurricanesoft.com
Web Site: www.hurricanesoft.com

TeamShare Announces TeamTrack 6.0


TeamShare announced the availability of TeamTrack 6.0, the newest
edition of its business process management tool. A new user interface,
a management dashboard portal, and
several new and enhanced features
extends TeamTrack from departmental
applications to true enterprise-wide
business process management.
Previous releases have focused
on functionality and architectural
improvements; TeamTrack 6.0 represents effort toward improving the
end-user browser experience. TeamTracks focus expands, from tracking
issues as they relate to different stages of a lifecycle, to providing a cross
departmental view of issues and their
health, to comprehensively managing
the community of business processes
within an organization.
To this end, the new user interface
contains tabs that can represent a
5

variety of business processes. One


example might be the different phases of a development cycle, such as
enhancement requests, development
tasks, or support incidents. Workflows for each tab can easily allow
posting between one to the next,
depicting real progression through
the various processes lifecycles. The
new tabbed interface allows departmental users across the enterprise to
interact with their TeamTrack system
without being distracted by information tracked by other departments. It
also allows users who interact with
TeamTrack across a variety of business functions to keep track of where
they are in the TeamTrack system.
TeamTracks new look and feel is a
significant usability improvement and
includes a series of tabs that display
at the top of the browser interface.
Each tab represents a separate solu-

DELPHI INFORMANT MAGAZINE | September 2003

ComponentOne Studio
Enterprise Integrated
with C#Builder for .NET
ComponentOne announced ComponentOne Studio Enterprise for Borland C#Builder. This special edition
of ComponentOne Studio Enterprise
is now integrated with C#Builder
for the Microsoft .NET Framework.
Customers who purchase C#Builder
for the Microsoft .NET Framework
will receive a special integrated
edition of ComponentOne Studio
Enterprise that includes a development and deployment license for all
ComponentOne Studio Enterprise
.NET (WinForms) and ASP.NET
(WebForms) components.
ComponentOne Studio Enterprise
for Borland C#Builder is a
suite of components, including
grid, reporting, charting, data,
user interface, and eCommerce
components for .NET and ASP.NET.
Popular .NET WinForms components
include True DBGrid for .NET,
FlexGrid for .NET, Reports for .NET,
Preview for .NET, Chart for .NET,
DataObjects for .NET, Input for .NET,
List for .NET, Zip for .NET, Menus
and Toolbars for .NET, and Spell
for .NET. ASP.NET WebForms
components include WebGrid
for ASP.NET, WebReports for
ASP.NET, WebChart for ASP.NET,
WebDataObjects for ASP.NET,
WebMenus and WebBars for ASP.NET,
and PayPal eCommerce for ASP.NET.
ComponentOne LLC
Price: Full version, US$899.95. Owners of Borland
C#Builder for the Microsoft .NET Framework, or any
APEX, VideoSoft, or ComponentOne product, can
upgrade to ComponentOne Studio Enterprise for
US$599.95.
Contact: info@componentone.com
Web Site: www.componentone.com/borland

tion that allows the TeamTrack user


to clearly differentiate items between
areas such as departments or business functions across the enterprise.
Each tab can have its own home page
showing a default report or series of
reports for that solution. In addition,
each tab can filter the users view.
TeamShare, Inc.
Price: Contact TeamShare
Contact: inquiries@teamshare.com
Web Site: www.teamshare.com

G R E A T E R
JAVA NATIVE INTERFACE

JAVA

D E L P H I

JBUILDER

DELPHI 6, 7

By Keith Wood

Going Native
Part 1: Using the Java Native Interface with Delphi

ava and Delphi serve different purposes as


programming languages, each with their
own advantages and disadvantages. They

can easily communicate by transferring data via


files, sockets, or Web Services. However, there are
times when you may want to converse between
the two in a more direct manner. The Java Native
Interface (JNI) was developed for such interaction, and this article introduces you to using Delphi and Java through the JNI.

JNI allows bi-directional calling between Java and native


(e.g. Delphi) code. You can create, update, and inspect Java
objects from within your native code. You can call methods
(both static and non-static) within Java classes. You can
capture and deal with Java exceptions within native code, or
generate exceptions back to the Java runtime.
Java Type

Delphi Type

Type Name

Signature

boolean

Boolean

JBoolean

byte

ShortInt

JByte

char

WideChar

JChar

double

Double

JDouble

float

Single

JFloat

int

Integer

JInt

long

Int64

JLong

short

SmallInt

JShort

void

N/A

N/A

Figure 1: Corresponding Java and Delphi types.

DELPHI INFORMANT MAGAZINE | September 2003

Some reasons that you might want to call native code from
Java include: gaining access to platform-specific features not
available in Java, reusing existing code libraries already in
native format for which you do not have the source code or the
time to port, or for running time-critical or CPU-hungry routines in a faster environment. Similarly, you may want to call
Java from native code to use existing packages and APIs, or to
gain access to Java-specific constructs, such as RMI and EJBs.
Although originally developed with C and C++ as the
target native languages, the efforts of Matthew Mead have
produced a Pascal translation of the JNI suitable for use in
Delphi. The package is available from Matthews Web site
(see the References section at the end of this article).
Included in the package are several examples and tutorials
to get you started.
Java Types
Communication between the two environments consists
of making method calls and passing parameters back and
forth. The arguments may be either primitive types or complete objects. Obviously there needs to be some mapping
between the basic types in Java and those in Delphi to facilitate their transfer. The JNI.pas and JNI_MD.inc files contain
these mappings, as shown in Figure 1. So, wherever you use
a particular type in Java, you should use the corresponding
J* type defined in Delphi. Behind the scenes these are just
renamings of the associated basic Delphi types.
Every other type is passed generically as an object and is
referred to in Delphi as JObject. Several renamings of this
base type appear, including JString, JClass, and JArray (and
its derivatives).
Associated with each type is a signature character. This
short form is used to identify types for fields, and for the
return and parameter types of methods. Class types have

Greater

Delphi

Going Native

package mypkg;
public class MyClass {
static {
System.loadLibrary("MyLib");
}
public native void doIt(String message);
}

Figure 2: Loading a native library from Java.

a signature that includes the full package and class name


(replacing periods, ., with slashes, /), prefixed by L
and suffixed by a semi-colon ( ; ), such as Ljava/awt/
Rectangle;. Array references are prefixed by an opening
bracket ( [ ), one for each dimension. Thus, the signature
[[I represents a two-dimensional array of integers.
Method Declarations
Java methods can be linked to external routines through the
use of the native modifier, as shown below from the Object
class. Such a method has no body (because this is provided
by the external library), but is not declared as abstract:
public final native Class getClass();

Your native code is kept in a shared library a DLL under


Windows or an SO under Linux. To make the library available within Java you must include a static initializer in your
class (see Figure 2). The appropriate prefix and extension
are added to the base library name depending on your platform. Thus the class in Figure 2 looks for MyLib.dll on Windows, or libMyLib.so on Linux.
The signatures of the routines within your native library
must follow specific conventions to be useable from Java.
First, they must be named in a particular format:
Java_<full_class_name>_<methodName><__overloaded_signature>

where <full_class_name> is the full package and class name,


with periods replaced by underscores. Remember that,
unlike Delphi, case is important in Java and that this carries
over into these method names. Always use the same case as
appears in the Java declarations.
Native methods with overloaded versions must include a suffix that indicates which method signature is being referenced.
Using the signature characters described earlier, append these
to the method name, following two underscores. In addition,
certain characters that cannot appear in a method name must
be escaped: Use _1 for _, _2 for ;, and _3 for [. Thus,
the getClass method previously referred to becomes:

Every routine must take at least two parameters: a reference to the JNI environment, and a reference to the
object making this call (or class if static). Additional
parameters are included to match those of the Java declaration. Also, the routines must follow the standard library
calling convention for the platform: stdcall on Windows
or cdecl on Linux. Thus, the full Delphi signature for the
doIt method defined in Figure 2 is:
procedure Java_mypkg_MyClass_doIt(PEnv: PJNIEnv;
Obj: JObject; message: JString);
{$IFDEF WIN32} stdcall; {$ENDIF}
{$IFDEF LINUX} cdecl; {$ENDIF}

Finally, these routines must be exported from the library to


make them accessible from Java:
exports Java_mypkg_MyClass_doIt;

The JNI Environment


The first parameter in any native method call is a pointer
reference to the JNI environment, PEnv. Its through this
that you access the Java runtime. Delphi/JNI includes a
class wrapper, TJNIEnv, for this pointer to make it easier to
deal with. Thus the body of your methods often includes
the code shown in Figure 3.
Through the environment object you can load classes and
create instances of them (FindClass, NewObjectA, etc.),
access the fields and methods of an object (GetIntField,
CallObjectMethod, etc.), work with arrays (NewByteArray,
GetCharArrayElements, etc.), and handle and generate
exceptions (ExceptionOccurred, ThrowNew, etc.). Have a
look at the source code (available for download; see end of
article for details), or use CodeInsight, for the full list.
JavaD
The Java Development Kit (JDK) comes with a tool, javah.exe,
that generates appropriate header and source files for using
JNI with C. To make it easier to use Delphi with Java, Ive
developed a similar tool that generates the appropriate Delphi
(Pascal) skeleton for native methods. (Matthew includes a
similar one named JavaToDPR in the Delphi/JNI package.)
The tool I developed is implemented as a Java class,
wood.keith.opentools.javad.JavaD, which is accessible via a
number of channels. You may call this class main method
from the command line, passing an optional flag, -o, to
indicate the overwriting of existing files, the full name of the
class to examine, and the location of the directory where the
resulting file is to be placed. The generated file is named the
same as the full class name provided (replacing periods, .,
with underscores, _), with a .dpr extension:

Java_java_lang_Object_getClass

in Delphi, and the overloaded wait routine from the Object class:

java -cp <path to both classes>


wood.keith.opentools.javad.JavaD
-o wood.keith.djniexample.Example1 c:\Projects\DJNI

public final native void wait(long timeout);

becomes:
Java_java_lang_Object_wait__J

DELPHI INFORMANT MAGAZINE | September 2003

where <path to both classes> contains the directories at the


top of the class file hierarchies for the two classes, separated
by a semi-colon ( ; ).

Greater

Delphi

Going Native

procedure Java_mypkg_MyClass_doIt(PEnv: PJNIEnv;


Obj: JObject; Message: JString);
{$IFDEF WIN32} stdcall; {$ENDIF}
{$IFDEF LINUX} cdecl; {$ENDIF}
var
JVM: TJNIEnv;
begin
// Create an instance of the Java environment.
JVM := TJNIEnv.Create(PEnv);
try
// Perform the task for this routine.
finally
JVM.Free;
end;
end;

Figure 3: A Delphi JNI routine skeleton.

The Delphi code produced includes the library declaration,


skeletons like Figure 3 for each public native method (thats
not derived from Object) found in the nominated class, and
an exports clause for each such routine.
Alternatively, you can access the generator via a JBuilder
OpenTool thats included in the package. Simply place the
tools JAR file into your JBuilder/lib/ext directory, and restart
JBuilder. In the Object Gallerys (File | New on the menu) General tab, you now have an icon for JavaD. Start it up, enter
the class and output directory names, and proceed to generate
the Delphi skeleton (and optionally open it in JBuilder).
Finally, to demonstrate how to call Java code from Delphi,
youll see later how to invoke the generator from a Delphi
GUI. You can easily add code to the routines to perform the
appropriate tasks after the Delphi skeleton is generated from
your Java class declarations.
Java Calling Delphi
To illustrate how to call Delphi code from Java, suppose you
have some data in a Delphi-accessible database that you
wish to use in your Java application. If an appropriate JDBC
driver (Javas version of ODBC) isnt available, you could
call a Delphi library to retrieve it instead. For this example,
query the BioLife database that ships with Delphi to find fish
that meet certain criteria. Matching entries have their details
collated into a data value object (an object with fields only,
a bit like a Pascal record) thats defined in Java, and are
passed back to the calling code in an array. If no matches are
found, an exception is raised to indicate the problem.
Start by defining your Java class, wood.keith.djniexample.Example1,
and its native methods (as shown in Figure 4). In
addition to the database search methods, theres a
printMessage method to show how Delphi can write to
the Java console.
As mentioned, any matching database records are placed
into a data value object for transfer back to the Java
application. The definition of that object is shown in
Figure 5. It consists mainly of a number of fields (corresponding to the database fields of interest) and their
accessor methods. Also included is an override of the
standard toString method to make it easier to display
these objects after theyve been retrieved.
8

DELPHI INFORMANT MAGAZINE | September 2003

The Delphi Code


After running the JavaD tool on the Example1 Java
class, you obtain the skeleton Delphi library file,
wood_keith_djniexample_Example1.dpr, the final version of
which is shown in Listing One (beginning on page 11).
Aside from the searchBioLife routine, and the central
statements in each of the native implementations, all
this code is generated for you.
Within the Delphi code, each getBioLife routine delegates to a
common function, searchBioLife, passing along the JVM reference, and a WHERE clause for the database query that reflects
the original parameters. Within searchBioLife, you create the
query object, set its properties, and open the query.
An exception is thrown within the Java application via
the JVM.ThrowNew call, if no records match the given
criteria. To achieve this, you first need a reference to
the exception class being created. The earlier call to
JVM.FindClass returns that class reference, given the full
name of the required class (with periods replaced by
slashes). Note that throwing this Java exception does not
halt processing within the Delphi code. You should exit
the routine immediately after the call. The exception is
caught normally within the Java code, and the message
and stack trace are displayed as expected.
When matching records are found, each one is read and has
its field values copied into a new Java BioLife object. Again,
you call JVM.FindClass to locate the data value class, then
JVM.NewObjectA to create an instance of that class. A particular constructor for the class is selected by identifying its parameter signature within a JVM.GetMethodID call. The constructors ID is passed into the creation call, along with an array of
values matching that signature in number and type.
To make JNI easier to use, Ive included a JNIUtils unit with
the code. Among its features is a function to convert a Java
version of a method signature into the coded form described
earlier. For example:
GetJavaMethodSig(
'void (int, String, String, String, int, double)')

returns:
'(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;ID)V'

relieving you from having to remember the actual type


codes. This method is used within the CreateObject call to
help locate the appropriate constructor to use. The unit
also includes a constant, ConstructorName, that holds the
internal Java name for an object constructor. The use of
this unit is controlled within this demonstration code by
the JNIUTILS conditional define.
Basic class types, such as String and Object, can be used
in the Java signatures call above without specifying
their full path. This is because they have had their
short name previously registered against the full class
name. The common types are predefined, but you can
add your own shortcuts to this mechanism by calling

Greater

Delphi

Going Native

package wood.keith.djniexample;
/* Demonstrate JNI access to Delphi library. */
public class Example1 {
static {
System.out.println("Library path: " +
System.getProperty("java.library.path"));
// Load the native library.
System.loadLibrary("wood_keith_djniexample_Example1");
}

/* Value object for BioLife records. */


class BioLife {
private int _speciesNo;
private String _category;
private String _commonName;
private String _speciesName;
private int _lengthCM;
private double _lengthIN;
public BioLife(int speciesNo, String category,
String commonName, String speciesName,
int lengthCM, double lengthIN) {
_speciesNo = speciesNo;
_category = category;
_commonName = commonName;
_speciesName = speciesName;
_lengthCM = lengthCM;
_lengthIN = lengthIN;
}

public Example1() {}
/* Display the message to the console.
* @param message the text to display */
public static native void printMessage(String message);
/* Find all BioLife database records.
* @return an array of matching BioLife records,
*
empty if none
*/
public native BioLife[] getBioLife();

public int getSpeciesNo() { return _speciesNo; }


public String getCategory() { return _category; }
public String getCommonName() { return _commonName; }
public String getSpeciesName() { return _speciesName; }
public int getLengthCM() { return _lengthCM; }
public double getLengthIN() { return _lengthIN; }
public String toString() {
return _commonName + " (" + _speciesName +
") - length " + _lengthCM + "cm (" +
(Math.round(_lengthIN * 100) / 100.0) + "in)";
}

/* Find BioLife database records matching given category.


* @param category the (partial) category to match
* @return an array of matching BioLife records,
*
empty if none
*/
public native BioLife[] getBioLife(String category);
/* Find BioLife database records matching given lengths.
* @param minLength the minimum length required
* @param maxLength the maximum length required
* @return an array of matching BioLife records,
*
empty if none
*/
public native BioLife[] getBioLife(
int minLength, int maxLength);
// ...supporting code removed...
/* Demonstrate calling native methods.
* @param args command-line parameters
public static void main(String[] args) {
Example1 example1 = new Example1();
printMessage("Starting example1");
example1.performSearch();
example1.performSearch("Ray");
example1.performSearch("XRay");
example1.performSearch(20, 40);
printMessage("Ending example1");
}

*/

Figure 4: Example native methods to access the BioLife database.

AddCommonJavaClass and supplying the full class name,


and an optional shortcut name (the class name without
the package is used by default).
The array that is the result of the searchBioLife function
is created through the JVM.NewObjectArray call, which
takes the number of items in the array, the type of object
stored in the array, and a set of initial values (or nil for
none). Each BioLife object is added to the array with the
JVM.SetObjectArrayElement call. Back in Java, the array is
stepped through, and the toString method of each BioLife
object allows us to easily display the results.
Running Native Code from Java
When your Delphi library is compiled, you must place it
where the Java code can find it (somewhere on the system
path). The first line in the static initializer for the Java
class prints out the full path used to locate the library, as
retrieved from the java.library.path system property, to
9

DELPHI INFORMANT MAGAZINE | September 2003

Figure 5: A data value object for BioLife records.

assist in resolving loading problems. Then you can run the


Example1 class via its main method:
java -cp <path to class> wood.keith.djniexample.Example1

where <path to class> is the directory at the top of your Java


class file hierarchy.
The resulting output should look like that shown in Figure 6. You
can see the BioLife entries found, as well as the exception generated when no matches result. Note that the console output from
the Delphi printMessage procedure (the time-stamped entries) is
not synchronized with output produced by the Java class.
Conclusion
The Java Native Interface lets you call native code from Java
code, or vice versa. A Delphi version of the JNI is available
because of the efforts of Matthew Mead. Create your Java class
with its native method declarations, add the JNI unit to your
Delphi library, follow certain naming and parameters conventions, and your interactions with Java follow effortlessly. To
call native code from Java, use the JavaD class that accompanies this article to generate Pascal skeletons for Java
native methods. Then complete the routines to implement
your native code requirements. The JNIUtils unit can make
interactions with the JVM a little less onerous by encoding
type and method signatures for you, as well as by handling
the various steps involved in calling a method or retrieving
a field value on a Java object.
The demonstration program described herein calls Delphi
code from a Java class to extract data from a database.

Greater

Delphi

Going Native

Searching fish for everything


Found Clown Triggerfish (Ballistoides conspicillum) length 50cm (19.69in)
Found Red Emperor (Lutjanus sebae) length 60cm (23.62in)
:
Found Senorita (Oxyjulis californica) length 25cm (9.84in)
Found Surf Smelt (Hypomesus pretiosus) length 25cm (9.84in)
Searching fish for "Ray"
Found Bat Ray (Myliobatis californica) length 56cm (22.05in)
Found Spotted Eagle Ray (Aetobatus narinari) length 200cm (78.74in)
Searching fish for "XRay"
java.lang.Exception: No matching fish found
at wood.keith.djniexample.Example1.getBioLife
(Native Method)
at wood.keith.djniexample.Example1.performSearch
(Example1.java:74)
at wood.keith.djniexample.Example1.main
(Example1.java:116)
Found none
Searching fish between 20 and 40cm
Found Blue Angelfish (Pomacanthus nauarchus) length 30cm (11.81in)
Found Firefish (Pterois volitans) length 38cm (14.96in)
Found Redband Parrotfish (Sparisoma Aurofrenatum) length 28cm (11.02in)
Found French Grunt (Haemulon flavolineatum) length 30cm (11.81in)
Found Redtail Surfperch (Amphistichus rhodoterus) length 40cm (15.75in)
Found Senorita (Oxyjulis californica) length 25cm (9.84in)
Found Surf Smelt (Hypomesus pretiosus) length 25cm (9.84in)
Starting example1 at 14/04/2003 10:39:30 PM
Ending example1 at 14/04/2003 10:39:33 PM

Figure 6: Output from running the Example1 Java class.

10

DELPHI INFORMANT MAGAZINE | September 2003

Matching records are copied to Java-defined data value


objects and added to an array. The array is then passed back
to Java for its contents to be displayed. A Java exception
is thrown if no matches are found, leaving it to the calling
class to deal with the error.
In Part II youll see how to invoke Java classes from Delphi
code, fulfilling the bi-directional promise of JNI. Until then,
you can download the Delphi/JNI package and look at the
examples and documentation that it provides. With Java and
Delphi now on speaking terms, the possibilities are greatly
expanded for both.
References
JNI Specification: http://java.sun.com/j2se/1.4.1/docs/
guide/jni/index.html
JNI FAQ: http://java.sun.com/products/jdk/faq/jnifaq.html
Delphi/JNI Home: http://home.pacifier.com/~mmead/jni/
delphi/index.html
JavaD and the Java and Delphi demo programs referenced in
this article are available for download on the Delphi Informant Magazine Complete Works CD located in INFORM\
2003\SEP\DI200309KW.

Keith Wood hails from Australia, where he is a consultant working with


Java and Delphi, and a freelance technical writer. He started using Borlands
products with Turbo Pascal on a CP/M machine. His book, Delphi Developers
Guide to XML from Wordware, covers many aspects of XML from a Delphi
point of view. You can reach him via e-mail at kbwood@iprimus.com.au.

Greater

Delphi

Going Native

Begin Listing One Delphi implementation of Example1 methods


library wood_keith_djniexample_Example1;
{ Pascal skeleton for using JNI with the
wood.keith.djniexample.Example1 Java class.
Generated Thu Apr 03 22:44:28 GMT+10:00 2003 by JavaD.
Updated by Keith Wood (kbwood@iprimus.com.au). }
uses
SysUtils, JNI,
{$IFDEF JNIUTILS}
JNIUtils,
{$ENDIF}
DB, DBTables;
{ Java declaration:
public static native void printMessage(java.lang.String)
Class: wood.keith.djniexample.Example1
Method: printMessage
Signature: (Ljava/lang/String;)V
Display the message provided. }
procedure
Java_wood_keith_djniexample_Example1_printMessage(
PEnv: PJNIEnv; Obj: JObject; message: JString);
{$IFDEF WIN32} stdcall; {$ENDIF}
{$IFDEF LINUX} cdecl; {$ENDIF}
var
JVM: TJNIEnv;
begin
JVM := TJNIEnv.Create(PEnv);
try
Writeln(JVM.JStringToString(Message) + ' at ' +
DateTimeToStr(Now));
finally
JVM.Free;
end;
end;
{ Search BioLife database, given a query,
and return matches.}
function searchBioLife(JVM: TJNIEnv;
QueryWhere: string): JObjectArray;
var
BioLifeQuery: TQuery;
ExceptionClass: JObject;
BioLifeClass: JObject;
{$IFNDEF JNIUTILS}
ConstructorId: JMethodID;
{$ENDIF}
BioLifeObj: JObject;
Index: Integer;
begin
Result
:= nil;
BioLifeQuery := TQuery.Create(nil);
try
// Find exception classes.
ExceptionClass := JVM.FindClass('java/lang/Exception');
if not Assigned(ExceptionClass) then
Writeln('Cannot find Exception class');
// Find BioLife value object class...
BioLifeClass :=
JVM.FindClass('wood/keith/djniexample/BioLife');
if not Assigned(BioLifeClass) then
Exit;
{$IFNDEF JNIUTILS}
// ...and its constructor.
ConstructorId := JVM.GetMethodID(BioLifeClass,
'<init>', '(ILjava/lang/String;Ljava/lang/String;' +
'Ljava/lang/String;ID)V');
if not Assigned(ConstructorId) then
Exit;
{$ENDIF}
// Run the query.
with BioLifeQuery do begin
DatabaseName := 'DBDemos';

11

DELPHI INFORMANT MAGAZINE | September 2003

SQL.Text
:= 'select BioLife."Species No", ' +
'Category, Common_Name, BioLife."Species Name", ' +
'BioLife."Length (cm)", Length_In ' +
'from BioLife where ' + QueryWhere;
Open;
if RecordCount = 0 then begin
JVM.ThrowNew(
ExceptionClass, 'No matching fish found');
Exit;
end;
// Create the result array.
Result := JVM.NewObjectArray(
RecordCount, BioLifeClass, nil);
Index := 0;
while not EOF do begin
// Create a BioLife object and populate it.
{$IFDEF JNIUTILS}
BioLifeObj := JNIUtils.CreateObject(JVM,
'wood.keith.djniexample.BioLife',
'void (int, String, String, String, int, double)',
[FieldByName('Species No').AsInteger,
FieldByName('Category').AsString,
FieldByName('Common_Name').AsString,
FieldByName('Species Name').AsString,
FieldByName('Length (cm)').AsInteger,
FieldByName('Length_In').AsFloat]);
{$ELSE}
BioLifeObj := JVM.NewObjectA(BioLifeClass,
ConstructorId, JVM.ArgsToJValues(
[FieldByName('Species No').AsInteger,
FieldByName('Category').AsString,
FieldByName('Common_Name').AsString,
FieldByName('Species Name').AsString,
FieldByName('Length (cm)').AsInteger,
FieldByName('Length_In').AsFloat]));
{$ENDIF}
if not Assigned(BioLifeClass) then
Exit;
// Add it to the array.
JVM.SetObjectArrayElement(
Result, Index, BioLifeObj);
Inc(Index);
Next;
end;
Close;
end;
finally
BioLifeQuery.Free;
end;
end;
{ Java declaration: public native
wood.keith.djniexample.BioLife[] getBioLife()
Class: wood.keith.djniexample.Example1
Method: getBioLife
Signature: ()[Lwood/keith/djniexample/BioLife;
Find all BioLife records. }
function
Java_wood_keith_djniexample_Example1_getBioLife__(
PEnv: PJNIEnv; Obj: JObject; Category: JString):
JObjectArray; {$IFDEF WIN32} stdcall; {$ENDIF}
{$IFDEF LINUX} cdecl; {$ENDIF}
var
JVM: TJNIEnv;
begin
JVM := TJNIEnv.Create(PEnv);
try
Result := searchBioLife(
JVM, 'BioLife."Length (cm)" > 0');
finally
JVM.Free;
end;
end;
{ Java declaration: public native

Greater

Delphi

Going Native

wood.keith.djniexample.BioLife[]
getBioLife(java.lang.String)
Class: wood.keith.djniexample.Example1
Method: getBioLife
Signature: (Ljava/lang/String;)
[Lwood/keith/djniexample/BioLife;
Find BioLife records like a given category. }
function Java_wood_keith_djniexample_Example1_
getBioLife__Ljava_lang_String_2(
PEnv: PJNIEnv; Obj: JObject; Category: JString):
JObjectArray; {$IFDEF WIN32} stdcall; {$ENDIF}
{$IFDEF LINUX} cdecl; {$ENDIF}
var
JVM: TJNIEnv;
begin
JVM := TJNIEnv.Create(PEnv);
try
Result := searchBioLife(JVM, 'Category like "%' +
JVM.JStringToString(Category) + '%"');
finally
JVM.Free;
end;
end;
{ Java declaration: public native
wood.keith.djniexample.BioLife[] getBioLife(int, int)
Class: wood.keith.djniexample.Example1
Method: getBioLife
Signature: (II)[Lwood/keith/djniexample/BioLife;
Find BioLife records with length (cm) in a given range. }
function
Java_wood_keith_djniexample_Example1_getBioLife__II(
PEnv: PJNIEnv; Obj: JObject; MinLength: JInt;
MaxLength: JInt): JObjectArray;
{$IFDEF WIN32} stdcall; {$ENDIF}
{$IFDEF LINUX} cdecl; {$ENDIF}
var
JVM: TJNIEnv;
begin
JVM := TJNIEnv.Create(PEnv);
try
Result := searchBioLife(JVM, 'BioLife."Length (cm)" ' +
'between ' + IntToStr(MinLength) +
' and ' + IntToStr(MaxLength));
finally
JVM.Free;
end;
end;
exports
// Make the routines available for external use.
Java_wood_keith_djniexample_Example1_printMessage,
Java_wood_keith_djniexample_Example1_getBioLife__,
Java_wood_keith_djniexample_Example1_getBioLife__
Ljava_lang_String_2,
Java_wood_keith_djniexample_Example1_getBioLife__II;
end.

End Listing One

12

DELPHI INFORMANT MAGAZINE | September 2003

. N E T
ASP.NET

T E C H

DELPHI FOR .NET COMPILER PREVIEW

DELPHI 7

By Alexei Fedorov and Natalia Elmanova

Creating ASP.NET Apps


Part II: Web Forms and Data Binding Controls

n Part I of this series (see the August 2003 issue


of Delphi Informant) we introduced one of the
most powerful technologies of the Microsoft .NET

platform: ASP.NET. We addressed common features of


ASP.NET, creating Web forms, and using server controls. This article continues those topics and discusses
creating ASP.NET database applications.

To create ASP.NET database applications, we must use


the ADO.NET universal data access mechanism, discussed
in Using the .NET Compiler Part III: Creating ADO.NET
Applications (see the March 2003 issue of Delphi Informant). ADO.NET classes provide a way of accessing and
editing data; however, if we need to provide our users
with a friendly interface to ADO.NET functionality, we
also must use data binding controls.
Namespace

Description

System.Data

A set of core ADO.NET classes, including classes (e.g. DataSet), that make up
the disconnected part of the data access
architecture.

System.Data.Common

Utility classes and interfaces inherited


and implemented by .NET data providers.

System.Data.SqlClient

SQL Server .NET data provider.

System.Data.OleDb

OLEDB .NET data provider.

System.Data.SqlTypes

Classes and structures for native SQL


Server data types. These classes provide a
safer, faster alternative to other data types.

System.Xml

Classes, interfaces, and enumerations


that provide standards-based support
for processing XML.

Figure 1: ADO.NET-related namespaces implemented in the Microsoft .NET


Framework.

13

DELPHI INFORMANT MAGAZINE | September 2003

This article will introduce the data binding controls available


in ASP.NET forms. Data binding is the process of associating
records in a data source (called data provider) with controls
in a form (called data consumer). This allows us to browse
and update data. Database-related structures that can serve
as a source of data include: DataView, DataTable, DataSet,
SqlDataReader, and OleDbDataReader.
Additionally, controls can be bound to other data structures. For example, we can use the following collections
as a source of data for our applications: Array, ArrayList,
HashTable, Queue, SortedList, Stack, and StringCollection. In
general, any object standard or customized that implements the IList interface can be used as a source of data for
the data-bound control.
To be able to use ADO.NET from our Delphi-based ASP.NET
applications, we must specify the ADO.NET-related
namespaces at the top of every ASPX page. For example, if
we use Microsoft SQL Server as a source of data, we must
include the following references:
<%@ Import Namespace="System.Data"%>
<%@ Import Namespace="System.Data.SqlClient"%>

The table in Figure 1 shows ADO.NET-related namespaces


implemented in the Microsoft .NET Framework.
It should be mentioned that Delphi code to access data in
ASP.NET is almost the same as in other types of applications, e.g. Windows Forms or console applications. From
Part I of this series, we already know that Web Forms allow
us to completely separate layout and business logic, and to
link controls and server-side code through events that are
handled in code declaration blocks.
Displaying data from a data source is extremely simple and
flexible in ASP.NET. ASP.NET includes a set of controls that
perform the function of displaying data. The developers only
need to bind these controls to a data source. To display data

.NET

Te c h

Creating ASP.NET Apps

Figure 2: Templates for the Repeater Web Server control.

<%@ Import Namespace = "System.Data" %>


<%@ Import Namespace = "System.Data.SqlClient" %>
<script language="Delphi" runat="server">
procedure Page_Load();
var
Conn : SqlConnection;
Cmd : SqlCommand;
begin
Conn := SqlConnection.Create(
'server=localhost;database=Northwind;uid=sa;pwd=');
Cmd := SqlCommand.Create('SELECT * FROM Employees',Conn);
Conn.Open;
Rpt.DataSource := Cmd.ExecuteReader;
Rpt.DataBind();
Conn.Close;
end;
</script>
<html>
<head>
<title>Repeater example</title>
</head>
<body>
<form id="main" runat="server">
<asp:Repeater id = "Rpt" runat="server">
<ItemTemplate>
<li> <%# DataBinder.Eval(Container.DataItem,'FirstName') %>
<%# DataBinder.Eval(Container.DataItem,'LastName')%>
(<%# DataBinder.Eval(Container.DataItem,'Title')%>)
</li>
</ItemTemplate>
</asp:Repeater>
</form>
</body>
</html>

Figure 3: Using the Repeater Web Server control.

on the client, you can use any list-bound Web Server control, such as Repeater, DataList, or DataGrid.
Using the Repeater Control
The Repeater control is the simplest data binding Web Server
control available in ASP.NET. We use this control to display a
list of records from a database table and we can specify a template that can be applied to each item displayed in the list.
We can use five templates that define how the header
(HeaderTemplate), item itself (ItemTemplate), separator
(SeparatorTemplate), and footer (FooterTemplate) should
be displayed on the page. If we want a different appearance
for alternating (odd-indexed) items in the table, create
AlternatingItemTemplate with the same contents as
14

DELPHI INFORMANT MAGAZINE | September 2003

Figure 4: An application with the Repeater control.

<html>
<head>
<title>Repeater example</title>
</head>
<body>
<form id="main" runat="server">
<asp:Repeater id = "Rpt" runat="server">
<HeaderTemplate> <table border=2>
<tr>
<td><b>Name</b></td>
<td><b>Title</b></td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr><td>
<%# DataBinder.Eval(Container.DataItem,'FirstName')%>
<%# DataBinder.Eval(Container.DataItem,'LastName')%>
</td><td>
<%# DataBinder.Eval(Container.DataItem,'Title')%>
</td></tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
</form>
</body>
</html>

Figure 5: Using HeaderTemplate and FooterTemplate to present data in a tabular format.

ItemTemplate, except with a different style specified. This is


shown in Figure 2.
At a minimum, we must specify ItemTemplate; that is,
define how elements must be rendered for each row in the
data source. Consider the example shown in Figure 3. The
ItemTemplate tag used in the example serves as a container
for other tags. For example, we used the bulleted list (HTML
<li>..</li> tags) to show each category with the category
description in brackets on the same line as the category name.
Within the ItemTemplate tag, we can use any HTML tags,
controls, text, and so on. Use the following syntax to display
a field from a record:
<%# DataBinder.Eval(Container.DataItem,'FirstName') %>

.NET

Te c h

Creating ASP.NET Apps

Figure 6: Displaying data as a table using HeaderTemplate and FooterTemplate.

<ItemTemplate>
<tr><td>
<%# DataBinder.Eval(Container.DataItem,'FirstName')%>
<%# DataBinder.Eval(Container.DataItem,'LastName')%>
</td><td>
<%# DataBinder.Eval(Container.DataItem,'Title')%>
</td></tr>
</ItemTemplate>
<AlternatingItemTemplate>
<tr bgcolor="#c0c0c0"><td>
<%# DataBinder.Eval(Container.DataItem,'FirstName')%>
<%# DataBinder.Eval(Container.DataItem,'LastName')%>
</td><td>
<%# DataBinder.Eval(Container.DataItem,'Title')%>
</td></tr>
</AlternatingItemTemplate>

Figure 8: Displaying odd and even items using AlternatingItemTemplate.

Using the DataList Control


The DataList control is an ASP.NET Web Server control that
is a template-defined data-bound list. This control provides
more functionality than the Repeater control (discussed in the
previous section) when, for example, selecting and editing.
Each record shown in the DataList control should be placed
in ItemTemplate as in the Repeater control. The DataList
control uses an HTML table to display the information. This
table can be fine-tuned using the CellPadding, CellSpacing,
and GridLines properties. Other properties of the control
include RepeatColumns and RepeatDirection to specify
how data should be displayed within the columns, and
RepeatLayout, which controls the layout of items in a list.

The other templates come into action when we need


to perform more complex formatting. For example, use
HeaderTemplate and FooterTemplate to present data in a
tabular format (see Figure 5). The result of running the
code from Figure 5 is shown in Figure 6.

The DataList control supports several events:


CancelCommand. This event occurs when the control
with the Command property set to Cancel is clicked in
the DataList control.
DeleteCommand. This event occurs when the control
with the Command property set to Delete is clicked in
the DataList control.
EditCommand. This event occurs when the control
with the Command property set to Edit is clicked in the
DataList control.
ItemCommand. This event occurs when the control is
clicked in the DataList control.
UpdateCommand. This event occurs when the control
with the Command property set to Update is clicked in
the DataList control.
SelectedIndexChanged. This event occurs when an item
on the list is selected.

Use AlternatingItemTemplate to display odd and even


records with different backgrounds (see Figure 7). The
result of running this code is illustrated in Figure 8.

Lets look at an example of how we can use commands in


the DataList control. Well use the LinkButton control to
create a menu of product categories. Add the event han-

Figure 7: Using AlternatingItemTemplate to display odd and even records with


different backgrounds.

The # character indicates were going to display data, and


the DataBinder statement specifies that were interested
in the value of the FirstName field stored in the DataItem
(items from the SqlDataReader) within the control that
contains this statement. In our example, the Container
control is an instance of the RepeaterItem class that
represents an element of the RepeaterItems collection. The
result of running this application is shown in Figure 4.

15

DELPHI INFORMANT MAGAZINE | September 2003

.NET

Te c h

Creating ASP.NET Apps

<%@ Import Namespace = "System.Data" %>


<%@ Import Namespace = "System.Data.SqlClient" %>
<script language="Delphi" runat="server">
procedure Page_Load();
var
Conn : SqlConnection;
Cmd : SqlCommand;
begin
Conn := SqlConnection.Create(
'server=localhost;database=Northwind;uid=sa;pwd=');
Cmd := SqlCommand.Create(
'SELECT CategoryName, Description FROM Categories',
Conn);
Conn.Open;
DList.DataSource := Cmd.ExecuteReader;
DList.DataBind();
Conn.Close;
end;
procedure ShowCategory(Sender: TObject;
e: DataListCommandEventArgs);
begin
Response.Write('Selected Category: ' +
e.CommandArgument.ToString);
end;
</script>
<html>
<head>
<title>DataList example</title>
</head>
<body>
<form id="main" runat="server">
<asp:DataList id = "DList" CellPadding=10
CellSpacing=10 GridLines="Both" RepeatColumns=4
RepeatDirection="Vertical"
OnItemCommand="ShowCategory" runat="server">
<ItemTemplate>
<asp:LinkButton id="Btn1" Text=
"<%# DataBinder.Eval(Container.DataItem,'CategoryName') %>"
CommandArgument =
"<%# DataBinder.Eval(Container.DataItem,'CategoryName') %>"
runat="server"/>
</ItemTemplate>
</asp:DataList>
</form>
</body>
</html>

Figure 9: Using the DataList control.

procedure ShowCategory(Sender: TObject;


e: DataListCommandEventArgs);
begin
DList.SelectedIndex := e.Item.ItemIndex;
LoadData();
end;
...
<ItemTemplate>
<asp:LinkButton id="Btn1" Text=
"<%# DataBinder.Eval(Container.DataItem,'CategoryName')%>"
CommandArgument =
"<%# DataBinder.Eval(Container.DataItem,'CategoryName')%>"
runat=server/>
</ItemTemplate>
<SelectedItemTemplate>
<span style='background:black;color:white;'>
<%# DataBinder.Eval(
Container.DataItem,'CategoryName')%>
</span>
</SelectedItemTemplate>

Figure 11: Using SelectedItemTemplate.

Figure 12: Highlighting text using SelectedItemTemplate.

CommandArgument property of the LinkButton control. The


result of executing this application is shown in Figure 10.
To highlight the currently selected item (white font on
black background) we can use SelectedItemTemplate, as
shown in Figure 11. The result of running this code is
shown in Figure 12.
Before we end our discussion of the DataList control, its
important to mention that there are several styles of this
control that can be used to customize its appearance.
These styles are: AlternatingItemStyle, EditItemStyle,
FooterStyle, HeaderStyle, ItemStyle, SelectedItemStyle,
and SeparatorStyle.
Each style contains such attributes as background color, border style, font, vertical alignment, and so on. We use styles
in the following way:

Figure 10: An application using the DataList control.

dler for the ItemCommand event, as shown in Figure 9, to


find which item on the menu was clicked.
Please note how we display the name of the selected
category; we assign the name of the category to the
16

DELPHI INFORMANT MAGAZINE | September 2003

<asp:DataList
Control properties are specified here.
<HeaderStyle BackColor = "#a7b7c7"
HorizontalAlign = "Center" Font-Size = "Large">
<ItemStyle BackColor="#d0d0d0">
Templates are specified here.
/asp:DataList>

Styles can be also specified as part of the <asp:DataList>


tag. For example, to set the background color of the item,
we use the ItemStyle BackColor property.

.NET

Te c h

Creating ASP.NET Apps

<%@ Import Namespace = "System.Data" %>


<%@ Import Namespace = "System.Data.SqlClient" %>
<script language="Delphi" runat="server">
procedure Page_Load();
var
Conn : SqlConnection;
Cmd : SqlCommand;
begin
Conn := SqlConnection.Create(
'server=localhost;database=Northwind;uid=sa;pwd=');
Cmd := SqlCommand.Create('SELECT * FROM Products', Conn);
Conn.Open;
Grid.DataSource := Cmd.ExecuteReader;
Grid.DataBind();
Conn.Close;
end;
</script>
<html>
<head>
<title>DataGrid example</title>
</head>
<body>
<form runat="server">
<asp:DataGrid id = "Grid" AutoGenerateColumns = "False"
runat="server">
<Columns>
<asp:BoundColumn HeaderText="Product"
DataField="ProductName"/>
<asp:BoundColumn HeaderText="Quantity"
DataField="QuantityPerUnit"/>
<asp:BoundColumn HeaderText="Price"
DataField="UnitPrice" DataFormatString="{0:c}"/>
</Columns>
</asp:DataGrid>
</form>
</body>
</html>

Figure 13: Using the DataGrid control.

Figure 15: The DataGrid control with editing capabilities.

DataGrid control also supports paging via the database data,


as well as the ability to specify the column type bound
column, button column, hyperlink column, and so on.
Columns can be generated automatically, using the
AutoGenerateColumns property, or manually. Note that in
Figure 13 we used the <Columns> tag.
Each <asp:BoundColumn> element inside the <Columns>
tag is used to specify one data-bound column. In our example, we defined three such columns by using the HeaderText
property to specify the label for the column heading and the
DataField property to associate this column with the database field. In the third column definition we also used the
DataFormatString property to specify that the column values
should be displayed as a currency (see Figure 14).
See Listing One (on page 20) for an example of the
editing capabilities of the DataGrid control. In that
example we added the <asp:EditCommandColumn>
element and specified names for the edit, update, and
cancel commands. This column is added automatically
for each row in the DataGrid control. When the row isnt
selected for editing, the <asp:EditCommandColumn>
element displays the Edit button. When we click on
this button, the <asp:EditCommandColumn> element
displays Update and Cancel buttons.
We associate event handlers for all three buttons
in the OnEditCommand, OnCancelCommand, and
OnUpdateCommand properties of the DataGrid control.
To extend the editing functionality of the DataGrid
control we can use EditItemTemplate. To do so, create a
number of <asp:TemplateColumn> elements and place
EditItemTemplate and other controls validators, for
example inside (see Figure 15). To use the sorting
capabilities of the DataGrid control, use the AllowSorting
property which must be set to True (see the example in
Listing Two on page 20).

Figure 14: The DataGrid control.

Using the DataGrid Control


The DataGrid Web Server control is the advanced version
of the DataList control just discussed. It allows us to select,
sort, and edit items from the specified data source. The
17

DELPHI INFORMANT MAGAZINE | September 2003

In the example illustrated in Listing Two we implemented


the sorting functionality for the DataGrid control. After
setting the AllowSorting property to True we attached
the event handler for the SortCommand event via
the OnSortCommand property. We also specified the
SortExpression property for each <asp:BoundColumn>

.NET

Te c h

Creating ASP.NET Apps

Figure 16: The DataGrid control with sorting functionality.

procedure LoadData();
var
Conn : SqlConnection;
DA : SqlDataAdapter;
DS : DataSet;
begin
Conn := SqlConnection.Create(
'server=localhost;database=Northwind;uid=sa;pwd=');
DA := SqlDataAdapter.Create(
'SELECT * FROM Products', Conn);
DS := DataSet.Create;
DA.Fill(DS, 'Products');
Grid.DataSource := DS;
Grid.DataBind();
end;
procedure PageProduct(Sender: TObject;
e: DataGridPageChangedEventArgs);
begin
Grid.CurrentPageIndex := e.NewPageIndex;
LoadData();
end;
</script>
<html>
<head>
<title>DataGrid</title>
</head>
<body>
<form runat="server">
<asp:DataGrid id = "Grid" HeaderStyle-BackColor="#c0c0c0"
AutoGenerateColumns = "False" AllowPaging="True"
OnPageIndexChanged="PageProduct" runat="server">
<PagerStyle Mode="NumericPages"
HorizontalAlign="Center"/>
<Columns>
...
</Columns>
</asp:DataGrid>
</form>
</body>
</html>

Figure 17: Using the AllowPaging property of the DataGrid control.

element in our grid. The DataGrid control does not


perform sorting of the data itself we execute a SELECT
SQL query with the ORDER BY clause set to the name
18

DELPHI INFORMANT MAGAZINE | September 2003

Figure 18: The DataGrid control with paging functionality.

<%@ Import Namespace = "System.Data" %>


<%@ Import Namespace = "System.Data.SqlClient" %>
<script language="Delphi" runat="server">
var
SortExpression : string = 'ProductID';
procedure Page_Load();
begin
if not IsPostBack then
LoadData();
end;
procedure LoadData();
var
Conn : SqlConnection;
Cmd : SqlCommand;
begin
Conn := SqlConnection.Create(
'server=localhost;database=Northwind;uid=sa;pwd=');
Cmd := SqlCommand.Create(
'SELECT * FROM Products order by ' +
SortExpression, Conn);
Conn.Open;
Product.DataSource := Cmd.ExecuteReader;
Product.DataTextField := 'ProductName';
Product.DataBind();
Conn.Close;
end;
procedure SelectProduct(Sender: TObject; e: EventArgs);
begin
Selection.Text := Product.SelectedItem.Text;
end;
</script>
<html>
<head>
<title>DropDownList example</title>
</head>
<body>
<form runat="server">
<asp:DropDownList id = "Product" runat="server"/>
<asp:Button id = "Btn1" Text="Select"
OnClick="SelectProduct" runat="server"/>
<asp:TextBox id = "Selection" runat="server"/>
</form>
</body>
</html>

Figure 19: Using the DropDownList control.

.NET

Te c h

Creating ASP.NET Apps


ASP.NET Web controls also support data binding:
CheckBoxList, DropDownList, HTMLSelect, ListBox, and
RadioButtonList.
These controls have a DataSource property that allows us to
associate them directly with database data. For other controls, such as LinkButton, we can indirectly specify the data
via the Text value when we use controls such as Repeater.
We saw an example of this earlier in this article when we
implemented a menu of a products categories.
Our last example shows how to bind data to the DropDownList control (see Figure 19). The result of running this application is shown in Figure 20.

Figure 20: Data binding with the DropDownList control.

of the column header the user clicked. This executes the


query and returns the data sorted by the selected column
(see Figure 16).
The paging capabilities of the DataGrid control are
supported by the AllowPaging property (see Figure 17).
In the example shown in Figure 17, we set the AllowPaging
property to True and specified the event handler for the
PageIndexChanged event in the OnPageIndexChanged
property. In this event handler, we assigned the new value
for the CurrentIndex property of the DataGrid control.
Please note that in this case all data should be loaded into
memory before the DataGrid control could page through it.
This means we need to use the DataSet object instead of
the DataReader object, because the former, unlike the latter,
supports caching data.
To change the appearance of the Pager control we can
use the <PagerStyle> element and its Mode attribute. In
our example, we display links to the pages by setting the
Mode attribute to NumericPages (see Figure 18).
Using other ASP.NET Controls
Earlier in this article we saw how to use the Repeater,
DataList, and DataGrid Web Server controls to display
and edit data loaded from the database. Several other

19

DELPHI INFORMANT MAGAZINE | September 2003

Conclusion
In this article we discussed creating ASP.NET applications
with the Delphi Compiler for Microsoft .NET. We created
examples that illustrate data binding using the Repeater,
DataList, and DataGrid controls, and we illustrated how to
display, highlight, select, edit, sort, and page data.
The 10 ASPX pages that support this article are available for
download on the Delphi Informant Magazine Complete
Works CD located in INFORM\2003\SEP\DI200309AF.

Alexei Fedorov is a developer and consultant based in Moscow, Russia.


During his 20 years of experience he has worked as a chief technology
officer for a Swiss IT company, has provided technical support for Borland
languages, has participated in development and software localization, and
has created many Internet and intranet sites. Alexei also contributes articles
for asp.netPRO magazine, and has co-authored many books, including
Professional ASP 2.0, ASP 2.0 Programmers Reference, and Advanced Delphi
Developers Guide to ADO. Alexeis recent book, A Programmers Guide to
.NET, was published by Addison-Wesley in 2002.
Natalia Elmanova, Ph.D. is a developer and trainer based in Moscow,
Russia, as well as an executive editor for ComputerPress magazine
(www.compress.ru). During the last 15 years she has trained several hundred
Delphi and Visual Basic developers and has been a team leader in several
software projects for various commercial companies, research institutes, and
governmental organizations. Natalia was a contributing author to the 10th,
11th, 12th, and 13th Annual Borland Conferences and has co-authored many
books, including Advanced Delphi Developers Guide to ADO.

.NET

Te c h

Creating ASP.NET Apps

Begin Listing One DataGrid


control with EditCommandColumn
<%@ Import Namespace = "System.Data" %>
<%@ Import Namespace = "System.Data.SqlClient" %>
<script language="Delphi" runat="server">
procedure Page_Load();
begin
if not IsPostBack then
LoadData();
end;
procedure LoadData();
var
Conn : SqlConnection;
Cmd : SqlCommand;
begin
Conn := SqlConnection.Create(
'server=localhost;database=Northwind;uid=sa;pwd=');
Cmd := SqlCommand.Create('SELECT * FROM Products', Conn);
Conn.Open;
Grid.DataSource := Cmd.ExecuteReader;
Grid.DataBind();
Conn.Close;
end;
procedure EditProduct(Sender: TObject;
e: DataGridCommandEventArgs);
begin
Grid.EditItemIndex := e.Item.ItemIndex;
LoadData();
end;
procedure CancelEdit(Sender: TObject;
e: DataGridCommandEventArgs);
begin
Grid.EditItemIndex := -1;
LoadData();
end;
procedure UpdateProduct(Sender: TObject;
e: DataGridCommandEventArgs);
begin
// Update data code goes here.
Grid.EditItemIndex := -1;
LoadData();
end;
</script>
<html>
<head>
<title>DataGrid</title>
</head>
<body>
<form runat="server">
<asp:DataGrid id = "Grid" AutoGenerateColumns = "False"
DataKeyField="ProductID" OnEditCommand="EditProduct"
OnCancelCommand="CancelEdit"
OnUpdateProduct="UpdateProduct" runat="server">
<Columns>
<asp:EditCommandColumn EditText="Edit"
CancelText="Cancel" UpdateText="Update"
ButtonType="PushButton" />
<asp:BoundColumn HeaderText="Product"
DataField="ProductName" />
<asp:BoundColumn HeaderText="Quantity"
DataField="QuantityPerUnit" />
<asp:BoundColumn HeaderText="Price"
DataField="UnitPrice" DataFormatString="{0:c}" />
</Columns>
</asp:DataGrid>

20

DELPHI INFORMANT MAGAZINE | September 2003

</form>
</body>
</html>

End Listing One


Begin Listing Two DataGrid control
sorting
<%@ Import Namespace = "System.Data" %>
<%@ Import Namespace = "System.Data.SqlClient" %>
<script language="Delphi" runat="server">
var
SortExpression : string = 'ProductID';
procedure Page_Load();
begin
if not IsPostBack then
LoadData();
end;
procedure LoadData();
var
Conn : SqlConnection;
Cmd : SqlCommand;
begin
Conn := SqlConnection.Create(
'server=localhost;database=Northwind;uid=sa;pwd=');
Cmd := SqlCommand.Create(
'SELECT * FROM Products order by ' + SortExpression,
Conn);
Conn.Open;
Grid.DataSource := Cmd.ExecuteReader;
Grid.DataBind();
Conn.Close;
end;
procedure SortProduct(Sender: TObject;
e: DataGridSortCommandEventArgs);
begin
SortExpression := e.SortExpression;
LoadData();
end;
</script>
<html>
<head>
<title>DataGrid</title>
</head>
<body>
<form runat="server">
<asp:DataGrid id = "Grid" HeaderStyle-BackColor="#c0c0c0"
AutoGenerateColumns = "False" AllowSorting="True"
OnSortCommand="SortProduct" runat="server">
<Columns>
<asp:BoundColumn HeaderText="Product"
DataField="ProductName"
SortExpression="ProductName" />
<asp:BoundColumn HeaderText="Quantity"
DataField="QuantityPerUnit"
SortExpression="QuantityPerUnit" />
<asp:BoundColumn HeaderText="Price"
DataField="UnitPrice" DataFormatString="{0:c}"
SortExpression="UnitPrice" />
</Columns>
</asp:DataGrid>
</form>
</body>
</html>

End Listing Two

I N
OOP

D E V E L O P M E N T
ENCAPSULATION

DELPHI 1-7

By Peter Gatis

The Nature of Encapsulation


The Strong, the Weak, and the Ugly

lthough it started as a pillar of objectoriented programming, encapsulation as a


theory rarely gets the dignity of a formal

presentation. Perhaps the idea is already simple


enough; a formal statement might be overdoing it.

These conditions are more stringent than we would like,


and are frequently ignored (even by the Delphi IDE class
completion feature), but we do have some reassurance
that, with time, we can create mechanically bulletproof
interfaces. We may pay a price in code overhead, and
classes that reference each other may lose some of the
benefits of strong typing, but we believe we can do it.

From an informal point of view, encapsulation involves the


The last condition that each class be compiled in a
separation of form and function. We mold a central idea (a
separate unit stems from the meaning of the Pascal
class concept) into the form of an interface (literally a type
keyword, private. It doesnt mean private within the
definition) and relegate all associated function to a private
class; rather, it means private within the unit that
implementation section. The architecture of the system may
declares the class. Multiple objects declared within the
go as far as the public portion of the interface, but no further.
same unit have free access to all private variables, as
That is, the public portion of the
illustrated in Listing One (on page
interface acts as the boundary of
26). Such units often remain in
Maintenance coders
encapsulation.
use because moving classes with
will attest that strong
references back and forth into
encapsulation is in fact
Objects have been likened to little
separate units requires that the
black boxes impervious to the world,
uses references be placed into
a rarity.
bodies of code carefully screened
the respective implementation
from careless visitors. The 5th Edition of the Microsoft Comsections, and we lose the strong type references in
puter Dictionary bluntly asserts that: Encapsulation ensures
the interface section. Pascal does not support forward
that the object providing service can prevent other objects from declarations across units.
manipulating its data or procedures directly, and it enables the
object requesting service to ignore the details of how that serWe need to clear up a few troubling points. For startvice is provided.
ers, does mechanical encapsulation (as described above)
really enable us to ignore the details of how that service
In the mechanics of encapsulation, the Delphi compiler can
is provided? We would like to know that such encapsulaformally prevent objects from interfering with each other on
tion has at least a ghost of a chance just by looking at
three conditions:
the class definition. We would also like to know that high
Data items must be kept in the private or protected area of mechanical encapsulation holds together once an object
the interface.
has been instantiated. In this article these complementary
points of view are addressed by semantic encapsulation
These items (and any constituent parts) must be made
available only through private or protected functions and
and encapsulated normal form (ENF), respectively. Well
procedures (particularly within properties).
look at these individually for some depth of understanding, then take the two together to see how they fit.
Each class must be compiled in a separate unit.

21

DELPHI INFORMANT MAGAZINE | September 2003

In

Development

The Nature of Encapsulation

Weakly Encapsulated

Strongly Encapsulated

A class is weakly encapsulated if the semantic value of


each public attribute may be
defined independently of any
reference to its implementation details.

A class is strongly encapsulated if the semantic value of


each public attribute may be
defined independently of any
reference to the implementation details of any class within
the Universe of Discourse.

Figure 1: Semantic encapsulation defined.

Semantic Encapsulation
The definitions in Figure 1 use the formidable word semantic to raise the level of discussion to the meaning of each
public (or published) declaration, and to provide the analytic wedge by which we may separate implementation code
from the intelligibility of the class definition. We also use
the term Universe of Discourse to restrict our thoughts to an
arbitrary set of objects and their proper attributes (as we
might find in an ordinary application). Were disregarding
such constructs as class functions or global variables. The
definition of semantic encapsulation tells us we can ignore
the implementation code of a class when the interface is
complete and understandable.
To clarify semantic encapsulation a little further, the semantic value of an item refers to its meaning and truth-value, or
validity. For example, a pointer is valid or invalid depending
on the value it contains and the context of its use. To speak
of the semantic value of a pointer makes this explicit:
1) A pointer may be either valid or invalid (the domain of
accepted truth-values).
2) A pointer must be either valid or invalid, if the pointer
exists at all.
3) A pointer cannot be both valid and invalid.
If any of these conditions fail, the pointer has no semantic
value, and were unable to speak about it meaningfully
without embracing difficult qualifications. Similar logic
applies to procedures, functions, and properties. Note that
existence and validity are not the same thing, but that existence is a necessary condition of validity.
Semantic encapsulation separates two distinct but related
definitions of encapsulation into strong and weak flavors.
Strong encapsulation is the limiting case of weak encapsulation. The definition implies that weak encapsulation can be
progressively bolstered through mechanical encapsulation
until it reaches our preferred strong encapsulation. Strong
encapsulation combines semantic and mechanical encapsulation in a satisfying union, i.e. we can make our black box
with solid sides.
Computer Science lecturers, computer dictionaries, and programming texts generally speak of any encapsulation as if it
were strong encapsulation. Clearly, this is a mistake; we have
no automatic reason to assume that any class defined unto
itself is already strongly encapsulated. Maintenance coders
will attest that strong encapsulation is in fact a rarity.
Often the best we can hope for are class definitions that prevent accidental misuse of the class. Nothing can stop a deliberate or misguided attempt to break weak encapsulation.
22

DELPHI INFORMANT MAGAZINE | September 2003

{ Highly vulnerable encapsulation. }


TGeneralMembership = class(TObject)
private
FMembers: TList;
public
constructor Create;
destructor Destroy; override;
property Members: TList read FMembers write FMembers;
end;
{ Slightly stronger encapsulation. }
TGeneralMembership = class(TObject)
private
FMembers: TList;
public
constructor Create;
destructor Destroy; override;
property Members: TList read FMembers;
end;

// Write removed.

Figure 2: Incrementally increasing encapsulation.

TParser = class(TObject)
public
property InputString: string write SetInputString;
property RealValue: extended read GetValue;
end;

Figure 3: Breaking semantic encapsulation through incompleteness.

We wont provide instructions for such transgressions here,


but we will show how vulnerable class definitions are, and
how strong encapsulation applies. The code in Figure 2
shows a prototype class definition for a club membership
application. We may presume the FMembers TList object
is created in the constructor. The first interface needlessly
omits the write aspect of the Members property, leaving an
inadvertent replacement of the TList in FMembers a real possibility. This mistake still meets our criterion of weak encapsulation (a member list is an understandable thing), but it
leaves our criterion of strong encapsulation wide open. We
cannot look at that interface and know for sure that it is
safe from reckless misuse.
In the second interface we fare incrementally better. As we
add techniques to safeguard the integrity of FMembers, we
are moving toward strong encapsulation. Ideally, we would
be able to add safeguards to the extent we need not worry
about FMembers at all. In practice, however, it rarely happens. An inexperienced client coder might casually free a
TMember object represented in the FMembers list, corrupting
that list practically by remote control.
Weak encapsulation can fail on its own terms. The class
definition code of Figure 3 shows a simple interface concealing a complex implementation. In the basic design of
the class TParser, we parse an input string as an arithmetic expression, and place the real-valued result in the
RealValue property. The interface illustrated in Figure 3
fails weak semantic encapsulation on the grounds that the
value of RealValue is completely unpredictable for expressions like 0/0 or abc. We would have to look at the
underlying code to know whether to expect an exception,
or -1, or anything else.

In

Development

The Nature of Encapsulation

TInputState = (isEmpty, isTooLong, isUndefined, isDefined);


...
TParser = class(TObject)
public
property InputString: string write SetInputString;
property RealValue: extended read GetValue;
property InputState: TInputState read GetInputState;
end;

Figure 4: Reasonable semantic encapsulation.

TInputState = (isEmpty, isTooLong, isUndefined, isDefined);


...
TParser = class(TObject)
public
procedure Initialize;
property InputString: string write SetInputString;
property RealValue: extended read GetValue;
property InputState: TInputState read GetInputState;
end;

Figure 5: Breaking semantic encapsulation through ambiguity.

As soon as were forced into code, our weak semantic


encapsulation has failed; our black box has collapsed.
Even if we define RealValue to be the arithmetic evaluation of the input string, or -1, there are arithmetic
expressions that do evaluate to -1, and we are stuck with
an incomplete definition.
The code in Figure 4 works much better, and in fact satisfies our condition of weak semantic encapsulation. The
addition of a third property identifying the parsing result
of the input string makes the object much easier to use
without recourse to the debugger. Unless the state of the
input string is defined, the value of RealValue is irrelevant, and should not be used. We have the value-added
option of seeing how the parsing may have failed.
Blindsided by our success, the example in Figure 5 once
again violates weak semantic encapsulation. The validity
of RealValue now depends on the meaning of the procedure Initialize. Should Initialize occur once after the
object has been created, or should it be used after every
change in the input string? The need to establish the
sequence of operations forces us again into the code to
figure out whats going on.
All these parser examples satisfy the standards of mechanical encapsulation as provided by our compiler. Mechanical
encapsulation and semantic encapsulation are complementary, not equivalent. The necessary and sufficient conditions of strong encapsulation are weak encapsulation plus
mechanical encapsulation. Starting with the authentic case
of weak semantic encapsulation illustrated in Figure 4, if
we place the GetValue and GetInputState functions in the
private (or protected) area of the class definition, and
place the class definition itself in its own unit, then we
have strong encapsulation. Strong encapsulation consists of
weak encapsulation with a mechanical bodyguard.
Does the semantic encapsulation of a class definition, weak
or strong, carry over into its implementation characteristics?
23

DELPHI INFORMANT MAGAZINE | September 2003

procedure TForm1.Button1Click(Sender: TObject);


var
MyObject: TMyObject;
MyObjectIdAsObject: TObject;
MyObjectIdAsInteger: Integer;
MyObjectIdAsPointer: Pointer;
MyObjectIdAsAddress: Pointer;
MyObj1, MyObj2, MyObj3, MyObj4: TMyObject;
begin
MyObject := TMyObject.Create;
try
MyObjectIdAsObject := TObject(MyObject);
MyObjectIdAsInteger := Integer(MyObject);
MyObjectIdAsPointer := @MyObject;
MyObjectIdAsAddress := addr(MyObject);
MyObj1
MyObj2
MyObj3
MyObj4

:=
:=
:=
:=

TMyObject(MyObjectIdAsObject);
TMyObject(MyObjectIdAsInteger);
TMyObject(MyObjectIdAsPointer^);
TMyObject(MyObjectIdAsAddress^);

if (MyObj1 = MyObject) and (MyObj2 = MyObject) and


(MyObj3 = MyObject) and (MyObj4 = MyObject) then
begin
ShowMessage('It's all the same to me!');
end;
finally
MyObject.Free;
end;
end;

Figure 6: Representations of the object id.

Unfortunately, no. Semantic encapsulation applies to the class


definition, but not to instantiated objects (as do most other
attempts to bring rigor to class design).
Encapsulated Normal Form
Encapsulated normal form (ENF) addresses this omission by a
definition tied to a fundamental physical characteristic of any
instantiated object, the object id. Figure 6 illustrates the various
representations and logical equivalence of the object id. The
object id fixes each object to a unique physical characteristic;
namely, its address within the address space of the instantiating machine. In the case of Delphi, were talking about a
pointer to the chunk of memory where the object resides. For
our purposes, how the compiler puts an object together is academic. If the object id is valid, we have an instantiated object.
Using the object id to pin encapsulation to the physical reality
of each unique instantiated object, heres a working definition
of encapsulated normal form: Within its scope of creation,
an object maintains encapsulated normal form, if at all times
within that scope the semantic value of each public attribute
is guaranteed to be true by the existence of the object id, the
mutual consistency of every public attribute associated with
the object id, and nothing else. More eloquently, we might say
the only semantic determinant of the object is the object itself.
ENF provides a standard for a well-behaved object, matching
our sense of what an object should do (we hope). Within this
definition, establishing the consistency of public attributes
entails the testing of two or more functionally related attributes. Through the principle that the value for one attribute
determines the valid values for its related attributes, the valid
attributes will ultimately exhibit characteristics of existence and
mutual correctness.

In

Development

The Nature of Encapsulation

By the existence of the object id, we mean the lifetime of the


object id, from the moment of instantiation, through the duration of the object, until the moment of destruction. By mutual
consistency, we mean quite literally that if any available part of
the object is valid (particularly the object id) then all available
parts of the object are valid.
How can we possibly establish that any given object satisfies ENF, when ENF involves such a fragile and demanding
temporal standard? We might conceivably specify a formal
statement of the logical nature of each public attribute
through functional dependencies if any of us knew how
to do that and then prove the consistency of all the
public attributes taken together. Even this, however, would
only get us halfway to where we want to be. From the
point of view of ENF, if the objects execution in machine
code is at all flawed, the formal consistency of the public
attributes hardly matters.

Violations
What about encapsulation violations? The following
examples illustrate encapsulation violations; they can be
extended indefinitely, and any given example could be
(but isnt) discussed at length.
Direct violations of mechanical encapsulation:
Failure to access private variables exclusively through
functions and procedures.
Failure to segregate class definitions into separate units.
Direct violations of weak encapsulation:
Providing an incomprehensible interface.
Providing properties that change value depending on the
order of access.
Direct violations of strong encapsulation:
Interlinking object references without safeguards.
Defining the validity of an attribute with respect to an
inherited class.

Theres no easy way out. Just as strong semantic encapsulation is the limiting case of weak semantic encapsulation,
ENF is the limiting case of our testing procedures. We canDirect violations of ENF:
not test everything, but we can show that the tests we do
Injecting a value directly into a private variable by priperform are at least consistent. We allow that test cases
vate address.
cannot be exhausted. We can fix the undefined quantities,
Substituting out event handlers created within the object.
the inaccurate results, the inconsistent values, the lack of
precision, the unmet boundary conditions, and still have
Bringing Them Together
an isolated exception blow sky high after the application
As we said earlier, semantic encapsulation applies to the
gets into production. If our test cases circumscribe the
class definition itself, not to instantiated objects. ENF, in its
ordinary circumstances of
turn, applies to instantiated
object use, we can at least
objects, but not particularly
We are at times obliged to
say that ENF has held up
to class definitions. Can we
link objects together. When this
under specified testing. Perforge a connection between
haps the best a quality prodthe two? Having two separate
happens, it appears there is
uct can do is fall within its
categories of encapsulation is
no way to preserve the strict
own testable specifications.
a little unsettling. How do we
integrity of encapsulation.
know the two are not mutually
Remember the Musketeers
exclusive? For the mathematiCreed: All for one and one for all. The Creed summarizes
cally inclined, see the sidebar Encapsulation Relation Proof
the relationship of object id to public attributes within
of the Equivalence of Semantic Encapsulation and ENF for
encapsulated normal form. If any public attribute is valid,
proof of the logical equivalence of the two.
the object id must be valid (all for one), and if the object id
is valid then all the public attributes must be valid (one for
Although the idea that black-box design might have a physiall). On the force of the Musketeers Creed, we might not be
cal counterpart is pretty exciting, one particular problem
able to prove that ENF succeeds, but we can prove to any
jumps out as the crucial application of encapsulation: We
degree of certitude that it doesnt fail. Conversely, where
are at times obliged to link objects together. When this hapthe Musketeers Creed fails, our object has an encapsulation
pens, it appears there is no way to preserve the strict integfracture line.
rity of encapsulation. The validity of the reference is bound
to be directly dependent on the validity of the pointer, i.e.
Further comments are in order. We have used the phase at
the object id of a completely different object. How we define
all times to reinforce the idea that ENF can be broken after
our class interface has no bearing on whether another object
the object has been instantiated. An object can be bullied by
has to exist, unless we also link our class semantics togethanother object into giving up its validity either by misusing
er. This could beat encapsulation altogether.
the intended interface, or by by-passing the intended interface
altogether (see Breaking Encapsulation in the July 2003
We can use the equivalence of semantic encapsulation and
issue of Delphi Informant). As maintenance coders facing an
ENF to show how object interlinking breaks encapsulation
object whose behavior has gone berserk, we may legitimately
(see the reference to subcase 2 in the sidebar). Figure 7
ask whether the integrity of the object has been sustained,
illustrates a simple interlinking where every TChild object
or whether the object has been abused along the way. The
has two TParent objects. The interlinking seems natural
object id remains our key to such a situation: A public attribute enough. As expected, we have a situation where the validity
whose validity depends on an interloper object id has clearly
of an attribute (mother or father) depends on the existence
gone out of bounds. ENF imposes limits.
of an externally referenced object, i.e. a semantic determi-

24

DELPHI INFORMANT MAGAZINE | September 2003

In

Development

The Nature of Encapsulation

interface
type
TParent = class(TObject)
private
FChildren: TList;
public
property Children: TList read FChildren;
end;
TChild = class(TObject)
private
FMother: TParent;
FFather: TParent;
procedure SetMother(ANewVal: TParent);
function GetMother: TParent;
procedure SetFather(ANewVal: TParent);
function GetFather: TParent;
public
constructor Create;
destructor Destroy; override;
property Mother read GetMother write SetMother;
property Father read GetFather write SetFather;
end;
TContextOfUse = class(TObject)
public
// Strong encapsulation breaks here.
procedure AssignParentsToChildren;
end;

Figure 7: An example of interlinking.

nant Alpha other than the original object id alone. In a case


of ENF broken by substitution (as in substituting out an
event handler), an attribute becomes dependent on an externally controlled validity. In the case of ENF broken by interlinking (as we have here), an attribute becomes dependent
on an externally controlled existence.
To figure out when we have valid references, were forced to
look at when the mother and father are assigned in the context
of use. That is, to define what part the original object id plays

in any functional dependency on Alpha, were forced to look


at the context of use. This context of use extends to the object
life span of each mother and father. If either object is freed prematurely, our respective public attribute becomes invalid. However, looking outside TChild to TContextOfUse breaks strong
semantic encapsulation, i.e. the semantic value of each public
attribute cannot be defined independently of any reference to
the implementation details of any class within the Universe of
Discourse. The reference to an external object id has translated
into a break in strong semantic encapsulation. Our black box
has a hole punched in it, right where we expected mechanical
encapsulation to protect us.
The equivalence of semantic encapsulation with ENF gives
us three things:
We may be more comfortable with our assumption
that encapsulation in design has a counterpart in
implementation.
We have a better idea of what constitutes a well-formed
interface.
Weve gained some insight into the nature of the relationship between a class definition and its implementation in ENF.
Conclusion
Even without the problem of object interlinking, we may be
taken aback by what has happened so far. In the first place,
we note that our discussion of encapsulation has taken
place in several completely different contexts: mechanical,
semantic, and normal form. This may be the first weve ever
heard of encapsulation context.
In the second place, we introduced degrees of encapsulation, starting from a weak assumption of what encapsulation entails (weak semantic encapsulation) and moving to a
strong but slightly impractical hope (strong semantic encapsulation). Encapsulation is no longer an elegant singularity, but a team of interlocking ideas. The structures of ENF

Encapsulation Relation Proof of the Equivalence


of Semantic Encapsulation and ENF
Prove: That strong encapsulation and ENF are equivalent for non-trivial objects.
Proof: ENF implies strong encapsulation, and strong encapsulation implies ENF.
If the semantic value of each public attribute is guaranteed by the existence of the object id, and the consistency of each public
attribute with the object id, and the object id itself exists independently of its own implementation details, then we have no reference to any implementation details for the sake of determining semantic value within ENF, and semantic encapsulation obtains.
If semantic encapsulation obtains while normal encapsulation fails, were led to a contradiction:
Primary case. If normal encapsulation fails, then either the object id itself is not a semantic determinant, or there exists a
semantic determinant which is not the object id.
Subcase 1. If the object id itself is not a determinant, then some public attribute exists which is valid independently of the
object being created. This can occur with class methods, but as far as created objects are concerned, it is a physical impossibility. We allow that the phenomenon of floating pointers can fool us temporarily in testing.
Subcase 2. If a semantic determinant Alpha exists other than the object id alone, we may presume that the determinant
Alpha is a composite which includes the object id; otherwise, the dependent attribute could not even exist. Although we
might be able to determine what attributes are affected by Alpha on the basis of the class definition alone, to define what
part the original object id plays in any functional dependency on Alpha we would be forced to look at the context of use.
This is prohibited by our requirement of strong encapsulation.
We are therefore led to conclude that semantic encapsulation implies ENF; to assume otherwise leads to a contradiction.

25

DELPHI INFORMANT MAGAZINE | September 2003

In

Development

The Nature of Encapsulation

thankfully brings in a workable guideline for what we are


looking for in testing the sustained mutual consistency of
public attributes and the object id.
One task remains to round out this tour of encapsulation
theory: to show whether we can sustain encapsulation at all
under ordinary conditions of object interlinking. While our
sanity may depend on it, that is the subject of another article.
Two projects that demonstrate principles discussed in this
article are available for download on the Delphi Informant
Magazine Complete Works CD located in INFORM\2003\
SEP\DI200309PG.

Peter Gatis is CEO of Delphinium Software. We gratefully acknowledge the


assistance of Peter Schultz, a Senior Developer for Irista, in the preparation of
this article. Peter Gatis may be e-mailed at pgatis@istar.ca. Look up Delphinium
(In Windows) at www.hotfiles.com and check out D-Project 3.0, an example of a
work-in-progress involving heavy encapsulation.

Begin Listing One Object interference within unit scope


unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;
type
TMyObject1 = class;
TMyObject2 = class;
TForm1 = class(TForm)
Button2: TButton;
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormActivate(Sender: TObject);
procedure FormDeactivate(Sender: TObject);
private
FMyObj1: TMyObject1;
FMyObj2: TMyObject2;
end;
TMyObject1 = class(TObject)
private
FValue1: Integer;
public
procedure InterfereWithMyObject2;
property Value1: Integer read FValue1;
end;
TMyObject2 = class(TObject)
private
FValue2: Integer;
public
procedure InterfereWithMyObject1;
property Value2: Integer read FValue2;
end;
var
Form1: TForm1;
implementation

26

DELPHI INFORMANT MAGAZINE | September 2003

{$R *.DFM}
{ TMyObject1 }
procedure TMyObject1.InterfereWithMyObject2;
begin
Form1.FMyObj2.FValue2 := 13;
end;
{ TMyObject2 }
procedure TMyObject2.InterfereWithMyObject1;
begin
Form1.FMyObj1.FValue1 := 17;
end;
{ Form events. }
procedure TForm1.Button1Click(Sender: TObject);
begin
FMyObj1.InterfereWithMyObject2;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
FMyObj2.InterfereWithMyObject1;
end;
procedure TForm1.FormActivate(Sender: TObject);
begin
FMyObj1 := TMyObject1.Create;
FMyObj2 := TMyObject2.Create;
end;
procedure TForm1.FormDeactivate(Sender: TObject);
begin
FMyObj1.Destroy;
FMyObj2.Destroy;
end;
end.

End Listing One

INFOR MAN T

SPO TLI GH T

By Jerry Coffey

Shuffling the Deck


Delphi Informant Magazine Readers Choice Awards 2003

ast years Readers Choice Awards seemed to


indicate that, after many years of volatility, the
pace of change had slowed significantly in the

Delphi third-party tools marketplace. For example, in


the 25 categories last year, 19 featured repeat winners
from the previous year.
Then TurboPower Software dropped a bombshell in January
of this year, announcing they were no longer doing business
as a vendor in the Delphi arena. Although TurboPower made
their decision for reasons that had nothing to do with Delphi
(see Alan Moores interview of TurboPowers President Gary
Frerking in the August 2003 Delphi Informant for all the
details), the announcement sent shock waves through the
Delphi community. And because TurboPower had 10 products in nine categories, our Readers Choice Awards were
deeply affected as well.
In brief, you can expect to see some new products moving into the spotlight in TurboPowers absence. And theres
certainly no shortage of products; this years ballot featured
299, up from last years 228.
In addition, were always tweaking the categories to make
them more accurately reflect the great diversity of products
in the Delphi third-party marketplace. To that end, weve
added three new ones: Security Tool, Team/Project Tool, and
Web Host, so there are now 28.
So lets get to it!
27

DELPHI INFORMANT MAGAZINE | September 2003

Best Accounting Package


Broken tie. Last year,
ColumbuSofts Accounting for Delphi tied for first
place with BS/1 (from
Davis Business Systems
Ltd.). This year however,
Accounting for Delphi
emerged as the clear winner with 33% of the vote,
besting runner-up BS/1
with 23%. Bravo (from Bravosoft) takes third place
for the third year in a row.

Accounting for Delphi (33%)


BS/1 (23%)
Bravo (15%)
Vizacc (11%)
AdaptAccounts (9%)
other (9%)

Best Add-in
Add-in redux. This category
is a near carbon copy of last
years results, with the same
products finishing first, second,
and third. Developer Express
CodeRush (purchased recently
from Eagle Software) took first
place for the fifth straight year,
with 36% of the votes. ModelMaker Code Explorer (from
ModelMaker Tools) took runner-up with 19%, and Multi-Edit
from American Cybernetics took
third with 12%.

CodeRush (36%)
ModelMaker
Code Explorer (19%)
Multi-Edit (12%)
Athlant (11%)
Castalia (8%)
other (14%)

Informant

Spotlight

Shuffling the Deck

Best Book

Best Database Engine

Thunderdome. This year, Best Book


turned into a battle between titans, the
latest editions of the two most popular
Delphi titles: Mastering Delphi 7 from the
indefatigable Marco Cant, and Borland
Delphi 6 Developers Guide by Steve Teixeira and Xavier Pacheco. Cant took first
place with 44%, while
Mastering Delphi 7 (44%)
Teixeira and Pacheco
Delphi 6 Developers Guide (39%)
took runner-up with 39%. other (17%)

Best Charting/Mapping Tool


Steemarolla. Not much new in this
category. Although its percentage
dropped 10 points, from 69% to 59%,
Steema Softwares teeChartPro still
dominates Best Charting/Mapping
Tool, and has done so since the category was introduced in 1998. Thats
six consecutive first-place finishes!
ExpressOrgChart Suite (from Developer
Express) placed second for the third
year running, while Chart FX (Software
FX) has emerged from the pack to
place a solid third.

teeChartPro (59%)
ExpressOrgChart
Suite (18%)
Chart FX (8%)
TatukGIS (7%)
other (8%)

Best Communications Tool


New champ. This
category has been owned
by TurboPowers Async
Professional for the last six
years; last year it took 75%
of the vote! With TurboPower
gone, however, this category
was completely up for
grabs. The new winner is
RemObjects SDK (RemObjects
Software) with 39% of the
vote. IP*Works! Delphi Edition
(/n software) repeats as
runner-up with 22%.

RemObjects SDK (39%)


IP*Works! Delphi Ed. (22%)
DXSock (8%)
Easy MAPI (7%)
ISGMapi (7%)
Xceed Winsock Library (6%)
other (11%)

Best Database Connectivity


New connections.
After placing first and
second for three straight
years, Jason Whartons
IB Objects and ASTA
(ASTA Technology Group)
must be satisfied with
third and fourth. The
two new winners in this
category are Advantage
TDataSet Descendant
(Extended Systems)
with 20%, and FIBPlus
(Devrace) with 15%.
28

Advantage TDataSet
Descendant
(20%)
FIBPlus (15%)
IB Objects (13%)
Asta (11%)
Oracle Data Access
Components (10%)
Direct Access Components
for MySQL (9%)
Direct Oracle Access
Component Set (8%)
kbm MW (7%)
other (7%)

DELPHI INFORMANT MAGAZINE | September 2003

Horror vacui. For three years now,


this category has featured close
competition between DBISAM
Database System (Elevate Software) and Advantage Database
Server (Extended Systems). Advantage Database Server won by 3
percentage points in 2001, and
the products actually tied for first
place in last years balloting. This
year, however, DBISAM has taken
first place in convincing fashion
with 40% of the votes, with Advantage garnering 28%.

DBISAM Database
System (40%)
Advantage Database
Server (28%)
Apollo (9%)
TOPAZ for Delphi (7%)
Pervasive SQL (6%)
other (10%)

Its also interesting to note how these two products are taking
a higher percentage of the total votes. Advantage and DBISAM
combined for 53% of the vote in 2001, and 54% in 2002, but
this year they teamed up to take 68%. This would appear to
indicate that they have moved into the vacuum left by TurboPowers FlashFiler, last years third-place finisher with 20%.
Apollo took third place this year with 9% (down from 15% last
year), with Software Sciences TOPAZ for Delphi nipping at its
heels in fourth place with 7%.

Best Database Tool


So close. After three wins in
a row for Woll2Woll Software
with their InfoPower product,
this year theyll have to be content with runner-up. But it was
extremely close, with winner IB
Expert (HK-Software) taking 21%
to InfoPowers 20%. This marks
a significant gain for IB Expert,
which finished in third place
last year with 13%. It leapt over
ExpressQuantumTreeList (Developer Express), which finished in
third place again this year with
16% (last year it pulled in 18%).

IB Expert (21%)
InfoPower (20%)
ExpressQuantumTreeList
(16%)
EhLib (8%)
MySQL Manager (7%)
Rubicon Text Search (6%)
other (22%)

Best Debugging Tool


Bugs Out. Not only does this
category have a new name (last
year it was Best Testing/Debugging
Tool), but with TurboPowers Sleuth
QA absent, it has a new winner
as well. After three second-place
finishes, this year you selected
Raize Softwares CodeSite as
Best Debugging Tool, giving it
33% of your votes. The runner-up
is AutomatedQAs AQTime with
27%. Thats a big advance for both
products; last year CodeSite got
24%, and AQTime finished in fourth
place with 10%.

CodeSite (33%)
AQTime (27%)
NuMega
BoundsChecker (15%)
ProDelphi
Professional (9%)
other (16%)

Informant

Spotlight

Shuffling the Deck

Best Globalization Tool

Best Library

New world order (kinda). The


players havent changed, but they
did reshuffle a bit. MULTILIZER
VCL Edition (MULTILIZER) wins for
the third straight year with 31%
of the vote. TsiLang Components
Suite (SiComponents) has
second place all to itself MULTILIZER VCL ED. (31%)
this year (with 26%) after
TsiLang Components Suite (26%)
sharing it last year with
Localizer (20%)
Localizer (Korzh.com), which QuickLocalizer Component
Suite (12%)
slipped to third with 20%
this year.
other (11%)

Best Help-authoring Package


No help necessary. It was a bit
surprising last year to see Help &
Manual (from EC Software) emerge
from the pack to win this category
with 29% of the vote, because HelpScribble and RoboHELP had finished one and two the three previous years. But there was no looking
back this year; Help & Manual has
gone on to dominate the category
with 51%. Last years third-place
finisher RoboHELP stepped up to
second with 15%.

Help & Manual (51%)


RoboHELP Office (15%)
HelpScribble (12%)
Doc-O-Matic (9%)
other (13%)

ImageLib Corporate Suite (25%)


LEADTOOLS Imaging Toolkit (25%)
ImageEn (22%)
ImagXpress (14%)
Billenium Effects (9%)
other (5%)

Best Installation Package


Slugfest resolved.
This category continues
to be dominated by the
two installation giants:
InstallShield Software and
Wise Solutions. InstallShield
is clearly pulling ahead in
your estimation, however.
After beating Wise last year
by 6 points, InstallShield has
gone on to best Wise easily
by 19 points.
29

ExpressBars Suite (41%)


ElPack (12%)
ESB Professional
Computation Suite (9%)
QuickExport Component
Suite (7%)
SMExport Suite (6%)
SMImport Suite (6%)
other (19%)

Best Modeling/CASE Tool

Best Imaging Tool


Photo finish. The voting
in this category ended
in a dead heat, so Best
Imaging Tool honors
will be shared this year
among ImageLib Corporate Suite (from Skyline
Tools), and LEADTOOLS
Imaging Toolkit (LEAD

Technologies). And this


category is heating up!
ImageEn from HiCompo-
nents finished a strong
third with 22%.

Into the breach. TurboPowers


SysTools had taken first place in
this category for the last three
years. Last year, however, after
losing ground in 2001, SysTools
edged out runner-up, ExpressBars Suite (Developer Express)
by just three percentage points.
If that trend had continued,
ExpressBars Suite would have
won this year. With SysTools
gone, its a moot point of
course, and ExpressBars Suite
won easily with 41% of your
votes. ElPack (EldoS) finished a
respectable second with 12%.

InstallShield (52%)
Wise for Windows
Installer (33%)
Ghost Installer Studio (7%)
Other (8%)

DELPHI INFORMANT MAGAZINE | September 2003

A question of scale. ModelMaker


and Rational Rose have finished
first and second (respectively) in
this category for three years now,
but ModelMaker Tools offering
continues to pull away from the
Rational Software product. In
2001 they finished with 27% and
22%, last year it was 40% and
21%, and this year the numbers
are 54% and 19%, respectively.
And despite the stiff competition,
Developer Express CDK garnered
a respectable 12% to take third
place. If these trends continue,
Developer Express will be right in
there with Rational.

ModelMaker (54%)
Rational Rose (19%)
CDK (12%)
other (15%)

Best Reporting Tool


Slippery slope. This category
also features a long-time winner, ReportBuilder (Digital
Metaphors), in first place.
However, its numbers have
slipped a bit again this year. In
2001 in had 57% of the votes,
54% in 2002, and this year
the percentage has dropped to
37%. Moving the other direction, FastReport (FR-Software
& A.Tzyganenko) is runner-up
again, and continues to gain
ground. In 2001 it had 12% of
the votes, it had 20% in 2002,
and it has climbed to 29% this
year. Rave BEX (Borland Edition
EXtended) finished third, its
best showing ever, undoubtedly
on the strength of having a version bundled with Delphi.

ReportBuilder (37%)
FastReport (29%)
Rave BEX (Borland
Edition EXtended) (15%)
QuickReport
Professional (7%)
Express Printing
System (6%)
other (6%)

Informant

Spotlight

Shuffling the Deck

Best Scheduling/Calendar
Critical path confirmed. This
category enters its second
year with the same winner
and runner-up. TMS TPlanner/
TDBPlanner (TMS Software)
took first place with 63%
(building on last years 51%),
while Jazmine Calendar/PIM
Widgets (Jazmine Components)
took second place again with
17% (virtually the same as last
years 18%).

TMS TPlanner/
TDB Planner (63%)
Jazmine Calendar/
PIM Widgets (17%)
other (20%)

UIL Security System (28%)


IP*Works! SSL (22%)
PowerTCP SSL Tool (10%)
StrSecII (10%)
TUsers Security
Components (9%)
Xceed Encryption Library (9%)
other (12%)

Best Team/Project Tool


E pluribus unum. Another new
category this year, Best Team/
Project isnt as crowded as the
previous group, but the competition was fierce, with three of the
four contenders making solid
finishes. With 37% of the votes,
Team Coherence (37%)
Team Coherence (Quality Software Components) has first place PVCS Professional (33%)
to itself. Not far behind however, AQdevTeam (27%)
SWBTracker (3%)
is PVCS Professional (Merant)
with 33%. Rounding out the top three, AQdevTeam (AutomatedQA)
placed a very respectable third with 27%.

Best Testing/QA Tool


Test results. AutomatedQA
goes from a respectable third
in the previous category to a
dominating first place in this
one, with its TestComplete
product taking 60% of the
votes. DevPartner Studio (Compuware) and Rational Robot
(IBM Rational) share secondplace honors as each received
18% of your votes.
30

Sir yes sir! Last years


surprise winner, Jensen
Data Systems, takes the
Best Training prize again,
this year with 30% of you
voting for their Delphi
Developer Days workshops. Theres a new face
as runner-up, however,
with Kazoo Softwares 24%
besting last years runnerup InfoCans 15%.

Delphi Developer Days (30%)


Kazoo Software (24%)
InfoCan Management (15%)
Web Tech Training & Dev. (7%)
other (24%)

Best Utility

Best Security Tool


Better safe. This is the first of
three new categories. Security
has become so important, Im
surprised we havent called out
this category before. In previous years, these tools ended
up in various categories such
as Best Utility, so its good to
see them finally competing
head-to-head. First place goes
to UIL Security System (Unlimited Intelligence Limited) with
28% of the votes. The runnerup is IP*Works! SSL (/n software) with 22%.

Best Training

TestComplete (60%)
DevPartner Studio (18%)
Rational Robot (18%)
ANTS Load (4%)

DELPHI INFORMANT MAGAZINE | September 2003

YAT (yet another tie). ASPack


(from ASPack Software) is a
repeat winner with 23% of the
vote (down from last years
30%). But with the absence
of TurboPower, ASPack must
share the win with VM Workstation (VMware), which
managed to pass last years
third-place finisher, Beyond
Compare (Scooter Software),
which improved its percentage
to 16% from last years 12%.

ASPack (23%)
VMware Workstation (23%)
Beyond Compare (16%)
FinalBuilder (12%)
Xceed Zip (9%)
other (17%)

Best VCL Component


Best Grid. Your pick for
Best VCL Component is
ExpressQuantumGrid (Developer
Express) for the third year running.
It got more votes than ever this
year, and a higher percentage as
well 43% as compared to last
years 39%. TAdvStringGrid (TMS
Software) repeats as runner-up
with 16%. Since most of the thirdparty grids fall into this category,
ExpressQuantumGrid can rightly
claim to be Best Grid.

ExpressQuantumGrid (43%)
TAdvStringGrid (16%)
UIL Time Framework (7%)
VCLZip (6%)
TRich View (6%)
other (22%)

Best VCL Component Set


Game, set, match.
Developer Express wins in
this category as well, and for
the second year in a row. You
gave ExpressQuantumPack
28% of your vote (as opposed
to last years 22%). TMS
ExpressQuantumPack (28%)
Software is also a repeat
TMS Component Pack (20%)
as runner-up with its TMS
Raize Components (14%)
Component Pack and 20%.
1stClass (8%)
LMD-Tools (6%)
UIL Plugin Framework (5%)
other (19%)

Informant

Spotlight

Shuffling the Deck

Best Web Development Tool


Something old, something new.
Last years winner, IntraWeb from
AToZed Software, strengthened
its position in this category with a
whopping 62% of the tally (last year
it had 41%). This years runner-up,
ExpressWeb Framework (Developer
Express) replaces last years
runner-up, Internet Professional
(TurboPower) with 25% of the vote,
vaulting past last years third-place
finisher, ASP Express (Marotz Delphi
Group), which fell to fifth place.

Winds of change. ReportBuilder has been the recent


perennial champion in this special category, but its reign
has ended (it actually fell to fifth place!).

IntraWeb (62%)
ExpressWeb
Framework (25%)
PackageForThe Web (5%)
other (8%)

Best Web Host


Host with the most for
Delphi folks. Our last new
category recognizes the Web
host you liked best. Defined
Systems was the clear winner
with 31% of your votes.
There was a tie for runner-up
between Reddi-Web and 1&1
Hosting, each with 17% of
the votes.

Product of the Year

Your new choice for Product of the Year is Help & Manual
from EC Software. The number two spot changed hands
as well, with ExpressQuantumGrid (Developer Express)
replacing Advantage Database Server. Just for fun, here
are the products that placed first and second as POY over
the years:
1996 InfoPower, (unknown)
1997 InfoPower, Orpheus
1998 InfoPower, Apollo
1999 ReportBuilder, Orpheus
2000 ReportBuilder, Apollo
2001 ReportBuilder, Advantage Database Server
2002 ReportBuilder, Advantage Database Server
2003 Help & Manual, ExpressQuantumGrid

Company of the Year

Defined Systems (31%)


Reddi-Web (17%)
1&1 WebHosting (17%)
TDMWeb (11%)
Kylix Host (11%)
other (13%)

A look back. It might also be interesting to look at the


relatively brief history of this award. Company of the Year
goes to the organization with the most first- and secondplace finishes for the year. I decided to create the award
in 2000 to recognize the remarkable achievement of
TurboPower Software that year; they placed first in six
categories a third of the categories at that time.

Hats Off!
As always, I thank the tireless Delphi third-party vendors who
create the products that are the subject of these awards. Without these entrepreneurs who are willing to risk their time and
effort each year, there would be no Delphi community. And,
of course, I thank all of you in the Delphi community for voting. We received the most votes ever this year, which is pretty
amazing since there are fewer of you using Delphi than when
we started the awards in 1996. Youre a more devoted group
now, however, and that makes all the difference.

Company of the Year became a tradition, and TurboPower


won again in 2001 and 2002, but with a slimmer margin
of victory each year. In 2002, TurboPower had three firstplace, and two second-place finishes, with Developer
Express hot on their heels with a win in two categories
and three as runner-up. Again, the trend favored
Developer Express, and they seemed likely to win this
year. Again, well never know because of TurboPowers
departure.

Jerry Coffey is Editor-in-Chief of Delphi Informant Magazine. You can reach


him at jcoffey@DelphiZine.com.

In any case, Developer Express is the clear winner of


Company of the Year for 2003, with four first-place
rankings, and two runner-up finishes. And, unlike previous
years, theres no one even close.

31

DELPHI INFORMANT MAGAZINE | September 2003

N E W

&

U S E D

By Alan C. Moore, Ph.D.

ExpressQuantumGrid 4
More than an Excellent Grid

hen I started working with ExpressQuantumGrid 4 I was overwhelmed. This doesnt


happen very often, but this product is

that feature-rich. To my delight I discovered that it


included features I have long hoped for in a grid. I
also found that its well-designed architecture provides
easy access to its many powerful features, generally
through properties and sub-properties. With its supporting cast of components and editors, it supports a
wide range of data-centric applications.

The heart of this component suite is the cxGrid. With


its many views this grid can work with a variety of
data (from standard databases or custom data) and a
variety of structures. When you drop a component on a
form, its major features the list view, which contains
the raw data, and the table view, which contains the
visual organization of that data are readily available
in the lower-right portion, as shown in Figure 1. Clicking
Customize brings up the component editor shown in the
top right of Figure 1. Here you can add additional list
views or table views. Table views can be regular tables,
banded tables, or card view. In card view, all the data in
a particular row is displayed in its own rectangle. Banded
tables allow you to organize one or more columns into a
band; you can have unmovable bands on the right and
left portions of the grid, with a movable band of columns
in the middle. This is a feature for which I have been
searching for a long time. Tables and cards can be dataaware or unbound.

Figure 2: The main component editor allows you to add, delete, and set the
properties of a grids columns.

After youve created one or more views, you can edit


their properties in the same component editor, adding
or deleting fields, and setting properties for those fields

in the Object Inspector by first selecting the field in the


right-hand column (Selected View). Figure 2 shows an
example of this from one of the demonstration applica-

32

DELPHI INFORMANT MAGAZINE | September 2003

Figure 1: The grid provides easy access to the main component editor, and
access to sub-components on the Object Inspector and other editors by clicking
or right-clicking to bring up context menus.

New

&

Used

ExpressQuantumGrid 4

Figure 3: The Layout Editor provides an intuitive interface for setting up the
appearance of a grid.

tions that ships with ExpressQuantumGrid. You can also


work with the visual appearance of a view by invoking
the Layout Editor (see Figure 3).
ExpressQuantumGrid 4 provides excellent support for
data stored in databases. However, I was surprised by its
level of support for unusual data data that doesnt lend
itself to standard database structures. This was important
to me, because one of my main education applications
keeps track of student grades, and the number of assessments (columns in the grid) can vary from course to
course, and within a course. Working with such data does
require some coding, but the Developer Express team provided some excellent examples that I was able to use as
templates. Ive included a sample application so you can
see what you need to do to support Provider Mode, an
enhanced form of unbound mode that supports retrieving
and saving non-database data from an external file (see
end of article for download details). Figures 4 and 5 illustrate the accompanying sample application.
Editors and Custom Controls
Much of the work of ExpressQuantumGrid is accomplished
through the use of its many editors (described in Figure 6).
These editors may either be attached to various columns in the
grid (as illustrated in Figure 4) or dropped on a form and used
as standalone controls (as illustrated in Figure 5). When you
assign a particular editor to a column, the Properties property
for that object is expanded to provide a series of properties
appropriate to that editor, such as TcxCalcEdit, TcxImage, and
TcxMaskEdit. But some of the new controls, like TcxProgressBar
and TcxSplitter, may seem out of place.
There seem to be two main reasons for including such a wide
range of editors and controls. First, it facilitates close connection between controls, editors, and grids. Second, it enables a
consistent appearance for all controls on a form using Developer Express TcxLookAndFeel class. This class Kind property
determines how the control is painted. Controls can have a
standard look, a flat look, or an ultra-flat look, or they can use
the Windows XP default setting. I think there is a more elegant
solution a meta-component that is aware of all the components on a form and paints them all, whether or not they were
produced by Developer Express. I plan to explore this idea
33

DELPHI INFORMANT MAGAZINE | September 2003

Figure 4: This dialog box uses standalone editors and shows the flat look.

further with the folks at Developer Express and maybe make


some specific suggestions.
Included in the many useful controls that accompany this
library are a tab control and a page control. The former contains a set of tabs and a client area. Its client area of the control can contain any number of other controls, and you can
dynamically change the contents of those controls by handling the OnChange event. The page control extends the functionality of the tab control by allowing you to create separate
page panels for each tab with different controls on each.
Extended Editors
As I was working on this review, Developer Express came out
with a series of extended editors that will be available not just
for this component set, but for all of their component sets.
Some of the components in the extended editor collection
arent strictly editors; theyre enhanced custom controls that
add considerable value to this suite. As with the previous
editors, these controls fall into three groups that are reflected
in their organization on the Component palette: editors, dataaware editors, and utility controls (see Figure 7). Most of the
controls and editors also have data-aware versions. Other
controls include the TcxShellTreeView, TcxShellComboBox,
TcxShellListView, TcxTreeView, and TcxListView.
Help, Demos, and Tutorials
The Help files that accompany the various components of
this library are superb. Theyre extremely detailed, include
many diagrams and screenshots, and feature helpful cross
references. Help is provided even for the lowest support
classes. After printing a large amount of material to study, I
would like to see Developer Express take all this voluminous
material and organize it into a PDF manual.
One of the most attractive features of this product is the
extensive series of demonstrations and tutorials that cover
just about every major feature of this library. Theyre structured so that when you properly complete a particular tutorial it will be identical to the similarly named demonstration. If you want to get a quick idea of a particular feature
set, simply run the demo. If you need help learning the

New

&

Used

ExpressQuantumGrid 4

Just the Facts


ExpressQuantumGrid 4 is a complete solution for any gridbased application. It includes a full complement of editors and
controls that provide powerful features and considerable flexibility. You can use it for standard databases or custom data.
The help, demonstrations, and tutorials are unsurpassed.

Figure 5: The main form shows the grid with a group box and button, all using
the ultra-flat look.

techniques involved, you should complete the tutorial. Its


great to have a choice. And the tutorials dont require that
you build applications from the ground up, because the
team at Developer Express has built all the requisite forms
and written the essential code. All that remains is setting
some properties and un-commenting some code! If you have
any doubts about what the demo/tutorial features, simply
click on Help/About and youll get all the clues you need.

Developer Express Inc.


6340 McLeod Drive, Suite 1
Las Vegas, NV 89120
Phone: (702) 262-0609
E-Mail: info@devexpress.com
Web Site: www.devexpress.com
Price: ExpressQuantumGrid 4, US$399.99 (US$349.99 without source). Upgrades from ExpressQuantumGrid 3, US$199.
ExpressQuantumGrid 4 is also available in the ExpressQuantumPack, US$699.99.

TcxBlobEdit, TcxDBBlobEdit Editor classes for working with


BLOb (Binary Large Object) data, capable of storing and
editing memo and image data.

TcxListBox A control that implements the functionality


of TListBox. As with other controls, it adds look-and-feel
functionality.

TcxButton An enhanced descendant of TButton that works


in three modes, two of which provide drop-down functionality
where clicking the button opens a specified popup menu.

TcxLookupComboBox A combobox in which field values are


displayed within the editor drop-down window that contains a
TcxLookupGrid control.

TcxCalcEdit An editor that incorporates a drop-down


calculator, enabling users to perform arithmetic operations such
as /, *, -, +, square root, %, 1/x, and to store the result in the
edit value of the control.

TcxMaskEdit A masked edit control that can validate and


format text a user enters against a mask, ensuring the texts
validity. There are many built-in masks, and you can create
custom masks.

TcxCheckBox A check box class in which users can select


an option; it can be programmed to have two (checked,
unchecked) or three (checked, unchecked, and grayed) states.

TcxMemo A memo control that allows displaying and editing of


multi-line text.

TcxComboBox A combobox in which users may enter text


in the editor and have that text be automatically completed to
match a value from the drop-down list.

TcxMRUEdit An MRU (most recently used) text editor that stores the
most recently inputted strings in its associated drop-down list.
TcxNavigator A navigator control that can manage external controls that dont have an assigned dataset.

TcxCurrencyEdit A currency editor that supports regional


settings.

TcxPopupEdit A text editing control that enables the embedding of


another control in the associated popup window.

TcxDateEdit An editor that allows the selection and editing


of date values in various ways, including via a drop-down
calendar and using appropriate regional settings.

TcxRadioButton A control that implements the functionality


of a TRadioButton. As with other controls, it adds look and feel
functionality.

TcxExtLookupComboBox A combobox that displays a dataaware grid view in its drop-down window, allowing the user to
select a record.

TcxRadioGroup A control that includes a number of grouped


radio buttons that affect each other; if a user checks one, the others
become unchecked.

TcxHyperLinkEdit A specialized editor that presents its


contents as a hyperlink, allowing users to edit text and
represent it as a hyperlink and execute a recognized system
command.

TcxSpinEdit An enhanced spin editor that allows editing numerical


values by clicking so-called spin buttons or up/down arrows displayed within an editor.

TcxImage An image-displaying editor that supports several


formats (JPEG, bitmap, icon, and metafile), allowing the user to
load and save graphical data from/to a file.

TcxTextEdit An enhanced single-line text editor that allows selecting text within the text editor, copying or cutting the selection to the
clipboard, and special functions such as entered value validation or
automatic completion functionality.

TcxImageComboBox A combobox that includes a list of


images with corresponding text descriptions within the dropdown window.

TcxTimeEdit An editor with spin buttons; this allows the user to


increment or decrement the time-value portion (hours, minutes, or
seconds) selected with the cursor.

Figure 6: Editors and controls that enhance the work of the grid.

34

DELPHI INFORMANT MAGAZINE | September 2003

New

&

Used

ExpressQuantumGrid 4

TcxLabel (TcxDBLabel) Enhanced label that supports various


visual effects, including 3-D shadows.
TcxProgressBar A progress bar that can be displayed in various
orientations, with a variety of fill characters, and with other special
features.
TcxTrackBar A track bar with flexible display capabilities.
TcxCheckListBox A list box control that includes a check box for
each item allowing users to select and unselect items.
TcxColorComboBox A combobox that displays a list of colors
(with text descriptions) from which users may choose.
TcxFontNameComboBox A combobox control that displays system fonts and includes a font preview area.
TcxCheckComboBox A combobox control that includes a check
box for each item allowing users to select and unselect items.
TcxGroupBox A group box that includes caption-text positioning
and alignment, background color, and XP painting; it can also be
used as a panel.
TcxSpinButton A spin button enhanced with fast navigation,
moving incrementally or by larger values when a user presses a
fast button or a PageUp/PageDown key.
TcxHintStyleController A specialized component that supports
centralized control over an applications hints appearance and
behavior with customized control over many aspects such as background and border color, display icons, animation, and so on.
TcxMCListBox A multi-column list box, including a header panel
with column headers.
TcxSplitter A splitter enhanced with various hot zone styles.
TcxHeader Resizable headers that can support several header
sections with borders.
Figure 7: Extended editors and controls included with this and other Developer
Express products.

35

DELPHI INFORMANT MAGAZINE | September 2003

Conclusion
This is one component library that lives up to all the praise
it has received. The only problem I encountered in working
with a mask edit control was quickly solved by personnel at
Developer Express. Download the executable program and
the source code for the testing application I wrote and give it
a spin. And be sure to visit the Developer Express Web site
and download some of the excellent demonstrations.
An application that demonstrates the mask edit control (on a
grid and as a separate edit control) is available for download
on the Delphi Informant Magazine Complete Works CD
located in INFORM\2003\SEP\DI200309AM.

Alan Moore is a professor at Kentucky State University, where he teaches


music theory and humanities. He was named Distinguished Professor for
2001-2002. He has been named the Project JEDI Director for 2002-2004. He has
developed education-related applications with the Borland languages for more
than 15 years. Hes the author of The Tomes of Delphi: Win32 Multimedia
API (Wordware Publishing, 2000) and co-author (with John C. Penman) of
The Tomes of Delphi: Basic 32-Bit Communications Programming (Wordware
Publishing, 2003). He also has published a number of articles in various
technical journals. Using Delphi, he specializes in writing custom components
and implementing multimedia capabilities in applications, particularly sound
and music. You can reach Alan at acmdoc@aol.com.

F I L E

N E W

Open Source Roundup

By Alan C. Moore, Ph.D.

hen I last wrote about Project


JEDI (Joint Endeavor of Delphi
Innovators; delphi-jedi.org) I promised
to write more about open source. There
was a time when open-source projects
in Delphi were few and far between,
but this is no longer the case. GExperts
(www.gexperts.org) has been opensource for several years. Indy (or
Internet Direct; sourceforge.net/
projects/internetdirect), the popular
component set that supports
common Internet protocols, has
been distributed with recent Delphi
versions. And now there are new
developments that have expanded
the movement beyond even the most
optimistic developers expectations.
As with most of the Project JEDI
libraries and projects, many other
open-source Delphi projects are hosted
by SourceForge (sourceforge.net). In
fact, there are 1,105 projects listed in
the Delphi/Kylix category! There are
prominent projects listed, as well as
others that are narrowly focused on
particular professions or application
types everything from games to
e-mail tools. Dont assume that the
category of Delphi/Kylix means all the
projects are cross-platform; some are,
but many are not.
Note: When you first visit the site,
click on Software Map. You can then
pick a particular topic (I checked out
36

Multimedia) or programming language


to see all the Delphi projects. Theres
also a helpful search facility if you
have something specific in mind. One
important non-Delphi project that should
be familiar to many readers is Firebird,
the relational database project that grew
out of Borlands decision to open-source
InterBase (firebird.sourceforge.net).
Sites with information or links. If
youre new to the concept of opensource and would like to have a
comprehensive introduction, visit
www.opensource.org, home of the
Open-source Initiative (OSI), where
you can find many of the Halloween
pieces written by Eric S. Raymond,
author of the famous open-source
book, The Cathedral and the Bazaar.
Of course, the emphasis is on Linux,
but you may learn some useful things
about open source and I have no
doubt youll be entertained.
The most comprehensive non-Borland
Delphi sites remain the Delphi Super
Page (delphi.icm.edu.pl) and Torrys
Delphi Pages (www.torry.ru). These
sites contain links to a variety of
Delphi materials, including opensource projects. A relatively new site
is Delphi Stargate (www.e-naxos.com/
scripts/st2001.dll/links). Although
many of the links take you to sites in
French, the organization is excellent
and there are some real gems.

DELPHI INFORMANT MAGAZINE | September 2003

Bombshell hits Delphi community.


TurboPower was for years the leading
third-party tool provider for many of
Borlands development tools, especially
Delphi and C++Builder. TurboPowers
decision to no longer sell these tools
making many, but not all, of them
available as open source rocked
the Delphi community. To learn
more about this monumental event
see my interview with TurboPowers
president, Gary Frerking, in the August
issue of Delphi Informant. [Space
limits my coverage of the TurboPower
libraries. For additional information,
refer to the many reviews available
at the Delphi Informant Web site
(www.DelphiZine.com), or on the
Delphi Informant Complete Works CD.]
Although not all of TurboPowers
component libraries are available
as open source, the most popular
ones can be found at SourceForge.
Several of them (Async Professional,
SysTools, Abbrevia, and LockBox)
are cross platform and feature
CLX versions and VCL libraries
or Pascal files that work in either
environment. Async Professional
(sourceforge.net/projects/tpapro) was
among the most popular TurboPower
component libraries. This extensive
set of communications components
provides access to serial ports, TAPI,
and Microsofts Speech API (SAPI),
with support for sending faxes,

File

New

terminal emulation, etc. Its available


for both Delphi and Kylix.
Orpheus, another popular and awardwinning library from TurboPower,
is also available on SourceForge
(sourceforge.net/projects/tporpheus).
This collection of more than 120
user-interface components includes
data entry controls, calendars, clocks,
complex components that mimic
advanced controls used in Microsoft
Outlook, and more.
SysTools (sourceforge.net/projects/
tpsystools) is one of the first
TurboPower libraries I reviewed, and
it remains one of my favorites. This
collection of routines and classes
supports a variety of low-level needs,
including bar codes, data sorting,
monetary routines, high-precision
math, and more.
Database support. Database
programming is one of the strongest
and most important areas of the Delphi
development universe. TurboPower has
two players in this arena.
B-Tree Filer (sourceforge.net/projects/
tpbtreefiler) originated in the days of
Turbo Pascal and works with that tool,
as well as with Delphi. This B-Tree Filer
library of file-based, database routines
works with stand-alone programs,
or with those running on Microsoftcompatible networks, including Novell.
FlashFiler (sourceforge.net/projects/
tpflashfiler) is a client-server database
that can be used as a substitute for
the BDE. Like the BDE, it uses a
component-based architecture and
a server engine. The latter can be
embedded in an application.
There are many non-TurboPower tools
supporting database development,
including the Zeos Library
(sourceforge.net/projects/zeoslib) and
TDBF (sourceforge.net/projects/tdbf).
The former is a set of native Delphi
datasets and database components
for MySql, PostgreSql, InterBase, MS
SQL, Oracle, and DB/2. The library
includes development tools such
as Database Explorer and Database
Designer. TDBF is a freeware native
data access component that enables
the creation of compact database
programs that dont require any
special installer programs (to install
37

the BDE, for example). This is


possible because its database engine
is compiled into the executable.
There are many tools that provide
support for InterBase and Firebird.
Marathon (sourceforge.net/projects/
gmarathon) is a SQL Tool for Firebird
and InterBase. Its a feature-rich, clientor server-side-based GUI development
tool that works with all the Firebird
and InterBase database objects, such as
tables, triggers, stored procedures, etc.
Other components and libraries.
Developers often need a good tool to
create reports. Report manager
(reportman.sourceforge.net) is a
reporting application (Report Manager
Designer) and a set of Delphi
components that also supports Kylix
and other platforms. It includes a TCPenabled Report Server that enables thin
clients to obtain reports processed in the
server. There is also a Web report server
application that can generate Adobe
PDF files on the fly. Report Manager
has many interesting features, including
single-page sub-reports, metafile reports,
and child sub-reports. Delphi and Kylix
developers can include the reporting
engine in their applications. Visit the
SourceForge site for more information.
In addition to the large libraries
described above, TurboPower
produced some outstanding smaller
libraries to meet specific developer
needs. One such product, LockBox
(sourceforge.net/projects/tplockbox),
is a powerful, cross-platform toolkit
for data encryption. It contains
encryption routines and components
with support for Blowfish, RSA, MD5,
SHA-1, DES, triple-DES, and Rijndael,
as well as digital signing of messages.

formats, as well as the creation of


self-extracting archives. It includes
visual components that simplify the
manipulation of ZIP files.
Essentials (sourceforge.net/projects/
tpessence), TurboPowers eclectic
collection of 13 native VCL controls,
includes drop-down calendars,
calculators, roll-up dialogs, 3-D labels,
tiled backgrounds, scrolling messages,
menu buttons, and more. Another
library, ShellShock (sourceforge.net/
projects/shellshock) contains
components that provide access to
much of the functionality of the
Windows shell and Windows Explorer.
Id like to mention two last
TurboPower libraries. The first,
Internet Professional (sourceforge.net/
projects/tpipro) is a set of VCL
components providing Internet
connectivity for Delphi and
C++Builder. iPRO includes POP3,
SMTP, NNTP, FTP, HTTP, Instant
Messaging, and HTML viewer
components, as well as components
for low-level socket access. Last among
TurboPowers libraries, Visual PlanIt
(sourceforge.net/projects/tpvplanit)
provides a set of synchronized,
data-aware components for adding
time, task, and contact management
capabilities to applications.

Another collection, OnGuard


(sourceforge.net/projects/
tponguard) is a Demo/Provisional
tool that enables developers to
create demonstration versions of
applications that are time-limited,
feature-limited, limited to a certain
number of uses, or limited to a
certain number of concurrent
network users.

Among the more specialized types of


components and tools are syntax-highlighting memo controls. If youre writing
special editors or wizards that manipulate code, youll probably want to use
a syntax highlighter. This came up for
me when I worked with another Project
JEDI member, Michael Beck, to create
a GUI front end for Bob Swarts Header
Converter tool (donated to Project JEDIs
DARTH Team). Although there was an
excellent commercial product available,
we wanted to find an open-source solution. That solution turned out to be
SynEdit (synedit.sourceforge.net). This
multi-line edit control isnt a wrapper for a Microsoft Windows control,
and doesnt depend on any run-time
library. Its packaged with highlighter
classes supporting ma ny programming languages.

Abbrevia (sourceforge.net/projects/
tpabbrevia) provides compression
functionality, and supports PKZIP
4, Microsoft CAB, TAR, and gzip

Beyond components. Of course,


not all projects are components
or component libraries. Some
are programmer utilities. For

DELPHI INFORMANT MAGAZINE | September 2003

File

New

example, many developers follow


a particular code formatting style
or discipline. Its helpful to have
a tool to implement such a style.
In addition to the JEDI Code
Formatter, there is a freeware
Code Formatter called DelForExp
(available at www.dow.wau.nl/aew/
DelForExp.html).
There are many commercial modeling
products available. In the world of
open source there is ESS-MODEL
(sourceforge.net/projects/essmodel)
which proclaims itself as the fastest
and easiest to use UML reversing
tool! With ESS-MODEL you can
view class diagrams from your code
in the time that other tools are still
busy loading. Its written in Delphi.
If you read Delphi Informant
regularly you probably know about
DUnit (sourceforge.net/projects/
dunit), a tool that automates unit
testing of Delphi code. In Extreme
Testing, a recent Delphi Informant
article, Ralph Krause explained how

38

to use DUnit in a program of regular


testing, the approach advocated
by Extreme Programming. DUnit is
based on an older project, JUnit.
Benefits and limitations. Opensource software has many benefits,
but it also has some limitations.
We usually think of the financial
savings as one of the main benefits.
However, there is a less obvious
benefit. Sometimes you can find a
solution to a programming need in
the open-source community that may
not be available anywhere else. Or if
it is available commercially, you are
forced to pay for other components
you dont need.

There are also limitations. The two


that come to mind immediately are
less support and a slower development
curve. Support is built into the cost of
commercial software. It includes static
support everything from help files,
tutorials, and other documentation
as well as dynamic support, such as
newsgroups, e-mail, and phone consultation. Although some level of support
may be available in open-source software, it can seldom compete with what
is available in commercial software.
This concludes our brief tour of
open-source projects. I know Ive
probably missed a few gems; please
contact me so I can include them in a
future column. Until next time...

Alan Moore is a professor at Kentucky State University, where he teaches music theory and humanities. He
was named Distinguished Professor for 2001-2002. He has been named the Project JEDI Director for 2002-2004.
He has developed education-related applications with the Borland languages for more than 15 years. Hes the
author of The Tomes of Delphi: Win32 Multimedia API (Wordware Publishing, 2000) and co-author (with
John C. Penman) of The Tomes of Delphi: Basic 32-Bit Communications Programming (Wordware Publishing,
2003). He also has published a number of articles in various technical journals. Using Delphi, he specializes in
writing custom components and implementing multimedia capabilities in applications, particularly sound and
music. You can reach Alan at acmdoc@aol.com.

DELPHI INFORMANT MAGAZINE | September 2003

Das könnte Ihnen auch gefallen