0% found this document useful (0 votes)
22 views49 pages

Object Pascal: The Language

This document is the November 1995 issue of the Delphi Informant magazine. It includes articles on code reuse using inheritance and polymorphism, robust language features in Object Pascal like subranges and enumerated types, a comparison of the cultural differences between C++ and Object Pascal, an introduction to using the DBNavigator component, and reviews of books and products related to Delphi development. The issue aims to help developers transitioning to Delphi from backgrounds in Pascal, C/C++, Visual Basic, and other languages while fostering a supportive community atmosphere.

Uploaded by

reader-647470
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
22 views49 pages

Object Pascal: The Language

This document is the November 1995 issue of the Delphi Informant magazine. It includes articles on code reuse using inheritance and polymorphism, robust language features in Object Pascal like subranges and enumerated types, a comparison of the cultural differences between C++ and Object Pascal, an introduction to using the DBNavigator component, and reviews of books and products related to Delphi development. The issue aims to help developers transitioning to Delphi from backgrounds in Pascal, C/C++, Visual Basic, and other languages while fostering a supportive community atmosphere.

Uploaded by

reader-647470
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 49

November 1995 - Volume 1, Number 7

Object Pascal
the Language
Comparisons and Reveries

Cover Art By: Michael Tanamachi

ON THE COVER
8 Think Objects, Not Reuse — Richard Wagner 30 Visual Programming — Douglas Horn
Code reuse is talked about a great deal, but seldom put Delphi’s ObjectBrowser can provide unparalleled insight into
into practice. Mr Wagner gets this month’s issue off to a the inner workings of Delphi and Windows. Unfortunately,
quick start by describing the contradictory disciplines of its use is next-to-undocumented. This month, Mr Horn helps
rapid application development and code reuse. He then reveal the ObjectBrowser for the incredibly useful instrument
goes on to resolve this dilemma through the use of inheri- that it is. It’s a comprehensive introduction and visual tour
tance and polymorphism. And manages to make it simple! of a tool you should become familiar with.
13 Power and Safety — John O’Connell 34 Informant Spotlight — Tom Costanza
Using Delphi’s powerful new Object Pascal language, we The issues and protocols of serial communications are nearly
can create object-oriented programs that go head-to-head as old as computers. In fact, in many respects, little has
with anything created in C++. But Mr O’Connell wants us changed. And when Delphi is added to the mix, an interest-
to slow down a bit and appreciate some robust language ing juxtaposition of old and new is created. From the middle
features that Pascal has had since its inception: subranges, of it all, Mr Costanza provides us with an outstanding intro-
enumerated types, and sets. duction to serial communications and a Delphi implementa-
tion.
21 Cultural Differences — Richard Holmes
C++ and Object Pascal have a lot in common. For exam- REVIEWS
ple, they’re both OO hybrids of classic 3GL languages. And
when it comes to raw power and capability, there is also 42 RAD Pack for Delphi — Product review by Tim Feldman
little to separate them. Yet there are some important dif- Shortly after shipping Delphi, Borland issued an accompanying
ferences as well. Mr Holmes dissects the two languages “RAD Pack” product. But just what is the RAD Pack? What
and provides us with an extraordinarily detailed — and does it contain? And what about the quality of those contents?
fascinating — comparison. It’s not perfect, as Mr Feldman explains, but may contain
some key tools for your Delphi development environment.
FEATURES
47 Delphi Developer’s Guide
26 DBNavigator — Cary Jensen, Ph.D. Book review by Tim Feldman
You’ve probably used the Table, DataSource, and Query 48 Mastering Delphi
components extensively (especially if you’ve followed this Book review by Larry Clark
column). But what about the BatchMove component that 48 Delphi: A Developer’s Guide
shares the same Data Access page on the Component Book review by Richard Wagner
Palette? Chances are you haven’t touched it — until now.
In this month’s DBNavigator, Dr Jensen shows us the many DEPARTMENTS
important tasks BatchMove can perform. 2 Editorial
4 Delphi Tools
6 Newsline

NOVEMBER 1995 Delphi INFORMANT ▲ 1


Symposium

“I never think of the future. It comes soon enough.”


— Albert Einstein

s we move too quickly into Camus’ cool breeze from the future, I thought it might be a good idea to
A revisit some recurring themes surrounding Delphi Informant and its readers. With due respect to Dr
Einstein, I’d like to keep us in sync. And that necessitates some planning, no matter how rudimentary.

So who reads DI? You come from munity,” but it’s the first time I’ve been I’m not coming over from VB — never
diverse programming backgrounds — struck by it. To observe that our profes- went there. I am using C++.
most notably Pascal, C/C++, Visual sion changes quickly is passé, itself an Make sure that as far as possible,
Basic, and Paradox for Windows. This indication of just how quickly things are and appropriate, each article leaves
letter is from a VB programmer: moving. Still, it’s remarkable that there us with real, self-contained, working
is already a genuine community for this examples. ...
Dear Editor; young product. The Borland and This is the most expensive program-
One of the great things about Visual Informant CompuServe forums (GO ming magazine I subscribe to. I hope
Basic is the attitude of the authors and DELPHI and GO ICGFORUM I resubscribe. That will depend on
programmers; There is none of the respectively) are evidence. And I heartily how I perceive its value, i.e. how
‘I’m smarter than the idiot that agree, Dennis — let’s keep it friendly. much I learn from it. I certainly hope
wrote...’ letters that we see so often in Then there’s your artful punctuation — Delphi is a real success and I hope
the C++ magazines; When a VB too clever by half Mr Pipes. your magazine is too.
author publishes stupid code, the Regards, Fred Browne
other authors correct it with ‘That’s Having shared the “snake pit” com-
great, but maybe you should do it this ment, I hasten to add that those from Thanks for the great letter Fred. Your
way...”; I hope {and I am sure others the C++ community I’ve run across good wishes are very much appreciated
will join me} that the Delphi commu- have been perfectly civil, thank you. and I hope we merit your patronage.
nity will continue with this supportive Take for example, this letter from
attitude; I thank your magazine for down under: Change and its pace are also ineluctable
helping me make the transition from themes of this business. And with the
VB to Delphi; The only hard part has Dear Mr Coffey: development landscape changing so
been to remember to end each state- ... Do we need more articles that rapidly, it’s vital that DI be responsive
ment with a damned semicolon; address Object Pascal basics? and continue to serve your interests.
Regards; Probably; I’d appreciate something What I’m hearing from you to-date is
Dennis Pipes; above the ‘elementary’ level that fills “So far, so good,” but keep the com-
the big gap Borland left in explaining ments coming. This message from Mr
Yes, thankfully, I’ve yet to see the kind their component hierarchy. That may Rice is representative:
of acrimony that can become the “per- be in their Component Writer’s Guide,
sonality” of a programming language but I haven’t been able to get my Dear Jerry:
community. (A friend of mine once hands on a copy yet!! ... in reply to your appeal for what
described a C++ forum he frequented as Do we want fewer database related arti- we would like to see in the
a “snake pit.”) And there’s that word — cles? YES! although a couple on inter- Informant, for my money, you’re
community. This may not be the first facing Delphi to dBASE and C++ would already right on track. ... For the rest
time I’ve seen the phrase “Delphi com- be welcome. ... of us who slog out commercial code

NOVEMBER 1995 Delphi INFORMANT ▲ 2


Symposium

for a living, the salient points of your consider my subscription an invest- of Windows 95 and SQL 4.21. In
magazine come through loud and ment in your efforts! the last week, we have finalized our
clear. Much more of a beginner’s Paul Jordan installations with the production
bent, and you would lose some of us. release of Win95 and SQL 6.0 run-
However, the same goes for the Thank you Paul! You have succinctly ning on a networked NT server. Our
other (guru) extreme. Most of us described Delphi Informant’s raison machines are Pentium/60s with 2MB
who are using Delphi are new to d’être. Surveys have shown us that most of video RAM (DFI boards) and
the product (but not necessarily Paradox Informant readers keep their 16MB of on-board RAM. A little
OOP) because it just hasn’t been on magazines indefinitely and use them as slow, but what the hell, right?
the market long enough to produce reference. Our goal is to achieve the
many experts ... same with DI. Nobody likes a braggart Mr Rice. <g>
Sincerely, By the way, I’m writing this fabulous
David L. Rice And now to one of my favorite topics piece of editorial on a Pentium/100 I
— books. This month’s issue closes with inherited from a guy in production. But
Thanks for the words of encouragement three book reviews that I’ve been impa- I digress. The point is that this type of
David. We’ll continue to carefully ply a tient to read, and to share with you. information is valuable to me; it lets me
course between the neophyte and guru Unfortunately it takes months to get know where you are on the great soft-
extremes. these reviews into your hands. I’ve been ware bell curve and helps me determine
especially impatient since, as Tim the article mix. It appears David is out
And here’s a letter that made my week: Feldman mentions in his review of toward the bleeding edge. He also
Pacheco and Teixeira’s Delphi Developer’s shared his opinions regarding some pre-
Jerry: Guide [Sams, 1995], we’re now well into vious letter writers, which, in the inter-
As a long time Paradox Informant the “second wave” of third-party Delphi est of keeping things friendly (see
subscriber and new DI subscriber, I've guides; books that took longer to get to above), I’ll keep to myself. However, I
grown accustomed to the layout, press, but are more comprehensive and got a kick out of them David, and
style and content of the Informant offer deeper insights into the product. thank you very much for writing.
magazines. One thing is clear with The two other books reviewed in this
regard to the question of technical issue are Marco Cantù’s Mastering Which brings us to the aforemen-
content -- if you can't use it or com- Delphi [Sybex, 1995], and Todd and tioned questions. With Delphi32 in
pletely understand it today, give Kellen’s Delphi: A Developer’s Guide the wings, where do you see yourself
yourself some time in the Delphi [M&T, 1995]. or your programming shop headed
environment then re-read the arti- vis-à-vis Windows 95? Like Mr Rice,
cles. I've found at first pass I might These are three of what I think are the do you already have Windows 95 up
be interested in using (or bothering five must-have Delphi books available as and running? Or is it in your short-
to understand) snippets from 25-50% of this early October writing. The oth- term plans? Or is it a year off? And
of the content, but on second pass ers are Neil Rubenking’s Delphi for most important, do you have clients
(after heading up the learning curve) Dummies [IDG, 1995], and Charlie clamoring for Windows 95 applica-
I end up "stealing" a good 80% or Calvert’s Delphi Unleashed [Sams, tions? Let me know what’s going on in
more of the ideas presented. 1995]. These are the texts I return to your part of the world and I’ll share
again and again for general reference the results in this forum.
In what amounts to a one-person and to resolve specific programming
programming shop, the Informant challenges. Until next time, thank you for reading.
magazines and CompuServe forums
have "saved me" many times over, I’d like to sign off with a new topic and
either from going down a dead-end some questions for you. Here’s another
path or allowing me to develop that portion of that letter from David Rice Jerry Coffey, Editor-in-Chief
much faster. As well, I've taken the (dated August 25):
time to contact the authors (giving CompuServe: 70304,3633
fair opportunity to ignore me if too My shop has been utilizing Delphi Internet: [email protected]
busy) to discuss/trade thoughts -- all- Client/Server for some months now, Fax: 916-686-8497
in-all, a very helpful, understanding and have, in the last three weeks, Snail: 10519 E. Stockton Blvd., Ste.
group. Thanks for a fine magazine -- coupled it with the June Test Release 142, Elk Grove, CA 95624

NOVEMBER 1995 Delphi INFORMANT ▲ 3


Delphi New VB Translator for Delphi
Eagle Research of San VB2D Professional Edition US$150. Both versions include an uncon-
T O O L S Francisco, CA is shipping also creates detailed analyses ditional 30-day, money-back guarantee.
VB2D, its new Visual Basic of VB and Delphi projects,
New Products (VB) to Delphi translator. including cross-references for Contact: Eagle Research, Inc., 360 Ritch
and Solutions VB2D converts 90 to 100 per- variables, procedures, func- Street, Suite 300, San Francisco, CA
cent of a VB software applica- tions, and object properties 94107
tion to Delphi. and methods. The source
VB2D handles variants, code for all added program Phone: (415) 495-3136
control, form and re-dimen- components is included with
sionable arrays, precedence the Professional Edition. Fax: (415) 495-3638
adjustments, gotos, gosubs,
type-1 VBXes, and virtually Price: VB2D Professional Edition, E-Mail: Internet: [email protected]
all intrinsic VB functions. US$450; VB2D Standard Edition, com.com
VB2D Standard Edition
includes a diagnostic report
Delphi and Object Pascal
listing all project files, insert-
Training in USA & Asia ed typecases, precedence
The first Borland Training Center
adjustments, renamed vari-
in the Connections Program, ables and procedures, substi-
GenoTechs, Inc., is providing tuted functions and classes,
Delphi and Object Pascal training
internationally (i.e. Singapore, and detailed diagnostic mes-
Indonesia, Malaysia, Thailand, sages cross-referenced to
India, and Hong Kong).
Developers can first learn the tool, source code line numbers.
OOP, and Pascal concepts in the VB2D is designed for
Delphi course, then proceed to
more advanced language method- developers managing the
ology in the Object Pascal course. translation and validation of
The training is hands-on.
On-site training is available, or medium to large systems. It
users can attend a monthly five- creates a side-by-side listing
day course in Phoenix, AZ. The
Delphi Developer and Object of VB programs with the
Pascal in Delphi courses each start resulting Delphi code. The
at US$1340 (in Phoenix), and
US$1440 (on-site). Discounts
apply for consecutive courses. For
information or to register, contact
ReportPrinter Version 1.1 for Delphi Released
GenoTechs, Inc. at (800) GENO- Nevrona Designs of extra files, such as DLLs or accessed from within Delphi.
TEX; (602) 438-8647; or e-mail at
[email protected]. Chandler, AZ has released VBXes. Therefore a separate Using ReportPrinter’s class
ReportPrinter version 1.1, a installation program isn’t nec- library, professional-looking
suite of native Delphi compo- essary, and only 25 to 50K is reports are created in Delphi
nents that allow programmers added to the executable’s size. with minimal coding.
to create reports compiled into ReportPrinter features memo Nevrona Designs will soon
applications without requiring field or text stream printing release an enhanced version
with automatic word wrap- of ReportPrinter with a visu-
ping, justified text, boxes al interface and added func-
around text for table style list- tionality.
ings, shaded fields or lines,
and snaking columns. It also Price: US$99 (includes complete source
supports custom paper sizes, and printed documentation).
graphics, scaling, precise page
positioning for pre-printed Contact: Nevrona Designs, 2581 E.
Commonwealth Circle, Chandler, AZ
forms, direct printer output,
85225-6019
printing to file, as well as stan-
dard or metric measurements. Phone: (602) 899-0794
ReportPrinter offers print pre-
view with zooming, panning, Fax: (602) 530-4823
and print-after-preview. It can
be used without a database, or is E-Mail: CIS: 70711,2020 or
compatible with a database Internet: [email protected]

NOVEMBER 1995 Delphi INFORMANT ▲ 4


Delphi SuccessWare’s Apollo Pro Adds SDM to Apollo
SuccessWare International of file locking is compatible with
T O O L S
Temecula, CA has released existing FoxPro and Clipper
Apollo Pro 1.0, which adds a applications. Apollo supports
New Products
Source-code Documentation CA-Clipper (NTX), FoxPro
and Solutions
Module (SDM) and a cus- 2.x (IDX/CDX), and HiPer-
tomized version of Nevrona’s SIx (NSX) systems.
ReportPrinter to the standard Apollo’s new features include
version of Apollo. Following Conditional Indexes, Index
Borland’s lead with their RAD SCOPES, and Record-level
Pack product, the Apollo SDM Data Encryption. Also integrat-
is a VCL source file that can’t ed into the RDE is MachSIx,
be compiled; it is supplied for SuccessWare’s integrated query-
educational purposes only. optimizer that increases database
Apollo’s Replaceable retrieval performance.
Database Engine (RDE) tech- Apollo is royalty-free and
Starfish Announces nology allows for record-based includes 30 days of free
Dashboard 95 (Xbase) data-table navigation voice, BBS, Fax, or
Starfish Software has announced and management syntax dur- CompuServe technical sup-
Dashboard 95, an upgraded 32- ing program development, port. A demonstration ver-
bit version of the popular utility.
Dashboard provides a graphical with minimal concern for the sion of Apollo is available for Phone: (800) 683-1657 or
front-end that operates consistently database format. A “no-code” immediate shipping. (909) 699-9657
across all three primary Windows
platforms: Windows 3.1, Windows replacement for the BDE sys-
95, and Windows NT. It features a tem, Apollo can be installed Price: Apollo Pro, US$239. Registered Fax: (909) 695-5679
customizable selection of interactive
controls, system activities gauges, into an existing application Apollo users can purchase SDM directly
and optional accessories. with no source code changes. from SuccessWare for US$99. There is a BBS: (909) 694-6891
Tabbed Quick Launch, Resource
Gauges, AppOrganizer, Shortcut This allows immediate, multi- 30-day, money-back guarantee.
menus, Tool Tips, and a Panel man- user access of Xbase files from E-Mail: Team SuccessWare 74774,2240
ager are new features in Dashboard
95. Those retained from the earlier legacy applications. Also, all Contact: SuccessWare, 27349 Jefferson
version include one-step drag-and- concurrent-access record and Avenue, Suite 101, Temecula, CA 92590 CIS Forum: GO SWARE
drop printing or faxing, and the
ability to switch between full screen
views of open applications.
Dashboard 95 is available for
download from the Internet
New Widgets Collection from Mobius
Shopping Network, ZiffNet,
CompuServe, and software.net, and
Mobius Ltd., of Hershey, PA form. The TmoShapedButton used as-is or you can register a
from retailers nationwide. Selling for has released its Widget component provides buttons property editor and get the
US$49.95, an upgraded version is
available for US$39.95. To order,
Collection. This kit of compo- that aren’t square, flat, or Mobius previewing dialog box.
call Starfish at (800) 765-7839. nents for Delphi includes gray. With this feature devel- The TmoCards component
TmoSticky, TmoShapedButton, opers can add color, rounded creates a card deck in the
TmoPicturePreviewDialog, edges, or make buttons ellip- .DFM file, supports multiple
TmoCards, TmoToolbox + soid. TmoShapedButton also card fronts and backs, and
TmoTool + TmoDockingPanel, makes multiple-line captions features several back designs.
and TmoTiler. easy to create. Mobius’ Widget Collection
The TmoSticky component Using TmoToolbox + ships with VCL source code
aligns all types of controls to TmoTool + TmoDockingPanel, and a hypertext help file.
fill the spaces on a re-sizable tools can be placed in toolbox-
es and maintain “distant” radio Price: US$149
button functionality. Simply
drag the toolbox and drop it in Contact: Mobius Ltd., P.O. Box 404,
space; the toolbox will float in Hershey, PA 17033
its own window. The toolbars
even re-size if the toolbox Phone: (717) 944-8265
doesn’t fit.
With TmoPicturePreviewDlg, Fax: (717) 944-8265
developers can search for
images in any storage medi- E-Mail: CIS: 73563,533
um. This component can be

NOVEMBER 1995 Delphi INFORMANT ▲ 5


Updates Available for Delphi and Delphi Client/Server
News Scotts Valley, CA — Borland
has released updates to their
ReportSmith, as well as the
most recent technical informa-
Reference and VCL Reference,
and maximum compatibility
L I N E Delphi and Delphi tion bulletins and frequently with Visual dBASE 5.5.
Client/Server products. asked questions from Delphi The Delphi Client/Server
November 1995 For Delphi, this upgrade Tech Support. It also features update adds support for
includes the latest versions of improved context-sensitive help Informix 5.x, Oracle syn-
the Borland Database Engine, in Delphi, Adobe Acrobat ver- onyms, and the Sybase forced
Local InterBase Server, and sions of the Delphi Language index feature.
To order, call Borland at 1-
800-453-3375, extension
InterBase Workgroup Server for Unix Ships 1327. An update CD is priced
Scotts Valley, CA — Borland transaction processing and deci- at US$5.95, and an update
International Inc. is now ship- sion-support users. InterBase disk set is priced at US$19.95
ping the InterBase 4.0 provides lock-free transactions (plus US$5 shipping and han-
Workgroup Server for Solaris, that require no additional pro- dling for either update).
SunOS, HP-UX, AIX, SCO, gramming, while providing a
and AT&T Unix platforms. result for every query.
InterBase 4.0 is designed for InterBase also features
Supreme Court to
enterprise and workgroup com- multi-dimensional arrays, two- Review Lotus vs.
Informant Moves from
BBS to CompuServe
puting environments and is phase commit and distributed Borland Ruling
Elk Grove, CA — Beginning
available on Windows 3.1, recovery, stored procedures,
Dec. 1, 1995, Informant Windows NT, Windows 95, event alerters, triggers, and Washington, DC — The US
Communications Group, Inc. Supreme Court has agreed to
(ICG) will close their BBS and and all popular Unix platforms. BLOb filters. It supports
move its contents to the InterBase offers superior ODBC, ANSI SQL 92 and review an appellate court’s rul-
Informant CompuServe forum.
performance for mission-criti- UNICODE character sets. ing that Quattro and Quattro
Operational since June, ICG cre- cal operations including stock Borland’s Delphi, priced at Pro spreadsheet products, for-
ated the Informant CompuServe
forum to foster the exchange of trading, pharmaceuticals, aero- US$495, has a single-user merly developed and marketed
technical information among
developers who use Borland’s space, and network manage- copy of InterBase. Delphi by Borland, did not infringe on
Paradox and Delphi, as well as ment, while adhering to Client/Server also includes a the copyright of Lotus 1-2-3.
Oracle. This forum currently fea-
tures code contained in past industry standards such as local Windows version of Recently acquired by IBM,
issues of Delphi Informant and SQL 92 and ODBC. InterBase, along with the Lotus appealed to the US
Paradox Informant, in addition to
shareware, company news, and The InterBase architecture rights to deploy local InterBase Supreme court just months
much more.
offers a multi-client and multi- applications, and costs after the US Court of Appeals
The Informant CompuServe threaded server for speed and US$1,995. For more informa- for the First Circuit reversed
forum can be accessed by typing
“GO ICGFORUM” at any optimal use of resources. Its tion call Borland at (408) 431- an earlier ruling in favor of
CompuServe GO prompt. To join versioning engine ensures data 1000 or visit their Web Site at Lotus. In their appeal to the
CompuServe and obtain a starter
kit, including a US$15 usage availability for concurrent http://www.borland.com. Supreme Court, Lotus argued
credit, call toll-free in the United
States (800) 524-3388, and ask
that Congress intended to
for REP Number 547. US Army to Use InterBase treat computer programs as
Scotts Valley, CA — Borland The commander receives copyrightable literary works
International Inc. has information from many according to a copyright law
announced that InterBase has sources over his extended enacted in 1976.
been chosen by the US Army battlefield. He then faces the Lotus’ decision to appeal was
for its Advanced Field Artillery complex problem of synchro- no surprise to Borland. “We
Tactical Data System nizing his forces based on are confident in the appellate
(AFATDS). Magnavox up-to-the minute informa- decision,” said Borland
Electronic Systems Company, tion from remote field loca- spokesman Steve Grady. “This
the prime contractor, recom- tions,” explained John will allow us to get a definitive
mended InterBase because it’s Williams, director of the answer and remove all ques-
platform-independent, and AFATDS program at tions surrounding the issue.”
includes unique, advanced dis- Magnavox. “Decision sup- The first ruling in the Lotus
tributed features. port of this nature requires a vs. Borland case was announced
“Operations on today’s air- modular and flexible archi- in August 1992. At that time,
land battlefields are swift, the District Court ruled the
“US Army to Use InterBase” “Supreme Court”
intense and highly lethal. continued on page 7 continued on page 7

NOVEMBER 1995 Delphi INFORMANT ▲ 6


DB/EXPO ’95 Heads to New York
News New York, NY — Offering
three concurrent conferences,
Topics for those attending
the Data Warehousing and
president of DataBase
Associates International and
L I N E DB/EXPO ’95 is slated for Parallel Computing Conference DB/EXPO conference direc-
Dec. 5-7, 1995 at Javits will include building a business tor; Don Haderie, IBM Fellow
November 1995 Convention Center in New case for a data warehousing and director of Data Manage-
York, NY. With over 25,000 IT project, selecting the right end- ment Architecture and
professionals and 150 vendors user tools, and listening to cus- Technology, IBM Corporation;
scheduled to attend, this year’s tomer experiences with data Dr Jerry Held, senior vice pres-
DB/EXPO features the warehousing. ident of Server Technologies
Database and Client/Server The Executive Conference Division, Oracle Corporation;
Development Conference, Data will examine IT trends Dennis McEvoy, vice president
Warehousing and Parallel including structuring an IT of Products Group, Sybase,
Computing Conference, and organization; business re- Inc.; and Mike Saranga, senior
the DB/EXPO Executive engineering; and maximizing vice president of Management
Conference. the business benefits of data and Development, Informix
Participants in the Database warehousing. Software.
and Client/Server Development Keynote addresses will be For more information, call
Upcoming Client/Server Conference will discuss presented by Colin White, 1-800-2DB-EXPO.
Seminars
Andover, MA — The Client/Server client/server issues such as
Project Management Seminar
comes to San Francisco, CA on building enterprise client/server
applications, integrating
Nov. 28-29, 1995. Seminar
instructor Peter M. Storer, vice
client/server and legacy applica-
Database and Client/Server World Nears
president of Client/Server
Consulting for Atre Associates, tions, and evaluating database Andover, MA — DCI has vice president of Products
will cover topics such as: What’s
Different About Managing servers and application develop- announced the Database and Group, Sybase, Inc.
Client/Server Projects; Common
Pitfalls and Mistakes and How to ment tools. Client/Server World Topics at this conference
Avoid Them; and The Breadth of Conference and Exposition, will address moving to
Knowledge Required of the
Client/Server Project Manager.
Supreme Court (cont.) scheduled for Dec. 5-7, 1995 finance, manufacturing, and
Command Hierarchy in in Chicago, IL. This event human relations client/server
For more information, call DCI
at (508) 470-3880 or visit their Borland’s spreadsheet products will feature several concur- applications; developing a
Web Site at
http://www.DCIexpo.com/. infringed the copyright of rent conferences that cover practical framework for IT
Lotus 1-2-3 and Borland vol- client/server issues, data and end-user teaming on
Objects and Relations untarily removed this feature. warehousing and reposito- client/server application
Seminar The court reaffirmed its deci- ries, parallel databases, mid- planning and implementa-
Author, columnist, and industry
expert Chris Date will present the sion in July 1993. dleware, object-oriented tion; and evaluating vendors
Objects and Relations seminar
Nov. 7 - 9, 1995 in Palo Alto, CA. Then later in 1993, the technologies, and groupware and selecting software.
Federal District Court ruled application development. Database and
This seminar reviews OODB sys-
tems and relational technology, another compatibility feature in Keynote speakers sched- Client/Server World is
but attendees are not required to uled to appear at the expected to attract over
have prior knowledge of object-
Quattro Pro and Quattro Pro
oriented technology. For more for Windows infringed the Database and Client/Server 25,000 MIS professionals
information, call DCI at (508)
470-3880 or visit their Web Site copyright of Lotus 1-2-3. The World include: Shaku Atre, and more than 800 exhibits.
at http://www.DCIexpo.com/. court placed an injunction president of Atre, Inc.; Dave For more information, call
against Borland, barring further Duffield, CEO and president DCI at (508) 470-3880 or
sales or distribution of the of PeopleSoft, Inc.; Dr E.F. visit their Web Site at
products. Borland shipped a Codd, independent consul- http://www.DCIexpo.com/.
new version of Quattro Pro tant; and Dennis McEvoy,
without the infringing feature.
In addition, Borland appealed US Army to Use InterBase (cont.)
the decision to the US Court of tecture that would support and control solution. It fea-
Appeals, and in their written both distributed processing tures commander’s guidance,
opinions, all three appellate and distributed databases.” mission planning guidance,
judges ruled in favor of AFATDS provides a singu- detailed asset control and sta-
Borland. lar fire support command tus, and movement control.

NOVEMBER 1995 Delphi INFORMANT ▲ 7


On the Cover
Delphi / Object Pascal

By Richard Wagner

Think Objects, Not Reuse


Using OOP Fundamentals to Achieve Code Reuse

ode reuse has always been a worthy objective for application devel-

C opers. How many developers, however, have actually been successful


in realizing this goal? Depending on the development environment
you have used in the past, most forms of reuse typically center on code
libraries, templates, and application frameworks. While Delphi supports
these, it also provides native support for something much more powerful:
object-orientation.
In this article, we will explore the notion that substantive code reuse is attainable only by
introducing object-oriented programming (OOP) concepts into your application development
process. In short, if you think in terms of objects, reuse will follow. And in contrast, if you try
to achieve reuse using conventional approaches, you will ultimately fall short. Because most
developers work in a highly-competitive market, an object-oriented strategy can make the dif-
ference between success and failure.

OOP in the Business World


Object-oriented programming has been around for a long time
and is implemented in many languages. However, unless you
have worked with C++ or Object Pascal, you may have never
encountered a true OOP environment before working with
Delphi. This is particularly true if you come from a client/serv-
er database application development background.
Tools such as PowerBuilder, Paradox for Windows, and Visual
Basic tout themselves as being object-oriented, when in reality
they are “object-based”. You may be able to work with objects
in these environments, but support for such principles as
abstraction and dynamic binding is altogether lacking.
I suppose one of the problems with object-oriented program-
ming (OOP) is that it sounds so academic. Think of OOP’s
principle concepts: abstraction, inheritance, encapsulation, and
polymorphism. When first mentioning these to my wife, she
remarked: “Have you joined a cult?”
On first take, such terms sound foreign and useless in a busi-
ness world where rapid application development is the buzzword
of choice. As you will see, however, these OOP principles can

NOVEMBER 1995 Delphi INFORMANT ▲ 8


On the Cover

be used in a practical manner to revolutionize the way you reuse it in future database applications. When you begin a new
develop applications in Delphi. project (Project #2), you can then reference the library that the
procedure is contained in and use it in the new application.
The Reuse Battle
While nearly everyone agrees on the principle of reuse, the During the development of Project #2, however, you realize
priority given to it by developers varies wildly. And this isn’t you must have specific table naming conventions that are not
the fault of the developer alone. After all, what developers provided for in the original code. Therefore, you must modify
usually hear from their managers, users, or clients is: “We the procedure to meet the needs of this second project. The
want it now!” In this context, the developer is met with a dilemma becomes: Do you 1) modify the tried and true
dilemma: Do I develop a program for this specific problem or CreatePrivTable procedure to account for these new changes?
create a generic solution in twice the amount of time? The or 2) copy the original code into a new procedure to avoid
“tyranny of the urgent” typically comes into play and a devel- tampering with bug-free code?
oper will — unless provided with a sufficient incentive for This quandary demonstrates where the goal of reuse eludes us
reuse — develop a solution that is perhaps great for a specific in traditional procedural languages. There is no architecture
need at a specific time, but useless for future needs. in place that can easily deal with change. Even small modifi-
cations to CreatePrivTable can have widespread implications
Even the term rapid application development (RAD) seems throughout one or more applications.
inherently contradictory to the ideal of generic reusable code.
While that is true in the short-term, a well thought-out code The Inheritance Solution
reuse strategy will facilitate RAD after an object component Using object-oriented techniques in Delphi, you avoid this
library has reached a certain degree of maturity. dilemma. Instead, you can convert the original procedure into
a TPrivTable class. You could make it into an object because it
Reuse Out of the Box has both properties (e.g. TableName, TableType, and Structure)
Reuse is certainly promoted in Delphi right out of the box — and methods (e.g. Execute).
through components, VBXes, and templates. Prudent use of
these resources will take you a long way to the “promised When you begin Project #2, you can create a descendant class
land” of reuse. Project templates serve as a good starting point called TPrivTableCustomNames and modify its properties and
for new applications, providing an application framework that behavior to meet its specific needs. From a reuse standpoint,
you can then customize. Form templates offer a means of this has two advantages. First, in creating a subclass you avoid
enforcing standards (font, button placement, and so on), but touching the bulletproof code of TPrivTable, yet at the same
be careful of extending their functionality much beyond that. time, you have full access to this code. Second, you can main-
tain a link between the ancestor and descendant class. Let’s say
Much of the reuse aspect of Delphi focuses on its component in six months you modify the TPrivTable class to take advan-
architecture. And for good reason — components are the tage of Windows 95 long filenames. TPrivTableCustomNames
“black box” objects you’re striving for. However, don’t make will be automatically updated as well.
the mistake of thinking solely in terms of visual component Let’s look at a second example of inheritance by creating stan-
libraries (VCLs). Components are a key element in a reuse dardized OK, Cancel, and Help buttons to use instead of
strategy, but you can use VCLs in a non-object-oriented man- constantly customizing TButton objects each time you need
ner and, in so doing, miss much of what they can offer. As a them. You have custom properties for each of them (e.g.
result, you must first have a successful object development Caption), and you want to make OK, Cancel, and Help the
strategy in place before creating these components. same width and height as standard Windows buttons.
(TButton buttons are too large by default.)
Think Objects
Inheritance and polymorphism are two basic OOP concepts that Therefore, you can create a derivative of the TButton class
are fundamental to discussing code reuse in Delphi. First, inher- called TStandardButton that overrides the size of the base class:
itance defines the relationship between object classes. For exam-
ple, a base class called TCola can have subclasses based on it { Within the interface section }
type
called TClassicCoke and TPepsi. Both TClassicCoke and TPepsi TStandardButton = class(TButton)
inherit all the properties and methods of its ancestor (TCola), public
such as the Caffeine property or the Drink method. However, constructor Create(AOwner: TComponent); override;
end;
you can add new data or behavior to the descendant class and
can even override methods of the ancestor at run-time. { Within the implementation section }
constructor TStandardButton.Create(AOwner: TComponent);
begin
To illustrate the importance of inheritance in your applications, inherited Create(AOwner);
let’s think about a typical code reuse scenario. Suppose you have Height := 23;
developed a nifty CreatePrivTable procedure and would like to Width := 95;
end;

