Вы находитесь на странице: 1из 39

July

2003

Volume 9 Number 7

INSIDE
ON THE COVER
Lifecycle Management

Model-driven Delphi: Part I

From UML to ModelMaker to Bold for Delphi, Peter Morris


introduces Delphi 7s approach to model-driven architecture
and demonstrates how to use it to create your own apps. Delphi
7 Architect is an aspect of Borlands Application Life-cycle
Management initiative, so this is key information.

Reviewed: CDK 7, InfoPower 4000, and RemObjects SDK

Delphi Informant

Breaking Encapsulation

Peter Gatis explains the importance of encapsulation and debunks


some of the common misconceptions that surround it. He then
describes how easy it is to break often unintentionally.

Greater Delphi

14

Safety .NET: Part II

Last month, Bill Todd described the security features of the .NET
run-time environment. This month, he explains how to use those
security features in your Delphi for .NET applications.

The Complete Monthly Guide to Delphi Development

July 2003 vol. 9, no. 7

The Model Is
the Application

FEATURES
On Language

www.DelphiZine.com

Breaking Encapsulation:
Easier than You Think
Programming .NET
with Delphi Page 20

Page 15

Security

Converting Delphi Form Files to

.NET-ready Source

Page 25

Remote Exception Reporting


Including Screen Shots

$5.99 US

Page 30

$8.99 CAN

Cover Art by Arthur A. Dugoni Jr.

Foundation Class

19

The Dfm2Pas Utility

Need to get your Delphi apps to .NET now? Then youll want to
read along as Fernando Vicaria explores the Dfm2Pas utility, a
program that converts .dfm files into .NET-compatible .pas files.

Delphi at Work

23

Warning Signs

Simon Murrell demonstrates how to add a simple notification


mechanism to your distributed Delphi apps. It will automatically e-mail
you an error message and a screen shot! when an error occurs.

REVIEWS
26 CDK for Delphi

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

29

InfoPower 4000

33

RemObjects SDK

36

Mastering Delphi 7

36
1

Product Review by Bill Todd


Product Review by Ron Loewy
Book Review by Alan C. Moore, Ph.D.

Web Services Development with Delphi


Book Review by Warren Rachele

DELPHI INFORMANT MAGAZINE | July 2003

D E PA R T M E N T S
2 Toolbox
38 File | New by Alan C. Moore, Ph.D.

T O O L B O X
Nevrona Provides Many Editions of Rave Reports 5.0

Several editions of Rave Reports 5.0. are


available from Nevrona Designs. Built
on the foundation of Nevronas ReportPrinter Pro, Rave Reports is a suite of
reporting components and classes.
Rave Reports 5.0 SE (Standard
Edition) provides the complete
Rave visual report design tool, as
well as a copy of a single user Rave
Server. Rave Standard also includes
SQL DataViews (drivers) to enable
direct connect or Web-oriented
access to reports from Microsoft
ODBC, Microsoft SQL Server, Apollo,
Advantage, DBXpress, Access, and
DBISAM databases.
Rave Reports 5.0 DE (Developer
Edition) includes everything in the
Standard version plus the DLLs
required to interface the reporting
system into an application. Programmer documentation is included.
Rave Reports 5.0 BEX (Borland Edition eXtended) includes everything
from the standard Developer Edition
visual features and continues to provide a powerful and flexible suite of
reporting components and classes
that are in its predecessor, ReportPrinter Pro. The code-based reporting
system contains numerous components with hundreds of methods,
properties, and events, and compiles
into your application with no external files. Some of its features include
word-wrapped memos, full graphics,
justification, precise page positioning, real-world measurements, printer
configuration, font control, and fullfeatured print preview. Rave 5.0 BEX
can handle banded style reports,
form letters, invoices, snaking col-

umns, preprinted forms, and any


other report you want to create.
A scaled down version of Rave
Reports 5.0 BE is included with Delphi
7. However, there are distinct differences between the version that ships
with Delphi 7 (Rave Reports 5.0 BE)
and Nevronas Rave Reports 5.0 BEX,
including: Rave Reports 5.0 BEX provides backward compatibility to Delphi
4, 5, and 6 (Rave Reports 5.0 BE does
not offer this); Rave Reports 5.0 BEX is
directly supported by Nevrona Designs
International and Nevrona Designs
USA (Rave Reports 5.0 BE is supported
directly by Borland); and Rave Reports
5.0 BEX provides the source code to
the components.
Rave 5.0 Report Server. A singleuser version of Rave 5.0 Report
Server is included with Rave SE, DE,
and BEX. Rave Server is the central
repository and library for storage and
execution of all Rave reports. The
server executes the report command
request from an authorized client
and sends the completed report in
HTML, PDF, or Rave native format
to the requesting client. The client
can execute Rave Server and receive
reports using only their browser.
Designed to be scalable from a
few users to many thousand, Rave
Server can grow as needs expand,
even to the extent of supporting
load balancing over multiple servers.
Licensing is based on the number of
concurrent users.
Nevrona Designs
Price: See Web site for complete details.
Contact: cust@nevrona.com
Web Site: www.nevrona.com

Gnostice RaveRender 1.2 Released


Gnostice announced a new release of
Gnostice RaveRender (version 1.2).
RaveRender is an enhanced rendering
add-on for Rave Reports. You can save
your Rave reports to PDF, HTML, RTF,
Excel, Text, JPEG, GIF, BMP, EMF,
and WMF file formats. You get more
than just Save Report functionality.
RaveRender 1.2 offers end-user
dialogs (to configure the export),
watermarking facilities, e-mailing of
saved reports, Web reporting facilities,
and more. RaveRender supports Delphi
4-7 and C++Builder 4-6.
2

DELPHI INFORMANT MAGAZINE | July 2003

This version introduces support


for Rave Reports 5.0 BE and BEX,
improved Excel output, support for
multiple page layouts in a single
report, and documentation updates.
Visit the Gnostice Web site to
download a trial version or see the
full feature list.
Gnostice Information Technologies
Price: Single-developer license, US$119. Multi-user
license discounts are available. Version 1.2 is a free
upgrade to all registered users of 1.x.
Contact: info@gnostice.com
Web Site: www.gnostice.com

SkyLine Tools Releases


Corporate Suite VCL 7
SkyLine Tools Imaging announced
Corporate Suite VCL 7, which
enables the integration of document imaging, Internet imaging,
and color and grayscale imaging
into Delphi applications.
The new suite includes the Delphi
source code to a complete end-user
document imaging application.
Simply choose your target industry,
make some minor changes, and
add some documentation.
New features in this suite include
rubber band blackout for hiding
text, a rubber band cropping tool,
encryption, despeckle, new color
imaging formats for digital cameras, and black border removal.
Other new document imaging
features include turbocharged multithreaded scanning, duplex scanning,
anti aliasing, deskew, and more. Also
added to this version of the suite is
the ability to read raw images from
more than 50 digital cameras.
Corporate Suite VCL 7 also provides a thumbnail manager, which
organizes and numbers thumbnails
and multipage tiffs. Additionally,
the magnifier lets users magnify
words and sentences rather than
requiring an overall zoom of the
image. And, the annotation capabilities allow users to mark up
images on-screen and save them
separately or burn them into
the document. The user can add
arrows, underline text, highlight
areas, and add Post-it notes and
time/date stamps.
Corporate Suite VCL 7 is also
equipped with image correction
effects (brightening, contrast, color
reduction, and rotation), manipulation and deformation tools, and
offers over 40 filters for handling
color image files.
Corporate Suite VCL 7 is compatible with Delphi 5, 6, and 7. You
can download a trial version from
the companys Web site.
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
DLite 1.0 Build 7.1 Released
Software by Martin released DLite 1.0
Build 7.1. DLite is a Delphi companion
tool that allows you to edit, compile,
and run pre-existing Delphi projects.
DLite gives you access to the DCC32
command-line compiler to compile any
project using any installed version of
Delphi 2-7, including the Delphi for
.NET preview included in Delphi 7.
The editor has the familiar look and
feel of the Delphi IDE.
DLite has incorporated icons from
GlyFx (www.GlyFx.com). You can now
configure DLite to use these colorful and aesthetically pleasing icons in
all menus and the toolbar. If you use
the GlyFx icons, you also have the
option to use large icons in the toolbar.
DLites classic icons are still available. Along with new GlyFx icons,
you can also configure which buttons
appear in DLites toolbar.
The search and replace functionality
has been rewritten and improved to
act just like the Delphi IDE, giving you
such options as Case Sensitive, Whole
Words Only, Prompt on Replace, Direction, and Origin.

In addition, an
editor option to
toggle Overwrite
Blocks has been
added. With this
option enabled, a
highlighted block
will be overwritten
if text is typed in.
Otherwise, typedin text will be
appended to the
highlighted block.
An environment
option to Load
desktop files for
projects, project
groups and packages has been added. With this option
enabled, DLite will read the .dsk file
associated with the project, project
group, or package being loaded and
automatically load any files that were
on the desktop.
A new menu option called Resize
and Center has been added to the
View menu. Depending on your current
screen resolution, this menu allows

Borland Launches Enterprise C# Development


Solution for the Microsoft .NET Framework
Borland Software Corp. announced
the launch of Borland C#Builder for
the Microsoft .NET Framework, the
first independent enterprise-focused
solution for .NET Framework-based
development. An integrated development environment for the C#
programming language, C#Builder
provides a design-driven development
paradigm for rapid application maintenance and integral support for connecting to back-end J2EE and CORBA
software infrastructures. C#Builder is
also designed to deliver high-performance native support for all major
enterprise-class database management
systems.
Borland C#Builder offers enterprise
design-driven development through
close integration with Borland Together and the Borland C#Builder Enterprise Core Objects (ECO) platform,
significantly improving time-to-market
by helping designers and developers work together iteratively. It also

DELPHI INFORMANT MAGAZINE | July 2003

enables high-performance seamless


database development and interoperability with enterprise databases
such as Borland InterBase, IBM DB2,
Microsoft SQL Server, and Oracle 9i.
Borland C#Builder addresses the
integration needs of enterprises with
mixed IT infrastructures by providing
support for direct .NET connectivity
with J2EE and CORBA to maximize
existing enterprise infrastructures. It
provides companies with the freedom
to choose the components of the
application development lifecycle that
best meet an organizations needs
with an integration platform that supports Borland and third-party application lifecycle management solutions.
Borland C#Builder will be available
in the summer of 2003. For additional
product information, visit the Borland
Web site.
Borland Software Corp.
Contact: (831) 431-1000
Web Site: www.borland.com

you to quickly resize and center the


main DLite screen to predefined common screen sizes. You can also quickly
access these options by pressing their
associated shortcut keys.
Software by Martin
Price: Single-user license, US$18; 5-user license,
US$55; 10-user license, US$88; site license, US$165.
Contact: info@softwarebymartin.com
Web Site: www.softwarebymartin.com

MsgConnect Released
EldoS Group released MsgConnect, an
open source cross-platform framework
for data exchange.
MsgConnect encapsulates low-level
transport protocols (currently TCP and
memory-mapped files) and provides a
uniform API for exchanging binary information on a single system or across a
network.
MsgConnect uses the paradigm of
messages, which are well known to
Windows developers. MsgConnect
provides optional support of Rijndael
(AES) encryption, ZLib compression and
CRC32/Adler32/MD5 integrity checking.
MsgConnect is available for a variety of
platforms and development tools, including Windows (Delphi, C++, VB, DLL/
ActiveX, .NET), Linux/Unix/QNX (Kylix,
C++/gcc), Windows CE, and Java 2
SE/EE. Palm and Java 2 ME support is
under development.
MsgConnect can be used in both opensource and commercial applications. See
Web site for licensing information.
EldoS Group
Contact: info@eldos.org
Web Site: www.msgconnect.com

T O O L B O X
Nix Software Solutions Announces Nix
Components 2.5
Nix Software Solutions announced
the availability of Nix Components 2.5,
a multi-purpose suite of more than 77
visual and non-visual components for
Delphi and C++Builder. In addition
to improvements and bug fixes, this
version introduces two new features
that add great value to the product:
FlySize and FlyDrag.
FlySize enables supporting controls
or their parent forms to be dynamically resized at run time. One mode
delivers a turnkey solution for presenting the user with resizable panels
and bevels in graphical and layout
design applications, whereas another
mode causes the border of a FlySizeenabled control to mimic its parent
forms sizing border, even if there is
none. FlySize makes it easy to give
borderless forms resizing capabilities:
simply drop a TNixPanel control on a
borderless form, align it to alClient, and
set its FlySize property to fsForm.
FlyDrag complements FlySize by
allowing visual controls or their parent
forms to be dynamically dragged at
run time. One mode makes the surface
of a FlyDrag-enabled control mimic
its parent forms title bar, even when
there is no such thing. This makes it
possible for end users to move border
and captionless forms simply by dragging FlyDrag-capable controls as if they
were virtual title bars.
To give developers complete and precise control over FlySize and FlyDrag,
supporting controls publish events
that are triggered immediately before

Developer Express
Acquires Eagle Software

any changes in size and dimensions


occur. These events pass variable
coordinate parameters, which can be
modified to alter the new coordinates
or even inhibit resizing and dragging
under certain conditions.
Nix Components 2.5 also introduces
a new RememberCoords property in the
TNixFormHelper component, which,
when enabled, causes a forms dimensions and placement on the screen to be
remembered across sessions and automatically restored whenever the form
is recreated. RememberCoords has been
implemented in all the enhanced property editors included in the package, which
also now sport customizable font styles.
Developers interested in Nix Components can download a free fully functional evaluation version from Nix Software
Solutions Web site.
Nix Software Solutions
Price: Standard, US$89.95; Professional
(includes data-aware controls), US$104.95.
Contact: sales@nixsoftware.com
Web Site: www.nixsoftware.com

Developer Express has acquired


Eagle Softwares complete product
line, which includes CodeRush, CDK,
and reAct. Mark Miller is now Chief
Architect of Developer Express new
IDE Tools Division.
Mark Miller and Eagle Software have
engineered cutting-edge IDE tools for
Delphi and set the standard for the
most complete range of products of
their kind. Developer Express plans to
chart an aggressive course to expand
their IDE tool offerings for Microsoft
and Borland development tools.
CodeRush Professional for Delphi
is now available from the Developer
Express Web site for US$250. This
product supports the Delphi 3-7
IDEs. Eagle Software customers with
a current license for a single IDE
edition of CodeRush can upgrade to
a full CodeRush license for US$99.
Plans to integrate CDK and reAct
into the Developer Express product
line are under way.
The Developer Express Subscription
plan will include these three products
as well. Developers with an active
Developer Express Subscription will
receive a license of CodeRush for Delphi as part of their ongoing subscription and will receive licenses for CDK
and reAct when the integration of
those products is completed.
Developer Express Inc.
Web Site: www.devexpress.com

Delphi Programming
with COM and ActiveX

C# for Dummies

Mission-Critical
Security Planner

Model Driven Architecture

V. Ponamarev
Charles River Media
ISBN: 1-58450-254-1
Cover Price: US$44.95
(312 pages)
www.charlesriver.com

Stephen Randy Davis


Hungry Minds
ISBN: 0-7645-0814-8
Cover Price: US$29.99
(426 pages, CD-ROM)
www.hungryminds.com

Eric Greenberg
Wiley Publishing, Inc.
ISBN: 0-471-21165-6
Cover Price: US$35
(416 pages)
www.wiley.com

David S. Frankel
Wiley Publishing, Inc.
ISBN: 0-471-31920-1
Cover Price: US$40
(328 pages)
www.wiley.com

