Anda di halaman 1dari 38

February

2004

Volume 10 Number 2

INSIDE
ON THE COVER
First Look

Product Reviews: toolsfactorys Doc-O-Matic, Devraces FIBPlus

Its Here! Delphi.NET

Okay so its not really named Delphi.NET; its official designation


is Delphi 8 for the Microsoft .NET Framework. Its here nonetheless,
and Cary Jensen, Ph.D. has the complete scoop on the most eagerly
anticipated new version of Delphi in years. Now you can program for the
.NET platform at the speed of Delphi!

Delphi Informant

February 2004 vol.10, no. 2

www.DelphiZine.com

The Complete Monthly Guide to Delphi Development

FEATURES
Columns & Rows

ADO.NET Data Access Components: Part I

Bill Todd begins a new series on database development with Delphi


8 and ADO.NET, describing the properties, methods, and events of
the BdpConnection component, and demonstrating how to connect
to a database, create a transaction object, retrieve metadata from a
database, and more.

ET
ADO.N
jects
hi 8 &
e Ob
r
o
C
Delp
e
is
r
p
s
r
Ente
Table s
Hash
ie
.NET Dictionar
ail
&
Hotm r
m
o
t
s
Cu oxy Serve
Pr

Cover Art by Arthur A. Dugoni Jr.

On the Net

13

Writing an E-mail Proxy Server: Part II

Completing his series on how to write a fully functional local POP/SMTP


proxy server for sending and retrieving hotmail.com e-mails using your
favorite e-mail client, Alfred Mirzagitov implements the back-end that
allows POP and SMTP servers to translate and pass commands to Hotmail.

.NET Developer

16

Using the Framework: Part II

Xavier Pacheco continues his new series on Microsoft .NET


Framework development by introducing the classes and interfaces in
the System.Collections namespace. This month, the focus is on the
HashTable class. Xavier also demonstrates how to create strongly typed
collections and dictionaries.

Lifecycle Management

21

Enterprise Core Objects

Glenn Stephens provides us with a real appreciation for building MDA


solutions with ECO using Delphi 8 for .NET. With full synchronization
between code and model, and the creation of powerful objects built on
the ECO framework, you can build apps faster allowing you to do more
with less.

REVIEWS
29 Doc-O-Matic Professional 3.4
Product Review by Robert Leahey

33
1

FIBPlus

Product Review by Bill Todd

DELPHI INFORMANT MAGAZINE | February 2004

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

T O O L B O X
DDC Offers Alternative Solution for Standard Delphi DataSnap/MIDAS
Server Environment
Decathlon Development Corporation
(DDC) announced the availability of
DDCAppService, an alternative solution for the standard Borland Delphi
DataSnap/MIDAS server environment. Using the latest Win32 server
technologies, DDCAppService offers a
scalable, reliable, and extendable environment for building n-tier database
applications.
DDCAppService improves on the
DataSnap architecture in 10 major areas:
DDCAppService is a Win32 service that runs 24x7. This enables
efficiencies such as database connection pooling without the need
for MTS/COM+ or ADO technologies. Several projects accessing
multiple databases can be hosted
in a single AppService, sharing
system resources.
At the I/O level, DDCAppService
is an IOCP-based socket server.
IOCP (I/O Completion Port) is an
advanced Win32 server technology
essential to effectively scaling any
server application.
An application layer IOCP-based
thread pool(s) runs separately

from the I/O thread pool. Communication between the two layers is done asynchronously for
a non-blocking optimized server
environment.
At the application level,
DDCAppService uses external
XML documents to define projects and their accompanying
DataSnap providers. Provider SQL
statements can be kept in these
documents so that as the SQL
changes, or as new providers are
added, no application needs to
be recompiled. Simply update the
XML document(s) and refresh the
AppService. For complicated business logic, DDCAppService Extensions are Delphi DLLs that plug-in
and enable one to link a provider
with a DLL function. With the
Extension class suite one can easily perform transactions, build and
execute custom SQL statements,
build and return custom standalone datasets, or complete any
task that the Delphi environment
enables. Accessing these Extension functions is done by simply

calling the standard TClientDataSet Open or Execute methods from


the client.
DDCAppService works seamlessly
with Oracle, Microsoft SQL Server,
Microsoft Access, or potentially
any ADO-based data source. Oracle communication is done with
the proven Direct Oracle Access
component suite. Switching database vendors for an application
can be as simple as redefining
the connection parameters in the
project XML files.
The DDCAppService GUI provides
an interface that details the configuration and status of the system.
A real time TRACE window is provided to view current application
activity. Automatic logging occurs
for all socket and application activity. From within Extension functions one can utilize the logging
interface to record custom application messages.
With the separate DDCRAppManager
utility, one is able to remotely control
any AppService installation. This
enables one to monitor the AppService activity, update application
files, execute either dynamic SQL or
any defined application provider, or
retrieve server logs for local analysis.
All Execute-oriented providers can
be executed on the server asynchronously. This enables long-running
processes to be launched on the
server, without the need for the client application to wait.
Custom application queues can be
defined in the AppService to facilitate different providers executing
in different thread pools. There is
no need for long-running providers to block the primary application threads.
An accompanying IOCP-based ISAPI
extension enables integration with a
DataSnap TWebConnection component for AppService communication
via HTTP or HTTPS.

Decathlon Development Corporation


Price: Contact DDC
Contact: ddcappservice@decath.com
Web Site: www.decath.com/ddcappservice

DELPHI INFORMANT MAGAZINE | February 2004

T O O L B O X

Softel vdm Releases


Upgraded Tab Control
Product

Pervasive Software Completes Acquisition of Data


Junction

Softel vdm, a developer and publisher of productivity tools for Windows


programmers (specializing in .NET,
ActiveX, and DLL-based controls and
development tools), has released
SftTabs/DLL 4.5, a new version of its
tab control product. SftTabs/DLL 4.5
is specifically designed for use with
C and C++ applications and Visual
C++/MFC. The product offers 60
basic tab control styles, which can
each be further customized.
This new version introduces hidden
tabs to allow an application to hide
tabs. This is particularly convenient
when an application wants to suppress certain tabs, which preserves
screen real estate and simplifies the
user interface. Tabs can be used to
host other controls by adding child
windows or dialog boxes to the tab
control, which are managed by the
tab control. As the user switches
between tabs, the tab control automatically displays the hosted controls
(child windows).
The tab control supports many different styles and tab locations (such
as top, left, right, or bottom). Tabs
can use different colors, can display
images, can use special fonts, and can
display multi-line text with various
alignment options. Dual sided tabs,
tab ToolTips, and hovering are also
available. Among its many features

Pervasive Software, a global value


leader in data infrastructure software,
announced the completion of its acquisition of Data Junction Corp., a pioneering data and application integration
company with headquarters in Austin,
TX. Pervasive paid approximately
US$22.1 million in cash and five million
shares of Pervasive common stock.
Data Junction brings important
data integration and transformation
technologies and products, which
are highly complementary to Pervasives existing data management
products, expertise, and customer
base. The acquisition significantly
advances Pervasives strategy to be
the global value leader in data infrastructure software, enabling businesses to capitalize on their data
investments.

Serving more than 35,000 customers in 150 countries, Pervasive is now


comprised of two divisions with a sales
force organized by geography and a
shared corporate services function. The
former Data Junction president, Michael
Hoskins, joins the Pervasive board of
directors and becomes vice president
and general manager of the Integration Products Division focused on data
and application integration software.
In addition, Suaad Sait, Pervasive vice
president of marketing, steps up to lead
the Database Products Division as its
vice president and general manager.
Each is responsible for global strategy
to drive product and market development for their respective divisions.

are background bitmaps, user-definable multi-row indentation, and scrollable tabs. Scrollable tabs offer three
button styles, which can even use
custom images. SftTabs/DLL 4.5 supports development of Wizard-style
dialog boxes and similar multi-page
dialog boxes, which can be switched
in response to other controls.
SftTabs/DLL 4.5 supports ANSI
and UNICODE character sets on all
supported platforms, Windows 95
through Windows Server 2003, allow-

ing easy migration of applications


across the supported platforms.
SftTabs/DLL 4.5 includes free
product support and maintenance
updates, and is available for immediate online delivery. Upgrades at
reduced cost are available to licensed
users of SftTabs/DLL 4.0.

The Common Language


Infrastructure Annotated
Standard

The C# Programming
Language

James S. Miller and Susann Ragsdale


Addison-Wesley
ISBN: 0-321-15493-2
Cover Price: US$59.99
(891 pages)
www.awprofessional.com/
msdotnetseries

Anders Hejlsberg, Scott Wiltamuth,


and Peter Golde
Addison-Wesley
ISBN: 0-321-15491-6
Cover Price: US$29.99
(644 pages)
www.awprofessional.com/
msdotnetseries

DELPHI INFORMANT MAGAZINE | February 2004

Pervasive Software
Contact: info@pervasive.com
Web Site: www.pervasive.com

Softel vdm, Inc.


Price: US$599 (single developer license)
Contact: (941) 505-8600
Web Site: www.softelvdm.com

Errata
In my article Creating Multi-threaded Windows Services,
which appeared in the November 2003 issue of Delphi Informant Magazine, I made an embarrassing mistake and said
that you could protect multiple functions with a single critical section without having the critical section block access
to all the functions if one thread had entered one function.
This is incorrect. Using a single TCriticalSection object to
protect multiple functions has the effect of serializing access
to all of the functions. This is the way you want it. A critical
sections job is to protect data that is shared among multiple
functions. If it didnt serialize access youd be in big trouble.
Thank you to Aart Molenaar for pointing this out.
Matthew Hess

F I R S T
DELPHI 8

L O O K

By Cary Jensen, Ph.D.

Its Here! Delphi.NET


AKA Delphi 8 for the Microsoft .NET Framework

here is something poetic about the version


number of Borlands first release of Delphi
for the Microsoft .NET Framework, Delphi 8.

If you enjoy coincidences, youll be interested to


know that the original release of Delphi, Delphi
1, was also an eighth version. Specifically, it was
the eighth version of Borlands Pascal compiler;
Borland Pascal with Objects version 7.0 was the
immediate ancestor of Delphi 1.

I find this coincidence fascinating for another reason;


Delphi 1 represented a major advance in Borlands Pascal technology without making existing Borland Pascal
code obsolete. The parallels are uncanny. Delphi 8 for the
Microsoft .NET Framework, which from this point on I
will refer to simply as Delphi 8 for .NET, represents another major advance in the language we now call Delphi,
without sacrificing your investment in Borland technology.
Consider this. Any current Delphi developer can build
applications for the .NET Framework today using
Delphi 8 for .NET, in some cases merely by opening an
existing Delphi application in Delphi 8 for .NET and
pressing C9 to compile it. Even most of the tools you
use on a daily basis, including the Code editor, object
inspector, and integrated debugger, to name a few, are
immediately recognizable, if not identical, to the Win32
version of Delphi.
4

DELPHI INFORMANT MAGAZINE | February 2004

But while Delphi 8 for .NET maintains an unprecedented


amount of backward compatibility with Delphi for Win32,
it simultaneously introduces the necessary new features to
make it not only a first class .NET language, but also an
exceptional development environment for defining, designing, building, testing, and maintaining .NET applications.
This article is designed to give you a broad overview of
what youll find in Delphi 8 for .NET. Keep in mind, however, that this article was written based on a pre-release
version of the software. Similarly, the names of the various
Delphi 8 for .NET technologies described in this article are
based on early drafts of Borlands documentation. The corresponding names in the shipping product may differ.
For a detailed listing of the features of the shipping product,
as well as in which edition (Architect, Enterprise, or Profes-

Figure 1: Delphi 8 sports a new IDE.

First

Look

Its Here! Delphi.NET

sional) those features appear, see the feature matrix available at www.Borland.com/Delphi.

CR to Record Keystroke Macro (if youre using the default


key mapping).

A Familiar
New IDE
The most obvious new feature in Delphi 8 for .NET is
its IDE, shown in Figure 1. This IDE, which made its
first appearance in Borlands C#Builder, appears similar
to the IDE of Microsofts Visual Studio for .NET. It has
a nice, clean layout, and is highly configurable, giving
you a wide range of options with respect to where your
various tools float or
are pinned. (Pinning
is what many Borland
developers would refer
to as docking. In the
.NET world docking
refers to alignment.)

But there are differences. One of the more notable changes


can be found in the Tool Palette, shown in Figure 4, which
replaces the Component palette in Delphi 7. Objects can
be added to your projects either by dragging and dropping
from the Tool Palette, or by entering the object name in the
provided text box. With each letter of an objects name you
enter into this text box, the list of objects that appears in
the Tool Palette shrinks to include only those whose names
match the entered characters.

A closer inspection,
however, reveals its
unmistakable Borland
heritage. Anyone familiar with the Delphi 7
IDE will quickly find
themselves at home.
The tools, options, and
dialog boxes are generally accessed through
the same or similar
menu selections. For
example, the Run menu,
shown in Figure 2, is
almost indistinguishable from that found in
Delphi 7.

The Tool Palette is context sensitive, displaying only those


components that are appropriate for the particular type
of object on which youre working. For example, if youre
designing a Windows Form, the Tool Palette displays
those components that you can use to build GUI Windows
applications. By comparison, if youre designing a Web
Form, only Web-related objects appear.
Initially, the Tool Palette contains only a small, but wellchosen, collection of the objects that can be configured
within the IDE. For example, although the 1.1 version of
the NET Framework includes approximately 4,500 different classes, the Tool Palette initially contains less than
100 components.
Figure 2: The Run menu.

The Code editor is another place where youll find all


your favorite coding support tools. In particular, Code
Insight, code templates, the todo list, and editor key bindings are all available. For example, Figure 3 shows Code
Completion, one of the Code Insight features, operating
within the editor.
On a similar note, the various key combinations and
menu items related to the Code editor are consistent with
the previous version of Delphi. For example, press 5 to
Add Source Breakpoint, 9 to Run, 7 to Trace Into, and even

Figure 3: Code Completion in the editor.

Objects in the Tool Palette are organized by category, and


individual categories can be collapsed and expanded as
needed. In addition, you can quickly go to a particular
category by clicking the Category button and selecting from
the displayed drop-down menu.

DELPHI INFORMANT MAGAZINE | February 2004

You add or remove components from the Tool Palette by


selecting Components | Installed .NET Components, or by rightclicking in the Tool Palette and selecting Installed .NET Components. This displays the Installed .NET Components dialog box, shown in Figure 5. The corresponding object will
appear in the specified category in the Tool Palette when
the check box to the left of a class name is checked.
As you can see
from Figure 5, this
is also where you
install unmanaged
COM or ActiveX
objects that you

Figure 4: The Tool Palette.

First

Look

Its Here! Delphi.NET

Figure 5: The Installed .NET Components dialog box.