NOVEMBER 1995 Delphi INFORMANT ▲ 9


On the Cover

Next, you must create three derivatives under TStandardButton


for the OK, Cancel, and Help buttons. This is accomplished
with the code shown in Figure 1. The entire .PAS file is shown
in Listing One on page 11.

{ Within the interface section }


type
TStandardOKButton = class(TStandardButton)
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
end;

type
TStandardCancelButton = class(TStandardButton)
public Figure 2: The TButton object hierarchy.
{ Public declarations }
constructor Create(AOwner: TComponent); override; and plane — are available to take Bill from Los Angeles to
end;
Boston. When he arrives in LA, Bill wants to be able to tell
type any of the vehicles, “Go to Boston,” and have it take him
TStandardHelpButton = class(TStandardButton) across the country. Without an object hierarchy, these vehicles
public
{ Public declarations } are independent creatures. That is, each has its own set of
constructor Create(AOwner: TComponent); override; properties, methods, and events to respond to. In such an
end; environment, how can Bill know the correct command to tell
{ Within the implementation section } the vehicle? Maybe the directive for the plane is FlyToBoston;
constructor TStandardOKButton.Create(AOwner: TComponent); for the car, DriveToBoston; and for the bicycle, RideToBoston.
begin Bill has no way of knowing for certain. To further complicate
inherited Create(AOwner);
Caption := 'OK'; matters, suppose he encounters a new vehicle he’s never seen
Default := True; before (like a spaceship) and is unsure of what it is. Since this
ModalResult := mrOK; object has no “common ground” with other vehicles he has
end;
previously used, Bill is unable to tell it what to do.
constructor TStandardCancelButton.Create(AOwner:
TComponent); Without an object hierarchy, Bill is forced to know everything
begin
inherited Create(AOwner); about each vehicle to ensure that it will get him to Boston. In
Cancel := True; addition, Bill needs to know about each possible vehicle in
Caption := 'Cancel'; advance so he will know what command to tell it when he’s
ModalResult := mrCancel;
end; ready for the cross-country trek.

constructor TStandardHelpButton.Create(AOwner: Now, let’s suppose Bill is in an object-oriented environment


TComponent);
begin and knows that each of these belong to a base class named
inherited Create(AOwner); TVehicle and that all TVehicle objects understand a
Caption := 'Help'; GoToBoston message. (In reality, we would want to separate
end;
the GoTo from the Boston since the GoTo is the behavior and
Figure 1: Creating three derivatives of TStandardButton for the OK, Boston is a variable. But for our purposes, let’s limit the GoTo
Cancel, and Help buttons. method to a single location — Boston.)

The hierarchy of these buttons is shown in Figure 2. Because Communication is simplified from Bill to all TVehicle objects
of the relationship between TStandardButton and its descen- and its descendants because he can issue a general message
dants, if you decide to change the size of the three buttons in (GoToBoston) to whichever vehicle he decides to use. The vehi-
the future, you only need to make a single change to the cle is responsible for figuring out what to do with it. In fact,
TStandardButton class. he doesn’t even need to know the type of vehicle it is. This is
polymorphism in action. In Object Pascal code, our example
The Polymorphism Solution may resemble the code shown in Listing Two.
The second OOP concept that is loosely integrated with reuse
is polymorphism. You can think of polymorphism as a means Conclusion
by which objects can communicate freely with each other. By incorporating object-oriented principles into our applica-
tions, we can realize tangible benefits of reuse. (Remember that
The importance of polymorphism is perhaps best explained OOP has many advantages beyond reuse alone.) Inheritance
with an example. Let’s imagine three vehicles — auto, bicycle, enables us to account for change by maintaining a linkage

NOVEMBER 1995 Delphi INFORMANT ▲ 10


On the Cover

between a base class and its descendants. It also provides a “fire- The demonstration source referenced in this article is available on
wall” for a class, protecting it from being sullied when we work the 1995 Delphi Informant Works CD located in
with a descendant class. Polymorphism allows us to create inde- INFORM\95\NOV\RW9511.
pendent objects with general interfaces, making communica-
tion between objects easier to code and maintain. As a result,
our objects become much more flexible and manageable.

If you intend to get serious about code reuse in Delphi, you will Richard Wagner is a technical architect for IT Solutions in Boston, MA. He is author of
spend considerable time learning component development. several Paradox, Windows, and CompuServe/Internet books and is also a member of
Team Borland on CompuServe. Richard can be reached on CompuServe at
However, make sure to approach components using an object- 71333,2031 or via Internet at [email protected].
oriented strategy. And remember — think objects, not reuse. ∆

constructor TStandardButton.Create(AOwner: TComponent);


Begin Listing One — TStandardButton .PAS File begin
unit Standbtn; inherited Create(AOwner);
Height := 23;
interface Width := 95;
end;
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, constructor TStandardOKButton.Create(AOwner: TComponent);
Graphics, Controls,Forms, Dialogs, StdCtrls; begin
inherited Create(AOwner);
type Caption := 'OK';
TStandardButton = class(TButton) Default := True;
public ModalResult := mrOK;
constructor Create(AOwner: TComponent); override; end;
end;
constructor TStandardCancelButton.Create(
type AOwner: TComponent);
TStandardOKButton = class(TStandardButton) begin
public inherited Create(AOwner);
{ Public declarations } Cancel := True;
constructor Create(AOwner: TComponent); override; Caption := 'Cancel';
end; ModalResult := mrCancel;
end;
type
TStandardCancelButton = class(TStandardButton) constructor TStandardHelpButton.Create(AOwner: TComponent);
public begin
{ Public declarations } inherited Create(AOwner);
constructor Create(AOwner: TComponent); override; Caption := 'Help';
end; end;

type procedure Register;


TStandardHelpButton = class(TStandardButton) begin
public RegisterComponents('Buttons',[TStandardButton]);
{ Public declarations } RegisterComponents('Buttons',[TStandardOKButton]);
constructor Create(AOwner: TComponent); override; RegisterComponents('Buttons',[TStandardCancelButton]);
end; RegisterComponents('Buttons',[TStandardHelpButton]);
end;
procedure Register; end.

implementation End Listing One

NOVEMBER 1995 Delphi INFORMANT ▲ 11


On the Cover

Begin Listing Two — Polymorphism in Action


unit Polymrph;

interface

uses
SysUtils, WinTypes, WinProcs, Messages, Classes,
Graphics, Controls, Forms, Dialogs, StdCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
end;

type
TVehicle = class(TObject)
procedure GoToBoston; virtual;
end;

type
TPlane = class(TVehicle)
procedure GoToBoston;
end;

type
TCar = class(TVehicle)
procedure GoToBoston;
end;

type
TBicycle = class(TVehicle)
procedure GoToBoston;
end;

var
Form1: TForm1;

implementation

{ $R *.DFM }
procedure TVehicle.GoToBoston;
begin
end;

procedure TPlane.GoToBoston;
begin
MessageDlg(‘Fly the skies.’,mtInformation,[mbOK],0);
end;

procedure TCar.GoToBoston;
begin
MessageDlg(‘Drive the Interstate.’,
mtInformation,[mbOK],0);
end;

procedure TBicycle.GoToBoston;
begin
MessageDlg(‘Ride on backroads.’,mtInformation,[mbOK],0);
end;

procedure TBill.Button1Click(Sender: TObject);


var
Plane: TPlane;
Car: TCar;
Bicycle: TBicycle;
AvailDays: Integer;
begin
AvailDays := StrToInt(Edit1.Text);
case AvailDays of
1..3 : Plane.GotoBoston;
4..6 : Car.GoToBoston;
else Bicycle.GotoBoston;
end;
end;

end.

End Listing Two

NOVEMBER 1995 Delphi INFORMANT ▲ 12


On the Cover
Delphi / Object Pascal

By John O’Connell

Power and Safety


Pascal Subranges, Enumerated Types, and Sets

elphi’s implementation of Pascal is a greatly enhanced dialect of stan-

D dard Pascal. Pascal’s roots lie in a language originally designed to help


teach basic concepts of structured programming and top-down design.
Indeed, Pascal was the language of choice in most academic institutions. For
example, those of you who studied computers at colleges or universities in the
early 1980s may have encountered Pascal on the school’s mainframe computer.

This history leads some programmers to think of Pascal as an old-fashioned programming language,
unsuitable for modern application development. This is especially true when Pascal is compared with
languages such as C or C++. Indeed, quite a number of “less than well-informed” computer journal-
ists hold this view of Pascal.

Pascal Emerges
However, this assertion about Pascal is — at least now — untrue. Borland has enhanced the language
to the degree where there’s little that programmers cannot achieve by using Pascal instead of the usual
“serious” C/C++ development systems.

And compared with C/C++, Pascal code is easier to understand. This