DELPHI INFORMANT MAGAZINE | July 2003

LIFECYCLE
MDA

BOLD FOR DELPHI

MANAGEMENT

MODELMAKER

UML

DELPHI 7

By Peter Morris

Model-driven Delphi
Part I: The Model Is the Application

orland has been a trendsetter for many


years. They often lead the way with new
ideas for software development, with the

competition soon afterward releasing versions


of their tools boasting similar features. Recently
however, Borland has had to play catch up.

Visual Studio from Microsoft has been .NET-enabled for


some time, yet we Borland customers are still waiting
for a full-fledged .NET product. I predict this is all about
to change with the ever increasing popularity of modeldriven architecture (MDA). And even more so now that
Borland has announced it is making this new MDA technology .NET compatible!
This article will introduce you to model-driven architecture,
and demonstrate how to start using this technology to write
your own applications. Well cover the requirements to get
you started, how to start modeling your application, and
how to use your model to create an application. Youll also
be introduced to
more advanced
subjects of MDA
in Delphi, such
as OCL (Object
Constraint
Language),
model refactoring
and database
evolution, and
object subscription
(akin to the
Observer pattern).
Figure 1: Project options.
5

DELPHI INFORMANT MAGAZINE | July 2003

What Is MDA?
Model-driven architecture is a difficult technology to
describe briefly. First, its based on an application
model described using Unified Modeling Language (visit
www.uml.org for more information). This technique
allows the application designer to specify a list of classes,
inheritance, properties, relationships between classes, and
constraints.
Borlands implementation of MDA, Bold for Delphi, is
derived from the UML model. Your applications business logic is defined using Bold for Delphi. In addition,
your database (known in MDA as the persistence storage)
is created or even evolved (more on this later). The
Delphi 7 Architect trial includes Bold for Delphi. Until
recently, Bold for Delphi was a product of BoldSoft, a
Swedish company. Borland purchased this company at the
end of 2002.
Getting Started
First, you need to get the software required to start modeling
your applications. Heres what youll need:
Delphi 7 Architect trial, available from
www.borland.com/products/downloads/download_delphi.
ModelMaker trial, available from
www.modelmakertools.com/download.htm.
Microsoft Access. Although numerous databases are supported, this article uses a local Access database.
The order of installation is important, because each product
tries to detect what software is already installed on your system so that it can add plug-ins, etc. Use the following order:
1) Delphi 7.
2) ModelMaker; this will install plug-ins into Delphi.
3) Bold for Delphi; this will install plug-ins into Delphi and
ModelMaker.

Lifecycle

Management

Model-driven Delphi

Defining the Business Model


The first step toward creating a model-driven application
is to design a business model. The idea is that the application source code is split into three separate logical areas:
database, business logic, and presentation. To start, youll be
defining your business logic by creating a model in ModelMaker. The application Ive chosen to develop for this article
is a club membership system.
Start ModelMaker. Theres a tab set at the top left of the
form; select the Diagrams tab. Right-click the empty diagram
list and select Add Class diagram from the popup menu. Rightclick the new diagram and rename it People. On the right
side of ModelMaker youll see a blank diagram. Select Add
Class to Model from the selection of icons at the top and click
the diagram to add the new class. In the class properties
dialog box that appears change Class name to Person. Finally,
change the Class style to Abstract. You now have an empty
and quite useless Person class.
Next youll need to add a few very basic attributes to your
Person class. On the left side of ModelMaker, beneath the
diagram list, youll see an empty list which will display
all properties and methods of the currently selected class.
From the small selection of icons select Add property. In the
property dialog form that appears change the property
name to FirstName and select String as the property type.
Leave the Read Access and Write Access both set to Field, then
click OK. Repeat this step adding the following attributes:
LastName: string
Title: string
Address1: string
Address2: string
Address3: string
City: string
PostCode: string
DateOfBirth: Date
Note: DateOfBirth should be declared as Date (not
TDate), so you must specify it as a custom type, then
type it in manually.
To tidy the display a little I usually do the following:
1) Click the Filter fields button above the property list so that
only the objects attributes are displayed.
2) Select Options | Project Options. Then select the Symbol style
tab. Beneath Class symbol member filter, check Properties and
Methods (see Figure 1). This will display methods and
attributes in all of our class diagrams.
ModelMaker wasnt designed specifically for designing UML models for Bold for Delphi, so not all settings
are available directly within the ModelMaker GUI. This
is where you must use the Bold Tagged Values Editor, a
plug-in which Bold for Delphi installs into ModelMaker.
Select Bold tagged values editor from the Tools menu. In the
editor form that appears select each attribute in turn and
change the following values:
Title:
Length = 8
AllowNULL = True
6

DELPHI INFORMANT MAGAZINE | July 2003

FirstName, LastName, City, PostCode:


Length = 16
AllowNULL = True
Address1, Address2, Address3:
Length = 32
AllowNULL = True
DateOfBirth
AllowNULL

= True

I specified AllowNULL = True in each case. This is my


preference, to add a constraint to the object so that I
can specify a user-friendly error message. In addition,
changing AllowNULL on attributes isnt reflected in
the database when the database structure is updated.
(Ill cover database evolution and the object constraint
language in another article.)
A UML Crash Course
So far youve created a single class and marked it as
abstract. Marking a class as abstract indicates to Bold
for Delphi that you cannot create new instances of this
class. You may ask yourself what the purpose is of
creating an object class which cannot be instantiated.
All will become clear as our business model develops.
First, however, a crash course in the Unified Modeling
Language is in order.
Figure 2 illustrates
our Person class.
In addition, there
are two more
classes, Member
and Employee,
which both point
to the Person
class. An empty
arrow indicates
inheritance;
these two new
classes descend
from Person and
therefore inherit
all attributes,
methods, and
constraints of a
Person. Although
the Person
Figure 2: Object inheritance.
object cannot be
instantiated, neither
of the two new classes are marked as Abstract, so both of
these classes can be instantiated.
Add two new classes to your diagram, and name them
Member and Employee as indicated. Next, select the Add
Generalization Relation icon (empty arrow) from the
selection of icons above the diagram. Simply use this
tool to draw a line from Member to Person to indicate the
inheritance; repeat this task for Employee.
Add the following attributes to the classes:

Lifecycle

Management

Member:
DateJoined: Date
MembershipNumber:

Model-driven Delphi

Integer

Employee:
DateJoined: Date
StaffNumber: Integer
DateLeft: Date
Again, use the Bold Tagged Values Editor to set AllowNULL
= True on each of these new attributes. Finally, save this
model as ClubMan.
Importing the Business Model into
Delphi
If this were a real-life application, your business model
would be designed to completion and probably by
someone else. The final UML diagrams may even have
been approved by the customer. For the purpose of this
article series, the model will be imported at various
stages of development to demonstrate the various stages
of developing a Bold for Delphi application.
First, start Delphi 7. Create a new application and name
the main form fmMain. Next, create a new data module
and name it dmClubMan. Rearrange the creation order
in the Project | Options menu so that the data module is
created before the main form. Save the application as
Inheritance, the form as MainForm, and the data module
as ClubManModule:
From the Bold Handles component tab, drop a
TBoldModel onto the data module. This component
will hold your UML business model imported from
ModelMaker.
From the Bold Handles component tab, drop a
TBoldSystemTypeInfoHandle onto the data module.
This component holds information about the model
in an efficient form by use of hash tables, etc.
From the Bold Misc component tab, drop a
TBoldUMLMMLink component onto the data module.
This will import a specific ModelMaker project into
your TBoldModel.
From the Bold Handles component tab drop a
TBoldSystemHandle component onto the data module.
This component holds all instances of your business
objects at run time.
The following properties must now be set:
1) BoldSystemTypeInfoHandle1.UseGeneratedCode = False
2) BoldSystemTypeInfoHandle1.BoldModel = BoldModel1
3) BoldSystemHandle1.AutoActivate = True
4) BoldSystemHandle1.SystemTypeInfoHandle =
BoldSystemTypeInfoHandle1
5) BoldUMLMMLink1.BoldModel = BoldModel1
6) BoldUMLMMLink1.FileName = filename to the
ModelMaker model
Figure 3 illustrates the relationships between the default Bold
for Delphi system components. First, a TBoldModel is needed
to store the business model. Next, a TBoldUMLMMLink is
needed to import a model into the BoldModel component.
Although its possible to alter the business model using
7

DELPHI INFORMANT MAGAZINE | July 2003

Figure 3: Bold model components.

the Bold Model Editor (by double-clicking the BoldModel


component), its much more intuitive to design using
ModelMaker or Rational Rose. BoldSystemTypeInfoHandle
holds information about the business model in a more
efficient form. Finally, BoldSystemHandle is used to hold
instances of your business objects.
Next, well import
the business
model into
Delphi. Simply
double-click
the TBoldModel
component to
bring up the Bold
UML Model Editor
(see Figure 4).
From the File menu
select Import via
Link and the model
will be imported.
Figure 4: The Bold UML Model Editor.
Make sure you
always perform
a consistency check (Tools | Consistency Check) each time you
import your business model, just to make sure that you
have no obvious errors in your model.
Configuring an Object Persistence Layer
The next step for configuring a persistence layer requires
quite a few additional Bold for Delphi components. Bold for
Delphi uses an abstract class hierarchy to achieve this goal,
so that the persistence layer (in our case a database) can be
changed in a matter of seconds, switching from InterBase
to Oracle for example, or even to SOAP. In this article, the
application will be persisting its business objects to an
Access database, simply because its widely available:
1) From the ADO component tab, drop a TADOConnection
onto the data module. This will be used by Bold for
Delphi for all SQL commands. Set the ConnectionString
property to point to an empty Access database file,
and set LoginPrompt to False.
2) From the Bold Persistence component tab, drop a
TBoldDatabaseAdapterADO component onto the data
module. Set the Connection property to ADOConnection1
and set SQLDatabaseConfig.EmptyStringMarker to _ (an
underscore). This is necessary because of a bug in the
Access ADO drivers.
3) From the Bold Persistence component tab, drop
TBoldPersistenceHandleDB onto the data module.
Set the BoldModel property to BoldModel1
and set the DatabaseAdapter property to
BoldDatabaseAdapterADO1.

Lifecycle

Management

Model-driven Delphi

4) Finally, set the PersistenceHandle property of


BoldSystemHandle1 to BoldPersistenceHandleDB1.
Figure 5 illustrates the relationships between the
TBoldSystemHandle component and a specific set of
Bold for Delphi persistence components. First, the
TBoldSystemHandle needs a persistence component;
again, in this article the application is using a database
for persistence. Next, TBoldDatabaseAdapterADO is used
to connect the persistence handle to TADOConnection.
Finally, TADOConnection is used to connect to an ADO
compatible database.
Generating the database structure for our business model
is easy. First, double-click BoldModel1 to bring up the Bold
Model Editor. Next, select Generate Database from the Tools
menu. Bold for Delphi will ask you to confirm that you
wish to use BoldPersistenceHandleDB1. Bold for Delphi
has now created your database structure.
Getting Started with the GUI
This section introduces some basic GUI controls, and
demonstrates how inheritance is handled within the database:
1) Make sure that fmMain is using the dmClubMan data module.
2) From the Bold Handles component tab, drop three
TBoldListHandles onto the form. Name them blhPerson,
blhMember, and blhEmployee. Set the RootHandle of each
to dmClubMan.BoldSystemHandle1.
3) Set the Expression of blhPerson to Person.allInstances.
4) Set the Expression of blhMember to Member.allInstances.
5) Set the Expression of blhEmployee to
Employee.allInstances.
6) From the Bold Controls component tab, drop three
TBoldGrids onto the form. Name them grPerson,
grMember, and grEmployee. Set the BoldHandle of each
to its respective TBoldListHandle.
7) Right-click each TBoldGrid in turn, and select Create Default
Columns.
8) From the Bold Controls component tab, drop three
TBoldNavigators onto the form. Name them navPerson,
navMember, and navEmployee. Set the BoldHandle of each to
its respective TBoldListHandle.
9) Run the application.
Abstract Classes and Inheritance
The first thing to notice about this application (see Figure 6)
is that only the Employee and Member navigation controls
have their insert buttons enabled; the insert button on the
Person navigator is disabled. This is because the Person class
has been marked as Abstract in your business model. In
accordance with normal OOP rules, abstract objects should
not be instantiated.
The next thing to do is to add an Employee. Notice how
adding an Employee also creates a Person. This is because
each Employee is also a Person. In addition, notice that
adding a new Member results in the Member being listed
as a Person. Although a Person cannot be created, a Person may still exist in other forms. This, I think you will
agree, is a very powerful approach. It enables us to list all
people in the database, regardless of whether theyre customers, employees, suppliers, etc.
8

DELPHI INFORMANT MAGAZINE | July 2003

Figure 5: Bold for Delphi persistence components.

Figure 6: Inheritance demonstration.

Now close the application. You may ignore the Dirty Objects
exception which is displayed; this is the correct behavior.
Conclusion
This first article in this series has demonstrated how to create
a very simple business model, import it into Delphi, generate a
database, and enter data. The article also demonstrates a very
powerful form of inheritance. And not a single line of source
code has been written.
Although impressive, the features demonstrated so far are basic
bread n butter features of Bold for Delphi. This is just the
tip of a very large iceberg. In future articles I will introduce you
to various other abilities of Bold for Delphi, such as relationships, object constraints, object subscriptions, auto forms, and
object space synchronization. See you then.
The files referenced in this article are available for download
on the Delphi Informant Magazine Complete Works CD
located in INFORM\2003\JUL\DI200307PM.

Peter Morris is married with two children. He works as a computer


programmer for an airline company based in Birmingham, UK. Peter is an
OOP enthusiast and more recently uses Bold (MDA) and UML for developing
applications. Peter can be contacted at pete@droopyeyes.com.

O N

L A N G U A G E

OBJECT-ORIENTED PROGRAMMING

ENCAPSULATION

DELPHI 1-7

By Peter Gatis

Breaking Encapsulation
Its Easy and Dangerous

long time ago (circa 1977), before objectoriented programming came of age, we
programmers were taught to keep related

things together, and keep unrelated things apart,

index. Altogether this gives encapsulation short shrift,


because the onus of creating a well-defined interface (as
opposed to a haphazard interface) remains squarely on
the individual developer. Where encapsulation has been
broken, code can quickly become unmaintainable. And
encapsulation is dead easy to break.

where the things in question were the routines

For the sake of this article, we may say that encapsulation


has been broken when the behavior of an object is no
longer predictable on the basis of its own internal struc(abstract data types) were introduced as a means
ture. This happens when a characteristic and usually private element of an object is impaired in a way that is neiof keeping those related things together, as well
ther expected nor protected by the object interface. More
as simplifying extended data types generally.
analytically, encapsulation has been broken if an ADT has
been accessed outside its intended interface. If the ADT
When object-oriented programming arrived, it seemed a
is in fact a class definition, the instantiation of that class
natural extension of the ADT concept. Indeed, the internal
will no longer produce an object with stable behavior,
structure of an object became equivalent to our old familiar
either on a straight reading of its implementation code,
ADT, and provided
or review of its interface.
an easy transition to
Every non-trivial object
Where encapsulation has been
the newer technology.
is vulnerable, no matter
broken, code can quickly become
(Notice that class
how the object interface
definitions appear under
was specified in the class
unmaintainable. And encapsulation is
the keyword type in
definition (see Figure 1
dead easy to break.
the interface section of
for proof).
Delphi Language code,
the traditional stomping ground of ADTs.) The foundational
Well demonstrate breaking encapsulation and the
precept of encapsulation nicely formalized our programming
resultant code instability in the examples to follow.
habits by the double benefit of grouping ADTs within wellWe will examine three categories of breaking encapsuladefined interfaces (keeping related things together), and
tion, including aggressive interference with an existing
data hiding (keeping unrelated things apart).
object, weakened encapsulation through object interlinking, and over-encapsulation. All examples are simplified
At the same time, once the idea of encapsulation became
cases of actual production code. The lessons given here
firmly embedded in compiler technology, discussion of
are from the experience of maintenance coders with comthe why of encapsulation why it was formalized
bined decades of experience. (Four demonstration projects
tapered off. Current literature often refers to encapaccompany this article, and are available for download;
sulation as a curiosity of object-oriented programming
see end of article for details.)
with gray-boxed paragraphs speaking of data hiding,
and lumping related data items and code together at the
Aggressive Interference
same location. Some teaching texts introducing Delphi
In just two statements, Figure 1 demonstrates a startling
at this time dont have the word encapsulation in the
break of a normal level of encapsulation through aggressive

