Delphi 3 The Activex Foundry
Delphi 3 The Activex Foundry
Delphi 3 The Activex Foundry
Delphi 3
The ActiveX
Foundry
From COM to DCOM,
Delphi 3 Means Business
ON THE COVER
6 Delphi 3: The ActiveX Foundry Danny Thorpe
Borland has cast another winner Delphi 3 is to ActiveX creation
as Delphi 1 was to Windows app creation. Watch the sparks fly as
Mr Thorpe previews all the items that merit buzzwords on the box
cover (and more).
12 Easier Yet Robert Vivrette
As he explores the Delphi 3 Code Editors new refinements in appearance and function, our writers mind is in the gutter the left gutter,
specifically. Find out why.
FEATURES
16 Informant Spotlight Ian Davies
With only a few lines of code, Word can become a sophisticated Delphi
reporting tool. Nifty tweaks like this make coming to grips with OLE
Automation well worth the effort, says Mr Davies.
21 Columns & Rows Dan Ehrmann
Developers use the Paradox file format every day, but Delphi documentation supplies almost no information about it. This second in a
series offers help in calculating record and table size, including an
application to crunch the numbers.
25 In Development Bill Todd
InstallShield Express lets you create a single disk set to install
myriad items, gladdening the hearts of your users. This first of two
articles shows you how to make the most of this product and
deal with its limitations.
32 DBNavigator Cary Jensen, Ph.D.
This month, Dr Jensen explains how cached updates can increase performance, reduce network traffic, add user interface options, and
enhance programmatic control over data updates all with
minimal outlay.
1
REVIEWS
47 Eagles Component Developer Kit 2.0
Product Review by Robin Karlin
56 Delphi Programming Problem Solver
Book Review by Richard Porter
56 Programming Delphi Custom Components
Book Review by Alan Moore, Ph.D.
DEPARTMENTS
2 Delphi Tools
5 Newsline
58 File | New by Richard Wagner
Delphi
T O O L S
New Products
and Solutions
Applied Analytic
Systems Ships New
Components
Applied Analytic Systems,
Inc. of Carnegie, PA has
released its statistical analysis
components for Delphi 1 and
2. The TRegress, TAnova, and
TForecast components perform randomized block analysis of variance, and exponential smoothing forecasting on
data in tables accessed
through the BDE.
The statistical components
can be used in place of the
TTable component, allowing
developers to incorporate
database-aware statistical capabilities into their software.
The components can analyze
the data (or subset of the
data) in any numeric column
of the table to which they are
attached. Developers using
the components supply the
database and table name as
party APIs.
Smart Debugging is included. It allows developers to
detect and fix errors as a normal by-product of the development process. Smart
Debugging works inside the
Delphi IDE and is compatible
with Delphi 2 and 3. It monitors all events, searches for
bugs as the user steps through
code, and displays any errors
found.
BoundsChecker displays
multiple call stacks, identifying the source of memory
overwrites and leaks, and the
location in the program where
memory is allocated or deallocated. Users have immediate,
contextual information about
why an error occurred and
where. Errors and events are
viewed in real time, providing
immediate and comprehensive
information on program execution.
BoundsChecker 5.0 intro-
Delphi
T O O L S
New Products
and Solutions
Borland Developers
Conference
The 8th Annual Borland
Developers Conference will
take place July 12-16th in
Nashville, TN.
Attendees will be able to
design their own agendas,
selecting from beginning,
intermediate, or advanced
developer sessions in the following categories: components; design and methodology; enterprise computing;
InterBase; Internet/intranet;
management issues; programming, tools, and techniques; and solutions.
For more information, visit
http://www.borland.com.
SuccessWare
International Ships
Apollo 3
SuccessWare International
of Temecula, CA has shipped
Apollo 3, an update to its
database engine for Delphi.
Apollo 3 features its proprietary technology, RollYour-Own Indexes and
Filters; ascending/descending index orders; increased
support for Delphis integrated components;
improved data access and
optimized-query speeds; a
smaller deployment footprint; and more.
Price: US$179
Contact: SuccessWare International,
27349 Jefferson Ave., Ste. 110,
Temecula, CA 92590
Phone: (800) 683-1657 or
(909) 699-9657
Fax: (909) 695-5679
E-Mail: [email protected]
Web Site: http://www.gosware.com
Delphi
T O O L S
New Products
and Solutions
ISBN: 0-07-882236-X
Price: US$29.95
(298 pages, CD-ROM)
Phone: (800) 262-4729
News
L
May 1997
Borland Appoints
Birmingham as Vice
President and General
Counsel
Hobart Birmingham has been
named Borlands vice president and general counsel.
Birmingham, who reports to
Borlands chairman and chief
executive officer, Delbert W.
Yocam, will manage legal services for Borlands world-wide
operations. Birmingham
replaces Robert Kohn who left
the company in October 1996.
On the Cover
Delphi 3
By Danny Thorpe
Delphi 3
The ActiveX Foundry
From COM to DCOM, Delphi 3 Means Business
ts spring again, a time when many eyes look to Borland for a new generation of Delphi development tools. This spring brings us the third incarnation
of Delphi, a lush garden of new tools and technologies designed to expedite
business-critical data handling and analysis.
The most exotic fruits of Borlands yearlong labors include the ActiveX
Component Foundry, Business Object
Broker, multi-tier Remote Data Brokers,
Distributed COM, Web Deployment, and
a suite of IDE features known collectively
as Code Insight.
There are so many new technical bits in
Delphi 3 that its difficult to grasp the
scope of the whole product simply by looking at its technical pieces. Lets first take a
Revisionist Terminology
Figure 1: One aspect of the ActiveX Component Foundry, a page of wizards makes it short work to create an ActiveX control. Delphi 3 makes creation, debugging, deployment, and maintenance of ActiveX controls, COM
servers, and COM interfaces simple and reliable.
6
On the Cover
Figure 4: You
can now directly
access interfaces
provided by
ActiveX controls
and take advantage of other
control features
that were previously only available through
variant variables.
ActiveForms
Another nifty spin-off of the core ActiveX development
work is the creation of an ActiveX control to encapsulate
an entire Delphi form (again, see Figure 1). This is necessary to support ActiveX property pages, but its also handy
for creating mini-application modules that can be automatically downloaded over the Internet and displayed
inside a Web browser such as Microsoft Internet Explorer
3.0. The Web browser sees the thing as an ActiveX control, but you can pack an entire application into it.
Web Deployment
To support Web-deployed ActiveX controls, the Delphi 3
IDE includes tools to digitally sign and seal your .DLL or
.EXE file with your Software Publisher digital certificate, and
On the Cover
Distributed COM
Delphi 3 supports Distributed COM, Microsofts newest
implementation of COM that enables an application on
one machine to talk to an application on another across the
network wire. Basically, DCOM is the heir-apparent to
Remote Procedure Calls (RPC). Delphi 3s remote datasets
use DCOM to make the hop from the client machine to
the middle-tier data broker. You can implement your own
middle-tier business logic by creating a COM server in
Delphi 3, and call its methods using interfaces in the client
application. DCOM takes care of the network transport;
you just have to ask for it.
On the Cover
MI = Multiple Interfaces, Not Multiple Inheritance
The flip side of interfaces is how they are implemented by an
object. An OLE object may support many different interfaces, such as for streaming, printing, or drawing on the
screen. Delphi 3 extends the declaration syntax of the class
type, so you can declare a class as an implementor of one or
more interface specifications. The Delphi compiler takes care
of binding declared methods in the interface types to implemented methods in the class type. No tables of macros of
pointers to functions to crosswire with a typo the compiler does it all. When something isnt quite right, the Delphi
compiler tells you where and what youve missed in your declarations. For example, an interface-implementing class must
implement all methods declared in the interface type. If you
forget one of the interface methods, the compiler will remind
you, just as it reminds you when you declare a method in a
class type, but forget to give it a method body.
When a class implements an interface, instances of that class
type are assignment-compatible with variables of the interface
type. You can take an object instance and assign it to an
interface variable, and the compiler will do the magic of
extracting the correct interface pointer from the object
instance automatically. You can also do late-bound (run-time)
interface extraction using the as typecast operator, which calls
the implementors QueryInterface method to obtain the
desired interface at run time.
Note that while an object may implement multiple interfaces,
this is not the same as multiple inheritance; you are not inheriting any implementation details from the multiple interfaces.
What this means is that implementing OLE objects (such as
ActiveX controls and custom COM servers) is now almost trivial. Delphi 3 requires none of the unintelligible tables of macros
of pointers that Microsofts ActiveX SDK heaps on itself. Where
Microsoft implements ActiveX as a system of macros and C++
template classes on top of the C/C++ language, Delphi implements ActiveX by incorporating the essential enabling technologies into the Object Pascal language and VCL classes. Why
bother with macros and well-meaning source code conventions
when you can have the compiler do the dirty work for you?
Data Visualization
Delphi 3s Component palette includes three new heavy-hitters:
an all-new version of QuickReport, powerful charting capabilities in TeeChart, and the DecisionCube interactive crosstab (see
Figure 7). You can embed TeeCharts in QuickReport reports, as
well as link a TeeChart to the DecisionCube to graphically display the crosstab data on-the-fly.
On the Cover
The Code Completion feature helps
you enter field names and parameter
values by displaying a pop-up list of
identifiers that are type-compatible
with the source code expression to
the left of the editor cursor. For
example, typing:
"Caption := IntToStr(ProgressBar1."
On the Cover
name and SQL dialect or vendor. BDE aliases allow you to revector server references on a client machine without recompiling
the client application, but those aliases are still on the client
machine. If your SQL server goes down and you have to prop up
your business with a backup machine, how do you make all
your clients automatically talk to the backup machine instead?
Another problem with two-tier is related to centralization of business rules and data policies. In the standard two-tier SQL model,
the rules that determine data relationships and links within the
database must be implemented on either the server or the client.
SQL has proven itself to be an adequate tool for describing and
managing data, but is terrible for implementing the programming logic required for complex business rules, such as non-tabular tax calculations or least-cost resource allocation. This means
enterprise-wide business rules tend to be implemented in the
client application instead of on the centralized server, inflating the
size of the client application and creating a maintenance liability.
Conclusion
There are too many exciting new features in Delphi 3 to cover
in one article, or even to try to absorb in one sitting. Id love to
rattle on about the Web-server dispatch and database components for building Netscape and Microsoft Internet Information
Server extension .DLLs, or the extensive support for DIB image
formats and direct pixel memory pointers in TBitmap, the new
TJPEGImage class, or the new globalization of the Delphi RTL
and VCL classes to support multi-byte character sets in Asian
locales, or the all-new documentation set and online Help, but
for now a tease will have to do. So many ideas, so little time.
Important note: This article is based on a prerelease version of
Delphi 3. Features may differ or be absent in the shipping version.
Danny Thorpe is a Delphi R&D engineer at Borland. He has also served as technical editor and advisor for dozens of Delphi programming books, and recently
wrote Delphi Component Design [Addison-Wesley, 1997] on advanced topics in
Delphi programming. When he happens upon some spare time, he rewrites his
to-do list manager to ensure that it doesnt happen again.
On the Cover
Delphi 3
By Robert Vivrette
Easier Yet
A Look at the Delphi 3 Code Editor
hen car shopping, youre first drawn by outward appearance. Then you
get close enough to check out the details of the trim, upholstery, and
dashboard. Then you open the door and ease into the drivers seat, maybe
push a few buttons, or check out the stereo. Car manufacturers strive to make
your driving experience more enjoyable, so theyre always trying to match the
cars functionality to consumer desires.
Its the same for software. Users demand a
better look, an easier-to-use interface, and
powerful new features that make their lives
simpler. This is certainly the case with the
enhancements to the Code Editor of Delphi
3 and Borland has delivered.
In the Gutter
The first difference youll notice when you
open the Code Editor is the inclusion of a
gutter on its left side. Weve all experienced trying to select a line of text by clicking near the front of the line, only to set a
breakpoint instead. By adding this gutter,
the new IDE provides a clickable area for
setting breakpoints, bookmarks, and the
like, as well as providing an area to show
various status glyphs.
Youll also notice one or more glyphs next
to each line of code (see Figure 2). The
small blue dots appear after you compile or
build, on each line for which code is generated. This is a particularly useful aid in setting breakpoints.
As a test, I placed:
if False then
Figure 1: The new look of Delphi 3 features the flat buttons made popular by Microsoft Office 97.
12
On the Cover
Figure 2: The Code Editor now features a gutter with breakpoints, bookmarks, linked status, etc. indicated with glyphs.
time, you can position the mouse over a variable, and it will
display that variables current value (see Figure 3). This also
works on constants and parameters passed to a function or
procedure. If no value appears, the value hasnt been defined,
or optimization was turned on and the variable isnt available.
if True then
Drag-and-Drop
Another new feature in the Code Editor is support for
drag-and-drop text editing ( la Word). You can now select
a section of text, grab it with the mouse, and drag it somewhere else. If you hold down C while doing this, the text
is copied rather than moved.
Code Templates
Another nifty time-saver of the new IDE are Code
Templates. A Code Template is a defined structure of code
that you can access through a menu, or by means of a
shortcut mnemonic.
The best way to understand how it works is to see it in use.
In Figure 4, I began typing code for a ButtonClick event. I
want to use an if statement, so I enter if, and call the
Code Template by pressing CJ. Delphi then presents a
list box of all if statements Ive defined, allowing me to
pick one. When I choose one, it inserts the text associated
with that template (see Figure 5).
You can easily define new templates, or modify existing
ones on the Code Insight page of the Environment
Options dialog box (see Figure 6). For each template, you
Code Insight
One of the great time savers in the new IDE is a group of
features named Code Insight. This term refers to four specific
enhancements made to the Delphi 3 Code Editor: ToolTip
Expression Evaluation, Code Templates, Code Completion, and
Code Parameters. Lets look at each enhancement.
On the Cover
Figure 7: The new Code Completion feature offers valid procedures, functions, properties, and variables while you type.
Code Completion
The third portion of Code Insight is the Code
Completion feature. Whenever you enter a class name
followed by a period, you will be presented with a list of
properties, methods, and events appropriate to the class.
You can then select an item, and it will be entered into
the code. Figure 7 shows Code Completion presenting a
list of the methods, properties, and events appropriate
for a Form object.
Furthermore, when you enter an assignment statement
and press CM, a list of valid variables is displayed.
14
Figure 8: The new Code Parameters feature helps you remember valid parameters without consulting the Help system.
Code Parameters
The fourth piece of Code Insight is the Code Parameters
feature, which allows you to view the required arguments
for a method as you type it. Code Parameters is triggered
when you enter a method name followed by an opening
parenthesis (see Figure 8).
In Figure 8, Code Parameters is activated for the Draw
method of the forms Canvas. There are three parameters for
this method: the X and Y coordinates, and the graphic to be
drawn. Code Parameters even highlights the particular parameter youre working with. As you move the cursor around
in the Code Editor, the Code Parameters feature keeps up
with you, highlighting the appropriate parameter.
Even more interesting, Code Parameters knows the difference between Windows API calls and Delphi wrapper
methods that happen to have the same name. For example,
if you were to type Canvas.Rectangle, it knows that you are
talking about Delphis Rectangle method, which only requires
the coordinates of the four corners of the rectangle. However,
if you just enter Rectangle, it knows youre talking about
the Rectangle function in the Windows API, which requires
completely different parameters.
On the Cover
Conclusion
The enhancements to the IDE in Delphi 3 will save a lot of
time and effort for developers. The new Code Editor gutter
provides visual clues about breakpoints, bookmarks, lines that
generate code, the program execution point, and more. The
Code Insight system is a real time-saver that allows you to
quickly insert common code structures into the Editor, and
helps with parameters to method calls. The ToolTip
Expression Evaluation hints help you examine variables at
run time in a manner more convenient than the standard
Watch window.
On top of an already powerful language and compiler, these
IDE improvements really will make Delphi 3 a more functional and productive development system.
Important note: This article is based on a prerelease version of
Delphi 3. Features may differ or be absent in the shipping version.
Robert Vivrette is a contract programmer for Pacific Gas & Electric, and
Technical Editor for Delphi Informant. He has worked as a game designer and
computer consultant, and has experience in a number of programming languages. He can be reached via e-mail at [email protected].
15
Informant Spotlight
Delphi 2 / Object Pascal / Word for Windows
By Ian Davies
Automated Word
Creating OLE Automation Clients: Part 1
his article will cover some general uses of OLE automation, building on
Cary Jensens article OLE Automation in the October 1996 issue of
Delphi Informant. Here, well concentrate on creating OLE automation clients
using Delphi 2 that access services and functions provided by existing Microsoft
Office OLE servers, such as Microsoft Word, Excel, and Access.
Why Microsoft Office? According to
Microsoft, Office has over 80 percent of the
office suite market thats why.
Informant Spotlight
uses
Windows, Messages, SysUtils, Classes, Graphics,
Controls, Forms, Dialogs, OLEAuto;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
V: Variant;
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
V := CreateOLEObject('Word.Basic');
{ Execute the Word AppShow method to un-hide itself. }
V.AppShow;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
V.Insert('Hello from Delphi');
end;
end.
Figure 1: Keeping Word in scope by declaring the Variant variable at the form level.
Each time this procedure is called (i.e. each time the button is clicked), Word will be loaded, some text will be
inserted in the normal document, and Word will be closed
again. This is an important issue, because the Word executable file (not including any supporting .DLLs) is
almost 4MB (for version 7).
In contrast, if V was declared as a global variable or as a
member of the form, it would exist for the life of the form
(i.e. normally for the life of the application). If the
CreateOLEObject method was then placed in the OnCreate
event of the form, the server would be loaded once when your
form is created, and lose scope only when the form is
destroyed, normally as the application is closed (see Figure 1).
Note the use of the AppShow statement in the FormCreate
procedure. OLE automation servers are normally hidden
from view; this is the statement issued to Word to make it
visible. Now, when the project is executed, Button1 can be
clicked repeatedly, and the text appears almost immediately.
AppShow and Insert are OLE server statements.
In the case of Microsoft Office (and most other servers), they
would be used if you programmed those applications directly.
Word versions 6 and 7 use WordBasic, Access 2 uses Access
Basic, and Word 97, Excel (versions 5, 7, and 97), and Access
version 7 all use Visual Basic for Applications (VBA).
17
Informant Spotlight
procedure TMainForm.GenerateInvoiceBtnClick(Sender:
TObject);
begin
Screen.Cursor := crHourglass;
Application.ProcessMessages;
{ Create new invoice document. You may have to amend the
path, depending upon where the template is stored. }
MSWord.FileNew(Template :=
'C:\MSOffice\Templates\Other Documents\INVOICE.DOT');
{ Remove protection on this document to
allow insertion of text. }
MSWord.ToolsUnprotectDocument;
{ Call the procedure that jumps to correct bookmark and
inserts the current date. }
GotoBookmark('Date');
MSWord.Insert(FormatDateTime('dd/mm/yy', Now));
{ Call the procedure that jumps to the correct bookmark
and inserts the Invoice Number, etc. }
GotoBookmark('Invoice_Number');
MSWord.Insert('123456');
GotoBookmark('Quantity_1');
MSWord.Insert('1');
GotoBookmark('Description_1');
MSWord.Insert('Marine Magnetometer');
GotoBookmark('Price_1');
MSWord.Insert('545.58');
GotoBookmark('Amount_1');
MSWord.Insert('545.58');
GotoBookmark('Subtotal');
MSWord.UpdateFields;
GotoBookmark('Total');
MSWord.UpdateFields;
{ Save the document with the filename TEMP.DOC
and close the file without prompting the user. }
MSWord.FileSaveAs('c:\temp.doc');
MSWord.FileClose(2);
{ Link the OLE Container to the file just created. }
PreviewForm.OLEContainer1.CreateLinkToFile('c:\temp.doc',
False);
Screen.Cursor:=crDefault;
Application.ProcessMessages;
{ Show the form containing the OLE Container. }
PreviewForm.ShowModal;
end;
To create a functional example, well use the Invoice template provided with Word 7, insert the appropriate information, and offer the user a preview of the invoice and the ability to print it.
The invoice is created by calling the WordBasic FileNew
statement. To enable some text to be programmatically
inserted, the file protection on this document must be
removed using the ToolsUnprotectDocument method. The
sub-total and total fields on the Invoice template are calculated fields, which simply need to be updated to show the
correct values. This is done using the UpdateFields statement. Finally, the document can be printed by using the
FilePrint statement.
18
Function
Use
FileOpen(FileName)
CountBookmarks()
BookmarkName$(Index)
ToolsMacro(MacroName)
FilePrint(NumCopies := x)
FileClose(x)
Informant Spotlight
Macro and enter GetSpelling as the Macro Name. Next,
click on the Create button and insert the WordBasic code
to describe the macro.
Informant Spotlight
First, any operation that would normally display a dialog box
should be treated with care. For example, closing a document
that may have been modified since it was last saved will result in
a prompt to save changes. Either ensure that the document is
saved before closing, or that the document is closed with a parameter indicating that you do not want to save any changes, i.e.
FileClose(2).
Also, sending the FileSave statement when a document
hasnt been saved will display the Save As dialog box. This can be
avoided by using the FileSaveAs statement with a filename
passed as a parameter.
Finally, Word has a facility that prompts the user to enter
summary information that will appear when the document
properties are obtained (using Explorer, for example). To
prevent this, either enter summary information using the
FileSummaryInfo statement, or turn this facility off with
the following statement:
ToolsOptionsSave(SummaryPrompt := 0, GlobalDotPrompt := 0)
Conclusion
This article has provided some background information on
creating OLE automation clients, and introduced some practical uses of using OLE automation with Microsoft Word.
Next month, well discuss how Microsoft Excel can be put to
good use from a Delphi application.
Its well worth coming to grips with OLE automation or simply Automation as its becoming known. Microsoft has chosen
this technology (over the likes of DDE) as a key feature of future
versions of Windows. Taking the concept one step further,
Windows NT 4 (server and workstation) now supports DCOM
(Distributed Component Object Model), which means the OLE
server doesnt need to reside on the same computer as the client,
but can be accessed over a LAN, an intranet, or the Internet.
Ian Davies is a developer of 16- and 32-bit applications for the Inland Revenue in
the UK. He began Windows programming using Visual Basic about four years ago,
but has seen the light and is now a devout Delphi addict. Current interests include
Internet and intranet development, inter-application communication, and sometimes a combination of the two. Ian can be contacted via e-mail at
106003.3317 @compuserve.com.
20
By Dan Ehrmann
any Delphi developers use the Paradox file format every day, yet the
Delphi documentation offers almost no information about it. In this article, well explore the available field types in Paradox tables, and examine some
important properties of each type. Youll learn how fields are stored in the .DB
file, and how to calculate record and table size for any table. Also, Ill supply a
sample application that performs these calculations for any specified table.
21
However, this isnt how Delphi works. When memos are displayed, the whole memo is read for each displayed field. The
first nn characters in each memo are stored twice once in
the .DB file, and again in the .MB file. If nn is large, this
duplication might use a lot of disk space.
Type
Abb.
Size (bytes)
Level
Delphi
Object
Standard
Component
Notes
Alpha
Ann
nn bytes;
1 <= nn <= 255
Pre-4
TStringField
TDBEdit
Number
Pre-4
TFloatField
TDBEdit
Money
Pre-4
TCurrencyField TDBEdit
Short
Pre-4
TSmallIntField
TDBEdit
Long Integer
TIntegerField
TDBEdit
Date
Pre-4
TDateField
TDBEdit
Time
TTimeField
TDBEdit
Timestamp
TDateTimeField TDBEdit
Memo
Mnn
10 + nn in the .DB;
1 <= nn <= 240
TMemoField
TDBMemo
Formatted
Memo
F(nn)
10 + nn in the .DB;
0 <= nn <= 240
TBlobField
TDBRichEdit
Graphic
TGraphicField
TDBGraphic
OLE
TBlobField
TDBImage
(see note)
Binary
B(nn)
10 + nn in the .DB;
0 <= nn <= 240
TBlobField
TDBImage
(see note)
Byte
Ynn
nn bytes;
1 <= nn <= 255
TBytesField
TDBEdit
Logical
TBooleanField
TDBCheckBox
BCD
#.nn
17
1 <= nn <= 3
TBCDField
TDBEdit
Autoincrement
TAutoIncField
TDBEdit
-307
15
31
Type
Size
(bytes)
OrderNo
CustNo
SaleDate
SaleTime
ShipDate
EmpNo
ShipToContact
ShipToAddr1
ShipToAddr2
ShipToCity
ShipToState
ShipToZip
ShipToPhone
ShipVIA
PO
Terms
+*
A8
D
T
D
A5
A20
A30
A30
A15
A2
A10
A20
A5
A12
A6
4
8
4
4
4
5
20
30
30
15
2
10
20
5
12
6
PaymentMethod
ItemsCount
ItemsTotal
SalesTax
Freight
TotalInvoice
AmountPaid
Government
OrderNotes
Record Size
A7
S
$
N
$
$
$
L
M10
7
2
8
8
8
8
8
1
20
249
For example, you might store readings from scientific instruments in a Binary field, then write special procedures to
process and interpret this data.
The next Autoincrement value is stored in the tables header,
where theres room for only a single value; hence the limit of
one Autoincrement field per table.
Field Names
Paradox field names follow these rules:
24
Dan Ehrmann is the founder and President of Kallista, Inc. a database and
Internet consulting firm based in Chicago. He is the author of two books on
Paradox and is a member of Team Borland and Corels CTech. Dan was the
Chairman of the Advisory Board for Borlands first Paradox conference, which
evolved into the current BDC. He has worked with the Paradox file format for
more than 10 years. He can be reached via e-mail at [email protected].
in development
Delphi 2 / InstallShield
By Bill Todd
Deployment: Part I
Deploying Delphi 2 Applications with InstallShield
Express and InstallShield Express Professional
The Setup
This article will take you through creating
a setup for a typical Delphi application. It
needs the BDE, but it doesnt use
ReportSmith. The program will be installed
on stand-alone PCs at some locations,
while at others it will be installed on a
LAN. The application uses local Paradox
tables as its database.
25
in development
in this case, a problem exists with Paradox tables, because there
is no safe way to set the Net Dir (network control directory
path) parameter of the Paradox driver as part of the installation
process. (A more detailed explanation of network installation
problems will be presented later in this article.)
When you install the BDE on a workstation, the installation not
only installs the BDE files on the workstation hard disk, but also
makes many entries in the Windows registry. Unfortunately,
theres no installation program Im aware of that supports a server-only BDE installation, i.e. an installation that puts the BDE
files on the server and makes only the necessary registry entries
on the workstation. Using a local BDE installation with a shared
configuration file on the server isnt easy either. This is because
the BDE uses a registry entry to determine where the BDE configuration file is located. Certainly the most common BDE
architecture is to install the BDE files on each workstation. This
provides much better performance if, like most networks, the
data transfer rate across the network is ten times slower than the
data transfer rate from the workstations local hard disk.
in development
buttons of the same name on the main form. At the Main
Window page you can opt to display the application name
as text on the background during installation, a custom
bitmap for the applications title, and a logo bitmap as
your companys logo. Finally, you can choose the background color displayed during installation.
The Features page contains a single option, Automatic
Uninstaller. This check box is checked by default so that an
uninstall option will be provided for your application. I
cant imagine why anyone would not want this feature.
Enter the application name. This is the name that the user
will see in the background when installing the application.
Click the ... (browse) button to the right of the Application
Executable edit box to find the main .EXE file for your
application. If the .EXE contains a version resource, the
version number will be displayed automatically in the
Version field. If not, you can enter any version number you
wish. This is an alphanumeric field that can accommodate
complex version numbers that include letters. Finally,
enter your company name or abbreviation. The string you
enter here will be the name of the top-level directory that
InstallShield Express will create in the Program Files directory to hold your programs.
The Set the Visual Design dialog box has two additional
pages, Main Window and Features, that correspond to the
27
in development
The dialog box in Figure 5 enables you
to choose to install the BDE, SQL
Links, or ReportSmith Runtime. After
checking the BDE check box, you can
use the Settings button to define any
aliases you want added to the BDE
configuration file. If you are creating an
alias to a database server, you can also
enter any parameters you want to set
for the alias in the window at the bottom of the form. Parameters must be
entered one-per-line in the format:
ParameterName=Value
28
in development
their workstation to run the copy of
the programs .EXE file on the server,
and install the BDE on their local
hard drive.
Specifier
<INSTALLDIR>
<WINDIR>
<WINSYSDIR>
<WINDISK>
<WINSYSDISK>
<WINSYS16DIR>
<PROGRAMFILESDIR>
<COMMONFILESDIR>
Description
The main installation directory
specified by the user.
The Windows directory.
The Windows\System directory.
The drive that the Windows
directory resides on, for
example, C:.
The drive that the Windows
system directory resides on.
On an NT system this is the
16-bit Windows directory.
The Program Files directory.
The Program Files\Common
Files directory.
list, and
On the Setup Types page you will find the three setup types,
Custom, Typical, and Compact, listed on the left, and the
components listed on the right. To add a component to a
setup type, click the setup type, then the component, then
the Add to Setup Type button. Adding the Application Files
component to all three setup types and the Data Tables component to the Typical setup provides the configuration you
need. Typical will install the entire application including the
BDE and data tables on either a file server or stand-alone system. Compact will install only the BDE and application for a
network workstation. Note that when users perform a
Compact installation to a network workstation, they must
specify the directory on the server that contains the program files as the installation directory. This will configure
29
Next, return to the Dialog Boxes button, and click it to display the dialog
box shown in Figure 8. The check
boxes let you control what dialog
boxes are displayed during the installation process. For example, Software
License Agreement and Readme
Information allow the user to see and
accept your license agreement and
view your readme file. To specify the
file that contains your license agreement, click on Software License
Agreement to select it, then click the
Settings tab and enter the path to the
text file. The Readme Information
option works the same way.
The Settings page for the Select Program Folder check box
enables you to enter the name of the program folder that will
be created for your program. If you dont enter a value, your
InstallShield Express project name will be used. You even
have the option to sign up for Pipeline Communications
online registration service to allow your users to register their
software via modem during installation.
in development
Configuring the BDE
in development
You can test the installation on your computer from within
InstallShield Express by clicking the Test Installation button.
When everything works the way you want it to, use the Copy
to Floppy button to make your diskettes.
InstallShield Express is a big step up from the days of Delphi
1, where you got a self-installing version of the BDE, but
you were on your own as far as installing your program and
its associated files. It has a simple, clear user interface and
good online Help. With the exception of a more elegant way
to set the Local Share option and a way to set the network
control directory path for Paradox tables, InstallShield
Express provides all the features you need to install basic
database applications.
NET DIR settings will not be able to access the same database at the same time. You will either have to write a separate
program that checks to see if the path to the network control
directory is already set, and if not, set it using BDE API calls.
Or you will have to give the user instructions for changing
this setting using the BDE configuration program.
If you are adding one or more new aliases to the target system, you must be careful to pick names that will be unique.
If an alias on the target system has the same name as an alias
you are trying to add, the Type and Path parameters for the
alias will be updated to the values you supplied, but none of
the other parameters will be changed. This could leave the
target system in a state where the alias exists, but your program does not work as expected.
Conclusion
After you have created your installation, run the Disk Builder
to create the diskette images for your installation diskettes.
31
Bill Todd is President of The Database Group, Inc., a database consulting and development firm based near Phoenix. He is co-author of Delphi: A Developers Guide
[M&T Books, 1995], Delphi 2: A Developers Guide [M&T Books, 1996], and
Creating Paradox for Windows Applications [New Riders Publishing, 1994], and is a
member of Team Borland providing technical support on CompuServe. He is also a
nationally known trainer and has been a speaker at every Borland Developers
Conference and the Borland Conference in London. He can be reached on
CompuServe at 71333,2146, on the Internet at [email protected],
or at (602) 802-0178.
DBNavigator
Delphi 2 / Delphi 3
Overview
Unless you program otherwise, changes to
records being edited by the user are posted
(applied) to the underlying database as soon
as the user has performed an action that
posts the record, e.g. moving off the record,
or clicking the Post changes button of a
linked DBNavigator component. Likewise,
you can programmatically post edits by initiating a move off the record, or by explicitly
calling a DataSets Post method.
When cached updates are enabled, the
Borland Database Engine (BDE) tracks all
data changes (modifications, insertions, and
deletions) locally. After the necessary changes
are made, theyre applied to the underlying
database as a group. The advantages of using
cached updates include:
Users can edit one or more records, then
cancel all changes without ever affecting the underlying data.
Network traffic may decline, because
edits neednt be transmitted across the
network individually.
32
DBNavigator
As you can see, this list argues powerfully for the use of
cached updates.
The following demonstration uses a
Paradox table, for simplicitys sake. While
cached updates are especially useful in
client/server applications, characteristics
of individual servers affect which techniques youll use to apply your updates.
By using a Paradox table, those serverspecific issues can be avoided.
Consider the following event handler associated with a button. Assuming the DataSet named Table1 is set to cache
updates, clicking this button will attempt to apply the
updates, then clear the cache. If ApplyUpdates generates an
exception, then CommitUpdates doesnt execute; consequently, the cache remains intact:
procedure TForm1.Button1Click(Sender: TObject);
begin
Table1.ApplyUpdates;
Table1.CommitUpdates;
end;
DBNavigator
procedure TForm1.FormCreate(Sender: TObject);
var
OldTable: TTable;
begin
OldTable := TTable.Create(Self);
try
OldTable.DatabaseName := 'DBDEMOS';
OldTable.TableName
:= 'CUSTOMER.DB';
Table1.TableName
:= 'CUST1.DB';
Table1.BatchMove(OldTable,batCopy);
Table1.AddIndex('','CustNo',[ixPrimary, ixUnique]);
Table1.Open;
finally
OldTable.Free;
end;
end;
34
As you inspect the code for Button1s OnClick event handler, youll notice that this project doesnt permit users to
edit the table unless they begin caching. Though this isnt
an essential feature, you might still want to employ it.
However, the primary technique to prevent the user from
editing the table that of setting the DataSources
AutoEdit property to False is sometimes only partially
successful. When you view a table through a DBGrid (or
use a DBNavigator, as is being done here), a user can still
insert and delete records even when AutoEdit is set to
False. Consequently, this project contains two additional
event handlers. One is on Table1s BeforeDelete event property, while the other is on Table1s BeforeInsert. From this
code, the tables CachedUpdates property is inspected; an
exception is raised if the property is not set to True. This
technique is demonstrated in the following event handler,
which is assigned to Table1s BeforeDelete event property:
procedure TForm1.Table1BeforeDelete(DataSet: TDataSet);
begin
if not Table1.CachedUpdates then
raise EDenyEdit.Create(
'Click Start Caching to delete a record');
end;
Finally, theres the issue of closing the table without applying cached updates, if some are pending. As you learned
earlier, all pending cached updates are lost if the table is
closed before the updates are applied. You can determine if
any cached updates are pending by inspecting the tables
UpdatesPending property. This property is True if the table is
caching updates, and if unapplied updates remain in the
cache; otherwise, its False. Note, however, that inspecting
the value of UpdatesPending when the corresponding
DataSets CachedUpdates property is set to False generates an
exception. Consequently, you should test UpdatesPending
only after confirming that CachedUpdates is True.
The CACHE1 project demonstrates the use of this property
in the forms OnCloseQuery event handler, as shown in
Figure 4. When the form is being closed, any pending edits
are first posted to the table. Next, if updates are being
cached, UpdatesPending is tested to determine whether or
not the cache is empty. If not, the user is asked to indicate
whether to cancel pending edits, or post them. If the user
confirms posting of the edits, but ApplyUpdates fails, an
exception is raised, and the form doesnt close.
DBNavigator
procedure TForm1.FormCloseQuery(Sender: TObject;
var CanClose: Boolean);
begin
if Table1.State in [dsInsert, dsEdit] then
Table1.Post;
if Table1.CachedUpdates and Table1.UpdatesPending then
if MessageDlg('Updates pending. ' +
'Select OK to apply, Cancel to lose',
mtInformation,
[mbOK,mbCancel],0) <> mrOK then
Table1.CancelUpdates
else
begin
Table1.ApplyUpdates;
Table1.CommitUpdates;
end;
end;
Using Database.ApplyUpdates
The TDatabase class also supports an ApplyUpdates method.
This method has the following syntax:
procedure ApplyUpdates(const DataSets: array of TDataSet);
DBNavigator
procedure TForm1.Button1Click(Sender: TObject);
begin
if not Table1.CachedUpdates then
begin
Table1.CachedUpdates := True;
DataSource1.AutoEdit := True;
Button1.Caption
:= 'Apply Updates';
Button2.Enabled
:= True;
end
else
begin
if Table1.State in [dsInsert, dsEdit] then
Table1.Post;
if Table1.UpdatesPending then
// Need to update only if cached edits are pending.
begin
Table1.Database.TransIsolation := tiDirtyRead;
Table1.Database.StartTransaction;
try
Table1.ApplyUpdates;
Table1.Database.Commit;
Table1.CommitUpdates;
except
Table1.Database.Rollback;
raise;
end;
end;
DataSource1.AutoEdit := False;
Table1.CachedUpdates := False;
Button1.Caption
:= 'Start Caching';
Button2.Enabled
:= False;
end;
end;
Figure 5: The OnClick event handler for the Start Caching button of the CACHE2 project.
procedure TDatabase.ApplyUpdates(
const DataSets: array of TDBDataSet);
var
I: Integer;
DS: TDBDataSet;
begin
StartTransaction;
try
for I := 0 to High(DataSets) do begin
DS := DataSets[I];
if DS.Database <> Self then
DatabaseError(FmtLoadStr(
SUpdateWrongDB,[DS.Name, Name]));
DataSets[I].ApplyUpdates;
end;
Commit;
except
Rollback;
raise;
end;
for I := 0 to High(DataSets) do
DataSets[I].CommitUpdates;
end;
Conclusion
Cached updates greatly increase your record-editing options.
In addition, the technique can generally improve your applications performance. Fortunately, in its simplest case that
of editing a single table cached updates are easy to employ.
Next months installment will continue the discussion of
cached updates by considering how to work with individual
records in the cache, and how to use the UpdateSQL component to permit editing of read-only DataSets.
The files referenced in this article are available on the Delphi
Informant Works CD located in INFORM\97\MAY\DI9705CJ.
36
On the Net
Delphi 2 / Object Pascal / Internet / Intranets
By John Penman
NetCheck: Part I
A 32-Bit Tool for Debugging Networks
ith the Internet and intranets playing important roles in the way we work
and communicate, any network application we use must be robust. An
application must always check the connectivity between itself (the client) and
the server.
Developers can easily add this connectivity
check to any network application; however, developing applications for the
Internet and intranets can be a tricky,
frustrating exercise. A developer must contend with two possible sources of apparent
program failure: poor network connectivity and internal program errors (i.e. bugs).
A network problem is less common than
an application bug, but can happen at
unexpected times. Network problems can
be caused by an improperly installed network card, a malfunctioning router that
can cause a break in the network, etc.
Sometimes its difficult to differentiate
between the two, so its important for a
developer to have a network debugger that
helps track down such problems.
Ping
To test connectivity between two peer
machines on a network, well use ping, a
popular diagnostic tool with its roots in the
UNIX world, now widely available on
diverse platforms, including Windows. The
ping application uses the Internet Control
Message Protocol (ICMP) to send an echo
request packet to the server. The server, if
running, responds automatically by returning an echo reply packet.
Figure 1: The complete NetCheck program with its Sonar, EchoC, and
Trace components.
37
On the Net
required on the server-to-service echo request packets. In contrast, an echo service (as well discuss in Part II) requires a
server program on the target host to service echo requests.
Using ping is an excellent way to check the connectivity
between peers at the Internet Protocol (IP) layer.
Additionally, ping yields interesting information such as the
round-trip time between the sender and target host, which
we can analyze for clues to packet loss.
The downside to ping is that its fallible. For example, the target host may hide behind a firewall server that filters out echo
request packets, preventing the target host from replying.
In UNIX and some Windows platforms, a ping application
uses raw sockets to work with ICMP packets. Some implementations of Winsock, such as Microsofts Winsock 1.1 for
Windows 95, do not support raw sockets. Microsoft has
included the ICMP.DLL file with its current release of
Windows 95 to rectify this lack of raw sockets support. The
Sonar component uses this .DLL.
(Note that Windows NT 4.0 uses Winsock 2.0, which does
support raw sockets, and Winsock 2.0 for Windows 95 is
expected to be released later this year. In a future article, Ill
present an enhanced version of the Sonar component to work
with raw sockets.)
I named this component Sonar because it sounds a target
host similar to how a ships sonar sounds an underwater
object. The client sends an echo request packet to a server,
which in turn must respond automatically by echoing an
echo reply packet. Hopefully, the name Sonar will distinguish it from other ping applications.
Inside Sonar
Sonar is based on the TSonar class (see Listing One on page
40), a direct descendant of TComponent. (I used Martien
Verbruggens demonstration ping program to develop Sonar.
See the reference listed at the end of this article.) Like all
components, the TSonar class has a constructor method,
TSonar.Create, that initializes some properties and calls two
functions to perform essential tasks.
The first function, CheckWS, initializes WINSOCK.DLL. If
Winsock isnt functioning or is missing, Sonar displays a
Warning dialog box and closes the calling application. Sonar
does this because the Sonar, EchoC, and Trace components
rely heavily on WINSOCK.DLL. Thus, it doesnt make sense
to continue with the application when Winsock isnt available.
The second function, CheckICMP, tries to create the
hIcmpModule handle for ICMP.DLL. If LoadLibrary fails to
load the .DLL, it sets hIcmpModule to nil. CheckWS assigns a
Boolean value to a read-only property, PingAvail, which
NetCheck starts up. When PingAvail is False, NetCheck disables the Ping button, and displays a warning message in the
memPingMsg Memo control. In contrast to CheckWS, when
CheckICMP fails to load ICMP.DLL, it doesnt abort the call38
On the Net
IcmpSendEcho is synchronous, meaning it
will block when its
waiting for a reply from
the target host before
timing out. In other
words, NetCheck will be
unresponsive, and appear
dead. This isnt satisfactory. We can avoid this
by creating a thread for
IcmpSendEcho. (This feature is not implemented
in this version of
NetCheck; well address
this thorny issue next
month.)
As Sonar receives a successful reply packet, it updates variables such as Fmin, Fmax, FNoEchoes, and FRTTSum needed
to calculate simple statistics (see Figure 3). Sonar then calls
the OnRecvDataEvent procedure to pass a status message to
NetChecks memPingMsg Memo control.
Also, OnProgressEvent is called to update the pbPing
TProgressBar control in NetCheck. Figure 4 shows
NetCheck during a pinging session. At the end of the
session, NetCheck displays the statistics as shown in
Figure 5.
Figure 5: NetCheck after successfully pinging a host.
Installing NetCheck
To make NetCheck work on your machine, first install the
Sonar component. Use the SONAR.DCU unit to install
39
Conclusion
A growing need exists for networking applications to embed
some connectivity checks for network integrity. Therefore,
Delphi developers should use a simple network debugger to
On the Net
test their Internet applications and ensure their robustness.
In Part II of this series, well extend NetChecks capabilities
to include the complementary components to Sonar
EchoC and Trace. See you then.
References
Chapman, Davis, Building Internet Applications with Delphi
2 [QUE, 1996].
Dumas, Arthur, Programming Winsock [SAMS, 1995].
Quinn, Bob and Shute, David, Windows Sockets Network
Programming [Addison-Wesley, 1996].
Stevens, W. Richard, UNIX Network Programming [PTR
Prentice Hall, 1990].
Taylor, Don, et al., KickAss Delphi Programming, Chapters 4
and 5 [Coriolis Group, 1996].
Verbruggen, Martien. Source code for the demonstration
ping program is available on the Web from
http://www.tcp.chem.tue.nl/~tgtcmv and
http://www.delphi32.com/apps.
40
procedure
OnResolveEvent;
procedure
OnProgressEvent;
function
GetTTL : Byte;
procedure
SetTTL(ReqdTTL : Byte);
function
GetPktSize : Word;
procedure
SetPktSize(ReqdPktSize : Word);
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
function
CheckWS : Boolean;
function
CheckICMP : Boolean;
procedure
GetHost;
procedure
DoSonar;virtual;
procedure
Stats;virtual;
public
{ Public declarations }
property PingAvail : Boolean read FICMPAvail;
property Msg : string read FMsg;
property HostIP : string read FHostIP write FHostIP;
property Progress : LongInt
read FProgress write FProgress default 0;
property PktSize : Word
read GetPktSize write SetPktSize default PacketSize;
property Version
: string read FVersion;
property VersionDate : string read FVersionDate;
property Name
: string read FComponentName;
property Developer
: string read FDeveloper;
procedure Ping;
published
{ Published declarations }
property HostName : string
read FHostName write FHostName;
property NoPackets : Word
read FNoPackets write FNoPackets default 5;
property TimeOut : DWord
read FTimeOut write FTimeOut default 2000;
property OnRecvData : TNotifyEvent
read FOnRecvData write FOnRecvData;
property OnResolveData : TNotifyEvent
read FOnResolveData write FOnResolveData;
property OnProgress : TNotifyEvent
read FOnProgress write FOnProgress;
end;
On the Net
TIcmpCreateFile = function : THandle; stdcall;
TIcmpCloseHandle = function (ICmpHandle : THandle) :
Boolean; stdcall;
TIcmpSendEcho = function (ICmpHandle : THandle;
DestAddress : DWord; RequestData : Pointer;
RequestSize : Word; RequestOptions : pIPOptions;
ReplyBuffer : Pointer; ReplySize : DWord;
TimeOut : DWord) : DWord; stdcall;
const
IP_ERROR_BASE
= 11000;
IP_SUCCESS
= 0;
IP_BUF_TOO_SMALL
= IP_ERROR_BASE;
IP_DEST_NET_UNREACHABLE
= IP_ERROR_BASE + 2;
IP_DEST_HOST_UNREACHABLE
= IP_ERROR_BASE + 3;
IP_DEST_PROT_UNREACHABLE
= IP_ERROR_BASE + 4;
IP_DEST_PORT_UNREACHABLE
= IP_ERROR_BASE + 5;
IP_NO_RESOURCES
= IP_ERROR_BASE + 6;
IP_BAD_OPTION
= IP_ERROR_BASE + 7;
IP_HW_ERROR
= IP_ERROR_BASE + 8;
IP_PACKET_TOO_BIG
= IP_ERROR_BASE + 9;
IP_REQ_TIMED_OUT
= IP_ERROR_BASE + 10;
IP_BAD_REQ
= IP_ERROR_BASE + 11;
IP_BAD_ROUTE
= IP_ERROR_BASE + 12;
IP_TTL_EXPIRED_TRANSIT
= IP_ERROR_BASE + 13;
IP_TTL_EXPIRED_REASSEM
= IP_ERROR_BASE + 14;
IP_PARAM_PROBLEM
= IP_ERROR_BASE + 15;
IP_SOURCE_QUENCH
= IP_ERROR_BASE + 16;
IP_OPTION_TOO_BIG
= IP_ERROR_BASE + 17;
IP_BAD_DESTINATION
= IP_ERROR_BASE + 18;
// The next group is status codes passed up on status
// indications to transport layer protocols.
IP_ADDR_DELETED
= IP_ERROR_BASE + 19;
IP_SPEC_MTU_CHANGE = IP_ERROR_BASE + 20;
IP_MTU_CHANGE
= IP_ERROR_BASE + 21;
IP_UNLOAD
= IP_ERROR_BASE + 22;
IP_GENERAL_FAILURE = IP_ERROR_BASE + 50;
MAX_IP_STATUS
= IP_GENERAL_FAILURE;
IP_PENDING
= IP_ERROR_BASE + 255;
// Values used in the IP header Flags field.
IP_FLAG_DF
= $2;
// Dont fragment this packet.
// Supported IP Option Types.
// These types define the options that may be used
// in the OptionsData field of the
// ip_option_information structure.
// See RFC 791 for a complete description of each.
IP_OPT_EOL
= 0;
// End of list option
IP_OPT_NOP
= 1;
// No operation
IP_OPT_SECURITY
= $82; // Security option
IP_OPT_LSRR
= $83; // Loose source route
IP_OPT_SSRR
= $89; // Strict source route
IP_OPT_RR
= $7;
// Record route
IP_OPT_TS
= $44; // Timestamp
IP_OPT_SID
= $88; // Stream ID (obsolete)
// Maximum length of IP options in bytes.
MAX_OPT_SIZE = 40;
IP_TRACE
= IP_TTL_EXPIRED_TRANSIT;
IP_REACHED
= IP_SUCCESS;
IP_TIMEOUT
= IP_REQ_TIMED_OUT;
ICMP_STATUS_BASE
= $80000100;
ICMP_INVALID
= ICMP_STATUS_BASE + 0;
ICMP_NO_ADDRESS
= ICMP_STATUS_BASE + 1;
ICMP_CANCEL
= ICMP_STATUS_BASE + 3;
ICMP_BUSY
= ICMP_STATUS_BASE + 4;
MAX_TTL
= 255;
MIN_PACKET_SIZE
= 8;
var
IcmpSendEcho
: TIcmpSendEcho;
wsaData
: TWSAData;
LibCount
: Integer;
hIcmpModule
: HModule;
IcmpCreateFile
: TIcmpCreateFile;
IcmpCloseHandle
: TIcmpCloseHandle;
hIcmp
: THandle;
41
implementation
end.
On the Net
FMsg := Concat('Received ',
IntToStr(DataSize),' bytes from
',FHostIP,
' in ',IntToStr(RTT),' msecs');
Inc(FNoEchoes);
if RTT > FMax then
FMax := RTT;
if RTT < FMin then
FMin := RTT;
FRTTSum := FRTTSum + RTT;
end;
IP_BUF_TOO_SMALL
:
FMsg := 'Buffer too small';
IP_DEST_NET_UNREACHABLE
:
FMsg := 'Network unreachable';
IP_DEST_HOST_UNREACHABLE :
FMsg := 'Host unreachable';
IP_DEST_PROT_UNREACHABLE :
FMsg := 'Protocol unreachable';
IP_DEST_PORT_UNREACHABLE :
FMsg := 'Port unreachable';
IP_NO_RESOURCES
:
FMsg := 'No resources';
IP_BAD_OPTION
:
FMsg := 'Bad option';
IP_HW_ERROR
:
FMsg := 'Hardware error';
IP_PACKET_TOO_BIG
:
FMsg := Packet too large;
IP_REQ_TIMED_OUT
:
FMsg := 'Request timed out';
IP_BAD_REQ
:
FMsg := 'Bad request';
IP_BAD_ROUTE
:
FMsg := 'Bad route';
IP_TTL_EXPIRED_TRANSIT
:
FMsg := 'TTL expired in transit';
IP_TTL_EXPIRED_REASSEM
:
FMsg := 'TTL expired in reassembly';
IP_PARAM_PROBLEM
:
FMsg := 'Parameter problem';
IP_SOURCE_QUENCH
:
FMsg := 'Source quench';
IP_OPTION_TOO_BIG
:
FMsg := 'Option too big';
IP_BAD_DESTINATION
:
FMsg := 'Bad destination';
IP_ADDR_DELETED
:
FMsg := 'Address deleted';
IP_SPEC_MTU_CHANGE
:
FMsg := 'Specified MTU changed';
IP_MTU_CHANGE
:
FMsg := 'MTU changed';
IP_UNLOAD
:
FMsg := 'Unload';
IP_GENERAL_FAILURE
:
FMsg := 'General failure';
IP_PENDING
:
FMsg := 'Pending';
end; { case }
end; { with pEchoReply }
OnRecvDataEvent;
end;{ for }
IcmpCloseHandle(hIcmp);
finally
FreeMem(pReqData, FPktSize);
FreeMem(pData, FPktSize);
FreeMem(pEchoReply, BufferSize);
end;
end;
end;
42
At Your Fingertips
Delphi / Object Pascal
By Robert Vivrette
procedure TForm1.Button1Click(Sender:
TObject);
begin
SHAddToRecentDocs(
SHARD_PATH,PChar(
'c:\My Documents\Resume.doc'));
end;
The first parameter, SHARD_PATH, indicates that the second parameter specifies a
path name to the recently-used document. In
this example, the second parameter is a
pointer to a buffer that contains the filename. After executing this call, there will be
a reference to the Microsoft Word document
Resume.doc in the Documents menu.
This technique is most useful in situations
where the file has a registered association with
your Delphi application. That way, selecting
the item from the Documents menu will
launch your particular Delphi application.
If you include NIL as the second parameter,
all documents are cleared from the list.
At Your Fingertips
the control specified in
its FocusControl property gets the focus when
the user hits that accelerator key.
simple way is to have the code take a little breather at regular intervals. The following code shows one technique for
doing this:
PacingCount := GetTickCount;
repeat
Application.ProcessMessages;
until (GetTickCount - PacingCounter) > 50;
Robert Vivrette is a contract programmer for Pacific Gas & Electric, and Technical
Editor for Delphi Informant. He has worked as a game designer and computer
consultant, and has experience in a number of programming languages. He can
be reached via e-mail at [email protected].
Case Study
By The EDD Development Team
Case Study
Application Profile
The CalJOBS site unites employers and job seekers to exchange information about job openings and qualifications. The system also handles the administrative tasks of submitting completed job applications to interested employers.
Third-Party Products: Informix, OReillys WebSite Professional, and HREF Tools WebHub.
Informix Software
4100 Bohannon Dr.
Menlo Park, CA 94025
Phone: (415) 926-6300
Web Site: http://www.informix.com
46
WebHub which (at that time) was unique in providing a built-in, server-side saving state. This prevents the
user from providing the same information multiple times.
Distributed Processing. WebHubs architecture provided
the team with a scalable solution that reduced required
computing resources, and improved the speed at which
information was delivered to the customer. The Hub
distributes page requests to the least busy instance of the
program. CalJOBS uses a cluster of two Web servers,
which further distributes processing to multiple
instances of the application for optimal performance of
the transactions to a database server.
Multiple Open Queries. WebHub database publishing
components simplified the process of providing quick
response via queries over the Web. Users are given a
specified number of records in response to a query;
WebHub keeps the answer available, enabling quick
forward and backward scrolling.
Database Independence. Database security and integrity is maintained by allowing it to operate independently from the Internet application, and implementing a
captive browser using ActiveX technology. Delphi
allows the application to communicate with key clientserver relational databases (CalJOBS uses Informix).
The EDD is a California State agency dedicated to providing California residents with job services at all levels, while promoting the development of new
fields and encouraging employment opportunities throughout the state. For
more information about the EDD CalJOBS project, contact Jesse Odell at
[email protected] or (707) 575-4543.
o you go to sleep at night thinking about all the wonderful Delphi components you could build with some extra time and expertise? Perhaps
youd build a compound component consisting of an edit box, a list box, and
an Add button you could type a new entry into the edit box, press Add,
and your entry would be added to the list box. Or how about a currency control that displays negative numbers in red? Maybe a TStringGrid that sorts
itself on any column when you click on that columns header ...
Maybe youve created components, but still
have many questions about the process.
Have you wondered when you must override the Loaded procedure? How to test if
your code is called at run or design time?
What the Notification method is used for?
Or if theres a way to hide an inherited published property in a descendant component?
The Component Developer Kit version 2.0
(CDK) from Eagle Software can help you
build the components described above, and
learn the ins and outs of component construction. This wizard-driven tool provides stepby-step instruction through the component
development process, and generates Delphi
code with comments showing you where
changes are needed.
Using CDK
The CDK installs easily, and seamlessly integrates with Delphi. It adds the following
options to the Component menu: Modify,
Quick Install, Browser, New Test Program,
Code Style, and Directories. After installation,
the Component | New command (File | New
| Component in Delphi 1) invokes the main
CDK interface, replacing Delphis
Component Expert.
When you select Component | New, the
CDK displays five options: Super
Component, Descending Component, Business
Component, Dialog Component, and Smart
Template (described in this article, these
arent a component type). Figure 1 shows the
first screen in the CDK.
When the CDK generates the super component code, the CDK_Container becomes
a TCompoundComponentPanel, the parent
and owner of the sub-components. The
CDK code initializes private properties, and
provides for communication between components when handling events.
Descending Components. To create a component that adds
functionality to an existing one, select the Descending
Component option. The descending component will inherit the
properties and methods of an existing component, and add new
properties and methods, or override virtual methods in an
ancestor class.
If you know which component you want to descend from,
you can select it from a combo box listing all the components
in your VCL. If youre unsure, click on the I Need Help
Deciding radio button. The CDK presents a colorful flowchart
(see Figure 3) that walks you through the available classes by
asking questions such as, Will this component be visible at
runtime? and Is there a similar VCL Component that
already exists?
Business Components. Delphis RAD model does not
encourage developers to build three-tier applications. The
RAD path of least resistance is to place business rules into
the form unit. The unfortunate result of doing this is that
business code becomes difficult to maintain and impossible
to reuse.
Delphi 2 adds data modules that are supposed to be used
as a middle tier. Business components, together with data
modules, provide an even better solution to this problem.
(The business components can and probably should be
located in a data module in your project.) They provide a
business rules layer thats separate from the UI and dataaccess layers. The advantage of this separation is that the
business component can be reused independently of the
UI and the data access for any particular form or application. Because business components are data-aware, you
can still take advantage of the native Delphi data controls.
The business components generated by the CDK descend
Component
The CDK provides two Method templates for building read/write or readonly data-aware components. Lets say
you want to create a data-aware button with its Enabled property controlled by the value in a string field in
your database. Figure 4 shows the
DataChange method generated by the
read-only Data-Aware template.
DataChange is triggered when data
changes in the data source. Figure 5
shows code to set your buttons
Enabled property to True, if the data
field contains the word charge. A
more useful version of the button
would have a string property indicating which value (in the
database) enables it.
Embedded Components. Using the main tabbed notebook,
you can embed components in any component youre building. The difference between super and embedded components is that the latter do not require a CDK_Container.
Embedded components are owned by your original component, and will be children of it, if they have a Parent property.
This is especially useful for embedding non-visual components in a visual component. The example in the CDK manual is a rotating Label thats converted into a Clock by adding
procedure TDBButton.DataChange(Sender: TObject);
{ Triggered when data changes in DataSource. }
begin
if FFieldDataLink.Field = nil then
begin
{ CDK: Update your control to show there is no
data link (optional). For example, if your
control has a Caption property, you might use
the following line:
Caption := '*No Data Link*';
}
exit;
end;
{ CDK: Update your control to reflect data change.
For example, if this control were a descendant of
TCalendar, you could use the following line:
CalendarDate := FFieldDataLink.Field.AsDateTime;
Other ways to look at data:
AsBoolean
AsDateTime
AsFloat
...
}
end;
Method Templates
The CDK ships with many Method templates that provide
common functionality for your components or other classes.
Templates can be used with any class, including forms.
Thus, they can be used to add common functionality to any
application code.
The CDKs Keypress Filter, Component Link Handler,
Runtime Drag, and Method Override templates are Smart
templates. A Smart template displays dialog boxes allowing
you to customize the template code before its generated. For
example, when adding the Keypress Filter template to your
component, a dialog box requests information about what
numbers, letters, and punctuation to allow. This reduces the
amount of custom code you must write.
Get Smart
If you are not yet completely impressed by the CDK, read on.
Todays software standards demand that a first-class tool be
extensible. The CDK meets that criterion with its Smart
template generation facility.
When you select the Smart Template option, a CDK wizard
leads you through the steps for generating a Smart template (see
Figure 6). The SDKs manual shows how to generate a Smart
The Virtual Methods page shows the inherited virtual methods for components that are part of the Delphi 2 VCL. It
In addition to the
CDK_Container mentioned, the CDK ships with
24 other components, some
of which are quite useful.
The highlights are: the
CDKAnimation component, which animates a
series of bitmaps specified
by the user; the CDKLight,
which displays an LED
light in different colors,
with an on or off state;
and the CDKCheckList, a
list box with check boxes
next to each item.
Conclusion
displays the declaration of each virtual method and a reference to the component that first declares the method. The
Lineage page depicts the entire ancestry of all the components in the VCL, including new ones (a handy feature thats
missing from Delphis Browser).
The interface of the CDK Component Browser is more
straightforward than Delphis, and it provides some information that you must otherwise search the VCL source files to
find. However, it does not replace the functionality of the
Delphi Browser. This is because CDKs Component Browser
doesnt include information from the private and protected
sections of your components, or new virtual methods
declared in your new components.
51
The Component
Eagle Software
Developer Kit version 2.0
12021 Wilshire Blvd., Ste. 655
makes component-building Los Angeles, CA 90025
faster and less tedious for
Phone: (310) 441-4096
novice and experienced
Fax: (310) 441-1996
developers. Its also a valuWeb Site: http://www.eagle-software.com
Price: US$279, with a 60-day, moneyable tool for learning about
back guarantee.
the nuts and bolts of component building. The
CDK manual is clearly
written, with plenty of illustrations and tutorials; especially
useful are tips identified with a small Mr. CDK graphic.
Other Eagle Software products, including a professional
programmers editor and a free upgrade of the CDK (to
existing customers) to compile under Delphi 3, are in the
works. Try the CDK. It will help your late-night component fantasies become reality.
Delphi Reports
Delphi 1 / Delphi 2 / ReportSmith
By Chris McNeil
re we there yet? With the advent of modern travel, virtually all destinations are within reach. However, as with most things, no single
mode of transportation is perfect. In air travel, for example, it seems most
flights require a time-consuming layover. Printing a ReportSmith report
from a Delphi application can also involve a delay. In fact, quite the rigmarole is required to print to a specific destination other than the Windows
default using a Report object. You must minimize your application and
select the required print driver as the Windows default printer.
Is There an Alternative?
Inspection of the TReport class source code
(the file name is REPORT.PAS) shows that a
method named Print is executed when
Preview is False. This assumes that
Delphi Reports
Property
Description
AutoUnload
EndPage
InitialValues
Preview
PrintCopies
ReportDir
ReportName
StartPage
{ Delphi 1 }
{ Delphi 2 }
Delphi 2 Implementation. Under Delphi 2, Borland significantly updated the interface to ReportSmith by writing a new
ReportSmith API that dodges some pitfalls of the DDE.
Borland has replaced most of the DDE communication with
calls to their new ReportSmith API. One of the functions of
this API is RS_PrintReport; its parameters match the
PrintReport macro exactly. Therefore, the TReport.Print
method executes this function:
{ Assuming default property values }
RS_PrintReport(1, 9999, nil, nil, nil, 1)
53
Figure 2 shows the implementation of PrintTo. Its functionally equivalent to Print, except it allows printer information to be passed in. In addition, it can call
RS_PrintReport. It would have been possible to call the
Delphi Reports
function TReport.PrintTo(
ADevice, APort, ADriver: string):
begin
if not Busy then
Result := RS_PrintReport(
StartPage, EndPage,
PChar(ADevice),
{
PChar(APort),
{
PChar(ADriver),
{
PrintCopies)
else
Result := RS_BUSY;
end;
Property
Integer;
Requires a PChar }
Requires a PChar }
Requires a PChar }
Canvas
Orientation
PrinterIndex
Printers
Title
Using the modified TReport, we can declare our new component as follows:
EndDoc
type
TRptSmith = class(TReport)
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
{$ifdef WIN32}
function Print: Integer; override; { Delphi 2 }
{$else}
function Print: Boolean; override; { Delphi 1 }
{$endif}
end;
Description
GetPrinter
NewPage
SetPrinter
Description
Sends a print job to the printer. If the print
job is sent successfully, the application
should call EndDoc to end the print job.
Printing wont start until EndDoc is called.
Ends the current print job and closes the text
file variable. After the application calls
EndDoc, the printer begins printing. Use
EndDoc after successfully sending a print job
to the printer.
Retrieves the current printer.
Forces current print job to begin printing on
a new page.
Specifies the current printer.
device name
port
driver
printer handle
Delphi Reports
require this parameter. In fact, by passing nil as the print driver, Windows 95
uses the device name and port to derive
which print driver to use.
Conclusion
Are we there yet? Our implementation isnt perfect, because it relies on
an external object, TPrinter, to provide several significant pieces of information. However, given the nature of
the TPrinter object, its doubtful that
its external interface will change significantly. It also modifies the VCL
source which can be problematic.
With a little care, however, this technique provides a simple and functional implementation of print destination capabilities for the Report component.
The files referenced in this article are
available on the Delphi Informant
Works CD located in
INFORM\97\MAY\DI9705CM.
Figure 6: The Report Test form has the Port set to COM3. Below is the result generated
by ReportSmith.
55
TextFile
readers level as
Intermediate/Advanced.
Bulback accurately articulates
the prerequisites in the introduction as being for those
somewhat familiar with the
Pascal programming language
and having at least a basic
understanding of the Delphi
environment. What level
does that sound like to you?
Also at issue is the nature of
the introduction. Entitled
Introduction to Delphi,
this 52-page chapter spends
too much time covering fundamental topics, such as the
nature of properties and
Delphis relationship to other
programming languages. In
fairness, the author discusses
these topics in an interesting
and insightful manner.
Furthermore, he includes
topics that are often omitted,
such as the function of initialization and finalization
sections, and using array
properties. Still, I prefer a
more focused discourse.
Following this introduction,
Bulback gets to the business
Programming Delphi
Custom Components
continued on page 57
TextFile
Windows messaging,
Delphi Programming
Problem Solver is for you.
Richard A. Porter
Delphi Programming
Problem Solver by Neil
Rubenking. IDG Books,
919 E. Hillsdale Blvd., Ste.
400, Foster City, CA 94404,
(800) 762-2974.
ISBN: 1-56884-795-5
Price: US$34.00
574 pages, Diskette
57
File | New
Directions / Commentary
Goliath Lives
he release of Delphi 3 gives us an opportunity to look at the brief history of Borlands flagship
product and see how it stacks up in the marketplace. When Borland introduced Delphi 1 in early
1995, I heard many Scotts Valley supporters tout it as the giant killer, fully expecting Delphi to dominate the Windows client/server development tool market. That didnt happen.
58