means that stable and bug-free applications are easier to build. In fact,
the problems with difficult-to-understand C code led to the introduc-
tion of the short-lived Pascal-like systems language, Modula-2, market-
ed by companies such as Logitech and Jensen & Partners in the early
1980s. However, Modula-2 never really caught on, possibly because of
the introduction of Turbo Pascal that went on to establish itself as the
de-facto Pascal implementation on PCs.

In addition to the object-oriented (OOP) extensions that Borland


added to Turbo Pascal (Object Pascal’s ancestor) in version 5.5, a whole
range of other useful language extensions essential for modern applica-
tions development were also added.

The aim of this article is not to discuss and compare Borland’s current
incarnation of Pascal with the version introduced by Niklaus Wirth in
1971. Instead, we’ll discuss a few useful features of the original Pascal
language that are often overlooked in the shadow of Object Pascal’s
extra language features.

NOVEMBER 1995 Delphi INFORMANT ▲ 13


On the Cover

Standard Pascal provided a number of user-definable data types


Integer Type Subrange Type Equivalent
such as the subrange, enumerated, and set type in addition to the
usual numeric and character types. These user-definable types can Figure 1:
ShortInt -128..127
be used to create flexible data constructs which, when used effec- Integer
Byte 0..255 types and
tively, make it very easy to write clear, understandable Pascal code.
SmallInt -32768..32767 their equiv-
alent sub-
Let’s find out more. Integer -32768..32767
range
Cardinal 0..65535 types.
The Subrange Type Word 0..65535
As its name implies, the subrange type allows you to define types
LongInt -2147483648..2147483647
that limit the possible values contained within a variable of this
type to a user-defined range. The type is defined with the lower a compile-time or run-time error if Range checking is enabled.
and upper bounds separated with two periods ( .. ). For example: However, because assignments must always be checked to see if
they are allowed, Range checking adds code and slows your pro-
type gram. Once your program is fully debugged (is there ever such a
TNibble = 0..15;
program?), you can turn off Range checking and re-compile your
application to make it smaller and faster before delivering it to
This defines a type that can be used to store integers with values
your customer.
within the range 0 and 15. Any attempt to assign a value out of
this range will cause a compile-time or run-time error (provided
Range checking can be useful for debugging Pascal applications.
that Range checking is enabled on the Compiler page of
When using integer variables, choose the Integer type with a range
Delphi’s Project Options dialog box, or the {$R+} compiler
that most closely fits the possible range of values your integer vari-
switch is used in your code).
able will encounter. Suppose, for example, that you’re using an
integer variable that should never be assigned a negative value —
Moreover, the specified range need not be zero-based. So, we can
it’s easy to be lazy and use a variable of type Integer. However, if
make the following subrange type definitions:
you make the variable a Byte or Word type, Range checking will
type catch any attempt to assign a negative value to the variable and
THiNibble = 16..255; pinpoint a bug in your application.
TSignedByte = -128..127;

The Enumerated Type


We can also declare a character-based subrange type to limit This user-defined type is frequently used throughout the VCL
assignable values to numeric characters: source code. Enumerated types are defined by a comma-separat-
ed list of “symbolic” ordinal values enclosed in brackets. For
type
TNumericChars = '0'..'9';
example:

type
But how much space is used to store a variable of subrange type? DOW = (Sunday, Monday, Tuesday, Wednesday,
In our examples above, only one byte is used. If the subrange was Thursday, Friday, Saturday);
0..65535, then 2 bytes — the size of the Word type — are used
for storage, the same as for a subrange of 256..65535. If the range declares a type representing a symbolic list of the days of the week.
is 0..$FFFFFF, the storage requirement is 4 bytes (not the expect- Declaring the variable, DayOfWeek, of this type, allows the follow-
ed 3 bytes, but the size of the Longint type). In terms of storage ing assignments:
required, the subrange type is matched to the nearest ordinal type,
DayOfWeek := Sunday;
thus 0..15 and '0'..'9' each occupy 1 byte of storage.

And just what is an ordinal type? An ordinal type is a sub-set of a or:


standard type, such as any of the integer types (byte, word, inte-
DayOfWeek := Friday;
ger, etc.) or the Char and Boolean types. Each possible value of
an ordinal type has its own ordinality that is an integer value.
but not:
The various Real types, String, Pointer, and Class types are not DayOfWeek := 'Saturday';
ordinal types. The Integer types shown in Figure 1 can be seen as
equivalent subrange types. (The size and range of the Integer and nor:
Cardinal types will increase from 16 to 32 bits in Delphi32.)
DayOfWeek := 1;
The subrange type is a useful aid in debugging code where the
possible values of a variable must be restricted to a certain range. Only the symbolic constants included in the enumerated type
As mentioned, any illegal assignment to a subrange type will cause definition can be assigned to a variable of that type. (The most

NOVEMBER 1995 Delphi INFORMANT ▲ 14


On the Cover

fundamental enumerated type is Boolean which has just two


possible values: True and False.) type
DOW = (Sunday, Monday, Tuesday, Wednesday, Thursday,
Friday, Saturday);
Other examples of enumerated types used in the VCL include:
var
TDataSetState = (dsInactive, dsBrowse, dsEdit, dsInsert, DayOfWeek: DOW;
dsSetKey, dsCalcFields); DayNum: Byte;
...
TBorderIcon = (biSystemMenu, biMinimize, biMaximize);
begin
TNavigateBtn = (nbFirst, nbPrior, nbNext, nbLast, { Groan! }
nbInsert, nbDelete, nbEdit, nbPost, DayOfWeek := Monday;
nbCancel, nbRefresh); { Assigns 1 to DayNum }
DayNum := Byte(DayOfWeek);
{ Also assigns 1 to DayNum }
Examine those VCL properties with pre-defined single values select- DayNum := Ord(DayOfWeek);
ed from a drop-down list in the Object Inspector. Whenever a com- DayNum := 5;
{ Assigns Friday to DayOfWeek }
ponent property can be assigned one of a number of pre-defined DayOfWeek := DOW(DayNum);
values, that property is of an enumerated type. { Causes a range-check error }
DayOfWeek := DOW(10);
end;
The enumerated type can also be used as the basis for a sub-
range type:
Figure 2: Demonstrating underlying ordinal values.
type
WorkingWeek = Monday..Friday; constants (as you would have to with Visual Basic, for example).
Standard ANSI C/C++ had the equivalent enum enumeration
We can even use the enumerated type as an array index: data type added only relatively recently.

const The Set Type


WorkDays = array [Monday..Friday] of string[3] = The user-defined set type is one of the most useful language fea-
('Mon','Tue','Wed','Thu','Fri');
tures of Pascal. A set type is a collection or list of values (also
or: called elements or set members) of the same ordinal type (the base
type) that is declared as a comma-separated list within brackets.
const
WorkDays = array [WorkingWeek] of string[3] =
('Mon','Tue','Wed','Thu','Fri'); For example, a set of characters including the characters Y, y, N
and n is declared as:
As I’ve stated, enumerated types are simply a symbolic represen-
type
tation of the list of possible ordinal values that a variable can YesNo = set of char;
have. The type DOW (defined earlier) is equivalent to the fol-
lowing hypothetical declaration: var
YN : YesNo;
...
type
DOW = (0,1,2,3,4,5,6); begin
YN := ['Y', 'y', 'N', 'n'];
The type DOW is simply a list of zero-based ordered values. We
can similarly interpret the Boolean type as (0,1) which is how So we’ve defined a set, but what use are sets in Pascal programs?
False and True are interpreted in C/C++. Before continuing, we need to take a brief look at set theory.

The code in Figure 2 demonstrates this concept of underlying Set Theory


ordinal values. We see that with a little typecasting we can con- We’ve all learned about sets at school and met with concepts
vert an enumerated type’s current symbolic value to its underly- such as set union, set intersection, and set difference. Set union is
ing ordinality by using the standard function Ord or an integer the set that includes elements from different sets; a set intersec-
typecast. We can also assign an integer that has been typecast to tion is a set that includes only those elements common to differ-
a variable of enumerated type. ent sets; and a set difference is the set containing those elements
not present in another set. Figure 3 illustrates these set operators
An enumerated type can have a maximum of 65536 symbolic val- diagramatically. The shaded areas represent the result set of the
ues that occupy 2 bytes of storage. Enumerated types with a max- operators applied between sets A and B.
imum of 256 symbolic values occupy a single byte of storage.
Sets in Pascal can be used with set union, set intersection, set dif-
The use of enumerated types makes code more readable and is ference, and set equivalence operators, as well as the set member-
certainly a better and safer alternative to defining several integer ship operator. Figure 4 lists the Pascal set operators.

NOVEMBER 1995 Delphi INFORMANT ▲ 15


On the Cover

We can also combine the above techniques to define sets of non-


consecutive values. For example:

['0'..'9','a..z','#']

defines a set of characters that includes the numeric characters,


lower-case alphabetics, and the hash (or pound sign ) character.
Similarly, the set defined by:

[0..15, 255]

defines the set of integers between 0 and 15 and including 255.

Suppose we wanted to define a set of integers that includes all


the values between 10 and 128 but excludes the values 15, 21,
29, 45, and 115. We could define the set by using the various
ranges (0..14, 16..20, and so on). A far easier way would be
to employ the set difference operator. It lets us define the
required set as:

NumberSet := [10..128] - [15,21,29,45,115];


Figure 3: An illustration of Pascal’s set operators.

The operands used in set union, set intersection, and set differ- which is the equivalent of:
ence expressions are themselves sets. However, the left and right
NumberSet := [10..14, 16..20, 22..28,
operand in set membership expressions are of ordinal and set 30..44, 46..114, 116..128];
type, respectively. Set equivalence and set membership expressions
evaluate to a Boolean result. Expressions using the set union, set where NumberSet is of type Byte.
difference, or set intersection operators evaluate to a set result.
If we wanted our set of integers to also include 2, 4, 6, and 8, we
Obviously, the set operators that use set operands can only be could also use the set union operator:
used with sets of the same type. Therefore, for example, the fol-
lowing expression is illegal: NumberSet := [10..128] - [15,21,29,45,115] + [2,4,6,8];

['Y','y','N','n'] + [1,0] And just to demonstrate the set intersection operator, the follow-
ing set expressions are equivalent:
Sets can be declared in a number of ways (in addition to being
declared in the standard comma-separated list). As we’ve seen, [10..20]
two periods can be used to define the range of values in a set.
Thus, the set defined as: and
['A'..'G'] [0..20] * [10..100]

is equivalent to the more verbose: But what is the result of the


['A','B','C','D','E','F','G'] [0..255] - [0..255]

Operator Meaning Expression Result

+ Set union [1,2,3] + [4,5,6] [1,2,3,4,5,6]

* Set intersection ['A','B','C'] * 'B','C','D'] ['B','C']

- Set difference ['A','B','C'] - 'B','C','D'] ['A'] Figure 4: Pascal’s set operators.

= Set equivalence ['A','B','C'] = 'A','B','C'] True


['A','B','C'] = 'C','D','E'] False

IN Set membership 'A' IN ['A','B','C'] True


'Z' IN ['U','V','W'] False

NOVEMBER 1995 Delphi INFORMANT ▲ 16


On the Cover

expression? This results in the empty set that is denoted by empty TBorderIcons, for instance, is a TForm property that is a set of
brackets ( [] ). As the name suggests, the empty set is the set that TBorderIcon. Sets are also found when specifying the buttons to
contains no values. be displayed in the dialog box created by calling the MessageDlg
function.
So on to the set membership operator, in. This operator
makes sets very useful in Delphi. Consider the following To check if a form has a maximize and minimize button, we
statement: could use the test:

if (NumVal >= 0) and (NumVal <= 32) then if (BorderIcons = [biMaximize, biMinimize]) then
DoSomething; DoSomething;

This can be shortened to: However, our test will fail if BorderIcons is set to biSystemMenu,
biMaximize, or biMinimize. To avoid this potential problem, we
if (NumVal in [0..32]) then should use the set intersection operator:
DoSomething;

if ((BorderIcons * [biMaximize, biMinimize]) =


With a more complicated conditional test, the statement: [biMaximize,biMinimize]) then
DoSomething;
if (NumVal = 10) or (NumVal = 15) or
(NumVal = 21) or (NumVal = 56) then Wherever the value of a component’s property can take on a
DoSomething;
combination of values from a list, that property is of a set of
enumerated type. If you closely examine the unexpanded
can be shortened to:
TForm.BorderIcons property in the Object Inspector, you’ll see
if (NumVal in [10,15,21,56]) then the property values are enclosed in brackets as set elements.
DoSomething;
Another use of sets is to test for a numeric character. This can be
With longer and more complicated conditional expressions, we as short as:
can see a clear advantage to using sets and the in operator.
However, the benefits are not just in terms of code clarity. Set IsNumeric := (NumChar in ['0'..'9']);

expressions are more easily optimized by the compiler, and thus


increase code speed and reduce code size. Pascal also provides the standard procedures, Include and
Exclude, for use with sets. The Include procedure allows you to
Not Just Data Types add an element to a set and takes the set and the element to be
So far, the examples have involved characters and integers. But added as parameters. The Exclude procedure allows you to
sets aren’t restricted to these data types. Recall that a set is a col- remove an element from a set and takes the set and the value of
lection of values of the same ordinal type. Therefore, a set’s base the element to be removed as parameters. Figure 5 shows the
type can be defined by an enumerated type. For instance, we parameters used with these procedures.
could define a set of the days of the week:
Procedure Example
DOWSet = set of DOW;
Include ( var s:set of T; e:T ) Include(CharSet,'A');
This line of code is equivalent to: Exclude ( var s:set of T; e:T ) Exclude(CharSet,'A');

DOWSet = set of (Sunday, Monday, Tuesday, Wednesday, Figure 5: The Object Pascal Include and Exclude procedures.
Thursday, Friday, Saturday);

Using the Include and Exclude procedures is equivalent to


A set’s base type can also be a subrange type:
using the set union and set difference operators. However,
DOWNumbersSet = set of 0..6; these Object Pascal procedures generate more efficient code.
Note that these procedures can only add or remove one ele-
The only restriction on a set’s members is that the maximum ment at a time. On the other hand, using the union or differ-
possible number of values the member type can have is 256. ence operators can add or remove several elements in one
This effectively restricts you to sets of type byte, char, subrange, statement. The choice is yours.
or enumerated. Therefore, the following set declaration is illegal:
Set Storage
BadSet: set of 0..120000; Okay. So, sets are useful for reducing complex Boolean
expressions to a short and simple set expression. Surely
Despite this restriction, sets are still useful and powerful tools in there’s a price to pay for this convenience, right? Sets are
your code armory. Delphi’s VCL uses sets in many places. slow and occupy lots of storage space, right? Well, don’t be

NOVEMBER 1995 Delphi INFORMANT ▲ 17


On the Cover

such a pessimist because this isn’t necessarily so. To see why, The byte position of a set member in the bit array can be deter-
let’s take a look at how sets actually work. mined with the formula:

A set is a bit array of a maximum 256 bits (or 32 bytes) with (SetElement div 8) - (MinValue div 8)
each bit representing a member of the set. If a particular mem-
ber exists in the set, then the corresponding bit representation is where SetElement is a set element’s position within the range of
set. The maximum size of the set, therefore, determines the possible values of the set base type, and MinValue is the mini-
amount of storage space required. For example, a set of Char or mum value that the base type can store.
set of Byte always occupies 32 bytes.
Narrowing down the position of the set element, we can deter-
However, a set of enumerated type requires only enough space mine the bit position (within the byte position) of a set member
to store its symbolic values. Therefore, the set DOWSet will with the formula:
occupy only 1 byte because the set contains 7 possible values.
That equates to 7 bits that fit into a single byte. So, a set of OrdinalValueOfTheElement mod 8

enumerated type containing 9 possible values will occupy 2


bytes and so on, up to the maximum of 256 possible values So how do the set operators work? Considering that a set is
that occupy 32 bytes. simply a bit pattern, you may guess that set operators are
essentially bitwise operators, and you’d be right. This makes
The storage requirements of a set of subrange base type set operations fast in practice. Let’s examine each set operator
depend on the bounds of the subrange. The following set dec- in turn.
larations will use one and two bytes of storage, respectively:
The set union operator is essentially a fancy wrapper for the bit-
var wise OR operator. Consider these two sets:
{ Has a maximum of 8 possible values and therefore
needs one byte of storage } a := [Red, Green, Blue];
ByteSet: set of 0..7; b := [Black, White];
{ Has a maximum of 16 possible values and therefore
needs two bytes of storage }
WordSet: set of 0..15; These are represented internally as the two bytes 7 and 192, or
00000111 and 11000000. OR’ing these two values gives us
The number of bytes required to store a set of a particular base 11000111 which is the byte representation of the set:
type is calculated with the following formula:
[Red,Green,Blue,Black,White]
(MaxValue div 8) - (MinValue div 8) + 1
This is the result of set a added to set b.
where MaxValue and MinValue are the largest and smallest values
of the base type. The set intersection operator is based on the bitwise AND oper-
ator. For example, look at sets a and b:
Set Internals
I’ve said that a set is simply a bit array. Let’s support that with a a := [Red, Green, Blue];
b := [Black, White, Green];
few facts and examine the performance issues when using sets.
Consider the following set declaration:
The binary representation of these sets is 00000111 and
var 11000010 for a and b, respectively. Therefore, if we apply the
ColourSet : set of (Red,Green,Blue,Cyan,Yellow, AND operator we get:
Magenta,Black,White);
begin
ColourSet := [Blue, Cyan, Black]; 00000111 AND
end; 11000010

00000010
Since there are 8 possible values for the enumerated type
ColourSet, it occupies only a single byte (determined using This is the binary representation of the set [Green] which is the
sizeof(ColourSet)). If we examine the value of this byte
result of a multiplied by b.
(using byte(ColourSet)within the Evaluate/Modify dialog
box of the IDE debugger) after assigning ColourSet, we see it’s The set difference operator is more complicated, and is based on
set to 76 (or binary 01001100). Because the set contains the the XOR and AND operators. Using sets a and b as declared
third, fourth, and seventh member of the enumerated type, above, we apply the XOR operator:
the third, fourth, and seventh bits are set in the byte repre-
sentation of the set. (Remember that the lowest, or least sig- 00000111 XOR
nificant, bit is the rightmost bit in this scheme.) 11000010

11000101

NOVEMBER 1995 Delphi INFORMANT ▲ 18


On the Cover

This is the binary equivalent of the set [Red, Blue, Black,


White]. Now we AND this result with the bit pattern of set a type
{ Bits 0 to 7 of a byte }
to complete the operation: TByteBits = set of (b0,b1,b2,b3,b4,b5,b6,b7);
{ Bits 0 to 15 of a word }
11000101 AND
TWordBits = set of 0..15;
00000111 (the bit pattern of set a)
var
00000101 MyByte: Byte;
MyWord: Word;
My8Bits: TByteBits absolute MyByte;
This is the binary form of the set [Red, Blue] which is the My16Bits: TWordBits absolute MyWord;
result of subtracting set b from set a.
begin
{ Sets My8Bits to [b7] }
The set membership operator uses the AND operator and com- MyByte := 128;
pares the result with the value of the ordinal left operand. The { Sets My8Bits to [b0,b1,b2, b3,b4] }
MyByte := 31;
following code is the equivalent of testing to see if White is a { Sets My16bits to [0..7] }
member of set b: MyWord := 255;
{ Sets My16bits to [7] }
10000000 AND MyWord := 128;
11000010 { Sets My16bits to [0,15] }
MyWord := 32769;
10000000 { Sets MyByte to 3 }
My8Bits := [b0,b1];
{ Sets MyWord to 7936 }
This is the binary value of White. It is then compared with the My16Bits:= [8..12];
value of the left operand (White) to return True. { Sets MyByte to 0! }
My8Bits := [];
end;
The inner workings of the set equality operator should be quite
obvious!
Figure 6: Using absolute variables.

A New Data Type? To clear the high bit use:


Now that the inner workings of sets has been revealed, I will invent
My8Bits := My8Bits - [b7];
a useful “bit-field” data type. This can be achieved by using what My16Bits := My16Bits - [15];
we’ve learned so far in this article in combination with a feature
that has been in Turbo Pascal for a long time: absolute variables. To clear the high and low bits use:
Absolute variables are declared (using the keyword absolute) as My8Bits := My8Bits - [b0,b7];
My16Bits := My16Bits - [0, 15];
being residents at a certain specified memory address. This
address can be a segment and offset combination (e.g.
7FC0:FF00) or the address of another specified variable. For After this discussion, it’s obvious that the highly sophisticated set
instance, the variables AByte and AChar overlay each other type is nothing more than a fancy wrapper around a bit-field
because both point to the same memory address: used with the AND, OR, and XOR bitwise operators. While the
set initially seems a sophisticated beast, once understood, it’s
var more like a sheep in wolf ’s clothing.
AChar: Char;
AByte: Byte absolute AChar;
Because of their internal workings, sets are fast and compact,
begin especially those sets of ordinal types with up to 8 or 16 possible
{ Same as AByte := 65 } values that occupy a single byte or two bytes, respectively. Any
AChar := 'A';
{ Same as AChar := 'a' }
number occupying 16 bits or less is a number that is easily
AByte := 97; handled by the CPU’s machine instructions. Because of this,
end; such 1 or 2-byte sets can have their operators optimized by the
compiler that generates in-line machine code instead of calls to
Therefore, you can carry out the code shown in Figure 6. run-time library routines. Similarly, the Include and Exclude
standard procedures, when used on 8 or 16 bit sets, generate
However, instead of messing around with bitwise operators to in-line machine code.
obtain or set a bit, we can use the far clearer set notation.
Therefore, checking to see if the high bit of MyByte and With Delphi32, you can expect to see all 32-bit set operations
MyWord is set is simply: optimized as the CPU and operating system instructions make
better use of 32-bit integers.
if (b7 in My8Bits) then
ShowMessage('The high bit of MyByte is set!');
if (15 in My16Bits) then Nearing the End
ShowMessage('The high bit of MyWord is set!'); Where would we be left with Pascal if we didn’t have the sub-