and data items that made up a program. ADTs

DELPHI INFORMANT MAGAZINE | July 2003

On

Language

Breaking Encapsulation

type
TForm1 = class...
TMyObject = class(TObject)
private
FValue: Integer;
public
constructor Create;
destructor Destroy; override;
property Value: Integer read FValue;
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
constructor TMyObject.Create;
begin
FValue := 7;
ShowMessage('OnConstruction: ' + IntToStr(FValue));
end;
destructor TMyObject.Destroy;
begin
ShowMessage('OnDestruction: ' + IntToStr(FValue));
end;
procedure TForm1.Button1Click(Sender: TObject);
var
MyObj: TMyObject;
MyAddr: pointer;
begin
MyObj := TMyObject.Create;
MyAddr := @MyObj.Value;
Integer(MyAddr^) := 9;
MyObj.Free;
end;

Figure 1: Breaking encapsulation through aggressive interference.

interference. What has happened here? A completely private variable, insulated properly by a well-defined interface
allowing nothing but read-only access, has changed its value
between creation and destruction. Nothing within the class
definition would suggest that this sort of thing would ever
be expected or allowed. The original architect of the class
would have no idea that the behavior of the object might be
materially altered at run time, nor would the coder responsible for the implementation perceive any risk.
Breaking encapsulation here involves an invasive manipulation of the ADT, that is, an adjustment of some private
object data by an agent other than the object itself. Such
manipulations are often well-intentioned, and often occur in
unfortunate flashes of brilliance in the heat of development.
No compiler warnings appear. No object is safe.
Figure 2 provides a second example of aggressive interference. The code represents a form with one button on it.
Click the button in the IDE and youll see an event with
the message Form1 Event. At run time, the message
becomes My Event. Without hard hunting, theres no
hint in the IDE as to how this could have happened. On the
single form in the IDE, you may place a breakpoint on the
ShowMessage('Form Event') statement a statement which
clearly compiles and find that this breakpoint is never
10

DELPHI INFORMANT MAGAZINE | July 2003

type
TMyObject = class;
TForm1 = class(TForm)
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
FMyObj: TMyObject;
end;
TMyObject = class(TObject)
procedure MyEvent(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
FMyObj := TMyObject.Create;
Button1.OnClick := FMyObj.MyEvent;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FMyObj.Destroy;
end;
procedure TMyObject.MyEvent(Sender: TObject);
begin
ShowMessage('My Event');
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage('Form Event');
end;

Figure 2: Substituting event handlers.

encountered. Weve successfully altered a non-virtual method, without a re-introduction or re-declaration of any sort.
Note that the encapsulation was broken by altering a private
variable of the object in a way that was never intended, but
difficult to prevent. The actual variable at issue in this case is
the private variable FOnClick: TNotifyEvent, as defined in the
TControl class definition in Controls.pas. This goes significantly
deeper into the code than anyone would care to look, and finding the disposed variable would not help trace the transgression anyway. If this form were multiply inherited, the point of
substitution where the original TNotifyEvent was lost would
be so thoroughly disguised that its existence might never be
deduced without help from the original architect.
Weak Encapsulation
Examples of broken encapsulation arent always so nasty.
Weak encapsulation often occurs as an intermediate step in
the evolution of an object, when the demands on the object
arent entirely clear. It may be a shortcut to get things working. Weak encapsulation simply means that interdependencies exist between objects interdependencies that have
not yet been designed out.

On

Language

Breaking Encapsulation

Listing One (on page 12) shows events calling each other
instead of properly encapsulating the business logic in
business objects and methods. Because events are so easy
to create in the IDE, theres a temptation to bury business logic in the event itself, rather than taking the time
to encapsulate business logic in business class definitions.
The effect of this is to have events that call each other
to access various segments of logic. This is bad enough.
Taken to an extreme, however, we may have different
forms calling each others events.

objects for expired pointers. The failure of encapsulation


here is met by extensive testing to make sure it all works.

The code in Listing One worked well, until someone figured


out that both forms could be opened at the same time. At
that moment, Button2 became a little depth charge, waiting to be set off. Once Button2 has been pressed, Form1 is
riding on an invalid pointer that could degrade at any time.
Contrary to popular belief, destroying an object might not
instantly render it unusable. This could leave bewildered
users and maintenance coders wondering why an application works on Thursdays, but not on Fridays. Using an
object after it has been destroyed certainly counts as accessing an ADT outside its intended interface. And as advertised the results are unpredictable.

Over-encapsulation
Over-encapsulation brings new light to the whole subject of
encapsulation, by demonstrating that its possible to hide
too much. Far from accessing an object outside its intended
interface, it may not be possible to figure out how to access
an object at all, even as it sits quietly in the IDE. Two
examples follow: one using inheritance, and the other using
sequence as a means to effectively conceal the inner workings of an object so completely as to render it unusable.

The fact of the matter is that class definitions rarely fit into
a clean hierarchical structure. Defining objects that work
together intimately, without killing each other, can be a
fierce exercise. The problem is similar to that of designing a
complex relational database without breaking normal form.
Imagine writing an application to assign students to portables. In the depths of design, it seems very natural to have
each student include a reference to his or her homeroom
portable, and to have each portable include a list of all its
homeroom students, as shown in Figure 3. This is a beautiful design strategy right up to the point that something
has to be deleted. Deciding to go from 8 portables to 7 one
month before school starts will leave 12.5% of the student
population without valid pointers. The interface is not yet
well-defined; the FHomeroom variable is vulnerable. The
encapsulation is weak.
There are a number of remedies to this particular difficulty,
the most common of which is to establish rigorous testing
procedures to catch all the cases where anything is deleted.
The onus is placed on all interlinked objects to have twoway links, and any deletion method must check all its sister
TStudent = class(TObject)
private
FHomeroom: TPortable;
public
property Homeroom: TPortable
read FHomeroom write FHomeroom;
end;
TPortable = class(TObject)
private
FHomeStudents: TList;
public
property HomeStudents: TList
read FHomeStudents; // List of TStudent.
end;

Figure 3: Weak encapsulation through object interlinking.

11

DELPHI INFORMANT MAGAZINE | July 2003

Other techniques, such as creating all persistent objects


within object sets, aim at bolstering the object interface,
improving encapsulation to the point that an arbitrary deletion never raises a blip. Object sets go beyond the scope of
this article, so suffice it say that breaking encapsulation by
interlinking without safeguards is a primary cause of access
violations in production code.

Listing Two (on page 13) shows a simple example of form


inheritance. Visually, both in the IDE and at run time,
Button1 appears on both forms. The button appears on
Form1 because we put it there, and on Form2 by virtue of
inheritance. Such form inheritance can have tremendous
advantages in standardizing look and feel, but there is a
price to be paid. Inherited events are invisible to the child
form from within the IDE, even though these events are
previously declared as published properties. The only
evidence that an event already exists is its name in the
Object Inspector. Theres no code that goes with it on the
child form.
The question is, what does a coder do when the form logic
has gone bad? Forcing an event into code through the IDE
doesnt help, because the inherited keyword doesnt take us
to the underlying code. And the event disappears with the
next build anyway along with any breakpoint you may
have put on it. We can neither trace the code through the
IDE, nor through the debugger at run time. Theres no harm
in hiding implementation details by inheritance, but making
them inaccessible to the debugger is something else again.
An equally insidious way of pushing maintenance coders toward suicide is the misuse of sequence. Digital logic
divides generally into combinational logic and sequential
logic, depending on whether a time element is involved.
Although never stated explicitly, theres an underlying
assumption that object methods and properties are combinational; that is, any property or method can be used at any
time with valid results. If a property named ActiveBox exists,
we might expect it to either have a valid pointer to an existing TMyBox object, or be nil.
What we dont expect is a floating pointer that may or may
not connect to an object that has already been destroyed. If
the validity of ActiveBox depends on the prior execution of
a method named GetBox, we have an imbedded sequence
which is nowhere evident in the class definition. To be sure,
it is hidden in the class implementation where things are supposed to be hidden, but in this second case of over encapsu-

On

Language

Breaking Encapsulation

lation, that is the substance of the problem. A maintenance


coder taking the ActiveBox method at face value would have
no idea that a prerequisite method has gone missing. In
short, were hiding things that should not be hidden.
Conclusion
The ways and means to fix broken encapsulation have not
been explored here. We have instead focused on recognizing
the problem. Encapsulation exists not just in object theory,
or the features of a compiler, but by a gentle agreement in
the structure of our code. Its both a design-time and runtime issue; the same encapsulation failure that allows a
floating pointer to blow up once every two weeks in production can make the code difficult to fix.
In maintenance we have warning signs: if the code seems too
clever, if the business logic behind an event spans multiple
forms, if a breakpoint on an obvious event is never tripped,
if objects are destroyed in more than one place, if the IDE is
unable to find a declaration, if a pointer violation has been
reported by multiple users but never shows up in test cases.
All these are strong indicators of an encapsulation problem.
As explored in this article, when an object is accessed outside
of its intended interface, the behavior of the object at design
time and at run time becomes unpredictable. Problems in
production code can erupt weeks after the delivery team has
walked away. The bottom line is that without well-defined
and respected encapsulation, a maintenance coder may be
unable to follow the flow of an application well enough to fix
it. If that sounds expensive, youre absolutely right.
The projects referenced in this article are available for download on the Delphi Informant Magazine Complete Works
CD located in INFORM\2003\JUL\DI200307PG.

Peter Gatis is a Senior Developer at Irista. An example of Peters work is


available at www.hotfiles.com: look for D-Project 3 under Delphinium in
Windows. Peter may be reached at peter.gatis@irista.com.

Begin Listing One Weak


Encapsulation: Failing to Encapsulate
Business Logic
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses Unit2;
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage('Depth Charge');
end;
end.
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;
type
TForm2 = class(TForm)
Button2: TButton;
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
uses Unit1;
{$R *.DFM}
procedure TForm2.Button2Click(Sender: TObject);
begin
Form1 := TForm1.Create(Self);
try
Form1.Button1Click(Sender);
finally
Form1.Free;
end;
end;
end.

End Listing One

12

DELPHI INFORMANT MAGAZINE | July 2003

On

Language

Breaking Encapsulation

Begin Listing Two Over-encapsulation through Form Inheritance


unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
// Business logic entry point.
end;
end.
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs, Unit1, StdCtrls;
type
TForm2 = class(TForm1)
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.DFM}
end.

End Listing Two

13

DELPHI INFORMANT MAGAZINE | July 2003

G R E A T E R
MICROSOFT .NET

SECURITY

D E L P H I
DELPHI FOR .NET

By Bill Todd

Safety .NET
Part II: Security in Delphi for .NET Applications

art I of this series introduced and described


the security features of the .NET run-time
environment, and explained how to configure

the security policy using code groups and permission


sets. This second and final part looks at using those
security features in your Delphi for .NET applications.

The security policy you establish for the .NET run-time environment is always enforced, regardless of anything you do
or dont do in your code. However, you can control
when security violations will be detected, and how your
application will behave if it cannot get the permissions it
needs. You can request permissions in code using declarative
security, imperative security, or a combination of the two.
Using Declarative Security
Declarative security uses attributes to request
permissions. The easiest way to understand how the
attributes work is with a simple example. Assume youve
created a new permission set called Custom Intranet. The
Custom Intranet permission set grants all permissions
except File IO. You have assigned this permission
set to the LocalInternet_Zone code group, so that all
applications loaded from servers on your local network
will have all permissions except File IO.
Create the simple console application shown in Figure 1.
This program displays the message, Press Enter to create
file., then waits for you to press R. The only purpose
of this prompt is to let you see that the program is running.
Next, the program creates an instance of the TTestObject class
shown in Figure 2. The program calls the WriteTextFile and
Hello methods of the TTestObject instance, and ends. Notice
that there is no call to TestObj.Free, because in the .NET
environment the garbage collector will free TestObj when the
program ends.
14

DELPHI INFORMANT MAGAZINE | July 2003

The WriteTextFile method shown in Figure 2 creates a


FileStream instance that creates the file c:\temp\junk.txt.
The method then creates a StreamWriter instance, writes
Hello World! to the file, flushes the StreamWriter to
disk, and closes the instance of StreamWriter. If you compile this program, copy it to a file server on your network,
and try to execute the program from the file server, youll
get a dialog box asking if you want to debug the program.
If you click the No button, youll get an error message.
The problem with this behavior is that the error doesnt
occur until the code tries to create the FileStream
instance. In a more complex program that requires the
user to enter a lot of data before trying to create the file,
you may not want the error to be delayed until after
the data is entered. One way to solve this problem is to
request File IO permission for the assembly, as shown in
Figure 3. The attribute:
[assembly: FileIOPermissionAttribute(
SecurityAction.RequestMinimum, All='c:\temp')]

program AssemPerm1;
{$APPTYPE CONSOLE}
uses
System.IO, System.Security.Permissions,
Test in 'Test.pas';
var
TestObj: TTestObject;
S: string;
begin
Console.WriteLine('Press Enter to create file.');
S := Console.ReadLine();
TestObj := TTestObject.Create;
TestObj.WriteTextFile;
TestObj.Hello;
end.

Figure 1: The AssemPerm1 test application.

Greater

Delphi

Safety .NET

unit Test;
interface
uses
System.IO, System.Security.Permissions;
type
TTestObject = class(TObject)
public
procedure Hello;
procedure WriteTextFile;
end;
implementation
procedure TTestObject.Hello;
begin
Console.WriteLine('File Written!');
end;
procedure TTestObject.WriteTextFile;
var
OutFileStream: FileStream;
Writer: StreamWriter;
begin
OutFileStream :=
FileStream.Create('c:\temp\junk.txt', FileMode.Create);
Writer := StreamWriter.Create(OutFileStream);
Writer.WriteLine('Hello World!');
Writer.Flush;
Writer.Close;
end;
end.

Figure 2: The TTestObject class.

program AssemPerm1;

procedure TTestObject.WriteTextFile;
var
OutFileStream: FileStream;
Writer: StreamWriter;
begin
try
OutFileStream := FileStream.Create(
'c:\temp\junk.txt', FileMode.Create);
Writer := StreamWriter.Create(OutFileStream);
Writer.WriteLine('Hello World!');
Writer.Flush;
Writer.Close;
except
on E: SecurityException do
Console.WriteLine('Security exception.');
end;
end;

Figure 4: Handling SecurityException.

The SecurityAction enumeration includes two other members