Figure 6: The Options dialog box.

want to use in your application, as well as components


from the VCL.NET (the visual component library for .NET;
more about this later in this article). Unmanaged code in
DLLs can also be used in Delphi 8 for .NET applications, but
those are accessed using a different technique.
Another aspect of the IDE that looks a little different are
the various options dialog boxes, including the Options
dialog box (for general IDE options) and the Project
Options dialog box. In this case, while the interface is a
little different (a tree view on the left side of this dialog
box displays the categories, instead of a tabbed notebook
interface), the various frames within these dialog boxes
are, again, familiar. The Options dialog box is shown in
Figure 6.

Figure 7: Code visualization for a Delphi 8 for .NET project.

There are many new features, as well. The Model View,


similar to Delphi 7s Diagram page, provides you with a
diagram of the various objects that you employ in your
application. Borland calls this code visualization. But if
youre using the Architect version of Delphi 8 for .NET,
the Diagram page becomes a sophisticated, synchronized
UML diagram editor. A sample of code visualization for a
medium-sized project is shown in Figure 7.
Another new tool is the Data Explorer, shown in Figure 8.
This dialog box provides you with a convenient browser
for inspecting available connections using Borland Data
Providers, or BDP.NET. (BDP.NET is described later in
this article.) You can even drag tables, views, or stored
procedures from the Data Explorer and drop them on any
WinForm or WebForm application to have Delphi 8 for
.NET add and configure the required BDP.NET classes to
your application.
Figure 8: The Data Explorer.

No discussion of the new IDE would be complete without


a few words about the WebForms designer. This designer,
which is very similar to both the WinForms and VCL.NET
form designer, permits you to build your Web page interfaces visually.
As you drop the various WebForm components into the
WebForms designer, Delphi generates the corresponding
HTML, inserting it into the .aspx file associated with that
form. Similarly, if the component is one that has event
6

DELPHI INFORMANT MAGAZINE | February 2004

handlers, such as a Button, Delphi adds the class reference to the WebForm class in the code-behind file, the file
that contains the Delphi statements that will be executed
on the server. An example of a WebForms in the designer
is shown in Figure 9.
Full .NET Support
Although there are many welcome similarities between the
Delphi 7 and Delphi 8 IDEs, there can be no doubt about

First

Look

Its Here! Delphi.NET

Delphi 8s .NET credentials. Delphi 8 for .NET is a .NET IDE,


and the Delphi language is a full-fledged .NET language.
Unlike Borlands C#Builder, which uses Microsofts C#
compiler under license, Delphi 8 for .NET employs Borlands new .NET compiler for the Delphi language. When
you compile a Delphi 8 for .NET project, this new compiler emits Microsoft Intermediate Language (MSIL), the
CPU-independent instructions that are converted to native
code, typically by a just-in-time (JIT) compiler. This MSIL
is equivalent to that generated by any of Microsofts compilers, including those for C# and Visual Basic for .NET.
Because Delphi 8 for .NET includes a full-fledged .NET
language, it has access to the entire .NET Framework Class
Library (FCL), a comprehensive library of classes, types,
and symbols that constitutes the .NET equivalent of Delphis
VCL. Classes in the FCL provide extensive support for data
access (ADO.NET), WebForms (ASP.NET and Web Services),
WinForms (Windows GUI development), XML development,
and much more. In short, as a .NET developer using Delphi
8 for .NET, youre making no sacrifices.
Also as a result of its true .NET nature, Delphi 8 for .NET
developers have transparent access to any public classes
declared in legitimate .NET assemblies. This means that
all third-party .NET components are easily accessible to
Delphi 8 for .NET developers, regardless of the language
in which those components were developed.
To accommodate many of the features of .NET, Borland
introduced significant enhancements to the Delphi language. These include the addition of attributes (descriptive declarations that are used to identify the characteristics of programmatic elements), unit namespaces,
operator overloading, and new visibility identifiers. For
example, class declarations now support both strict private and strict protected visibility.
What is particularly exciting about these enhancements
to the Delphi language is that Borland has indicated that
these new features will also be added to future versions
of the Delphi Win32 compiler. This will be done to ensure
that your code continues to be compatible with the various Delphi language compilers.
Beyond the .NET FCL
Although Delphi 8 for .NET provides full support for the
FCL, it goes well beyond, making the Delphi language
an especially attractive solution for .NET development.
Specifically, Borland has included in Delphi 8 for .NET
a number of technologies that extend and/or complement the FCL. Borland refers to these technologies as
Borland Data Providers (BDP.NET), RTL.NET, VCL.NET,
dbExpress.NET, IBX.NET, DataSnap.NET, and BDE.NET.
The first two of these technologies, BDP.NET and RTL.NET,
can be used in standard WinForms, WebForms, and console .NET applications that employ the FCL. BPD.NET is a
collection of concrete classes that implement the ADO.NET
interfaces used for data access. These concrete classes differ from the corresponding FCL concrete classes in that
7

DELPHI INFORMANT MAGAZINE | February 2004

Figure 9: The WebForms designer.

they provide an open, portable solution for accessing a


variety of different database servers, including Microsoft SQL Server, InterBase, Oracle, and DB2. (Note that
BDP.NET is available only in the Architect and Enterprise
editions of Delphi 8 for .NET.)
The RTL.NET is a .NET version of Delphis runtime library,
the collection of pure functions and procedures (and their
associated constants, variables, and types) that you can
use from your custom code. RTL.NET maintains a tight
source code compatibility with Win32 versions of Delphi,
smoothing the migration path of your existing Win32 code
to .NET, as well as permitting you to write routines that
easily compile under your platform of choice.
In my opinion, the presence of RTL.NET alone provides a
compelling argument to use Delphi as your preferred .NET
language. RTL.NET includes literally hundreds of useful routines, including those in the Borland.Vcl.SysUtils,
Borland.Vcl.StrUtils, Borland.Vcl.DateUtils, and
Borland.Vcl.Math units, to name a few.
Another Borland technology, Db Web Controls for
ASP.NET, is available for use when youre building WebForms. These are visual, data-aware Web controls that you
can use with ADO.NET and BDP.NET classes to quickly
and easily build database Web applications.
The remaining technologies listed earlier in this section
are designed to simplify the process of migrating existing applications from Win32 to .NET, as well as to permit developers to leverage their current skill sets when
building new .NET applications. These technologies can
be broadly referred to as VCL.NET, with dbExpress.NET,
IBX.NET, DataSnap.NET, and BDE.NET being subsets of
VCL.NET technologies.
VCL.NET is a component framework that provides extensive source code compatibility between Delphi Win32
and Delphi for .NET. The classes and types available in
VCL.NET represent a rich subset of the Win32 VCL. Furthermore, these classes and types sport interfaces that are
essentially identical to their VCL counterparts, permitting
you to easily create single source projects that can be com-

First

Look

Its Here! Delphi.NET


wont be alone nearly every other developer using
.NET is going through the same thing. After all, the FCL
is the native class library of .NET. Its a good one too!
Soup to Nuts: Borlands ALM Offerings
For more than a year now, Borland has been enhancing
their best-of-breed programming environments with a rich
collection of tools that help manage nearly all aspects of
the application lifecycle, from requirements management,
to UML modeling tools, to source code version control, to
defect tracking.

Figure 10: A Delphi 7 Project compiled as a .NET assembly.

piled either to the .NET platform or Win32, as well as to


provide a greatly simplified migration path to .NET.
At first glance, VCL.NET is truly remarkable. If one of
your existing applications makes use of common Delphi
VCL components (Edit, Label, DBGrid, MainMenu, and
the like), you may be able to simply open that project in
Delphi 8 for .NET and compile it to MSIL.
For example, if youve installed both Delphi 8 for .NET
and Delphi 7, use Delphi 8 for .NET to open the ConvertIt project, which by default is located in the Demos\
ConvertIt folder under the Delphi 7 directory. Press 9 to
compile and run this project as a .NET assembly without
changing a single line of code. Amazing, isnt it?
As for dbExpress.NET (dbExpress for .NET), IBX.NET
(InterBase Express for .NET), DataSnap.NET (for building
DataSnap clients under .NET), and BDE.NET
(Borland Database Engine for .NET), these are .NET
implementations of the associated VCL classes for data
access. As with other parts of the VCL.NET, these classes
provide a nearly seamless upgrade path to .NET for most
existing database applications. Here you will find such
classes as TSqlDataSet, TIBConnection, TClientDataSet,
TDataSetProvider, TDCOMConnection, TDataSource, and
even TTable. (Only the Architect and Enterprise editions
ship with dbExpress.NET and DataSnap.NET.)
Take a look at Figure 10. This is the FishFact.drp project,
which is located in the Demos\DB\FishFact folder located
under the Delphi 7 directory. What you see in Figure 10
is a VCL.NET application that uses BDE.NET to access
a Paradox table. Like the ConvertIt project, all I did was
open FishFact.dpr in Delphi 8 for .NET and hit 9. And
voil! I get a running .NET managed code assembly.
I suspect that VCL.NET will be particularly important to two
groups of Delphi developers: those who need to run existing applications under .NET with a minimum of changes (or
future maintenance), and those who need to create quick
and dirty .NET applications without having to learn the FCL.
For most other developers, its probably best to bite the
bullet and learn the FCL. This will take time, but you
8

DELPHI INFORMANT MAGAZINE | February 2004

Although most of these tools can be purchased separately,


the high-end editions of Delphi 8 for .NET include some
or all of these tools. Delphi 8 for .NET Enterprise includes
all the features available in the Professional edition, as
well as CaliberRM and StarTeam Standard Edition Client
and Server (in addition to BDP.NET, DataSnap.NET, and
dbExpress.NET). The Enterprise edition includes all of
the tools that ship with the Enterprise edition plus ECO
(Enterprise Core Objects), a sophisticated two-way tool
for building and maintaining applications using UML class
diagrams, as well as OptimizeIt, Borlands .NET profiler.
Is Delphi 8 for .NET Right for You?
Most Delphi developers will find Delphi 8 for .NET very
exciting. First of all, it permits you to build .NET applications today using the tools you know and the language
you love. Lets face it, if you build applications for Windows, you will eventually need to be working in .NET.
Delphi 8 for .NET makes it easy.
If youre a Delphi developer, but arent using Delphi 7,
youll be interested to know that Delphi 8 for .NET includes
a copy of Delphi 7 (for Win32). Even if you have only a
passing interest in .NET development at this time, the offer
to get Delphi 7 bundled with Delphi 8 for .NET should provide you with a pretty compelling argument for upgrading.
For developers who arent using Delphi at all, I personally
think Delphi 8 for .NET deserves a good look. As I pointed
out earlier, Delphi 8 for .NET includes RTL.NET, quite
possibly the richest set of .NET routines available. That,
coupled with one of the easiest to write and maintain languages available (Im talking about the Delphi language),
and with Borlands outstanding compiler and support tools,
make Delphi 8 for .NET a very attractive .NET solution.
And if you must build applications for both Win32 and
.NET, youll find no other language that makes this interplatform migration as easy.
Cary Jensen, Ph.D. is president of Jensen Data Systems, Inc., a training
and consulting company that won the 2002 and 2003 Delphi Informant
Magazine Readers Choice Awards for Best Training. Cary is the co-author
of 19 books, including Advantage Database Server: The Official Guide
(McGraw-Hill/Osborne, 2003), Building Kylix Applications (Osborne/
McGraw-Hill, 2001), JBuilder Essentials (Osborne/McGraw-Hill,1997),
and Delphi in Depth (Osborne/McGraw-Hill, 1996). He is the author
and trainer for the Delphi Developer Days tours, a Contributing Editor of
Delphi Informant Magazine, and a featured Web columnist on the Borland
Developer Network. For more information about Cary and his companys
services, including Delphi Developer Days 2004 workshops and seminars,
visit www.JensenDataSystems.com.

C O L U M N S
ADO.NET

&

R O W S

DELPHI 8 FOR THE MICROSOFT .NET FRAMEWORK

By Bill Todd

ADO.NET Data Access


Components
Part I: An Introduction

he .NET data access model is designed


to support two basic types of database
applications: Web and multi-tier. Web

applications and multi-tier applications have two


characteristics in common:
They both use client applications that connect to
server applications running on another machine, frequently in another location.
The connection between the client and server is stateless.
Dont be surprised if this sounds suspiciously like a
description of DataSnap (formerly MIDAS). DataSnap was
designed to support the same types of applications, and
ADO.NET bears a striking resemblance to DataSnap. Lets
start with a look at the ADO.NET components and how
they relate to the DataSnap components in Delphi.
ADO.NET components are divided into two groups: connected and disconnected. Figure 1 shows how the connected components relate to one another; Figure 2 shows
the disconnected components. Figure 3 lists the ADO.NET
components and the analogous DataSnap components.
There isnt a one-to-one correspondence between the
ADO.NET and DataSnap object models. However, if youre
familiar with DataSnap, Figure 3 should give you some
sense of the purpose of the ADO.NET objects.

DELPHI INFORMANT MAGAZINE | February 2004

By the way, if you havent worked with DataSnap, dont let


all this discussion about DataSnap worry you. This is the
first in a series of articles about ADO.NET data access components. This series will explore all the ADO.NET objects in
detail and requires no knowledge of DataSnap.
There are, however, some important differences between
ADO.NET and DataSnap. ADO.NET is more flexible than
DataSnap. For example, you have complete control over the
SQL statements that are used to apply updates to your data-

Figure 1: Connected ADO.NET components.

Columns

&

Rows

ADO.NET Data Access Components

ADO.NET
Component

TSqlConnection, TAdoConnection, TIBDatabase,


TDatabase

Transaction

TIBTransaction, TTransDesc, transaction methods of connection components

DataAdapter

TDataSetProvider

Command

SQL statements generated by TDataSetProvider;


SELECT statement in TDataSetProviders dataset

Parameter

TParam objects in the Params collection of


query and stored procedure components

DataReader

TDataSet descendants (TAdoDataSet, TSqlDataSet, TIBDataSet, TQuery)

DataSet

TClientDataSet with nested datasets

DataTable

TClientDataSet

DataRow

Row in a TClientDataSet

DataColumn

TField descendant in the FieldDefs collection of


a TClientDataset

Constraint

Constraint properties of TClientDataSet

DataRelation

Nested datasets in a TClientDataSet

DataView

Index and filter properties of TClientDataset

Figure 2: Disconnected ADO.NET components.