NOVEMBER 1995 Delphi INFORMANT ▲ 19


On the Cover

range, enumerated, and set types? Without enumerated types, and we'd be stuck with:
we’d be forced to write code such as:
var
const DaysOffThisWeek: byte;
Sunday = 0;
Monday = 1; begin
Tuesday = 2; DaysOffThisWeek := Wednesday + Friday;
Wednesday = 3; ...
Thursday = 4;
Friday = 5; { Check if Wednesday has been taken as holiday }
Saturday = 6; if (DaysOffThisWeek and Wednesday) = Wednesday then
...
var end;
DOW: byte; instead of:
begin var
DOW := Sunday; DaysOffThisWeek = set of (Sunday, Monday, Tuesday,
end; Wednesday, Thursday, Friday,
Saturday);
instead of: begin
DaysOffThisWeek := [Wednesday, Friday];
var ...
DOW: (Sunday, Monday, Tuesday, Wednesday, Thursday,
Friday, Saturday); { Check if Wednesday has been taken as holiday }
if (Wednesday in DaysOffThisWeek) then
begin ...
Dow := Sunday; end;
end;

Once again, the first version will be more prone to invalid


Also note that in the longer version of the code there is no built- assignments and is less easy to follow unless you understand
in mechanism to prevent the assignment of values outside the bitwise operators.
range of 0 to 6 to the byte variable DOW.
Conclusion
Without sets we’d have to write: So there you have it. Pascal makes it easier to write clear, read-
able code that gives you a better chance of catching those bugs
begin
if (Num = 1) or (Num >= 6 and Num <= 66) or that your customer may find first.
(Num = 128) or (Num = 132) or
(Num >= 149 and Num <= 155) or (Num = 170) then Who said Pascal is passé? ∆
DoSomething;
end;

instead of: John O’Connell is a software consultant (and born-again Pascal programmer), based
in London, specializing in the design and development of Windows database applica-
begin tions. Besides using Delphi for software development, he also writes applications
if Num in [1,6..66,128,132,149..155,170) then using Paradox for Windows and C. John has worked with Borland UK technical sup-
DoSomething;
port on a regular free-lance basis and can be reached at (UK) 01-81-680-6883, or
end;
on CompuServe at 73064,74.

NOVEMBER 1995 Delphi INFORMANT ▲ 20


On the Cover
Delphi / Object Pascal / C++

By Richard D. Holmes

Cultural Differences
A Comparison of Pascal and C++ Language Features

ecause of its capabilities as an easy-to-use Windows programming tool,

B Delphi is often compared to products such as PowerBuilder and Visual


Basic. (Delphi is sometimes even described as a “Visual Basic killer”.) Yet,
in many ways, the Object Pascal language that lies at the heart of Delphi is
more akin to C++ than to Basic. Like C++, Object Pascal is a hybrid, object-
oriented language with strong type checking that is enforced at compile-time.
This article compares the language features of Delphi and C++, especially with
regard to support for object-oriented programming. (In a future article the per-
formance of identical applications written in Delphi and C++ will be compared.)

Note that throughout this article, the feature set of C++ is that of the proposed ANSI/ISO stan-
dard, as described by Bjarne Stroustrup in his book, The Design and Evolution of C++ (Addison
Wesley, 1994). Many current implementations of C++ differ significantly from this dialect. For
details, consult your system’s language reference manual. Details of the Object Pascal language are
given in the Object Pascal Language Guide.

The Object Model


An object is a data structure that packages some data fields together
with the code that manipulates them. Objects allow the internal
implementation of a data structure to be hidden. The users of an
object can access only those fields and methods that the object
designer chooses to expose. Objects allow the compiler to enforce
the separation between interface and implementation. Through
inheritance, an object can be extended and refined “by difference”
— it need not be totally rewritten.

Hybrids. Both Object Pascal (OP) and C++ are hybrid languages in
which object-oriented programming features have been grafted onto a
non-object-oriented parent. The similarities between OP and C++ arise
more from the similar way in which they have evolved to support object-
oriented programming than from similarities in the parent languages.

As hybrids, both languages are required to maintain a large measure of


backward compatibility. This results in a certain degree of schizophrenia
as primitive data types are mixed with objects, and as calls to statically

NOVEMBER 1995 Delphi INFORMANT ▲ 21


On the Cover

bound procedures are mixed with calls to dynamically bound Calls to virtual methods must be dispatched by the program at
polymorphic methods. The requirement to support two pro- run-time. Both OP and C++ use a virtual method table (VMT)
gramming models enlarges and complicates both languages, but to store the address of each virtual method. Each class has its
also enhances their flexibility. own VMT that is nothing more than an array of function
addresses. Dispatching virtual methods is fast, since it typically
Classes. Both OP and C++ are class-based object languages. requires just de-referencing the pointer to the VMT and then
Individual objects are not defined directly. Instead, a class is indexing into the array to retrieve the method’s address.
defined and then objects are created that represent instances of
that class. There is a one-to-many relationship between a class In addition to virtual methods, OP also allows the dynamic dis-
and its instances (objects). The class stores the code (methods) patching of methods. This is used primarily for handling Windows
that is shared by the objects. However, each object stores its own messages. Because there are hundreds of these messages, the space
data fields (state). In distinguishing between classes and objects, overhead of maintaining an entry for each of them in the VMT of
the nomenclature of C++ is more rigorous than that of OP, every class that is a descendant of TWindow would be substantial.
which often refers to both objects and classes as objects. Therefore, the dynamic method table (DMT) for each class con-
tains entries for only those methods (message handlers) that have
Fields. The fields within an object can be either primitive data been overridden within that class. If a message handler is not
types or objects. Both languages allow the construction of com- found in an object’s DMT, then the DMT of each of its ancestors
posite objects of unlimited complexity. is searched. Since TWindow contains a default handler for every
message, the search will be satisfied there, if not before. ANSI/ISO
Normally, every object has its own copy of the data fields declared standard C++ has no equivalent to dynamic dispatching.
within its class. In the jargon of SmallTalk, these data fields are
instance variables. It’s also possible to have class variables that are In both OP and C++, only methods that are explicitly declared as
created only once per class rather than once per object. In C++, a virtual can exhibit polymorphic behavior. This is probably an
data field declared to be static is a class variable. OP has no direct unavoidable tradeoff in a hybrid language that must maintain
support for class variables. However, they can easily be emulated compatibility and competitive performance with its non-object-
using global variables within the unit’s implementation section. oriented parent. It is nonetheless a shortcoming compared to pure
object languages such as SmallTalk or Eiffel. It limits the refine-
Properties. In OP, a property is a field that can be viewed and set ment and specialization of descendants to only those characteris-
at design time. The addition of properties, property sheets, and tics that the original class designer saw fit to make polymorphic.
property sheet editors to OP represents a significant extension
compared to other compiled object languages. There is no equiv- C++ allows methods to be declared in-line. This allows simple
alent in C++. methods, such as those that read or write a private data field, to
be invoked without the overhead of a function call (that must
Properties are also noteworthy because they are accessed indirect- create a stack frame and save the CPU’s register values). In-line
ly. Read and write methods provide a layer of code that encapsu- methods are essentially an optimized form of static binding.
lates a property’s state. They can be either simple references to a
data field or calls to functions that perform additional work, OP allows a method to be declared to be a class method. Class
such as maintaining referential integrity. Read and write methods methods, existing independently of any instance of the class, can
can easily be emulated in C++. be invoked even if no instances of the class have yet been creat-
ed, and are not allowed to access any of the data fields within the
Methods. Both OP and C++ allow the overloading of method class. In C++, a member function declared to be static is a class
names. Two or more methods within a class are allowed to use method. (Note that in OP a static method is statically bound,
the same name, provided that each method’s signature is whereas in C++, it’s a class method.)
unique. A method’s signature is determined by its name, the
data type of its parameters, and the data type of its return value. Delegation. OP allows an event to be handled not by a method
C++ also allows operators, such as +, -, =, and [], to be redefined within the receiver’s class, but by a method within an associated
for each class. OP does not allow operator overloading. class. In essence, message handling is “delegated” to another
class. The message receiver is usually a visual control, and the
The mechanisms for dispatching methods in OP and C++ clearly associated class is usually the form that contains the control. C++
reflect their origins as hybrid languages. Both languages allow has no direct support for delegation.
method calls to be either statically or dynamically bound.
Statically bound methods are non-polymorphic, can be resolved Access Control. Within an object’s declaration, both OP and
at compile time, and correspond to traditional function calls. C++ use the access control modifiers — private, protected,
The address of a static method can be stored directly in the code and public — to control the visibility of the object’s fields and
segment by the linker. On the other hand, dynamically bound or methods. In C++, a public field or method has global visibili-
virtual methods are polymorphic and can only be resolved at ty, a private field or method is visible only within that object’s
run-time, when the exact type of the object is known. methods, and a protected field or method is visible only with-

NOVEMBER 1995 Delphi INFORMANT ▲ 22


On the Cover

in that object’s methods or within the methods of its descen- inheritance versus multiple inheritance are widely debated (and
dants. In OP, a public field or method has global visibility, a this controversy is beyond the scope of this article). Multiple
private field or method is visible to all procedures and func- inheritance introduces into C++ complications (name clashes)
tions contained within that object’s unit, and a protected field and language features (virtual base classes) not present in OP.
or method is visible to all procedures contained within that
object’s unit or in the units that implement its descendants. Both languages allow the declaration of abstract classes. Abstract
C++ allows a class to grant methods in another class access to classes allow an interface to be defined for a concept that cannot
its private fields by declaring them to be “friends”. OP does meaningfully exist as a concrete object. The classic example is a
not have a friend directive, since all methods implemented graphics program in which TShape defines the common interface
within an object’s unit are automatically treated as friends. for the concrete classes TCircle, TRectangle, and TTriangle. An
abstract class is one whose declaration includes one or more
OP also adds the modifier published for properties that must be abstract methods.
visible at design time. It’s a kind of “super public”. In C++, a
field or method is private unless declared otherwise, whereas in Methods in OP are made abstract by adding the abstract
OP, it’s published unless declared otherwise. Although the terms directive to the method declaration. In C++, methods are
are identical and the concepts are similar, the details of access made abstract by adding the pure virtual qualifier ( = 0 ) to
control are somewhat different between OP and C++. the method declaration. In OP, abstract classes can be instanti-
ated and used, provided the abstract (undefined) methods are
References. In C++, a reference is a synonym or alias for not called. In C++, abstract classes can never be instantiated
something. References act similarly to pointers, but without — they can only be used as a base for deriving other classes.
the need for explicit de-referencing. References are used mostly
for passing arguments to functions, especially for operator Templates. Templates are used in C++ to define generic classes
overloading. OP does not have explicit references. However, in that can be instantiated for a variety of specific types. Templates
OP every object’s identifier is implicitly a reference. Viewed are especially useful for creating type-safe containers. For exam-
another way, OP doesn’t really have (local) objects, it has only ple, a linked list template could be used to create a list object
references (to dynamic objects). that accepts only triangles. With templates, type checking can
be performed at compile-time to ensure that every object added
There are some differences between references in OP and C++. to TList<TTriangle> is either a TTriangle or one of its descen-
For instance, in OP a reference always points to an object (i.e. dants. Delphi has no features for defining generic classes.
an instance of a class), whereas in C++, it may point to either
an object or a built-in data type. In OP, a reference may be nil, Run-Time Type Information. Both OP and C++ provide run-
but in C++, a reference must always point to something. In OP, time type information (RTTI) on objects. OP uses the
a reference may be reassigned to point to a different object. ClassName, ClassType, ClassParent, and ClassInfo methods to pro-
However, a reference always points to the same object in C++. vide type information on an object. The is operator is used to
determine whether an object is of a given type or one of its
Constructors and Destructors. Both OP and C++ use constructor descendants. The as operator is used to perform type-safe casting.
methods to create and initialize new objects, and destructor methods In C++, the typeid operator returns a reference to the type_info
to destroy them and perform any required clean up. Both languages object that describes an object’s class, including its name. The
support constructor overloading, and both require (C++) or recom- dynamic_cast<> operator is used both to determine whether an
mend (OP) using virtual (polymorphic) destructors. Constructor object is of a given type and to perform type-safe casting.
overloading allows specialized constructors to be used in cases where
the object requires specialized initialization. Memory Management
Both OP and C++ are designed to create objects that use memory
Inheritance. Both OP and C++ allow a class to be specialized efficiently. Except for the addition of a pointer to the VMT for its
through inheritance. The descendant may add new data fields, but class, the size and memory layout of an object’s data fields are
may not remove any existing fields. The descendant may add new identical to that of the equivalent record (OP) or struct (C++).
methods and may replace (or override) existing methods. (Classes that are not polymorphic avoid even this overhead.)

Inheritance is implemented by appending any new fields to the end C++ supports three storage classes for allocating program vari-
of the parent object’s data record, appending any new polymorphic ables: static, automatic, and dynamic. Static objects are created in
methods to the end of the parent’s VMT, and replacing the address the program’s data segment, automatic objects are created on the
in the VMT of any inherited methods that have been overridden. stack, and dynamic objects are created on the heap. Static storage
is used for global objects, automatic storage is used for local
OP allows a descendant to inherit from only one ancestor. It objects, and dynamic storage is used for objects created on-the-fly.
uses a single-inheritance hierarchy that is rooted in TObject, the
ancestor of all objects. C++, on the other hand, allows a descen- C++ also separates the object construction process into two
dant to inherit from multiple ancestors. The benefits of single steps: memory allocation and initialization. Memory allocation

NOVEMBER 1995 Delphi INFORMANT ▲ 23


On the Cover

is performed by the new method, which can be both overrid- Both languages allow parameters to be passed either by value or by
den and overloaded. By allowing the use of customized memo- reference. In both OP and C++, parameters can be declared const
ry allocation routines, this provides considerable flexibility, to prevent the function from modifying their value. This allows
albeit at the cost of requiring the programmer to grapple with calls by reference to be used for efficiency without compromising
the low-level details of writing a custom memory manager. safety. (In OP, passing a const parameter by value or by reference is
decided by the compiler.) In C++, methods can also be declared
OP, by contrast, supports only dynamic objects. Local and global const. This guarantees that they do not modify any object’s fields.
objects can be declared, but in actuality, only the reference (point-
er) is stored in the data segment or on the stack. The object itself Both languages provide casts so that a variable of one type can be
must be manually created and is always stored on the heap. OP treated as if it were a different type. These casts can be used on
also does not allow custom memory allocation routines. All class- either primitive or user-defined types. Unchecked casts place the
es use the built-in heap manager that is optimized for both space burden of ensuring compatibility upon the programmer. In addition
and speed compared to the Windows GlobalAlloc function. to ordinary casts, C++ also provides specialized casts that give the
programmer finer grained control and make the intent of the cast
Neither language provides automatic garbage collection. The more obvious. These specialized casts include dynamic_cast<>, stat-
programmer is responsible for tracking and deleting any objects ic_cast<>, reinterpret_cast<>, and const_cast<>. In OP, the is and
created dynamically. as operators must be used together to perform type-safe casting.

Type Checking All in all, the type safety of C++ has improved to the point
Both C++ and OP use static type checking as the primary where it is now essentially equal to that of OP. This is a major
means of verifying that a program is internally consistent. All change from the relative positions of C and Pascal.
identifiers must be explicitly declared before they are used. All
assignments, expressions, and function calls are checked for Exception Handling
type compatibility. Type checking is done at compile-time Both OP and C++ use exception handlers to separate the code
rather than at run-time. that handles errors from the code that represents the normal
flow of control. The code to be protected is enclosed within a
Both languages require that the identifiers used for variables try block and followed by an exception handling block.
and constants be explicitly declared. However, OP requires Functions that detect an error will either raise (OP) or throw
that all variables and constants be declared in special sections (C++) an exception. If the caller is not prepared to handle (or
at the top of the sub-program (const and var). On the other catch) the exception, then it will be propagated upwards through
hand, C++ allows them to be declared at the point in the code the chain of exception handlers that may have been installed by
where they are first used. C++ allows a variable to be initial- higher-level callers. If the exception is not caught by a user-
ized as part of its declaration, while OP allows this only for installed handler, then it will be caught by the default handler.
“typed constants” (which really aren’t constant). If a variable or In OP, the default handler displays a message box describing the
constant is an object, C++ will call the constructor specified by error. In C++, the default handler terminates the program.
the initialization expression, or the default constructor if no
initialization is provided. In OP, declaring an object variable In addition to the try...except construct, OP also provides the
only allocates space for the reference pointer. It neither creates try...finally construct. The difference is that the statements in the
nor initializes the object. finally block do not constitute an exception block and are executed
whether or not an error occurs. This is useful for ensuring that allo-
Both languages require that the identifiers for functions be cated resources are released regardless of the success or failure of the
explicitly declared and that the declarations include a list of code in the try block. C++ has no structural equivalent to try...final-
the function’s parameters and their data type. (OP makes a ly, but relies instead upon a strategy of “resource acquisition is ini-
distinction between functions and procedures, but a procedure tialization”, wherein the destructors of local objects (storage class
is just a function with a return type of “void”.) The combina- “automatic”) are used to release any resources that were acquired by
tion of a function’s name, returned data type, number of para- their constructors. The destructors will be called as the stack
meters, and sequence of parameter data types determines its unwinds, regardless of whether it is being unwound because an
“signature”. It is an error in either language to call a function exception was raised or because the function completed normally.
without the correct number or sequence of parameters. In this
respect, C++ is much stricter than its parent, which originally Both languages treat exceptions as objects and implement a hier-
performed no parameter checking at all. For compatibility archy of exception types. This allows a generalized exception
with C, both languages allow a function to be explicitly handler to catch any of a variety of specialized exceptions.
declared to accept a variable number of parameters. C++ also
allows a default value to be specified for each parameter, which Modularity
allows an abbreviated parameter list to be used for simple calls Both OP and C++ allow the source code for a large program to
to a function that sometimes requires many parameters. OP be divided into individual files that can be separately compiled. In
does not support default parameter values. Delphi, the program is divided into units (these are similar to

NOVEMBER 1995 Delphi INFORMANT ▲ 24


On the Cover

modules in Modula-2 and packages in Ada). A unit consists of a objects to be specialized through inheritance, but allow only
public interface and a private implementation. The public part of those methods originally declared as virtual to be made poly-
a unit is imported into another unit through the uses directive. morphic. Both use the access control modifiers private, pro-
The explicit separation of interface and implementation allows tected, and public to control the visibility of an object’s fields
the compiler to manage dependencies between units and to auto- and methods. Both use strict type checking at compile time as
matically recompile only those units that are affected by a change. the primary means of verifying that a program is internally
Implementation sections also provide a level of enforced privacy consistent. Both treat exceptions as objects, use inheritance to
that is not available in C++. Through the use of nested subpro- implement a hierarchy of exception types, and pass exceptions
grams, OP also supports finer grained modularization than C++. from the innermost scope outwards until a handler is found.
Lastly, both languages provide for the separate compilation of
A C++ program consists of header files and source files. The program modules and support reuse through object libraries.
header files typically contain the interface definitions, and the
source files contain the implementation. However, this sepa- The most significant features in C++ that are missing in
ration is not enforced by the language, and the contents of a Object Pascal are templates, multiple inheritance, operator
source file have equal visibility to the contents of a header overloading, in-lined functions, the ability to allocate objects
file. C++, like C, does not support nested functions. It does on the stack (“automatic”) or in the data segment (“static”),
support nested classes, but these are generally less useful. and the ability to override the memory allocation operator
(new). The features in Object Pascal that are missing in C++
ANSI/ISO C++ provides namespaces to assist in the construction are published properties that can be viewed and set at design
of large programs and in the use of libraries. This provides a pow- time, delegation, nested subprograms, and modules (“units”).
erful mechanism for managing namespace pollution and for Neither language provides automatic garbage collection, and
ensuring that identifiers are not “silently” re-declared. Units in both are handicapped by gaps in their standard object
OP provide a similar form of encapsulation for identifiers libraries. C++ has the edge in portability, but for Windows
declared within the interface part. (Identifiers declared within the programming, Delphi provides a development environment
implementation part are, of course, completely private to that that is unsurpassed for convenience and speed.
unit.) However, the rules of unit scope mean that the resolution
of clashing names is dependent upon the sequence of units listed Lastly, in spite of their similarity in features, there are signifi-
in the uses clause. Changing the sequence of items in the uses cant cultural differences between Object Pascal and C++.
clause can (silently) change the meaning of an OP program. Both languages are hybrids created by grafting object-oriented
features onto popular 3GLs, but the philosophical founda-
Lastly, OP has introduced the concept of initialization sections tions of their parents are quite different (see Figure 1). For
that are executed during program start up. This is useful for ini-
tializing library routines. A similar effect can be achieved in C++ Pascal was designed: C was designed:
by using constructors for static objects, but this can get tricky.
for clarity, safety, and modularity. for direct manipulation of raw
memory with minimal overhead
Portability in space and time.
C++ is available on many platforms, while Delphi is currently
available for only one. If portability is a primary concern, howev- as a high-level language with as a medium-level language
direct support for multi-level that is close to the machine.
er, C is much more portable than either C++ or OP. modularization and data
abstraction.
The limited portability of C++ is due to two factors. First, the lan-
to protect the programmer. to trust the programmer.
guage itself has undergone many revisions, some quite recently.
Many implementations of C++ lag behind the feature set of the to teach applications for professional systems
ANSI/ISO standard by as much as five years, lacking major fea- programming. programmers.
tures such as templates and exception handling, not to mention
Figure 1: Original design intentions for Pascal and C.
new-style casts, RTTI, and namespaces. Second, most object-ori-
ented programs use third-party class libraries that are not portable. example, for nearly 20 years Pascal was the premier language
Even after the ANSI/ISO standard library for C++ is completed for teaching structured programming. C was, and still is, the
and becomes widely available, there will be problems with library best “portable assembler”. Although their object-oriented off-
portability. This is because the standard library does not cover spring have converged significantly, these cultural differences
such key areas as graphical user interfaces and database access. are still quite evident. They should not be ignored. ∆