you can use when the assembly is the target of the attribute.
RequestRefuse lets you specify a permission that you dont
want the assembly to have, even if the security policy allows
it, because the permission might be misused by an attacker.
For example, if you want to ensure that your assembly cannot access the HKEY_LOCAL_MACHINE registry key, add
the following attribute:
[assembly: RegistryPermissionAttribute(
SecurityAction.RequestRefuse, All='HKEY_LOCAL_MACHINE')]

RequestOptional lets you request permissions that your assembly would like to have, but that arent required to run. For
example, your application has the option to allow the user to
save current settings to a disk file, but the settings cannot be
saved unless the assembly has File IO permission. The following attribute requests File IO permission optionally:

{$APPTYPE CONSOLE}
uses
System.IO, System.Security.Permissions,
Test in 'Test.pas';
[assembly: FileIOPermissionAttribute(
SecurityAction.RequestMinimum, All='c:\temp')]
var
TestObj: TTestObject;
S: string;
begin
Console.WriteLine('Press Enter to create file.');
S := Console.ReadLine();
TestObj := TTestObject.Create;
TestObj.WriteTextFile;
TestObj.Hello;
end.

Figure 3: Requesting FileIOPermission at the assembly level.

informs the .NET run-time environment that this assembly needs all File IO permissions for the c:\temp folder,
and all the files and folders below it in the folder tree.
SecurityAction.RequestMinimum indicates that the assembly
must have this attribute to run. With this attribute in place,
youll get an immediate error when you attempt to run the
program, and it will never begin executing. In addition to
the All property, the FileIOPermissionAttribute class also has
Append, Read, and Write properties.
15

DELPHI INFORMANT MAGAZINE | July 2003

[assembly: FileIOPermissionAttribute(
SecurityAction.RequestOptional, All='c:\temp')]

If you request one or more optional permissions, your


code must handle the case where the permission is not
granted. One way to do this is to wrap the code that
requires the optional permission in a try..except block and
catch SecurityException, as shown in Figure 4. Be sure to
add the System.Security namespace to your uses clause, or
SecurityException will be undefined.
Figure 5 demonstrates another way to find out if a
permission has been granted to your assembly. This version
of the WriteTextFile method begins by creating an instance
of the FileIOPermission class, and then adds the AllAccess
member of the FileIOPermissionAccess enumeration, and the
c:\temp directory to the permission objects state. Creating
an instance of the FileIOPermission class doesnt request the
permission (youll see how to request a permission in the
discussion of imperative security later in this article). Next,
the code calls the SecurityManager class IsGranted method
and passes the FileIOPermission instance as the parameter.
SecurityManager.IsGranted returns True if the method has
been granted the specified permission, and False if it hasnt.
Instead of making the entire assembly the target of a permission
attribute, you can make a class or a method the target, as

Greater

Delphi

Safety .NET

procedure TTestObject.WriteTextFile;
var
OutFileStream: FileStream;
Writer: StreamWriter;
FioPerm: FileIOPermission;
begin
try
FioPerm := FileIOPermission.Create(
FileIOPermissionAccess.AllAccess, 'c:\temp');
if (SecurityManager.IsGranted(FioPerm)) then
Console.WriteLine('Permission Granted!')
else
Console.WriteLine('Not Granted!');
OutFileStream := FileStream.Create(
'c:\temp\junk.txt', FileMode.Create);
Writer := StreamWriter.Create(OutFileStream);
Writer.WriteLine('Hello World!');
Writer.Flush;
Writer.Close;
except
on E: SecurityException do
Console.WriteLine('Security exception.');
end;
end;

[FileIOPermissionAttribute(
SecurityAction.Demand, All='c:\temp')]
procedure TTestObject.WriteTextFile;
var
OutFileStream: FileStream;
Writer: StreamWriter;
begin
OutFileStream := FileStream.Create(
'c:\temp\junk.txt', FileMode.Create);
Writer := StreamWriter.Create(OutFileStream);
Writer.WriteLine('Hello World!');
Writer.Flush;
Writer.Close;
end;

Figure 7: Attaching an attribute to a method.

SecurityAction

Description

LinkDemand

The immediate caller must have the specified permission.

InheritanceDemand

The derived class inheriting the class or


overriding a method is required to have
been granted the specified permission.

Demand

All callers higher in the call chain must


have the specified permission.

Assert

Callers higher in the call chain arent


required to have the specified permission.
Assembly must have SecurityPermission to
call Assert.

Deny

The resource cannot be accessed even


if all callers in the call chain have
permission.

PermitOnly

Only the resource for the specified permission can be accessed even if callers
have permission for other resources.

Figure 5: Using SecurityManager.IsGranted.

type
[FileIOPermissionAttribute(
SecurityAction.Demand, All='c:\temp')]
TTestObject = class(TObject)
public
procedure Hello;
procedure WriteTextFile;
end;

Figure 6: Attaching an attribute to a class.

shown in Figure 6. When the target of the attribute is a class,


the permission is requested when an instance of the class is
created. Again, if the requested permission isnt granted, an
exception is raised. Figure 7 shows the FileIOPermissionAttribute
with the WriteTextFile method as its target. In this case, the
permission is requested each time the method is called.
The RequestMinimum, RequestRefuse, and RequestOptional
members of the SecurityAction enumeration apply only when
the target is the assembly. Figure 8 shows the enumeration
members you can use when the target is a class or a method.
The examples in Figures 6 and 7 use SecurityAction.Demand,
so all methods higher in the call chain must have File IO permission for c:\temp, or permission wont be granted (to the
class in Figure 6 or the method in Figure 7).
Note that calling Assert, described in Figure 8, opens a security hole by making it possible for a malicious assembly that
doesnt have the permission you are asserting to call your
assembly. For this reason, any assembly that calls Assert
must have SecurityPermission.

Figure 8: SecurityAction members that can be used at the class and method level.

This method creates a FileIOPermission instance that can be


used to obtain AllAccess to the path passed in the FolderPath
parameter. The next statement calls the FileIOPermission
objects Demand method. Demand is one of the methods
you can call to request or deny the specified permission
(these methods are shown in Figure 10). After demanding
the permission, the SecurityManager.IsGranted method is
called to determine if the requested permission was granted.
If the permission was not granted, the method displays a
message and exits.
If you call Assert, Deny, or PermitOnly and want to undo the
effect of your call later in your code, call the RevertAssert,
RevertDeny, RevertPermitOnly, or RevertAll static methods that
all permission objects inherit from the CodeAccessPermission
class. For example, to remove a FileIOPermission assertion, call:
FileIOPermission.RevertAssert;

Using Imperative Security


Declarative security is easy to use, but doesnt provide the
flexibility you may need. Suppose you need permission to
read and write files in a folder, but you dont know the path
to the folder until run time. Figure 9 shows a modified version of the WriteTextFile method that gets the path to the
folder where the file will be created as a parameter.
16

DELPHI INFORMANT MAGAZINE | July 2003

Remember that security is not free. The permission is


requested every time the method is called if you make a
method the target of a security attribute. Unless the permission is being asserted, granting the permission requires
walking the stack to verify the permission of all methods in
the call chain. This can take a substantial amount of time. If

Greater

Delphi

Safety .NET

procedure TTestObject.WriteTextFile(FolderPath: string);


var
OutFileStream: FileStream;
Writer: StreamWriter;
FioPerm: FileIOPermission;
begin
try
FioPerm := FileIOPermission.Create(
FileIOPermissionAccess.AllAccess, FolderPath);
FioPerm.Demand;
if (not SecurityManager.IsGranted(FioPerm)) then begin
Console.WriteLine('Permission Not Granted!');
Exit;
end;
OutFileStream := FileStream.Create(
'c:\temp\junk.txt', FileMode.Create);
Writer := StreamWriter.Create(OutFileStream);
Writer.WriteLine('Hello World!');
Writer.Flush;
Writer.Close;
except
on E: SecurityException do
Console.WriteLine('Security exception.');
end;
end;

Figure 9: Using imperative security.

Method

Description

Assert

Allows access to the resource even though callers


higher in the call chain dont have the required
permission. Assembly must have SecurityPermission
to call Assert.

Demand

Requires that all methods higher in the call chain


have the specified permission before the permission
will be granted.

Deny

Prevents callers from using this code to access


a resource even though they have the required
permission.

PermitOnly

Prevents callers higher in the call stack from


using the code that calls this method to access all
resources, except for the resource specified by the
current instance.

Figure 10: Methods used to obtain a File IO permission.

a method will be called many times, consider requesting the


permission at the class or assembly level, instead of each
time the method is called.
Using Role-based Security
Role-based security can be implemented using either
declarative or imperative security. Figure 11 shows the
WriteTextFile method with the PrincipalPermissionAttribute
demanding that the user be a member of the Administrators
group in order to call the method.
Imperative role-based security uses two classes,
WindowsIdentity and WindowsPrincipal. The
WindowsIdentity class represents the user running the code.
The WindowsPrincipal class represents the complete security
context of the user running the code. WindowsIdentity has
properties that let you determine if the user is authenticated
and the authentication type. You can also determine if the
user is the system account, the guest account, if the user is
17

DELPHI INFORMANT MAGAZINE | July 2003

[PrincipalPermissionAttribute(
SecurityAction.Demand, Role='Administrators')]
procedure TTestObject.WriteTextFile;
var
OutFileStream: FileStream;
Writer: StreamWriter;
begin
try
OutFileStream := FileStream.Create(
'c:\temp\junk.txt', FileMode.Create);
Writer := StreamWriter.Create(OutFileStream);
Writer.WriteLine('Hello World!');
Writer.Flush;
Writer.Close;
except
on E: SecurityException do
Console.WriteLine('Security exception.');
end;
end;

Figure 11: Using declarative role-based security.

anonymous, and the users name. The WindowsPrincipal


class has the IsInRole method used in Figure 12 to determine
if the user is a member of the specified Windows group.
The code in Figure 12 creates a WindowsIdentity object
representing the current user by calling the GetCurrent method
of the class. The next statement creates a WindowsPrincipal
object, passing the WindowsIdentity object as the parameter to
the constructor. The if statement uses the WindowsPrincipal
objects IsInRole method to determine if the user is in the
PowerUser group by passing the WindowsBuiltInRole.PowerUser
enumeration value as the parameter. You can also pass a string
that contains the role name as the parameter to IsInRole so you
can easily use Windows groups youve created.
Using PermissionSet
The PermissionSet class lets you work with a collection
of permission objects. Suppose your application requires
several permissions. Instead of creating each permission
object and demanding its permission separately, you
could use a permission set, as shown in Figure 13.
This method begins by creating an instance of the
PermissionSet class. Next, it creates a FileIOPermission
object and adds it to PermissionSet. It also creates a
SecurityPermission object and adds it to the permission
set. The method finishes by calling the Demand method
of PermissionSet. This calls the Demand method of every
permission object in the set.
PermissionSet also has Assert, Deny, and PermitOnly
methods, just as the individual permission classes do. If you
need to work with one of the permission objects in the set,
you can get a reference to the object you want by calling
PermissionSets GetPermission method and passing the type
of the permission object you want as a parameter. You can
also use the RemovePermission method to remove one of
the permission objects from the set. Again, you identify the
permission object by passing its type as the parameter.
Conclusion
Most of the examples in this article use a single
permission, File IO. However, there are permission and

Greater

Delphi

Safety .NET

procedure TTestObject.WriteTextFile;
var
OutFileStream: FileStream;
Writer: StreamWriter;
WinIdentity: WindowsIdentity;
WinPrincipal: WindowsPrincipal;
begin
try
WinIdentity := WindowsIdentity.GetCurrent;
WinPrincipal := WindowsPrincipal.Create(WinIdentity);
if (not WinPrincipal.IsInRole(
WindowsBuiltInRole.PowerUser)) then begin
Console.WriteLine('User is not in PowerUser.');
Exit;
end;
OutFileStream := FileStream.Create(
'c:\temp\junk.txt', FileMode.Create);
Writer := StreamWriter.Create(OutFileStream);
Writer.WriteLine('Hello World!');
Writer.Flush;
Writer.Close;
except
on E: SecurityException do
Console.WriteLine('Security exception.');
end;
end;

Figure 12: Using imperative role-based security.

procedure TTestObject.GetPermissions(FolderPath: string);


var
PermSet: PermissionSet;
begin
PermSet := PermissionSet.Create(PermissionState.None);
PermSet.AddPermission(FileIOPermission.Create(
FileIOPermissionAccess.AllAccess, FolderPath));
PermSet.AddPermission(SecurityPermission.Create(
PermissionState.Unrestricted));
PermSet.Demand;

Figure 13: Using PermissionSet.

permission attribute objects for all of the permissions


listed in Figure 8 in Part I of this series. You can use any
of these permissions with either declarative or imperative
security in your applications. See the .NET online help for
detailed information about any of the permission objects.
Although this two-part series has presented all
the security features youre likely to need in your
applications, there are many capabilities that were not
discussed. For example, the WindowsIdentity class
has an Impersonate method that lets your application
impersonate a user other than the user that is running the
code. If you need advanced security capabilities, read the
security-related topics in the .NET online documentation.
There is almost certainly a way to implement the security
controls you need.

Bill Todd is president of The Database Group, Inc., a database consulting


and development firm based near Phoenix. He is co-author of four database
programming books, author of more than 100 articles, a contributing editor
to Delphi Informant Magazine, and a member of Team B, which provides
technical support on the Borland Internet newsgroups. Bill is an internationally
known trainer and is a frequent speaker at Borland Developer Conferences in
the United States and Europe. Readers may reach him at bill@dbginc.com.

18

DELPHI INFORMANT MAGAZINE | July 2003

F O U N D A T I O N
DFM2PAS

WIN32

.NET

C L A S S

DELPHI FOR .NET COMPILER PREVIEW

DELPHI 7

By Fernando Vicaria

The Dfm2Pas Utility


Converting Delphi Form Files to .NET-ready Source

his article targets those who are currently


experimenting with the Delphi for .NET
Compiler Preview (or Morpheus as it is

known at Borland) that comes bundled with Delphi


7. The Compiler Preview, currently on Update 3,
comes with a couple of utility tools, Dfm2Pas and
Delphi for .NET IDE Integration, that are intended
to help you with writing new code and converting
existing Win32 code into .NET.

This article explores the Dfm2Pas utility, a program that converts .dfm files into .NET-compatible .pas files. John Kasters
article, Using the Delphi for .NET Preview compiler in the
Delphi 7 IDE, provides a good primer for how to install
and use Delphi for .NET IDE Integration (see Further Reading at the end of this article for the specific reference). Its
important that the reader understands that although these
tools play an important role during the Preview (Beta) stages
of development, they wont be part of the final product and
have no official support from Borland.
Getting to Know the Tool
Make sure Dfm2Pas is added to your systems environment
path. Dfm2Pas doesnt have an installation program of its own,
so you need to add it to your systems path manually. On Windows XP you can do that by opening Control Panels System
icon, selecting the Advanced tab, then clicking the Environment
Variables button. Finally, add the location of Dfm2Pas to the list
in the Path variable. In a typical installation of the Delphi for
.NET Compiler Preview, Dfm2Pas is located at: C:\Program
Files\Borland\Delphi for .NET Preview\Demos\Dfm2Pas\, but
this can vary from one system to another.
To verify all is set correctly, open the DOS prompt and type:
dfm2pas. The result should look something like Figure 1. As
you can see, there are several command-line switches you
can pass to Dfm2Pas:
19

DELPHI INFORMANT MAGAZINE | July 2003

-v or /v indicates that you want to have verbose output of


