Object Pascal: The Language
Object Pascal: The Language
Object Pascal
the Language
Comparisons and Reveries
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
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
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
By Richard Wagner
ode reuse has always been a worthy objective for application devel-
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;
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.
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
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. ∆
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;
end.
By John O’Connell
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.
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.
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.
['0'..'9','a..z','#']
[0..15, 255]
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]
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;
DOWSet = set of (Sunday, Monday, Tuesday, Wednesday, Figure 5: The Object Pascal Include and Exclude procedures.
Thursday, Friday, Saturday);
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
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
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;
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.
By Richard D. Holmes
Cultural Differences
A Comparison of Pascal and C++ Language Features
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.
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.
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-
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
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
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.
t’s often overlooked when the Data Access page on the Component Palette
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.
batAppend (default) No No
batAppendUpdate Yes Yes
batCopy No No
batDelete Yes Yes
batUpdate Yes Yes
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.
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;
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;
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.
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.
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
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?
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
By Tom Costanza
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.
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.
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-
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]
Figure 2: Signals used in serial communications with cable-connector Windows API Functions
pin numbers. Delphi can communicate with the serial port through the
(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));
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.
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.
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.
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,
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.
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
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.
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].
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
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