Conclusion
In summary, Object Pascal provides most of the object-orient- Richard Holmes is a senior programmer/analyst at NEC Electronics
ed programming features of C++. Both languages are hybrids in Roseville, California, where he designs and develops client/serv-
that implement object-oriented programming through the use er database applications. He can be reached on CompuServe at
of virtual method tables for polymorphic methods. Both allow 72037,3236.

NOVEMBER 1995 Delphi INFORMANT ▲ 25


DBNavigator
Delphi / Object Pascal

By Cary Jensen, Ph.D.

The BatchMove Component


Copy, Delete, Append, and Update Data
with this Versatile Component

t’s often overlooked when the Data Access page on the Component Palette

I is mentioned, but contrary to general perception, the BatchMove component


can play an important role in database applications created with Delphi.

The capabilities of the BatchMove component appear simple enough. It permits you to move or
copy records from a DataSet to a table. However, this simplicity belies its usefulness. Like a SQL
INSERT query, BatchMove can be used to insert records from a DataSet into an existing table.
Unlike an INSERT query, however, the table you copy the records to doesn’t need to exist.

But this is just the beginning. There are four major capabilities of the BatchMove component: cre-
ating a table and placing the current records of a DataSet in it, deleting records from a table that
correspond to those in a DataSet, inserting records from a DataSet to a table, and updating exist-
ing records in a table based on those in a DataSet.

Before examples of these operations are highlighted, let’s consider the essential properties and
methods of this component.

Using BatchMove
There are three essential properties for using the BatchMove component: Source, Destination,
and Mode.

First, the Source property can be assigned any DataSet component. Therefore, you can assign either
a Table, Query, or StoredProc component name to this property. While any Table component is
acceptable, you would only assign one of the other DataSet descendants to this property if they
return a cursor to a DataSet. For example, it would be reasonable to assign a Query component
containing a SQL SELECT statement to the Source property, but it wouldn’t make sense to assign
a Query containing an ALTER TABLE statement.

Second, the Destination property is always assigned a Table component. This table is where the
records of the source DataSet are copied, deleted, inserted, or updated.

Third, the Mode property defines the type of operation performed by the BatchMove compo-
nent. Figure 1 shows the five modes. It also shows whether a table assigned to the Destination
property must exist before calling BatchMove’s Execute method, and if the destination table
must be indexed.

NOVEMBER 1995 Delphi INFORMANT ▲ 26


DBNavigator

Mode Destination Must Be


Must Exist? Indexed?

batAppend (default) No No
batAppendUpdate Yes Yes
batCopy No No
batDelete Yes Yes
batUpdate Yes Yes

Figure 1: The types of operations performed by BatchMove.

Creating a Table
One of the simplest and more common uses of BatchMove is to
create a new table containing the records returned by a Query or
StoredProc.
procedure TForm1.Button1Click(Sender: TObject);
As an example, the form in Figure 2 provides a memo field begin
where a user can enter a SQL SELECT statement. The results of if Query1.Active = False then
this query — executed against the database selected in the Alias Exit;
if SaveDialog1.Execute then
combobox when the Execute Query button is clicked — are dis- begin
played in the Query Result DBGrid. Table1.TableName := SaveDialog1.Filename;
with BatchMove1 do
begin
After executing the query, the results can be written to a new table Source := Query1;
by clicking the Copy Result to Table button. The Object Pascal Destination := Table1;
code associated with this button is shown in Figure 3. First, the code Mode := batCopy;
Execute;
ensures the Query component is active. If so, it displays the Save ShowMessage(IntToStr(MovedCount) +
File common dialog box using a SaveDialog component. If the user ' records copied');
selects or enters the file name to copy the query result records to end;
end;
(indicated when the SaveDialog’s Execute method returns True), the end;
selected file name is assigned to the Table component Table1.
Figure 2 (Top): The BATDEMO project. This project permits a user to
Next, BatchMove’s Source property is set to Query1, its enter a SQL SELECT statement, execute it, and then copy the results to
a new table. Figure 3 (Bottom): The OnClick event handler for the
Destination property is set to Table1, and its Mode property to
Copy Result to Table button.
batCopy. Its Execute method is then called to initiate the copying.
Finally, a message is displayed that indicates how many records When RecordCount is set to its default value, 0 (zero), all
were copied based on the BatchMove’s MovedCount property. records referred to by the source DataSet are processed by the
BatchMove’s Execute method. When you set this property to
When the Mode property is set to batCopy, BatchMove creates any positive integer, that number identifies the maximum
the destination table if it does not already exist. (This is also amount of records BatchMove will process during any one call
true when Mode is set to batAppend, despite what it says in to its Execute method.
the on-line help description.) If the destination table exists,
it’s replaced by the new table when Mode is set to batCopy, Using a Table as a Source
and added to it if Mode is set to batAppend. In each case While the BatchMove Source property is often assigned a Query
where Mode is set to batCopy, the destination table is not component, it is also useful to assign a Table component to this
keyed. To apply an index to this table, you must use the property. Several characteristics of such a table are important in
AssignIndex method of the TTable class. BatchMove’s execution, including index and range.

Under normal conditions, all records in the source DataSet are Either a primary or secondary index defines the ordering of
copied to the destination (see the discussion of table ranges in records in a table component. For certain types of BatchMove
this article). There may be times that you want to place an upper operations, such as batDelete, batUpdate, and batAppendUpdate,
limit on the number of records that BatchMove can process. For it’s necessary to assign an index to the source table, and a corre-
example, if the source DataSet has the potential of containing a sponding index to the destination table. This permits
large DataSet (say, in the millions of records), and the user can BatchMove to match the records in this table for deleting or
request that these records are processed by BatchMove, you may updating the destination table records. Any index defined for
want to limit the number of records to be copied. You can do the source table when batCopy is the mode, defines the order of
this with the RecordCount property. records in the destination table.

NOVEMBER 1995 Delphi INFORMANT ▲ 27


DBNavigator

A range defines a restriction on the records available in a table.


For example, even though a table may contain all sales records
for the past five years, it is possible to define a range that
includes only those records from a single year. You can apply a
range using either the Table method, SetRange, or the Table
methods: SetRangeStart, SetRangeEnd, and ApplyRange.

When a range is defined for the source table of a BatchMove


operation, only those records in the defined range are
processed. If the Mode is batCopy, for instance, only the
records in the defined range are copied to the destination
table. Consider this example: If you have defined your Sales
table as the source table and set a range to include only
records from a given year, only records that lie within the
range will be copied to the destination table.

The use of BatchMove where the source table has an applied with Table1 do
begin
range is demonstrated in the project BATRDEMO (see Figure 4). EditRangeStart; { Set the beginning key }
This table is the Employee table from the alias, DBDEMOS. Fields[0].AsInteger := StrToInt(Edit1.Text);
This alias points to a directory of example data installed when a EditRangeEnd; { Set the ending key }
Fields[0].AsInteger := StrToInt(Edit2.Text);
complete installation of Delphi is performed. ApplyRange; { Tell the dataset to establish
the range }
When a range is applied to this table and the Move Records end;

button is clicked, only records in the currently selected range


are copied to the destination table. The code that defines the Figure 4 (Top): This project permits you to define a range on the
employee number field to restrict which records are referred to by the
range is shown in Figure 5, and the following code copies the
table. After applying a range, using BatchMove to copy records from
records: this table will copy only those records in the defined range. Figure 5
(Bottom): Defining the range.
if SaveDialog1.Execute then
begin
8) Assign the Archive table component to the Source property.
Table2.Tablename := SaveDialog1.Filename;
BatchMove1.Execute; 9) Assign the Sales table component to the Destination table
end; property.
10) Set the Mode property to batDelete.
Deleting Records 11) Call BatchMove’s Execute method.
Although not obvious by its name, BatchMove can delete records
from the destination table. Both source and destination tables Moving Records to an Existing Table
must use a compatible index, and the Mode property must be set Using the Mode, batAppend, you can add records from a DataSet
to batDelete. Under these conditions, any record in the destina- to an existing table. This operation is more complex than simply
tion table with indexed field values matching those of the source creating a new table, since the records added must conform to
table record will be deleted when BatchMove is executed. the rules defined for the destination table. For example, if the
destination table is keyed, there may be one or more records in
This feature is useful for archiving records. For example, imagine the source table with key field values that duplicate those in the
you want to keep only the current year’s sales in the Sales table. destination table. Also, a source table record may contain values
Once a year it’s necessary to copy last year’s records to an archive that conflict with table integrity rules (e.g. required fields), or
table, and then remove them from the Sales table. This is easily other data rules (e.g. minimum or maximum acceptable values).
done by following these steps:
1) Assign a Table component to the Sales table. The BatchMove component has a number of methods that
2) Set a range on the Sales table to include only those records enable you to control what should happen if a problem
prior to the current year. occurs during execution. Using the AbortOnKeyViol and
3) Assign the Sales table component to BatchMove’s Source AbortOnProblem properties, you can instruct BatchMove to
property. terminate operation if a corresponding problem is encoun-
4) Assign another Table component to the archive table. tered. Using the properties, KeyViolTableName and
5) Set the BatchMove Mode property to batAppend. ProblemTableName, you can enter the name of a Paradox table
6) Call the BatchMove component’s Execute method. that BatchMove will create if a problem does occur.
7) Remove the range from the Sales table component (calling
SetRangeStart, SetRangeEnd, and ApplyRange without defining Problem records encountered during BatchMove’s execution are
a range removes a range). placed in one of the tables specified by the KeyViolTableName

NOVEMBER 1995 Delphi INFORMANT ▲ 28


DBNavigator

and ProblemTableName properties. For example, any records that of the move. For example, regardless of how many fields there are
would generate a key violation (attempted duplication of destina- in the source and destination tables, if you only want to move the
tion key field values) are placed in the table specified by the values stored in the source table field named Account_Number to
KeyViolTableName property. If AbortOnKeyViol is set to True, one the destination table field named Account_Number, add the text
record appears in this table if a key violation is encountered. If Account_Number to the Mappings property. Here’s an example:
AbortOnKeyViol is set to False, all records that would produce a
key violation are placed into this table. with BatchMove1 do
begin
Source := Table1;
Updating Tables Destination := Table2;
While batAppend permits you to insert records into an existing table Move := batAppend;
Mappings.Clear;
(but only if records using the same key do not already exist in the Mappings.Add('Account_Number');
destination), BatchMove also provides two modes that permit you Execute;
to update records in the destination table based on values stored in end;

the source. These modes are batUpdate and batAppendUpdate. Using


batUpdate, any records in the destination table whose current index The second form you can use with the elements of the Mappings
values exactly match those same index values in the source table will list is to define field-name pairs. These field names appear sepa-
have non-indexed field values updated by those corresponding fields rated by an equals sign (=). There is a destination field name on
in the source table. Using this mode, source table records with no the left-hand side of the equals sign and a corresponding source
corresponding records in the destination table are ignored. The table name on the right. Data is only transferred between fields
index may be either primary or secondary. when field-name pairs are provided. The code in Figure 6 moves
only those fields of the source table specified by the names on
The batAppendUpdate mode works similarly to the batUpdate mode, the right of the equals sign to the destination fields on the left.
with one important difference. Records in the source table with no
with BatchMove1 do
corresponding records in the destination table are appended to the begin
destination. Therefore, when the mode is batAppendUpdate, all Source := Table1;
source table records either update existing records, or are added to Destination := Table2;
Move := batAppend;
the destination table. Mappings.Clear;
Mappings.Add('Student_ID=ID');
Unlike the batAppend mode, there are no key violations when Mappings.Add('Last_Name=LNAME');
Mappings.Add('First_Name=FNAME');
the batAppendUpdate or batUpdate modes are used. However, Mappings.Add('Address=STREET');
problem records are still possible. Mappings.Add('City_CITY');
Mappings.Add('State/Prov=STATE');
Mappings.Add('Country=ORIGIN');
Following the execution of BatchMove using either the Mappings.Add('Postal_Code=ZIP');
batAppendUpdate or batUpdate modes, you can use the Execute;
ChangedCount property to determine how many records were end;
updated. Furthermore, if you assign a value to the
Figure 6: Using Mappings with field-name pairs.
ChangedTableName property, a copy of each record with a
changed value is placed into a Paradox table of that name.
Conclusion
Mapping Tables The BatchMove component is a remarkably flexible tool for
It is possible to use BatchMove when source and destination transferring and updating data between tables. It’s also an essen-
tables do not have identical structures. By default, BatchMove tial tool for creating permanent tables from the result sets
attempts to add or update records between the source and des- returned by SELECT queries and stored procedures. ∆
tination on a field-by-field basis. If the field types do not corre-
spond exactly, a best-fit is attempted. For example, if the third The demonstration projects referenced in this article are available on the
field of a destination table is a seven-character text field, and 1995 Delphi Informant Works CD located in
the same field of the source table is 10 characters, values longer INFORM\95\NOV\CJ9511.ZIP.
than seven characters are truncated when the move is executed.

BatchMove also allows you to move only a subset of fields or Cary Jensen is President of Jensen Data Systems, Inc., a Houston-based database
data between fields that are not in corresponding positions with- development company. He is a developer, trainer, and author of numerous books on
database software. You can reach Jensen Data Systems at (713) 359-3311, or
in the source and destination tables. This is done using the through CompuServe at 76307,1533.
Mappings property.

Mappings is a StringList property. It can contain a list of text val-


ues that can take two forms. The first form is to include in each
element of Mappings the field name you want to process as part

NOVEMBER 1995 Delphi INFORMANT ▲ 29


Visual Programming
Delphi / Object Pascal

By Douglas Horn

The ObjectBrowser
An Introduction and Visual Tour

magine getting a fantastic deal on a new car. Then you discover that not

I only does it handle like a dream, it also sports a computerized map. The
salesman didn’t tell you it was there, the owner’s manual only mentions it
in passing, and you didn’t pay extra for it. The only hitch is, no one tells you
how to use it.

If this scenario sounds far-fetched, consider the Delphi ObjectBrowser: a powerful tool that enables
you to inspect applications, as well as Delphi and Windows (see Figure 1). Unfortunately, Delphi’s
documentation on the ObjectBrowser is sparse. This article will demonstrate the ObjectBrowser’s
various features and show you how to use it.

Symbols
The ObjectBrowser works with
symbols. For its purposes, a
symbol is just about anything in
a Delphi application. For
example, a form, a button on
that form, and a property of
that button, are symbols the
ObjectBrowser can examine.
Anything Delphi can read,
write, or execute — a constant,
variable, types, property, proce-
Figure 1: Delphi’s ObjectBrowser allows developers to inspect objects
dure, etc. — is a symbol. from their applications, Delphi, and Windows.

Developers can choose from three main categories of symbols to search with the ObjectBrowser:
objects, units, and globals:
• Objects include those objects used within a Delphi application (e.g. forms, controls, proce-
dures, and variables).
• Units consist of the class libraries that make up objects.
• Globals are symbols that exist throughout the current application, or outside of it, in Delphi or
the Windows API.

The ObjectBrowser can explore these symbols, provided that certain conditions exist (discussed
later in the article). This makes the ObjectBrowser a powerful tool for understanding the applica-
tions we develop with Delphi, as well as Delphi and Windows.

NOVEMBER 1995 Delphi INFORMANT ▲ 30


Visual Programming

The ObjectBrowser Compiler page of the Project


Before exploring the ObjectBrowser, it’s important to understand Options dialog box).
its parts. In many respects, the ObjectBrowser is a simple tool.
The interface consists of a main screen, two dialog boxes, a The Show buttons at the top
SpeedMenu, and a few other controls. left of the ObjectBrowser con-
trol which symbols are shown
The ObjectBrowser’s primary (see Figure 6). By selecting or
control is the Inspector pane deselecting a button, a filter is
on the left side of the win- applied to both the Inspector
dow (see Figure 2). It lists the pane and the Scope page of
Figure 5: The References page of
symbols in the area the the Details pane. This allows
the Details pane shows where
ObjectBrowser is currently symbols appear in program code. users to quickly search for the
inspecting. (The area’s name various types of symbols.
appears on the Title bar.)
Double-clicking on a symbol To the right of
causes the ObjectBrowser to the Show but-
inspect the represented Figure 2: The Inspector pane lists tons are naviga- Figure 6: The 11 Show buttons control the types
information about the object being of symbols the ObjectBrowser will display. From
object, and moves the tion controls for left to right, they are: Constants, Procedures or
inspected.
ObjectBrowser one step fur- returning to pre- Functions, Types, Variables, Properties, Inherited,
ther down the inheritance tree. vious symbols: Virtual, Private, Protected, Public, and Published.
the Back and History buttons.
The Details pane, on the right
side of the ObjectBrowser, dis- Clicking the Back button (the left-pointing arrow) moves the
plays information about the focus of the Inspector pane to the last object inspected — usual-
symbol selected in the ly one step back up the inheritance tree. Clicking the History
Inspector pane, and consists of button calls a list of previously inspected objects (see Figure 7).
a three-page tabbed notebook. Double-clicking on any entry automatically moves the Inspector
The first is the Scope page (see pane back to that object.
Figure 3), which lists all the
symbols associated with the
symbol in the Inspector pane.
Figure 7: The
The second is the Inheritance
History list allows
page (see Figure 4), which dis- the user to quickly
plays a collapsible tree of return to previ-
object hierarchies. It is a useful ously browsed
“touchstone” showing where objects.
the current symbol lies in the
scheme of the application.

The third is the References