base. You can send the updates from one or more tables in
your DataSet object to stored procedures, and let the stored
procedures update the data tables if you want.
On the other hand, DataSnap does a lot of things for you
that ADO.NET doesnt. For example, when you have a master-detail relationship using nested datasets in DataSnap and
you call ApplyUpdates, the provider automatically applies the
changes in the correct order. It does the inserts to the master
table first and the detail table second, but it does the deletes
from the detail table first and the master second. ADO.NET
is not this smart. Its up to you to apply the updates in the
correct order, and you must write code to control the order in
which inserts, updates, and deletes are applied.
In brief, ADO.NET is more flexible but the flexibility
comes at a price. The price is that you have to write a lot
more code.
Creating a Connection
As with most things, the best way to learn the ADO.NET
objects is to use them. So Ill describe each component as
I use it in a demonstration application (the application is
available for download; see end of article for details). The
first step is to connect to a database; the database well use
is the sample EMPLOYEE.GDB InterBase database. Start Delphi 8 for the Microsoft .NET Framework, and select File | New
| Windows Forms Application from the menu.
Click the Data Explorer tab. Right-click InterBase in the list of
providers and choose Add New Connection. Enter Employee for
the Connection Name. Right-click the Employee connection and
choose Modify Connection to display the Connections Editor
dialog box (shown in Figure 4). Set the Database property to
the name of the computer where InterBase is running, followed by a colon, followed by the path to EMPLOYEE.GDB.
If InterBase is running on the same computer as Delphi, the
connection string might look like this:
localhost:c:\program files\borland\interbase\examples\
database\employee.gdb

If InterBase is running on the same computer as Delphi, you


can use localhost instead of the machine name. However,
you must use the machine name if InterBase is running on
another computer on your network.
10

DELPHI INFORMANT MAGAZINE | February 2004

DataSnap Components

Connection

Figure 3: ADO.NET and corresponding DataSnap components.

Change the Password and UserName if necessary on your


InterBase server and click the Test button at the bottom of
the dialog box. A dialog box with the message Connection
Successful should appear. If the connection doesnt succeed, check the UserName and Password, as well as the path to
the database. Also, make sure that you have the InterBase
client installed on your computer.
Getting Connected: The
BdpConnection Properties
Drag the Employee connection from the Data Explorer and drop
it on the form. This will add a new BdpConnection component
to the tray at the bottom of the form designer. You can also
add a BdpConnection from the tool palette, but dragging the
connection from the Data Explorer saves a lot of time, because
all the BdpConnections properties are set automatically.
Although I use the Borland Data Provider components in this
series of articles, theyre not your only choice. You may want
to use the SqlConnection and SqlDataAdapter components
if youre working with SQL Server, for example. If you dont
have an ADO.NET provider for your database, you can use
the OleDb components to connect using an OLEDB provider.
You can use the ODBC provider components if you need to
connect using an ODBC driver. The features of all these component sets are similar, so most of the information in this
series of articles will apply no matter which youre using.
Change the name of the connection object from
BdpConnection1 to EmployeeConn. A look at the Object
Inspector reveals that the BdpConnection component
has few properties. The most important and complex is
ConnectionString. For example, the connection string
for the employee database on my system is:

Columns

&

Rows

ADO.NET Data Access Components

database=DellInsp8000:c:\program files\borland\interbase\
examples\database\employee.gdb;assembly=Borland.Data.
Interbase,Version=1.1.0.0,Culture=neutral,PublicKeyToken=
91d62ebb5b0d1b1b;vendorclient=gds32.dll;provider=
Interbase;username=sysdba;password=masterkey

As you can see, the format is similar to an ODBC connection string. The string consists of several Name=Value
pairs separated by semicolons. The order of the
Name=Value pairs is unimportant. The Database property
gives the name of the database. For an InterBase database
this is the InterBase connection string, which is the server
name followed by a colon, followed by the path to the database file. Assembly provides the name, version, and public
key for the assembly that contains the BDP driver for the
database. For InterBase this is Borland.Data.InterBase.
VendorClient is the database vendors client library, in this
case, gds32.dll. Provider specifies the name of the BDP provider. Username and password are obvious.
Because the connection string is complex and differs from
one database to another, the easiest way to create one is
to create a connection in the Data Explorer and set all the
properties there. Even if you need to change the connection
string at run time, you can create a connection in the Data
Explorer, test it, then copy the connection string into your
code and add the logic to modify it at run time.
The Database property is a read only property that
returns the value of the Database parameter in the
connection string. It exists to provide an easy way to
get the database name. The ConnectionTimeout property
isnt currently supported. When implemented it will
let you specify how long to wait for a connection to
open before an exception is raised. The BdpConnection
component also has a run time read-only property
named State that returns either ConnectionState.Open or
ConnectionState.Closed.
Connection Pooling
The BdpConnection component doesnt support
connection pooling, but the Microsoft SqlConnection and
OleDbConnection components do. Pooling connections
lets many clients reuse each open connection. Opening a
connection is a relatively expensive operation, so pooling
connections can improve performance in the middle
tier of a multi-tier application. This reduces the number
of times a connection has to be opened and improves
performance.
Connection pooling is enabled by default for both the
SqlConnection and OleDbConnection components; however,
there is no reason to use connection pooling in a two-tier
application. Add the following attribute to the connection
string if you want to disable connection pooling in the
SqlConnection component:
Pooling=False

The OleDbConnection object uses a different connection


string attribute:
OLE DB Services=-4

11

DELPHI INFORMANT MAGAZINE | February 2004

Figure 4: The Connections Editor.

Using the Connection: The


BdpConnection Methods
Drop a Button, a ListBox, and a StatusBar component on
the form so it looks like Figure 5. Change the buttons
Name to ListTablesBtn and its Text property to List Tables.
Change the name of the ListBox to ListBox and change
the name of the StatusBar to StatusBar. Set the text of the
StatusBar to Connection closed.
Double-click the Button component to create an
OnClick event handler, and add the code shown in
Figure 6. The first step in using the BdpConnection
component is to open it. The code begins by checking
the BdpConnections State property and opening the
connection if its closed.
The Borland Data Provider architecture implements
transactions as a separate object. The OnClick event handler
declares a variable of type IdbTransaction and calls the
BdpConnections BeginTransaction method to start a new
transaction and return a reference to the IdbTransaction
interface. BeginTransaction takes an optional parameter which
specifies the transactions isolation level. The parameter must
be a member of the IsolationLevel enumeration. The members
are Chaos, ReadCommitted, ReadUncommitted, RepeatableRead,
Serializable, and Unspecified. Implementing transactions in a
separate object means that you can have multiple transactions
active on the same connection at the same time, as long as
like InterBase your database allows doing so.
Only the BdpConnection component is capable of getting
the metadata of your database. The BdpConnections

Columns

&

Rows

ADO.NET Data Access Components

procedure ConnMainForm.EmployeeConn_StateChange(
Sender: System.Object;
e: System.Data.StateChangeEventArgs);
var
NewState: string;
begin
if (e.CurrentState = ConnectionState.Open) then
NewState := 'open'
else
NewState := 'closed';
StatusBar.Text := 'Connection ' + NewState;
end;

Figure 8: The OnStateChange event handler.

in-memory table and, in this case, holds the information


that GetTables returns about the tables in the database.

Figure 5: The demo applications form.


procedure ConnMainForm.ListTablesBtn_Click(
Sender: System.Object; e: System.EventArgs);
var
SchemaTable: DataTable;
Trans: IdbTransaction;
I: Integer;
begin
if (EmployeeConn.State = ConnectionState.Closed) then
EmployeeConn.Open;
Trans := EmployeeConn.BeginTransaction(
IsolationLevel.ReadCommitted);
SchemaTable := EmployeeConn.GetMetadata.GetTables(
'%', TableType.Table);
ListBox.Items.Clear;
for I := 0 to SchemaTable.Rows.Count - 1 do begin
ListBox.Items.Add(SchemaTable.Rows[I][3].ToString);
end;
Trans.Commit;
EmployeeConn.Displose;
end;

Figure 6: The Button objects Click event handler.

GetMetadata method
returns an ISQLMetadata
interface. The methods of
the ISQLMetadata interface
are listed in Figure 7. See
the online help for more
information about these
methods.

GetColumns
GetIndices
GetObjectList
GetProcedureParams
GetProcedures
GetProperty
GetSchemaTable

GetTables
Returning to the OnClick
event handler shown in
SetProperty
Figure 6, the code calls the
Figure 7: ISQLMetadata methods.
GetTables method for the
ISQLMetadata interface
returned by the BdpConnection. GetTables creates a
DataTable object and returns a reference to the DataTable.
Ill describe the DataTable object in detail in a later article
in this series. For now, just accept that a DataTable is an
12

DELPHI INFORMANT MAGAZINE | February 2004

The OnClick event handler clears the Items property of the


ListBox. Then its for loop iterates through the rows of the
DataTable and adds the name of each table to the ListBox.
Finally, the code commits the transaction and calls the
Dispose method of the BdpConnection. Why call Dispose
instead of Close? Any object that has a Dispose method uses
unmanaged resources; calling Dispose frees those resources
immediately, instead of waiting for the garbage collector
to destroy the object. As a general rule, if an object has a
Dispose method, you should call it as soon as you are done
with the object.
Responding to State Changes:
The BdpConnections Event
The OnStateChange event is the BdpConnection
components only event. Figure 8 shows the
OnStateChange event handler from the sample
application. OnStateChange fires whenever the state
of the BdpConnection changes from open to closed, or
vice versa. The code in Figure 8 changes the message
displayed in the status bar to indicate the current state of
the connection.
Conclusion
The first step in using ADO.NET is to connect to your
database using the connection objects. This article has
looked at the properties, methods, and events of the
BdpConnection component, as well as how to connect
to a database, create a transaction object, and retrieve
some metadata from the database. In the next installment,
well examine the Command, Parameter, and DataReader
objects and use them to select and update data.
The files referenced in this article are available for download on the Delphi Informant Magazine Complete Works
CD located in INFORM\2004\FEB\DI200402BT.

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 also an internationally known trainer and frequent speaker at
Borland Developer Conferences in the United States and Europe. Readers
may reach him at btarticle@dbginc.com.

O N

T H E

POP, SMTP, WEBDAV

N E T

HOTMAIL

E-MAIL PROXY SERVER

DELPHI 4-7

By Alfred Mirzagitov

Writing an E-mail Proxy Server


Part II: Implementing Hotmail Specifics

his two-part series provides a small case


study on how to use Delphi to handle the
e-mail protocols POP and SMTP, WebDAV

(Web Distributed Authoring and Versioning


protocol), and to write a fully functional local
POP/SMTP proxy server for sending and retrieving
hotmail.com e-mails using your favorite e-mail
client. It also touches on some security issues such
as Internet Explorer security zones and filtering
client connections based on IP addresses. In Part I,
we examined the problem and technologies. Now
well implement the solution.

With last months work complete, we have the entire


framework we need. The final task is to implement the
back-end that allows our POP and SMTP servers to translate and pass commands to Hotmail. If we use a layered
view, well be building the lower layer, which uses Microsoft Hotmail as the e-mail transport.
As we discussed last month, if your return address is
hotmail.com, then currently Microsoft Outlook is the only
e-mail client that can directly communicate with the Hotmail
mail server and send and receive e-mail messages. Unfortunately, Microsoft doesnt disclose how Outlook communicates
with the hotmail.com Web site. However, if youre willing to
13

DELPHI INFORMANT MAGAZINE | February 2004

eavesdrop on the TCP/IP packets long enough, its possible to


recognize patterns and figure out how things work.
Outlook uses a special protocol named WebDAV. Using WebDAV, a program (user-agent) on the client computer can
retrieve or send e-mails via HTTP. Therefore, the protocol used
by Outlook is sometimes referred to as HTTPMail. WebDAV is
an extension to HTTP to provide a standards-based infrastructure for asynchronous collaborative authoring on the Web.
Traditionally, the Web has been a read-only medium. WebDAV is called to change this, making the Web a writable,
collaborative medium. At least, thats the vision of the WebDAV working group of the Internet Engineering Task Force
(IETF). Influential vendors such as Microsoft, Netscape,
Xerox, IBM, and Novell have assisted in WebDAV development, as has the WWW Consortium. Ultimately, the full
implementation of WebDAV extensions is supposed to provide a common interface to many types of repositories, making the Web analogous to a large-grain, network-accessible
file system. You would simply edit Web documents (or any
Web resource) in place at a URL. These documents would
be protected by a discoverable locking mechanism, so they
wouldnt be overwritten, and you would effectively limit
access rights. In brief, imagine a huge, distributed, multiuser file system based on HTTP. (Details of WebDAV can be
found in RFC2291, RFC2518, and RFC3253.)
Using WebDAV commands, you can lock a resource, and get
or change a property. Because its HTTP, WebDAV can work
through firewalls and proxy servers that allow HTTP.
WebDAV uses Extensible Markup Language (XML) for
encoding method parameters and the responses from

On

the

Net

Writing an E-mail Proxy Server

methods, for method output and input. XML has been


chosen because it has a highly flexible syntax that can
be used to describe virtually any kind of information that
can be stored on computers, and because of its support
for multiple character sets.

PROPFIND

Retrieves properties defined on the resource


identified by the Request-URI.

PROPPATCH

Processes instructions specified in the request


body to set and/or remove properties defined
on the resource identified by the Request-URI.

For our purposes of communicating with the Hotmail server,


we need to know very little about the WebDAV protocol
implementation. Our HotServer application (and Microsoft
Outlook) use only the six methods shown in Figure 1.

GET and POST

These allow sending and receiving data to and


from the server.

BDELETE

Lets us batch-delete documents on the server.

MOVE

Hotmail allows deleting files from the trash


folder only, so we also use the MOVE method.
Using MOVE, its possible to change the location of a resource without a client loading, then
resave the resource under a different name.
After a MOVE operation, its no longer possible
to access the resource at its original location.

This all sounds exciting, but the immediate question is how


to use the WebDAV protocol in our Delphi applications.
Luckily, Microsoft Internet Explorer ships with a component
named XMLHTTP that helps you do the job. XMLHTTP is a
component of MSXML (Microsoft XML Core Services), and
is designed to pass XML documents to programs over the
Internet using standard HTTP. You still have to send correctly formatted WebDAV requests when using XMLHTTP,
but it greatly simplifies the process.
MSXML is a set of services that provide functions for working with XML documents. A primary use of MSXML is to
parse, generate, validate, and transform XML documents, so
the information can be displayed, stored, or manipulated.
At the time of this writing, MSXML is on version 4, SP 2.
Standard Windows installations will typically have an older
version of MSXML, which is adequate for our current application. For general development and production purposes,
you may want to download and install a later version of
MSXML. For deployment purposes you can get the latest
MSXML as a redistributable file.
MSXML is implemented as a COM-based library. Delphi
provides excellent support for creating applications based
on the COM technology. Details of the COM technology are
beyond the scope of this series, and Delphi does a good job
of hiding them from the programmer.
All you have to do to be able to use XMLHTTP in Delphi
is import a type library. Select Project | Import Type Library and
scroll to find Microsoft XML, v3.0 (Version 3.0). (You may be able
to use MSXML version 4.0, if its in the list.) Click the Create
Unit button. Delphi will automatically generate an interface
unit named MSXML2_TLB, and put it in $(DELPHI)\Import
directory. After that, all you need to do in your code is add
MSXML2_TLB to your uses clause.
For parsing the data retrieved from the Hotmail server, we
use another component named DOMDocument from the
same MSXML library. Document Object Model (DOM) is a
standard library of APIs for accessing XML documents. DOM
is complex, but Microsoft provides a pretty detailed description of DOM in MSXML 4.0 SDK documentation.
UHotSrv.PAS is the biggest unit in the project and it contains the code that handles the Hotmail specifics of our
mail proxy. The code is lengthy, but it is rather simple in
essence. The THotPopConnection and THotSmtpConnection
classes derive from TPopConnection and TSmtpConnection
classes respectively, and implement all the abstract methods of the parent classes.
14