the conversion result.
-l or /l is meant for UNIX/Linux-style text files with only
a new-line (#10) character marking the end of a line. This
option will add a carriage return (#13) after each new line
it encounters in the source or DFM file provided.
-h or /h will return the syntax for Dfm2Pas. It has been
added for compatibility only.
For those of you who havent seen it before, the syntax
that follows the BNF notation in the square brackets mean
optional anything between two square brackets can be
safely omitted. Here are a couple of command-line switch
combinations youre likely to use:
dfm2pas Unit1

converts the Unit1.dfm file into code overriding the original contents of Unit1.pas. (Warning: If you use this option,
youll loose the original Unit1.pas file and wont be able to
recompile it in Win32.)
dfm2pas Unit1 Unit1_NET

converts Unit1.dfm into a new file named Unit1_NET.pas.


This is one of the alternatives to use when you want to keep
the original file. (You can also redirect the output to a different directory and keep the files original name. Well see
how to do this later.)

Figure 1: Dfm2Pas syntax.

Foundation

Class

The Dfm2Pas Utility

program Project1;
uses
{$IFDEF CLR}Borland.VCL.Forms
{$ELSE}Forms{$ENDIF},
Unit1 in {$IFDEF CLR}'NET\Unit1.pas'
{$ELSE}'Win32\Unit1.pas'{$ENDIF};
{$R *.res}
begin
Application.Initialize;
{$IFDEF CLR}
Form1:= TForm1.Create(nil);
Application.MainForm:= Form1;
{$ELSE}
Application.CreateForm(TForm1, Form1);
{$ENDIF}
Application.Run;
end.

Figure 4: The demonstration projects main form.

Figure 2: A new VCL.NET project.

Figure 3: The demonstration projects directory structure.

Figure 5: This batch file targets .NET (makeNET.bat).

If you have Linux source/DFM files you want to convert, dont


forget to add the -l switch. Old DFM files in binary format
will be automatically converted to text format.

Turning your attention back to the project source code,


youve probably noticed that we had to add a few conditional defines in the project source. These conditionals
tell the compiler where to find the source files used for
the project, and help compensate for the lack of resources
and dedicated IDE in Delphi for .NET.

Dfm2Pas in a New VCL.NET Project


Ive been using a technique with my new VCL.NET projects
that allows me to design applications using the IDE in the
same way as when designing Win32 Delphi GUI applications.
Well explore that technique here, as well as see how to compile the result into Win32 or .NET with just one mouse click.
To play along at home, install the Delphi for .NET IDE Integration package to the IDE. Again, consult Using the Delphi for
.NET Preview compiler in the Delphi 7 IDE.
Start by opening the IDE and creating a new GUI application,
via File | New | Application. Now open the project source code and
modify it to look like the example shown in Figure 2.
After youve modified the source code, save the project to a
location of your choice and create a couple of subdirectories
called /NET and /WIN32. Then save the main form unit in the
/WIN32 subdirectory. Figure 3 shows a possible arrangement for
the project directories.
First, lets make sure our do nothing Win32 project compiles
with no errors. From the Delphi IDE, select Project | Build. The
project should compile with no errors or warnings. If thats not
the case, fix it as appropriate.
20

DELPHI INFORMANT MAGAZINE | July 2003

Now well add a couple of controls to the main form


(Form1) and add a bit of code to them just to prove weve
achieved a visual design (it doesnt really matter what
you write; you can always check out the source code that
accompanies this article). After adding a few controls to
the project, your main form may resemble Figure 4.
From now on well use the IDE only to design the forms
in our project; well actually build the project using target-specific batch files. For clarity, well create one batch
file for each platform. Figure 5 shows the contents of the
batch file that targets the .NET platform (use Notepad to
edit/view the batch files).
To generate our .NET application, simply click on
makeNET.bat to run it. This should call Dfm2Pas (assuming its been correctly added to your system path), which
will then convert Unit1.pas and Unit1.dfm into a single
file, Unit1.pas, saving it in the NET subdirectory we created earlier. The result should be your .NET assembly:
Project1.exe.

Foundation

Class

The Dfm2Pas Utility

program TextEdit;
uses
{$IFDEF CLR}Borland.VCL.Forms
{$ELSE}Forms{$ENDIF},
MDIFrame in {$IFDEF CLR}'NET\MDIFrame.pas'
{$EL SE}'Win32\MDIFrame.pas'{$ENDIF},
MDIEdit in {$IFDEF CLR}NET\MDIEdit.pas'
{$ELSE}'Win32\MDIEdit.pas'{$ENDIF};
{$R *.res}
begin
Application.Initialize;
{$IFDEF CLR}
FrameForm:= TframeForm.Create(nil);
Application.MainForm:= FrameForm;
{$ELSE}
Application.CreateForm(TframeForm, FrameForm);
{$ENDIF}
Application.Run;
end.

Figure 7: Project source for TextEdit.dpr.


@ECHO OFF
REM This batch file converts a Delphi Win32 Application
REM using Dfm2Pas, then it compiles the Delphi for .NET
REM Application using Morpheus.
CLS
ECHO *** Deleting old executable (if present) ***
IF EXIST TextEdit.exe DEL TextEdit.exe
ECHO.
ECHO *** Converting MDIEdit.pas ***
IF EXIST NET\MDIEdit.pas DEL NET\MDIEdit.pas
Dfm2Pas Win32\MDIEdit NET\MDIEdit
IF NOT EXIST NET\MDIEdit.pas GOTO BadExit

Figure 6: Project1 compiled for .NET, as it appears in ILDASM.

To confirm that what you have now is a real .NET application, open ILDASM.exe (it comes free with the .NET
SDK) and select the application you just created. The
result is shown in Figure 6. ILDASM uses metadata (and
the Reflection namespace) to navigate the types imported
and referenced by Project1. To learn more about Reflection
check out the references listed in the Further Reading
section at the end of this article.
If you want to recompile your project to Win32, simply
click on makeWin32.bat. The result will be a Win32 executable (just as we did with the .NET batch file). We now
have the option to compile the project to two platforms
without having to change any code.
Converting an Existing Project
Like creating a new project, compiling an existing Delphi 7
project into a .NET application is very simple, and requires
only minor changes to the project source file. To demonstrate this well convert one of the demonstrations included
in Delphi 7; well use the TextEdit demo, which youll find
in the /Demos/Doc subdirectory. Here are the steps:
1) Open the TextEdit.dpr project using the IDE.
2) Open the project source file and modify the code in
the project source so it looks like Figure 7.
3) Now create a couple of subdirectories named /WIN32
and /NET, as we did with our first example.
21

DELPHI INFORMANT MAGAZINE | July 2003

ECHO *** Converting MDIFrame.pas ***


IF EXIST NET\MDIFrame.pas DEL NET\MDIFrame.pas
Dfm2Pas Win32\MDIFrame NET\MDIFrame
IF NOT EXIST NET\MDIFrame.pas GOTO BadExit
ECHO *** Compiling MDIDemo.dpr ***
dccil TextEdit.dpr
IF ERRORLEVEL 1 GOTO BadExit
GOTO Exit
:BadExit
ECHO.
ECHO An error occurred during the build process
PAUSE
GOTO Exit
:Exit

Figure 8: .NET batch file for the TextEdit demo project.

4) Move the two Pascal files and their associated DFM files
into the /NET subdirectory.
5) Create two batch files (one for Win32 and one for .NET).
Figure 8 shows the .NET batch file created for TextEdit.dpr.
6) Run the batch files.
As you can see, the process is nearly identical to that of
creating a new project. However, there will be times when
the conversion wont be that simple, and youll need to
modify or add conditional defines to the source code.

Foundation

Class

The Dfm2Pas Utility

There may also be cases where some of the traditional VCL


features used in a project might not yet be fully implemented
in the new VCL.NET, in which case youll have to comment
out or add conditional defines to the code before trying to
compile it for .NET. Look at the documentation that accompanies the new Delphi for .NET Preview Compiler for more
details on language differences and new features.

A property storing raw data in the DFM file may cause


Dfm2Pas to choke and die. If that happens, open the DFM
file you are trying to convert and try to locate blocks guarded
between braces. They usually contain the .Data extension and
represent a resource. Delete the block and try again. Alternatively, open the Dfm2Pas.ini file and add the offending property
to the list of ignored properties.

Known Issues
There are a few things to be aware of when using Dfm2Pas
for converting an existing project or creating a new one.
Dfm2Pas is a tool created mainly to help Borlands QA
department debug the new VCL.NET, and is not meant to be
a commercial product. As such, it might not have the same
quality of other supported products.

These are the most common problems youll encounter when


converting existing projects. Theyre somewhat less of an issue
when designing a new project because you can avoid them
from the beginning.

Following is a list of some known issues you might find in


the generated source (some of them may or may not be fixed
by the time you read this article). Dont expect a 100 percent
conversion of the code, and be aware of the possible problems.
Keep these in mind if your program starts misbehaving.
No resources, no streaming of resources. Things like icons,
images, and some other data normally saved as a resource in
a Win32 .exe are not converted. This, in effect, stops you from
adding bitmaps to TImageList and TBitBtn or item information
to TListView and TTreeView. You can still use these controls;
just remember to load/write them manually in the code.
Code generated by Dfm2Pas may be in the wrong order. You
may find situations where you are setting an item index property before all items have been added. To solve this problem,
spend a couple of minutes inspecting the generated code to
make sure everything is in its place. Dont just blindly accept it.
Some non-visual controls might store design-time information, such as Left and Top that are used by the IDE to place a
components representation on the form (TMainMenu or dialogs, for example). Dfm2Pas cannot distinguish design-time
properties from run-time properties, so when its sees that
it will try to set it in your code. Because of the with block
that Dfm2Pas generates for each component, setting Left will
inevitably cause the forms Left property to be set. Keep an
eye on your main form; if it appears with different dimensions, or in a different position than the one you expected, a
non-visual component might be the culprit.

22

DELPHI INFORMANT MAGAZINE | July 2003

Conclusion
Weve explored how to take advantage of one of the add-on
tools included with the Delphi for .NET Compiler Preview.
Weve learned how to create a new desktop application that
targets .NET using VCL.NET and Delphi 7s IDE. We also saw
how to quickly convert an existing Win32 project into .NET.
And finally, we learned how to easily compile a Delphi project
to Win32 and .NET.
To learn more, check out the excellent articles on the Internet
covering VCL.NET and the new Delphi for .NET Compiler Preview. A good place to start is at Borlands Developer Network.
Further Reading
Delphi for .NET compiler preview by John Kaster
and Danny Thorpe, http://bdn.borland.com/article/
0,1410,28972,00.html
Using the Delphi for .NET Preview compiler in the Delphi
7 IDE by John Kaster, http://bdn.borland.com/article/
0,1410,29159,00.html
Documentation files for Delphi for .NET Preview
The demonstration projects referenced in this article are available for download on the Delphi Informant Magazine Complete Works CD located in INFORM\2003\JUL\DI200307FV.

Fernando Vicaria is a QA Engineer at Borland Software Corporation in Scotts


Valley, CA. He is also a freelance technical author for Delphi and C++Builder
issues. Fernando specializes in VCL and CLX frameworks. When hes not at
work hes probably surfing at some secret spot in Northern California. He can be
reached via e-mail at fvicaria@borland.com.

D E L P H I
EXCEPTIONS

A T

TROUBLESHOOTING

W O R K
REMOTING

DELPHI 2-7

By Simon Murrell

Warning Signs
Send Exception Notifications from Your Applications

ne of the great benefits of computer


programming is the ability to automate
tasks. One of the great programming

annoyances is troubleshooting especially


remote problems. In this article youll learn
how to combine these two common aspects of
programming in one simple example.

Im going to demonstrate how to add a simple notification


mechanism that will e-mail a screen shot of an application,
as well as a detailed error message, when an error occurs.
The mechanism will mail the information, along with the
customer details, to a predefined e-mail address.

Sample Application
The sample application that accompanies this article demonstrates the notification mechanism by generating an unhandled
exception, and then a handled exception. (The sample application is available for download; see end of article for details.)
Figure 1 shows the Sample Application form. The application
contains seven settings that store the configuration details. The
configuration details store the SMTP Server Name and Port for
the e-mail message destination. The configuration details also
store the e-mail address to where the e-mail message must be
sent, along with the details of the client who is sending the
e-mail message. Finally, the configuration details provide the
option to include a screen shot attachment.
Generating an Unhandled Exception
One button on the Sample Application generates an
unhandled exception; the code in its OnClick event tries
to divide an integer value by zero. Because Im not using
a try statement, the exception is not handled and, thereprocedure TfrmMain.cmdUnhandledExceptionClick(
Sender: TObject);
var
i: Integer;
j: Integer;
k: Integer;
begin
// Assign values.
i := 1;
j := 0;
k := i div j;
// Show result.
MessageDlg('Result: ' + IntToStr(k), mtInformation,
[mbOk], 0);
end;

Figure 1: The Sample Application form.

23

DELPHI INFORMANT MAGAZINE | July 2003

Figure 2: The OnClick event of the unhandled exception.

Delphi

At

Work

Warning Signs

fore, the MessageDlg procedure will never be reached successfully. The code in Figure 2 displays the OnClick event
handler that generates an unhandled exception and then
tries to display an error message.
I overrode the OnException event of the TApplication class,
so it will use my newly defined event, named AppException.
I did this so that any unhandled exception generated in the
application will be redirected to the AppException procedure.
The AppException event then calls a locally defined procedure named ShowNotificationForm, which initializes the
Notification Form. ShowNotificationForm then assigns the
exception information received via the parameter listing to
the Error memo field found on the Notification Form.
Once assigned, the procedure takes a screen shot of the
current application display so the programmer can see
what generated the exception. Finally, the method displays the Notification Form so the user can send a report.
The following code is used to override the OnException
event of the TApplication class:
// Assign exception wrapper.
Application.OnException := Self.AppException;

The following code displays the AppException procedure


(which calls the ShowNotificationForm procedure), which is
called whenever an unhandled exception is generated:
procedure TfrmMain.AppException(Sender: TObject;
E: Exception);
begin
// Show notification form.
Self.ShowNotificationForm(E);
end;

The code in Figure 3 displays the ShowNotificationForm


procedure, which displays the Notification Form.
Generating a Handled Exception
Also on the Sample Application form is a button that, when
pressed, will generate an exception that is handled by using a
try statement.
The code in the OnClick event tries to divide an integer value
by zero. Because Im using a try statement, the exception has
been successfully handled; the error dialog box showing the
error is displayed. After the dialog box has
been closed, the ShowNotificationForm
method is called, which in turn displays
the Notification Form.

procedure TfrmMain.ShowNotificationForm(E: Exception);


var
NotificationForm: TfrmNotification;
begin
// Inititalize class.
NotificationForm := TfrmNotification.Create(nil);
// Clear lines.
NotificationForm.txtError.Lines.Clear;
// Assign values.
NotificationForm.txtError.Lines.Add(
'An unhandled exception occurred while using ' +
ApplicationName + '.');
NotificationForm.txtError.Lines.Add('');
NotificationForm.txtError.Lines.Add(
'Exception Type: ' + E.ClassName);
NotificationForm.txtError.Lines.Add(
'Application Name: ' + ExtractFileName(
Application.ExeName) + '.');
NotificationForm.txtError.Lines.Add(
'Additional Error Message: ' + E.Message);
NotificationForm.Hide;
// Hide form.
Self.Refresh;
// Refresh screen.
NotificationForm.ScreenCapture; // Capture screen.
NotificationForm.ShowModal;
// Show form.
NotificationForm.Free;
// Dispose class.
end;

Figure 3: The ShowNotificationForm procedure.