page (see Figure 5), which
Figure 3 (Top): The Scope page
shows where symbols appear in
of the Details pane shows all the
symbols associated with the sym- program code. It lists all
bol in the Inspector pane. Figure instances of the symbol in the The status bar of the ObjectBrowser is referred to as the Info
4 (Bottom): The Inheritance page program, including the code Line. It displays information about the current object in the
of the Details pane displays a col- file and line number (provided Inspector pane or in the Scope page of the Details pane,
lapsible tree of object hierarchies. depending on which is active.
the symbol is within a unit
compiled with the Symbol info parameter as we’ll discuss). This
page offers a direct link to the symbol within the code. Simply The SpeedMenu
select the reference in the Details pane and press M to high- The ObjectBrowser has no main
light the corresponding line in the Code Editor, or double-click menu, but uses a simple
on the reference to move there directly. SpeedMenu of eight commands
(see Figure 8). Like most
The ObjectBrowser can show many types of symbols: SpeedMenus, it is accessed by
Constants, Procedures, Types, Variables, and Properties. It right-clicking anywhere within
can show statements from the Private, Protected, Public, and the ObjectBrowser window, or Figure 8: The ObjectBrowser’s
Published sections of the code (if this is enabled on the by pressing A0. SpeedMenu.

NOVEMBER 1995 Delphi INFORMANT ▲ 31


Visual Programming

The first three commands on one of the Show buttons causes a hint message to appear.
control the types of informa- When Info Line is selected, the Info Line is visible. Deselecting it
tion displayed in the causes it to disappear.
Inspector pane. As shown in
Figure 9, Objects displays an Enabling and Configuring the ObjectBrowser
inheritance tree for the appli- For the ObjectBrowser to work properly, certain Delphi program
cation being browsed. The options must be selected. These are found on the Project Options
inheritance tree allows the dialog box. To access them, select Options | Project from the
developer to inspect the over- Delphi menu, then select the Compiler page (see Figure 12).
all structure of the various
Figure 9: The Objects SpeedMenu Figure 12:
components, procedures, and item displays an inheritance tree in To enable
properties in an application. the Inspector pane. the full use of
ObjectBrowser,
Selecting the Units com- select Debug
mand lists all the applica- Information,
Local
tion’s units in the Inspector symbols,
pane (see Figure 10), while and Symbol
selecting the Globals com- info on the
mand displays the global, Compiler
Delphi, and Windows API page of the
Project Options
symbols used in the current dialog box.
application (see Figure 11).

Figure 10: The Units SpeedMenu The Symbol command has In the Debugging group there are three options: Debug infor-
item lists all the application’s units in the same effect as the mation, Local symbols, and Symbol info. To get all the infor-
the Inspector pane.
Search | Browse Symbol mation the ObjectBrowser can provide, select all three options.
command from the Delphi main menu. It allows the user to
search for a specific symbol throughout the current application. Debug information allows the ObjectBrowser to browse sym-
bols that are declared in the implementation section of the
The next two SpeedMenu program modules. If this option is not selected, ObjectBrowser
commands affect the appear- only sees symbols from the interface part. Local symbols
ance of items in the Inspector allows the ObjectBrowser to read those symbols declared local-
and Detail panes. When ly within program routines (the implementation part).
Qualified symbols is enabled,
it displays each symbol with its When Symbol info is not selected, the ObjectBrowser sees only
qualified identifier (i.e. its symbols declared in the interface part of the module. (It still
more complete name in dot sees other symbols in the implementation section, provided they
notation). For example, the are not declared there.) When enabled, the Symbol info option
symbol ClassName:String allows the ObjectBrowser to display line numbers in the
Figure 11: The Globals
with its qualified identifier is References page of the Details pane, and jump directly to the
SpeedMenu item displays the global,
TObject.ClassName: Delphi, and Windows API symbols selected line of code while browsing an object. However, neither
String. Although this nota- used in the current application. Local symbols nor Symbol info have any effect unless the
tion occupies more space, it is Debug Information option is selected.
easier to understand.
Note: Delphi’s on-line help is confusing in this regard. Under the
When checked, the Sort always command sorts symbols alpha- topic “Enabling the ObjectBrowser,” it mistakenly reverses the
betically. If unchecked, the symbols are listed in the order they definitions for Local Symbols and Symbol info.
are declared in the application. If both Qualified symbols and
Sort always are enabled, the symbols will be sorted by their Using the debugging options increases the size of compiled
names and not their qualified identifiers. Therefore, .DCU files, but is almost always worthwhile for its debugging
TObject.ClassName: string will come alphabetically before value. Turning the options off shrinks the re-compiled .DCU
Exception.Create(const string) because the qualified file. The debugging options have no effect on the size of exe-
identifiers TObject and Exception are ignored. cutable (.EXE) program files.

The last two SpeedMenu commands are Show Hints and Info Since the debugging information is stored in the project’s .DCU
Line. These control the behavior of ObjectBrowser’s “helping file, once the debugging options are selected, the project must be
hands”. When Show Hints is activated, resting the mouse cursor compiled or re-compiled for them to take effect. The

NOVEMBER 1995 Delphi INFORMANT ▲ 32


Visual Programming

ObjectBrowser receives its information from this file. Therefore, if those lines. Note however, that if a reference is modified to no
the current project has not been compiled, the ObjectBrowser will longer occur on the same program line, the ObjectBrowser can-
not run, and the View | Browser Delphi menu option is disabled. not move directly to it again until the project is re-compiled.

The ObjectBrowser options offered on the SpeedMenu can be Here’s another possibility: If you want to figure out exactly what’s
configured via the Environment Options dialog box. From the going on with some aspect of your program — say the Popup
menu, select Options | Environment and the Environment Menus — select Objects from the ObjectBrowser’s SpeedMenu
Options dialog box is displayed. Choose the Browser page (see to get an object hierarchy tree. Now move through the levels from
Figure 13). These settings control the default appearance and TObject to TPersistent to TComponent, TMenu — all the way to
behavior of the ObjectBrowser. TPopupMenu. With TPopupMenu selected, choose the References
page of the Details pane and go to the first reference listed. This
Figure 13:
Use the
should be the declaration statement in the type section of the
Browser code. If so, it lists the name corresponding symbol (e.g.
page of the PopupMenu1: TPopupMenu;). From here, browse the symbol
Environment directly and repeat it for each TPopupMenu reference until you
Options find what you’re looking for.
dialog box to
configure the
ObjectBrows The ObjectBrowser is also an excellent self-guided learning
er’s default tool that takes you as deep into the inner-workings of Delphi
appearance and the Windows API as you dare go. For example, this allows
and a developer to find the values of all the Delphi and Windows
behavior.
API constants. Such knowledge can be used for silly things,
like rendering source code practically unreadable to other pro-
The Symbol filters group contains 11 check boxes that corre- grammers by replacing commonly-used constants with their
spond to the 11 Show buttons. The check boxes selected here actual numerical values. (It works, but why bother?)
will appear as depressed Show buttons in the ObjectBrowser.
The Initial view group of radio buttons controls what will be It’s useful for more practical purposes, as well. As an example,
shown in the Inspector pane at opening: Objects, Units, or select Units from the SpeedMenu and select Controls in the
Globals. Likewise, the Qualified symbols and Sort always Inspector pane. Then search for the values of the cursor con-
options in the Display group have SpeedMenu commands. stants. (Typing cr takes you right there.) The various cursor
constants are listed (e.g. crArrow, crDefault, crNone, etc.). Funny,
Finally, there is the Object tree group. Entering an object name crNone never appears in the Object Inspector as a possible listing.
(or series of object names separated by semi-colons) into the
Collapse Nodes field instructs the ObjectBrowser to initially Now try this: Create a one-form project and instead of selecting
collapse those nodes on the object hierarchy tree. one of the Object Inspector’s listed constants for the Cursor
property, enter -1, the value found for crNone using the
The options selected from the Environment Options dialog box ObjectBrowser. (Typing crNone returns an error.)
take effect only after the ObjectBrowser is re-opened. The excep-
tion is the Display group — Qualified symbols and Sort When you run the form, the cursor is invisible. This capability
always. These commands take effect immediately when the isn’t apparent from the Object Inspector, and who’s to say you
ObjectBrowser is already running. won’t need it some day?

Using the ObjectBrowser Conclusion


This brings us to the fun part — using the ObjectBrowser. Its This is only a small example of what you can find using the
usefulness is nearly limitless and becomes more helpful as your ObjectBrowser. (crNone is a documented constant, but difficult
developer skills increase. to find in the documentation.) Who knows what other hidden
pearls lurk in the depths of Delphi? One thing’s for sure — the
The most common way to use the ObjectBrowser is to start at the ObjectBrowser is the way to find them. ∆
Code Editor and select Search | Browse Symbol from the menu.
This is useful for finding all other incidences of a particular con-
Douglas Horn is a free-lance writer and computer consultant in Seattle, WA. He spe-
stant, variable, or procedure. For example, when working with a cializes in multilingual applications, particularly those using Japanese and other Asian
variable, it can be very convenient to find all the lines dealing with languages. Douglas is also a Contributing Editor to Delphi Informant. He can be
that variable (from the time it was declared to the present). reached via e-mail at internet:[email protected].

By searching for the symbol and then selecting the Detail pane’s
References page, the developer can view all files and line num-
bers where the variable appears. This even allows direct access to

NOVEMBER 1995 Delphi INFORMANT ▲ 33


Informant Spotlight
Delphi / Object Pascal / Windows API

By Tom Costanza

One Bit at a Time


A Serial Communications Primer
and Delphi Implementation Guide

serial port is a cheap and easy way to connect two or more electronic

A devices. Every PC comes with at least one serial port. Most printers
allow for serial input, and an infinite number of bulletin board services
are accessible via a serial port.

The serial port is also used to transfer data from computer to computer with programs such as
LapLink. In an industrial setting, a PC can communicate with dedicated industrial automa-
tion equipment.

Support for Serial Communications: DOS vs. Windows


When Microsoft wrote DOS, they chose to include only minimal support for the asynchronous serial
port. Calls to DOS and the BIOS are provided to initialize the port, and read and write single char-
acters. However, there is no support for interrupt-driven buffered communication. Programmers are
forced to buy a third-party library, or write their own interrupt service routines. And having written
interrupt service routines, I can tell you that it’s no day at the beach. (For more information about
interrupts, see the sidebar “What Is an Interrupt?” on page 36.)

Microsoft mercifully corrected this omission with Windows’ feature-rich API (which we’ll dis-
cuss later). We’ll also look at a simple technique that enables the programmer to read (on
demand) any characters in the receive buffer, as well as send a string of characters.

In addition, we’ll cover a slightly more complicated technique that enables the programmer to
write an event handler to respond to interrupts from the serial port. These interrupts can be pro-
grammed to occur for a number of reasons, including: a character has been received and needs to
be processed; a modem status signal has changed state (e.g. the modem has answered the phone);
and, the transmit buffer is empty.

To understand the Windows API for communications functions, you must first understand how
serial communications is accomplished. Therefore, we’ll discuss generic serial communications, the
PC’s implementation of asynchronous serial communications, and the Windows API. Finally, we’ll
talk about how to implement all this in Delphi.

Serial Communications: A Primer


There are three generic types common to all forms of communications: simplex, half-duplex, and
full-duplex:
• Simplex communication is one-way only. An example of simplex communication is television.

NOVEMBER 1995 Delphi INFORMANT ▲ 34


Informant Spotlight

While you can see and hear the characters on a television


show, they can’t hear or see you.
• Half-duplex is two-way communication, but in only one
direction at a time. An example of half-duplex communica-
tion is the two-way radios used by police departments. The
dispatcher talks to an officer in a patrol car. Then, the dis-
patcher waits for the officer’s response.
• Full-duplex means both ends of the conversation can talk at
the same time. A telephone is an example of full-duplex
communication.

Serial communications is accomplished by varying the voltage on


a wire. The voltage can be one of two levels. The level for a “1”
or “MARK” is defined as anything between -5 and -15 volts, Figure 1: The character “A” with odd parity.
with -12 volts being nominal. A “0” or “SPACE” is defined as
anything between +5 and +15 volts, with +12 being nominal. the least significant bit is sent first and the parity bit is sent last.
Each time a new start bit is received, the receiver re-synchronizes.
If a transmitter were to just start varying the voltage on the
line, the receiver would soon become confused about where Baud Rate
one character ends and the next character begins. What is Baud rate is loosely defined as the transmission facility’s signal-
needed is a way to synchronize the receiver with the transmit- ing rate. For the purposes of this article, baud rate and bits-per-
ter. There are two techniques for this: synchronous and asyn- second represent the same thing. Therefore, this article will use
chronous communication. Synchronous communications is the term baud rate to refer to the number of bits-per-second
outside the scope of this article. Asynchronous communications transmitted from, or received by, the computer’s serial port.
is accomplished by re-synchronizing the receiver each time a
character is received. This is accomplished by framing each A common baud rate today is 9600. This means that bits are
character with start and stop bits. transmitted at a rate of 9600 bits-per-second. Note that this
does not mean that every second 9600 bits are transmitted. It
Start, Stop, and Data Bits means that one bit takes 1/9600 seconds (about 104 microsec-
With asynchronous communications, a character is sent by mak- onds) to transmit.
ing the wire sending data from the transmitter to the receiver
change from a 1 (MARK or idle state), to a 0 (zero or SPACE). For the receiver to sample the data line at the correct times, the
This is known as the start bit. Every character sent begins with a receiver and transmitter must agree on the baud rate. Therefore,
one-to-zero transition. Data bits are then sent, followed by one if 9600 baud is used, the receiver will sample the data line every
or more stop (MARK) bits. A stop bit is created by letting the 104 microseconds.
line remain idle, or quiescent, for 1, 1.5, or 2 bit times. A bit
time is the time it takes to transmit one bit. Parity
The ASCII character set contains 128 different characters. To
7
By letting the line remain idle for a period, and since a start bit have 128 unique codes, seven bits must be used (2 = 128).
is defined as the transition from idle to a MARK state, it is read- When this data is being transmitted over phone lines with
ily apparent to the receiver when a start bit has been received. modems, noise on the phone line can often change a 1 to a 0, or
When the receiver sees the one-to-zero transition, it waits for vice versa. While the noise can’t be eliminated, the errors caused
half a bit time and looks at the data line again. If the line is still by the noise can be detected.
zero, the receiver assumes a start bit has been received. If not, it
assumes noise caused the transition, and waits for another one- One technique for detecting these errors is to send an eighth bit,
to-zero transition. If a start bit has been received, the receiver called a parity bit. The transmitter and receiver must agree as to
samples the line once every bit time. what this parity bit will be. (This is why BBS systems say you
must set your communications port to a specific parity.) The
The data line’s state at the time of the sample is the next bit’s agreement is this: the transmitter will send an even or odd num-
value. The receiver can maintain synchronization for a short ber of 1’s per character. It’s inconsequential if the parity is even
period of time (the time it takes to receive one character) by or odd, as long as both sides agree.
sampling the data line once every bit time. If the sampled volt-
age is positive, the bit is a zero. The bit is a one if the sampled Let’s assume odd parity is used. When a character is sent by the
voltage is negative. transmitter, the transmitter sets the eighth bit, the parity bit, as
appropriate, to force an odd number of 1’s to be sent. For exam-
Figure 1 illustrates the transmission of a single character. For sim- ple, the character “A” has a binary value of 1000001. This value
plicity, logic levels rather than voltage levels are shown. Note that has an even number of 1’s, so the transmitter sends a 1 for the

NOVEMBER 1995 Delphi INFORMANT ▲ 35


Informant Spotlight

parity bit, making the total number of 1’s odd. The character
“C” has a binary code of 1000011. This code has on odd num- What Is an Interrupt?
ber of 1’s, so the transmitter sends a 0 for the parity bit — leav-
ing the total number of 1’s odd.
An interrupt is a piece of hardware’s request for attention
At the receiver, the number of 1 bits are counted and compared from the processor. Without interrupts, the programmer must
to the agreed parity. Suppose that noise on the phone line poll the device to determine if the device needs attention.
changes the code for the character “C” from 1000011 to Here’s an analogy: Suppose you’re at home reading a book
1010011 (i.e. the third bit has changed from 0 to 1). As stated and you want to know if anyone comes to the front door.
in the previous paragraph, the parity bit is 0. The receiver has One way would be to put down the book every minute or so,
received four bits that are set to 1. Since four is an even number, and open the door to see if anyone is there (polling). This
obviously wastes time, since usually no one is there. A more
and there’s agreement the number of bits set to 1 must be odd,
efficient way would be to install a door bell. Now you can
the receiver knows an error has occurred. keep reading your book until you hear the bell ring (inter-
rupt). You can then mark your place in the book and answer
If the number of 1 bits is ever even (when an odd parity was the door only when needed.
agreed upon), the receiver knows something is wrong, and gener-
ates a parity error. It should be obvious by now that this tech- When an interrupt occurs, program execution is suspended, and
nique works only if no errors occur, or the number of bits that the processor is directed to an interrupt service routine, a special
are inverted is an odd number (i.e. one bit is inverted, or three subroutine written to deal with the interrupt. When this routine
bits are inverted, etc.). has completed, the normal program execution is resumed.

If an even number of bits are inverted, the parity will still be cor- Anyone who has installed an interface card in a PC has had to
deal with interrupts. For serial ports, an interrupt may indicate
rect, even though the character received is not the character sent.
that a character has been received and must be processed,
It should also be apparent that it makes no difference whether a the transmit buffer is empty, or some modem status signal has
data bit is inverted, or the parity bit itself is inverted in transmis- changed state. The programmer usually has control over
sion. This form of error detection is crude at best. For reliable whether an interrupt will occur. If the programmer has enabled
data exchange, a more sophisticated method can be used. interrupts, then the next question to be answered is this: What
is allowed to cause the interrupt? For example, a program
Parity is only an option (on PC-style hardware) when seven data might want to be interrupted when a character is received, but
bits (or fewer) are used. When anything but text (e.g. a program, not if the transmit buffer is empty. This also is programmable.
or a Paradox data file) is sent serially, eight data bits are needed,
because each byte in the data can contain a value from 0 to 255. In the PC there are interrupt levels that denote the priority of
an interrupt. The higher the number, the lower the priority.
Serial port interrupts have a fairly high priority. While reading
The serial port in PC-style hardware will not let you send more
from a disk can be postponed for a second or two, a char-
than eight bits per character. If you use all eight bits for data, acter received at the serial port must be retrieved before the
there are no bits left to use for parity. So, if eight data bits are next character is received or the second character will over-
specified, parity is set to “NONE”. This is not much of a loss write the first. At 9600 baud, a character can be received
since, as discussed earlier, character-by-character parity checks are approximately every 960 microseconds.
not of much value.

For completeness, note that there are two other types of parity: transmitter can send characters. If not, the transmitter should
mark and space. With mark parity, the parity bit is always a mark suspend transmission.
(1), and with space parity, the parity bit is always a space (0).
This technique is sometimes used for half-duplex communica-
Flow Control and Handshaking tion, where one device tells another device, “I have finished trans-
Different serial devices operate at different speeds. For example, a mitting. Now I will receive and you can transmit.” It’s also used
computer can send characters to a printer at a rate far greater than when the two devices are connected by a “hard” cable (a continu-
the printer’s ability to print those characters. Therefore, it’s usually ous piece of copper from one end of the cable to the other).
necessary to provide some way of telling the transmitter that the Modems and phone lines don’t qualify. It can also be used with
receiver cannot currently receive any more characters, and the simplex communication. For example, the connection between a
transmitter should suspend transmission until further notice. computer and a serial printer can use this type of flow control.

There are two commonly used techniques for this. Hardware On the other hand, if you are sending data over a modem to
flow control uses voltage levels on one or more lines of the RS- another computer, and if full-duplex communication is possible,
232 interface. For example, the serial port can be configured so another form of flow control is usually employed. With this tech-
the clear-to-send (CTS) line is monitored to determine if it’s nique, when computer A’s receiver can’t accept any more characters
acceptable to transmit characters. If this line is set to one, the from computer B, computer A’s transmitter sends a special charac-

NOVEMBER 1995 Delphi INFORMANT ▲ 36


Informant Spotlight

ter (called XOff) to computer B. When computer B sees this char- you let your program talk directly to the hardware, you may
acter, it suspends transmission. Later, when computer A can again need to change it if the hardware changes.
accept characters, its transmitter sends another special character
(called XOn) to computer B. When computer B sees the XOn In Object Pascal (as well as earlier versions of Pascal) the com-
character, it knows to begin sending data again. This is called mand to read or write to an I/O register is Port[x] for byte val-
XOn/XOff flow control (the X is an abbreviation for transmit). ues, and PortW[x] for 16-bit (word) values, where x is the port
address to be read or written. (This syntax is well-noted in the
The PC’s Serial Port Turbo Pascal User Guide, but I have not found it in the Delphi
The original PC had an optional internal card known as the documentation.) The communications adapter registers are 8-
IBM Asynchronous Communications Adapter that enabled con- bits (1 byte) wide, so the command to read the modem status
nection to modems and other serial devices. Although this serial register at address $3FE is:
interface has evolved with the PC, and is now usually included
on the motherboard, the software interface has remained the val = Port[$3FE]

same for compatibility reasons.


The DSR bit is bit 5. To isolate that bit, we must perform an
There is a block of I/O address space reserved for the asynchro- AND operation with the value read from the register with a
nous communications adapters. The addresses range from $3F8 mask that has a 1 at bit 5, and 0’s at all other bit locations. In
to $3FF for COM1, and $2F8 to $2FF for COM2. A set of binary, this is 00100000; in hexadecimal it’s $20. Thus the
registers in this address space allow the programmer to config- statements:
ure the port, send and receive characters, and read and write
val := Port[$3FE];
modem control signals and status bits. (A register can be val := val AND $20;
thought of as a single memory location, although it’s separate
from the computer’s RAM.) will set val to 0 if DSR is low, or 32 ($20) if DSR is high. (For
more information about AND operations, see the sidebar
Most of these control and status bits are available through the “Masking Bits with the AND Operator” on page 38.)
Windows API. For example, the programmer can tell when the
DSR line changes state, but cannot read its current value. (DSR A better way (that is undocumented in the Windows Software
is an acronym for Data Set Ready. A complete listing of signals Development Kit) makes use of an extended device control block
used in serial communications is shown in Figure 2.) The DSR (or DCB). Within this extended DCB is a field called
signal is sent by a modem to its attached computer to indicate MSRShadow (modem status register shadow). This is a copy of
it’s ready to operate. the modem status register on the UART. MSRShadow is located
35 bytes past the event word for the desired port. The event
To obtain this signal’s current value, the programmer can word’s address is returned by the SetCommEventMask function
access the modem status register directly, and many DOS (which we’ll discuss later).
programmers will be tempted to do just that. This is a bad
idea, since one of Windows’ strengths is its device indepen- The following Object Pascal code reads the MSRShadow word:
dence. If the vendor of a new serial port uses some new hard-
ware, that vendor can supply a new device driver for the port, procedure TMainForm.GetMSR;
and your old program won’t need to be changed. If however, var x: PWord;
z: byte;
begin
{ Get pointer to event word. }
Signal Description Pin Number Pin Number x := SetCommEventMask(hCommPort,constCommEvents);
on 25-Pin on 9-Pin { MSRShadow byte is 35 bytes past this pointer. }
Connector Connector word(x) := word(x) + 35;
{ Get MSRShadow byte and display it. }
TxD Transmit Data 2 3 z := x^;
Edit2.Text := intToHex(z,2);
RxD Receive Data 3 2
end;
RTS Request To Send 4 7
CTS Clear To Send 5 8 Again, this code isolates the DSR bit:
DSR Data Set Ready 6 6
z := z AND $20;
SG Signal Ground 7 5
DCD Carrier Detect 8 1 (Additional information on the asynchronous communications
DTR Data Terminal Ready 20 4 adapters and register addresses can be found in the IBM Personal
RI Ring Indicator 22 9 Computer Technical Reference Manual.)

Figure 2: Signals used in serial communications with cable-connector Windows API Functions
pin numbers. Delphi can communicate with the serial port through the

NOVEMBER 1995 Delphi INFORMANT ▲ 37


Informant Spotlight

where x is the port number (e.g. ‘COM1,9600,N,8,1’), and the


TDCB variable that is passed by reference. Any fields in the
Masking Bits with the AND Operator DCB that are not specified in the parameter string are set to
their default values. This function does not set the COM port to
the settings specified in the TDCB variable. SetCommState does
Good programmers won’t waste a whole byte of memory to
store a logical (yes/no, on/off, etc.) value. Only one bit is
that. BuildCommDCB returns zero if successful. Otherwise, it
required. This means a programmer can store eight logical returns less than zero.
values (sometimes called flags) in one byte of memory.
SetCommState. This function sets the COM port to the set-
It’s clear that you need a A B A AND B tings specified in the TDCB variable. The TDCB variable is
way to isolate one particular the only parameter for this function. The API knows which
0 0 0
flag in a byte. This is done COM port to set because the COM port is specified in the
with the AND operator. The 0 1 0 TDCB variable itself. This function returns zero if successful.
truth table for the AND 1 0 0 Otherwise it returns less than zero.
operator is shown in Figure 1 1 1
A. The programmer masks
SetCommEventMask. This function enables selected events for
off every bit except the one Figure A: The truth table for the
of interest, and then com- AND operator.
the specified COM port. The two parameters are the ID of the
pares the result to zero. If the result is zero, the bit in question port (returned by OpenComm) and a mask for the appropriate
is 0. If the result is non-zero, the bit in question is 1. In Figure events. The mask should contain a bit set to 1 for each event to
B, bit 3 is the one we are interested in. be enabled. Enabled events are recorded in the event word.
GetCommEventMask will retrieve the event word.
Bit number 7 6 5 4 3 2 1 0
EnableCommNotification. This function enables or disables a
Memory byte holding flags var1 1 0 0 1 1 0 1 1 Windows message (WM_COMMNOTIFY) being posted to a
Mask var2 0 0 0 0 1 0 0 0 window. Messages are disabled by default. The function takes
var1 AND’ed with var2 0 0 0 0 1 0 0 0 four parameters:
1) The communications device in question.
Figure B: Masking off bit number 3.
2) The window to which messages are to be posted.
3) A parameter indicating the number of bytes the input buffer
Windows API. The API communicates with the serial port via a must contain before a message is sent to the application. A
DCB. The actual DCB is a component of the device driver message is sent if the number of characters in the input
(COMM.DRV). You edit this DCB by declaring a Delphi vari- buffer exceeds this number. It’s a notice that the application
able, setting the fields of the variable, and setting the actual DCB must read characters from the input buffer or there will
with your copy of the DCB using the SetCommState function. soon be no more room in the buffer. If this parameter is set
to -1, the message for this event is disabled.
The variable declared in the Delphi program is of type TDCB. A 4) A parameter indicating the minimum number of bytes the
TDCB is a Pascal record (or a structure in the C language) that transmit buffer must maintain without sending a message
contains several fields (baud rate, parity, etc.) describing how the to the application. A message is sent if the number of bytes
serial port is configured. The Windows API help that ships with in the transmit buffer falls below this number. It’s a notice
Delphi contains excellent documentation on each field — just to the application that the transmit buffer will soon be
search on TDCB. The following Windows API functions are empty. If this parameter is set to -1, the message for this
used in the demonstration form, Communications Demo #1. event is disabled.
(Again, for more information about these functions, use
Windows API Help.) GetCommEventMask. This retrieves the event word for the
desired port, and then clears those bits in the event word that are
OpenComm. This function opens a COM port and allocates specified by the event mask. The two parameters are the port’s
memory for the buffers. The COM port to be opened is one ID (returned by OpenComm) and a mask for the appropriate
parameter, and the other two parameters are the sizes of the events. This function returns the entire event word for the speci-
input and output buffers. OpenComm returns an integer iden- fied port, regardless of the event mask.
tifying the opened port. This identifier is used by many other
communications functions listed here. GetCommState. This function retrieves the device control
block for the specified port. It takes two parameters: the
BuildCommDCB. This function is a quick way to initialize a port’s ID (returned by OpenComm), and a reference to the
TDCB variable. It takes two arguments: A null-terminated TDCB variable.
string of the form:
ReadComm. This reads characters from the device driver’s inter-
‘COMx,BaudRate,Parity,DataBits,StopBits’ nal serial buffer. It takes three parameters: the serial port’s ID

