May 1997, Volume 3, Number 5
Delphi 3
The ActiveX
Foundry
From COM to DCOM,
Delphi 3 Means Business
Cover Art By: Tom McKeith
ON THE COVER
6 Delphi 3: The ActiveX Foundry — Danny Thorpe 37 On the Net — John Penman
Borland has cast another winner — Delphi 3 is to ActiveX creation With the Internet and intranets playing increasingly important roles, net-
as Delphi 1 was to Windows app creation. Watch the sparks fly as work applications ought to check connectivity with the server. These days,
Mr Thorpe previews all the items that merit buzzwords on the box a network debugger is a developer’s necessity — and here’s a handy one.
cover (and more). 43 At Your Fingertips — Robert Vivrette
Another pithy collection of tips awaits. Need to know how to add files to
12 Easier Yet — Robert Vivrette the Win95 Documents menu, or how to keep a program from running
As he explores the Delphi 3 Code Editor’s new refinements in appear- too fast? It’s all here.
ance and function, our writer’s mind is in the gutter — the left gutter,
specifically. Find out why. 45 Case Study — The EDD Development Team
The State of California Employment Development Department recently put
FEATURES an interactive, database-driven Web site to work. Find out how it helps
16 Informant Spotlight — Ian Davies employers and job seekers help themselves.
With only a few lines of code, Word can become a sophisticated Delphi 52 Delphi Reports — Chris McNeil
reporting tool. Nifty tweaks like this make coming to grips with OLE Printing a ReportSmith report can sometimes seem as frustrating as an
Automation well worth the effort, says Mr Davies. airline layover. Here’s a TReport technique that ensures your destination
is reached with time to spare.
21 Columns & Rows — Dan Ehrmann
Developers use the Paradox file format every day, but Delphi docu- REVIEWS
mentation supplies almost no information about it. This second in a 47 Eagle’s Component Developer Kit 2.0
series offers help in calculating record and table size, including an Product Review by Robin Karlin
application to crunch the numbers.
56 Delphi Programming Problem Solver
25 In Development — Bill Todd Book Review by Richard Porter
InstallShield Express lets you create a single disk set to install
56 Programming Delphi Custom Components
myriad items, gladdening the hearts of your users. This first of two
Book Review by Alan Moore, Ph.D.
articles shows you how to make the most of this product — and
deal with its limitations.
DEPARTMENTS
32 DBNavigator — Cary Jensen, Ph.D. 2 Delphi Tools
This month, Dr Jensen explains how cached updates can increase per- 5 Newsline
formance, reduce network traffic, add user interface options, and 58 File | New by Richard Wagner
enhance programmatic control over data updates — all with
minimal outlay.
1 May 1997 Delphi Informant
Applied Analytic
Delphi Systems Ships New
T O O L S Components
Applied Analytic Systems,
New Products
Inc. of Carnegie, PA has
and Solutions
released its statistical analysis
components for Delphi 1 and
2. The TRegress, TAnova, and
TForecast components per-
form randomized block analy-
sis of variance, and exponen-
tial smoothing forecasting on
data in tables accessed
through the BDE.
The statistical components
can be used in place of the
New Delphi Book
TTable component, allowing they would with TTable or arrangement for multiple developers at
Building Internet developers to incorporate TQuery. The resulting soft- a single location. All components
Applications with database-aware statistical capa-
Delphi 2
ware can produce robust include unlimited royalty-free run-time
Davis Chapman bilities into their software. inferential outputs, even licenses.
QUE Corp. The components can analyze though the programmers may Contact: Applied Analytic Systems, Inc.,
the data (or subset of the have little or no training in 600 North Bell Ave., Bldg. 1,
data) in any numeric column statistical methodologies. Carnegie, PA 15106
of the table to which they are Phone: (412) 278-2360
attached. Developers using Price: Each component, US$79 for a Fax: (412) 788-4205
the components supply the single-developer; three-component set, E-Mail: [email protected]
database and table name as US$199. Site licenses are available by Web Site: http://www.aasdt.com
NuMega Announces BoundsChecker 5.0 Delphi Edition
NuMega Technologies, Inc. party APIs. duces ActiveCheck and
ISBN: 0-7897-0732-2 of Nashua, NH has Smart Debugging is includ- FinalCheck, error detection
Price: US$49.99 announced BoundsChecker ed. It allows developers to technologies that deliver per-
(624 pages, CD-ROM)
Phone: (800) 428-5331 5.0 Delphi Edition, the detect and fix errors as a nor- formance increases of 500 to
newest release of its error mal by-product of the devel- 700 percent and higher. It
detection system for develop- opment process. Smart analyzes a program at run
ers of Windows, Internet, and Debugging works inside the time and pinpoints errors
enterprise applications. Delphi IDE and is compatible without requiring instrumen-
BoundsChecker 5.0 Delphi with Delphi 2 and 3. It moni- tation, re-compiling, or re-
Edition performs active API tors all events, searches for linking. ActiveCheck performs
validation on over 3,000 calls bugs as the user steps through thorough run-time checking
to the latest Windows APIs code, and displays any errors of each API call to ODBC
and OLE methods, including found. 3.0, Internet APIs, ActiveX,
Win32, ActiveX, DirectX, BoundsChecker displays and DirectX, as well as the
ODBC, and more. Bounds- multiple call stacks, identify- Win32 interface to the
Checker’s active validation ing the source of memory Windows operating system.
checks each API call for valid overwrites and leaks, and the FinalCheck is effective at find-
parameters, valid return codes, location in the program where ing difficult memory and
proper number of parameters, memory is allocated or deallo- pointer errors.
out-of-range parameters, cated. Users have immediate,
invalid flags, conflicting flags, contextual information about Price: US$399
uninitialized fields, and bad why an error occurred and Contact: NuMega Technologies, Inc.,
pointers. BoundsChecker’s where. Errors and events are #9 Townsend West, Nashua, NH 03063
API validation facility is open viewed in real time, providing Phone: (800) 468-6342 or
and extensible. Users can immediate and comprehensive (603) 578-8400
extend BoundsChecker’s error information on program exe- Fax: (603) 889-1135
detection power to include cution. E-Mail:
[email protected] their proprietary and third- BoundsChecker 5.0 intro- Web Site: http://www.numega.com
2 May 1997 Delphi Informant
SuccessWare
Delphi International Ships
Page Technology Marketing, Inc. Releases
PCLTool SDK Version 4.4
T O O L S Apollo 3
Page Technology It can also convert PCL
New Products SuccessWare International
Marketing, Inc. of San form overlays into a
and Solutions of Temecula, CA has shipped
Apollo 3, an update to its Diego, CA has released Windows Metafile Format
database engine for Delphi. PCLTool SDK Version 4.4. (.WMF) for porting PCL
Apollo 3 features its pro- This .DLL library views, forms to device-indepen-
prietary technology, Roll- indexes, archives, searches, dent Windows applications.
Your-Own Indexes and retrieves, overlays, and Version 4.4 includes: loca-
Filters; ascending/descend- converts PCL 4/5 print tion indexing; a PCL text
ing index orders; increased data files for COLD, faxes, search; drag-and-drop oper-
support for Delphi’s inte- browsers, and other appli- ations; and a ’Net browser
grated components; cations. Developers can helper. In addition, it’s
improved data access and integrate PCLTool’s .DLLs command-line driven.
optimized-query speeds; a
to add PCL5 file-handling
smaller deployment foot-
print; and more. capabilities into their high Price: US$495 for a 100-user
Borland Developers volume e-form applica- license.
Conference tions. Contact: Page Technology Marketing,
The 8th Annual Borland Price: US$179
Developers Conference will PCLTool SDK can index Inc., 10671 Roselle St., Ste. 100, San
Contact: SuccessWare International,
take place July 12-16th in mortgage-loan print data- Diego, CA 92121
Nashville, TN. 27349 Jefferson Ave., Ste. 110,
Attendees will be able to streams, retrieve individual Phone: (800) 748-3668 or
Temecula, CA 92590
design their own agendas, pages by index or full text (619) 658-0191
selecting from beginning, Phone: (800) 683-1657 or
intermediate, or advanced search of the PCL, view it, Fax: (619) 658-0194
(909) 699-9657
developer sessions in the fol- overlay data, or convert it E-Mail:
[email protected] lowing categories: compo- Fax: (909) 695-5679
nents; design and methodol- to a .TIF for imaging, Web Site:
E-Mail:
[email protected] ogy; enterprise computing; storage, or faxing. http://www.tfb.com/pagetech
InterBase; Internet/intranet; Web Site: http://www.gosware.com
management issues; pro-
gramming, tools, and tech-
niques; and solutions. TransCom Software Inc. Releases TCP/IP Development Tool
For more information, visit
http://www.borland.com.
TransCom Software Inc. .DCU format, which means HTML documents with all
of Castletown, UK has there are no other external images; floating images, even
released WaveTools, a RAD support files. Developers within tables; GIF87,
TCP/IP development tool. can build and ship an GIF89a, and JFIF/JPEG
WaveTools allows developers application in a compact image decompression with
to build Internet/intranet- single file knowing it will no external .DLLs; progres-
based applications with little run without any further sive display of decompress-
or no knowledge of the user installation or inter- ing images; as well as disk-
underlying protocols and vention, and won’t experi- and memory-based cache
document formats. ence any version conflict with user-definable size. In
Created for Internet and with other previously addition, WaveTools
intranet software developers installed software. Users includes HTTP-based, mul-
using Delphi, WaveTools can process the information tiple- file downloading capa-
comes in native Delphi from the HTML document bility; proxy support; print
they are retrieving, either preview and print engine;
locally or from the net- and a large number of meth-
work, instead of simply ods to control almost all
viewing it. aspects of all components.
WaveTools includes:
HTTP connections over Price: US$399
TCP/IP-enabled networks; Contact: TransCom Software Inc.,
facilities to deal with remote 11 Malew St., Castletown,
HTML documents as if they Isle of Man IM9 1AB, UK
were disk-based files; and Phone: 41 (0) 22 849 8358
position- and pattern-based Fax: 41 (0) 1624 825384
text-extraction engines. It E-Mail:
[email protected] also supports the saving of Web Site: http://www.transerve.com
3 May 1997 Delphi Informant
ICFM Software Launches TStringClass for Delphi Developers
Delphi ICFM Software of London,
T O O L S England has released
TStringClass, a large string
New Products management component.
and Solutions The TStringClass class is
designed to manage large
string variables by encapsu-
lating a core PChar type text
buffer within a controlled
class wrapper.
The TStringClass object
controls its own internal
buffer for holding the PChar
variable and, before perform-
ing any assignments or con-
catenations, checks to see Assign methods for moving in use after being disposed.
that sufficient room is avail- different types of text vari- TStringClass includes a test
able. If there is insufficient ables into the object data bed application that illus-
Web Site Stats value; and a range of differ- trates main methods. A fully
Rick Stout
space, it re-sizes the buffer to
Osborne/McGraw-Hill fit the required action. ent Append methods for functional shareware prod-
TStringClass has been adding different types of uct, it includes .DCU files
expanded to cover almost text variables onto the end for Delphi 1 and 2.
anything that can be done of any existing object data TStringClass must be regis-
with a string type variable, value. tered to obtain source code.
including: multiple con- TStringClass is designed to
structors for initiating the handle the problems of Price: US$45
object for different situa- passing nil or zero length Contact: ICFM Software, 12 Lightfoot
tions; a set of high-level PChar parameters. It can Rd., London, England N8 7JN, UK
methods for working with also manage the problem of E-Mail:
[email protected] other TStringClass type vari- passing parameters which Web Site: http://dspace.dial.pipex.-
ISBN: 0-07-882236-X ables; a range of different are uninitialized or remain com/town/estate/ns21/icfmdc.htm
Price: US$29.95
(298 pages, CD-ROM)
Phone: (800) 262-4729 SELECT Software Tools Ships SELECT Component Factory
SELECT Software Tools, ing products, and named its round-trip code generation
Inc. of Irvine, CA has overall product line the tool for Delphi, Visual Basic,
released a line of products SELECT Component PowerBuilder, and others; and
that support the wrapping of Factory (SCF). The wrapping SELECT SE, an industrial-
existing systems to create tools provide the ability to strength application-develop-
components that can be re- create components from exist- ment toolset providing inte-
used. ing systems such as COBOL grated data modeling for
SELECT has integrated the applications, databases, and SELECT Enterprise users.
wrapping tools with its exist- application packages, and can The wrapping tools
integrate the components include: SELECT CASE
with new applications being Wrapper, SELECT Database
developed with modeling Wrapper, SELECT Legacy
tools such as SELECT Wrapper, and SELECT
Enterprise. Within SCF are Package Wrapper.
analysis and design tools,
wrapping tools, management
tools, and a repository. Price: Not available at press time.
Analysis and design tools Contact: SELECT Software Tools, Inc.,
include: SELECT Enterprise, 19600 Fairchild, Ste. 350,
an object-oriented modeling Irvine, CA 92612
toolset supporting integrated Phone: (714) 477-4100
BPM and the Unified Fax: (714) 477-3232
Modeling Language; SELECT E-Mail:
[email protected] Enterprise Generators, a Web Site: http://www.selectst.com
4 May 1997 Delphi Informant
News Borland Announces Restructuring Plan, Reduces Staff by 30 Percent
Scotts Valley, CA —
Borland announced a
staffing, Borland will employ
approximately 700 full-time
In anticipation of expand-
ing the company’s enterprise
L I N E world-wide restructuring employees world-wide. business, Borland is adding
plan aimed at returning the This restructuring plan is fee-based technical support
May 1997 company to profitability in anticipated to produce annual programs.
its 1998 fiscal year, which operating cost savings in Borland also downsized its
began April 1, 1997. The excess of US$30 million, and Open Environment division,
restructuring plan involves product restructuring savings located in Boston. Key tech-
reductions in operational in excess of US$30 million. nical personnel were relocat-
expenses, including a reduc- Borland’s restructuring pro- ed to Scotts Valley, CA.
tion of approximately 300
gram also features a renewed This restructuring plan
employees and contractors.
interest in new product devel- serves as the foundation for
In addition, programs
aimed at increasing the com- opment. Research and devel- Borland’s new business
pany’s revenues are planned. opment programs at Borland organization.
Only selective restructur- plan to deliver at least one A strategic business plan will
ing was conducted in major release each quarter. be presented by Delbert W.
Borland and Symantec Borland’s international New client/server and Yocam, Borland’s Chairman
Settle Trade Secret operations, which continue Internet/intranet products and CEO, at the Borland
Litigations
Borland and Symantec Corp. to show positive results. scheduled include C++Builder, Developers Conference in
have settled the trade secret After the reductions in Delphi 3, and JBuilder. Nashville, TN.
lawsuit that Borland brought
against Symantec, its
President and Chief Executive
Officer Gordon Eubanks, and Three Editions of Borland’s C++Builder Begin Shipping
former Executive Vice
President Eugene Wang in Scotts Valley, CA — Borland designed for programmers, US$799 (current owners of
September 1992. has released the C++Builder ISVs, VARs, and consultants. C++, Delphi, Microsoft
The parties agreed to a dis-
missal of the lawsuit and product line, which includes Its toolset includes the VCL Visual Basic, Microsoft
related counterclaims, and the C++Builder Client/- source code, advanced data- Visual C++, PowerBuilder,
have entered into mutual
releases of all claims relating Server Suite, C++Builder aware components, a scalable Optima++, Watcom C++, or
to the lawsuit. Professional, and C++Builder data dictionary, the Internet Symantec C++ products are
Standard editions. Solutions Pack, and other eligible to purchase Borland
C++Builder is a 32-bit programming tools. C++Builder Professional for
Borland Appoints Windows development envi- C++Builder Standard a special upgrade price of
Birmingham as Vice
President and General ronment that combines C++ includes a tutorial, Teach US$299.95). C++Builder
Counsel with Borland’s visual tools Yourself Borland C++Builder Standard is US$99.95.
Hobart Birmingham has been
named Borland’s vice presi-
and database architecture. in 14 Days, in-depth code Borland plans to ship a
dent and general counsel. C++Builder Client/Server examples, sample applica- fourth version, Learn to
Birmingham, who reports to
Borland’s chairman and chief
Suite is for consultants, tions, and more. Program with Borland
executive officer, Delbert W. VARs, and C++ developers In addition, Borland will C++Builder, for beginning
Yocam, will manage legal ser-
vices for Borland’s world-wide
creating client/server solu- update its current Borland programmers and students.
operations. Birmingham tions and connecting to C++ 5.0 product line. Pricing was not available at
replaces Robert Kohn who left
the company in October 1996.
data using a visual RAD C++Builder Client/Server press time.
tool for C++. It includes Suite is US$1,999; For details, visit
native SQL drivers for C++Builder Professional is http://www.borland.com.
Oracle, Sybase, Microsoft
SQL Server, Informix, New Arabic Language Support for Delphi
DB2, and InterBase, as well Scotts Valley, CA — Delphi now supports 14
as a suite of SQL tools. Borland has released an languages: English, German,
C++Builder features SQL Arabic language enablement French, Japanese, Danish,
Explorer, SQL Monitor, for its Delphi 2 line of Dutch, Italian, Portuguese,
Visual Query Builder, Data RAD tools. Spanish, Swedish, Korean,
Migration Wizard, Cached By using this Arabic sup- Chinese, Thai, and Arabic.
Updates, a four-user port package, any existing For details about Delphi
InterBase server for proto- installation of Delphi 2 run- Arabic Enablement, or to
typing and testing multi- ning on the Arabic version place orders, call (800) 233-
user SQL applications, and of Windows 95 can be 2444. International customers
companion products. upgraded to develop new should contact their local
C++Builder Professional is Arabic applications. Borland office or distributor.
5 May 1997 Delphi Informant
On the Cover
Delphi 3
By Danny Thorpe
Delphi 3
The ActiveX Foundry
From COM to DCOM, Delphi 3 Means Business
I t’s spring again, a time when many eyes look to Borland for a new genera-
tion 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 Borland’s year- high-level tour, focusing on how Delphi 3’s
long labors include the ActiveX new tools enable new ways to solve tough
Component Foundry, Business Object development and deployment problems.
Broker, multi-tier Remote Data Brokers,
Distributed COM, Web Deployment, and ActiveX Component Foundry
a suite of IDE features known collectively Delphi 3 goes completely overboard to sup-
as Code Insight. port, adopt, and internalize Microsoft’s
ActiveX technology initiative. Delphi 3 is to
There are so many new technical bits in ActiveX creation as Delphi 1 was to
Delphi 3 that it’s difficult to grasp the Windows application creation. Through a
scope of the whole product simply by look- combination of new language extensions,
ing at its technical pieces. Let’s first take a new classes, and new design-time wizards
and tools (see Figure 1), Delphi 3 cuts
through the Microsoft rhetoric to deliver
what Microsoft has been trying to do for
ages: a development environment that makes
creation, debugging, deployment, and main-
tenance of ActiveX controls, COM servers,
and COM interfaces simple and reliable.
Revisionist Terminology
Microsoft’s Component Object Model
specification, COM, is the standard to
which all OLE objects are implemented.
COM is the low-level stuff; OLE is a ser-
vice built on COM. Depending on who
you talk to at Microsoft, ActiveX is the
new name for OLE Controls (OCXs, the
32-bit replacement for VBXs), the new
name for all things formerly known as
OLE, or the new name for all things new.
Pessimists are already assuming the latter
Figure 1: One aspect of the ActiveX Component Foundry, a page of wiz-
ards makes it short work to create an ActiveX control. Delphi 3 makes cre- definitions. In any case, ActiveX is also a
ation, debugging, deployment, and maintenance of ActiveX controls, COM group of services and standards built on
servers, and COM interfaces simple and reliable. COM interfaces.
6 May 1997 Delphi Informant
On the Cover
Figure 3: A new OLE type library editor makes short work of
Figure 2: Delphi 3 has a new wizard that generates an ActiveX defining a new COM interface definition, saving it into an OLE-
control class wrapper around the VCL component you specify. standard typelib file, and generating a source code unit with the
interface type declaration.
Create ActiveX Controls from VCL Components
Delphi 3 has a new wizard that generates an ActiveX control class
wrapper around the VCL component you specify (see Figure 2). Figure 4: You
It’s as simple as that. If you write VCL components for a living, can now directly
you’re now just a few button clicks away from selling those com- access interfaces
ponents as ActiveX controls to the Visual Basic and C++ markets. provided by
If you work in a mixed-tool environment, you can develop your ActiveX controls
and take advan-
core business objects as VCL components, then spit out ActiveX tage of other
versions of your work for folks hopelessly shackled to other tools. control features
that were previ-
Create COM Servers and Automation Servers from Scratch ously only avail-
A new OLE type library (typelib) editor (see Figure 3) makes able through
variant variables.
short work of defining a new COM interface definition, saving
it into an OLE-standard typelib file, and generating a source
code unit with the interface type declaration. You create new
COM interfaces whenever you build a new COM server, be it
a visual ActiveX control or a non-visual data processing server.
Create VCL Components from ActiveX Controls
OLE typelibs are symbol files that tell other applications The ActiveX wrapper class generation found in Delphi 2 has
what methods are available in your COM server, and how to been expanded to take advantage of new language features
call them. Just as the IDE form designer and source code like interface types, and new buzzwords like ActiveX. You can
editor are linked two-way tools (i.e. modifications to one are now directly access interfaces provided by ActiveX controls
reflected immediately in the other), the new typelib editor is and take advantage of other control features that were previ-
also a two-way tool — modifications made to the Pascal ously only available through variant variables (see Figure 4).
interface type declaration source code are reflected in the
typelib editor, and vice-versa. ActiveForms
Another nifty spin-off of the core ActiveX development
Generate Pascal Declarations from Typelibs work is the creation of an ActiveX control to encapsulate
As a side effect of the extensive typelib editor work, you can an entire Delphi form (again, see Figure 1). This is neces-
also generate Object Pascal source-code constants and inter- sary to support ActiveX property pages, but it’s also handy
face type declarations from any OLE typelib. Think of this for creating mini-application modules that can be auto-
as an expansion of the OCX wrapper class generation in matically downloaded over the Internet and displayed
Delphi 2. If you can obtain a typelib file for a COM object inside a Web browser such as Microsoft Internet Explorer
you want to use in Delphi (ActiveX controls are required to 3.0. The Web browser sees the thing as an ActiveX con-
have a typelib), creating Pascal interface declarations to use trol, but you can pack an entire application into it.
that COM object are a snap, and considerably more accurate
than trying to mechanically convert ambiguous C header Web Deployment
files into Pascal declarations. Unfortunately, some COM To support Web-deployed ActiveX controls, the Delphi 3
objects do exist without typelibs; Microsoft’s DirectX is IDE includes tools to digitally sign and seal your .DLL or
probably the biggest offender in this category. .EXE file with your Software Publisher digital certificate, and
7 May 1997 Delphi Informant
On the Cover
Distributed COM
Delphi 3 supports Distributed COM, Microsoft’s 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 3’s 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.
New Interface Type
OLE objects are always accessed through COM interfaces —
abstract, virtual, base classes that define a group of related
functions, but not their implementation. All COM interfaces
are derived from the IUnknown standard interface, which
defines simple reference-counting methods and a
QueryInterface method to gain access to other interfaces sup-
ported by that object.
The most common programming error when using OLE
objects is forgetting to increment or decrement the refer-
ence count of interfaces onto which you’re holding. If you
forget to call AddRef on an interface, the object behind
that interface may delete itself if some other action causes
the object’s reference count to drop to zero. Subsequent
use of the interface pointer you held onto will cause an
access violation. If you forget to call Release on an interface
when you’re finished with it, the object behind that inter-
face will remain in memory, because its reference count is
artificially inflated.
Delphi 3 eliminates this debugging nightmare by adding a
Figure 5 (Top): The new Web Deployment Options dialog box. new standard type to the Object Pascal language defini-
To support Web-deployed ActiveX controls, Delphi 3 can digitally tion: the interface type. An interface type declaration looks
sign and seal your .DLL or .EXE file with your Software Publisher
digital certificate, and deliver it to a directory you select.
much like a class type declaration, but an interface type is
Figure 6 (Bottom): The Web deployment wizard can also bun- only a declaration — it has no implementation of its own.
dle and compress multiple files into the Microsoft .CAB file for- An interface is like a standardized subset of methods that
mat, generate .INF files needed for a downloadable component an object can implement. Regardless of what else the
to refer to required modules downloadable separately, and implementing object implements, you know that if it
much more.
implements the XYZ interface, you can use the XYZ meth-
ods on it. Furthermore, you can obtain the XYZ interface
deliver it to a directory of your choosing (see Figure 5). This from the implementing object, and use it without knowing
signature is checked by the Microsoft Internet Explorer 3.0 anything about the implementor’s class type.
Web browser after downloading the ActiveX control as part
of an HTML document to verify that the file is from who it In use, interface variables are initialized, reference-counted
says it’s from, and that the file has not been tampered with or (through standard IUnknown methods), and released auto-
corrupted in transfer. matically by compiler-generated code, just as long strings
and variants are dynamically allocated, reference-counted,
The IDE deployment wizard can also bundle and com- and released in Delphi 2. In Delphi 3, transferring values
press multiple files into the Microsoft .CAB file format, between interface variables or passing them as parameters
generate .INF files needed for a downloadable component is as simple and reliable as transferring integer or string
to refer to required modules downloadable separately, and values. In many respects, passing interface values is safer
generate an HTML object tag for you to paste into your than passing object instances, because interface reference-
Web page, to refer to your downloadable component counting eliminates the question of who is responsible for
(see Figure 6). freeing the object.
8 May 1997 Delphi Informant
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 inter-
faces, 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 imple-
mented methods in the class type. No tables of macros of
pointers to functions to crosswire with a typo — the compil-
er does it all. When something isn’t quite right, the Delphi
compiler tells you where and what you’ve missed in your dec-
larations. 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 implementor’s 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 inherit- Figure 7 (Top): Delphi 3’s Component palette includes three
ing any implementation details from the multiple interfaces. new heavy-hitters, including the powerful DecisionCube.
Figure 8 (Bottom): The new Packages page of the Project
What this means is that implementing OLE objects (such as Options dialog box. A package is a special .DLL which con-
ActiveX controls and custom COM servers) is now almost triv- tains and exports one or more units for applications or other
ial. Delphi 3 requires none of the unintelligible tables of macros packages to share.
of pointers that Microsoft’s ActiveX SDK heaps on itself. Where
Microsoft implements ActiveX as a system of macros and C++ (non-Delphi applications should not try to link directly to a
template classes on top of the C/C++ language, Delphi imple- package .DLL) and you don’t have to change any Delphi
ments ActiveX by incorporating the essential enabling technolo- source code to use it.
gies into the Object Pascal language and VCL classes. Why
bother with macros and well-meaning source code conventions In compiler parlance, packaging is a code-generation option (see
when you can have the compiler do the dirty work for you? Figure 8), which means it should have no effect on the seman-
tics of your source code. When your Delphi application is com-
Data Visualization piled to use the VCL core package, for example, the compiler
Delphi 3’s Component palette includes three new heavy-hitters: generates code to reference the Forms unit in the VCL package
an all-new version of QuickReport, powerful charting capabili- .DLL instead of placing the Forms unit code in your .EXE. The
ties in TeeChart, and the DecisionCube interactive crosstab (see result is that your .EXE size drops from around 200KB to less
Figure 7). You can embed TeeCharts in QuickReport reports, as than 20KB. With packages, the .EXE file contains only your
well as link a TeeChart to the DecisionCube to graphically dis- application logic and form resources. This also makes ActiveX
play the crosstab data on-the-fly. control .DLLs extremely small — about 25KB — far smaller
than Microsoft’s 50KB minimum ActiveX template-based con-
Application Deployment: Web or Otherwise trol library, or 800KB minimum, MFC-based ActiveX control
If you’ve ever installed multiple Delphi applications on the library. The package .DLL must contain every bit of code and
same machine, you’ve probably wondered if there was some data that its member units define in their interface sections.
way to share the VCL component code between the multi- This makes the core VCL package weigh in at just over 1MB.
ple applications. Well, now there is: a Delphi package. A (Because most units in the core VCL package are used by the
package is a special .DLL which contains and exports one or simplest blank form application, and that minimal application
more units for applications or other packages to share. A produces a 150KB .EXE file, that should tell you something
package is different from a .DLL in that it’s Delphi-specific about the value of smart linking.)
9 May 1997 Delphi Informant
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."
and pressing a hotkey will show all
the integer properties and functions
available on the form’s ProgressBar1
component. The helper knows that
ProgressBar1 is a component, and
that IntToStr requires an integer type
parameter, so it shows you the things
in ProgressBar1 that can provide an
integer-compatible value. For debug-
ging, the ToolTip Expression
Figure 9: Class hierarchy of TDataSet for Delphi 2 and 3. In Delphi 3, TDataSet is now Evaluation feature shows the values of
abstract and has a new ancestor, TBDEDataSet. The Delphi 3 BDE now features direct
links to Access and DB2, as well as dBASE, Paradox, ODBC, Informix, InterBase,
variables in a hint balloon as your
Microsoft SQL Server, Oracle, and Sybase. mouse moves over the source code
symbols in the Code Editor. I may
Packages are a great way to reduce the overall size of a suite of never use the Evaluate/Modify dialog box again!
applications, and open up interesting options for such
bandwidth-sensitive applications as ActiveX controls deployed To make it easier to debug ActiveX control .DLLs and
over the Internet (as objects embedded in HTML documents) COM servers, particularly when they are used by non-
or network-deployed shareware. The common packages could Delphi applications, you can tell the Delphi IDE debugger
be bundled separately from the main application file set, so that to run a particular .EXE to debug the current .DLL project.
folks who already have the packages don’t have to download So, you can compile your ActiveX control .DLL project, set
them again. Better yet, you could refer to the Borland Web site a few breakpoints in the source code, tell the debugger that
as the source for the Delphi core packages instead of bundling the host .EXE for your .DLL is VB.EXE, select Run | Run,
them yourself, and consuming disk space on your file server. and Visual Basic is displayed. Tell VB to load your ActiveX
control .DLL and execution stops at a breakpoint in the
Code Insight Delphi debugger. You can step, evaluate, watch (and so
How many times have you started to write a function call forth) items in your .DLL while it’s being used by VB.
statement, but forgotten what parameters that function call
requires? Wouldn’t it be great if you could type a function Virtualized Datasets
name and hit a hotkey to show the function’s parameter decla- To enable BDE-less remote datasets (and to respond to a com-
ration, right there in the editor? Wouldn’t it be great if it mon customer request), Delphi 3 virtualizes all database activity
showed the functions you created, as well as the Borland- through a — now abstract — TDataSet class. BDE awareness is
documented stuff? Wouldn’t it be wild if it would help you fill introduced in a new TDataSet descendant, TBDEDataSet,
in the parameters too? which serves as the ancestor of TDBDataSet and the familiar
TTable, TQuery, and TStoredProc classes (see Figure 9).
Delphi’s Code Insight provides all this, and more. Its Code
Parameters feature uses the compiler to determine what func- Delphi 3 also implements support for “thin-client” remote
tion you’re trying to use, what its parameters are, and the types datasets as a descendant of the base TDataSet class, indepen-
of those parameters. Moreover, it’s nearly instantaneous and dent of the BDE. This abstraction of the dataset will also
non-intrusive. (Beware of similar-sounding features in other enable third parties to implement Delphi dataset support for
products, which only give you help on functions defined by other data providers and file formats, without resorting to
the tool vendor. Delphi uses the compiler symbols to give you fate-tempting BDE .DLL hacks.
help on all functions in your project — Borland’s, yours, and
all third-party units used by your project.) Breaking Up Client/Server
Seasoned SQL database folks can rattle off all sorts of weaknesses
Using code templates, you can define standard code blocks and liabilities of the industry-standard two-tier SQL client/server
(if/then/else, begin/end, for and while loops, etc.) with short- application model. For example, the client machine and applica-
cut names to insert in the editor with just a keystroke or two. tion are often intimately bound to the SQL server’s network
10 May 1997 Delphi Informant
On the Cover
name and SQL dialect or vendor. BDE aliases allow you to re-
vector 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 busi-
ness 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 program-
ming logic required for complex business rules, such as non-tabu-
lar tax calculations or least-cost resource allocation. This means Figure 10: The two-tier SQL server model.
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.
Multi-Tier Remote Data Brokers
The solution to these and many other weaknesses of the tradi-
tional two-tier SQL model is to break the direct connection
between the client application and the server. Multi-tier data
models make the client application talk to an intermediate
machine or service (a broker), which can then process or forward
the information to an appropriate server. The client never talks
directly to the final SQL server that owns the actual data, so the
client application doesn’t need to know how to talk SQL — the
client application can speak simply and frankly to the intermedi-
ate data broker, and the broker can carry the burden of speaking
SQL to the data servers, and fret with maintaining connections
to multiple data servers — SQL and otherwise. Because business
rules and other data-handling logic can live on a middle tier bro- Figure 11: The multi-tier server model.
ker, a significant portion of what you’ve been calling your client
application can be moved off the client machine and onto cen- the middle-tier broker to forward client requests to the least busy
trally managed servers. What’s more, the middle-tier broker can machine in a server farm.
be implemented — and debugged — using real programming
tools (such as Delphi, of course) instead of primitive SQL stored Conclusion
procedures (see Figures 10 and 11). There are too many exciting new features in Delphi 3 to cover
in one article, or even to try to absorb in one sitting. I’d love to
Delphi 3 opens the floodgates to multi-tier distributed appli- rattle on about the Web-server dispatch and database compo-
cation development with the introduction of the remote nents for building Netscape and Microsoft Internet Information
dataset. A remote dataset looks and acts like any other dataset Server extension .DLLs, or the extensive support for DIB image
(TTable, TQuery), serving rows of data to data-aware con- formats and direct pixel memory pointers in TBitmap, the new
trols. The difference is that a remote dataset doesn’t require TJPEGImage class, or the new “globalization” of the Delphi RTL
the presence of a full database engine on the client machine and VCL classes to support multi-byte character sets in Asian
— the dataset talks to a second machine (the middle-tier data locales, or the all-new documentation set and online Help, but
broker) that contains the database engine, complete with for now a tease will have to do. So many ideas, so little time. ∆
querying, filtering, and SQL connectivity intelligence. With
no BDE to install or configure on the client machine, remote Important note: This article is based on a prerelease version of
datasets enable you to reduce the size and complexity of your Delphi 3. Features may differ or be absent in the shipping version.
client application’s file set by an order of magnitude.
With only a handful of middle-tier machines connecting to your Danny Thorpe is a Delphi R&D engineer at Borland. He has also served as techni-
SQL servers, Delphi 3’s remote datasets could save you an enor- cal editor and advisor for dozens of Delphi programming books, and recently
mous amount of money in SQL server connection licenses wrote Delphi Component Design [Addison-Wesley, 1997] on advanced topics in
alone. Disconnecting the client from the server also opens many Delphi programming. When he happens upon some spare time, he rewrites his
to-do list manager to ensure that it doesn’t happen again.
options for failover and server load balancing, simply by causing
11 May 1997 Delphi Informant
On the Cover
Delphi 3
By Robert Vivrette
Easier Yet
A Look at the Delphi 3 Code Editor
W hen car shopping, you’re 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 driver’s seat, maybe
push a few buttons, or check out the stereo. Car manufacturers strive to make
your driving experience more enjoyable, so they’re always trying to match the
car’s functionality to consumer desires.
It’s the same for software. Users demand a In the Gutter
better “look,” an easier-to-use interface, and The first difference you’ll notice when you
powerful new features that make their lives open the Code Editor is the inclusion of a
simpler. This is certainly the case with the “gutter” on its left side. We’ve all experi-
enhancements to the Code Editor of Delphi enced trying to select a line of text by click-
3 — and Borland has delivered. ing near the front of the line, only to set a
breakpoint instead. By adding this gutter,
A New Flat World the new IDE provides a clickable area for
Even before you open the Code Editor, one setting breakpoints, bookmarks, and the
of the first things you’ll notice when launch- like, as well as providing an area to show
ing the Delphi 3 IDE is the flat, “buttonless” various status glyphs.
appearance of the SpeedBar and Component
palette (see Figure 1). This look is becoming You’ll also notice one or more glyphs next
popular in new Microsoft applications, such to each line of code (see Figure 2). The
as Internet Explorer and Office 97. small blue dots appear after you compile or
build, on each line for which code is gener-
At first glance, it appears the buttons don’t ated. This is a particularly useful aid in set-
have edges. However, when the mouse ting breakpoints.
moves over them, their edges appear to “pop
up.” Each button has its normal fly-over As a test, I placed:
hint as well. Some may question the value of
borderless buttons. The more I work with if False then
them, however, the more I appreciate the
clean, uncluttered appearance. To make this just above the ShowMessage statement shown in
look available to the Delphi applications you Figure 2. When it compiled, the linker knew
create, the SpeedButton component now has this code would never be called, so it didn’t link
a Boolean property named Flat. it in. As a result, no blue dots appeared on
Figure 1: The new look of Delphi 3 features the flat buttons made popular by Microsoft Office 97.
12 May 1997 Delphi Informant
On the Cover
Figure 2: The Code Editor now features a “gutter” with break- Figure 3: The new ToolTip Expression Evaluation displays the
points, bookmarks, linked status, etc. indicated with glyphs. values of variables and properties at run time.
either line. If I changed the False to True, the ShowMessage line time, you can position the mouse over a variable, and it will
was linked back in, but the display that variable’s current value (see Figure 3). This also
works on constants and parameters passed to a function or
if True then procedure. If no value appears, the value hasn’t been defined,
or optimization was turned on and the variable isn’t available.
line remained linked out (i.e. no blue dot). This is because
the ShowMessage line will always occur, so there’s no point in Evaluation hints can also show the properties of an object.
compiling the logic to jump around it. For example, if you had a line of code with a reference to
BitBtn1.Caption and you placed the cursor over the
Then I set bookmark 1 on the statement:
Caption portion, it would give you a hint showing the cap-
F := 23;
tion’s current setting. However, if you position it over the
BitBtn1 part, it would give you the reference to the visible
which made an appropriate notation in the gutter. properties of BitBtn1. Essentially, you get the same informa-
tion in a fly-over evaluation hint that you would normally see
Bookmarks are used to save your place in a piece of code in the standard Watch window.
(by pressing CS and a single number from 0 to
9), then allow you to jump back to these saved locations Code Templates
later (by pressing C and the same single number). Another nifty time-saver of the new IDE are Code
Although bookmarks aren’t new with Delphi 3 (they’ve been Templates. A Code Template is a defined structure of code
there since Delphi 1), the gutter provides a better place for that you can access through a menu, or by means of a
bookmark glyphs, keeping them out of the way of source shortcut mnemonic.
code in the main editing pane.
The best way to understand how it works is to see it in use.
The gutter is a property of the Code Editor. It’s on by In Figure 4, I began typing code for a ButtonClick event. I
default, but can be turned off if you like. You can also want to use an if statement, so I enter if, and call the
adjust its width. Code Template by pressing CJ. Delphi then presents a
list box of all if statements I’ve defined, allowing me to
pick one. When I choose one, it inserts the text associated
Drag-and-Drop with that template (see Figure 5).
Another new feature in the Code Editor is support for
drag-and-drop text editing (à la Word). You can now select
You can easily define new templates, or modify existing
a section of text, grab it with the mouse, and drag it some-
ones on the Code Insight page of the Environment
where else. If you hold down C while doing this, the text
Options dialog box (see Figure 6). For each template, you
is copied rather than moved.
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. Let’s look at each enhancement.
ToolTip Expression Evaluation
When you’re debugging your code at run time, you might
step through the program logic using 7 or 8. The
Delphi 3 IDE adds a handy new feature called ToolTip Figure 4: The new Code Template feature relieves the tedium of
Expression Evaluation (fly-over evaluation) hints. At run oft-typed code sequences.
13 May 1997 Delphi Informant
On the Cover
Figure 7: The new Code Completion feature offers valid proce-
Figure 5: The result of choosing a Code Template. dures, functions, properties, and variables while you type.
define its descrip-
tion text (e.g. if
then else (no
begin/end)), the
code you want
inserted, and a
mnemonic. The
mnemonic is used
by the IDE to filter
the list of available
templates before
presenting them to Figure 8: The new Code Parameters feature helps you remem-
you. For example, ber valid parameters without consulting the Help system.
because I only Figure 6: You can create, modify, or
typed the letters if delete Code Templates. Just select the variable you want; it will be entered into
in the previous your code automatically.
example, it presented templates that had mnemonics start-
ing with those letters. If I had known that I wanted the Code Parameters
template associated with the “ifE” mnemonic, I could have The fourth piece of Code Insight is the Code Parameters
typed ifE and it would have simply inserted the code, feature, which allows you to view the required arguments
without presenting the list (the list would have had only for a method as you type it. Code Parameters is triggered
one choice anyway). when you enter a method name followed by an opening
parenthesis (see Figure 8).
You don’t need to type anything before calling the Code
Templates list. In that case, it will show all available templates. In Figure 8, Code Parameters is activated for the Draw
Delphi 3 includes a wide range of pre-defined Code Templates, method of the form’s Canvas. There are three parameters for
from if statements, to for loops, to procedure and function this method: the X and Y coordinates, and the graphic to be
headers — even class declarations. And nothing stops you from drawn. Code Parameters even highlights the particular para-
changing them; you can modify existing templates, delete ones meter you’re working with. As you move the cursor around
you don’t want, and of course, add new ones. If you don’t like in the Code Editor, the Code Parameters feature keeps up
the mnemonic codes Borland uses, you can create your own. with you, highlighting the appropriate parameter.
For each template, you can even define where the cursor will
be left after inserting the code — a very nice touch. Even more interesting, Code Parameters knows the differ-
ence between Windows API calls and Delphi wrapper
Code Completion methods that happen to have the same name. For example,
The third portion of Code Insight is the Code if you were to type Canvas.Rectangle, it knows that you are
Completion feature. Whenever you enter a class name talking about Delphi’s Rectangle method, which only requires
followed by a period, you will be presented with a list of the coordinates of the four corners of the rectangle. However,
properties, methods, and events appropriate to the class. if you just enter Rectangle, it knows you’re talking about
You can then select an item, and it will be entered into the Rectangle function in the Windows API, which requires
the code. Figure 7 shows Code Completion presenting a completely different parameters.
list of the methods, properties, and events appropriate
for a Form object. Conducting a Thorough Search
The last enhancement I want to mention was that made to its
Furthermore, when you enter an assignment statement find facility. In previous versions, you can find text in one file at
and press CM, a list of valid variables is displayed. a time. In Delphi 3, however, the Find Text dialog box has a
14 May 1997 Delphi Informant
On the Cover
Figure 9: With Delphi 3’s enhanced text search capabilities,
you’ll no longer have to turn to Windows 95 to find all instances
of a variable in your project.
Find in Files page which allows you to perform a search in all
project files, all open files, or even in a list of specified directo-
ries (see Figure 9). And if the cursor is on a word, that word is
automatically placed in the Text to find edit box — another
slick feature that makes a programmer’s life just a little easier.
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 func-
tional 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 lan-
guages. He can be reached via e-mail at [email protected].
15 May 1997 Delphi Informant
Informant Spotlight
Delphi 2 / Object Pascal / Word for Windows
By Ian Davies
Automated Word
Creating OLE Automation Clients: Part 1
T his article will cover some general uses of OLE automation, building on
Cary Jensen’s article “OLE Automation” in the October 1996 issue of
Delphi Informant. Here, we’ll 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 Although I refer specifically to Word,
Microsoft, Office has over 80 percent of the Excel, and Access, the principles of OLE
office suite market — that’s why. automation discussed here can be applied
to any automation server, including one
Why Use OLE Automation? you create.
OLE automation offers the ability to use code
already developed in an application-specific The Importance of Scope
language, without the expense of porting it to Chapter 15 of the Delphi 2 User’s Guide
Delphi. In some cases, the conversion process explains how to develop a simple application
may simply be time-consuming. In others, that creates a new document in Word, and
such as when dealing with complex financial inserts some text:
calculations in an Excel spreadsheet, it may be
extremely difficult. uses OLEAuto;
procedure TForm1.Button1Click(Sender:
TObject);
var
V: Variant;
begin
V := CreateOLEObject('Word.Basic');
V.Insert('Hello from Delphi');
end;
The first line of the procedure attempts to
load Word into memory, create the link
with the Word.Basic object exposed by
Word, and store its instance data in the
Variant V. However, when the variable hold-
ing the instance data loses scope (in this
case, immediately after the Insert statement
is executed), the OLE automation server is
removed from memory. Because V is a local
variable that exists only within the
Button1Click procedure, Word, as a server,
will exist only for the length of time this
procedure is being executed.
16 May 1997 Delphi Informant
Informant Spotlight
There are a number of issues to bear in mind when using OLE
uses
automation with different versions of OLE servers. The code
Windows, Messages, SysUtils, Classes, Graphics,
Controls, Forms, Dialogs, OLEAuto; previously shown and in Figure 1 works fine when using Word
6 and 7 as a server, but fails when used with Word 97. The
type
reason for this is that Word 97 doesn’t start with an initial doc-
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject); ument loaded; so, the Insert statement is attempting to enter
procedure Button1Click(Sender: TObject); text into a document that doesn’t yet exist. This is easily over-
private
come by placing the following statement immediately before
{ Private declarations }
public the call to the Insert statement:
{ Public declarations }
V: Variant; V.FileNew; // This creates a new, blank document.
end;
var The WordBasic statements may seem strange to a Delphi
Form1: TForm1; programmer, but comprehensive online help is available in
implementation
Word. You can get a head-start in producing the code by
recording your actions using the Record Macro feature in
{$R *.DFM} Word and Excel, and viewing the resulting code. This is nor-
procedure TForm1.FormCreate(Sender: TObject);
mally a good place to start, because the important functions
begin can be identified, then called from your Delphi application.
V := CreateOLEObject('Word.Basic');
{ Execute the Word AppShow method to un-hide itself. }
V.AppShow; As stated earlier, Word 97 uses VBA. This provides your
end; OLE client application with far more power, flexibility, and
control over the OLE server. For backward compatibility, the
procedure TForm1.Button1Click(Sender: TObject);
begin Word.Basic object available in previous versions of Word
V.Insert('Hello from Delphi'); remains available in Word 97. Although not as powerful as
end;
VBA, Word.Basic does provide a usable and effective OLE
end. automation interface.
Figure 1: Keeping Word in scope by declaring the Variant vari- This article will concentrate on the use of the Word.Basic
able at the form level.
object, because this will enable your applications to be used
on all recent versions of Word, rather than just Word 97.
Each time this procedure is called (i.e. each time the but- Any differences between Word.Basic in Word 97 and earlier
ton is clicked), Word will be loaded, some text will be versions are identified at the appropriate points.
inserted in the normal document, and Word will be closed
again. This is an important issue, because the Word exe- It should be said that using VBA with Word 97 is likely to
cutable file (not including any supporting .DLLs) is offer a better solution in the future. In the interest of com-
almost 4MB (for version 7). patibility, however, we’ll look at that another day.
In contrast, if V was declared as a global variable or as a Using Word as a Reporting Tool
member of the form, it would exist for the life of the form With only a few lines of code, Word can be used as a sophisti-
(i.e. normally for the life of the application). If the cated tool for reporting any information available to Delphi.
CreateOLEObject method was then placed in the OnCreate Word offers precise control over the layout of documents on
event of the form, the server would be loaded once when your paper sizes other than the standard A4 (UK) or legal (US), as
form is created, and lose scope only when the form is well as the ability to control from which trays the paper is
destroyed, normally as the application is closed (see Figure 1). taken. Coupled with the use of document templates, this
makes it useful as a form-generation system for standard let-
Note the use of the AppShow statement in the FormCreate ters, invoices, and other small, but often-used documents.
procedure. OLE automation servers are normally hidden
from view; this is the statement issued to Word to make it Word’s Bookmark facility provides a simple way to control
visible. Now, when the project is executed, Button1 can be the placement of text in a document. A bookmark is simply a
clicked repeatedly, and the text appears almost immediately. named location in a document, which can be used for place-
AppShow and Insert are OLE server statements. ment of the cursor before text entry. It’s accessed through
OLE automation, by using the EditGoto statement. In Word
In the case of Microsoft Office (and most other servers), they 97, the EditGoto statement has been replaced by the
would be used if you programmed those applications directly. Bookmark object, but it remains available, provided it’s pre-
Word versions 6 and 7 use WordBasic, Access 2 uses Access fixed with the version of Word being used (i.e. EditGoto in
Basic, and Word 97, Excel (versions 5, 7, and 97), and Access Word 7 becomes WW7_EditGoto, where “WW7” denotes
version 7 all use Visual Basic for Applications (VBA). Word for Windows version 7).
17 May 1997 Delphi Informant
Informant Spotlight
procedure TMainForm.GenerateInvoiceBtnClick(Sender:
Function Use
TObject);
begin
FileOpen(FileName) Opens file named
Screen.Cursor := crHourglass; FileName in Word.
Application.ProcessMessages; CountBookmarks() Returns number of bookmarks
in current document.
{ Create new invoice document. You may have to amend the
path, depending upon where the template is stored. } BookmarkName$(Index) Returns name of bookmark
MSWord.FileNew(Template := referenced by Index.
'C:\MSOffice\Templates\Other Documents\INVOICE.DOT');
ToolsMacro(MacroName) Executes Word macro
{ Remove protection on this document to
named MacroName.
allow insertion of text. }
MSWord.ToolsUnprotectDocument; FilePrint(NumCopies := x) Prints x copies of the
current document.
{ Call the procedure that jumps to correct bookmark and
inserts the current date. } FileClose(x) Closes the current document:
GotoBookmark('Date'); 0 - Prompts user to save
MSWord.Insert(FormatDateTime('dd/mm/yy', Now)); unsaved document;
{ Call the procedure that jumps to the correct bookmark 1 - Closes and saves current
and inserts the Invoice Number, etc. } document;
GotoBookmark('Invoice_Number'); 2 - Closes current document
MSWord.Insert('123456'); without saving it.
GotoBookmark('Quantity_1');
MSWord.Insert('1');
Figure 3: Selected WordBasic functions.
GotoBookmark('Description_1'); Adding a Print Preview Facility
MSWord.Insert('Marine Magnetometer');
GotoBookmark('Price_1');
A preview of the document before printing can be achieved
MSWord.Insert('545.58'); using an OLE container, which can be linked to the file creat-
GotoBookmark('Amount_1'); ed in the previous steps. Instead of printing the docu-ment, the
MSWord.Insert('545.58');
GotoBookmark('Subtotal');
WordBasic FileSaveAs statement will create a file on the disk,
MSWord.UpdateFields; which can be viewed using the OLE container and its
GotoBookmark('Total'); CreateLinkToFile method. The example uses an OLE container
MSWord.UpdateFields;
located on another form named PreviewForm (see Figure 2).
{ Save the document with the filename TEMP.DOC Note that, for clarity’s sake, I’ve changed the name of the
and close the file without prompting the user. } Variant holding the server instance details from V to MSWord.
MSWord.FileSaveAs('c:\temp.doc');
MSWord.FileClose(2);
An advantage of using a word processor as a reporting tool is
{ Link the OLE Container to the file just created. } that it allows your customers to create and modify their
PreviewForm.OLEContainer1.CreateLinkToFile('c:\temp.doc',
False);
reports using a familiar tool. The interface between the tem-
Screen.Cursor:=crDefault; plates and your application could be achieved by providing a
Application.ProcessMessages; facility to allow the users to map the bookmarks in a docu-
{ Show the form containing the OLE Container. }
ment to fields in a database table or any other information
PreviewForm.ShowModal; available to your control program. The CountBookmarks and
end; BookmarkName$ functions will provide access to all book-
marks defined by the author of the template (see Figure 3).
Figure 2: Using Word as an OLE server to create a “report pre-
viewer.” Using the Word Spell Checker from Delphi
Not only can you create and control documents within
Word, but you can also gain access to its proofing tools, such
To create a functional example, we’ll use the Invoice tem-
as the spell checker. This requires a little more effort, because
plate provided with Word 7, insert the appropriate informa-
you must create a macro in Word that performs the spell
tion, and offer the user a preview of the invoice and the abil-
check, and passes the results back to your Delphi application.
ity to print it.
Information can be passed to and from Word through the use
The invoice is created by calling the WordBasic FileNew of Word’s document variable feature. These can be treated just
statement. To enable some text to be programmatically like variables common to both client and server, and are
inserted, the file protection on this document must be accessed using the WordBasic functions GetDocumentVar$ and
removed using the ToolsUnprotectDocument method. The SetDocumentVar (or, in this case, by Delphi calling the func-
sub-total and total fields on the Invoice template are calcu- tions using OLE automation).
lated fields, which simply need to be updated to show the
correct values. This is done using the UpdateFields state- On the Word Side
ment. Finally, the document can be printed by using the First, you need to create a new macro in Word. Open
FilePrint statement. Word and close any open documents. Then choose Tools |
18 May 1997 Delphi Informant
Informant Spotlight
Macro and enter GetSpelling as the Macro Name. Next,
procedure TSpellChkForm.CheckSpellingBtnClick(Sender: TObject);
click on the Create button and insert the WordBasic code var
to describe the macro. suggestions : string;
begin
{ Assign the word to be checked to the
If using a version of Word earlier than Word 97, use:
WordToCheck document variable. }
if MSWord.SetDocumentVar('WordToCheck',
Sub MAIN Edit1.Text) = True then
Dim WordList$(100) begin
WordToCheck$ = GetDocumentVar$("WordToCheck") { Call the user-defined GetSpelling macro in Word. }
NumWords = ToolsGetSpelling(WordList$(), WordToCheck$) MSWord.ToolsMacro('GetSpelling', 1);
Suggestions$ = WordList$(0) { Retrieve the list of suggestions from
If NumWords > 0 Then the Suggestions document variable. }
For index = 1 To NumWords - 1 suggestions := MSWord.GetDocumentVar('Suggestions');
Suggestions$ = Suggestions$ + Chr$(13) + { Call the procedure to break returned string into
WordList$(index) its component parts, and add them to a list box. }
Next index ParseAndAdd(ListBox1, suggestions);
End If end
SetDocumentVar "Suggestions", Suggestions$ else
End Sub MessageDlg('There was an error with the Word macro',
mtError, [mbOK], 0);
For Word 97 use: end;
Sub GetSpelling()
ReDim WordList$(100)
WordToCheck$ = WordBasic.[GetDocumentVar$]("WordToCheck") function TSpellChk.ParseAndAdd(Lst: TListBox;
NumWords = WordBasic.ToolsGetSpelling(WordList$(), Items: string) : Boolean;
WordToCheck$) var
Suggestions$ = WordList$(0) posn: Word;
If NumWords > 0 Then begin
For index = 1 To NumWords - 1 Lst.Clear;
Suggestions$ = Suggestions$ + Chr(13) + if (Length(Items) > 0) then
WordList$(index) begin
Next index { Parse the results and add them to a listbox. }
End If posn := pos(#13, Items);
WordBasic.SetDocumentVar "Suggestions", Suggestions$ while (posn <> 0) do begin
End Sub Lst.Items.Add(Copy(Items, 1, posn-1));
Delete(Items, 1, posn);
posn:= pos(#13, Items);
When you’re done, close the macro document, and
end;
respond Yes to the question asking if you want to keep the Lst.Items.Add(Items);
changes to the macro. end
else
The macro simply retrieves the word to spell check from Lst.Items.Add('No suggestions or spelled correctly');
end;
the document variable named WordToCheck, and passes it
to the WordBasic function ToolsGetSpelling. This func-
tion returns a list of suggested replacements in the Figure 5 (Top): This procedure calls a Word macro to perform a
spell check. Figure 6 (Bottom): The ParseAndAdd function.
WordList$ array.
Because arrays cannot be passed using OLE automation, it’s SetDocumentVar function. Next, call the GetSpelling
converted into a string separated by carriage returns, which is macro in Word by using the ToolsMacro(GetSpelling)
then passed back to the calling procedure in Delphi using the statement. The results are passed back to the calling rou-
document variable Suggestions. tine using the Suggestions document variable, which is
then split into its component parts and added to the list
On the Delphi Side box (see Figure 5).
Next, we need to create the
application in Delphi that Then the Object Pascal function shown in Figure 6 is used
will call this macro. Create to search the string for each occurrence of a carriage
a new project and add Edit, return (ASCII code 13) that delimits the returned words.
Button, ListBox, and Text The function then adds those words to a list box.
components, as shown in
Figure 4. Keeping Word Hidden
By default, as with the vast majority of OLE automation
We need to assign the servers, Word remains hidden while in use. However, cer-
work to check the docu- tain functions — such as those that cause a dialog box to
ment variable be displayed by the server — will automatically “unhide”
WordToCheck; this is Figure 4: The Spell Check the server. Fortunately, you can take precautions to ensure
achieved using the Example demonstration program. the server remains hidden.
19 May 1997 Delphi Informant
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 para-
meter indicating that you do not want to save any changes, i.e.
FileClose(2).
Also, sending the FileSave statement when a document
hasn’t 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 prac-
tical uses of using OLE automation with Microsoft Word.
Next month, we’ll discuss how Microsoft Excel can be put to
good use from a Delphi application.
It’s well worth coming to grips with OLE automation — or sim-
ply “Automation” as it’s 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 doesn’t need to reside on the same computer as the client,
but can be accessed over a LAN, an intranet, or the Internet. ∆
The files referenced in this article are available on the Delphi
Informant Works CD located in INFORM\97\MAY\DI9705ID.
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 some-
times a combination of the two. Ian can be contacted via e-mail at
106003.3317 @compuserve.com.
20 May 1997 Delphi Informant
Columns & Rows
Paradox / BDE / Delphi
By Dan Ehrmann
The Paradox Files: Part II
Properties, Field Names, and Record and Table Sizes
M any Delphi developers use the Paradox file format every day, yet the
Delphi documentation offers almost no information about it. In this arti-
cle, we’ll explore the available field types in Paradox tables, and examine some
important properties of each type. You’ll learn how fields are stored in the .DB
file, and how to calculate record and table size for any table. Also, I’ll supply a
sample application that performs these calculations for any specified table.
Working the Fields ters, even if the contents of the field are
A record may contain from 1 to 255 fields. shorter than nn. In Figure 1, the Size col-
The Paradox file format supports 17 field umn shows how many bytes the field uses
types, described in Figure 1. As noted in in a record. (Terminology note: Unlike
Part I of this series, Paradox tables use a most database systems, which use the
fixed length for each field, even if the field terms columns and rows, Paradox uses the
contains no data. terms fields and records, respectively.)
A Number field always uses eight bytes, The Level column (in Figure 1) shows the
and an Alpha field always uses nn charac- table level at which that field type was
introduced. When you save the definition
of a new table, the Borland Database
Engine (BDE) will use the highest level
necessary to support the newest field type
included in the table. (Index type and
other factors also affect the table level.)
The Delphi Object column lists the object
used to represent each field type. Each of these
is a descendant of the TField object. If you
don’t create persistent objects for each field at
design time, Delphi will create these objects at
run time, allowing you to review and/or modi-
fy their properties, or to invoke methods for
the object type.
The Standard Component column lists the
data-bound control normally used to edit
this object. Note that other controls (e.g.
TDBLookupListBox) can be used, especially
if the field is a foreign key to another
table. The final column includes comments
about most field types.
21 May 1997 Delphi Informant
Columns & Rows
The Memo Type Delphi performs this function through the MaxLength
For the Memo type, the BDE will store the first nn char- property of the TDBMemo component.
acters in the .DB file, and the whole memo in the .MB
file, unless the memo for a particular record is less than or Here’s a tip: If the memos you’re working with are frequent-
equal to nn. The main reason for this dual-storage feature ly very short and only occasionally need to be much longer,
is the table view in the Database Desktop (DBD). sizing nn as a larger number allows you to fit the whole
memo in the .DB file, with nothing in the .MB file except
In table view, the DBD displays only the first nn characters, the longer memos. In this approach, designating Mnn
and doesn’t read the complete memo until you enter field instead of Ann allows your text to overflow in the rare
view by pressing a hotkey, or clicking on a toolbar icon. instances when it’s necessary.
However, this isn’t how Delphi works. When memos are dis- Another tip: If you often search on the first few characters
played, the whole memo is read for each displayed field. The of the memo, use that number of characters for nn. The
first nn characters in each memo are stored twice — once in BDE will then need to search only the .DB file.
the .DB file, and again in the .MB file. If nn is large, this
duplication might use a lot of disk space. Other Field Types
For the Formatted Memo, Graphic, OLE, and Binary field
The Paradox file format provides no way to limit how types, the BDE allows you to optionally specify the num-
much data can be stored in a memo field. Fortunately, ber of bytes to be stored in the table. But a fixed number
Delphi Standard
Type Abb. Size (bytes) Level Notes
Object Component
Alpha Ann nn bytes; Pre-4 TStringField TDBEdit
1 <= nn <= 255
-307
Number N 8 Pre-4 TFloatField TDBEdit 15 significant digits in the range of ±10
308
to ±10 .
Money $ 8 Pre-4 TCurrencyField TDBEdit Same as Number, but displayed by default at
two decimal places.
15
Short S 2 Pre-4 TSmallIntField TDBEdit 16-bit signed integer; ±2 with a bit for the
sign; -32,767 to +32,767; $00 holds the
“null” value.
31
Long Integer I 4 5 TIntegerField TDBEdit 32-bit signed integer; ±2 with a bit for the
sign; -2,147,483,647 to +2,147,483,647;
$0000 holds the “null” value.
Date D 4 Pre-4 TDateField TDBEdit A sequential number for each day, starting
from 1/1/100, and allowing for leap years.
Time T 4 5 TTimeField TDBEdit Milliseconds since midnight; 24 hours max.
Timestamp @ 8 5 TDateTimeField TDBEdit A combination of a date and a time, each
using four bytes.
Memo Mnn 10 + nn in the .DB; 4 TMemoField TDBMemo nn must be specified. Max size of
1 <= nn <= 240 4MB per memo.
Formatted F(nn) 10 + nn in the .DB; 5 TBlobField TDBRichEdit nn is optional. Max size of 64MB
Memo 0 <= nn <= 240 per memo, including formatting.
Graphic G(nn) 10 + nn in the .DB; 5 TGraphicField TDBGraphic nn is optional. Max size of 64MB
0 <= nn <= 240 per image.
OLE O(nn) 10 + nn in the .DB; 5 TBlobField TDBImage nn is optional. Max size of 64MB
0 <= nn <= 240 (see note) per OLE file.
Binary B(nn) 10 + nn in the .DB; 4 TBlobField TDBImage nn is optional. Max size of 64MB
0 <= nn <= 240 (see note) per object.
Byte Ynn nn bytes; 5 TBytesField TDBEdit
1 <= nn <= 255
Logical L 1 5 TBooleanField TDBCheckBox Only True, False, and Blank are allowed.
Truw displays as checked, False as
unchecked, and Blank as a grayed box.
BCD #.nn 17 5 TBCDField TDBEdit Binary Coded Decimal; used to
1 <= nn <= 3 avoid precision and rounding errors
in calculations. nn represents the
number of digits after the decimal.
Autoincrement + 4 5 TAutoIncField TDBEdit Internally, this is a Long Integer Max of
one per table; usually the primary key.
Figure 1: The Paradox file format supports 17 field types.
22 May 1997 Delphi Informant
Columns & Rows
Field Name Type Size of bytes doesn’t rep- ■ The period, comma, vertical bar, and exclamation mark are
(bytes) resent directly view- allowed, but not recommended. These characters create pars-
OrderNo +* 4 able data, as with ing and compiler problems with syntax options in Delphi
CustNo A8 8 Memo fields. and other environments.
SaleDate D 4 Therefore, it’s best ■ Field names can contain spaces, but cannot begin with a
SaleTime T 4 to omit the number, space. Consider also that most other database products, espe-
ShipDate D 4 or specify 0 for the cially database servers (e.g. Oracle and InterBase) don’t allow
EmpNo A5 5 nn value. spaces in field names. If you plan to move your data to
ShipToContact A20 20 another format, or upsize it to a database server, don’t use
ShipToAddr1 A30 30 Delphi doesn’t pro- spaces in field names.
ShipToAddr2 A30 30 vide native compo-
ShipToCity A15 15 nents to display Calculating Record and Table Size
ShipToState A2 2 OLE, Binary, and Suppose you want to calculate the minimum size of a table,
ShipToZip A10 10 Byte fields on forms. assuming a particular record structure and number of records. As
ShipToPhone A20 20 And for good reason. we’ve seen, this is relatively easy to do.
ShipVIA A5 5 The contents of an
PO A12 12 OLE field are nor- Consider the Orders table shown in Figure 2. The total record
Terms A6 6 mally surfaced using size for this table is 249 bytes. Because the table is keyed, the
PaymentMethod A7 7 the OLE-enabled BDE will use the smallest size (excluding 1KB) that holds a
ItemsCount S 2 application that cre- minimum of three records. In this instance, that’s 2KB, or
ItemsTotal $ 8 ated the object. 2048 bytes. Six bytes are used by the file format at the begin-
SalesTax N 8 Binary and Byte ning of each record, leaving 2042 bytes available for data.
Freight $ 8 fields are used for
TotalInvoice $ 8 data streams that Records Table Size (bytes) The BDE can fit eight
AmountPaid $ 8 require special pro- 500 131,072
records into this
Government L 1 cessing, and aren’t 5,000 1,282,048
space, using 1992
OrderNotes M10 20 directly displayed on 50,000 12,802,048
bytes. Fifty bytes will
Record Size 249 a form; you’re be wasted at the end
500,000 128,002,048
responsible for writ- of each block.
Figure 2: This example has a total size Figure 3: Table size calculations.
ing this code. However, this also
of 249 bytes.
means that you could add six bytes to each of the eight
For example, you might store readings from scientific instru- records without increasing the table size, because this data
ments in a Binary field, then write special procedures to will fit nicely into the wasted space.
process and interpret this data.
But consider what happens if you add seven bytes to a
The next Autoincrement value is stored in the table’s header, record. This makes the total record size 256 bytes; the
where there’s room for only a single value; hence the limit of BDE will be able to fit only seven records into each block,
one Autoincrement field per table. using 1792 bytes. At the end of each block, 240 bytes are
wasted, and overall table size increases sharply.
There is no easy way to change this value, although with an
existing table, you can change a Small Integer or Long
Integer field to an Autoincrement field; the next number will
then be set to the highest found in the table.
Tip: Delphi doesn’t automatically designate a displayed
Autoincrement field as read-only. You should do this manu-
ally, so that users don’t receive an exception if they try to
change this field.
Field Names
Paradox field names follow these rules:
■ They can be from 1 to 25 characters in length.
■ They must be unique within a table.
■ They can contain letters, numbers, and any printable
character except double quotes ("), left or right brackets,
left or right braces, left or right parentheses, the # sign, or the
combination ->. The restriction on some of these characters
is a holdover from the old days of Paradox for DOS; for
compatibility reasons, these limits have remained. Figure 4: The Paradox Record and Block Size Calculator.
23 May 1997 Delphi Informant
Columns & Rows
When you restructure and pack a table, the BDE will fill Until Next Time
each block completely. Using this information, it’s easy to The next article in this series will explore indices, includ-
calculate the minimum size of the table. ing the index on the primary key, as well as the options for
secondary indices. It will explain how indices are struc-
Simply divide the number of records by eight, and round up to tured internally, and will discuss the performance and file-
get the number of blocks required; then multiply the result by size implications of keeping the primary key as short as
2KB to get the total size of data blocks. Add 2KB for the header possible. ∆
— because this is a small table — and you have your answer.
Figure 3 shows this calculation for different numbers of records.
The sample application referenced in this article is available
When individual record sizes grow especially large (for on the Delphi Informant Works CD located in
example, between 500 and 1000 bytes) you can use these INFORM\97\MAY\DI9705DE.
calculations to carefully analyze wasted space.
Sometimes you’ll find that a small reduction in one or two
fields (usually the longer Alpha fields) means that you can fit
four records into a pre-defined block size instead of three,
Dan Ehrmann is the founder and President of Kallista, Inc. a database and
resulting in a significant reduction in total disk space. Internet consulting firm based in Chicago. He is the author of two books on
Figure 4 shows a small Delphi application that lets you Paradox and is a member of Team Borland and Corel’s CTech. Dan was the
select a Paradox table, then calculates record size, block Chairman of the Advisory Board for Borland’s first Paradox conference, which
size, records per block, and wasted space per block, using evolved into the current BDC. He has worked with the Paradox file format for
the algorithms described earlier. more than 10 years. He can be reached via e-mail at
[email protected].
24 May 1997 Delphi Informant
in development
Delphi 2 / InstallShield
By Bill Todd
Deployment: Part I
Deploying Delphi 2 Applications with InstallShield
Express and InstallShield Express Professional
O ne of the third-party tools that ships with Delphi 2 is InstallShield Express
from InstallShield Corp. InstallShield Express enables you to create a sin-
gle installation disk set that will install your application and its files, the
Borland Database Engine (BDE), and ReportSmith Runtime. This, the first of two
articles, will take you through the process of building a setup for a typical
Delphi application using InstallShield Express. You will see not only how to use
InstallShield Express, but also how to deal with some of its limitations. In the
second article, we’ll tour InstallShield Express Professional and look at the
additional features it offers.
InstallShield Corp. makes a third setup pro- Installing a Delphi database program on a
gram, InstallShield3. InstallShield3 is an LAN presents some special problems. First,
extremely powerful script-based installation you have to provide two setup options. One
program. Any time you install a piece of setup will install the program on a work-
commercial software on your PC, chances station, and install the initial set of data
are the installation program was built using tables on the file server. You must also pro-
InstallShield3. It’s the most popular installa- vide a second setup option to install the pro-
tion program among commercial software gram on a new workstation after the system
companies, because it’s extremely powerful is in use. This second option is required
and flexible. However, the price you pay for because it must not install the database
power and flexibility, as with most software, tables. If it did, it would overwrite the data-
is that it’s complex and not easy to learn. By base with a new set of empty tables.
the time you read this, InstallShield5
Professional should be shipping. BDE Installation Options
InstallShield5 features a visual integrated There are several potential options for
development environment that will make it installing a BDE application on a LAN:
easier to use than InstallShield3. Because 1) You can put the program files (.EXEs and
InstallShield3 is beyond the needs of most .DLLs) on the server or on each
Delphi programmers, it won’t be covered in workstation.
these articles. 2) You can install the BDE on each work-
station, or on the server.
The Setup 3) You can install the BDE on each worksta-
This article will take you through creating tion, but have all workstations share a
a setup for a typical Delphi application. It common BDE configuration file on the
needs the BDE, but it doesn’t use server for ease of administration.
ReportSmith. The program will be installed
on stand-alone PCs at some locations, Unfortunately, InstallShield Express only sup-
while at others it will be installed on a ports installing the BDE and its configuration
LAN. The application uses local Paradox file on each local machine, and installing the
tables as its database. program files and database on the server. Even
25 May 1997 Delphi Informant
in development
in this case, a problem exists with Paradox tables, because there Using InstallShield Express
is no safe way to set the Net Dir (network control directory InstallShield Express is not automatically installed when you
path) parameter of the Paradox driver as part of the installation install Delphi 2. To install InstallShield Express, go to the
process. (A more detailed explanation of network installation IsExpress\Disk1 subdirectory on your Delphi 2 CD and run
problems will be presented later in this article.) SETUP.EXE. This will install InstallShield Express in the
\Program Files\InstallShield\IS Express Delphi directory. As is
When you install the BDE on a workstation, the installation not true of the other third-party products that ship with Delphi
only installs the BDE files on the workstation hard disk, but also 2, there is no manual for InstallShield Express. The only doc-
makes many entries in the Windows registry. Unfortunately, umentation is in the online Help.
there’s no installation program I’m aware of that supports a serv-
er-only BDE installation, i.e. an installation that puts the BDE When you select File | New from the InstallShield Express
files on the server and makes only the necessary registry entries menu, the New Project dialog box appears (see Figure 1).
on the workstation. Using a local BDE installation with a shared Enter a name for your project. By default, this name will be
configuration file on the server isn’t easy either. This is because used for the project directory. Optionally, you can also enter
the BDE uses a registry entry to determine where the BDE con- the path to a new subdirectory where your project will be
figuration file is located. Certainly the most common BDE stored. If you leave this field blank, your project directory
architecture is to install the BDE files on each workstation. This will be created in the \Program Files\InstallShield\IS Express
provides much better performance if, like most networks, the Delphi directory. Be sure to check the Include a custom setup
data transfer rate across the network is ten times slower than the type check box if you want to offer Typical, Compact, and
data transfer rate from the workstation’s local hard disk. Custom setup types as you do in this example.
“Do I have to install the entire BDE?”
This frequently-asked question is usually motivated by the
size of the BDE. Borland’s answer is “No,” but mine is “Yes.”
It is possible using InstallShield Express to set up a partial
BDE installation. If you do this, however, the BDE will be
installed in the same directory that contains your program’s
.EXE file. Because the BDE is designed to be a shared com-
ponent that can be used by many different programs, a par-
tial installation isn’t safe.
To understand why, consider a PC that already has a program
installed that uses the BDE (WordPerfect, Paradox, Quattro Figure 1: InstallShield’s New Project dialog box.
Pro, dBASE, Delphi, Borland C++, or a custom Delphi appli-
cation). When a Borland certified BDE installation program After you have created a project, the InstallShield Express
installs the BDE, the installation program checks to see if the main window looks like Figure 2. If you look closely, you
BDE is already installed. If it finds an existing copy of the will notice a mildly annoying problem: Its main form
BDE, the installation program checks the version and only doesn’t fit on the screen if you are running at 640 x 480
installs the BDE if the version to be installed is newer than — even with the Windows 95 task bar hidden. The obvi-
the one already installed. If the installation software would let ous solution is to resize the window, but that doesn’t
you install a partial copy of the BDE in the same directory work. If you make the window shorter, no vertical scroll
that already contains a copy of the BDE, you might update bar appears, so there is no way to reach the choices at the
some BDE files and not others. This will almost certainly bottom of the yellow notepad. The only solution is to use
leave the user with a copy of the BDE that will not run. the View menu to turn off either the toolbar or the status
bar at the bottom of the window. For the rest of this arti-
To avoid this problem, InstallShield Express and any other cle, you will not see the toolbar.
Borland certified installation system that supports partial
BDE installations, will only install a partial copy of the BDE The notepad metaphor is actually quite nice. It’s supposed
in the directory that contains the program’s .EXE file. While to resemble a checklist with the hand at the left pointing
this prevents your installation from damaging an existing to the next item you need to do. As you click each button
BDE installation, it also means that you may use a lot more to work your way down the list, a red check mark appears
disk space in the long run by forcing each of your Delphi next to each button so you can tell at a glance what you’ve
programs to have its own copy of the BDE. done. The only problem is that you can’t go through the
items in the order listed. You will see why as you go
My opinion is that the best way to install the BDE is the way through the steps.
it was designed to be installed: as a shared component that
will support any and all BDE-based programs that the user Start by clicking the Application Information button to dis-
may install. play the Set the Visual Design dialog box (see Figure 3).
26 May 1997 Delphi Informant
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 application’s title, and a logo bitmap as
your company’s logo. Finally, you can choose the back-
ground 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
can’t imagine why anyone would not want this feature.
Creating Components Groups and Files
The next step is to select the files that must be installed as
part of your application. InstallShield Express organizes
your files into groups; all files in a group will be installed
in the same directory. The groups are organized into com-
ponents. InstallShield Express allows you to provide three
setup types for your users: Typical, Compact, and Custom.
You organize your file groups into components, and use
the components to determine which files are installed for
Figure 2: The main window after creating a new project — each of the three setup types.
InstallShield’s Setup Checklist.
As an alternative, you can have a single setup type, in
which case, you will only need one component and it will
be created for you automatically. If you do want to offer
Typical, Compact, and Custom setups and didn’t check
the Include a custom setup type check box when you creat-
ed your project, you can still do so. Simply skip down to
the Dialog Boxes button under Select User Interface
Components. Clicking this button displays the dialog box
shown in Figure 4. The Setup Type and Custom Setup check
boxes are linked so that both are checked, or neither are
checked. That means, for example, that you can’t offer the
user just two setup types, Typical and Compact. You also
cannot change the name of the setup types.
At this point, you have a major decision to make. Because
our sample program uses Paradox tables and you must be
able to install it on either a stand-alone system or a net-
Figure 3: The Set the Visual Design dialog box. work, you need two installation types. One that installs
the program, the BDE, and the data tables, and a second
Enter the application name. This is the name that the user that installs only the program and the BDE so that the
will see in the background when installing the application. user can install the system on additional network worksta-
Click the ... (browse) button to the right of the Application tions without overwriting the data tables and destroying
Executable edit box to find the main .EXE file for your the existing data. There are two ways to do this.
application. If the .EXE contains a version resource, the
version number will be displayed automatically in the The first approach is to build a single installation disk set
Version field. If not, you can enter any version number you that offers the user three setup options: Typical, Compact,
wish. This is an alphanumeric field that can accommodate and Custom. This is the option you’ll use. You’ll design the
complex version numbers that include letters. Finally, installation so that if the user chooses a Typical installation,
enter your company name or abbreviation. The string you the program, the BDE, and the data tables will be
enter here will be the name of the top-level directory that installed. If the user chooses a Compact or Custom instal-
InstallShield Express will create in the Program Files direc- lation, only the program files and the BDE will be
tory to hold your programs. installed. The big problem with this approach is the names
of the three types of installations; it would be much less
The Set the Visual Design dialog box has two additional confusing if you could change the names to File Server,
pages, Main Window and Features, that correspond to the Network Workstation, and Stand Alone.
27 May 1997 Delphi Informant
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 bot-
tom of the form. Parameters must be
entered one-per-line in the format:
ParameterName=Value
Now you’re ready to return to the
Groups and Files button that displays the
Specify Components and Files dialog
Figure 4: The Select User Interface Components dialog box. box (see Figure 6). The BDE file groups
were created automatically by
InstallShield Express when the BDE
check box in Figure 5 was checked.
To create a new group, enter the group
name in the Group Name field and the
directory where you want the files
placed in the Destination Directory field,
then click the Add Group button. There
is no way to prompt the user for a
directory path. You are limited to the
destination directory specifiers in the
drop-down list shown in Figure 6. The
complete list of directory specifiers is
shown in Figure 7. Note that you can
use sub-directories under any of these
directory specifiers. In the example in
Figure 6, the data tables are placed in
the <INSTALLDIR>\JCMISDat sub-
directory. InstallShield Express will
automatically create any directories
that don’t exist.
Figure 5: The Select InstallShield Objects for Delphi dialog box. After the group has been created, you
can add files to it by dragging the files
The second alternative is to build two sets of installation from Explorer and dropping them on the group. In this exam-
disks and send both sets to the user. The disadvantage of this ple, I have created two groups: Program Files, which contain
technique is that you have to create twice as many disks, and the application’s .EXE file; and Data Files, which contain all the
the user has to keep the sets straight. Paradox tables the application uses. If you need to create an
empty subdirectory as part of your installation process, simply
Because you’re creating one disk set with multiple setup types, add a group, but don’t add any files to it. You will get a warning
you will check the Setup Type check box (see Figure 4), and when you build your setup files, but the user sees nothing
return to the Groups and Files button (again, see Figure 2). unusual and the directory will be created.
One of the groups of files that you have to install is the BDE,
and you can’t create that group from here. You need to take a Next, click on the Components tab and create two compo-
detour in the InstallShield Express checklist down to the nents. The first, Application Files, is created by InstallShield
General Options button under Select InstallShield Objects for Express. You need to change it so that it contains the Program
Delphi. (This problem with the order of the checklist has Files group and all three BDE groups. To add a group to a
been corrected in InstallShield Express Professional.) component, select the component in the Application
28 May 1997 Delphi Informant
in development
their workstation to run the copy of
the program’s .EXE file on the server,
and install the BDE on their local
hard drive.
Selecting User Interface
Components
Next, return to the Dialog Boxes but-
ton, 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 instal-
lation 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 agree-
ment, click on Software License
Agreement to select it, then click the
Settings tab and enter the path to the
text file. The Readme Information
Figure 6: The Specify Components and Files dialog box.
option works the same way.
Specifier Description The Settings page for the Select Program Folder check box
<INSTALLDIR> The main installation directory
enables you to enter the name of the program folder that will
specified by the user. be created for your program. If you don’t enter a value, your
<WINDIR> The Windows directory. InstallShield Express project name will be used. You even
<WINSYSDIR> The Windows\System directory. have the option to sign up for Pipeline Communications’
<WINDISK> The drive that the Windows online registration service to allow your users to register their
directory resides on, for software via modem during installation.
example, C:.
<WINSYSDISK> The drive that the Windows Creating Registry Entries
system directory resides on.
If you need to create or change any registry entries as part
<WINSYS16DIR> On an NT system this is the
16-bit Windows directory. of your installation, begin by clicking the Keys button
<PROGRAMFILESDIR> The Program Files directory. under Make Registry Changes (back on the Setup
<COMMONFILESDIR> The Program Files\Common Checklist shown in Figure 2) to display the dialog box in
Files directory. Figure 9. To add or change an entry in the registry, select
Figure 7: InstallShield Express directory specifiers.
the top-level key, then click the Add Key button and enter
the complete path to the key you want to create or change.
Components list, select the group in the File Groups list, and Do not type a leading backslash (\) at the beginning of
click the Add to Application Component button. your list of keys. If you do, InstallShield Express will cre-
ate a null key in the registry between the top-level key you
On the Setup Types page you will find the three setup types, selected and your first key. To add a value under any key,
Custom, Typical, and Compact, listed on the left, and the select the key, then click the Registry - Values tab, and use
components listed on the right. To add a component to a the Add Value button to add as many values as you wish
setup type, click the setup type, then the component, then under the selected key.
the Add to Setup Type button. Adding the Application Files
component to all three setup types and the Data Tables com- For the sample installation, you will change one of the keys
ponent to the Typical setup provides the configuration you for the BDE to ensure the Local Share setting in the BDE
need. Typical will install the entire application including the configuration is set to True. Setting Local Share to True is
BDE and data tables on either a file server or stand-alone sys- required to make table and record locking work correctly on
tem. Compact will install only the BDE and application for a a peer-to-peer network. In addition, it disables write caching,
network workstation. Note that when users perform a to protect against data loss and table corruption in case of a
system crash. Setting Local Share requires adding the key
Compact installation to a network workstation, they must Software\Borland\Database Engine\Settings\System\Init
specify the directory on the server that contains the pro- under HKEY_LOCAL_MACHINE, and adding the value
gram files as the installation directory. This will configure Local Share = True.
29 May 1997 Delphi Informant
in development
Configuring the BDE
When you install a program that uses
the BDE and Paradox tables, you must
be concerned with four things:
1) If the user installs your program on
a peer-to-peer network such as a
Microsoft network, you want to set
Local Share to True to disable write
caching and ensure that file sharing
works correctly.
2) You must create any aliases your
program requires.
3) You must set the NET DIR
property of the Paradox driver to
the shared network directory where
you want the network control files
created.
Figure 8: The Select User Interface Components dialog box. 4) You must set any other options in
the BDE configuration file.
As you have already seen, you can set
Local Share by setting the value of its
registry key. Creating aliases is also
easy: Click the Settings button in the
Select InstallShield Objects for Delphi
dialog box (again, see Figure 5). That
takes care of bullet items 1 and 2.
The fourth bullet item — other BDE
configuration file options — is a bit of
a problem. InstallShield Express uses
the IDAPI32.CNF file in the IS
Express Delphi\Redist subdirectory as
the default BDE configuration file,
and you can edit this file using the
BDE configuration program. If the
BDE doesn’t exist on the target
machine, InstallShield Express will
install IDAPI32.CNF and rename it to
IDAPI32.CFG. If the BDE has already
been installed on the target machine,
Figure 9: The Make Registry Changes dialog box. InstallShield Express will merge the
settings in IDAPI32.CNF into the
Specifying Folders and Icons existing BDE configuration file. However, it will not over-
The next step in creating an installation is defining the con- write existing settings. If a setting in the existing BDE con-
tents of the application folder you want created as part of the figuration file differs from a setting in the IDAPI32.CNF
installation. Figure 10 shows the Specify Folders and Icons file, the setting in the existing file will prevail. There is no
dialog box. To add an icon to the folder, use the ... (browse) way to change this behavior.
button to the right of the Run Command edit box to select a
file from one of your groups. Next, enter any command-line Bullet item 3, setting the NET DIR path, is simply impossi-
parameters and the description you want to appear below the ble. Although this setting is stored in the registry, it’s also
icon, and click the Add Icon button. stored in the BDE configuration file, and the value in the
configuration file is the one the BDE configuration program
For the sample installation, an icon for the program’s .EXE reads. Even if you could change the registry entry, you may
file has been added, as well as one for the BDE configura- not want to. If the user already has the BDE installed and
tion program. It’s a good idea to provide access to the BDE configured to use Paradox tables on a network, changing the
configuration program, just in case any settings have to be network control directory will cause a serious problem, unless
changed manually. it’s changed for every user. If not, users that have different
30 May 1997 Delphi Informant
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.
The only thing that makes InstallShield Express a bit difficult
Figure 10: The Specify Folders and Icons dialog box. to learn to use is that you can’t go through the checklist in the
order it’s presented, and there is no tutorial in the online Help
NET DIR settings will not be able to access the same data- to take you through the process in order. I think most users
base at the same time. You will either have to write a separate could learn to use the program faster if the Help file contained
program that checks to see if the path to the network control a topic that listed each of the steps in creating a setup, and the
directory is already set, and if not, set it using BDE API calls. topic to search for that described that step in detail. ∆
Or you will have to give the user instructions for changing
this setting using the BDE configuration program. The files referenced in this article are available on the Delphi
Informant Works CD located in INFORM\97\MAY\DI9705BT.
If you are adding one or more new aliases to the target sys-
tem, 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 Bill Todd is President of The Database Group, Inc., a database consulting and devel-
opment firm based near Phoenix. He is co-author of Delphi: A Developer’s Guide
target system in a state where the alias exists, but your pro- [M&T Books, 1995], Delphi 2: A Developer’s Guide [M&T Books, 1996], and
gram does not work as expected. 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
Conclusion Conference and the Borland Conference in London. He can be reached on
After you have created your installation, run the Disk Builder CompuServe at 71333,2146, on the Internet at
[email protected],
to create the diskette images for your installation diskettes. or at (602) 802-0178.
31 May 1997 Delphi Informant
DBNavigator
Delphi 2 / Delphi 3
By Cary Jensen, Ph.D.
Cached Updates: Part I
Diversify Your Record-Editing Options
D elphi 2 introduced a powerful new database-related capability:
cached updates. These allow changes made to one or more DataSets
(Tables, Queries, or StoredProcs) to be stored locally, and applied as a
group. The benefits of this technique include increased performance,
reduced network traffic, additional user interface options, and enhanced
programmatic control over data updates.
This is the first of a three-part series that ■ You can allow users to preview edits
takes an in-depth look at cached updates. It before the cached changes are applied to
begins with an overview of what cached the underlying database. Even “deleted”
updates are, and what they are not. It con- records can be previewed.
tinues with a step-by-step discussion of how ■ A user can selectively revert individual
to implement cached updates in your data- edits to their pre-edited state without
base applications. Unless otherwise specified, affecting other edits still in the cache.
this material applies to Delphi 2 and 3. Even “deleted” records can be undeleted.
■ Edits being cached can be updated within
Overview a transaction, and a transaction can be
Unless you program otherwise, changes to rolled back if all the edits can’t be applied.
records being edited by the user are posted ■ You can permit a user to edit read-only
(applied) to the underlying database as soon DataSets. When applied correctly, cached
as the user has performed an action that updates can, for example, permit a user
posts the record, e.g. moving off the record, to edit the result set of a join query.
or clicking the Post changes button of a ■ Cached updates provide complete pro-
linked DBNavigator component. Likewise, grammatic control over the posting of
you can programmatically post edits by initi- cached changes. Specifically, you can cre-
ating a move off the record, or by explicitly ate an event handler that’s called as each
calling a DataSet’s Post method. changed record is posted. From this code,
you can choose to modify the record
When cached updates are enabled, the before posting, ignore the change, and
Borland Database Engine (BDE) tracks all continue to the next record — or abort
data changes (modifications, insertions, and the posting process.
deletions) locally. After the necessary changes ■ You can use cached updates as a means
are made, they’re applied to the underlying of creating an audit trail. As each
database as a group. The advantages of using record is posted, you can programmati-
cached updates include: cally determine the type of change
■ Users can edit one or more records, then made to that record (e.g. insertion,
cancel all changes — without ever affect- deletion, or modification). Also, you
ing the underlying data. can easily determine which fields in a
■ Network traffic may decline, because modified record were edited, and write
edits needn’t be transmitted across the both the old and new values for those
network individually. fields to your audit trail.
32 May 1997 Delphi Informant
DBNavigator
■ You can create an event handler that
executes when an attempt to post a
cached change fails. Again, your code
can modify the record and retry,
ignore just that one record and con-
tinue applying the other edits in the
cache, or abort the posting entirely.
As you can see, this list argues power-
fully for the use of
cached updates.
The following demonstration uses a
Paradox table, for simplicity’s sake. While
cached updates are especially useful in
client/server applications, characteristics
of individual servers affect which tech-
niques you’ll use to apply your updates.
By using a Paradox table, those server-
specific issues can be avoided. Figure 1: The main form of the CACHE1 project.
(An alternative to cached updates — Consider the following event handler associated with a but-
transaction processing — is available under all versions of ton. Assuming the DataSet named Table1 is set to cache
Delphi. You can initiate a transaction before the edits begin, updates, clicking this button will attempt to apply the
and commit or roll back the transaction when the edits are updates, then clear the cache. If ApplyUpdates generates an
complete. This technique is quite different from cached exception, then CommitUpdates doesn’t execute; consequent-
updates. During a transaction, the database is informed of each ly, the cache remains intact:
edit as it occurs, although the changes are not made permanent
until the transaction is committed. Also, transaction processing procedure TForm1.Button1Click(Sender: TObject);
begin
is handled by the database server, not at the application level.) Table1.ApplyUpdates;
Table1.CommitUpdates;
end;
Cached Updates: The Basics
Despite the power that cached updates provide, they’re remark- If you close this DataSet before applying the updates,
ably easy to use in their simplest form. All DataSets have a cached changes are lost. However, a more elegant tech-
CachedUpdates property. When you set this property to True, all nique is to call the DataSet CancelUpdates method, which
edits to the corresponding DataSet are cached. CachedUpdates is has the effect of clearing the cache. However, like
a published property, and consequently can be set to True at ApplyUpdates, calling CancelUpdates doesn’t affect the
run time or design time. You can set CachedUpdates to True on CachedUpdates property.
more than one DataSet simultaneously.
These basic techniques are demonstrated in the project named
As long as CachedUpdates is True, the BDE continues to CACHE1.DPR, shown in Figure 1. This project makes use of
cache updates. Setting CachedUpdates to False causes the BDE a table named CUST1.DB, which is an exact duplicate of the
to cancel any pending edits in the cache, then stop caching. CUSTOMER.DB table that ships with Delphi. The
Likewise, if you close the DataSet before posting pending CUST1.DB table is copied from the CUSTOMER.DB table
edits in the cache, the edits are canceled. To post the cached each time you run the downloadable example projects for this
changes to a DataSet, you must call the ApplyUpdates method article. This is because cached updates can be adequately
of either the DataSet or its Database. The use of a Database’s demonstrated only by editing a table.
ApplyUpdates method is described later in this article.
The code performing this task (see Figure 2) is attached to
The DataSet ApplyUpdates method attempts to post all edits the OnCreate event handler for this project’s main form,
pending in the cache. If it’s unsuccessful, then an exception is which includes two buttons. The button labeled Start
raised, the cache’s contents remain pending, and the DataSet Caching is associated with the OnClick event handler
continues caching. If the method succeeds, it’s then necessary shown in Figure 3.
to exit the Cached Updates mode by setting the DataSet’s
CachedUpdates property to False, or to clear the cache by call- When clicked, it tests the CachedUpdates property of Table1
ing CommitUpdates, then continue caching. If you want the to determine if it’s caching updates. If not, it places Table1
BDE to continue caching after posting pending edits, it’s into the Cached Update mode, sets the DataSource’s
essential to call CommitUpdates. AutoEdit property to True (to permit the user to edit the
33 May 1997 Delphi Informant
DBNavigator
As you inspect the code for Button1’s OnClick event han-
procedure TForm1.FormCreate(Sender: TObject); dler, you’ll notice that this project doesn’t permit users to
var
OldTable: TTable;
edit the table unless they begin caching. Though this isn’t
begin an essential feature, you might still want to employ it.
However, the primary technique to prevent the user from
OldTable := TTable.Create(Self);
try
editing the table — that of setting the DataSource’s
OldTable.DatabaseName := 'DBDEMOS'; AutoEdit property to False — is sometimes only partially
OldTable.TableName := 'CUSTOMER.DB'; successful. When you view a table through a DBGrid (or
Table1.TableName := 'CUST1.DB';
Table1.BatchMove(OldTable,batCopy);
use a DBNavigator, as is being done here), a user can still
Table1.AddIndex('','CustNo',[ixPrimary, ixUnique]); insert and delete records — even when AutoEdit is set to
Table1.Open; False. Consequently, this project contains two additional
finally
OldTable.Free;
event handlers. One is on Table1’s BeforeDelete event prop-
end; erty, while the other is on Table1’s BeforeInsert. From this
code, the table’s CachedUpdates property is inspected; an
end;
exception is raised if the property is not set to True. This
Figure 2: This code copies the CUST1.DB table from the technique is demonstrated in the following event handler,
CUSTOMER.DB table. which is assigned to Table1’s BeforeDelete event property:
procedure TForm1.Button1Click(Sender: TObject); procedure TForm1.Table1BeforeDelete(DataSet: TDataSet);
begin begin
if not Table1.CachedUpdates then if not Table1.CachedUpdates then
begin raise EDenyEdit.Create(
Table1.CachedUpdates := True; 'Click Start Caching to delete a record');
DataSource1.AutoEdit := True; end;
Button1.Caption := 'Apply Updates';
Button2.Enabled := True;
end Both the BeforeDelete and BeforeInsert event handlers raise a
else custom exception named EDenyEdit. Alternatively, it would be
begin
if Table1.State in [dsInsert, dsEdit] then
just as effective to raise one of the predefined exceptions, such
Table1.Post; as Exception, rather than a custom exception. However, it’s gen-
if Table1.UpdatesPending then erally considered good programming practice to leave the rais-
begin
Table1.ApplyUpdates;
ing of predefined exceptions to Delphi, and define a custom
Table1.CommitUpdates; exception when you need to explicitly raise one within your
end; code. The following is the type declaration of EDenyEdit :
DataSource1.AutoEdit := False;
Table1.CachedUpdates := False;
Button1.Caption := 'Start Caching'; type
Button2.Enabled := False; EDenyEdit = class(Exception);
end;
end;
Finally, there’s the issue of closing the table without apply-
Figure 3: The OnClick event handler for the Start Caching ing cached updates, if some are pending. As you learned
button of the CACHE1 project. earlier, all pending cached updates are lost if the table is
closed before the updates are applied. You can determine if
table), updates Button1’s caption, and enables the Empty any cached updates are pending by inspecting the table’s
Cache button. If Table1 is already caching updates, clicking UpdatesPending property. This property is True if the table is
Button1 results in posting any current edits to the cache, caching updates, and if unapplied updates remain in the
applying the updates, clearing the cache, turning cached cache; otherwise, it’s False. Note, however, that inspecting
updates off, toggling the button’s caption, and disabling the the value of UpdatesPending when the corresponding
Empty Cache button (Button2). DataSet’s CachedUpdates property is set to False generates an
exception. Consequently, you should test UpdatesPending
The Empty Cache button simply removes any changes only after confirming that CachedUpdates is True.
stored in the cache. The OnClick event handler for this
button calls Table1’s CancelUpdates method to empty the The CACHE1 project demonstrates the use of this property
cache. Next, ShowMessage reminds the user that the table in the form’s OnCloseQuery event handler, as shown in
is still caching updates. This is the OnClick event handler Figure 4. When the form is being closed, any pending edits
for Button2: are first posted to the table. Next, if updates are being
cached, UpdatesPending is tested to determine whether or
procedure TForm1.Button2Click(Sender: TObject);
begin not the cache is empty. If not, the user is asked to indicate
Table1.CancelUpdates; whether to cancel pending edits, or post them. If the user
ShowMessage('Cache emptied. Still caching updates');
confirms posting of the edits, but ApplyUpdates fails, an
end;
exception is raised, and the form doesn’t close.
34 May 1997 Delphi Informant
DBNavigator
automatically by Delphi. One way is by using the Databases
procedure TForm1.FormCloseQuery(Sender: TObject;
var CanClose: Boolean);
property of the TSession class. Because Delphi automatically
begin creates an instance (named Session) of this class, any database
if Table1.State in [dsInsert, dsEdit] then application has ready access to databases created automatical-
Table1.Post;
if Table1.CachedUpdates and Table1.UpdatesPending then
ly. TSession.Databases is an array property. Because it’s a zero-
if MessageDlg('Updates pending. ' + based array — and assuming only one automatic database is
'Select OK to apply, Cancel to lose', created, and no explicitly defined databases appear on the
mtInformation,
[mbOK,mbCancel],0) <> mrOK then
form — you can use Session.Databases[0] to access the
Table1.CancelUpdates automatic database. Another way is through the Database
else property of a DataSet. This read-only property contains a
begin
Table1.ApplyUpdates;
pointer to the DataSet’s database — whether it’s automatically
Table1.CommitUpdates; created, or one you explicitly placed on the form.
end;
end;
The following code demonstrates how to wrap a transaction
Figure 4: The OnCloseQuery event handler.
around a DataSet using its Database property to access the
automatically created database:
Cached Updates and Transactions Table1.Database.StartTransaction;
The use of ApplyUpdates in the preceding example has try
Table1.ApplyUpdates;
some limitations. As mentioned, when ApplyUpdates fails, Table1.Database.Commit;
an exception is raised. A potential problem arises if some of Table1.CommitUpdates;
the pending edits were actually applied prior to the excep- except
Table1.Database.Rollback;
tion. In most cases, it’s better if the pending edits are raise;
applied in an “all or none” fashion. This requires transac- end;
tion processing.
The use of a transactional wrapper for cached updates is
I offer two solutions to providing transaction control with demonstrated in the CACHE2 project. (This project is iden-
cached updates. One is to provide a transaction wrapper around tical to CACHE1, with the exception of the transaction.)
your call to a DataSet’s ApplyUpdates method. The second is to One additional adjustment is necessary in this project, how-
use the ApplyUpdates method of the DataSet’s Database. ever, because a Paradox table is being used. Whenever you
use transactions with local tables (dBASE, Paradox, and so
Adding a transaction wrapper is easy. First, begin a transac- forth), Delphi requires that the database’s TransIsolation prop-
tion. Next, enter a try..except block. Within the try block, erty be set to tiDirtyRead. In essence, tiDirtyRead treats
apply the updates, commit the transaction, then commit those records that have been modified by another pending
the updates. From within the except block, roll back the transaction (one that has not yet been committed) as if they
transaction and raise the exception again. (Repeating the have been committed, even though they may eventually get
exception is optional, but provides a simple means of let- rolled back by that transaction. Because the TransIsolation
ting the user know that updates couldn’t be applied.) property of the default Database is not tiDirtyRead, this must
be set within your code.
Transaction processing is provided by the TDatabase class.
In most cases, this means adding a Database component to
your form, and using it as the source of data access for your The code in Figure 5 is associated with the OnClick event
DataSets. For example, suppose you have a Database named handler for the Start Caching button in the CACHE2 project.
Database1, and Table1 uses this Database. The following
code permits you to apply updates within a transaction: Using Database.ApplyUpdates
The TDatabase class also supports an ApplyUpdates method.
Database1.StartTransaction; This method has the following syntax:
try
Table1.ApplyUpdates;
Database1.Commit; procedure ApplyUpdates(const DataSets: array of TDataSet);
Table1.CommitUpdates;
except As you can see, when calling ApplyUpdates, you must pass
Database1.Rollback;
raise; an array of DataSets. The Database component will then
end; call ApplyUpdates and CommitUpdates for each of the
DataSets in this array.
But can you use this technique without explicitly adding a
Database component to your form? Yes, you can. To use a In addition, it makes the calls to ApplyUpdates from within a
DataSet, a database is required; but if you haven’t added one to transaction, which it will roll back if any of the updates can’t be
your form explicitly, Delphi will create one for you at run time. applied. This is obvious from the source code of the TDatabase
There are two ways to access a Database component created class (see Figure 6), which can be found in the DB.PAS unit.
35 May 1997 Delphi Informant
DBNavigator
procedure TForm1.Button1Click(Sender: TObject); procedure TForm1.Button1Click(Sender: TObject);
begin begin
if not Table1.CachedUpdates then if not Table1.CachedUpdates then
begin begin
Table1.CachedUpdates := True; Table1.CachedUpdates := True;
DataSource1.AutoEdit := True; DataSource1.AutoEdit := True;
Button1.Caption := 'Apply Updates'; Button1.Caption := 'Apply Updates';
Button2.Enabled := True; Button2.Enabled := True;
end end
else else
begin begin
if Table1.State in [dsInsert, dsEdit] then if Table1.State in [dsInsert, dsEdit] then
Table1.Post; Table1.Post;
if Table1.UpdatesPending then if Table1.UpdatesPending then
// Need to update only if cached edits are pending. begin
begin Table1.Database.TransIsolation := tiDirtyRead;
Table1.Database.TransIsolation := tiDirtyRead; Table1.Database.ApplyUpdates([Table1]);
Table1.Database.StartTransaction; end;
try DataSource1.AutoEdit := False;
Table1.ApplyUpdates; Table1.CachedUpdates := False;
Table1.Database.Commit; Button1.Caption := 'Start Caching';
Table1.CommitUpdates; Button2.Enabled := False;
except end;
Table1.Database.Rollback; end;
raise;
end;
Figure 7: The Database ApplyUpdates method could have been
end;
DataSource1.AutoEdit := False; substituted for TTable.ApplyUpdates in the CACHE2 project.
Table1.CachedUpdates := False;
Button1.Caption := 'Start Caching'; rolled back. Because the except clause raises the exception
Button2.Enabled := False; again, the subsequent calls to CommitUpdates are made
end;
end; only if no exception is encountered. (A side note: The call
to CommitUpdates cannot fail.)
Figure 5: The OnClick event handler for the Start Caching but-
ton of the CACHE2 project.
Because of its strong support for both transaction process-
ing and the inclusion of the call to CommitUpdates, you
procedure TDatabase.ApplyUpdates(
should definitely consider using TDatabase.ApplyUpdates in
const DataSets: array of TDBDataSet);
var lieu of TDataSet.ApplyUpdates. The code in Figure 7
I: Integer; demonstrates how the Database ApplyUpdates method could
DS: TDBDataSet; have been substituted for the TTable.ApplyUpdates method
begin
in the CACHE2 project.
StartTransaction;
try Conclusion
for I := 0 to High(DataSets) do begin Cached updates greatly increase your record-editing options.
DS := DataSets[I];
if DS.Database <> Self then
In addition, the technique can generally improve your appli-
DatabaseError(FmtLoadStr( cation’s performance. Fortunately, in its simplest case — that
SUpdateWrongDB,[DS.Name, Name])); of editing a single table — cached updates are easy to employ.
DataSets[I].ApplyUpdates;
end;
Commit; Next month’s installment will continue the discussion of
except cached updates by considering how to work with individual
Rollback; records in the cache, and how to use the UpdateSQL compo-
raise;
end;
nent to permit editing of read-only DataSets. ∆
for I := 0 to High(DataSets) do The files referenced in this article are available on the Delphi
DataSets[I].CommitUpdates;
Informant Works CD located in INFORM\97\MAY\DI9705CJ.
end;
Figure 6: The source code of the TDatabase.ApplyUpdates
method.
The code shows that the Database component begins the Cary Jensen is President of Jensen Data Systems, Inc., a Houston-based database
development company. He is author of more than a dozen books, including
transaction, then calls the ApplyUpdates method for each Delphi In Depth [Osborne/McGraw-Hill, 1996]. Cary is also a Contributing Editor
DataSet in the passed array of DataSets. Only after all of Delphi Informant, as well as a member of the Delphi Advisory Board for the
DataSets have been updated does the transaction get com- 1997 Borland Developers Conference. For information concerning Jensen Data
mitted. If an exception is raised by any call to Systems’ Delphi consulting and training services, visit the Jensen Data Systems
ApplyUpdates, or the call to Commit, the transaction is Web site at http: //gramercy.ios.com/~jdsi. You can also reach Jensen Data
Systems at (281) 359-3311, or via e-mail at [email protected].
36 May 1997 Delphi Informant
On the Net
Delphi 2 / Object Pascal / Internet / Intranets
By John Penman
NetCheck: Part I
A 32-Bit Tool for Debugging Networks
W 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 NetCheck: A Simple Network
“check” to any network application; how- Debugging Tool
ever, developing applications for the In this two-part series, we’ll examine
Internet and intranets can be a tricky, NetCheck, a simple network debugging tool
frustrating exercise. A developer must con- that uses three non-visual Delphi compo-
tend with two possible sources of apparent nents (see Figure 1). Each component encap-
program failure: poor network connectivi- sulates a well-known debugging service:
ty and internal program errors (i.e. bugs). ■ Sonar is a wrapper for the
A network problem is less common than ping application,
an application bug, but can happen at ■ EchoC is an echo client wrap per for the
unexpected times. Network problems can Echo service, and
be caused by an improperly installed net- ■ Trace encapsulates the TraceRoute
work card, a malfunctioning router that application.
can cause a break in the network, etc.
Sometimes it’s difficult to differentiate Each component uses the Windows Sockets
between the two, so it’s important for a (Winsock) .DLL to interface with the
developer to have a network debugger that Internet. To follow this series, you must have
helps track down such problems. some knowledge of the Winsock API. (It’s
too large a topic to cover here in detail; for
more information on the Winsock API, see
the references at the end of this article.)
Ping
To test connectivity between two peer
machines on a network, we’ll 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 return-
ing an echo reply packet.
The nature of ICMP dictates such a
Figure 1: The complete NetCheck program with its Sonar, EchoC, and response, meaning no server program is
Trace components.
37 May 1997 Delphi Informant
On the Net
required on the server-to-service echo request packets. In con- ing application because the EchoC component does not
trast, an echo service (as we’ll discuss in Part II) requires a require ICMP.DLL. Additionally, the TSonar.GetHost method
server program on the target host to service echo requests. calls several functions from the Winsock API to resolve the
Using ping is an excellent way to check the connectivity name of the target host to an address Sonar uses to ping.
between peers at the Internet Protocol (IP) layer.
Additionally, ping yields interesting information such as the As mentioned, Microsoft’s Winsock 1.1 does not support
round-trip time between the sender and target host, which raw sockets, so Sonar uses ICMP.DLL to send ping pack-
we can analyze for clues to packet loss. ets instead. Before Sonar can ping a host, it must initialize
two important structures, TIPOptions and
The downside to ping is that it’s fallible. For example, the tar- TICMPEchoReply, with appropriate values (see Listing Two
get host may hide behind a firewall server that filters out echo beginning on page 40). The IcmpSendEcho function, which
request packets, preventing the target host from replying. sends and transmits echo packets, requires these filled
structures before use.
In UNIX and some Windows platforms, a ping application
uses raw sockets to work with ICMP packets. Some imple- The TIPOptions record specifies the options in the IP head-
mentations of Winsock, such as Microsoft’s Winsock 1.1 for er. Such options include the Time To Live (TTL), Type Of
Windows 95, do not support raw sockets. Microsoft has Service (TOS), and OptionsData data fields. The TTL is set
included the ICMP.DLL file with its current release of nominally to 128 (although you can change this from 32 to
Windows 95 to rectify this lack of raw sockets support. The 255 in the Object Inspector). This value tells the packet how
Sonar component uses this .DLL. many hops it can go. That is, Sonar can send a packet that
lives for a number of hops — set by the TTL field — before
(Note that Windows NT 4.0 uses Winsock 2.0, which does expiring. For our purposes, a hop is a “link” between hosts.
support raw sockets, and Winsock 2.0 for Windows 95 is
expected to be released later this year. In a future article, I’ll The TICMPEchoReply structure contains the data
present an enhanced version of the Sonar component to work IcmpSendEcho returns in response to an echo reply request.
with raw sockets.) For example, pEchoReply, a pointer to TICMPEchoReply,
contains an Address field holding the target host’s replying
I named this component Sonar because it “sounds” a target address. The Status field is important because the compo-
host similar to how a ship’s sonar sounds an underwater nent uses it to check the state of the returned packet. The
object. The client sends an echo request packet to a server, RTT field tells Sonar the total round-trip time for a packet
which in turn must respond automatically by echoing an in milliseconds.
echo reply packet. Hopefully, the name Sonar will distin-
guish it from other ping applications. Because Sonar calls the IcmpCreateFile, IcmpCloseHandle, and
IcmpSendEcho functions from a .DLL, it must call
Inside Sonar GetProcAddress to establish each function’s address. Sonar does
Sonar is based on the TSonar class (see Listing One on page this before calling IcmpSendEcho in the DoSonar method (see
40), a direct descendant of TComponent. (I used Martien Listing Three beginning on page 41). The IcmpCreateFile
Verbruggen’s demonstration ping program to develop Sonar. function creates a context handle for IcmpSendEcho, and
See the reference listed at the end of this article.) Like all IcmpCloseHandle closes the same context handle when Sonar
components, the TSonar class has a constructor method, is done with IcmpSendEcho.
TSonar.Create, that initializes some properties and calls two
functions to perform essential tasks. To monitor the progress of these echo request packets sent by
Sonar, the echo reply packets sent by the host, and other
The first function, CheckWS, initializes WINSOCK.DLL. If messages, Sonar uses these TNotifyEvent procedures:
Winsock isn’t functioning or is missing, Sonar displays a 1) OnRecvDataEvent posts all messages including statistics to
Warning dialog box and closes the calling application. Sonar NetCheck,
does this because the Sonar, EchoC, and Trace components 2) OnResolveEvent posts the host name and IP address of the
rely heavily on WINSOCK.DLL. Thus, it doesn’t make sense target host, and
to continue with the application when Winsock isn’t available. 3) OnProgressEvent updates the progress bar to chart progress
(or lack thereof ) of packets sent to the target host.
The second function, CheckICMP, tries to create the
hIcmpModule handle for ICMP.DLL. If LoadLibrary fails to Are You There?
load the .DLL, it sets hIcmpModule to nil. CheckWS assigns a Let’s look at Sonar in action. In NetCheck, before we can
Boolean value to a read-only property, PingAvail, which click on the Ping button, we must enter the name, or IP
NetCheck starts up. When PingAvail is False, NetCheck dis- address, of the target host. We pass this string to Sonar’s
ables the Ping button, and displays a warning message in the GetHost method via the Sonar1.Ping method. GetHost deter-
memPingMsg Memo control. In contrast to CheckWS, when mines the target host’s IP address, which IcmpSendEcho uses
CheckICMP fails to load ICMP.DLL, it doesn’t abort the call- to ping that host.
38 May 1997 Delphi Informant
On the Net
IcmpSendEcho is syn-
chronous, meaning it // Calculate statistics for a batch of packets.
procedure TSonar.Stats;
will “block” when it’s begin
waiting for a reply from try
the target host before FAve := Round(FRTTSum/FNoEchoes);
FMsg := Concat('Sent ',IntToStr(FNoPackets),' packets');
timing out. In other OnRecvDataEvent;
words, NetCheck will be FMsg := Concat('Received ',IntToStr(FNoEchoes),
unresponsive, and appear ' packets');
OnRecvDataEvent;
dead. This isn’t satisfac- FMsg := Concat('Min/Avg/Max= ',IntToStr(FMin),
tory. We can avoid this '/',IntToStr(FAve),'/',IntToStr(FMax));
by creating a thread for OnRecvDataEvent;
except
IcmpSendEcho. (This fea- on EDivByZero do
ture is not implemented begin
in this version of FMsg := 'Cannot calculate stats';
OnRecvDataEvent;
NetCheck; we’ll address Figure 2: The published proper-
end;
this thorny issue next ties of the Sonar component in end;
the Object Inspector. end;
month.)
Figure 3: Calculating simple statistics.
The IcmpSendEcho function sends a number of pings as
determined by FNoPackets. IcmpSendEcho uses FAddress that
Sonar obtained from GetHost to locate the target host.
FTimeOut is a time-out value of Sonar’s TimeOut property,
set in the Object Inspector. TimeOut’s default value is 2000.
You can increase this for hard-to-reach hosts on slow and dif-
ficult connections (see Figure 2).
After sending a packet, IcmpSendEcho returns an echo reply.
A non-zero value indicates a request packet reached the target
host, but this doesn’t necessarily mean the host was success-
fully “pinged.” A value of zero indicates a failure, possibly
due to one or more factors such as a time out. We check the
Status field of the pEchoReply record, a pointer to the
pIcmpEchoReply record, to determine the state of the returned
packet. The pEchoReply^.Status function returns a value of Figure 4: NetCheck during a pinging session.
IP_SUCCESS to indicate a successful reply; any other value
indicates an error.
As Sonar receives a successful reply packet, it updates vari-
ables 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
NetCheck’s 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.
To test another host, you must enter a new string in the
edPingHost edit control. You could, of course, ease the pain Sonar onto the Winsock page of the Component palette. For
of retyping a host name by adding a TListBox to hold the more information on component installation, refer to
list of hosts in NetCheck. I leave this improvement (and Delphi’s online Help.
others) to you.
Conclusion
Installing NetCheck A growing need exists for networking applications to embed
To make NetCheck work on your machine, first install the some connectivity checks for network integrity. Therefore,
Sonar component. Use the SONAR.DCU unit to install Delphi developers should use a simple network debugger to
39 May 1997 Delphi Informant
On the Net
test their Internet applications and ensure their robustness.
procedure OnResolveEvent;
In Part II of this series, we’ll extend NetCheck’s capabilities procedure OnProgressEvent;
to include the complementary components to Sonar — function GetTTL : Byte;
EchoC and Trace. See you then. ∆ procedure SetTTL(ReqdTTL : Byte);
function GetPktSize : Word;
procedure SetPktSize(ReqdPktSize : Word);
References constructor Create(AOwner : TComponent); override;
Chapman, Davis, Building Internet Applications with Delphi destructor Destroy; override;
function CheckWS : Boolean;
2 [QUE, 1996]. function CheckICMP : Boolean;
Dumas, Arthur, Programming Winsock [SAMS, 1995]. procedure GetHost;
Quinn, Bob and Shute, David, Windows Sockets Network procedure DoSonar;virtual;
procedure Stats;virtual;
Programming [Addison-Wesley, 1996]. public
Stevens, W. Richard, UNIX Network Programming [PTR { Public declarations }
Prentice Hall, 1990]. property PingAvail : Boolean read FICMPAvail;
property Msg : string read FMsg;
Taylor, Don, et al., KickAss Delphi Programming, Chapters 4 property HostIP : string read FHostIP write FHostIP;
and 5 [Coriolis Group, 1996]. property Progress : LongInt
Verbruggen, Martien. Source code for the demonstration read FProgress write FProgress default 0;
property PktSize : Word
ping program is available on the Web from read GetPktSize write SetPktSize default PacketSize;
http://www.tcp.chem.tue.nl/~tgtcmv and property Version : string read FVersion;
http://www.delphi32.com/apps. property VersionDate : string read FVersionDate;
property Name : string read FComponentName;
property Developer : string read FDeveloper;
procedure Ping;
The files referenced in this article are available on the Delphi published
{ Published declarations }
Informant Works CD located in INFORM\97\MAY\DI9705JP. property HostName : string
read FHostName write FHostName;
property NoPackets : Word
read FNoPackets write FNoPackets default 5;
John Penman is the owner of Craiglockhart Software, a company specializing in property TimeOut : DWord
read FTimeOut write FTimeOut default 2000;
providing Internet and intranet software solutions. John can be reached on the property OnRecvData : TNotifyEvent
Internet at
[email protected]. read FOnRecvData write FOnRecvData;
property OnResolveData : TNotifyEvent
read FOnResolveData write FOnResolveData;
property OnProgress : TNotifyEvent
read FOnProgress write FOnProgress;
end;
Begin Listing One — The TSonar Class End Listing One
type
TSonar = class(TComponent) Begin Listing Two — The ICMP Unit
private unit ICMP;
{ Private declarations }
FParent : TComponent; interface
FStatusWS : Boolean;
FNoSent, FNoRecv, FNoEchoes, FMin, FMax, uses
FAve, FRTTSum : Word; Windows, WinSock;
FHostName : string;
FOnRecvData, FOnResolveData, FOnProgress : TNotifyEvent; type
FSocket : TSocket; { The following structures are required
FHwnd : THandle; for calling the ICMP.DLL }
FwMsg : Word; pIPOptions = ^TIPOptions;
FSockAddr : TSockAddr; TIPOptions = record
FSockAddrIn : TSockAddrIn; TTL : Byte;
FVersion, FVersionDate, TOS : Byte;
FComponentName, FDeveloper : string; Flags : Byte;
protected OptionsSize : Byte;
{ Protected declarations } OptionsData : PChar;
FICMPAvail, FICMPDone : Boolean; end;
FStatus : Integer;
FHostIP, FMsg : string; pIcmpEchoReply = ^TICMPEchoReply;
FProgress : LongInt; TICMPEchoReply = record
FAddress, FTimeOut : DWord; Address : DWord;
FOkay, FTrace : Boolean; Status : DWord;
FPktSize, NoPackets : Word; RTT : DWord;
FTTL : Byte; DataSize : Word;
FIPOptions : TIPOptions; Reserved : Word;
FPIPE : pIcmpEchoReply; Data : Pointer;
FHost : PHostent; Options : TIPOptions;
FProtocol : PProtoEnt; end;
procedure OnRecvDataEvent;
40 May 1997 Delphi Informant
On the Net
TIcmpCreateFile = function : THandle; stdcall; implementation
TIcmpCloseHandle = function (ICmpHandle : THandle) :
Boolean; stdcall; end.
TIcmpSendEcho = function (ICmpHandle : THandle;
DestAddress : DWord; RequestData : Pointer;
End Listing Two
RequestSize : Word; RequestOptions : pIPOptions;
ReplyBuffer : Pointer; ReplySize : DWord; Begin Listing Three — The TSonar.DoSonar Procedure
TimeOut : DWord) : DWord; stdcall; procedure TSonar.DoSonar;
var
const BufferSize, nPkts : Integer;
IP_ERROR_BASE = 11000; pReqData, pData : Pointer;
IP_SUCCESS = 0; pEchoReply : pIcmpEchoReply;
IP_BUF_TOO_SMALL = IP_ERROR_BASE; Count : Integer;
IP_DEST_NET_UNREACHABLE = IP_ERROR_BASE + 2; begin
IP_DEST_HOST_UNREACHABLE = IP_ERROR_BASE + 3; { Creating handles to ICMP.DLL's functions. }
IP_DEST_PROT_UNREACHABLE = IP_ERROR_BASE + 4; if hIcmpModule <> 0 then
IP_DEST_PORT_UNREACHABLE = IP_ERROR_BASE + 5; begin
IP_NO_RESOURCES = IP_ERROR_BASE + 6; @IcmpCreateFile :=
IP_BAD_OPTION = IP_ERROR_BASE + 7; GetProcAddress(hIcmpModule, 'IcmpCreateFile');
IP_HW_ERROR = IP_ERROR_BASE + 8; @IcmpCloseHandle :=
IP_PACKET_TOO_BIG = IP_ERROR_BASE + 9; GetProcAddress(hIcmpModule, 'IcmpCloseHandle');
IP_REQ_TIMED_OUT = IP_ERROR_BASE + 10; @IcmpSendEcho :=
IP_BAD_REQ = IP_ERROR_BASE + 11; GetProcAddress(hIcmpModule, 'IcmpSendEcho');
IP_BAD_ROUTE = IP_ERROR_BASE + 12; if (@IcmpCreateFile = nil) or
IP_TTL_EXPIRED_TRANSIT = IP_ERROR_BASE + 13; (@IcmpCloseHandle = nil) or
IP_TTL_EXPIRED_REASSEM = IP_ERROR_BASE + 14; (@IcmpSendEcho = nil) then
IP_PARAM_PROBLEM = IP_ERROR_BASE + 15; begin
IP_SOURCE_QUENCH = IP_ERROR_BASE + 16; MessageDlg(
IP_OPTION_TOO_BIG = IP_ERROR_BASE + 17; 'Error: can't get a handle to ICMP.DLL.’,
IP_BAD_DESTINATION = IP_ERROR_BASE + 18; mtError, [mbOk], 0);
// The next group is status codes passed up on status Exit;
// indications to transport layer protocols. end;
IP_ADDR_DELETED = IP_ERROR_BASE + 19; hIcmp := IcmpCreateFile;
IP_SPEC_MTU_CHANGE = IP_ERROR_BASE + 20; if hIcmp = INVALID_HANDLE_VALUE then
IP_MTU_CHANGE = IP_ERROR_BASE + 21; begin
IP_UNLOAD = IP_ERROR_BASE + 22; MessageDlg('Error: can't open file handle.',
IP_GENERAL_FAILURE = IP_ERROR_BASE + 50; mtError,[mbOk], 0);
MAX_IP_STATUS = IP_GENERAL_FAILURE; Exit;
IP_PENDING = IP_ERROR_BASE + 255; end;
BufferSize := SizeOf(TICMPEchoReply) + FPktSize;
// Values used in the IP header Flags field. { Prevent warning messages from the compiler. }
IP_FLAG_DF = $2; // Don’t fragment this packet. pEchoReply := nil;
// Supported IP Option Types. pReqData := nil;
// These types define the options that may be used pData := nil;
// in the OptionsData field of the try
// ip_option_information structure. GetMem(pReqData, FPktSize);
// See RFC 791 for a complete description of each. GetMem(pData, FPktSize);
IP_OPT_EOL = 0; // End of list option GetMem(pEchoReply, BufferSize);
IP_OPT_NOP = 1; // No operation FillChar(pReqData^, FPktSize, $AA);
IP_OPT_SECURITY = $82; // Security option pEchoReply^.Data := pData;
IP_OPT_LSRR = $83; // Loose source route FillChar(FIPOptions, SizeOf(FIPOptions), 0);
IP_OPT_SSRR = $89; // Strict source route FIPOptions.TTL := FTTL;
IP_OPT_RR = $7; // Record route FMin := 9999;
IP_OPT_TS = $44; // Timestamp FMax := 0;
IP_OPT_SID = $88; // Stream ID (obsolete) FAve := 0;
FNoEchoes := 0;
// Maximum length of IP options in bytes. FRTTSum := 0;
MAX_OPT_SIZE = 40; FOkay := True;
IP_TRACE = IP_TTL_EXPIRED_TRANSIT; { We loop and ping. Blocking can occur here. }
IP_REACHED = IP_SUCCESS; for Count := 1 to FNoPackets do begin
IP_TIMEOUT = IP_REQ_TIMED_OUT; MessageBeep(MB_OK);
ICMP_STATUS_BASE = $80000100; nPkts := IcmpSendEcho(hIcmp, FAddress, pReqData,
ICMP_INVALID = ICMP_STATUS_BASE + 0; FPktSize, @FIPOptions, pEchoReply,
ICMP_NO_ADDRESS = ICMP_STATUS_BASE + 1; BufferSize, FTimeOut);
ICMP_CANCEL = ICMP_STATUS_BASE + 3; FOkay := nPkts <> 0;
ICMP_BUSY = ICMP_STATUS_BASE + 4; try
MAX_TTL = 255; FProgress := (Count * 100) div FNoPackets;
MIN_PACKET_SIZE = 8; OnProgressEvent;
var except
IcmpSendEcho : TIcmpSendEcho; on EDivByZero do FProgress := 0;
wsaData : TWSAData; end; { try..except }
LibCount : Integer;
hIcmpModule : HModule; with pEchoReply^ do begin
IcmpCreateFile : TIcmpCreateFile; case Status of
IcmpCloseHandle : TIcmpCloseHandle; IP_SUCCESS :
hIcmp : THandle; begin
MessageBeep(MB_OK);
41 May 1997 Delphi Informant
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;
End Listing Three
42 May 1997 Delphi Informant
At Your Fingertips
Delphi / Object Pascal
By Robert Vivrette
Shell Games, etc.
Delphi Tips and Techniques
Adding a File to the procedure TForm1.Button1Click(Sender:
TObject);
Windows 95 Documents Menu begin
With the ever-growing popularity of SHAddToRecentDocs(
SHARD_PATH,PChar(
Windows 95 and Windows NT, many 'c:\My Documents\Resume.doc'));
Delphi developers are looking for better ways end;
to integrate their applications into the oper-
ating system. Delphi makes this easy with The first parameter, SHARD_PATH, indi-
the ShellAPI and ShlObj units. cates that the second parameter specifies a
path name to the recently-used document. In
One of the simplest things you can do is add this example, the second parameter is a
a recently-accessed file to the Documents pointer to a buffer that contains the file-
menu that is accessible from the Start menu name. After executing this call, there will be
in Windows 95 (see Figure 1). All that’s a reference to the Microsoft Word document
needed to add an entry to this menu is a Resume.doc in the Documents menu.
simple call to the SHAddToRecentDocs
function in the Win32 API. To use this pro- This technique is most useful in situations
cedure, you must of course add the ShlObj where the file has a registered association with
unit to your uses clause. A sample of how your Delphi application. That way, selecting
the routine is called is: 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.
Making Your Code
Processor-Speed Independent
Remember the early days of PC games? The
game ran great on your 8MHz IBM XT, but
later, when you got a faster machine, the
game ran so quickly it was unplayable.
Normally, we really don’t care if a program runs
more quickly. Faster is better, right? In some
cases, however, you may need to limit how
quickly a program or segment of code executes:
an arcade-style game, for example, where things
moving faster is not necessarily better.
Although there are a number of ways to do
this (some more complex than others), one
43 May 1997 Delphi Informant
At Your Fingertips
the control specified in
its FocusControl proper-
ty gets the focus when
the user hits that accel-
erator key.
For example, Figure 2
shows a ListBox com-
ponent with a Label
Figure 1: The Windows 95 Documents menu.
component above it;
the Label’s Caption is
simple way is to have the code take a little breather at reg- &House Inventory. By
ular intervals. The following code shows one technique for placing an ampersand
doing this: character in Caption,
the character following
PacingCount := GetTickCount; the ampersand becomes
repeat
the label’s accelerator
Application.ProcessMessages;
until (GetTickCount - PacingCounter) > 50; key, and is indicated as
such on the form by
First, a variable is created (PacingCount) to hold the result of being underlined.
a call to GetTickCount. This function retrieves the number of
milliseconds that have elapsed since Windows was started. Because a ListBox does-
n’t have its own Caption
Now, we go into a repeat..until loop until a new call to property, the Label
GetTickCount minus the saved value in PacingCount is serves that function. By
greater than some predetermined amount of milliseconds. specifying ListBox1 in
In this case, the application will stay in a loop until 50 the Label’s FocusControl
milliseconds have passed. property (see Figure 3),
the focus will shift to
Inside the loop we put an Application.ProcessMessages call to the list box when the
user hits AH H H (the Figure 3: Using the FocusControl
ensure other applications get some processor time. This call is
property of a Label component.
very important in a non-preemptive operating system such as “H” in House
Windows 3.x, where the application must surrender time for Inventory).
other applications to run.
In the event the list box needs to be disabled, it generally
In a preemptive environment, the operating system takes gives a clearer signal to the user if you disable the label as
control away from the application, so the well. That way, there is no confusion about whether the
Application.ProcessMessages call is not as critical. list box can obtain focus.
With this code, any machine will be guaranteed to stay in Remember that any TWinControl on a form can be chosen
the loop at least 50 milli- for a Label’s FocusControl property, not only list boxes! ∆
seconds (or whatever value
you determine). This will
have the effect of causing Robert Vivrette is a contract programmer for Pacific Gas & Electric, and Technical
faster machines to appear to Editor for Delphi Informant. He has worked as a game designer and computer
execute a section of code no consultant, and has experience in a number of programming languages. He can
faster than that of a slower be reached via e-mail at [email protected].
machine.
Tying Labels to List Boxes
One of the lesser-known
properties of a Label com-
ponent is the FocusControl
property. This property
links the Label’s control
with another control on the
form. If the Label’s caption Figure 2: An accelerator key
includes an accelerator key, in a Label.
44 May 1997 Delphi Informant
Case Study
By The EDD Development Team
California’s CalJOBS Project
Developing Cost-Effective Information Solutions
Using the Web
W ith an opportunity to revamp its job-matching system, the State of
California Employment Development Department (EDD) turned to
Borland’s Delphi, HREF Tools’ WebHub, Informix databases, and O’Reilly’s
WebSite Professional, to create an interactive, database-driven Web site,
known as CalJOBS (California Job Openings Browse System).
The CalJOBS Web site offers employers request for that information (drawn from a
and job seekers self-help options, and database), which would then be presented
includes the ability to maintain the user’s in a browser. If you wanted to further
identity throughout a session, provide define the search by entering your county,
complex drill-down queries, and increase the original information would then be
information-delivery speed with extreme drilled down to include only those jobs
modular scalability. offered in that county.
What the CalJOBS Project What Made This Possible?
Sought to Provide After looking at many different tools and
Initially, the site was established to offer an languages, the development team chose
integrated employer/job seeker job service two technologies that enabled them to create
to anyone with Internet access. The site a structured development framework. This
needed to allow employers to place and framework consisted primarily of Delphi
maintain job listings, and search the EDD’s and WebHub.
applicant pool for qualified applicants. Job
seekers also needed access to list their appli- With these tools, the team developed the ini-
cations or résumés with the EDD for tial site in approximately eight weeks. The
employers to view. They also needed the team united the employer and employee job
ability to directly apply for jobs. search features, connected the Web site to an
independent client-server relational database,
The CalJOBS Web site required more than and developed the applications necessary to
simple static information, because cus- perform each of the basic job search and
tomers accessing the site (job seekers or posting tasks. Delphi and WebHub gave
employers) would need to submit or them the solutions needed to create a Web
retrieve specific information, tailored to site, with the capacity to expand.
their needs. CalJOBS needed to be con-
nected to a searchable, amendable database, WebHub addressed many issues, including:
and it needed to generate dynamic, user- ■ Server-side Surfer Tracking. The EDD’s
specific pages to match users’ requests. For first prototype attempts used client-side
example, if you wanted a list of available tracking of user data, but it was limited.
construction jobs, you could make a Then, in late 1995, the team found
45 May 1997 Delphi Informant
Case Study
Application Profile ■ Division of Labor. WebHub provides an
ideal development environment, because
it allows separating the HTML from the
The CalJOBS site unites employers and job seekers to exchange information about job openings and qualifi- SQL code. Development tasks could be
cations. The system also handles the administrative tasks of submitting completed job applications to inter- divided amongst staff, and, unlike other
ested employers. Web application tools that embed SQL
code within the HTML document,
Third-Party Products: Informix, O’Reilly’s WebSite Professional, and HREF Tool’s WebHub. WebHub keeps the HTML in separate
files, which are collected at run time.
Informix Software O’Reilly & Associates, Inc. HREF Tools Corp.
4100 Bohannon Dr. Software Products 300 B St. Pilot Period (January 1997 to October
Menlo Park, CA 94025 101 Morris St. Santa Rosa, CA 95401 1997). The pilot program will provide auto-
Phone: (415) 926-6300 Sebastopol, CA 95472 Phone: (707) 542-0844 mated employment services for job seekers
Web Site: http://www.informix.com Phone: (707) 829-0515 Web Site: and employers by introducing a full range of
Web Site: http://www.href.com employment opportunities. EDD offices in
http://www.ora.com eight counties will participate in the pilot:
Butte, Kern, Los Angeles, Placer, Sacramento,
WebHub — which (at that time) was unique in provid- San Bernardino, San Mateo and Ventura.
ing a built-in, server-side saving state. This prevents the Access to CalJOBS will be restricted to employers and job
user from providing the same information multiple times. seekers in the eight pilot counties. The EDD will only
■ Distributed Processing. WebHub’s architecture provided allow access in the eight counties to partner organizations
the team with a scalable solution that reduced required such as Private Industry Council offices, Service Delivery
computing resources, and improved the speed at which Area offices, community colleges, and the county welfare
information was delivered to the customer. The Hub department offices.
distributes page requests to the least busy instance of the
program. CalJOBS uses a “cluster” of two Web servers, The Significance of This Project for California. The
which further distributes processing to multiple CalJOBS project not only marks the successful implemen-
instances of the application for optimal performance of tation of cutting-edge technology, it also sets the standard
the transactions to a database server. for high-quality, cost-effective government service pro-
■ Multiple Open Queries. WebHub database publishing grams. Using Delphi and WebHub, the EDD merged
components simplified the process of providing quick desktop computing, allowing people to access database
response via queries over the Web. Users are given a information easier than they could from their personal
specified number of records in response to a query; computers. ∆
WebHub keeps the answer available, enabling quick
forward and backward scrolling.
■ Database Independence. Database security and integri-
ty is maintained by allowing it to operate independent- The EDD is a California State agency dedicated to providing California resi-
ly from the Internet application, and implementing a dents with job services at all levels, while promoting the development of new
captive browser using ActiveX technology. Delphi fields and encouraging employment opportunities throughout the state. For
more information about the EDD CalJOBS project, contact Jesse Odell at
allows the application to communicate with key client-
[email protected] or (707) 575-4543.
server relational databases (CalJOBS uses Informix).
46 May 1997 Delphi Informant
New & Used
By Robin Karlin
Component Developer Kit 2.0
A Dream Tool for Component Builders
D o you go to sleep at night thinking about all the wonderful Delphi com-
ponents you could build with some extra time and expertise? Perhaps
you’d 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 con-
trol that displays negative numbers in red? Maybe a TStringGrid that sorts
itself on any column when you click on that column’s header ...
Maybe you’ve created components, but still learn the ins and outs of component construc-
have many questions about the process. tion. This “wizard-driven” tool provides step-
Have you wondered when you must over- by-step instruction through the component
ride the Loaded procedure? How to test if development process, and generates Delphi
your code is called at run or design time? code with comments showing you where
What the Notification method is used for? changes are needed.
Or if there’s a way to hide an inherited pub-
lished property in a descendant component? Using CDK
The CDK installs easily, and seamlessly inte-
The Component Developer Kit version 2.0 grates with Delphi. It adds the following
(CDK) from Eagle Software can help you options to the Component menu: Modify,
build the components described above, and 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 Delphi’s
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
aren’t a component type). Figure 1 shows the
first screen in the CDK.
While some dialog boxes are specific to each
of these options, the main CDK interface is
a tabbed notebook (see Figure 2). Using
information you enter in the notebook, the
CDK generates declarations and skeleton
Figure 1: Welcome to the CDK. code. Of course, you must understand
47 May 1997 Delphi Informant
New & Used
specifying name and class information,
paste your super component into the
waiting screen.
In the Inherited page of the tabbed note-
book (again, see Figure 2), you must speci-
fy which properties and events of the sub-
components and container component to
publish in your super component. Be care-
ful you don’t expose two properties with
the same name. Fortunately, the CDK
makes this tedious job much easier. It can
generate unique names for you, and allows
you to rename
individual properties.
When the CDK generates the super com-
ponent code, the CDK_Container becomes
a TCompoundComponentPanel, the parent
and owner of the sub-components. The
Figure 2: The CDK’s main interface is a tabbed notebook.
CDK code initializes private properties, and
provides for communication between com-
enough about component creation to know which properties, ponents when handling events.
methods, events, editors, etc. you’ll need.
Descending Components. To create a component that adds
Fortunately, the CDK’s interface, the generously com- functionality to an existing one, select the Descending
mented code it produces, and its clear manual do an excel- Component option. The descending component will inherit the
lent job of guiding you through the component creation properties and methods of an existing component, and add new
process. After you have completed the information in the properties and methods, or override virtual methods in an
notebook and the Palette Image editor, the CDK previews ancestor class.
it in a read-only window. To change something, you can
back up as far as you want. Finally, you can choose If you know which component you want to descend from,
whether to have the CDK build a test program, then press you can select it from a combo box listing all the components
the Finish button. in your VCL. If you’re unsure, click on the I Need Help
Deciding radio button. The CDK presents a colorful flowchart
Super Components. Without the CDK, building compound (see Figure 3) that walks you through the available classes by
components is arduous. With the CDK, this task becomes asking questions such as, “Will this component be visible at
much easier, although you must still keep track of many runtime?” and “Is there a similar VCL Component that
details. To help you learn about creating compound compo- already exists?”
nents, the CDK manual has step-by-step instructions for
creating a “Super” component. It consists of three Business Components. Delphi’s RAD model does not
buttons (OK, Cancel, and Help) that align to the top right encourage developers to build three-tier applications. The
corner of your form. RAD “path of least resistance” is to place business rules into
the form unit. The unfortunate result of doing this is that
The first step in creating a super component is to visually business code becomes difficult to maintain and impossible
design it in Delphi. Start by selecting the CDK_Container to reuse.
component from the CDK tab on the Component
palette and dropping it on a blank form. Then, place your Delphi 2 adds data modules that are supposed to be used
sub-components in the CDK_Container. Make adjust- as a middle tier. Business components, together with data
ments until you’re satisfied with the super component’s modules, provide an even better solution to this problem.
visual design. (The business components can and probably should be
located in a data module in your project.) They provide a
Next, select the container component and copy it to the business rules layer that’s separate from the UI and data-
Clipboard. To include non-visual components, place them access layers. The advantage of this separation is that the
on the form outside the CDK_Container. To copy visual business component can be reused independently of the
and non-visual components to the Clipboard, click on the UI and the data access for any particular form or applica-
container to select it, then V-click to select the non- tion. Because business components are data-aware, you
visual components. Now you can select Component | New can still take advantage of the native Delphi data controls.
to start the CDK, and choose Super Component. After The business components generated by the CDK descend
48 May 1997 Delphi Informant
New & Used
Component option enables you to
convert any Delphi form into a non-
visual component. The Dialog
Encapsulation Options screen
requests the name of the form and the
name of the execution method (the
default is Execute).
The CDK provides two Method tem-
plates for building read/write or read-
only data-aware components. Let’s say
you want to create a data-aware but-
ton with its Enabled property con-
trolled 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 button’s
Enabled property to True, if the data
Figure 3: This flowchart helps you pick a descendant. field contains the word “charge.” A
more useful version of the button
from a pre-defined business component class developed by would have a string property indicating which value (in the
Ray Konopka. They are described in chapter 13 of his database) enables it.
book, Developing Custom Delphi Components [Coriolis
Group Books, 1996]. Embedded Components. Using the main tabbed notebook,
you can embed components in any component you’re build-
The CDK automates the process of creating business compo- ing. The difference between super and embedded compo-
nents. After you select the Business Component option, you’re nents is that the latter do not require a CDK_Container.
presented with the following: Embedded components are owned by your original compo-
■ The Business Component - Field Selector screen allows you nent, and will be children of it, if they have a Parent property.
to specify a database, a table, and the fields to include in This is especially useful for embedding non-visual compo-
your business component. nents in a visual component. The example in the CDK man-
■ The Business Component - New Fields screen enables you ual is a rotating Label that’s converted into a Clock by adding
to specify any new calculated fields to create. (It would be
nice if you could also specify new lookup fields, but you
must add that programmatically.) procedure TDBButton.DataChange(Sender: TObject);
{ Triggered when data changes in DataSource. }
■ Finally, the Business Component - Field Options screen begin
allows you to select from the following options (where if FFieldDataLink.Field = nil then
applicable) for each field: Alignment, Min Value, Max Value, begin
{ CDK: Update your control to show there is no
Edit Mask, Currency, Invisible, Read-Only, Required, and data link (optional). For example, if your
Validate. control has a Caption property, you might use
the following line:
When you’re finished creating your business component, you Caption := '*No Data Link*';
can drop it on a form (or better yet, a data module), and you }
exit;
have an OOP middle tier that uses a TTable or TQuery to end;
access the back 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:
Eagle Software and Ray Konopka have just released a new
version of the business component that’s available (free to CalendarDate := FFieldDataLink.Field.AsDateTime;
existing customers) on Eagle’s Web site. When installed, the
Other ways to look at data:
Business Component Wizard automatically integrates into AsBoolean
the CDK. Some features of this new version are the ability AsDateTime
to embed business components within other business com- AsFloat
...
ponents, and to link business components. The new version }
will also work with descendants of TTable and TQuery, such end;
as InfoPower’s TwwTable or TwwQuery.
Dialog and Data-Aware Components. The Dialog Figure 4: CDK generates plenty of helpful comments.
49 May 1997 Delphi Informant
New & Used
template that adds code to set minimum and maximum sizes
procedure TDBButton.DataChange(Sender: TObject); for a resizeable form. This code prevents the user from resizing
{ Triggered when data changes in DataSource. }
begin
a form below the minimum size or above the maximum size.
if FFieldDataLink.Field = nil then
begin A Smart template is a .DLL, and the CDK generates all the
{ If there's no data link we won't do anything. }
exit;
code to create it. You programmatically connect any values that
end; the user enters to variables you define. Then, you can use those
{ This will enable our button when the current string values in the code that you cause the CDK to generate.
data field contains the word charge. The button
will bring up a page of charge information. }
Enabled := FFieldDataLink.Field.AsString = 'Charge'; Component and Property Editors
end; Component editors provide a design-time interface for your
components when you right- or double-click on them. This
Figure 5: Altering the Enabled property of a Button object.
interface can be used to add functionality beyond what’s avail-
able in the Object Inspector, or to make existing functionality
a Timer component to the original Label class. The Timer more accessible. Delphi books usually consider component edi-
event is used to update the clock label. tors an advanced topic. The CDK makes it very easy to add
your own component editors to the components you create.
Method Templates
The CDK ships with many Method templates that provide Property editors provide a design-time interface for editing
common functionality for your components or other classes. component property values. This is another advanced task that
Templates can be used with any class, including forms. the CDK makes easier. However, you must understand how
Thus, they can be used to add common functionality to any property editors work to successfully create one with the CDK.
application code. You will have to carefully study the generated code to see what
you must change. As usual, the CDK provides plenty of help,
The CDK’s Keypress Filter, Component Link Handler, as well as “Mr. CDK” Advice dialog boxes.
Runtime Drag, and Method Override templates are Smart
templates. A Smart template displays dialog boxes allowing Modifying Existing Components
you to customize the template code before it’s generated. For This is the CDK’s one weak area. The CDK allows you to mod-
example, when adding the Keypress Filter template to your ify existing components (as opposed to creating a descending
component, a dialog box requests information about what component class). This is useful when you have created a com-
numbers, letters, and punctuation to allow. This reduces the ponent, then realize you want to add or subtract functionality.
amount of custom code you must write. Component creation, such as application coding, works best as
an iterative process. The Component | Modify command allows
Get Smart you to expose or hide properties and events that you have not
If you are not yet completely impressed by the CDK, read on. previously modified, and to add new components on-the-fly.
Today’s software standards demand that a first-class tool be
extensible. The CDK meets that criterion with its Smart The weakness arises because the CDK doesn’t display your pre-
template generation facility. vious work, or allow you to modify it. Properties and events
you have exposed or hidden don’t appear in the Modify dialog
When you select the Smart Template option, a CDK “wizard” box. In a warning, Mr. CDK explains: “The CDK does not
leads you through the steps for generating a Smart template (see perform a deep scan of the code you are modifying and there-
Figure 6). The SDK’s manual shows how to generate a Smart fore doesn’t know which sub-component events and properties
you’ve already published. This also means that if you try to re-
expose a property or event that is already exposed in the code,
the CDK will let you.” The suggested solution is to be familiar
with your code to avoid mistakes.
The CDK Component Browser
The CDK Component Browser is a tabbed notebook that
helps you investigate Delphi’s class hierarchy and the struc-
ture of individual classes (see Figure 7). The Properties page
provides information about the implementation of each
property, including whether it uses procedural access speci-
fiers, has a default value, etc. The Events page displays the
declaration of each event type.
The Virtual Methods page shows the inherited virtual meth-
Figure 6: The Method Template Options dialog box. ods for components that are part of the Delphi 2 VCL. It
50 May 1997 Delphi Informant
New & Used
In addition to the
CDK_Container men-
tioned, the CDK ships with
24 other components, some
of which are quite useful.
The highlights are: the The Component Developer Kit version 2.0
from Eagle Software assists developers in
CDKAnimation compo- building Delphi components. This product
nent, which animates a installs easily and integrates seamlessly
series of bitmaps specified into Delphi. Those using the CDK must
have rudimentary knowledge of compo-
by the user; the CDKLight, nent creation; however, the CDK interface,
which displays an “LED” the generously commented code it pro-
light in different colors, duces, and the well-written manual are
excellent guides through the component
with an “on” or “off ” state; creation process. The CDK fully supports
and the CDKCheckList, a 16- and 32-bit components within Delphi,
list box with check boxes and comes with an evaluation copy of
reAct for Delphi 2.0, a component tester
Figure 7: The CDK Component Browser showing properties next to each item. and debugger. The CDK also comes with 25
information for the TBitBtn control. VCL components. The CDK will be an excel-
Conclusion lent addition to your suite of third-party
Delphi development tools.
displays the declaration of each virtual method and a refer- The Component
ence to the component that first declares the method. The Developer Kit version 2.0 Eagle Software
12021 Wilshire Blvd., Ste. 655
Lineage page depicts the entire ancestry of all the compo- makes component-building Los Angeles, CA 90025
nents in the VCL, including new ones (a handy feature that’s faster and less tedious for
Phone: (310) 441-4096
missing from Delphi’s Browser). novice and experienced Fax: (310) 441-1996
developers. It’s also a valu- Web Site: http://www.eagle-software.com
The interface of the CDK Component Browser is more able tool for learning about Price: US$279, with a 60-day, money-
back guarantee.
straightforward than Delphi’s, and it provides some informa- the nuts and bolts of com-
tion that you must otherwise search the VCL source files to ponent building. The
find. However, it does not replace the functionality of the CDK manual is clearly
Delphi Browser. This is because CDK’s Component Browser written, with plenty of illustrations and tutorials; especially
doesn’t include information from the private and protected useful are tips identified with a small Mr. CDK graphic.
sections of your components, or new virtual methods
declared in your new components. Other Eagle Software products, including a professional
programmer’s editor and a free upgrade of the CDK (to
But Wait, There’s More existing customers) to compile under Delphi 3, are in the
The CDK ships with an evaluation copy of reAct for Delphi works. Try the CDK. It will help your late-night compo-
2.0, a component testing tool. This limited version tests up nent “fantasies” become reality. ∆
to 10 properties and five events. reAct is a useful tool for test-
ing your new components, standard Delphi components, and
third-party components. reAct is worthwhile even for the
experienced developer, because it transforms testing from
drudgery to an easy, even enjoyable, task. Robin Karlin is a Senior Software Developer at PCSI, a leading client/server and
Internet/intranet consulting and development firm. She is a Borland Certified
Developer, and specializes in component design and object-oriented programming
solutions. She can be reached at (201) 816-8002 or by e-mail at
[email protected].
51 May 1997 Delphi Informant
Delphi Reports
Delphi 1 / Delphi 2 / ReportSmith
By Chris McNeil
Full Report Control
Building a Custom ReportSmith Component
A re we there yet? With the advent of modern travel, virtually all desti-
nations 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 rigma-
role 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.
Typically, an application with printing restored (non-minimized) state and loads
capabilities will also provide a means of the report. Then, you can either navigate
setting the print destination. However, through the report or print it. Printing can
when using a ReportSmith report within a be directed to specific printers by selecting
Delphi application, the ReportSmith File | Print Setup from the menu. This com-
Runtime Viewer formats the report and mand displays the Print Setup dialog box
ultimately sends the report to the printer, and allows you to select any Windows-
while the Delphi application handles the installed printer. Note that this is possible
user interaction. because the Runtime Viewer is the active
application and is issuing the print com-
ReportSmith Implementation under mands to Windows.
Delphi
Borland’s implementation of ReportSmith If, however, the Preview property is False
under Delphi is the Report component (its and you execute the Run (or Print) method
properties are listed in Figure 1). It encap- of the Report object, ReportSmith starts
sulates the DDE communication between minimized, loads and formats the request-
the Delphi application and ReportSmith, ed report, then prints the report automati-
so you can: cally. Notice, however, that you never get
■ load ReportSmith, an opportunity to establish the print desti-
■ open an existing report (ReportSmith nation. Therefore, ReportSmith has no
reports have an .RPT extension), and alternative but to print to the Windows
■ preview the report on screen (the value of default printer.
the Preview property is True), or
■ print the report while ReportSmith remains Is There an Alternative?
minimized (the value of Preview is False). Inspection of the TReport class source code
(the file name is REPORT.PAS) shows that a
In preview mode, the Report object starts method named Print is executed when
the ReportSmith Runtime Viewer in a Preview is False. This assumes that
52 May 1997 Delphi Informant
Delphi Reports
Property Description Notice that Borland continues to leave the printer
information nil, which still forces ReportSmith to
AutoUnload Determines whether ReportSmith Runtime unloads from
print to the Windows default printer.
memory when you have finished running a report.
EndPage Specifies the last page of the report. The default value is
We can change all that!
9999; if the report is fewer than 9999 pages and you
don’t change the value of EndPage, your entire report is
printed. The TRptSmith Component
InitialValues List of report variable strings the specified report requires Armed with this information, I set out to create a
to run. By specifying these initial values, your application TReport descendent that would print to any printer
can bypass the dialog boxes that prompt you for these defined to Windows. The only method that must
values when the report runs. be overridden in TReport is Print. It’s a public
Preview Determines whether a report should be viewed on method; however, it’s not declared as dynamic or
screen or printed. If Preview is True, the report appears virtual, so it cannot be overridden.
on screen when the report is run. If Preview is False, the
report is printed.
This leaves us with two choices for replacing
PrintCopies Determines how many copies of the report will print
when you run a report. The default value is 1. Print’s functionality. One: We can duplicate the
function name in our descendent object, effective-
ReportDir The directory where ReportSmith expects to find saved
reports. By specifying a report directory, you won’t have ly hiding the ancestor implementation. This would
to include a path when specifying a report name. also require us to duplicate every other static
ReportName Determines which report you want to run. You can method that calls Print and every static method
include a full path name as part of the report name if that calls those methods, and so on. Conceivably,
you have not specified a ReportDir property value or we could end up with a complete copy of TReport
want to run a report that is stored elsewhere. If you have under a new name. This solution isn’t possible,
specified a ReportDir value, omit the path name and
because it provides too much source code that isn’t
simply specify the name of the report.
in the public domain.
StartPage Determines the page from which you want the report to
start printing. The default value is 1, indicating the first
page. You can change that value to begin printing the Two: The alternative is to modify the existing
report on some other page. TReport and make Print a virtual method by
Figure 1: Common properties associated with a TReport object. adding the virtual directive:
ReportSmith and the requested report have been successfully function Print: Boolean; virtual; { Delphi 1 }
loaded. Depending on the version of Delphi you have, the function Print: Integer; virtual; { Delphi 2 }
Print method interacts with ReportSmith in different ways.
If you don’t have the original source code, the modified
Delphi 1 Implementation. Under Delphi 1, the TReport.Print REPORT.DCU files for Delphi 1 and 2 are available for
method issues the following ReportBasic macro to ReportSmith: download (see end of article for details). Before proceeding,
however, be aware that this implementation requires a minor
PrintReport StartPage$, EndPage$, "Printer$",
"Port$", "Driver$", Copies$ change to the VCL.
Notice that this command does support the Printer$, Port$, There is a further, special consideration for Delphi 2. The
and Driver$ parameters. However, the ReportSmith Help file ReportSmith API is implemented using a Windows .DLL
states: “To use the default printer, use null strings for the that is loaded explicitly using the Windows API function,
Printer$, Port$, and Driver$ arguments.” Because a Report LoadLibrary. Internally to TReport, Borland has defined
object doesn’t have properties to support printer information, the ReportSmith API as local variable references to func-
the Print method simply issues: tions in the .DLL. This means that descendent objects have
no way to call these functions directly.
PrintReport 1, 9999, "", "", "", 1
To circumvent this shortcoming, I created a new protected
Delphi 2 Implementation. Under Delphi 2, Borland signifi- method named PrintTo. Protected methods have the benefit
cantly updated the interface to ReportSmith by writing a new of being visible to descendent objects. The PrintTo method is
ReportSmith API that dodges some pitfalls of the DDE. declared as follows:
Borland has replaced most of the DDE communication with
calls to their new ReportSmith API. One of the functions of function PrintTo(ADevice, APort, ADriver: string): Integer;
this API is RS_PrintReport; its parameters match the
PrintReport macro exactly. Therefore, the TReport.Print Figure 2 shows the implementation of PrintTo. It’s func-
method executes this function: tionally equivalent to Print, except it allows printer infor-
mation to be passed in. In addition, it can call
{ Assuming default property values }
RS_PrintReport. It would have been possible to call the
RS_PrintReport(1, 9999, nil, nil, nil, 1)
53 May 1997 Delphi Informant
Delphi Reports
function TReport.PrintTo( Property Description
ADevice, APort, ADriver: string): Integer;
begin Canvas Represents the surface of the currently
if not Busy then printing page.
Result := RS_PrintReport( Orientation Determines if the print job prints vertically
StartPage, EndPage,
or horizontally on a page. The possible
PChar(ADevice), { Requires a PChar }
values are: poPortrait and poLandscape.
PChar(APort), { Requires a PChar }
PChar(ADriver), { Requires a PChar } PrinterIndex Specifies which printer listed in the Printers
PrintCopies) property is the currently selected printer. To
else select the default printer, set the value of
Result := RS_BUSY; PrinterIndex to -1.
end;
Printers List of all printers installed in Windows.
Figure 2: TReport.PrintTo is the new protected method of Delphi Title Determines the text that appears in the Print
2 required to call RS_PrintReport. Manager and on network header pages for
the current print job.
RunMacro method using the PrintReport macro (similar to Figure 3: Common properties associated with a TPrinter object.
the Delphi 1 implementation). However, I speculate that
Borland updated the interface for a reason, so I chose to Method Description
stay with their approach.
BeginDoc Sends a print job to the printer. If the print
job is sent successfully, the application
Using the modified TReport, we can declare our new compo- should call EndDoc to end the print job.
nent as follows: Printing won’t start until EndDoc is called.
EndDoc Ends the current print job and closes the text
type file variable. After the application calls
TRptSmith = class(TReport) EndDoc, the printer begins printing. Use
public EndDoc after successfully sending a print job
constructor Create(AOwner: TComponent); override; to the printer.
destructor Destroy; override; GetPrinter Retrieves the current printer.
{$ifdef WIN32}
NewPage Forces current print job to begin printing on
function Print: Integer; override; { Delphi 2 }
a new page.
{$else}
function Print: Boolean; override; { Delphi 1 } SetPrinter Specifies the current printer.
{$endif}
end; Figure 4: Commonly-used TPrinter methods.
The Printer Object ■ device name
Before getting into the details of the TRptSmith Print ■ port
method, let’s look at how Delphi manages printer infor- ■ driver
mation. Delphi defines a global object named Printer that ■ printer handle
is of type TPrinter. This object is accessible by including
the Printers unit in a uses statement. The TPrinter object Do any of these look familiar? We can directly use the first
contains information about all the printers currently three of these parameters in our component. The code for
defined to Windows. It gleans this information by using the TRptSmith component is available for download (see end
WIN.INI or the Registry. The table in Figure 3 lists com- of article for details). Note that there are two versions condi-
monly used properties of TPrinter; the table in Figure 4 tionally compiled into the VCL, depending on your version
lists its commonly used methods. of Delphi. In both instances, it calls the TPrinter.GetPrinter
method to retrieve information about the currently selected
Normally, TPrinter is used to manually print information printer, and passes this information to ReportSmith.
directly to a specific printer using the BeginDoc and
EndDoc methods and the Canvas property. In addition, by I have provided a sample Delphi application that allows you
dropping a TPrintSetupDialog component on your form, to select any report on your system, as well as any printer
you enable your application to have instant access to a defined to your system. When you press the Run Report but-
facility to change the currently selected printer for your ton, RS_RunTime is started, and the report is printed to the
application. Any print commands issued through TPrinter requested destination. The rest of the TReport methods and
would then print to the new destination. This frees us properties are unchanged and work as expected. Figure 5
from a lot of hassle over print control. shows RS_RunTime displaying the Print To File dialog box.
Figure 6 shows RS_RunTime about to fax a report (by
Even if you don’t need to print directly from Delphi, the selecting a WinFax print driver). Of course, you can select a
TPrinter object can provide valuable information about physical printer as well.
the currently selected printer. The method that we’re inter-
ested in is named GetPrinter. It returns the following One interesting note about Delphi 2 is that the print driver is
information about the currently selected printer: not returned by GetPrinter. It seems that the Win32 API doesn’t
54 May 1997 Delphi Informant
Delphi Reports
require this parameter. In fact, by pass-
ing 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 implementa-
tion isn’t perfect, because it relies on
an external object, TPrinter, to pro-
vide several significant pieces of infor-
mation. However, given the nature of
the TPrinter object, it’s doubtful that
its external interface will change sig-
nificantly. It also modifies the VCL
source which can be problematic.
With a little care, however, this tech-
nique provides a simple and function-
al implementation of print destina-
tion capabilities for the Report com-
ponent. ∆
The files referenced in this article are
available on the Delphi Informant
Works CD located in
INFORM\97\MAY\DI9705CM.
Chris A. McNeil is an independent software developer
in Louisville, KY specializing in Delphi and Paradox
for Windows database solutions. You can reach Chris
on CompuServe at 72734,2270.
Figure 5: The Report Test Form with the Port set to FILE:. Below is the result generat-
ed by ReportSmith.
Figure 6: The Report Test form has the Port set to COM3. Below is the result generated
by ReportSmith.
55 May 1997 Delphi Informant
TextFile
Delphi Programming Problem Solver
Neil Rubenking’s Delphi cusses database program- with problems that can’t be
Programming Problem Solver ming — display issues more resolved within the confines
has created quite a buzz than anything else. of the VCL, Rubenking
since it appeared, but I However, there’s no better either grabs a Windows
think not nearly enough. book on using the Windows message, or derives a new
While it’s possible to look at API and messaging system component that responds to
this book as just a collection from Delphi. messages its ancestor
of solutions to common doesn’t. He uses API calls
problems, I tend to view it Although only a 28-page constantly. In short, Solver is
more as a short course in chapter on messaging and a the most compact tutorial
Windows programming. 39-page chapter on the API on Windows programming
These are my favorite books are listed in the table of I’ve seen.
— the ones that pop the contents, they’re dealt with
hood and tinker around in every chapter. The reader Rubenking assumes his stand than others, but after
with the engine. is grabbed early and thrown readers are competent pro- presenting them, Rubenking
into the volcano. Not three grammers with years of comes back with short
A lot of people call them- pages into Solver, a proce- Windows experience. What
“Delphi Programming Problem Solver”
selves Windows program- dure is presented to respond a refreshing approach. Some continued on page 57
mers. Since the first appear- to WM_NCHITTEST! of the program samples took
ance of Microsoft Visual Mostly concerning himself me a little longer to under-
Basic, people with no clue
about Windows’ underlying
Programming Delphi Custom Components
structure have been writing While some early Delphi reader’s level as
Windows programs — some books contained an obligato- “Intermediate/Advanced.”
of them decent, some of ry chapter on component Bulback accurately articulates
them not — and being well writing, it took quite a while the prerequisites in the intro-
paid for their efforts. Delphi for the first book dedicated duction as being for those
helped accelerate that trend. to this important topic to “somewhat familiar with the
Usually, I think this is a appear. That book, Ray Pascal programming language”
great advancement, until I Konopka’s Developing Custom and having “at least a basic
install some of their soft- Delphi Components [Coriolis understanding of the Delphi
ware. The real problem isn’t Group Books, 1996], became environment.” What level
with programmers who an instant hit, and is now does that sound like to you?
write things within the con- considered a classic by many
Furthermore, he includes
fines of the systems they (see Richard Wagner’s Also at issue is the nature of
topics that are often omitted,
use. The problem is with insightful review in the June, the introduction. Entitled
such as the function of ini-
developers who try to do 1996 Delphi Informant). “Introduction to Delphi,”
tialization and finalization
things more intricate than this 52-page chapter spends
sections, and using array
their development environ- Fred Bulback’s Programming too much time covering fun-
properties. Still, I prefer a
ments allow. Delphi Custom Components damental topics, such as the
more focused discourse.
was published not long after- nature of properties and
They need this book. There wards. While my impression Delphi’s relationship to other
Following this introduction,
are better books on the of Programming is largely posi- programming languages. In
Bulback gets to the business
IDE, and certainly better tive, there are certain aspects I fairness, the author discusses
books on database program- take issue with. First, the pub- these topics in an interesting “Programming Delphi
Custom Components”
ming; only one chapter dis- lisher categorizes the target and insightful manner. continued on page 57
56 May 1997 Delphi Informant
TextFile
Delphi Programming Problem Solver (cont.)
explanations of some of the Nearly every programming Computer books are never Windows messaging,
trickier elements. Like a problem includes a full perfect, and Solver is defi- Delphi Programming
good teacher, he knows code solution in the text. I nitely a computer book. Problem Solver is for you.
what to emphasize and what know that when compan- Other than one figure
to let us figure out on our ion disks contain complete duplicated from chapter — Richard A. Porter
own. In particular, in the source code (as is the case two to chapter six, however,
last chapter — a great .DLL here) many people prefer to the mistakes aren’t worth Delphi Programming
primer — we are frequently see only code fragments in mentioning. What is worth Problem Solver by Neil
reminded to use types com- the text, but I’ve always mentioning repeatedly is Rubenking. IDG Books,
mon to most languages for preferred it in front of me. how much you need this 919 E. Hillsdale Blvd., Ste.
.DLL function returns. Often, a solution consists book. Whether you’re a 400, Foster City, CA 94404,
of one long code listing casual programmer who (800) 762-2974.
Solver is broken into five with two or three short, yet needs to figure out a few
sections, and the chapters telling, remarks. Some problems, or an experienced ISBN: 1-56884-795-5
in those sections are filled readers might disagree, but developer who needs a Price: US$34.00
with program examples. this style is perfect for me. quick refresher on 574 pages, Diskette
Programming Delphi Custom Components (cont.)
of creating new components. Another interesting compo- knowledge and skill in one of the component areas
Here the value of nent, TComm, provides working with Windows discussed. However, I think
Programming becomes access to basic serial commu- graphics. If you’re new to this is an excellent intro-
apparent. Beginning with nications functions, such as this, you’ll gain valuable duction to the topic for the
the simplest of non-visual opening and closing the experience working with Delphi programmer new to
components, the author COM port, setting configu- TCanvas, brushes, pens, and component writing. The
introduces increasingly more ration options (baud rate, other graphics elements. detailed, basic information
complex components. Not parity checking, etc.), and included throughout
counting the trivial compo- transmitting data. TComm is The book concludes with a Programming Delphi
nent with which he begins, basic; you’ll need to add chapter on property and Custom Components will be
Bulback introduces seven functionality and perhaps component editors. particularly helpful and
components: a WIN.INI file additional components for However, if you are an expe- appropriate for the less-
watcher, a serial communi- most actual communications rienced component writer experienced programmer.
cations component, a cus- applications. To his credit, and are looking for more
tom About box, an LED Bulback provides an excel- information on these last — Alan C. Moore, Ph.D.
gauge, a check grid, a color- lent conceptual framework two topics, I recommend
selection combo box, and a and foundation on which to Ray Lischner’s Secrets of
Programming Delphi
printer component. build, and even points out Delphi 2 [Waite Group
Custom Components by Fred
where the shortcomings lie. Press, 1996] because of its
Bulback. M&T Books,
TWinIni is a simple, non-visu- greater depth and detail.
4375 West 1980 South,
al component that watches for I found the printing compo-
Salt Lake City, UT 84104,
and reports changes to nent particularly interesting. Which Delphi developers
(800) 488-5233.
WIN.INI using the The print preview capability are likely to benefit from
WM_WININICHANGE mes- of this component is attrac- Programming? I can’t rec-
sage. It demonstrates how to tive and useful. With this ommend it to advanced ISBN: 1-55851-457-0
create and use Delphi events, and other components, Delphi developers unless Price: US$39.95
specifically TNotifyEvent. Bulback demonstrates his they have a special need in 420 pages, CD-ROM
57 May 1997 Delphi Informant
File | New
Directions / Commentary
Goliath Lives
T he release of Delphi 3 gives us an opportunity to look at the brief history of Borland’s 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 dom-
inate the Windows client/server development tool market. That didn’t happen.
The good news for Delphi developers reason to do so given the release of Windows programming easier.
in 1997 is that the tool has legit- Delphi’s sister product, C++Builder. Second, Borland must continue to
imized itself and gained strong mar- In fact, I suspect many C++ devel- enhance Delphi’s database access. I’ve
ket acceptance. If we’re honest, how- opers who switched to Delphi will long thought of the BDE as the
ever, we must also admit that it’s not likely spend an increasing amount Achilles’ heel of Delphi. By and large,
about to rule the world. With its first of time with C++Builder. developers tend to tolerate the BDE,
two versions, Delphi has penetrated not embrace it. The new BDE of
the Visual Basic/-PowerBuilder The relentless Java hype has also Delphi 3 is a step in the right direc-
fortress, but it hasn’t broken the bul- taken its toll on Delphi. Just when tion, providing much easier ODBC
wark wide open. And, while Delphi Delphi 2 was gathering steam, Java access. Before you hear me rave about
3 may be a “must” upgrade for devel- altered the development tool land- Delphi’s database prowess, however, I
opers already using Delphi, its new scape, bringing more attention to want to see the elimination of the
features are not sexy enough to win multi-platform Web development quirks often associated with SQL con-
over massive droves of VB, rather than the technical merits of nectivity which have given many
PowerBuilder, or C++ developers. Windows desktop development tools. Delphi SQL developers headaches
since version 1.
No VB Killer. It’s now apparent that Looking Ahead. Given this reality,
Delphi will never significantly pene- what must Borland do to ensure No, Delphi is not a David preparing
trate the VB developer marketplace. Delphi remains a viable development to defeat the mighty Goliath up
When Delphi was introduced, its tool? Allow me to offer two sugges- north in Redmond, but it does have
technical superiority was compelling, tions. two key factors in its favor: techno-
enough so that it was able to win the logical prowess and a sizable, loyal
hearts of many VB programmers. First, Borland must continue to focus developer base. So long as Borland
But this number was never the their attention on keeping Delphi as (or another suitor) continues to
legions that Borland had hoped for. the premier Windows desktop and enhance Delphi’s core strengths, you
The problem for Borland in 1997 is client/server development environ- can continue to feel comfortable
that any window of opportunity for ment. While RAD software vendors adding semicolons to the end of your
converting VB developers has largely have been running scared given the code statements. ∆
closed. Those who have remained Internet hype, a recent study by
steadfast with VB will not likely find Sentry Research Services suggests that — Richard Wagner
anything in Delphi 3 to win them Internet-based technologies will not
over. Essentially, Visual Basic 5.0 is replace client/server as the dominant Richard Wagner is Chief Technology
good enough for most VB developers. computing model. Therefore, while Officer of Acadia Software in the Boston,
Delphi 3 has some interesting Web MA area, and is Contributing Editor to
C++ and Java. Delphi is not the deployment technology that will serve Delphi Informant. He welcomes your
“C++ Killer” either. I know of many some of you, Borland cannot let the comments at [email protected].
C++ programmers who switched to Web radically alter future develop-
Delphi, but any C++ developer who ment efforts. Borland should focus
hasn’t already converted has little on Delphi’s core strength: making
58 May 1997 Delphi Informant