procedure TfrmMain.cmdHandledExceptionClick(
Sender: TObject);
var
i: Integer;
j: Integer;
k: Integer;
begin
try
// Assign values.
i := 1;
j := 0;
k := i div j;
// Show result.
MessageDlg('Result: ' + IntToStr(k), mtInformation,
[mbOk], 0);
except
on E:Exception do begin
// Return error message.
ShowError('An error occurred during calculation - ' +
E.Message);
// Show notification form.
Self.ShowNotificationForm(E);
end;
end;
end;

Figure 4: The OnClick event of the handled exception.

The code in Figure 4 displays the


OnClick event of the handled exception,
which generates a handled exception,
then displays an error message and
then the Notification Form.
The Notification Form is used to display the exception that occurred (see
Figure 5). This form provides the
option of whether to send an exception
report. Lets get into the code that gen24

DELPHI INFORMANT MAGAZINE | July 2003

Figure 5: The Notification Form.

Delphi

At

Work

Warning Signs

procedure TfrmNotification.ScreenCapture;
var
DC: HDC;
BitmapImage: TBitmap;
JpegImage: TJPEGImage;
begin
// If no attachment required...
if (ReadRegistry(RegistryKeyName,
'IncludeAttachment') = 'No') then
Exit;
DC := GetDC(GetDesktopWindow); // Assign device context.
BitmapImage := TBitmap.Create; // Initialize classes.
JpegImage := TJPEGImage.Create;
try // Assign values.
BitmapImage.Width := GetDeviceCaps(DC,HORZRES);
BitmapImage.Height := GetDeviceCaps(DC,VERTRES);
BitBlt(BitmapImage.Canvas.Handle, 0, 0,
BitmapImage.Width, BitmapImage.Height, DC,
0, 0, SRCCOPY);
JpegImage.Assign(BitmapImage); // Assign source.
JpegImage.CompressionQuality := 75;
// Save Jpeg image.
JpegImage.SaveToFile(ExtractFilePath(
Application.ExeName) + 'temp.jpg');
finally
// Release device context.
ReleaseDC(GetDesktopWindow,DC);
JpegImage.Free; // Dispose classes.
BitmapImage.Free;
end;
end;

Figure 6: Capture a screen shot of your current desktop.

erates the e-mail, along with the code that takes a screen
shot of the Main Application Form.
Capturing the Screen
I created a method named ScreenCapture (see Figure 6),
which is used to capture the current desktop display.
The procedure first gets the device context of the
desktop. After the device context has been assigned, the
procedure initializes the TBitmap and TJpegImage classes.
ScreenCapture then defines the dimensions of the bitmap
image and uses the BitBlt method from the Win32 API to
copy the image from the Desktops Device Context to the
TBitmap class. ScreenCapture then assigns the TBitmap class
to the TJpegImage class, and saves the image to a .jpeg file
on disk. The procedure finally disposes the Desktops Device
Context and the TBitmap and TJpegImage class instances.
Send Report
The Send Report button is used to generate a new email using the configuration details found in the Main
Application Form of the sample application and send the
e-mail to you to respond to the customer with a solution
to the problem. The code in Figure 7 displays how to
generate the e-mail message sent to you.
The procedure first initializes a new instance of the TIdMessage
class. Then it assigns the SMTP Server Name and Port that
will be used to send the e-mail message. The procedure then
assigns the recipient of the e-mail message along with details of
the sender of the e-mail message. The procedure then checks
whether an attachment must be added. Finally, the procedure
connects to the SMTP Server and sends the e-mail message.
25

DELPHI INFORMANT MAGAZINE | July 2003

procedure TfrmNotification.cmdSendReportClick(
Sender: TObject);
var
MailMessage: TIdMessage;
begin
try
// Initialize class.
MailMessage := TIdMessage.Create(nil);
// Assign SMTP client properties.
Self.SMTPClient.Host :=
ReadRegistry(RegistryKeyName, 'ServerName');
Self.SMTPClient.Port :=
StrToInt(ReadRegistry(RegistryKeyName,'ServerPort'));
// Assign message detail properties.
MailMessage.Recipients.EMailAddresses := ReadRegistry(
RegistryKeyName, 'NotificationEmailAddress');
MailMessage.From.Name :=
ReadRegistry(RegistryKeyName, 'ContactName');
MailMessage.From.Address := ReadRegistry(
RegistryKeyName, 'ContactEmailAddress');
MailMessage.Subject :=
'Unhandled Exception Notification - ' + ReadRegistry(
RegistryKeyName, 'CompanyName');
MailMessage.Priority := mpHighest;
MailMessage.Body.AddStrings(Self.txtError.Lines);
// Add attachment.
if (ReadRegistry(RegistryKeyName,
'IncludeAttachment') = 'Yes') then
// Add attachment.
TIdAttachment.Create(MailMessage.MessageParts,
ExtractFilePath(Application.ExeName) + 'temp.jpg');
// Disconnect if already connected.
if (Self.SMTPClient.Connected) then
Self.SMTPClient.Disconnect;
Self.SMTPClient.Connect; // Open connection.
// Send e-mail.
Self.SMTPClient.Send(MailMessage);
Self.SMTPClient.Disconnect; // Disconnect.
ShowInformation('Report Successfully Sent!');
Self.Close; // Close form.
except
on E:Exception do
ShowError(
'An error occurred while sending the Report - ' +
E.Message);
end;
end;

Figure 7: Generate e-mail.

Conclusion
Of course, you dont have to use e-mail to submit an error.
You can also submit the error via a Web site or Web Service sitting out on the Internet. I hope you find this feature
useful. Ive found that if a customer experiences an error
because of incorrect input, or an error that has been unhandled, this feature allows them to communicate with me
more easily by sending the error along with the screen shot,
so I can minimize the time it takes to resolve any problems.
The sample application referenced in this article is available for download on the Delphi Informant Magazine
Complete Works CD located in INFORM\2003\JUL\
DI200307SM.

Simon Murrell uses a wide variety of languages, from C#, Delphi, Java, and Visual
Basic to JavaScript. You can reach Simon at SimonM@byteforest.co.za.

N E W

&

U S E D

By Alan C. Moore, Ph.D.

CDK for Delphi


The Classiest Tool of All

ve been working with CDK since version 1


was released for Delphi 1. There has been a
new version of CDK with each new version

of Delphi, and as you would expect from an


Eagle Software product, CDKs capabilities
have increased exponentially. (Note: CDK now
stands for Class Developer Kit, not Component
Development Kit as it did initially.)

Did I say Eagle Software? Im sorry; I meant Developer


Express. In one of the more dramatic developments in the
Delphi third-party community in recent memory, Developer
Express acquired Eagle Software in May of 2003. See the
news item on page 4 for more information.
New Features Increase Productivity
You can expect some pleasant surprises if youve used
previous CDK versions and youre planning to upgrade to
work with Delphi 7. One of the most noticeable changes is
CDKs new interface, which is well designed and provides
easy access to its rich array of features. In the area of persistence, CDK has added the ability to save designs to a file
before committing changes to disk. And CDK Professional
includes some additional capabilities, such as interface
support and working with various patterns, such as Singleton, Factory, Flyweight, etc.
CDK automates just about every aspect of component creation. It also provides considerable help at each stage of the
process, with a powerful tutorial and contextual help. To get
things started, you must make a few decisions, such as creating a name for your class, determining the unit that will
hold your code, and possibly providing a description. One of
the most important decisions is the selection of an ancestor.
For those new to Delphis component library, CDK provides
the breakdown of the VCL shown in Figure 1.
26

DELPHI INFORMANT MAGAZINE | July 2003

After youve made the preliminary decisions, CDK provides a variety of ways to work with properties, events,
and methods. Figure 2 shows the second page of the Class
Details portion of the main wizard, which allows you to
hide, publish, or override inherited properties, events, and
methods. As you can see, the main wizard provides two
ways to access the various tasks: by clicking on one of
the notebook pages, or by clicking on the task list in the
lower-left corner. The task list provides additional services.
As you move through the various stages, CDK keeps track
of your work. If you introduce errors or leave something
unfinished, CDK will place a warning icon by that task to
remind you to come back and deal with it.
You can also create a variety of component types using
CDK: visual, non-visual, and compound. The latter are
referred to as Super Components because they contain
sub-components that interact with each other. Earlier versions of CDK supported compound components, but they
required a bit more work. Those hard-coded composites
featured sub-components that were created dynamically
in the source code. Now the process is more automated.

Figure 1: CDK provides help at every stage. Here it provides a breakdown of the
VCL to assist in the selection of a class ancestor.

New

&

Used

CDK for Delphi

Figure 2: Hide, publish, or override inherited properties, events, and methods.

You can create a visual composite that includes a layout


that you can later modify quite easily. Conveniently, CDK
provides access to properties, events, or methods of the
sub-components. You can expose these as published properties and events for your composite component with just a
single click on the event or property name. CDK takes care
of many other chores as well, including the generation of
get and set methods to access sub-component properties.
Composite components are great, but non-visual components can also be helpful. Many Delphi developers use
business rules to define particular relationships between
elements of a database (for information on creating business
rules components, see Sharing Business Rules, Bill Todds
excellent article in the April, 2003 Delphi Informant). CDK
provides the opportunity to store these rules in a class, thus
separating them from an applications user interface. Then
the rules can easily be used in multiple applications.
To facilitate the process, CDK includes TRzBusinessComponent
from Raize Software, a low-level, abstract data-aware business
class from which business components may be derived. As
with many other database objects, these data-aware business
components use field objects to provide access to the actual
data, and can be accessed at design time and run time. Using
BeforePost and OnStartPost events with a Validate method,
CDK provides a rich foundation from which to build businessrules components that include validation. Additionally, there
are many ready-to-use, built-in business components that ship
with CDK.
Support for Patterns, Code
Templates, and More
Classes perform various kinds of services on behalf of
applications. One system to organize or conceptualize
the various types of services is patterns. Design patterns,
including Factory, Flyweight, Lock, Observer, Outline Node,
and of course, the Singleton, are included in the Professional version. The various patterns are easily available in
the process of building a class (see Figure 3).
What about reusing segments of code in new components?
Using code templates, this kind of reuse has been available
in CDK since the earliest versions. In fact, I wrote such a
template to accompany an earlier article about the product.
That template, included in subsequent versions, adds wave
27

DELPHI INFORMANT MAGAZINE | July 2003

Figure 3: CDK for Delphi allows you to use various design patterns in your
classes.

Figure 4: Browse all the components in the VCL.

file playing capabilities to a controls OnClick event. How


are these templates constructed? Templates are simply
text files with special lines used to delimit sections of a
unit, such as UnitHeader, InterfaceHeader, ClassHeader,
ClassDeclaration, and so on. Each new version of CDK
expands this rich library of templates. CDK for Delphi
now includes support for interfaces (available only in the
Professional version), and additional support for working
with properties within templates.
Tools, Help, & a Tutorial Set to Die For
In addition to its main class creation wizard, CDK includes
many other useful tools. For example, you can browse
all the components in the VCL, examining details such
as properties, events, methods, and more (see Figure 4).
Theres also a convenient Form Loader tool that allows you
to select a Delphi form and use it in a dialog-based property editor or component editor.
The CDK Package Wizard allows you to create various types
of packages, including simple component packages, complex
component packages, and data-aware/non data-aware packages. Regardless of the type of package, the wizard provides
some useful choices, such as limiting package names to eight
characters, appending a version number to run-time package
names, and so on.

New

&

Used

CDK for Delphi

Just the Facts


Class Developer Kit (CDK for Delphi) is a complete tool for
creating or modifying classes and components of all types. It
includes tools for browsing components and creating packages, as well as an excellent set of tutorials. Simply put, CDK
is an outstanding tool. It makes class and component creation easy and fun.
Developer Express
6340 McLeod Drive, Suite 1
Las Vegas, NV 89120

Figure 5: CDKs powerful tutorials can get you up to speed quickly.

Weve already discussed the main class-creation wizard. But


there is also a Modify Class Wizard that allows you to open an
existing class and modify it. This is especially helpful in adding
new properties, types, methods, and so on. However, it does
not provide a means to remove or rename such elements, a
feature that I believe would be helpful.
There is built-in help in all the various tools, so its difficult
to get off track. But even more significant is the splendid
set of tutorials and tutorial viewer that come with CDK (see
Figure 5). After a short introduction to the tutorial viewer
itself, there are a series of tutorials on various topics. The
first, Introduction to Building Components, is a nine-page
tutorial for the novice. It begins by explaining the reasons
for building components, then goes on to describe some of
the basic issues, such as the base class, the main elements
(properties, events, and methods), scope or privacy levels,
and so on. It even touches on more advanced issues such
as the difference between VCL components and ActiveX
components. There is a tutorial that introduces CDKs architecture and its many capabilities, tutorials on all the major
class types (hard-coded composites, visual composites,
business objects, etc.), a 23-page tutorial on component
editors, and more. There are many excellent articles and
book chapters on component creation, but you wont need
them if you use the CDK tutorial set.

28

DELPHI INFORMANT MAGAZINE | July 2003

Phone: (702) 262-0609


Fax: (702) 262-0619
E-Mail: info@devexpress.com
Web Site: www.devexpress.com
Pricing: CDK for Delphi, US$250. See Web site for upgrade
pricing and information on CDK and reAct bundles.
Conclusion
CDK is a complete solution for writing or modifying classes
and components. Experienced component writers will find
that this outstanding tool automates many of the tasks they
have previously been forced to deal with manually. For
those aspiring to become component writers, CDK provides
the necessary tools and techniques.
Simply put, CDK is an outstanding tool. It makes class and
component creation easy and fun!

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 on the Internet at acmdoc@aol.com.

N E W

&

U S E D

By Bill Todd

InfoPower 4000
Venerable Must-have Component Suite Gets Overhaul

oll2Woll Software has added an impressive set of new features to the InfoPower
grid and other components in their vener-

able component suite. InfoPower 4000 is a major


upgrade, with some of the most striking changes
appearing in the TwwDBGrid component. Like the
standard Delphi DBGrid, the InfoPower grid lets you
display data in rows and columns. But thats where
the similarities end.

Noticeably New
Take a look at Figure 1 and youll immediately see some differences. Note that alternate rows in the grid appear in different colors. Showing the active row in a different color makes
it stand out so users can see at a glance on which row they
are working. It also makes reading across without jumping
lines much easier for the user. Implementing this feature is a
snap; simply set the grids AlternatingRowColor property.
Figure 1 shows another handy feature. Notice that the Company column is a hyperlink. You can display any number
of fields as links. When a user clicks a link, InfoPower
attempts to open the link in your browser. However, the
OnURLOpen event fires first, passing the URL string and
field object to your event handler, so you can take any
action you wish. For example, you could open another form
when the user clicks the link.

Figure 1: The InfoPower 4000 grid.

29

DELPHI INFORMANT MAGAZINE | July 2003

You may have noticed the plus sign (+) in the first column
of the grid. The InfoPower grid lets you show master-detail
relationships to any depth. Figure 2 shows the grid with
one of the customer records expanded to show the orders
for the customer. Notice that the order records are shown
in an embedded panel that contains a TwwDBNavigator
component, as well as the orders grid. Using this technique
you can provide any controls you need as part of the detail
tables display. Figure 3 shows one of the order records
expanded to show the items for that order. I really like the
way that each record expands vertically to contain the detail
grid or panel, without hiding other master records.
Youve Got the Power
The InfoPower grid lets you grant the user total control of
the row and column size and column order, simply by setting a few properties. Figure 4 shows the grid with the column order changed and the row height increased. You can
also specify the name of an INI file to hold the grid settings,
so a users grid layout will be preserved between sessions.
Another handy new feature you can enable simply by setting a property is double-click column sizing. With this feature enabled you can place the mouse cursor over the sizing
line for a column in the grids title bar and double click to
have the grid automatically adjust the column width to fit
the largest value being displayed.
If you need a more sophisticated user interface, you can
embed other data access components in an InfoPower grid,
such as a check box, combo box, or rich edit component.
In InfoPower 4000 you can allow embedded controls to