DELPHI INFORMANT MAGAZINE | February 2004

Figure 1: WebDAV methods used by HotServer (and Microsoft Outlook).

The client starts a login sequence to our POP server by sending the username and password. THotPopConnection forms
and sends a series of WebDAV commands to hotmail.com.
The first command contains the username and password
because Hotmail requires authentication. The rest of the
WebDAV commands dont have to pass the username and
password, since hotmail.com server keeps track of the clients.
Notice that we still need to introduce our own so-called
e-mail session for storing some basic client information and
Hotmail outbox URL. This information will be used later for
sending e-mails.
The first WebDAV command after a successful authentication retrieves Hotmail folder locations. There are more than
three folders, but all we need to know is the URLs of three
folders (or mailboxes): the incoming mail folder (inbox), the
outgoing mail folder (outbox), and the trash folder.
Once it knows the inbox location, THotPopConnection is ready
to retrieve e-mail statistics and download e-mail messages following the commands issued by an e-mail client application
talking to our POP server. The client commands are parsed by
the POP server, and translated into WebDAV commands. The
results of the WebDAV commands are translated to POP protocol responses and passed back to the client.
THotPopConnection keeps track of all the changes during
the transaction state, but there are no permanent changes to
Hotmail folders. When the client finally issues a QUIT command, all the changes are made permanent.
The SMTP communications are handled similarly, except
for authentication. When an e-mail client initiates an SMTP
connection, it doesnt provide a user ID or password. Hotmail, on the other hand, requires authentication. If we initiated, or if we just finished, a POP session for this specific
client, we can access the client outbox without authentication. But the question is how to identify the client. When
the client tries to send an e-mail, he provides his return
address. THotSmtpConnection checks if there is a valid email session for this return address and for this specific
IP address. If theres no active e-mail session, then SMTP
returns an error. For the SMTP session to work, therefore, it

On

the

Net

Writing an E-mail Proxy Server

procedure TForm1.PopSocketAccept(Sender: TObject;


ClientSocket: TCustomIpClient);
var
pop: THotPopConnection;
begin
if AcceptRemoteClient(ClientSocket.RemoteHost) then
begin
pop := THotPopConnection.Create(ClientSocket);
try
pop.Execute;
finally
pop.Free;
end;
end
end;

Figure 2: The PopSocketAccept event handler.

must follow a POP session. If theres an active e-mail


session, it means that HotServer has already run a POP
session and the user has been authenticated. Then
THotSmtpConnection can retrieve the Hotmail outbox URL
from the e-mail session and use that URL to upload e-mails.
The e-mail sessions expire in 60 minutes. To avoid running an SMTP session before a POP session, simply
set your client to check e-mails automatically every 30
minutes, so you dont have to worry about the proper
sequence of calls.

Putting It All Together


The final step is to modify our main module to use the
classes we just built (see Figure 2). When the client tries
to establish a connection to this TCP/IP socket, the
PopSocketAccept event handler first checks the clients
IP address. If it isnt a valid (acceptable) IP address, then
the connection is dropped. Otherwise, the application
creates an instance of THotPopConnection. The Execute
method will handle all client commands until the client
disconnects. The last step is to free the resources. The
SMTP socket handler is almost identical to the POP
socket handler.
Installing HotServer
HotServer doesnt really require installation. You just
need to start it and keep it running before you start your
e-mail client. You can simply create a .BAT file that does
this, and stick it into your Windows StartUp directory. If
you intend to run HotServer on an NT (or W2K, XP), HotServer can be implemented as a service.
Set up your Hotmail account in your e-mail client. For
this example, assuming you have a valid hotmail account:
john_doe@hotmail.com, lets also assume that you
havent forgotten your password:
Name: John Doe
E-mail: john_doe@hotmail.com

Trust but Verify: IE Security Zones


There is a curious detail in using the XMLHTTP component and MSXML, and it relates to Internet security.
Older versions of the XMLHTTP control in the Microsoft
XML Core Services did not respect the Internet Explorer
Security Zone restrictions. Therefore, before the release of
the security patch described in Microsoft Security Bulletin
MS02-008 (02/21/2002) the applications could use the
XMLHTTP control without any special measures. However, ignoring the IE Security Zone restrictions was one of
the vulnerabilities in the XMLHTTP control, and Microsoft
fixed the problem by releasing a security patch. Of course,
many applications that use XMLHTTP stopped working
after installing the patch.
On computers with the security patch in place, its important to add the Hotmail domain to the list of Trusted Sites
to be able to send and receive e-mails. The UTrust.PAS unit
exposes a public TrustedInternetZone function that allows
the programmer to check, and, if necessary, add the specific domain to the IE Trusted Sites Zone. TrustedInternetZone
is called before THotPopConnection issues the first WebDAV
command.
The Trusted Sites Zone contains a list of the sites you trust
sites you believe you can download or run files from,
without worrying about damage to your computer or data.
The default security level for the Trusted Sites Zone is Low.
Details on the registry keys used by Internet Explorer
Security Zones are available in Microsoft Knowledge Base
article Q182569 and the MSDN online library at http://
msdn.microsoft.com/workshop/security/szone/urlzones.asp.
15

DELPHI INFORMANT MAGAZINE | February 2004

Username: john_doe
Password: **********

Specify localhost as both your incoming POP server and


outgoing SMTP server for this account. Now youre ready
to receive, compose, and send e-mails.
Conclusion
In this series weve discussed a specific implementation of an e-mail proxy server for sending and receiving
e-mails using Hotmail. We also touched on the use of
MSXML components, WebDAV, and Internet security. The
code provides a good example of how multiple different
technologies can be used within the same application.
The code that accompanies this series can be easily
expanded, and knowledge of mail protocols can be used
to write very sophisticated applications for your enterprise. For example, this can be an e-mail proxy server
for tunneling e-mails across a restrictive firewall, or for
implementing e-mail logging, filtering spam and junk emails, or specific and fine e-mail handling which cannot be done using an off-the-shelf e-mail server. At this
point you are limited only by your imagination.
The project referenced in this series is available for download on the Delphi Informant Magazine Complete Works
CD located in INFORM\2004\FEB\DI200402AM.

Alfred Mirzagitov is a senior programmer for Software Science Inc., located


in San Rafael, CA. He has been programming in C and Pascal for over 15
years and in Delphi since the release of version 1. You can contact him by
e-mail at: alfred@softsci.com.

. N E T
.NET FRAMEWORK

D E V E L O P E R

.NET COLLECTIONS

DELPHI FOR .NET PREVIEW

By Xavier Pacheco

Using the Framework


Part II: HashTables and Strongly Typed Collections

n Part I of this series, I began a discussion on


collections (see the November 2003 issue of
Delphi Informant). In this installment, Ill pick

up where I left off by discussing the HashTable


class. Then I will illustrate how you can create
your own, strongly typed collection and dictionary. If you havent already, I recommend that you
read my first article.
HashTable
The HashTable class stores items that are indexed by an
alphanumeric key. This is different from an ArrayList,
which indexes items by a numeric value. Additionally,
there is no ordering that you control in the HashTable class.
HashTable uses its own hashing algorithm to order items
for fast searching and retrieval. HashTable is a Dictionary
and thus implements the IDictionary interface. A Dictionary
is a class that represents values as Name/Value pairs.
Basically, the HashTable class works as follows. When
given an alphanumeric key, HashTable, using a hashing
algorithm, converts a key to a hash code. A hash code is
a unique numeric index used to index a requested element. Items stored in a HashTable are stored in buckets.
The HashTable uses a key to identify a bucket. Ideally,
there would only be one item in each bucket, thus making HashTable very efficient at searching.
HashTable implements the IDictionary, ICollection,
IEnumerable, ISerializable, and ICloneable interfaces.
16

DELPHI INFORMANT MAGAZINE | February 2004

HashTable Methods/Properties
HashTable has several overloaded constructors. These constructors allow you to specify certain attributes, such as
the default capacity, load factor, hash code provider, and
comparer. Additionally, you can specify another IDictionary
instance from which to copy elements and serialization/
streaming objects for streaming customization. HashTables
load factor is the maximum ratio of elements it stores to
buckets. The default is 1. The capacity is the number of
buckets to allocate, based on this load factor. The comparer
is a class that implements the IComparer interface and is
used to determine the equality of keys.
The table in Figure 1 lists the various properties of HashTable.
The table in Figure 2 lists some key methods of HashTable.
Property

Description

Count

Returns the number of items (key/value pairs)


contained in HashTable.

IsFixedSize

Specifies whether HashTable is of a fixed size.

IsReadOnly

Specifies whether HashTable is read-only. When


a collection is read-only, you cannot add,
remove, or modify items in the collection.

IsSynchronized

Specifies whether HashTable is thread safe.

Item

Get/Set value with a specified key.

Keys

Retrieves an ICollection with the keys contained


in HashTable.

SyncRoot

Retrieves an object used to synchronize


HashTable.

Values

Retrieves an ICollection of Values contained in


HashTable.

Figure 1: HashTable properties.

.NET

Developer

Using the Framework

A HashTable Example
Listing One (on page 18) illustrates the use of HashTable.
In this example, I store customer information, which is
indexed by a Customer ID, a string field. The customer
information is contained in the class TCustomer (lines 916). The TCustomer constructor (lines 37-45) simply populates the customer members with the information passed
in as parameters.
Line 49 creates a HashTable class instance. Lines 50-61 populate HashTable with information about various customer
contacts. Note that the first parameter to the Add method is
the Key by which items in HashTable will be located.
Lines 63-66 call the PrintCustomer procedure, which illustrates how to extract an entity from HashTable. PrintCustomer
takes a string parameter, the key to the entity to extract
and print.
Creating a Strongly Typed Collection
With my last article and this one, you have seen the various
collections that are available through the .NET Framework.
Each of these collections can hold a list of heterogeneous types.
You may have a need to contain a single type; in this case, it
would be advantageous to use a strongly typed collection.
There are two routes you can take to create a strongly typed
collection: the easy way, and the easier way. The easy way
is to create a class that implements the various required
interfaces: IList, ICollection, and IEnumerable. The easier
way is to use a class that already does this, CollectionBase.
Here are the steps required to create a descendant from the
CollectionBase class:
1) Create an indexed property to retrieve items in Collection.
2) Override type-checking events (OnInsert, OnSet,
OnValidate) and add code to raise an exception given
an invalid type (a type that is not a TStateInfo class).
3) Implement methods for working with the collection,
using the same standard names as IList and ArrayList.
Listing Two (beginning on page 18) illustrates a strongly
typed collection based on the TCustomer class example from
Listing One. In line 19, you see that TCustomerCollection
descends from the CollectionBase class. To follow Step 1) Ive
created Customer, which is an indexed property and uses
the getter and setter methods GetCustomer and SetCustomer,
respectively. The next step is to override the type checking
methods OnInsert, OnSet, and OnValidate. I simply wrote a
method, VerifyType, that ensures that the object being evaluated is of the type TCustomer.
The remaining methods are methods which must be overridden to actually manipulate the collection list. The collection list is an internal member, List, which is a class that
implements the IList interface. That is basically all there is
to defining a strongly typed collection. To use this collection
and add an item, simply execute code similar to this:
custDemo := TCustomerCollection.Create();
custDemo.Add(TCustomer.Create('Xavier Pacheco',
'Xapware Inc.', '719-573-4049', EncodeDate(2003,12,14)));

17

DELPHI INFORMANT MAGAZINE | February 2004

Method

Description

Add

Adds an element to HashTable using the provided Key and Value.

Clear

Removes the HashTable contents.

Close

Creates a shallow copy of HashTable.

Contains

Determines whether the HashTable contains a


specified Key.

ContainsKey

Same functionality as the Contains method.

ContainsValue

Determines whether HashTable contains a


specified Value.

CopyTo

Copies elements from a HashTable to a onedimensional Array class.

Remove

Removes an element using a specified Key from


HashTable.

Synchronized

Returns a thread-safe wrapper for HashTable.

Figure 2: HashTable methods.

Creating a Strongly Typed Dictionary


Similar to CollectionBase is the DictionaryBase class from
which you can derive your strongly typed dictionary classes.
Using the same TCustomer class, Listing Three (beginning
on page 19) illustrates a strongly typed dictionary.
Listing Three really only differs from Listing Two in how the
elements are retrieved from the indexed property. In the dictionary, elements are retrieved by a string index (lines 44-45).
You will also see two additional properties, Keys and Values,
both of which return an ICollection. The PrintItems method
illustrates how to iterate through the dictionary by obtaining an Array of its Keys. Line 115 retrieves an ICollection of
the dictionaries Keys, then, using the CopyTo method, copies
those keys to an array (on line 117). The values of the Array
are then used to get the TCustomer element which is then
printed to the console.
That concludes our discussion about collections. In the next
installment, Ill examine how you can bind custom collections to user controls.
Helpful Reading
Check out these Web sites for more information:
MSDN: http://msdn.microsoft.com (search on
System.Collections)
Borland Developer Network:
http://community.borland.com/delphi/
Dr. Bobs Site: www.drbob42.com
Coming soon: www.DelphiGuru.com
The files referenced in this article are available for download
on the Delphi Informant Magazine Complete Works CD
located in INFORM\2004\FEB\DI200402XP.
Xavier Pacheco is the president and chief consultant of Xapware Technologies
Inc., provider of Active! Focus a practical solution for managing software projects
and requirements management. Xavier is the co-author of Delphi 6 Developers
Guide and has also written for publications such as Delphi Informant and Delphi
Magazine. Xavier is available for consulting and training engagements. You may
contact him at xavier@xapware.com or visit www.xapware.com.

.NET

Developer

Using the Framework

Begin Listing One HashTable Usage


1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:

program d4dnHashTable;
{$APPTYPE CONSOLE}
uses
System.Collections, Borland.Vcl.SysUtils;
type
// Define a class to store in the HashTable.
TCustomer = class
ContactName: string;
Company: string;
PhoneNumber: string;
DateOfContact: TDateTime;
constructor Create(aContactName, aCompany,
aPhoneNumber: string; aDateOfContact: TDateTime);
end;
var
htDemo: HashTable;
procedure PrintCustomer(aKey: string);
const
fmtStr = 'ContactName: { 0 }, Company: { 1 }, ' +
'PhoneNumber: { 2 }, Date: { 3 }';
var
si: TCustomer;
begin
// First retrieve TCustomer item from the HashTable.
si := htDemo[aKey] as TCustomer;
// Print out its contents.
Console.WriteLine(System.string.Format(fmtStr,
[si.ContactName, si.Company, si.PhoneNumber,
si.DateOfContact]));
end;
{ TCustomer }
constructor TCustomer.Create(aContactName, aCompany,
aPhoneNumber: string; aDateOfContact: TDateTime);
begin
inherited Create;
ContactName
:= aContactName;
Company
:= aCompany;
PhoneNumber
:= aPhoneNumber;
DateOfContact := aDateOfContact;
end;
begin
// Initialize and populate the HashTable
htDemo := HashTable.Create();
htDemo.Add('SBEEBE',TCustomer.Create('Steven Beebe',
'Xapware Inc.',
'719-573-4049', EncodeDate(2003, 12, 14)));
htDemo.Add('MBRYANT',TCustomer.Create('Mark Bryant',
'Acme Inc.',
'123-456-7890', EncodeDate(2002, 3, 18)));
htDemo.Add('SADAMS',TCustomer.Create('Susan Adams',
'XYZ Corp', '456-234-8736',
EncodeDate(2003, 7, 22)));
htDemo.Add('PYOUNG', TCustomer.Create('Paul Young',
'ABC Associates', '987-654-3210',
EncodeDate(2000, 8, 1)));
// Print the HashTable items by Key.
PrintCustomer('SBEEBE');
PrintCustomer('MBRYANT');
PrintCustomer('SADAMS');
PrintCustomer('PYOUNG');
System.Console.ReadLine;
end.

End Listing One


Begin Listing Two A strongly
typed collection
1:
2:
3:

18

unit CustColl;
interface

DELPHI INFORMANT MAGAZINE | February 2004

4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76
77:
78:
79:
80:
81:
82:
83:

uses System.Collections;
type
// Define a class to store in the Collection.
TCustomer = class
ContactName: string;
Company: string;
PhoneNumber: string;
DateOfContact: TDateTime;
constructor Create(aContactName, aCompany,
aPhoneNumber: string; aDateOfContact: TDateTime);
end;
// Define the strongly typed collection.
TCustomerCollection = class(CollectionBase)
private
function GetCustomer(Index: Integer): TCustomer;
procedure SetCustomer(Index: Integer;
const Value: TCustomer);
procedure VerifyType(Value: TObject);
strict protected
// Type checking events.
procedure OnInsert(index: Integer;
value: TObject); override;
procedure OnSet(index: Integer; oldValue: TObject;
newValue: TObject); override;
procedure OnValidate(value: TObject); override;
public
constructor Create;
function Add(value: TCustomer): Integer;
function IndexOf(value: TCustomer): Integer;
procedure Insert(index: Integer;value: TCustomer);
procedure Remove(value: TCustomer);
function Contains(value: TCustomer): Boolean;
procedure PrintItems;
property Customer[Index: Longint]: TCustomer
read GetCustomer write SetCustomer;
end;
implementation
{ TCustomer }
constructor TCustomer.Create(aContactName, aCompany,
aPhoneNumber: string; aDateOfContact: TDateTime);
begin
inherited Create;
ContactName
:= aContactName;
Company
:= aCompany;
PhoneNumber
:= aPhoneNumber;
DateOfContact := aDateOfContact;
end;
{ TCustomerCollection }
constructor TCustomerCollection.Create;
begin
inherited Create;
end;
function TCustomerCollection.GetCustomer(
Index: Integer): TCustomer;
begin
Result := List[Index] as TCustomer;
end;
procedure TCustomerCollection.SetCustomer(
Index: Integer; const Value: TCustomer);
begin
List[Index] := Value;
end;
procedure TCustomerCollection.OnInsert(Index: Integer;
Value: TObject);
begin
VerifyType(Value);
end;
procedure TCustomerCollection.OnSet(Index: Integer;
OldValue: TObject; NewValue: TObject);
begin

.NET

84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:

Developer

Using the Framework

VerifyType(NewValue);
end;
procedure TCustomerCollection.OnValidate(
Value: TObject);
begin
VerifyType(Value);
end;
function TCustomerCollection.Add(Value: TCustomer):
Integer;
begin
Result := List.Add(Value);
end;
function TCustomerCollection.IndexOf(
Value: TCustomer): Integer;
begin
Result := List.IndexOf(Value);
end;
procedure TCustomerCollection.Insert(Index: Integer;
Value: TCustomer);
begin
List.Insert(Index, Value);
end;
procedure TCustomerCollection.Remove(
Value: TCustomer);
begin
List.Remove(Value);
end;
function TCustomerCollection.Contains(
Value: TCustomer): Boolean;
begin
result := List.Contains(Value);
end;
procedure TCustomerCollection.PrintItems;
const
fmtStr = 'ContactName: { 0 }, Company: { 1 }, ' +
'PhoneNumber: { 2 }, Date: { 3 }';
var
i: Integer;
cust: TCustomer;
begin
for i := 0 to Count -1 do begin
cust := TCustomer(List[i]);
Console.WriteLine(System.string.Format(fmtStr,
[cust.ContactName, cust.Company,
cust.PhoneNumber, cust.DateOfContact]));
end;
end;
procedure TCustomerCollection.VerifyType(
Value: TObject);
begin
if not (Value is TCustomer) then
raise ArgumentException.Create('Invalid Type');
end;
end.

End Listing Two


Begin Listing Three Strongly typed
dictionary
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:

19

unit custdict;
interface
uses System.Collections;
type
// Define a class to store in the Collection.
TCustomer = class
ContactName: string;

DELPHI INFORMANT MAGAZINE | February 2004

11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:

Company: string;
PhoneNumber: string;
DateOfContact: TDateTime;
constructor Create(aContactName, aCompany,
aPhoneNumber: string;
aDateOfContact: TDateTime);
end;
// Define the strongly typed dictionary.
TCustomerDictionary = class(DictionaryBase)
private
function GetCustomer(key: string): TCustomer;
procedure SetCustomer(key: string;
const Value: TCustomer);
function GetKeys: ICollection;
function GetValues: ICollection;
procedure VerifyType(Value: TObject);
strict protected
// Type checking events.
procedure OnInsert(key: TObject; value: TObject);
override;
procedure OnSet(Key: TObject; OldValue: TObject;
NewValue: TObject); override;
procedure OnValidate(key: TObject;
value: TObject); override;
public
constructor Create;
procedure Add(key: string; value: TCustomer);
procedure Remove(key: string);
function Contains(key: string): Boolean;
procedure PrintItems;
property Customer[key: string]: TCustomer
read GetCustomer write SetCustomer;
property Keys: ICollection read GetKeys;
property Values: ICollection read GetValues;
end;
implementation
{ TCustomer }
constructor TCustomer.Create(aContactName, aCompany,
aPhoneNumber: string; aDateOfContact: TDateTime);
begin
inherited Create;
ContactName
:= aContactName;
Company
:= aCompany;
PhoneNumber
:= aPhoneNumber;
DateOfContact := aDateOfContact;
end;
{ TCustomerDictionary }
constructor TCustomerDictionary.Create;
begin
inherited Create;
end;
procedure TCustomerDictionary.OnInsert(key: TObject;
value: TObject);
begin
VerifyType(Value);
end;
procedure TCustomerDictionary.OnSet(Key: TObject;
OldValue: TObject; NewValue: TObject);
begin
VerifyType(NewValue);
end;
procedure TCustomerDictionary.OnValidate(key: TObject;
Value: TObject);
begin
VerifyType(Value);
end;
procedure TCustomerDictionary.Add(key: string;
value: TCustomer);
begin

.NET

Developer

Using the Framework