NOVEMBER 1995 Delphi INFORMANT ▲ 38


Informant Spotlight

(returned by OpenComm); a pointer to the buffer to receive the buffer. You only need to ensure that you remove characters from
bytes read; and the number of characters to read. If the function this buffer before the buffer becomes full.
is successful, it returns the number of bytes read. If unsuccessful,
it returns less than zero, the absolute value of which is the num- The first demonstration program, Communications Demo #1,
ber of bytes actually read. relies on the operator to click a button to get characters from the
buffer. It also relies on the operator to click a button to send what-
WriteComm. This function sends a buffer of information to ever is in the transmit window. Communications Demo #1 has
the serial port for transmission. It takes three parameters: the four buttons and two memo fields on the main form (see Figure 3).
serial port’s ID (returned by OpenComm); a pointer to the
buffer holding the characters to be written; and the number
of characters to write. If the function is successful, it returns Figure 3:
the number of bytes written. If unsuccessful, it returns a The example
Communica-
value less than zero, the absolute value of which is the num-
tions Demo
ber of bytes actually written. #1 applica-
tion in
GetCommError. When a communication error occurs, action.
Windows locks the COM port until the programmer calls
this function. The ReadComm and WriteComm functions
will return an error if called before this function. However
the port will, if able, continue to receive characters, and
transmit whatever characters are currently in its transmit The OnClick event handler for the Read button takes the
buffer. characters in the receive buffer and adds them to the adjacent
memo field:
This function takes as parameters the COM port to be
checked (the OpenComm function returns this value), and a if ReadComm(hCommPort,inBuf,RecBufSize) > 0 then
Memo1.Text := Memo1.Text + StrPas(inBuf);
record (structure) of the type TCOMSTAT. After the call to
the GetCommError function, the TCOMSTAT structure will
The OnClick event handler for the Write button takes the
contain status information for the COM port. Information
characters in the lower memo field and copies them to the
such as “Transmission has been suspended because of recep-
transmit buffer.
tion of an XOff character” can be obtained from the TCOM-
STAT record. GetCommError returns an integer. Each bit of StrPCopy(outBuf,Memo2.Text);
the integer represents one type of error. The return value can rVal := WriteComm(hCommPort,outBuf,StrLen(outBut));

be a combination of these bits. The programmer can then


decode these bits and find the reason for the error. The Windows communica-
tions device driver
EscapeCommFunction. This function directs the specified (COMM.DRV) then sends
communication device to carry out an extended function. these characters through the
The first of two parameters is the COM port that will carry serial port. The baud rate,
out the function (OpenComm returns this value). The sec- parity, data bits, and stop bits
ond parameter is an integer specifying which function to can be set-up by selecting
carry out. EscapeCommFunction is used in sample form, Setup from the main menu
Communications Demo #2, to set and clear the RTS (see Figure 4).
(Request To Send) and DTR (Data Terminal Ready) signals. Figure 4: By selecting the
It returns zero if successful, less than zero if unsuccessful. Windows serial communica- Setup button on either the
tions is interrupt-driven since Communications Demo #1 or
CloseComm. In the demonstration form, this function is called Windows (without any inter- #2, this CommSetup dialog box
by the FormDestroy event, and transmits any characters left in the vention from any application appears.
transmit buffer, closes the COM port, and then releases any program) places received characters in a receive buffer, and
memory allocated for the transmit and receive buffers. It returns transmits characters from a transmit buffer. This is accom-
zero if successful, less than zero if unsuccessful. plished by the Windows communications device driver
COMM.DRV. If you want Windows to interrupt your
Basic Serial Communications with Delphi Delphi program, you must write the appropriate code to
The Windows device driver for the COM ports is interrupt-dri- intercept Windows messages.
ven. This means your Delphi program does not need to respond
to each character received at the port. Windows is interrupted Programmers new to Windows may be unfamiliar with the
when each character is received. Windows then takes the charac- interaction between the application program and the Windows
ter received at the port and places it in Windows’ own input operating system. In the DOS world, the application takes

NOVEMBER 1995 Delphi INFORMANT ▲ 39


Informant Spotlight

total control of the computer, and calls the DOS operating


system for various services. In Windows, while the application
Figure 5:
still calls the operating system for services, the operating sys-
The example
tem can make calls to the application. In Windows terminolo- Communications
gy, Windows sends a message to the application. Demo #2 applica-
tion displays the
Windows responds to events by sending messages to an appli- character it
received in the
cation. Most of these messages are handled behind the scenes
Memo component.
by Delphi. Delphi converts these messages into appropriate
events (OnClick, etc.) for each component. Delphi programs
respond to these events using event handlers — procedures
that process the keystroke, mouse click, etc. However, what is
needed is a way to respond to serial port events.
because a character was received, the program should get the
By default, each Delphi application declares a variable, character and place it in the Memo component’s window. The
Application, of the type TApplication. Using this variable, you can code for the message handler accomplishes this by testing the
write event handlers, not for individual components, but for the right-most bit in the event word (returned from the
application itself. GetCommEventMask function). If the bit is set, a character
has been received. Otherwise, the message was sent for some
First, write an event handler that is called for, but does not other communications event:
need to process, all Windows messages. In the second sample
if Msg.message = WM_COMMNOTIFY then
application, this handler is called MsgHndlr. You then tell begin
Delphi about this event handler. This is done in the if (GetCommEventMask(hCommPort,constCommEvents)
FormCreate event handler: and 1) = 1 then
ReadCommPort;
GetMSR; { Examine modem status register. }
procedure TMainForm.FormCreate(Sender: TObject);
end;
begin
Application.OnMessage := MsgHndlr;
end; How does Windows know for what events to send the
WM_COMMNOTIFY message? Your program must tell
Now, whenever Windows sends a message, MsgHndlr will be Windows the events you’re interested in. You do this with the
called, and will have an opportunity to intercept the message. SetCommEventMask function which takes two parameters.
MsgHndlr is called with two parameters. The first is a variable of
the type TMsg, a structure in which Windows places information The first is a handle to the port (the value returned by the
about the message, including the type of message. The message OpenComm function). The second is a mask with bits set for
for communications events is called WM_COMMNOTIFY. You each event in which you are interested. (These bits are
can test for communication events with the following code: described in Windows API help.) Communications Demo #2
is configured so a WM_COMMNOTIFY message is sent if
procedure TMainForm.MsgHndlr(var Msg: TMsg;
var Handled: Boolean);
one or more characters are in the receive buffer, or if the
begin CTS, DSR, or DCD lines change state. SetCommEventMask
if Msg.message = WM_COMMNOTIFY then is called in the FormCreate event handler for the main form.
begin
{ Process the communication event here. }
end; Communications Demo #2 also displays the state of the CTS,
end; DSR, and DCD lines by changing the color of the labels to red
if the signal is asserted. It does this by examining the modem sta-
The second parameter tells Windows if it should handle the tus register and updating the display each time a WM_COMM-
event. If you set Handled to True, then Windows/Delphi will NOTIFY message is received for any reason.
not do anything with the message. Conversely, if Handled is set
to False, then Windows/Delphi performs the default processing. The output signals RTS and DSR are set or cleared using the
EscapeCommFunction function:
The Communications Demo #2 (see Figure 5) responds to
received characters by displaying them in the Memo component procedure TMainForm.btnDTRClick(Sender: TObject);
begin
at the top of the screen. This is in contrast to the first sample { SetDTR & ClrDTR are constants defined in WINTYPES.PAS }
form that required some user event (i.e. a button click) to read if btnDTR.Checked then
the receive buffer and display the characters. EscapeCommFunction(hCommPort,SetDTR)
else
EscapeCommFunction(hCommPort,ClrDTR);
The MsgHndlr procedure requires a test to determine why the end;
WM_COMMNOTIFY message was sent. If it was sent

NOVEMBER 1995 Delphi INFORMANT ▲ 40


Informant Spotlight

Conclusion
Learning to program a computer is similar to learning to play
the piano. You can’t learn how to do it by just reading about it.
The documentation for writing serial communications programs
is so thin, there isn’t much to read anyway.

Feel free to experiment with the two sample applications. It’s


possible to connect two PCs together with serial cables and a
null modem adapter (available at most computer stores and
electronic distributors). A null modem adapter makes each com-
puter think it is connected to a modem. Then run the demon-
stration programs on both computers and send characters back
and forth. Make small modifications to the program and
observe the results. A few hours of creative playing should have
you on your way to using the serial port in your programs. ∆

The demonstration programs referenced in this article are avail-


able on the 1995 Delphi Informant Works CD located in
INFORM\95\NOV\TC9511.

Tom Costanza is the founder of Costanza & Associates in Langhorne, PA, providing
development tools, programming, and training since 1989. He can be reached at
(215) 752-5115, or on CompuServe at 76615,2154.

NOVEMBER 1995 Delphi INFORMANT ▲ 41


New & Used
by Tim Feldman

Borland RAD Pack for Delphi


What It Is, Why You Need It

ven if you never use the VBX controls in “Roadmap” explains

E Borland’s RAD Pack for Delphi, its other ele-


ments make the package well worth its
price. Besides the Visual Basic controls, the RAD
what’s in the RAD
Pack and gets you
started on the installa-
tion. The installation
Pack contains Delphi-compatible versions of program had one small
Borland’s classic Turbo Debugger and Resource problem — it tried to
Workshop tools; the source code of the Visual write the VCL source
Component Library (VCL); a new Resource Expert code to my CD-ROM
for the Delphi IDE; and a patch kit for the first — but I overrode it
release of Delphi. There are also hardcopy manu- easily.
als for the VBXes and the Turbo Debugger, and a
After I finished the
hardcopy version of Object Pascal Language Guide. Windows installation, I followed the README.TXT instruc-
About the only thing missing is hardcopy of the tions and used DOS to patch the Delphi IDE from the RAD
Visual Component Library Reference. Pack’s CD-ROM. There was no need to patch the VCL
source code or rebuild the IDE’s component library.
It’s no secret that Borland has fallen back upon its core
strength — development tools — to survive in today’s PC The VBXes
software business. Delphi is critical to Borland’s future. The The RAD Pack includes volume 1, version 1.1 of Borland’s
first release of Delphi earlier this year must have involved Visual Solutions Pack for Windows. This is a collection of
tough marketing decisions. The package had to be small VBXes written by commercial vendors. Perhaps the key word
enough to be irresistible to independent developers, but com- here is “commercial” — many of the VBXes are less-powerful
plete enough to avoid being rejected as a “toy language.” versions of other packages from the vendors. That the controls
Borland couldn’t throw the kitchen sink into its initial release are limited versions is not mentioned in the RAD Pack’s docu-
of Delphi or it would have been too expensive. By releasing mentation, but if you activate their “About” property at design
Desktop and Client/Server versions of Delphi, Borland seems time, many of the controls display dialog boxes that read like
to have made the right marketing decisions. Delphi appears magazine advertisements for the full versions.
to be well on its way to success. Now Borland has released the
Delphi RAD Pack, which rounds out the IDE with tools that The About boxes also reveal that the VBXes are of 1993/94
most serious developers will want to have. vintage. Older VBXes that predate Delphi, such as those in
the Visual Solutions Pack, are more likely to suffer in compari-
Installation son to Delphi’s object-oriented VCLs. For example, they may
The RAD Pack software comes on a single CD-ROM and not be data-aware nor do a good job of wrapping complexity
eats up about 25MB of hard disk. A four-page printed in an easy-to-use set of properties and methods. In addition,

NOVEMBER 1995 Delphi INFORMANT ▲ 42


New & Used

using VBXes in commercial software requires you to redistrib- controls. There are no examples for the ImageKnife control.
ute and properly install .VBX and .DLL files. The ImageKnife documentation shipped with the VBXes is
no help. The massive hardcopy Reference Guide (nearly 1,000
Despite these limitations, if you buy the RAD Pack, you’ll be pages) and the ImageKnife on-line Help file both predate
curious about the VBXes. You’ll want to install them in the Delphi and lack programming examples. The Reference Guide
IDE and try them. I installed all the VBXes easily — there has several chapters about the ImageKnife control (also with
are clear instructions in the RAD Pack Roadmap and several no examples).
other places.
A thin (36-page) Visual Solutions Pack User’s Guide for Delphi
Using them, however, was a different story. The first VBX I tried contains what appears to be an excellent tutorial — on one of
was AniButton (for “Animated Button”) from DesaWare. Drop the other VBXes. It has nothing about the ImageKnife VBX.
this simple little gadget on a form, give it an event to handle, In fact, the only VBX it discusses in detail is the tutorial’s set
and it works much like a normal button. The only typical but- of TX Word Processor components. While this makes some
ton events it doesn’t handle are OnMouseMove, OnMouseDown, sense (re-writing the entire Reference Guide for Delphi would
and OnMouseUp. probably have been prohibitively expensive), it’s an indication
that mastering the more complex VBXes may be a “learning
The difference with AniButton is its appearance. If you don’t experience.”
give its Picture property a value, it looks like a standard Edit
control (a plain white rectangle). The fun comes after you use In the end, I abandoned efforts to make the ImageKnife VBX
its Picture and Frame properties to specify a set of bitmaps for work since I had no real-world need to use it. If I did need to
it to animate. The AniButton will play the pictures back on an work with images, I would probably look for a true Delphi VCL
event, showing a little cartoon movie on its surface. Other rather than a VBX.
properties let you stretch the bitmaps, change their playback
rate, and modify the animation so that some bitmaps play The VBXes in the Visual Solutions Pack include:
when the button is pushed, and the rest play when the button • AniButton Animated Buttons by Desaware
is released. The AniButton is cute, easy to use, and quite flexi- • Chart Controls by Kansmen
ble. It’s data-aware and similar to a true Delphi VCL. I had • Formula One Spreadsheet Controls by Visual Tools
fun playing with it. • Gadgets by MicroHelp
• ImageKnife Image Editor Control by Media Architects
Heartened, I tried another, more complex VBX: the • Integra Visual Database Builder by Coromandel Industries
ImageKnife component from Media Architects, Inc. The • SaxComm Communications Tools and SaxTabs Notebook
ImageKnife is billed as a super-charged version of the IDE’s Tab Controls by Sax Software
standard Image component. It can display advanced image • TX Word Processor Controls by European Software Connection
formats, perform simple image processing operations, and
manipulate the image’s color palette. Or rather, the
ImageKnife should be able to do all those things. I don’t
know if it can or not, because I could not make it work.

Perhaps the ImageKnife’s Delphi interface isn’t complete, or its


documentation skips some crucial step. I had no problems
installing the ImageKnife VBX or dropping its visual control,
PicBuf, onto a form. PicBuf ’s design-time properties worked, as
did some of its run-time-only properties and methods. Some of
the run-time methods compiled without problems, but many of
them — including the ones that load an image file into PicBuf
— were unrecognized by the compiler. The interface file to the
VBX (KNIFE.PAS) appears to be valid, but omits references to
many of the properties and methods described in the Visual From the Borland Visual Solutions Pack, the TX work processor VBX in
Solutions Pack Reference Guide. action.

I was curious about this quiet failure. Knowing that the Visual The VCL Source Code
Solutions Pack also supports C++ and dBASE (the hardcopy Disappointing as the VBXes are, the VCL source code inspires
user guides for both languages are included), I looked at the the opposite feeling. For experienced developers, the source code
ImageKnife example programs in C++ and dBASE on the RAD is an exciting treasure. I have always found that no matter how
Pack CD-ROM. Those examples do support the image load well a development environment is documented, there are ques-
function. Unfortunately, the only Delphi examples on the CD- tions that can only be answered by “looking under the hood.”
ROM are for the simpler VBXes and the TX Word Processing For that, you need the source code to the library routines. And,

NOVEMBER 1995 Delphi INFORMANT ▲ 43


New & Used