Figure 2: A master-detail relationship.

New

&

Used

InfoPower 4000
comes from the record above unless you are positioned on
the first record in the grid. In that case, the data is copied
from the record below.
Another new feature is the ability to group data that has a
one-to-many relationship, such as the result set returned
by a join query. For example, if you join customer and
orders tables, you can group by customer name to show
the customer with the order information. When you do, the
customer name is shown once for the first record for that
customer. For the second and subsequent records for that
customer, the name and grid lines are suppressed so your
grid looks like a grouped report. You can also add footer
cells to the grid to hold totals.

Figure 3: A one-to-many-to-many relationship.

Figure 4: The grid after the user has changed the grid layout.

expand when they get focus. This is particularly handy for


a rich edit or any other control that can contain a lot of
text. The grid also provides complete control over the way
memo fields are handled. You can have text from the memo
field appear in the grid so users can see as much text as
will fit, or you can disable memo field display to improve
performance with desktop databases. Word wrap is on by
default, so memo text will wrap to fill the vertical space in
its cell. To see more of the memo text, simply double-click
the memo cell in the grid. A dialog box will pop up so you
can edit the text in a memo component. You can disable the
memo editor dialog box by setting a property if you dont
need this feature.
The InfoPower grid lets you export the data youre viewing in
HTML, XML, SYLK, or delimited ASCII format. You can choose
any delimiter character when exporting to delimited ASCII.
One of my favorite new features in InfoPower 4000 is the
ability to ditto values from the prior record in a grid. This
is particularly handy for users who enter a series of records
where many of the fields are the same. The grid lets users
ditto the current field or the entire record by pressing a
shortcut key that you assign. You can choose one shortcut to
ditto the current field and another to ditto the entire record,
so both features are available at the same time. You can also
control whether the data is copied from the record above,
the record below, or both. If you choose both, the data
30

DELPHI INFORMANT MAGAZINE | July 2003

You have more control in code over the appearance of the


grid in InfoPower 4000 thanks to two new events and two
new methods. The OnBeforeDrawCell event lets you control
the cells default drawing behavior by setting the value of
fields in the event handlers DrawCellInfo parameter. You can
control whether the background, text, top line, and bottom
line will be drawn. The OnAfterDrawCell event fires after the
cell has been painted and lets you add code to paint additional
text or objects in the cell. The new GetPriorRecordText and
GetNextRecordText methods let you examine the values in the
prior and next records, so you can control the appearance of
the cell being drawn based on values in those records.
The InfoPower grid also lets you edit calculated fields in a
unique and intuitive way. Suppose you have a dataset with
two calculated fields, one that combines the first and last
names, and another that combines all the elements of an
address. Using calculated fields saves space if you can eliminate the individual fields from the grid. However, you have
no way to edit the values. Figure 5 shows an InfoPower grid
with a plus icon (+) in each of the calculated fields. This
figure also shows the calculated address field for one record
expanded, so the user can easily change the individual values that are used in the calculation.
So Much More than the Grid
I could spend the rest of this review describing the features
of the grid, but its only part of the InfoPower story. Let
me just say that there is nothing I can think of that a grid
should do that the InfoPower grid does not do well, and
move on to some of the other InfoPower components.
InfoPower provides both data-aware and non-data-aware versions of its rich edit component. This component is a complete RTF word processor that you can drop into any application. It supports fonts, bold, underline, italics, and all the
other features you would expect, including left, right, and full
justification. You can even do a mail merge within your application. New in InfoPower 4000 is the ability to import from or
export to HTML files, and import Microsoft Word documents.
The rich edit component can print its contents and can now
include headers and footers in the printed output.
Another unique component is the Data Inspector. The best
way to understand it is to see it in action (see Figure 6). The
TwwDataInspector component provides a hierarchical view of
data similar to the hierarchical view of properties in Delphis

New

&

Used

InfoPower 4000

Figure 5: A calculated field expanded for editing.

Object Inspector. You can group fields into categories and


expand the category to see the individual fields. You can
have a calculated field, an address for example, and expand
the calculated field to show the individual fields used in the
calculation. You can also include data from another table
and, as you can see in Figure 6, view more than one record
at a time so the Data Inspector is really a horizontal grid.
The Data Inspector provides an intuitive way to view and
edit a record that contains many fields, without the constant
horizontal scrolling that a grid requires. InfoPower 4000 adds
the ability to disable individual items in the inspector so they
will not be seen.
Instant forms. One of the most annoying features if you
work with grids is that you must frequently scroll horizontally to see the fields with which you want to work. You
can solve that by creating a custom form that shows all the
fields for each record and giving the user a way to pop up
the form. That usually means you must take the time to
design the form unless you use InfoPower.
InfoPower provides two components, TwwRecordViewPanel and
TwwRecordViewDialog, that solve this problem instantly. When
you connect either of these components to a DataSource the
component creates a form on-the-fly at run time that shows all
the fields in the dataset. The component automatically uses the
correct data-aware component based on each fields data type.
You can control whether the form will have a horizontal or
vertical layout by setting a single property.
If you want to add this functionality to your own form use
a RecordViewPanel component. Use the RecordViewDialog
component if you want a form that already contains a
RecordViewPanel component. Either way, these components
will eliminate a lot of time you used to spend on form
design. Figure 7 shows a RecordViewPanel displaying
customer information.
Search and filter. Starting with TwwFilterDialog, InfoPower
includes a complete set of controls that make it easy to
search for data. The FilterDialog component works with all
dataset components, including ClientDataSets, to let users
filter their view of data. When filtering a query you also
have the option to let the database server perform the filter,
instead of retrieving all the data and performing the filter on
the users workstation. This option works by changing the
WHERE clause and re-executing the query to take full advantage of the power of your database server. The filter can
encompass any number of columns and supports matching
on single values or a range of values. Filters on columns can
be logically connected using AND or OR.
31

DELPHI INFORMANT MAGAZINE | July 2003

Figure 6: Using the Data Inspector for a hierarchical view.

Figure 7: A RecordViewPanel component on a form.

When searching for a single value in a column, you can


specify an exact match or what the value starts with, or
search for the value anywhere in the columns text. You
can control whether the match is case-sensitive, and you
can give the user the ability to logically invert the search
to see all records that do not match the specified criteria.
FilterDialog can filter the data using the dataset components Filter property, the datasets OnFilterRecord event, or
by constructing the WHERE clause for a query. By setting
the correct properties, you ensure you get the best possible
performance from your back-end database.
TwwLocateDialog lets users search easily for a value
in a column using exact match, starts with, or
is contained in options. Users can control the case
sensitivity of the search, and use wild cards in the
search string. Find First and Find Next buttons let users
step through all the records that match the search
condition. TwwIncrementalSearch looks like an edit box,
but provides incremental searching on a single field in
a dataset. InfoPower 4000 adds support for searching
multiple fields using a delimiter. Also new is the ability
to perform the search on the back-end database server
by requerying the data each time a key is pressed.
TwwSearchDialog also provides incremental searching, but
in a dialog box that displays the dataset being searched
in a grid. Users can choose which field to search, and the
dialog box can contain a user-defined button that lets you
add custom features.

New

&

Used

InfoPower 4000

Just the Facts


Available for Delphi 5, 6, and 7, and C++Builder 5 and 6,
InfoPower 4000 represents a major upgrade. Woll2Woll has
added an impressive set of new features to the InfoPower
grid and other components to the component suite. One of
the most noticeable differences in the grid is making alternate rows appear in different colors. One of the most powerful features of the InfoPower components is the flexibility
they give you in controlling your forms appearance. With
more than 30 components InfoPower continues to be the
must-have component suite for Delphi.
Woll2Woll Software
2217 Rhone Drive
Livermore, CA 94550
Voice: (925) 371-1663
Fax: (925) 371-1664
E-Mail: sales@woll2woll.com
Web Site: www.woll2woll.com
Price: InfoPower 4000 Standard, US$279; InfoPower 4000
Professional, US$349; upgrade from InfoPower 3000 Standard to 4000 Standard US$129; upgrade from InfoPower
3000 Professional to 4000 Professional, US$149.
Eye candy. One of the most powerful features of the InfoPower components is the flexibility they provide for controlling your forms appearance. This is illustrated in Figure 7;
the custom framing property has been set to True and the top,
left, and right sides of the components have been turned off
to produce the underlined look. The components Transparent
property has also been set to True so the background color of
the form shows through.
If you look again at Figure 6 youll notice that the Data
Inspector has a textured background. This is the result of
providing a background bitmap and making the component
transparent. InfoPower 4000 also adds a new TwwController
component to centralize the Frame properties of its edit
controls. This allows you to change the focus and non-focus
border styles of all InfoPower and 1stClass controls in an
application. With these features you can easily build a form
that looks like a paper form. InfoPower 4000 adds support
for Windows XP themes so your forms will take on the
appearance of the theme the user has configured.
Conclusion
Get InfoPower 4000 if you want to cut your development time
and give your users a visually stunning and powerful user
interface. InfoPower continues to be the must-have component suite for Delphi. The InfoPower suite consists of more
than 30 components that will make your work easier. Its easy
to see why InfoPower keeps winning awards year after year.

Bill Todd is president of The Database Group, Inc., a database consulting


and development firm based near Phoenix. He is co-author of four database
programming books, author of more than 100 articles, a contributing editor
to Delphi Informant Magazine, and a member of Team B, which provides
technical support on the Borland Internet newsgroups. Bill is an internationally
known trainer and is a frequent speaker at Borland Developer Conferences in
the United States and Europe. Readers may reach him at bill@dbginc.com.

32

DELPHI INFORMANT MAGAZINE | July 2003

N E W

&

U S E D

By Ron Loewy

RemObjects SDK
Create Multi-tier Apps Using Delphi and Kylix

emObjects SDK is a new software


development kit for the creation of multitier applications using Delphi and Kylix.

What distinguishes RemObjects from datasetbased, multi-tier development tools such as


ASTA, kbmMW, or Borlands own DataSnap is
its emphasis on creating a framework for remote
object-oriented development.

HTTP port 80, so no special configuration is needed for a


firewall. Using the other options, you can easily create a
stand-alone server application as a Windows executable
or Win32 service.
The project module created includes an RODL file, RemObjects
version of a service definition. This is the equivalent of a
WSDL file for a standard SOAP Web Services server, or a TLB
file for a Windows COM server. The project source includes
a remark that ties this RODL file to the application. The
correct service interface and invocation code are automatically
generated whenever you compile your server.

Its claim to fame is the ability to create Smart Services, i.e.


remote server applications that can expose their services in two
ways. The first is by using a standard SOAP-based protocol that
can interact with any client that knows how to handle WDSL
and SOAP envelopes. The second is an optimized binary-based
message format that doesnt suffer from the overhead of the
SOAP envelope and XML transfer size.

For example, in my test application (a scaled down,


source code management tool), the source to the servers
DPR file starts with:

The RemObjects product is a combination of a designtime service builder (think of it as the RemObjects
equivalent of Delphis Type Library Editor), and a set of
components and interfaces used to create your servers
and clients. The installation program also features a
reference manual and several samples. Complete source
code is included, and the license allows you to deploy
your clients and servers with no royalties.

uses
...

library RemDirServer;
// RemObjects: Careful, do not remove!
{#ROGEN:RemDirServer.rodl}

Remote Project Wizards


Once the product is installed, a new tab labeled RemObjects
SDK is added to Delphis New Items dialog box (see
Figure 1). This tab includes a set of icons for RemObjects
server projects. Among the available wizards are Apache and
Apache 2 shared modules, CGI Server, DLL Server, ISAPI/
NSAPI Server, and Windows Executable Server. Each of these
will create an empty skeleton of a server that you can extend
to provide your specific service functionality.
I like to deploy my RemObjects servers as ISAPI DLLs;
this way, deployment is familiar to any Web site
administrator, and the service works via the standard
33

DELPHI INFORMANT MAGAZINE | July 2003

Figure 1: The RemObjects New Items templates integrated with Delphi.

New

&

Used

RemObjects SDK
In addition to the RODL file, and the
comment that ties it to the project, the
wizards create a module (TWebModule,
TDataModule, etc., based on the project
youre creating) with an instance
of a transport server component
TROWebBrokerServer in my case), and
an instance of a message type (SOAP
or RemObjects optimized Binary
message type). A unit is created to
define the interface published by the
service (this is the equivalent of Delphis
Project_TLB.pas file for COM Servers),
a unit used to invoke the service (the
code in this unit extracts the parameters
sent by the clients and dispatches the
actual services you write), and an
implementation unit where you will write
the code for the services you publish.

Figure 2: The service builder showing the interface published by the Remote Directory Service; the
ListFiles method is selected.

Component

Use

TROWinMessageServer

If the client and server reside on the same Windows


machine, you can communicate using the fast and efficient
WM_COPYDATA Windows Message, instead of TCP/IP or
HTTP. This component implements the code that can intercept
requests sent using this approach.

TROWebBrokerServer

Used when your server application is deployed as an ISAPI DLL.

TROIndyHTTPServer

Implements an HTTP Server that listens to a specific


port and intercepts client requests sent over HTTP. It
uses the Indy components as its underlying HTTP server
implementation.

TROIndyTCPServer

Implements a listener that intercepts and services requests


sent over TCP/IP. It uses the Indy components as its underlying
TCP/IP Server implementation.

TROBPDXTCPServer

Implements a listener that intercepts and services requests sent


over TCP/IP, using components supplied by Brain Patchwork
for the underlying TCP/IP implementation.

TROBPDXHTTPServer

Implements an HTTP Server that intercepts and services


requests sent via HTTP, using components supplied by Brain
Patchwork for the underlying HTTP implementation.

TRODLLServer

Not available as part of the Component palette, but


rather is created in the library code of a DLL Server in
cases where the service is consumed by a client running
in the same process as the server, where direct in-process
calls can be performed. The main benefit of using this
approach, instead of simply exposing the interface via
standard DLL entry points, is that the application can later
be easily scaled up to use a remote server, if desired.

Figure 3: Server components installed with RemObjects.

34

DELPHI INFORMANT MAGAZINE | July 2003

The Service Builder


The service builder is an application
that is integrated by the setup program
with Delphi (see Figure 2). Think of
the service builder as the RemObjects
version of the Type Library Editor that
Delphi provides for COM applications.
The service builder is used to define
the RODL file (Service Definition). It
includes the ability to create complex
types, enumerations, arrays, and
services (interfaces). This is the
definition of the service that your
application publishes. The service
builder can also be used to import
service definitions from WSDL files,
COM Type Libraries, or Delphi units.
Components
In addition to the wizards and service
builder, installing RemObjects adds a
new Component palette entry labeled
(predictably) RemObjects. Among the
core components youll find there are
the Message and Server components.
A Message component is used to
encapsulate the message thats sent
between the client and server. Youll
find message components in every
RemObjects application you write,
server or client.
RemObjects comes with two Message
components: TROSOAPMessage
encapsulates a standard Web Services
message based on the SOAP protocol.
TROBINMessage encapsulates a binary
optimized message unique to any
RemObjects application that eliminates
the overhead imposed by SOAP and its
XML-based foundation. It removes this
overhead by specifying that ZLib-based