90:
Dictionary.Add(key, value);
91: end;
92:
93: procedure TCustomerDictionary.Remove(key: string);
94: begin
95:
Dictionary.Remove(key);
96: end;
97:
98: function TCustomerDictionary.Contains(
99:
key: string): Boolean;
100: begin
101:
result := Dictionary.Contains(key);
102: end;
103:
104: procedure TCustomerDictionary.PrintItems;
105: const
106:
fmtStr = 'ContactName: { 0 }, Company: { 1 }, ' +
107:
'PhoneNumber: { 2 }, Date: { 3 }';
108: var
109:
cust: TCustomer;
110:
enum: IDictionaryEnumerator;
111:
KeyColl: ICollection;
112:
KeyArray: array of string;
113:
i: Integer;
114: begin
115:
KeyColl := GetKeys;
116:
SetLength(KeyArray, KeyColl.Count);
117:
KeyColl.CopyTo(KeyArray, 0);
118:
for i := Low(KeyArray) to High(KeyArray) do begin
119:
cust := Customer[KeyArray[i]];
120:
System.Console.WriteLine(System.String.Format(fmt
Str,
121:
[cust.ContactName, cust.Company,
cust.PhoneNumber,
122:
cust.DateOfContact]));
123:
end;
124: end;
125:
126: function TCustomerDictionary.GetCustomer(key: string):
127:
TCustomer;
128: begin
129:
Result := Dictionary[key] as TCustomer;
130: end;
131:
132: procedure TCustomerDictionary.SetCustomer(key: string;
133:
const Value: TCustomer);
134: begin
135:
Dictionary[key] := Value;
136: end;
137:
138: function TCustomerDictionary.GetKeys: ICollection;
139: begin
140:
Result := Dictionary.Keys;
141: end;
142:
143: function TCustomerDictionary.GetValues: ICollection;
144: begin
145:
Result := Dictionary.Values;
146: end;
147:
148: procedure TCustomerDictionary.VerifyType(
149
Value: TObject);
150: begin
151:
if not (Value is TCustomer) then
152:
raise ArgumentException.Create(Invalid Type');
153: end;
154:
155: end.

End Listing Three

20

DELPHI INFORMANT MAGAZINE | February 2004

LIFECYCLE MANAGEMENT
MDA

ECO

DELPHI 8 FOR THE MICROSOFT .NET FRAMEWORK

By Glenn Stephens

Enterprise Core Objects


Behind the Model-driven Architecture of
Delphi 8 for the Microsoft .NET Framework

ike me, youre probably a hard-core coder,


spending hours programming the latest
applications using the greatest technology

you can find, reading Dilbert in your spare


time, and silently playing games like buzzword
bingo at meetings (whenever you hear phrases
like paradigm shift, your internal alarm goes
off). I have never used the phrase paradigm
shift in conversation for fear that I will be sent
automatically to marketing. But in regard to
model-driven architecture (MDA), I am going to
make an exception.

Model-driven architecture redefines the way you as a developer will build an application. In todays programming
world you may be getting the requirements from business
analysts for an application. You may start designing the
structure of the application, whether its using Unified Modeling Language (UML) or another method. Once you have
designed your application, you can then go on to the development stage. At best, if youve been using UML and
your modeling tool supports it you may be able to generate code that represents your design.
21

DELPHI INFORMANT MAGAZINE | February 2004

So what is a model?
Basically, a model is
a preliminary work
or design that is the
basis for a final product. If you are familiar
with technologies
such as UML, you will
undoubtedly know
what a model is. If
you dont have a clue,
then think about the
term model for a minute. What you will
find yourself thinking
about are things such
as model airplanes,
model cars, small
designs of houses, and
other pieces of construction. In essence,
a model is a representation of something
that youre trying to
build. For software
development, the
model is an abstract
representation of what
you are trying to build
in your application.

Figure 1: Transformations between


a PIM and a PSM.

Lifecycle

Management

Enterprise Core Objects

Productivity
Boost
The main benefit of
MDA is productivity. As the model
generates a vast
amount of code
your application
will use, you spend
more time focusing
on ensuring that
your model is correct, and less time
programming the
plumbing aspects
of your application.
By spending more
time working on
the model, in most
cases your model
will reflect the actual system its trying
to represent. Many
companies that
have adopted MDA
in their development arsenal have
noticed productivity
improvements of
between 40 and 80
percent. Ive re-written applications that
I developed against
Figure 2: ECO model properties available
while designing a model.
databases, and have
converted them over
to MDA. The development of the system took 35 percent
of the time it took to build the original version.
Not only is the development of the application more productive, but because there are validation steps in building
the model, there are also improvements in testing that the
model is valid. As a result, the quality of your end application will be improved.
Reduced Cost
Applying MDA dramatically changes the way that applications are built and maintained, reducing not only the
cost of development, but also the cost of maintenance. A
common phrase you hear now in the post dot-com bubble
days is that as developers we have to do more with less.
By adopting model-driven development and MDA, you
will obviously be able to save time and money by developing the application faster. There are other ways that
adopting ECO will help to reduce cost.
Primarily, its in the maintenance of an application developed with ECO that is most likely to deliver significant
cost savings. In many cases, developers are so crunched
for time when building the application, that little documentation is generated. The documentation of the system
may be the initial project designs or it may consist of
comments in the code. Either way, there is insufficient
22

DELPHI INFORMANT MAGAZINE | February 2004

time spent documenting the system. Many developers feel


that they will document the system after they finish programming it, but are often moved on to other projects, or
leave the company.
Using model-driven development, new developers can
examine models directly to understand the relationship
between classes, and then view the information about
the classes. This reduces the learning curve for the new
developer, therefore reducing costs in the development of
the project.
The MDA approach not only recognizes the development
of an application as important, but also the maintenance
of the various systems that comprise the application. For
example, if you create a class named Customer, and later
add an additional attribute named EmailAddress, then you
should not have to regenerate each part of the application, or worse, manually update code and database schemas, but instead update the parts of the applications that
are affected.
The Pieces of the Puzzle, PIM, PSM,
and Transformations
The power behind MDA is that it generates code based on
models. However, there are two types of models that you
will come across. The first is called a Platform Independent Model (PIM), which, as its name suggests, is a model
that describes a system that is not reliant on any platform.
The next type of model is called the Platform Specific
Model (PSM). As you can probably guess, the PSM is a
model that contains the information specific to a platform. For a client-server application, you will have one
PIM that represents the system, and then two PSMs.
One PSM will be generated for the database that you
will be running your application against, while the other
model will be the business objects that are created to
support your application. Typically, the PIM will be converted to a PSM and also to code or database schema via
a transformation (see Figure 1). Transformations are the
power behind MDA, because they generate the majority of
the system for you.
In a PIM, you will rarely have specific information about
the implementation. Normally in UML, youll have information about the classes that youll be building. However,
when you transform the class information into something
like a relational database, youll need information, such
as column name, type, and size. To maintain relationships
between classes you also need identifiers, links, tables,
and indexes. The same applies for code; implementing
classes in code usually requires get and set methods for
attributes, and handling of objects lists, and perhaps
the trickiest associations. This is the kind of information that the realization of a model requires, but you
dont want to pollute your core domain model with.
So how does a PIM get transformed into a PSM? The most
common way is by programming transformation logic,
scripted rules, and templates that handle transformations.

Lifecycle

Management

Enterprise Core Objects

Figure 4: Entering the name of your new application.

Figure 3: Creating a new ECO application.

What Is Enterprise Core


Objects (ECO)?
Now that you have an idea what MDA is all about, youre
going to love Enterprise Core Objects (ECO). Borland
ECO is an implementation of MDA concepts, but it eliminates the need for transformation script programming.
With ECO, transformations are done transparently and
automatically. Thats where the Rapid in Rapid MDA
comes in.
In regards to transformations, ECO can transform your
model into a relational database, such as InterBase, Oracle,
DB2, and SQL Server to name a few, as well as transform
your model to Delphi classes. But these classes arent merely
representations of the information. They plug into a powerful model-powered platform that provides the most common
services of an application, as well as a range of advanced
services. Among the common services, you will find persistence mapping, transaction handling, inter-object relationships, and so on. The advanced services include user-controlled undo/redo, object versioning, and more. Imagine
having undo/redo in your application just by adding a component and setting properties on a button, or being able to
find out what the objects values were two weeks ago. This
is just a small example of the power behind ECO.
ECO also gives you the ability to evolve your system over
time. You can upgrade the database as the class definitions change, or update the functionality of a method
that deals with a class in an ECO system. ECO allows the
designer to add specific information by using the UML
extension mechanism, Tagged Values. Figure 2 shows the
model properties available while designing a model.
So with Delphi 8 for .NET Architect you have the best of
breed tools to implement MDA.
Building Your First ECO Application
All this talk about the benefits of MDA is useless, unless
we can put it into practice. So well go through the steps of
building a simple master-detail application. This application
will track a collection of products and categories, where
well have many products for each category.
23

DELPHI INFORMANT MAGAZINE | February 2004

First well create the ECO application, which we can do by


selecting File | New | Other from Delphis main menu. Select
Delphi for .NET Projects, then select ECO Windows Form Application,
as shown in Figure 3. At this point youll be prompted to
enter the name of your application (see Figure 4).
Now that you have a blank ECO application, youre ready
to go. Because we are working with model-driven architecture, however, we need to go straight to the model to
build the application. Remember, the model is the application and its design should come first.
The Delphi 8 for .NET IDE has a built-in modeling system
that builds on the power of Borlands Together software.
The Together technology provides a design surface that
allows you to create UML class diagrams, which allow you
to create your classes and the associations between those
classes. The Together technology provides more features,
but for the sake of simplicity, well deal with just these
features to get through our typical application. In Delphi
8 for .NET, unlike other MDA implementations (where
you would load an external modeling tool such as Rational Rose, Model Maker, or ArgoUML), whatever changes
you make to the model are automatically reflected in your
code. Talk about making the modeling process easier!
To start the class diagram designer, select the Model View,
and expand the tree until CoreClasses is selected. Doubleclick this tree node, and the model designer will open up
(see Figure 5).
Youll need a few classes to work with. Because our
example application will deal with Categories and Products, well create these two classes first. Select the new
class item from the UML Class Diagram in the Tool Palette (see Figure 6), then drag a rectangle onto the model
designer. An edit box will be presented where you can
enter the name of your class. In this case, well create one
class named Category, and another named Product (see
Figure 7).
The next thing well want to do is create some properties
for our classes. For the Category class, well have a Code
and a Name, and for our Product class well have Code,
Name, UnitCost, and StockOnHand (see Figure 8).
One of the more powerful features of ECO, and my personal favorite, is the way in which associations are managed. Much of the plumbing code that you may normally

Lifecycle

Management

Enterprise Core Objects

Figure 6: Selecting the new UML class.

Figure 7: Creating empty classes.

Figure 5: The blank model.

write in database applications is for managing the associations between entities. In the class diagram designer
you can select the association item from the Tool Palette
(again, see Figure 6), and draw a line between the classes
you want associated.
You will then have an association defined between the
two classes. By default, the association will be one-to-one
on both sides of the association. In the case of our model,
there will be one category to many products listed, so
you should change the multiplicity for the Products from
0..1 to 0..*, and change the names of the associations to
reflect the multiplicity values (see Figure 9).
Now we have a simple model that we can use in our
application, which has the appropriate properties and a one-to-many
association. You are now ready to
build the presentation layer for the
application.

Space, which is a central piece of an application based on


ECO. The Eco Space can be described as an object cache
or container, where all the objects in the system reside. It
needs the model information and the class diagrams to be
able to manage all the objects. When building a user interface, you would normally bind the UI controls to a DataSource, but with ECO there is a clear separation between
persistence, the object layer, and the GUI. Instead, we bind
objects within the Eco Space to the UI, thus turning UI
design to a model-driven process as well.
So, from the Object Inspector we select the EcoSpaceType
property, and thereby select the Eco Space that we will
use (see Figure 10). (Theres only one Eco Space in the
application, so its an easy selection process.)

Important: The first thing that must


be done is to compile the application. The ECO run-time platform uses
the compiled information to find
the model information, so its very
important that when you create or
modify a model you recompile your
application, enabling ECO to access
the information contained in the
model. The good news is that this
will be taken care of automatically if
you check Autocompile in Tools | Options
| ECO Options.
Now open the WinForm.pas unit, and
select the ReferenceHandle, the rhRoot
component. The rhRoot component
represents a connection to the Eco
24

Figure 8: Creating the properties for a class.

DELPHI INFORMANT MAGAZINE | February 2004

Lifecycle

Management

Enterprise Core Objects


The OCL expression is used to query
the Eco Space for information (see
Figure 11). If the requested information isnt there, it will fetch the information from the database into the
Eco Space dynamically.
The ExpressionHandle also implements
System.ComponentModel.IListSource,
which means that the values in the
ExpressionHandle can be bound to any
component that uses a DataSource. By
adding a DataGrid to the WinForm,
you can set its DataSource property to
your ehCategories component. Once
thats done, youll have a DataGrid
thats bound to classes defined in your
model. Next, well add a button to the
form, which will be used to add a new
category at run time:

Figure 9: The association names between classes.

procedure TWinForm.Button1_Click(Sender:
System.Object;
e: System.EventArgs);
begin
Category.Create(EcoSpace);
end;

Because were dealing directly with


objects in the Eco Space, all we need
to do is create an instance of Category, and youll see it directly in
the user interface when you run the
application (see Figure 12).

Figure 10: Selecting the Eco Space.

The ExpressionHandle component (found on the ECO tab)


allows us to retrieve any object, its elements, or list of
objects, within the Eco Space. Well drop a single ExpressionHandle component onto our WinForm, and rename it to
ehCategories. Set the components RootHandle property to the
rhRoot component, then enter an Object Constraint Language
(OCL) expression in the Expression property. (OCL is a powerful expression and validation language originally developed
by IBM, and is part of the UML specification.) The value here,
Category.allInstances, is the database equivalent of:
SELECT * FROM Category

25

DELPHI INFORMANT MAGAZINE | February 2004

Our model includes a one-to-many


relationship, which, in the user interface, will be a list of products related
to the current category. A grid has no
such thing as a cursor; instead .NET
provides the concept of a CurrencyManager that keeps track of the current row in a grid. ECO leverages this
in the CurrencyManagerHandle component, which is used to obtain the
current object in an ExpressionHandle
list, based on the CurrencyManager
for a data bound control. So add a
CurrencyManagerHandle component
to the WinForm, rename it to cmhCategories, then set its RootHandle property
to the ExpressionHandle, ehCategories. You then need to set
the CurrencyManagerHandles BindingContext property to the
DataGrid for your categories.
Once thats set, were ready to display the products for
each particular category. Setting this up is very similar to
how we set up the display for the categories. The main
difference is that instead of setting the RootHandle property
of the new ExpressionHandle to rhRoot, you set it to point
to CurrencyManagerHandle. When you click on the ellipsis for the ExpressionProperty of your new list handle, youll
get the OCL expression editor showing the possible OCL

Lifecycle

Management

Enterprise Core Objects

Figure 12: Creating new categories.

Figure 11: Using the OCL Expression property editor to enter the OCL expression.

expression in the context of the roothandle, here a Category. Now you


can just select self.hasProducts, which
was defined in the model earlier (see
Figure 13). Now were selecting the
products based on the selected category in the DataGrid.
Once youve selected to view the
products for the selected category,
youll have the one-to-many relationship shown in your application.
To add a product to the selected
category, we just need to obtain the
selected category in the DataGrid. To
do that, we use CurrencyManagerHandle. Then we can use the hasProducts association for the category
that was created in the model to add
a new product for the current category (see Figure 14).

Figure 13: Selecting the detail products.

You should now be able to run the application, and create categories, and the products for the related categories.
You may notice that the DataGrid for your objects displays all the properties and associations for the classes
(see Figure 15), so you may want to modify the layout of
the DataGrid by modifying the TableStyles property to make
the forms look more presentable.
Making the Changes Persistent
Now that we have the application working, we need to
define how we will store our objects. The ECO framework
makes this extremely simple for us, and provides three
components for persisting the instances of our modeled
objects. These components are PersistenceMapperXML,
PersistenceMapperSqlServer, and PersistenceMapperBdp.
These components allow us to save our objects to an XML
file, a Microsoft SQL Server Database, and a Borland Data
Provider database, respectively.
26

DELPHI INFORMANT MAGAZINE | February 2004

procedure TWinForm.Button2_Click(Sender: System.Object;


e: System.EventArgs);
var
cat: Category;
newProduct: Product;
begin
// Check if there are no selected Categories.
if cmhCategories.Element <> nil then begin
cat := cmhCategories.Element.AsObject as Category;
newProduct := Product.Create(EcoSpace);
cat.hasProducts.Add(newProduct);
end;
end;

Figure 14: Adding a new product using CurrencyManagerHandle.

In the Project Manager for your ECO project, you should


see a file named ProductsAndCategoriesEcoSpace.pas.
Double-click on this tree node to bring up the Eco Space
(see Figure 16). Place either the PersistenceMapperXML,
PersistenceMapperSqlServer, or PersistenceMapperBdp
component on this form. For this example, we will connect
to an InterBase database using the Borland Data Provider.

Lifecycle

Management

Enterprise Core Objects

Super Fast Productivity Tip


The code listings youve seen demonstrate one way of
adding objects to your Eco Space. You will always find it
useful to understand how to obtain a reference to one of
your models objects using the CurrencyManagerHandle,
but there is also a way of adding common functionality,
such as adding an object, without having to write a single
line of code.

Figure 15: The master-detail application at run time.

If you dont have one, create a blank InterBase database


file using whatever InterBase tool youre comfortable
with, e.g. IBConsole, Marathon, etc. Once youve created
your InterBase file, place a BdpConnection component,
and connect it to your newly created database. Now add a
PersistenceMapperBdp to the Eco Space, and set its
Connection property to the BdpConnection component. You
then need to right-click on the PersistenceMapperBdp and
select InterBase dialect 3 setup (again, see Figure 16). The
PersistenceMapperBdp component requires this information to correctly map the classes in your model to the
specific database that its using.

When the default ECO application is created, there are


several extender components placed on your WinForm,
such as EcoActionExtender, EcoListActionExtender, and
EcoAutoFormExtender. These components add new properties to the components on your form to augment their
functionality. In our previous example, once you set up
your CurrencyManagerHandle for the categories, you
could add a button to your form, set the Buttons CurrencyManagerHandle to cmhCategories, and then set the
EcoListAction to Add. This would give you the same functionality as shown in the first code snippet, without writing
a single line of code.
There are other EcoListActions that you can use, such as
Delete, and others for navigating through your expression.
As you can see, by using these extender components,
youll have your application built in next to no time. I told
you ECO was fast.

Glenn Stephens

Once youve placed your


PersistenceMapperBdp
component on the form,
click on the Eco Space and
change its PersistenceMapper
property to point to your
PersistenceMapperBdp
component. With that
done, you can create the
database. At the bottom
of the Eco Space there are
four buttons. The first of
these buttons is the Create
Database button. Click this
button to create database
tables that are designed
specifically for your model.
The last bit of code that
well write for this application saves our changes
to the persistence layer.
Fortunately for us, this
is extremely simple; it
just requires a call to the
EcoSpace.UpdateDatabase
method:
27

Figure 16: Setting up the PersistenceMapperBdp component for InterBase use.

DELPHI INFORMANT MAGAZINE | February 2004

Lifecycle

Management

Enterprise Core Objects

procedure TWinForm.Button3_Click(Sender: System.Object;


e: System.EventArgs);
begin
EcoSpace.UpdateDatabase;
end;

You could also use the ECO extender components to do this


without code, by dropping a button on your WinForm and
setting the buttons EcoAction property to UpdateDatabase.
Thats it! Run your application. You now have a fullfledged model-driven application that persists all changes
to a database.
Conclusion
By now you should have a real appreciation for building MDA solutions with ECO using Delphi 8 for .NET. By
incorporating best-of-breed technologies, such as a full
synchronization between the code and the model, and
the creation of powerful objects built on the ECO framework, you can build quality business applications faster
allowing you to do more with less.
The example project referenced in this article is available
for download on the Delphi Informant Magazine Complete
Works CD located in INFORM\2004\FEB\DI200402GS.

Glenn Stephens designs and develops applications for various platforms, and
has been programming for more than 15 years. He a Borland Certified Consultant, a Microsoft Certified Solution Developer, and is the author of The Tomes
of Kylix: The Linux API. Living in sunny Australia, Glenn spends his spare
time marathon swimming and playing the piano way too loud for his neighbors. Feel free to contact Glenn at glenn@glennstephens.com.au.

28

DELPHI INFORMANT MAGAZINE | February 2004

N E W

&

U S E D

By Robert Leahey

Doc-O-Matic Professional 3.4


An Accountable Documentation Tool

wo years ago, I reviewed a new product named


Doc-O-Matic 1.0 (see the July 2001 issue of
Delphi Informant Magazine). Now Im pleased

erate reports about the state of your documentation project),


and support for JavaDoc and XMLDoc. The entire feature list
is impressive and beyond the scope of this review; I recommend you download the trial version.

to report on the latest version of this tool. So those of


you unfamiliar with this product wont have to search
your back issues, Ill start with a primer.

Doc-O-Matic is a documentation tool with a Java-like