as you try to master the new environment, you’ll never find strokes, steps backward through your code, and examines the
enough example programs. The source code helps fill that void. CPU and system memory directly. It runs on a second video dis-
Installing it adds hundreds of files under \DELPHI\SOURCE in play, or on a second computer over a network or serial link. It
three subdirectory trees. contains its own assembler, disassembler, and expression evalua-
tor. It supports C, C++, and Object Pascal, and understands
The IDE displays special dialog boxes to help you set certain objects, exceptions, and properties. It debugs DLLs, monitors
design-time component properties. For example, to set the Windows messages, and even performs hardware debugging by
Picture property for an Image component, the IDE displays a taking advantage of the debug registers in 386 and higher
Picture Editor dialog box. The \DELPHI \SOURCE\LIB tree processors. This lets the Turbo Debugger detect CPU accesses to
contains the source code for those special dialog boxes. specific memory and I/O addresses, or with specified ranges of
data values. In short, it handles industrial-strength bugs.
The \DELPHI\SOURCE\RTL tree contains the Delphi run-
time library (RTL) source code. The \RTL\SYS subdirectory is The version in the RAD Pack is Turbo Debugger 4.6 for
where the string, math, and other “primitive” routines are Windows only. Unlike separate Turbo Debugger packages from
implemented in .ASM and .PAS files. Do you need to see how Borland, the RAD Pack doesn’t include DOS and Win32 ver-
random numbers really work in Object Pascal? Check the code sions of it (nor Borland’s Turbo Assembler). Those won’t be
in RAND.ASM. Are you trying to figure out what the real dif- serious shortcomings for most Delphi developers.
ferences are between New and GetMem, and are you confused
by the printed documentation and on-line help? Search for A 144-page manual specifically for Delphi/Object Pascal users is
“NewPtr” in SYSTEM.PAS and WMEM.ASM. You might be included. Along with several text files on disk, it covers the
surprised by what you find! basics of configuring and using the Turbo Debugger. While the
manual is well-written, it falls short in one area: it does not con-
The \RTL\WIN subdirectory holds the interface .PAS files that tain any tutorials. There are no sample Delphi programs with
join Delphi to the Windows 3.1 APIs. Here, you can discover subtle captive bugs for you to practice on. Because of this, you
how Delphi connects to Pen Windows, to the Windows will probably defer learning to use the Debugger until the worst
Common Dialogs, and to other APIs that aren’t even mentioned possible time: when a real bug bites you and your code needs to
in the Delphi documentation. ship in a hurry. But at least when that does happen, there’s an
excellent tool to help fix your code.
If you want to translate Delphi’s run-time error messages into
another language, you’ll want the English, French, and German The Resource Workshop
subdirectories in the \RTL\SYS tree. Example files in all three lan- The last major tool in the RAD Pack is Borland’s Resource
guages show how to recompile the RTL to change the messages. Workshop, version 4.5. It lets you edit the Windows resources
used in your program.
Finally, the \DELPHI\SOURCE\VCL tree contains the Delphi
source code to the VCLs in the IDE’s Component Palette (except The most common editable resources are icons, bitmaps, and
for the sample VBXes — their source code is not given — and the menus. The Delphi IDE contains built-in support for editing
Sample VCLs, whose source code is shipped with Delphi in \DEL- those resource types. For example, IDE’s Image Editor can be
PHI\SOURCE\SAMPLES). This source code is an absolute must- used to work on icons, bitmaps, and several other resource
have for any developer creating custom visual components. Foreign- types. However, just as the Turbo Debugger is more powerful
language developers will also want the English, French, and German than the Integrated Debugger, the Resource Workshop is more
resource files, which define the error message strings in all the VCLs. powerful than the Image Editor. The Workshop has more tools
and options. More importantly, the Resource Editor is more
Note that the source code package does not supply the source code stable than IDE’s Image Editor, which has been known to crash
for other parts of Delphi, such as the Image Editor or the IDE’s text on occasion. I found the Resource Workshop’s stability well
editor. And, of course, if you have the Client/Server version of worth the price.
Delphi, you already have the source code. It’s also available separate-
ly from Borland for approximately US$100. Since that is almost as If you want to define custom fonts for your applications, you’ll
much as the RAD Pack’s street price, it makes sense to get the RAD want the Workshop. If you want to internationalize your pro-
Pack. Its additional tools are easily worth the price difference. grams by having them load their strings at run-time, you’ll find
putting the strings into a resource file created by the Workshop a
The Turbo Debugger good method. You can even use the Workshop to extract the
The Delphi IDE’s Integrated Debugger does a very good job of resources from a .DLL or .EXE file, modify them, and then bind
debugging at the Object Pascal level. But when you need to grab the them back into the same executable file.
CPU by its registers and shake it, you need the Turbo Debugger.
If your application needs a custom resource — perhaps special
The Turbo Debugger does things the Integrated Debugger can’t binary data, or a large block of text to be displayed at run-time
do. It logs debugging sessions to a disk file, records your key- — the Workshop will help you define, edit, and manage it.

NOVEMBER 1995 Delphi INFORMANT ▲ 44


New & Used

your screen. The form contains the menu or dialog box


defined in the .RC file. From that point on, the new form
behaves exactly as if you had created it by hand, and you can
discard the old .RC and support files.

I had no problems converting old .RC scripts with the Expert,


even though its only documentation is a Windows Help file.
Installing the Resource Expert hooks it into the IDE’s Help menu
so the Expert starts when you select Help | Resource Expert. The
Database Form Expert and Interactive Tutors are also wired into
the Help menu the same way. It’s a startling effect — you’re
expecting a Windows Help file to pop up, not a separate applica-
tion — but after working with it for a while, I grew to like it.

Borland’s Resource Workshop. Even though the Resource Expert was released after Delphi
shipped, it fits into the IDE perfectly. It’s a nice example of the
With all these capabilities, it’s a shame the Resource Workshop forward thinking in Delphi’s design. I wonder how quickly other
isn’t well documented. Borland did not include a hardcopy man- vendors will start developing their own plug-in experts for the
ual in the RAD Pack. However, there are several language-inde- Delphi IDE. Most of the source code for the Resource Expert is
pendent Windows help files that do an average job of making up provided with the RAD Pack.
for the missing manual. A single short README.TXT file dis-
cusses installing and using the Workshop with Delphi. Beyond The Patches
that, you’ll have to learn about the Workshop by tinkering with A few months after Delphi’s official release, Borland issued free
it. It’s worth the time. patches to the VCL and its source code, and to both the
Desktop and Client/Server versions of the Delphi IDE. These
The Resource Expert version 1.01 patches apply to the Delphi files dated 2/15/95
If you have developed Windows applications in other lan- 8:00 am. The patches are available from Borland’s CompuServe
guages, you’ve probably worked with .RC files. These are the and ftp sites, and are also part of the RAD Pack.
files that define the Windows resources created with the
Resource Workshop or similar tools. They’re a kind of source The patches fix a number of relatively minor bugs in Delphi. I
code or script file written in a language defined by Microsoft. never noticed the differences after installing them. A complete
Delphi supports .RC files indirectly. After they have been list of the bugs is included with the patch kit.
compiled into .RES or .DFM files, Delphi can link them into
your application. That’s what the mysterious little {$R *.DFM} The Object Pascal Language Guide
compiler directive in the implementation part of a Delphi When Delphi was released, users were quick to praise it. They
form’s unit is for. It tells the compiler that any .DFM resource were also quick to complain about the skimpy documentation
files in the project’s directory should eventually be linked into that shipped with the Desktop version of Delphi. I recently had
the application. the opportunity to ask Borland’s Phillipe Kahn if Borland had
decided to change their future policy on hardcopy documenta-
Normally, you use the IDE to compile Delphi components tion because of all the loud complaints. He replied that they
into .DFM files or the Resource Workshop to compile .RC were “satisfied” with their practices.
files into .RES files. Then, you manually rename the .RES
files to .DFM files so Delphi will link them into your appli- Still, Borland responded to the complaints by making an Adobe
cation. But, if you have developed a large number of .RC files Acrobat version of the Object Pascal Language Guide available at
containing menus or dialog boxes, you may want to convert no cost on their CompuServe and ftp sites. They have also
them into Delphi menus and dialog box forms. That is what announced the 32-bit version of Delphi will include a hardcopy
the Resource Expert does. After they have been converted, version of the Guide, and a copy is part of the RAD Pack.
you can manipulate them within the Delphi IDE as if you
had defined them using the IDE’s usual tools. At 290 pages, the Guide goes into some depth about the lan-
guage Delphi is built upon. It’s a reference, not a tutorial, but
The Resource Expert is a new plug-in for the IDE. After contains plenty of code snippets. Its 20 chapters and three
installing it and configuring the IDE, the Resource Expert appendices cover all the details of the Object Pascal language,
appears alongside the Database Form and Dialog Experts in the compiler/linker, and the built-in assembler.
the Experts page of the Browse Gallery whenever you create a
new form. If you activate the Resource Expert, it asks for the The Guide also covers the basic parts of the Object Pascal RTL,
location of the .RC and support files you wish to convert. including strings, I/O, and memory issues. An interesting point
Then it processes those files and displays the new form on is that Object Pascal and Delphi are not synonymous. Object

NOVEMBER 1995 Delphi INFORMANT ▲ 45


New & Used

Pascal is the core upon which Delphi’s IDE and the VCL are
built. By itself, Object Pascal could compile DOS applications (if
DOS RTLs were supplied; they are not). Therefore, the Object
Pascal Language Guide says little about Windows or Delphi. It
does, however, include a short chapter about Windows DLLs
and a section on using the WinCrt unit to produce text-oriented
Windows applications. The Guide’s main purpose is to explain
the Object Pascal language succinctly. It does that quite well.

The (Missing) VCL Reference


If Object Pascal is the hidden
foundation upon which Delphi is
built, the VCL is the elegant
structure that we think of as Borland's RAD Pack for Delphi is a
Delphi. The definitive guide to collection of tools, source code, and
documentation that enhances the
that structure is Borland’s Visual Delphi IDE. It includes version 1.1,
Component Library Reference, a Volume 1 of the Visual Solutions
Pack; Delphi-compatible releases
1,000 page hardcopy manual. of Turbo Debugger and Resource
Unfortunately, it’s not part of the Workshop; a new Resource Expert
for the IDE; patches for the initial
RAD Pack. It would have been release of Delphi; the source code
better to include the Reference for Delphi's Run-Time Library and
Visual Component Library; and a
than the entire Visual Solutions printed copy of the Object Pascal
Pack of VBXes. Language Reference. The Visual
Solutions Pack is the only weak
aspect of an otherwise must-have
The hardcopy Reference is available package for serious Delphi devel-
separately from Borland. An opers.
Adobe Acrobat version of the Borland International
Reference is also available. 100 Borland Way
Scotts Valley, CA 95066-3249
Curiously, it’s not included in the Phone: 1-800-336-6464
RAD Pack. It can be downloaded Internet: http://www.borland.com
CompuServe: GO BORLAND
from Borland’s CompuServe and Price: $US189.95
ftp sites. The file is about 5MB in
size when expanded. I find it
essential for serious development work.

Conclusion
If you are a Delphi developer, you should get the RAD Pack for
its VCL and RTL source code, its tools, and the hardcopy Object
Pascal Language Guide. Use those parts because they are excel-
lent, and ignore the VBXes of the Visual Solutions Pack because
they are not. Add a hardcopy or Adobe Acrobat version of the
Visual Component Library Reference, and you’ll have the essential
tools to do serious work with Delphi. ∆

Tim Feldman has more than fifteen years of experience in hardware and software
development. His most recent large project was designing and coding an event-driven
GUI, debugging, and calibration package for a high-speed almond sorting system. He
can be reached via the Internet at [email protected].

NOVEMBER 1995 Delphi INFORMANT ▲ 46


Te xt F i l e

Sometimes Good Things Take a Little Longer


The first wave of Delphi ners. Its 900 pages are divid- In the second section, the
books has passed. Now come ed into three major sections. authors move beyond short
the more thorough books; the The first section alone is examples to begin teaching
ones that took a little longer worth the price of the book. the techniques used to build
to get to market. These are In fact, it contains more real-world applications. In six
the books that professional material than many other chapters, they create a system
developers will use as stan- complete Delphi books. resource monitor, an address
dard references — the ones book, a calendar/scheduler/
that will end up with dog- In twenty-two chapters, it alarm application, a phone
eared pages and smudged covers every major area of dialer/terminal application, a file
CD-ROMs. The Delphi Windows and DPMI pro- manager, and a time-tracker
Developer’s Guide by Xavier gramming using Delphi application. and how to resolve them.
Pacheco and Steve Teixeira is including: MDI applications,
one of those standards. And GDI programming, DLLs, With these projects, you learn The text is well written. The
if you’re serious about OLE, DDE, the Windows development techniques as well authors have a comfortably
Delphi, you need this book. multimedia API, SQL, as the details of various Delphi direct style, informal without
Windows messages and components. The authors being chatty. It’s neither aca-
Steve Teixeira is a regular hooks, building custom com- explain each project completely demic nor simplistic — they
contributor to Delphi ponents, and testing and and deftly insert advanced con- assume you understand com-
groups, and has written a debugging. cepts, such as deriving descen- puters and programming,
number of excellent articles dant components. and spend their effort in pro-
for various Delphi magazines The authors use short exam- viding lots of examples and
including Delphi Informant. ple programs to illustrate In the final section, Pacheco useful tips. Their experience
Both Teixeira and Pacheco each topic and offer useful and Teixeira devote another in working with developers
worked in Borland’s notes and tips. They cover six chapters to developing gives them a refreshingly
Technical Support depart- advanced operations such as two large applications: an practical tone.
ment. Teixeira is still there, creating custom components inventory manager and a per-
and Pacheco is now with in a clear, step-by-step fash- sonal information manager. Despite the book’s profes-
TurboPower Software, mak- ion that’s just right. As with the other examples, sional orientation, it’s accessi-
ers of VCL add-in compo- they build each application ble to serious amateurs. It
nents for Delphi. Their com- First, they explain the with an emphasis on real- contains excellent chapters on
bined experience is what method they will use and world development tech- programming in Pascal and
makes this book so valuable. then present an example pro- niques. They cover prelimi- Object Pascal, and it suc-
Manning the front lines at ject that explicitly illustrates nary design issues and deci- cinctly explains important
Borland, they’ve answered the method. In many places, sions, develop the applica- aspects of Windows program-
Delphi questions that most they point out the easiest tion’s user interface, and then ming, with an emphasis on
of us haven’t even thought way to accomplish some- add finishing touches. providing useful examples.
of. Their book is packed with thing. Then they bring up
valuable source code, discus- advanced alternatives and In a brief Appendix, the The CD-ROM included with
sions, step-by-step proce- explain why you would need authors cover Delphi error the book is also valuable. In
dures, cautions, and tips. to use them. And always, handling and error messages. addition to the source code,
there are examples — lots of As usual, the material has a “Sometimes Good Things
As its name states, this guide them — that are well-docu- practical emphasis, describ- Take a Little Longer”
continued on page 49
is for developers, not begin- mented and ready to run. ing common causes of errors

NOVEMBER 1995 Delphi INFORMANT ▲ 47


TextFile

A Developer’s Guide Targets Database Developers


Surveys indicate that most will have little appeal to devel- Delphi: A Developer’s Guide
developers use Delphi as a opers not interested in devel- also tackles other topics
tool to create database appli- oping database applications. important to advanced devel-
cations, and authors Bill Despite its intense coverage opers, including creating
Todd and Vince Kellen cater of database issues however, DLLs, exception handling,
to this audience in Delphi: A Delphi: A Developer’s Guide and calls to the Borland
Developer’s Guide. This new provides more information Database Engine. The book
title from M&T Books pro- about Object Pascal than and accompanying CD are
vides the most comprehen- most third-party Delphi filled with useful examples
sive guide to-date in chroni- books. Several chapters study and sample code. And there’s
cling the complexity of Object Pascal program struc- no doubt that you’ll find code
designing client/server appli- ture, data types, expressions, (e.g. string manipulation pro-
cations in Delphi. statements, procedures and cedures), that can easily be Database Application”. Also,
functions, and units. used in your applications. the advanced topic of creat-
Todd and Kellen are well- ing DLLs is discussed before
respected in the Paradox com- However, the discussions of The book is well-written and an introductory chapter on
munity and have strong back- some issues (e.g. linked lists interesting. However, it working with VCL compo-
grounds in database applica- and PChar variables) are not could have been better orga- nents. In addition, object-
tions. Their expertise definitely as detailed as those in Charles nized. For example, informa- oriented programming is
comes through in the pages of Calvert’s, Delphi Unleashed tion on error handling is examined in three chapters
this book. [Sams, 1995]. In fact, Delphi: curiously sandwiched when one would have been
A Developer’s Guide can be between chapters that sufficient. Therefore, a cover-
Beginning and intermediate seen as a good companion to describe the Query compo- “A Developer’s Guide Targets
database developers will appre- Calvert’s Unleashed. nent and “Building a Database Developer”
continued on page 49
ciate the comprehensive cover-
age of the issues surrounding Mastering Delphi is Complete and Insightful
database application develop-
ment. For example, it shows If you intend to buy just one An overview of the Visual
that developing a database book on Delphi, Marco Component Library is fol-
application involves more than Cantù’s Mastering Delphi lowed by 12 chapters (Part II
working with TQuery and deserves a place on your of the book, which fills 700
TDataSource components. It short list of candidates. This pages) that explore the indi-
might well be necessary to deal encyclopedic text weighs in at vidual components in detail.
with issues such as database 1500 pages, covering the
integrity, data security, SQL-92 Delphi spectrum from intro- This same material is covered
isolation levels, and implicit vs. ductory concepts to advanced in most other Delphi texts,
explicit transactions. programming techniques. but Mastering Delphi goes far
beyond the standard enumer-
Of the book’s 33 chapters, 15 Cantù uses his unusually ations of properties and
focus on database-related top- high page count to great needed much encouragement). methods. Examples are espe-
ics. Although that makes for a advantage, providing more The first three chapters pro- cially well chosen. One
strong book on database complete treatments of the vide a general introduction example often serves to illus-
application development, it topics than any other text to Delphi. Chapter 4 offers a trate several key concepts
also detracts to an extent from I’ve seen. Many discussions concise overview of the that are woven together
Object Pascal programming. show several ways to accom- Pascal language, emphasizing seamlessly.
plish a particular task, with the motivation for various
For example, Chapters 23-28 welcome comments on the elements of the language, Mastering devotes more than a
and 33 concentrate on data- tradeoffs. rather than just their syntax. hundred pages to database
base development concerns Chapter 5, “Object Pascal as programming. A separate
(e.g. database integrity, Despite its length, the text is an OOP Language,” devotes chapter describes how to write
Microsoft SQL Server, highly readable and about as 76 pages to object-oriented client/server applications, cov-
InterBase, and the Database entertaining as the material programming concepts, and ering topics such as the Local
Desktop). Although crucial allows. The author’s enthusi- includes the best treatment
“Mastering Delphi is Complete
database concerns, these are asm for Delphi is apparent and of Dephi’s exception han- and Insightful”
continued on page 49
not Delphi topics per se, and infectious (as if Delphi users dling I’ve seen.

NOVEMBER 1995 Delphi INFORMANT ▲ 48


TextFile

Sometimes Good Things Take a Little Longer (cont.)

project, data, and resource projects not described in the ties to your hard disk. Installing Delphi Developer’s Guide
files for all the book’s exam- text. I had some difficulties the text’s source code took by Xavier Pacheco and
ples, it includes trial versions with some of this extra about 14MB; the extra source Steve Teixeira,
of many Delphi-related com- source code — missing class- code took another 1.4MB. Sams Publishing/Borland Press,
mercial utilities and VCLs. es and project files — but 201 West 103rd Street,
Some of the VCLs are “crip- only with code that was writ- To reiterate: If you are a seri- Indianapolis, IN 46290-1097;
pled” because they only work ten by third parties. All of ous Delphi developer or phone: (800) 428-5331;
while the Delphi IDE is run- Pacheco and Teixeira’s code want to become one, you’ll fax: (800) 882-8583.
ning. A few of the advanced that I tried worked properly. find Pacheco and Teixeira’s
projects in the text use these Delphi Developer’s Guide ISBN: 0-672-30704-9
special VCLs, but most of An excellent setup program indispensable. And well Price: US$49.99
the projects do not. There serves as a hypertext guide to worth the wait. 907 pages, CD-ROM
are also several directories of the CD-ROM, and lets you
extra “bonus” source code for install the source code and utili- — Tim Feldman

Mastering Delphi is Complete and Insightful (cont.)


InterBase Server, InterBase ware, shareware, and demon- Mastering Delphi will give you Challenger Drive, Alameda,
server tools, and the Visual stration versions of commer- a good head start on the road CA 94501; (800) 227-2346 or
Query Builder. cial products. to guruhood. (510) 523-8233.

Part III, “Advanced Delphi There is also a directory con- — Larry Clark ISBN: 0-7821-1739-2
Programming”, goes well taining tools, and another Price: US$49.99
beyond the scope of most with the text of several Mastering Delphi by Marco 1,503 pages, CD-ROM
other Delphi books. One Delphi-oriented magazines Cantù, SYBEX Inc., 2021
chapter covers techniques (including the Premiere issue
such as timers, painting of Delphi Informant).
methods, and background A Developer’s Guide Targets
computing. Another provides The book is not without
excellent treatment of debug- minor flaws. Some of the Database Developers (cont.)
ging methodologies. Still oth- introductory material seems to to-cover read may not be the tions — especially
ers discuss the use of switch too rapidly from ele- best approach. client/server applications.
Windows resources, printing mentary to difficult material. A There is simply no other
techniques (including few terms that may be unfa- Delphi: A Developer’s Guide book like it on the market
ReportSmith, which Cantù miliar to new users (e.g. “heap” includes an obligatory chap- when it comes to database
disparages for its limitations), on page 111 and “call stack” ter on using ReportSmith programming. Experienced
file support, data exchange on page 213) are used without that is weak and perhaps the Delphi developers will also
(Clipboard and DDE), OLE, definition. I noted minor least useful. ReportSmith find the Object Pascal discus-
and multimedia devices. inconsistencies among variable integration with Delphi, for sions and advanced chapters
names in one set of sample example, is only superficially complementary to Delphi
Mastering concludes with a well code fragments (page 109). discussed. Finally, the book books they already have.
constructed chapter on creating offers just 16 pages to com-
components and a shorter one Finally, I felt that some ponent design, a subject — Richard Wagner
on using DLLs from Delphi. important warnings, notably important to Delphi develop-
Appendices provide a some- one about memory leakage ers. Although, to be fair, none Delphi: A Developer’s Guide
what formal discussion of (on page 217) receive less of the current third-party by Bill Todd and Vince
OOP principals and a too-brief emphasis than they deserve. books I’ve seen have covered Kellen, M&T Books, 4375 W
introduction to SQL. this subject adequately. 1980 S; Salt Lake City, Utah,
Flaws notwithstanding, this is 84104 (800) 488-5233.
An accompanying CD-ROM by far the best Delphi book I In conclusion, despite its
provides the code for all the have seen. No single book shortcomings, I recommend ISBN: 1-55851-455-4
examples in Mastering. In will transform a novice into a Delphi: A Developer’s Guide Price: US$44.95
addition, it offers a useful set Delphi guru overnight, but for developers interested in 820 pages,
of components, including free- one or two careful readings of designing database applica- CD-ROM

NOVEMBER 1995 Delphi INFORMANT ▲ 49

You might also like