New

&

Used

Component

RemObjects SDK
Use

TROWinInetHTTPChannel Connects to a server via HTTP using the Windows wininet


library.
TROWinMessageChannel

Connects to a server using the WM_COPYDATA Windows


message useful when the client and server are deployed on
the same machine.

between Borlands Service application


implementation and COM, you cannot
create DataSnap Server applications
in a Service without third-party code,
such as SvCom from Alexey Dynnikov.

RemObjects SDK offers DataSnap


integration that enables you to continue
to develop DataSnap applications,
Connects to a server via TCP/IP, using Indy to provide the
TROIndyTCPChannel
but it makes deployment easier by
underlying TCP/IP connectivity.
allowing you to use any of the standard
Connects to an HTTP server using Indy to provide the underlyTROIndyHTTPChannel
RemObjects protocols. Moreover,
ing HTTP code.
as described earlier, performance
will benefit from low overhead and
Figure 4: Channel components installed with RemObjects.
compression capabilities when using
compression can be used to automatically compress the data
RemObjects binary protocol. In brief, it keeps the good stuff
stream passed between the client and server.
in DataSnap, but eliminates some of the hassles. Because
RemObjects does not require COM for server registration,
If your server applications can be accessed by both RemObjects creating a DataSnap Server in a Service is easier, as well.
clients and other clients written with other tools (.NET, Java,
or Delphi without RemObjects for example), you can create
Building a RemObjects DataSnap Server requires using
what RemObjects refers to as Smart Services where both
RemObjects replacement to an RDM (Remote Data Module),
message types are accepted by the server offering optimized
called TRODataSnapModule. On this module you must drop
performance for RemObjects clients while keeping universal
the usual RemObjects transport and message components,
standard accessibility from non-RemObjects clients.
and your datasets and data provider. Creating a RemObjects
client is as easy as creating any other RemObjects or
Server components are used to implement the code needed to
DataSnap clients. Instead of using any of the different
accept requests, dispatch them to the implementation code,
Borland-supplied connections (DCOM, Web, Sockets, etc.),
and return the results. These components are usually created
however, you use a TRODataSnapConnection that you connect
automatically for you when you use the RemObjects wizard
to the RemObjects message and transport components.
of your choice. See the table in Figure 3 for a list of the
available installed Server components.
Conclusion
My experience in the area of multi-tier development is cenChannel components are used by RemObjects client
tered on DataSnap and MIDAS, which I have been using to
applications to connect to a server using a specific
develop applications during the last three years. Learning
transport method (see Figure 4).
RemObjects and starting to develop applications with it was
a fascinating process that taught me a lot, and I feel that the
DataSnap Integration
educational value of RemObjects is by itself of great value to
Borlands DataSnap technology provides a great way to
anyone who contemplates taking on multi-tier development.
create multi-tier, data-rich applications, but can be a hassle
to deploy. A DataSnap Server must be registered with the
RemObjects is one of the more exciting products to hit the
COM system, and if you want to access it using TCP/IP,
Delphi third-party scene recently. It makes Web Services
you also must deploy Borlands socket server. Likewise, if
development easier than anything that has been available
you want to deploy over HTTP, you must deploy Borlands
with Delphi before, yet shields you from the overhead
httpsrvr.dll ISAPI module. Because of incompatibilities
inherent in an XML-based protocol by offering optimized
Binary protocols (or the ability to create your own optimized
protocols). It virtualizes everything, from the transport to the
Just the Facts
messaging, and it can even be used with existing popular
Delphi technologies like DataSnap.
RemObjects SDK is a new software development kit for
the creation of multi-tier applications using Delphi and
My experiments with performance proved that RemObjects
Kylix. The installation program adds a reference manual
applications (not dataset based) perform better (using the
and several samples to the installation directory. Comsame architecture) than DataSnap, while making deployment
plete source code is included and the license allows you
and licensing easy. This product is hard to resist when you
to deploy your clients and servers with no royalties. An
factor in the good online documentation and technical supupcoming Enterprise edition will allow you to connect .NET
port, as well as the promise of a future Enterprise edition that
clients with your Delphi or Kylix servers.
will allow you to connect .NET clients with your Delphi or
Kylix servers and provide its own optimized dataset streaming
RemObjects Software, Inc.
(dubbed DataAbstract) and virtualization code.
E-Mail: info@remobjects.com
Web Site: www.remobjects.com
Ron Loewy is a software developer specializing in business-intelligence
Price: Visit the RemObjects Web site for complete details.
TRODLLChannel

Connects to an in-process server implemented in a DLL.

applications.

35

DELPHI INFORMANT MAGAZINE | July 2003

T E X T F I L E

Mastering Delphi 7
M

arco Cant is one of the most


highly respected authors and
speakers in the Delphi community.
Not surprisingly, his Mastering Delphi
series has been a perennial favorite. The
qualities that placed its predecessors
at the pinnacle of general introductory
works place Mastering Delphi 7 in a
class by itself. This edition provides a
comprehensive introduction to Delphi
programming with an attention to detail
that will provide value even to experienced Delphi programmers. Although
there is no accompanying CD, you can
download all the code from Cants
Web site at www.marcocantu.com. This
site includes other valuable resources,
which are also freely available. Well
begin by examining the general content
and then concentrate on some of the
newer topics.
Mastering Delphi 7 is organized into
four large sections containing 25 chapters and three appendices. The first section covers essential foundational topics. The second section explores objectoriented topics, including components
and COM. The third section is devoted
to one of Delphis major strengths, database programming. And the final section discusses an increasingly important
area, Internet programming and related
topics. Lets examine each.
As in previous editions of the Mastering Delphi series, the first part begins
with a tour of Delphis IDE. It emphasizes features introduced in more recent
versions and those that are not well
known or obvious to newcomers. It
also briefly introduces other tools available, such as XML Mapper, TeamSource,
and so on. Some are discussed in more
detail in later chapters. The second
chapter, an introduction to the Delphi Programming Language (formerly
known as Object Pascal), emphasizes
its object-oriented basis. Although this
chapter provides an excellent foundation for the section on object-oriented
programming, it may not meet the
needs of those completely new to
Pascal. But dont worry Delphis
36

DELPHI INFORMANT MAGAZINE | July 2003

online Help is excellent, and Cants


online book, Essential Pascal (available at his Web site) is an excellent
reference. However, even at this early
part of the book, Cant broaches some
rather advanced issues, such as Delphis
Object Reference Model, and the subtle
but important differences between virtual and dynamic methods. The remaining chapters in the opening section
introduce other essential topics, such as
Delphis run-time library, basic classes,
and three chapters related to building a
user interface.
The remaining three sections concentrate on more advanced topics. In Part
II, Cant begins by explaining some of
the nuances of a Delphi applications
architecture, including events, threads,
and Delphis frames. There are chapters on component writing, DLLs and
packages, and COM/COM+. Most
welcome for me was the chapter on

Mastering Delphi 7
by Marco Cant, SYBEX,
www.sybex.com
ISBN: 0-7821-4201-X
Cover Price: US$59.99
(1,011 pages)

Mastering Delphi 7 continued on page 37

Web Services Development


with Delphi
B
efore opening the cover of Web
Services Development with Delphi, readers should be clear about
what theyre trying to accomplish
in terms of developing distributed
applications. The authors have no
intention of gently guiding readers
through the process of building these
programs with Delphi. Instead, they
move rapidly from one topic to the
next in an attempt to cover all the
coding possibilities that Delphi offers.
The reader is treated to an interesting
amalgamation of information on these
pages. Most of it is appropriate to this
advanced guide, but some would be
better served in other volumes.
To be fair, most who buy this book
will not sit down and read it from cover
to cover. More than likely, they will seek
specific information to solve a pressing problem via the table of contents or

index, both of which will direct them to


the appropriate pages. The developer will
then be able to skip over the three chapters devoted to database development, or
others touching on the basics of network
architecture and the OSI model. The skill
level of the developer who is building
distributed applications for use over the
Internet is likely beyond these pages of
core information, and they may resent
space that might have been better used
to provide more thorough examples. In
addition, these fundamental, specialty
topics are better served in full-length
treatments rather than the 70 or so pages
devoted to them in this book.
Learning to program is often best
accomplished through the use of multiple examples from which the programmer can derive their own applications.
Web Services Development with Delphi
continued on page 37

T E X T F I L E

Mastering Delphi 7 (cont.)


ModelMaker, the third-party UML tool
available with some Delphi versions.
Part III provides a comprehensive
exposition of database development,
covering the spectrum from basic components to ADO. As throughout the
book, there are some hidden gems here,
such as Cants explanation of mimicking data-aware controls using standard
controls. As expected, the newer database libraries such as dbExpress and
DataSnap are covered. Again, readers
will benefit from Cants considerable
experience and expertise, with page
after page of excellent advice on working with database development, including writing data-aware components.
The final section on Internet development contains much of the freshest
material in the book. Essential component groups such as Indy and WebSnap
are included, along with essential tech-

nologies like SOAP and XML. Throughout, Cant presents complex issues in
a very understandable manner. The
highlight of this section was the final
two chapters covering Delphis .NET
preview. These 45 pages alone will be
sufficient for many to consider buying
this important work.
My opinion of Marco Cant grows
with each new edition of this excellent
book. A must for anyone new to Delphi, and a most valuable resource for
those developers working with database and/or Web applications, Mastering Delphi 7 is appropriate for all levels
of Delphi programmers, but especially
for those just getting started. Visit
Cants Web site, try out the code, read
his online books, and then buy this
book. You wont be disappointed.
Alan C. Moore, Ph.D.

Web Services Development


with Delphi (cont.)
Darakhvelidze and Markov write what
amounts to a reference manual for the
Delphi implementation of technologies
such as XML and SOAP, but without
providing meaty examples that would
make the text more understandable.
Sample programs are included, but
they do little more than communicate
with one another in the simplest fashion. This is helpful, but the developer
will have to supplement this knowledge with much experimentation to
fully grasp the usefulness of the technologies theyre trying to learn.
On balance, this book contains a lot
of useful information that the talented
programmer will have no problem converting into job skills. The jacket and
introduction clearly state that this book
targets professional developers looking
for a reference book. Those new to data
communications and distributed application development would do well to look
elsewhere for lengthy examples and a
step-by-step treatment of the topic.
Warren Rachele
37

DELPHI INFORMANT MAGAZINE | July 2003

Web Services Development


with Delphi
by Peter Darakhvelidze and
Eugene Markov, A-LIST, LLC,
www.alistpublishing.com
ISBN: 1-931769-08-7
Cover Price: US$49.95
(694 pages, CD-ROM)

F I L E

N E W

The Kylix Bookshelf

By Alan C. Moore, Ph.D.

havent written about


Linux or Kylix since Kylix
was in its infancy. At that
time there were no Kylix
books. Now there are a half
a dozen or so Kylix titles,
so I thought it was time to
examine a few. The first
five titles target general
development; the last is a bit
more specialized.
Borland Kylix Developers
Guide (SAMS, 2002) by
Charlie Calvert, Marjorie
Calvert, John Kastner, and
Bob Swart is particularly
appropriate for any developer
who has some programming
experience and background
in object-oriented
development, but not in
Delphi or Object Pascal.
The first half of the book
is devoted to an excellent
introduction to Object Pascal
(AKA the Delphi Language),
the IDE, and the crossplatform component library, CLX. The
second half broaches more advanced
topics, such as creating custom
components, database programming,
and Web server development. The
chapters on writing components are
particularly strong. There is also an
excellent chapter on working with
graphics, in which Charlie Calvert
shows how to develop a Linux game
using low-level graphics functions. If
you are using Kylix to develop games,
this book is a must.
38

DELPHI INFORMANT MAGAZINE | July 2003

for anyone moving to Unix


from Microsoft Windows.
This book also covers file
handling, processes, and
threads (some of the same
territory as the Stephens
book addressed later). One
final factor puts this book in
a special class; Ray Lischner
did the technical review.

Jon Shemitzs Kylix: The Professional


Developers Guide and Reference
(Apress, 2001) is similar in that it
has an extensive introduction to the
underlying language, the IDE, and
the component library. However, one
distinguishing feature throughout the
book is the penguin-icon warnings,
Kylix is not Delphi. There is also
a short appendix, Kylix for Delphi
programmers and a similar one for
Visual Basic developers. Another
chapter provides valuable information

Kylix 2 Development
(Wordware, 2002) by Eric
Whipple and Rick Ross is
another fine introduction to
Borlands RAD Linux tool.
Similar to the two works
discussed above, it covers
Object Pascal, the IDE, the
component library, and
specific Linux issues, albeit
in a more concise way.
Its introduction to Object
Pascal is especially good.
More advanced but essential
topics, such as database
development and Internet
development, are also
included. I recommend this book to
anyone who has not used Delphi.
Marco Cant, a favorite author of
mine, has teamed up with Uberto
Barbini to write Mastering Kylix 2
(SYBEX, 2002). If youre a fan of
Marcos excellent Delphi books,
youll be pleased to find the same
writing style here, with clear stepby-step instructions to carry out
essential tasks. Theres a concise
introduction to certain elements of

File

New

Object Pascal (especially the objectoriented aspects), and an excellent


introduction to working with the
IDE, the CLX library, and building
applications. There are also several
excellent chapters on building various
types of components, including
graphical components and compound
(super) components. I especially
enjoyed the advanced chapters in the
second half.
Building Kylix Applications (Osborne/
McGraw-Hill, 2001) by Cary Jensen and
Loy Anderson was the first Kylix book I
reviewed (see the November 2001 issue
of Delphi Informant), and it remains
at the top of my list. As indicated in
my review, this title includes features
that should appeal to developers new
to Kylix and Delphi, and those moving
from Delphi to Kylix. As with some of
the other books discussed here, differences between Kylix and Delphi are
carefully articulated. The chapter titled
Debugging Kylix Applications is one
of the best on this topic Ive seen, and
the excellent treatment of database programming is another major strength.
But, as I indicated in my earlier review,
I felt this book would have benefited
from a chapter on Object Pascal.

39

DELPHI INFORMANT MAGAZINE | July 2003

The Tomes of Kylix:The Linux API


(Wordware, 2001) by Glenn Stephens
definitely fits into a specialized
category. Some of the previous books
(especially the one by Shemitz) touch
on Linux issues, but this one is devoted completely to this important topic.
After a short chapter on Linux API
errors, there is a detailed chapter on
file input/output. For the experienced
Delphi developer moving to Kylix, I
recommend that this title be placed at
the top of the must buy list.
The future of Kylix. This may be my
last Kylix column, at least for the foreseeable future. It seems that much of
the initial excitement around Kylix has
dissipated. No doubt there is a dedicated army of developers working with
Kylix, including me. But I dont have
any idea how large that army might be.

Regardless, Kylix remains the RAD tool


for creating Linux x windows applications. Its future depends on many factors, not the least of which is the willingness of traditional Linux developers
to actually pay for such a tool.
At the same time I know that many
Delphi developers are looking at
future possibilities with Microsoft
Windows, especially the .NET initiative. This is another reason for me to
take a break from writing about Kylix.
I plan to write a few columns on .NET
topics, including C#. Ill also have
new installments of The Delphi Toolbox, Open Source 2003, and possibly an interview or two. If there are
readers who would like me to explore
Kylix topics (or particular Windows
topics), please drop me a line at
acmdoc@aol.com. 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 on the Internet at acmdoc@aol.com.

Вам также может понравиться