approach: write once, publish to many. This isnt unique in
the documentation tool sector, of course, but Doc-O-Matic
also offers the ability to create documentation directly from
your source code. It can parse your source, be it Delphi,
C++, VB .NET, C#, Java, or IDL, and create topics and
customizable documentation straight from the structure of
the symbols it finds there. It does a better job if your code
is commented, as it can read the comments and add them
to the appropriate symbols in the generated documentation.
You can also easily add topics of your own, resulting in documents that not only contain information about your source
code, but expository topics as well.
Doc-O-Matic Professional will output the generated documentation from a single source to any of the following formats: Acrobat (PDF), WinHelp (HLP), HTML, HTML Help
(CHM), or Microsoft Help 2 (HXS).
Doc-O-Matic offers many features you would expect: It can
automatically generate a glossary, an index, and a table of
contents; the integrated editor offers standard content processing features such as images, colors, tables, lists, and
spell checking, as well as a table of contents designer. There
are also quality assurance features such as the QA view
(which graphically displays how much of your source code
is commented), a reports feature (which allows you to gen29

DELPHI INFORMANT MAGAZINE | February 2004

{ --------------------------------------------------------TtsUnitTestingClass.CompareFiles
Summary
Compares two files and logs the result.
Description
Call CompareFiles to use TestComplete's Files object to
perform a comparison. <p> CompareFiles calls Files.Compare
using aFileName1 and aFileName2 (see the TestComplete
online help for more information on the Files object.) If
Files.Compare returns false, CompareFiles gets the latest
error message from the Files object and posts it as part
of the error message sent to the log.
Note
The aMsg parameter is optional. If it is empty,
CurrentTestMessage is used instead, allowing this test to
be part of a test set (see StartTestSet). The test index is
only incremented if aMsg is empty and CurrentTestMessage is
used as part of the logged message.
Parameters
aFileName1 - a file to be compared; this file can either be
on disk on in the <i>Files</i> storage.
aFileName2 - a 2nd file to be compared.
aMsg - a message to be sent to the TestComplete Log object.
See Also
StartTestSet }
procedure TtsUnitTestingClass.CompareFiles(
const aFileName1, aFileName2, aMsg: string);
begin
...
end;

Figure 1: Source code example showing keywords in comments (modified to fit


magazine format).

New

&

Used

Doc-O-Matic Professional 3.4


Enter Doc-O-Matic. Although Ive
used Doc-O-Matic since version 1.0,
Ive used it primarily for in-house
development documentation, or for
component help files. I wasnt completely satisfied with the level of
control that earlier versions of DocO-Matic afforded me when generating my printed materials. Id much
rather use Quark Express or Adobe
InDesign to have total control of page
layout. However, I was in a tight spot:
I didnt have time to generate online
documents and materials for print. I
am responsible for more than white
papers, so like for most of you
that sort of tweaking is a luxury I
cant afford.

Figure 2: HTML Help output of help topic generated from source code comments in Figure 1. Notice the
automatically generated hot links, and the way the different sections (Parameters, Summary, and Description) are presented.

At the time I reviewed Doc-O-Matic 1.0, I made the distinction that the product was not so much a documentation
authoring tool as it was a documentation generation tool.
This was based on the fact that version 1.0 of Doc-O-Matic
read code and comments from which it generated documentation output. If you wanted to incorporate topics that were not
part of your source code comments, you had to do so using a
hand-written text file containing markup tags. This is no longer the case; Doc-O-Matic is now a full-fledged help-authoring
package. It still features the same ability to generate help topics from code and comments, but it now also offers a built-in
topic editor, which allows you to manage and edit topics
from a variety of sources, including your source code, which
results in a sort of two-way documentation tool.
Before continuing my description of Doc-O-Matic, let me
first explain how Im using the product. My duties at AutomatedQA include writing technical white papers on how
to get more out of our products. The first paper I wrote,
published in Adobes PDF format, is an example of how
best intentions can go astray. As a long-time page layout
designer, I felt strongly enough about how my paper should
be laid-out that I chose to forgo any HTML output; I published only to PDF. Although PDF is an appropriate medium
for Web publication of print materials, the reality is that if
I want my papers to be read, I need an HTML version that
can be viewed online, a PDF version that can be printed,
and possibly even an HTML Help (or WinHelp) version that
can be downloaded.
30

DELPHI INFORMANT MAGAZINE | February 2004

Doc-O-Matic 3.0 had just been


released, and I decided it was time
to see if it provided enough layout
control for my needs. For this review,
I chose to reformat one of my white
papers, entering it into Doc-O-Matic
to find out whether I could customize the generated layout sufficiently. I
knew the generated HTML and WinHelp would be good. I also knew that
the generated PDF wouldnt be exactly the way I wanted it. The question
was, would it be good enough?

Proof Positive
My white papers typically include example code or working classes, and Doc-O-Matics automation capabilities
would enable me to automatically generate the documentation for those classes. It would also automatically link
from my handwritten topics to the appropriate generated
source code symbol topics. As my body of work expands,
I can create standalone papers and a comprehensive tome
containing all of my papers. Each time I regenerate this
comprehensive work, including new material, all possible
relevant links will get added to the output, even in the
older papers that I havent changed. Pretty slick, huh?
One of the great features of Doc-O-Matic is that it automatically generates topics from source code. Doc-O-Matic
will parse any source code files you add to your documentation project and generate all the topics necessary to
fully document all the code symbols it finds. If you add a
Delphi project file (dpr or dpk), Doc-O-Matic will parse all
the units in that project. For instance, if it finds a class, it
will generate a topic for the class, as well as topics for all
the class members. It will create a listing of all the various
class members and generate links to the member topics. If
Doc-O-Matic finds comments that youve associated with
the code symbols, it will attempt to make these comments
the text of the topics it generates (more on this later).
Deciphering Comments
There are other products that serve to generate class

New

&

Used

Doc-O-Matic Professional 3.4

documentation from source code.


However, Doc-O-Matic is the best Ive
seen at avoiding the need to obfuscate your source comments with a
great many formatting tags or special commands. Although there are
certainly a few markup tags you can
use that have a distinct HTML feel to
them, for the most part, Doc-O-Matic
allows you to write your comments
in a human language. For instance,
Doc-O-Matic uses the idea of Sections within comments to delineate
the various parts of a documentation
topic. Sections can be things like a
summary, an author indication, see
also notes, version info, a bug list, a
to-do list, etc.
Each section that Doc-O-Matic detects
in a comment is output according
to your formatting rules. Best of all,
those sections are demarcated by a
keyword list that you can modify.
When Doc-O-Matic detects the keyword Parameters, for example, in
the source code comment shown in
Figure 1, it will create a specially formatted section with a table describing
the given parameters. Thus, as DocO-Matic reads the preceding comment, it will produce (in HTML Help
format) the topic shown in Figure 2.

Figure 3: Doc-O-Matics Symbols and Topics view.

The point here is that if youre not


fond of filling your source comments
with funny markup tags, preferring
to see readable, human text, then
Doc-O-Matic will suit you.
One thing I mentioned earlier was
that Doc-O-Matic can combine
auto-generated topics from source
code, and your custom expository
topics. While doing so, it can also
parse your topic text for references
to source code elements (or other
Figure 4: Doc-O-Matics Configuration view.
topic IDs) and automatically create
links within your output for those
references. The result is that you dont have to go to great ly generate powerful project documentation as a boon to
lengths to create links to your source code topics; with
new programmers and those who maintain code (or any
Doc-O-Matic, its done automatically.
developer for that matter). I know of one large shop that
includes a rebuild of their Doc-O-Matic-maintained inThe additional benefit here is seen in another application
house project documentation every night as part of their
of this tool; bear with me and Ill get to that benefit. Ive
automated build/test/report process. When their programworked with some clients who, while not using Doc-Omers come in each day, they have the results of the latest
Matic for their end-user documentation, have developQA sessions, and the latest documentation for the project.
ment teams who were quite excited by the tool. Doc-OMatic provides a great way to automate and improve inAdditional Benefits
house project documentation. All you really need to do is
Two of the great arguments against large-scale in-house projto implement some amount of standard code commenting
ect documentation are that it takes too much time, and that
(even a minimal amount helps) and you can automaticalit can quickly get out of synch with the actual code. These
31

DELPHI INFORMANT MAGAZINE | February 2004

New

&

Used

Doc-O-Matic Professional 3.4

Just the Facts


Doc-O-Matic is a powerful documentation solution capable
of producing a variety of output formats, Acrobat (PDF),
WinHelp (HLP), HTML, HTML Help (CHM), or Microsoft Help
2 (HXS), from one source. The usability of Doc-O-Matic has
increased over time and, in spite of the many options and
configuration complexity, it is suitable for use by developers
and non-developers alike.
toolsfactory GbR
Heckscherstrasse 42
20253 Hamburg, Germany
Contact: support@toolsfactory.com
Web Site: www.doc-o-matic.com
Price: Doc-O-Matic Professional, US$799; all other editions,
US$399. See www.doc-o-matic.com/purchase.html for more
pricing information.
arguments are moot with a tool like Doc-O-Matic; you get
the best of both worlds the benefits of large-scale project
documentation for your team members with the minimal
effort of simple code commenting. Because Doc-O-Matic reparses your code each time it generates the output, the documentation is always in sync with your current code base.
The applications Ive mentioned so far have all included
source code as a basis for some or all of the generated
documentation. This does not have to be the case. DocO-Matic can, in many ways, compete with standalone
authoring tools where there is no code to parse and no
comments to read. You can use Doc-O-Matic to create
standard, non-code related, end-user documentation. In
fact, one of the Doc-O-Matic editions is primarily for that
purpose: Doc-O-Matic for Authoring. See the Doc-O-Matic
Web site for a description of the various editions.
Doc-O-Matic offers a variety of conveniences and productivity tools. The Info page and New Project Wizard are great
for getting started, as well as for project organization. The
QA view (discussed in more detail in my first review of
this product in the July 2001 issue of Delphi Informant) is
a great way to see, at a glance, the level of documentation
coverage in your source code; the various code elements are
depicted as colored dots, indicating clearly what code has
been documented.

32

DELPHI INFORMANT MAGAZINE | February 2004

The Symbols and Topics view (see Figure 3) demonstrates


an integration of automatically generated source code topics (classes, members, types, etc.) and custom topics. This
is where I spend a lot of time when creating white papers.
You can see in the screen capture the topics that were automatically created by parsing the code and then populated
from the source code comments. Above them in the tree are
custom expository topics written for the discussion portion
of the paper.
So what was my evaluation after porting my white paper
over to Doc-O-Matic? I found that the level of customization
for printed output in version 3 is high enough to allow me to
accomplish the task, so Ill be generating the rest of my papers
with this tool. Granted, the PDF output isnt what I would have
created manually; there are lowest-common-denominator limitations that result from the one-source-to-many-outputs approach,
but it is good enough for me for these papers (and Im overly
picky; for most people the output will be great). Again, see the
sample output at the tech paper section of the AutomatedQA
site (www.automatedqa.com/techpapers/index.asp).
Be forewarned: the Configuration view (see Figure 4) is
complex. I think toolsfactory has done a good job of making
the vast number of available options as manageable as possible. But as you can see, there are an amazing number of
options in setting up a project. This can be daunting to new
or infrequent users; make sure you take advantage of the
Display Help for this Page button.
Conclusion
Doc-O-Matic Professional 3.4 is a powerful documentation
solution with many possible uses. Given its one-source-tomany-outputs nature, the amount of customization available
is considerable. The usability of Doc-O-Matic has increased
over time and, in spite of the many options and configuration complexity, it is suitable for use by developers and nondevelopers alike. I recommend it heartily.

Robert Leahey is Director of Developer Relations for AutomatedQA Corp, and


has been developing since discovering AppleBASIC on his Apple II+ 25 years
ago. He is currently pursuing his Ph.D. in music theory, and has published
articles on Delphi, development, music theory, and life in general. He currently
lives in North Texas with his wife and daughters. You can reach Robert at
robertl@automatedqa.com.

N E W

&

U S E D

By Bill Todd

FIBPlus
Native Components for InterBase and Firebird

orland provides the InterBase Express (IBX)


components as part of Delphi. So why pay for a
third-party component suite? One reason is that

FIBPlus (Fast InterBase Plus) offers many features that


IBX does not (read on to learn what they are). A second reason is that if you are using (or thinking about
using) IBX with Firebird, you should think again.

Although people are successfully using IBX with Firebird


today, they may not be able to in the future. IBX isnt tested
against Firebird, and Borland has no plans to maintain compatibility with future versions of Firebird. As the Firebird
and InterBase developers enhance the two products in different ways, the APIs are nearly certain to become incompatible. In my opinion, if youre using IBX with Firebird, the
question isnt if youre going to have to change to another
component set,
but when. On the
other hand, the
developers of FIBPlus are committed to maintaining compatibility
with both InterBase and Firebird,
so moving your
applications to
future versions of
Firebird should
be easy if you use
FIBPlus.
Figure 1: The sample data module.

33

DELPHI INFORMANT MAGAZINE | February 2004

What Sets FIBPlus Apart


You can see one of the unique features of FIBPlus in a
simple sample application. Figure 1 shows the data module
that contains a FIBDatabase, two FIBTransaction components, two FIBDataSets, and two DataSources. Figure 2
shows the Object Inspector with one of the FIBDataSets
selected. Notice that there is a Transaction property and an
UpdateTransaction property.
One of the challenges in working with InterBase has been
deciding when to commit transactions. All database access,
including SELECTs, takes place within a transaction. When
you commit your transaction to make changes permanent,
the dataset components that use that transaction close and
the user can no longer see any data. You have to start a new
transaction and reopen the datasets to continue.
Using separate transactions for reading and updating the
data lets you commit changes without having the dataset
closed. This works particularly well with InterBase 7.1,
because you can make the read transaction read-committed
and read-only and that means the transaction can stay
open forever with no impact on performance.
The FIBDataSet component lets you specify SQL statements
for selecting, inserting, updating, and deleting records. Once
youve entered the SELECT statement, you can use the component editor to generate the other SQL statements automatically. You can add FIBUpdateSQL components and connect
them to the FIBDataSet if your SELECT includes a join, and
you need to update more than one table. Each FIBUpdateSQL
component lets you add one SQL statement and set it to fire
when the FIBDataSet processes an update, delete, or insert.
This lets you execute any number of SQL statements when a
record is inserted, updated, or deleted in a FIBDataSet. You

New

&

Used

FIBPlus

Figure 3: The Data Repository editor.

Figure 2: The properties of the EmpDataSet component.

can also make the


FIBUpdateSQL
components active
or inactive at any
time. This lets you
use a UNION in
your SELECT and
then control which
update statement
is executed, based
on from which
table the current
record came.

The FIBPlus repository is another unique feature that lets you


save dataset and field properties in your database, without
having to write code. The properties are automatically loaded
at run time. This lets you change any of the stored properties
without having to recompile your application. The field properties that are stored are DisplayLabel, Visible, DisplayFormat,
EditFormat, and DisplayWidth. For the FIBDataSet, the properties stored in the repository are SelectSQL, InsertSQL,
UpdateSQL, DeleteSQL, RefreshSQL, GeneratorName,
KeyFields, UpdateTablename, UpdateOnlyModifiedFields,
and Conditions.
Using the repository is a snap. To store field properties,
simply right-click a FIBDatabase component and choose Edit
Field Information Table from the context menu. If your database
doesnt contain the FIB$FIELDS_INFO table, youll be asked
if it should be created. The property editor shown in Figure
3 appears once the table has been created. Just double-click
a table to enter all of its fields, then edit the properties in
the grid. To save a FIBDataSets properties, right-click the
dataset and choose Save to DataSets Repository Table from the
context menu. You will be asked if its ok to create the
FIB$DATASETS_INFO table if it doesnt exist. To edit the
save properties, right-click the FIBDataSet and pick Choose
From DataSets Repository Table from the menu.
34

DELPHI INFORMANT MAGAZINE | February 2004

You can also add custom columns to the repository tables to


store additional information. Suppose you need to display
column labels in English, French, and Spanish. Start by altering the FIB$FIELDS_INFO table by adding FRENCH_LABEL
and SPANISH_LABEL columns. All you have to do is add an
OnAfterOpen event handler to each FIBDataSet with the code
shown in Figure 4. This code assumes that the user picks the
language from a ComboBox.
Although parameterized SQL statements make changing the
values in the WHERE clause easy, changing a table name or
column name at run time is not as convenient. You can replace
the entire SQL statement by assigning a new value to the
appropriate property, but that means having multiple copies
of the same statement, except for the table or column name,
in your code. If you need to change the statement, you must
be careful to change all versions. The second alternative is to
enter the SQL statement so that each table or column name
you need to replace is on a line by itself. However, that means
that changing a value leads to code like:
EmpDataSet.SelectSQL[3] := 'Employee';

which means that if you need to change the SQL statement you
must be very careful to keep the items that must be replaced
on the same line or your code will not work. FIBPlus solves
this problem by letting you write statements such as this:
SELECT * FROM @TABLE_NAME WHERE DEPT = :DEPT

In this example, @TABLE_NAME is a macro that can be


replaced with a value at run time using the ParamByName
method, in exactly the same way you would use ParamByName
to assign a value to the :DEPT parameter. Using macros simplifies your code and makes maintenance much easier. FIBPlus
also makes dealing with null parameters easy. If you set a
parameter in a parameterized SQL statement to null, FIBPlus
will automatically change the WHERE clause from SOME_FIELD
= :SOME_PARAMETER to SOME_FIELD IS NULL.

New

&

Used

FIBPlus

procedure TMainDm.EmpDataSetAfterOpen(DataSet: TDataSet);


var
I: Integer;
S: string;
begin
with DataSet do
for I := 0 to (FieldCount - 1) do begin
case ComboBox1.ItemIndex of
1 : Dl := GetOtherFieldInfo(
Fields[I], 'SPANISH_LABEL');
2 : Dl := GetOtherFieldInfo(
Fields[I], 'FRENCH_LABEL');
else
Dl := GetOtherFieldInfo(
Fields[I], 'DISPLAY_LABEL');
end;
if Dl <> '' then
Fields[I].DisplayLabel := Dl;
end;
end;

Figure 4: Loading custom display labels from the repository.

Component

Description

pFIBDatabase

A connection to a database.

pFIBDataSet

A dataset in a database.

pFIBTransaction

A transaction.

pFIBQuery

A lightweight component for executing


SQL in code.

pFIBStoredProc

Call a non-selectable stored procedure.

pFIBUpdateObject

Lets you execute multiple SQL statements


when user inserts, updates, or deletes a
row in a FIBDataSet.

DataSetsContainer

Centralizes processing of dataset events.

pFIBErrorHandler

Centralizes processing of errors.

pFIBStatistic

Accumulates statistics about query execution.

SibFIBEventAlerter

Triggers an event when an InterBase event


is raised.

FIBSQLMonitor

Shows SQL set to the InterBase server.

Figure 6: The FIBPlus components.


V := JobDataSet.FieldByName('LANGUAGE_REQ').Value;
for I := VarArrayLowBound(V,1) to VarArrayHighBound(V,1) do
if (not VarIsNull(V[I])) then
ArrayListBox.Items.Add(V[I]);

Figure 5: Using an array field.

If you need to change the WHERE clause of your SQL statement at run time, use the FIBDataSets Conditions property.
The property editor lets you enter as many conditions as
you wish, with a name for each condition. At run time, just
set the conditions Enabled property to True to use it in the
WHERE clause. You can enable more than one condition
and the conditions will be logically anded together.
FIBPlus includes two unique components that let you centralize code. The first is DataSetsContainer. The FIBDataSet has
a Container property that can be set to a DataSetsContainer
component. When it is, all the FIBDataSets events are sent to
the DataSetsContainer component first. After the code in the
DataSetsContainers OnDataSetEvent event handler executes,
the event handler of the FIBDataSet component will execute.
The DataSetsContainers OnDataSetEvent event handler gets
two parameters. The first is the dataset that triggered the
event and the second identifies the event. If you need to
handle several events for each dataset, you will want to code
the OnDataSetEvent handler as a switch statement that calls
a custom method to handle each event type. Otherwise, the
OnDataSetEvent event handler would become very long.
The FIBErrorHandler component provides the same
functionality for database errors. It lets you write an
OnFIBErrorEvent handler that handles all exceptions
that arent caught by try..except blocks in your code.
Although InterBase supports array fields, Borland has
never produced a set of data access components that provide access to array field values. FIBPlus provides complete support for array fields by treating them as a variant
array of variants. Just assign the Value property of the
array field object to a variant variable, and manipulate it
as you would any variant array. Figure 5 shows a code
35

DELPHI INFORMANT MAGAZINE | February 2004

Component

Description

pFIBServerProperties

Returns server configuration information.

pFIBConfigService

Returns or sets configuration parameters,


including sweep interval, async mode,
page buffer size, and access mode. Allows
shutting down and restarting a database
and activating a database shadow.

pFIBLicensingService

Enter license certificates and keys.

pFIBLogService

Read the log file.

pFIBStatisticalService

View database statistics including OIT,


OAT, and next transaction.

pFIBBackupService

Back up a database.

pFIBRestoreService

Restore a database.

pFIBValidationService

Validate or repair a database.

pFIBSecurityService

Add, delete, and modify users.

pFIBInstall

Install InterBase or Firebird.

pFIBUninstall

Uninstall InterBase or Firebird.

Figure 7: The FIBPlusServices components.

snippet that adds the values of the LANGUAGES_REC


field from the JOB table in the sample employee database
to a ListBox component.
Another great feature of the FIBDataSet component is its
ability to sort its result set in local memory. This lets you
change the sort order for the records without having to
change the ORDER BY clause of the SelectSQL property
and re-query the server.
The FIBPlus Components
The FIBPlus components are presented on two tabs on
the Component palette. The table in Figure 6 lists the
components on the FIBPlus tab. Note that FIBPlus does
not include any BDE migration components. There are
no components designed to be analogous in properties,

New

&

Used

FIBPlus

Just the Facts


FIBPlus is a set of native Delphi, C++Builder, and Kylix
components that provide access to all the features of the
InterBase and Firebird database servers. The FIBPlus components use direct API calls for maximum performance and
the FIBDataSet component is a TDataSet descendant for
compatibility with Delphi, C++Builder, Kylix, and third-party
data aware controls.
Devrace Software Development
Phone: +78452444682 (sales)
E-Mail: sales@devrace.com
Web Site: www.devrace.com
Price: 199.00. Site license 989.00. Volume discounts
available.
methods, and events to Table and Query. Instead, FIBPlus
provides just two data access components, FIBDataSet
and FIBQuery, both of which are SQL based. This might
seem like a disadvantage. It isnt however, because it forces anyone porting an application from Paradox, dBASE, or
any other file server database to convert all dataset components to use SQL. That may be a bit more work, but
the converted application will perform much better than
it would using pseudo-table components.
The table in Figure 7 lists the components on the FIBPlusServices tab. These components provide access to the services API
introduced in InterBase 6. Using these components you can
perform virtually all the functions that are available through
the InterBase and Firebird command-line utilities.
Conclusion
FIBPlus is a great choice if youre going to work with
InterBase and/or Firebird. The components let you easily
use all the features of both databases in your applications. The option to use separate transactions for reading
and updating data is particularly valuable with InterBase
7.1, because it lets you keep datasets open for any length
of time without worrying about performance degradation
caused by long-running transactions. FIBPlus makes using
array fields easy by treating them as variant arrays. Macros make modifying SQL statements in code easy. And
the ability to sort a result set in memory without having
to re-execute the query lets you provide flexible views of
data with minimum network traffic and server load. FIBPlus will make your InterBase and Firebird development
easier than ever before.

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 also an internationally known
trainer and frequent speaker at Borland Developer Conferences in the United
States and Europe. Readers may reach him at btarticle@dbginc.com.
36

DELPHI INFORMANT MAGAZINE | February 2004

F I L E

N E W

Delphi on the Web 2004

By Alan C. Moore, Ph.D.

elphis presence on the Web is in many ways a


barometer of its status and level of maturity. The
initial excitement from the early days of Delphi has
passed, and many of the older Web sites are gone (one of
my goals is to save you the grief of performing an Internet search that produces a plethora of obsolete links). But
with Delphis deepening maturity and its constant commitment to support cutting edge technologies, the sites
that remain are excellent and reflective of that maturity.
Well begin with the essentials those sites that each of
us should consider adding to our Favorites list because
they boast a wealth of Delphi information and resources.
Then well examine some old (but useful) sites, as well as
a few new and improved sites. By the way, the sites I list
in this article are all English-language; however, given the
international popularity of Delphi, there are many Delphi
sites in other languages.
The essential sites. Any list of essential Delphi sites
must begin with the Borland Community Network
(http://community.borland.com/delphi). On the initial
log-in page youll see the latest topics, and there are some
hot ones there! You can access the main features once
you sign in and everyone reading this needs to register on this site if you havent already done so. The main
features include Code Central, a repository of source
code contributed by members that includes full projects,
components, models, patterns, and so on; Quality Central, a Web Services-based section that supports problem
reporting and allows feature requests; The Coad Letter,
which has reports dealing with modern approaches to
development such as Modeling and Design, Agile Management, Strategy, Process, and Test-driven Development;
and more.
The Delphi Super Page at http://delphi.icm.edu.pl remains a
major essential site. Its difficult to imagine a site with more
Delphi components and resources. The other major site,
Torrys Delphi Pages (www.torry.net) is also alive and well.
37

DELPHI INFORMANT MAGAZINE | February 2004

I especially like the manner in which the Sites page is organized according to programming language.
With over 1,300 Delphi/Kylix projects, SourceForge
(http://sourceforge.net) has become an essential source
of information and downloads for those who use opensource materials. This is the place where youll find most
of the projects under Project JEDI, all of the libraries
that TurboPower open sourced, GExperts, and more. See
my last column on open source (in the September 2003
issue) for more details, especially regarding TurboPower.
Youll find many projects related to common programming
areas, such as Web, database, and game development. To
quickly find projects in specific areas of interest, I recommend searching on Delphi and the particular topic.
Old, new, and improved. While the sites we just reviewed
are essential, there are many others old and new
worth visiting. In particular is Richeys Delphi-Box
(http://inner-smile.com/delphi5.phtml). The book review
section is better than most Ive seen, and I especially recommend the Resources page. I found several useful items that I
downloaded and about which you may be hearing more from
me in the coming months.
Many once venerable Delphi sites have languished
into obsolescence. One example is the City Zoo
(www.mindspring.com/~cityzoo/cityzoo.html) which
hasnt been updated since 1996 and is mainly limited to
information on Delphi 1. In contrast, www.delphi32.com
is up to date and strong on educational resources, with
articles, bug reports, a comprehensive series of book
reviews, and excellent Kylix coverage.
Another growing site with more current information is the
Delphi section of About.com that I mentioned last month
(http://delphi.about.com). One of the richest Delphi sites Ive
seen, it includes many interesting articles, including some on
usual topics. With its tutorial, this site is a must for newer
Delphi developers. There is a wonderful reference on the RTL

File

New

(run-time library), with convenient links to the main subcategories such as arithmetic routines, character manipulation
routines, date/time routines, various file-related categories,
string categories, and much more.
If I had to pick a most improved Delphi site, it would
be Marco Cantus at www.marcocantu.com. Youll find
all the code for Mastering Delphi 7 (see my review in
the July 2003 issue of this magazine) and many of his
other books. There are a couple of free Delphi books you
can download as PDF files, and chapters from some of
his older books, including Delphi Developers Handbook.
Chapter 15 of that important work (which is no longer in
print), Other Delphi Extensions, includes discussions of
such advanced topics as Delphi Notifications, the Tools
API, and Hacking the Delphi Environment. Although
some of the information in this book is now out of date,
much is still useful; I hope that Marco will find some way
to make more of this information available in the future.
One page on the site deserves special mention. If youre like
me and sometimes work on a project for many hours in a
row and need to take a break, go to Marcos Fun, Info and
Humor page. There youll find an excellent history of Delphi
from one of the gurus who was there at the beginning. You
can revisit Marcos legendary Fun Side of Delphi by downloading code that demonstrates Writing Useless Components
in Delphi. There are also links to other humor pages, such
as the article How to Write Unmaintainable Code!
Speaking of Delphi gurus, Bob Swarts Delphi 7 Clinic
(www.drbob42.com/delphi7) is also worth a regular visit.
Youll find interesting information here on the latest technologies and Delphi personalities. Another guru, Ray Lis-

38

DELPHI INFORMANT MAGAZINE | February 2004

chner, has a site devoted mainly to his books. On a recent


visit I discovered an article I had not read before on the
Open Tools API (www.tempest-sw.com/opentools).
Ill conclude with a couple of links sites devoted to Delphi.
Of course, many of the sites weve discussed so far have fine
links pages, but these sites specialize in links. Jazar Top 200
Delphi Sites (www.top200.jazarsoft.com/delphi) has links
to 173 sites; most are in English, but some are in other languages. Cetus links (www.cetus-links.org/oo_delphi.html)
is a very well organized links site, with categories such as
Search sites, Tutorials, FAQs, Newsgroups, and of course,
more links sites, some in other languages (such as French
and German). But be warned: Many of the links dont work.
This month I have concentrated on what I consider to be the
most important sites. But I know there are other lesser known
sites out there, off the beaten track. If you know of such sites,
please let me know. I hope to write about such sites later in
the year. Until next time.

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


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

Anda mungkin juga menyukai