Professional Documents
Culture Documents
ON THE COVER
WEB FEATURE
www.DelphiZine.com/Features
Greater Delphi
FEATURES
9
On the Net
15
OP Tech
19
Informant Spotlight
25
Delphi at Work
In Development
REVIEWS
31
34
38
ExpressLayout Control
ModelMaker 6.11
ActivePatch 1.1
DEPARTMENTS
2
Delphi Tools
40
Delphi
T O O L S
New Products
and Solutions
Book Picks
.NET Common Language
Runtime Unleashed
Kevin Burton
SAMS
ISBN: 0-672-32124-6
Cover Price: US$59.99
(997 pages)
www.samspublishing.com
ISBN: 0-672-32088-6
Cover Price: US$39.99
(464 pages)
www.samspublishing.com
HK-Software Announces
IBExpert Personal Edition
HK-Software
Price: Free
Contact: info@h-k.de
Web Site: www.hksoftware.net/download
Delphi
T O O L S
New Products
and Solutions
Book Picks
Learn Java with JBuilder 6
John Zukowski
Apress
ISBN: 1-893115-98-4
Cover Price: US$54.95
(625 pages, CD-ROM)
www.apress.com
ISBN: 0-672-32320-6
Cover Price: US$39.99
(883 pages)
www.samspublishing.com
Greater Delphi
XML Transformations / XML Mapper Utility / Delphi 6 Enterprise
XML Transformations
Part I: Using the XML Mapper Utility
orland has always done a good job of differentiating its Professional and Enterprise
editions of Delphi, including sufficient goodies in the high-end release to justify the
additional expense. One of these extras in Delphi 6 Enterprise is XML transformations.
Support for XML transformations is provided in
two ways. The first is a collection of components
that use a special XML file called a transformation file to convert from one form of XML file
to another. The second is a special utility, called
the XML Mapper, which you use to generate the
transformation files.
XML transformations are provided in Delphi 6
Enterprise primarily to convert between XML
<customers>
<customer custno="1001">
<name>John Doe</name>
<address>101 Broadway Avenue</address>
<city>New York</city>
<state>New York</state>
<zip>00123</zip>
<credit>GOOD</credit>
<comments></comments>
</customer>
<customer custno="1002">
<name>Jane Doe</name>
<address>1001 Main Street</address>
<city>Los Angeles</city>
<state>California</state>
<zip>90123</zip>
<credit>GOOD</credit>
<comments>This is a great customer.</comments>
</customer>
</customers>
Greater Delphi
<?xml version="1.0" standalone="yes"?>
<DATAPACKET Version="2.0">
<METADATA><FIELDS>
<FIELD attrname="custno" fieldtype="string" WIDTH="4"/>
<FIELD attrname="name" fieldtype="string" WIDTH="21"/>
<FIELD attrname="address"
fieldtype="string" WIDTH=v32"/>
<FIELD attrname="city" fieldtype="string" WIDTH="32"/>
<FIELD attrname="state" fieldtype="string" WIDTH="32"/>
<FIELD attrname="zip" fieldtype="string" WIDTH="32"/>
<FIELD attrname="credit" fieldtype="string" WIDTH="4"/>
<FIELD attrname="comments"
fieldtype="string" WIDTH="32"/>
</FIELDS><PARAMS/></METADATA>
<ROWDATA>
<ROW custno="1001" name="John Doe"
address="101 Broadway Avenue" city="New York"
state="New York" zip="00123" credit="GOOD"
comments=""/>
<ROW custno="1002" name="Jane Doe"
address="1001 Main Street" city="Los Angeles"
state="California" zip="90123" credit="GOOD"
comments="This is a great customer."/>
</ROWDATA>
</DATAPACKET>
XML Mapper
Figure 3: The XML Mapper utility.
Greater Delphi
in the file named xmldata.xml (available for
download; see end of article for details).
First, select Tools | XML Mapper from
Delphis main menu to display the XML
Mapper. Then, from the XML Mappers
main menu, select File | Open. Browse to
the directory in which you have stored
xmldata.xml, select it, and click OK. The
XML Mapper will open this file and
display its structure in the Document pane.
Its worth noting that you can also load a
schema file or document type definition
(DTD), permitting you to create a
transformation from an XML description
without the actual XML file. In addition,
you can view XML schema information
by clicking on the Schema View tab of the
Document pane, as shown in Figure 4.
Greater Delphi
button. This time you will find ample room for
full names in the generated DBGrid. When youre satisfied with
the transformation, select File | Save | Transformation. The XML
Mapper will suggest the name ToDP.xtr (to data packet). You can
accept this name, or provide any other you find appropriate.
Transformation
Greater Delphi
complete the definitions necessary for the transformation, as
shown in Figure 9.
You can now create your data-packet-to-XML-file transformation.
Begin by clicking Create and Test Transformation. The XML
Mapper displays a sample Document view showing the structure
of your transformation, which will look similar to that shown
in Figure 7. Close this dialog box when youre done inspecting
the structure. If the structure was satisfactory, select File | Save |
Transformation to save it.
With the current definitions in the XML Mapper, you can
quickly create a corresponding XML-file-to-data-packet
transformation. To do this, select the XML to Datapacket radio
button in the Transformation pane, click the Create and Test
Transformation button, close the displayed dialog box, and select
File | Save | Transformation.
Summary
The XML Mapper utility permits you to create transformation files
that are used by Delphi 6 Enterprises transformation components
to convert an arbitrary XML file to a data packet, and a data packet
to an arbitrary XML file. Next month, in Part II of this series, you
will learn how to use the transformation components in Delphi 6 to
perform XML transformations in your applications. See you then.
The files referenced in this article are available on the Delphi Informant
Complete Works CD located in INFORM\2002\AUG\DI200208CJ.
On the Net
Web Services / SOAP / WSDL / Kylix / Delphi 6
By Bill Todd
ast month, in Part I of this series, we looked at building a simple Web Service
server and client, creating a WSDL file, working with complex types, and using
custom exceptions. Well continue this month by converting the TempConvert server
from Part I to run under Linux. Then well create an example of a Web Service that
provides large amounts of binary or text data to the client. Well also add logging to a
Web Service so that it records the IP address, date, and time of every client that uses
the Service. Finally, we will build a database application using a SOAP server.
Now add the following lines to ensure the directory has the ExecCGI option set:
<Directory "/etc/httpd/cgi-bin">
AllowOverride None
Options ExecCGI
Order allow,deny
Allow from all
</Directory>
On the Net
The last step is to copy TempConvert into the /etc/httpd/cgi-bin
directory. For more information, see the Kylix 2 README file.
Now that the CGI application is installed on your Linux server, you
can change the URL property of the THTTPRIO component in the
Windows client application, run it, and connect to the Linux server.
For example, on my network the URL is http://redhatserver/scripts/
TempConvert/soap/.
On the Net
THTTPRIO component to the IBlobServer interface and calling the
GetBinaryFile method, passing the file name entered in the Edit control
as a parameter. GetBinaryFile returns a TByteDynArray thats assigned to
the local variable named Blob.
This program saves the file received from the server in the directory
where the EXE is stored. The path to the directory is extracted from
the Application.ExeName property, and the file name is extracted from
the editFileName components Text property. Next, a TFileStream
instance is created with the mode set to fmCreate, and the contents of
the TByteDynArray are written to the file. After the file is written, a
message is displayed and the file stream is freed.
Figure 7 shows the code for the Get Text buttons OnClick event handler.
This code is identical to the code for the Get Binary button, except that
the GetTextFile method returns a string variable instead of a dynamic
array of bytes. Compile and run the client program, and you should be
able to copy text or binary files from the server to the client.
Logging Clients
Return to the BlobServer application and open the BlobServerImpl
unit in the Delphi IDE. Add a new method, LogClientData, to
the TBlobServer class so it looks like Figure 8. You do not have to
add LogClientData to the IBlobServer interface, because it wont be
called by the client.
Implement LogClientData as shown in Figure 9. Change the
LogName constant to the path for your log file. This method
begins by opening the log file using AssignFile and then calling
either Reset or Rewrite depending on whether the file exists. The
heart of this method is the call to Writeln which first writes the
date and time to the file.
GetSOAPWebModule returns a reference to the Web module thats processing the current request, so GetSOAPWebModule.Request.RemoteAddr
returns the RemoteAddr property of the Web modules request object.
This property contains the clients IP address. The Writeln call also
writes the RemoteHost property of the TWebRequest object. This property
contains the domain name of the client, if it could be found; otherwise,
it contains the IP address. Now all you have to do to enable logging is
call LogClientData from the GetBinaryFile and GetTextFile methods.
On the Net
TBlobServer = class(TInvokableClass, IBlobServer)
public
function GetBinaryFile(FileName: string): TByteDynArray;
stdcall;
function GetTextFile(FileName: string): string; stdcall;
procedure LogClientData;
end;
17) The last step is to create the data modules OnCreate event handler,
as shown in Figure 15. This code opens both ClientDataSets when
the application starts. You should now be able to compile and run
the client application.
On the Net
Figure 16: The client main form with the method call buttons added.
procedure TfrmMain.btnTimes2Click(Sender: TObject);
begin
// Set up the variant array. The first element contains
// the number of the method to call. The second element
// contains the parameter value to pass to the method.
dmMain.CallParams := VarArrayCreate([0, 1], varVariant);
dmMain.CallParams[0] := gTimesTwoMethod;
dmMain.CallParams[1] := 2;
// Call FetchParams to trigger the ClientDataSet's
// BeforeGetParams event handler.
dmMain.cdsCaller.FetchParams;
end;
virtually any type and amount of data. That means that if I can
get the client application to fire an event whose before and after
event handlers have an OwnerData parameter, I can pass information to the server in the OwnerData parameter that tells the
server what custom method to execute. The server can return any
resulting information to the client in the OwnerData parameter of
the after event handler.
The first thing we need to make this work is an innocuous event
that we can fire at will. The ClientDataSets FetchParams method
is perfect. All it does is fetch the parameters from the dataset
the provider is connected to on the server. Calling FetchParams
fires the BeforeFetchParams and AfterFetchParams events of the
ClientDataSet and DataSetProvider, and all of these events pass
an OwnerData parameter.
13 August 2002 Delphi Informant Magazine
unit Globals;
interface
const
gTimesTwoMethod = 1;
gTimesThreeMethod = 2;
implementation
end.
On the Net
procedure TdmMain.cdsCallerBeforeGetParams(Sender: TObject;
var OwnerData: OleVariant);
begin
// Assign the calling params to the OwnerData parameter.
OwnerData := CallParams;
end;
procedure TdmMain.cdsCallerAfterGetParams(Sender: TObject;
var OwnerData: OleVariant);
begin
ShowMessage('In = ' + IntToStr(OwnerData[0]) + ' ' +
'Out = ' + IntToStr(OwnerData[1]));
end;
Conclusion
Borland has done a great job of implementing a technology so new
thats its still in a state of flux. And as always the Borland
engineers have made using the technology easy. The Web Service
Application Wizard lets you quickly create a SOAP server that can
be used by any client. The WSDL Importer makes creating client
applications that use any SOAP server a snap.
Building database applications using the DataSnap components is
also easy, although the lack of support for multiple data modules
and calling custom methods on the server makes the process harder
than it needs to be. In spite of these limitations Web Services are
ready to go for Delphi developers.
The eight example projects and associated files referenced in this article
are available on the Delphi Informant Complete Works CD located in
INFORM\2002\AUG\DI200208BT.
Bill Todd is president of The Database Group, Inc., a database-consulting and development firm based near Phoenix. He is the co-author of four database programming
books, the author of more than 90 articles, and a Contributing Editor to Delphi Informant
Magazine. Bill is a member of Team B, which provides technical support on the Borland
Internet newsgroups. Bill is a nationally known trainer, has taught Delphi programming classes across the country and overseas, and is a frequent speaker at Borland
Developer Conferences in the United States and Europe. Readers may reach him at
bill@dbginc.com.
OP Tech
StringReplace / Optimization / Delphi 4-6
By Peter Morris
Optimizing StringReplace
Part I: The Boyer-Moore String-searching Algorithm
n Delphi, Borland created an excellent IDE and compiler. So its understandable that
programmers trust Borland not to let them down, and often just use the routines the
company has provided. Borland developers are human, however, and make mistakes. The
problem is that once Borland makes a mistake, its difficult (or sometimes even impossible)
for them to correct it. Simply fixing some code in a later version of Delphi could break existing applications that depend on Delphi to act in a predictable way.
Its probably for this reason that Borland wont
change its StringReplace function. Introduced
in Delphi 4, its purpose is to take a string and
replace all occurrences of one word (or substring)
with another. Given the monumental importance
of HTML files, XML documents, etc., text files
have become not only more popular, but also a
lot bigger. Unfortunately, this is the Achilles heel
of StringReplace.
In a simple test, I repeated the sentence, It
was the night before Xmas, and all was quiet.
I repeated it 2,500 times, which made a string
approximately 117KB in size. Then, I used
StringReplace to replace all occurrences of Xmas
with Christmas. It took seven seconds (on a
Duron 700MHz). Thats fairly poor! So lets see
what we can do to improve the situation.
The first thing you could do to improve the
speed of this routine would be to improve the
speed at which it finds text, so lets examine that
operation first. (Note that the technique used
here wont work on multi-byte locales without
modification.)
Boyer-Moore Algorithm
The Boyer-Moore string-searching algorithm was
invented in the mid 1970s by Robert Boyer and
J Strother Moore. The algorithm allows you to
find a substring within a source string without
reading every character in the source string. The
first difference between the two methods is that
OP Tech
Boyer-Moore uses the last character of the substring, again E in this
case, as the character to search for in the source string. The next
difference is that it doesnt start at the first character in the source
string; instead, it jumps immediately to the character at position
Length(SubString), the seventh position in this case:
EXAMPL[E]
THIS I[S] A SIMPLE EXAMPLE
We dont get a match, but this tells us much more than that. It also
tells us that there cant possibly be a match at any of the positions
starting before S. We know this because S doesnt occur in the
substring. So we can jump ahead another substring length, i.e. seven
more characters in this example:
EXAMPL[E]
THIS IS A SIM[P]LE EXAMPLE
Again, theres no match. This time, however, the letter P in the source
string does occur in the substring. It occurs two characters from the end
of the substring, so the algorithm jumps two characters, like so:
EXA[MPLE]
THIS IS A SI[MPLE] EXAMPLE
Its a match! In this example, the algorithm read only 17 characters from the source string, plus a single lookup from a table to
retrieve the number of characters to look ahead when theres a
mismatch (there were four mismatches).
This is only a simple example, yet it requires 23 percent fewer character reads of the source string. When searching for a large substring,
the savings can be greater. This is good stuff, so lets see how we can
implement it in Delphi.
type
TBMJumpTable = array[0..255] of Integer;
...
procedure MakeBMTable(const Buffer: PChar;
const BufferLen: Integer; var JumpTable: TBMJumpTable);
var
I, Distance: Integer;
SourceChar: PChar;
begin
if BufferLen <= 0 then
raise EBMError.Create('Buffer length is 0');
// For each character not in the search string
// (Buffer), jump the length of the search string.
for I := 0 to 255 do
JumpTable[I] := BufferLen;
// For each character in the buffer, note how far
// it is from the end of the buffer.
Distance := BufferLen - 1;
SourceChar := Buffer;
for I := 1 to BufferLen - 1 do begin
JumpTable[Ord(SourceChar^)] := Distance;
Inc(SourceChar);
Dec(Distance);
end;
end;
OP Tech
Boyer-Moore Again
Second, I used a function featuring the Boyer-Moore search routine
and which uses a kind of FindNext implementation (see Figure 5).
The routine uses a pointer to the start of the string rather than altering the string itself. This involves:
1) Setting a pointer to the start of the substring, and another to the
start of the source string.
2) Creating your jump table. (Notice you do not need to convert
each character in the source string and substring to uppercase.)
3) Finding an occurrence of the substring in your source string.
4) Incrementing Result.
OP Tech
5) Setting the source strings size to the amount of characters
left from the end of this occurrence to the end of the actual
source string.
6) Incrementing the pointer at the start of the source string so that it
points to the character after the current occurrence. (Technically,
you have done a Delete without reassigning your source string.)
7) Repeating the third step.
The results of this exercise were that the Borland method took 2.3
seconds, and the Boyer-Moore method (without reassigning the
source string) took a mere 10 milliseconds (on my feeble Duron
700MHz).
Conclusion
Now that you are more familiar with the inner workings of string
assignment, next month well look at Borlands implementation of
StringReplace, in particular some obvious inefficiencies that slow it
down. See you then.
The osFastStrings.pas unit and demonstration project referenced in this
article are available on the Delphi Informant Complete Works CD located
in INFORM\2002\AUG\DI200208PM.
Peter Morris is 26 years old and married, with two children. He works from home
as a computer programmer for Insite Technologies Ltd., where he writes a wide
variety of non-standard-looking Windows applications. He loved breaking away
from the Windows GUI standards. Now, he writes special graphical effects and
animated components. You can reach Peter at MrPMorris@hotmail.com.
Informant Spotlight
Microsoft .NET Framework / Delphi 7 / Delphi for .NET
By Jon Shemitz
he new, developer-oriented Borland is much less secretive than it used to be. This
started with Kylix and has accelerated with .NET. There were some great sessions
at BorCon about the case for .NET and Borlands .NET plans. This article provides a
brief summary of both.
This article is mostly about .NET and Borlands
.NET plans, though I also talk a bit about the
syntax changes well start to see in Delphi 7 and
in the Delphi for .NET preview that will ship
with D7. Most of this comes from Danny Thorpes
two language preview talks, Chuck Jazdzewskis
Moving Delphi talk, and Microsofts Jim Hoggs
Inside the CLR talk, but I also draw a bit from
the Anders Hejlsberg and James Gosling keynotes.
Why .NET?
You may still be wondering how much attention
you should be paying to .NET. (It wasnt all that
long ago that all I really knew about .NET was that
it was Microsofts response to Javas server-side dominance.) So, before I get to the Delphi syntax stuff,
Ill just run through a couple of common questions
and one common assertion about .NET.
Informant Spotlight
Figure 1: The heap, before (above) and after (below) a generation 0 garbage collection.
Garbage collection can be so fast because memory life spans are distributed according to a power law. Most memory is freed quite soon after
its allocated. Most of whats left is freed within seconds or minutes. And
most of what lasts longer than that lasts until the program shuts down.
So, .NET has a three-generation garbage collector. When the system
has done enough recent allocations, it triggers a generation 0 garbage collect. This looks only at the most recently allocated blocks,
and finds the ones that are still in use. At this point, the system
only has to pay attention to the blocks that arent garbage. These get
moved down to the bottom of the partition, and promoted to generation 1, which means that the next generation 0 collection wont
look at them. Once all the current data has been promoted and
moved to the bottom of the partition, whats left is free memory (see
Figure 1). By default, the generation 0 garbage collection threshold
is the size of the CPUs L2 cache at least in principle, short-lived
allocations never even make it to main memory.
When the set of generation 1 blocks exceeds a different, larger threshold or a generation 0 collection cant make enough room the
system does a generation 1 collection, which finds all the blocks that
have become garbage since being promoted to generation 1. All survivors are moved and marked as generation 2, and wont be touched
again until the system does a generation 2 garbage collection (see
Figure 2). A generation 2 garbage collection just moves the surviving
blocks down; it does not promote them to generation 3.
As you can see, this three-generation garbage collection minimizes
the time the system spends repeatedly noticing that a long-lived
object is still alive. This in turn, greatly reduces the number of times
a long-lived block gets moved. The idea of generations also saves time
in a more subtle way. The way the system detects that an object is still
live is to walk every reference from a set of roots on down. (It can
do this because it has type data for every structure in the system, i.e.
it knows every field of every structure.) This walk can stop as soon as
it reaches an object that is a higher generation than the garbage collection, e.g. every reference in a generation 1 object is to a generation
1 or 2 object, which a generation 0 sweep doesnt care about.
Informant Spotlight
Figure 2: The same heap from Figure 1, before (above) and after (below) a generation 1 garbage collection. Some blocks have turned
to garbage, and some new blocks have been allocated.
In this vein, Chuck talked about what goes into the Delphi feel.
I think there were three main points, here. Chuck emphasized
that the component model is probably the single biggest part of
the feel. It contributes to the tactile nature of Delphi programming theres something you can look at and touch, even for
something abstract like a timer or a database connection and
most Delphi programmers are more component oriented than
object oriented. In fact, Chuck said that you can be a successful Delphi programmer without ever using inheritance. Hes
probably right: While some of the most interesting parts of various projects have required inheritance, Ive certainly done plenty
of bread-and-butter apps where inheritance didnt come in at all.
Somewhat more broadly, Chuck says that one of the most important questions to ask when comparing programming environments
is: How many things do you have to remember? The more things
you have to remember, the easier it is to forget one and make a serious mistake. Delphi promotes a contract-less programming style
that encourages you to freely mix components without having to
worry much about how they ought to be used.
Finally, with Delphi you Debug the code you wrote ... and only
the code you wrote. Your code isnt cluttered with lots of toolgenerated code, as in C#. Despite some recent online discussions
about how building a form with run-time code can be faster (less
string lookup), and can make for smaller executables (no need to
link in unused property setters) than Delphis resource streams,
Delphi will continue to use resource streams.
One thing that struck me about the Delphi feel part of Chucks
Moving Delphi talk was that Chuck might almost as well have been
talking about Visual Basic. Chuck did talk a bit about the difference
in the C and Pascal notion of types, but otherwise he didnt say all that
much about Pascal. Unfortunately, somehow its just as chic to disdain
21 August 2002 Delphi Informant Magazine
DfN will produce 100 percent managed code. That is, it will generate
only CIL that you can run through the Microsoft PEVerify utility to
prove that it is memory type safe. Type-safe code plays by the rules,
and doesnt do tricks like read other objects private fields. .NET code
doesnt have to be verifiably type safe, but unsafe code requires special
permissions to run. For example, the Microsoft WinForms classes,
which are how you build GUIs in .NET, are unmanaged code that
ultimately call the existing Win32 libraries like User32, ComCtrls,
and RichEd. They come signed by Microsoft in a way that asserts
that theyre just as safe as the libraries they call. These libraries may
not be perfect, but youve been using them for years.
With Delphi for .NET, youll be able to write WinForms applications, just as you can with the Microsoft Development Environment
(aka Visual Studio .NET). Borland will also write a version of the
VCL for .NET the familiar Delphi control set implemented
as managed code that ultimately calls the existing Win32 libraries
like User32, ComCtrls, and RichEd. This library will be signed by
Borland in the same way that WinForms is signed by Microsoft. My
guess would be that VCL for .NET wont be 100 percent compatible with the existing native VCL, but since its ultimately calling the
same libraries that the VCL does now, it should be more compatible
than CLX, which has to implement VCL-like behavior using Qt.
Whether your desktop application uses WinForms controls or the
new VCL for .NET controls, it will be able to use all the functionality of the Microsoft framework classes the new, object-oriented
Informant Spotlight
API that covers everything from Web Services and object serialization, to a nice set of collection classes and Perl-compatible regexes.
Your decision to use WinForms or VCL for .NET for any given project will be based mostly on your plans for that project: WinForms
projects should run on any desktop platform that supports .NET
(like IA64 platforms in a couple of years, and possibly OS/X or
Linux) while VCL for .NET projects will require a Windows desktop
host, but can be more easily ported from (and to) Delphi or Kylix.
Delphi for .NET will ship sometime in 2003. D7, which will ship in
2002, will include a Preview Edition of Delphi for .NET, which will
include (at least a preliminary version of) the VCL for .NET library and
the DCCIL command-line compiler, which compiles Delphi source
to .NET assemblies. (A .NET assembly is a standard Microsoft PE
[Portable Executable] file, which contains CIL byte codes and metadata
instead of Intel object code. Every entry point in the PE file points to a
stub which JIT compiles the code and then modifies the entry point so
that future calls just go straight to the compiled code. Metadata is basically just a generalized and extended version of Delphis RTTI.)
While obviously the Preview Edition will be a lot harder to use
than the eventual full blown Delphi for .NET, youll be able to
use it to build .NET applications in Delphi. In particular, youll
be able to embed Delphi code in ASP documents. (The audience
was very impressed when Anders did this during his keynote.)
New Syntax
There will be language changes. Many of the changes are necessary
to support .NET, but others seem to be coming because the compiler
guys want to do some cleanup while they make big changes. These
language changes will also appear in future versions of Delphi for
Windows and Kylix to maximize portability between Delphi for
.NET and the classic versions of Delphi (the ones that generate
native Intel code). However, while classic Delphi programs will be
able to use Delphi for .NET syntax, they wont have access to the
.NET run-time library (the Framework classes) or to standard .NET
object methods like ToString and HashCode.
In .NET, Delphis TObject will be a System.Object. (If Borland
didnt map TObject this way, then TComponent wouldnt be a
System.ComponentModel.Component, and Delphi components
wouldnt be playing in the language-neutral space.) Since TObject
does have methods like ClassName and Free that System.Object
does not, Borland is adding the concept of helper objects:
type
THelper = class helper for TObject;
and then use those dotted names as part of a fully qualified name in code:
HashTable := System.Collections.Hashtable.Create;
Informant Spotlight
Since those dotted names can get pretty long, well be able to define
aliases in the uses clause:
uses System.Drawing.Text as GuiText;
Well be able to have class properties, not just class methods. Well be
able to declare static class methods, which wont have a Self parameter
that reveals the type of class that the method was actually invoked on.
Much like in Java and C#, well be able to declare sealed classes that
cant be inherited from, and final methods that cant be overridden.
New Semantics
.NET is a garbage-collected environment. That means we can all forget
the old Free-What-You-Create rule. I imagine that Borland will build
some sort of mechanism so if ported code does Free an object, the garbage collector wont try to run the destructor again during finalization,
but thats just me Borland didnt say anything about it at BorCon.
Garbage collection also means that Delphi doesnt need to use reference counting to Free strings, dynamic arrays, and interfaces. Those
types will still be available, and with one exception will act the
same, but they will no longer be reference counted. This means that
assignment of every one of these types will be faster; it also means it
will take less time to call and return from every routine that now has
reference-counted local variables.
If you dont explicitly Free an object, its destructor only gets called
when the garbage collector needs to reclaim the space. Thus, one
big difference between interfaces in Delphi and Kylix and interfaces in Delphi for .NET is that on .NET an interfaces destructor
doesnt get called the instant the last reference goes away. That
is, if youve been using interfaces for resource protection, current
plans mean that your code will break. If you open a file in append
mode and wrap the handle in an IStream interface, your file wont
close as soon as the stream is all written. If you store the current
Cursor in an interfaced object before changing Screen.Cursor,
the system Cursor wont be reset when the procedure that set it
returns; itll be reset at some random time later, perhaps after
some other code had made its own changes.
If losing reference counting would break your code in this way, you
probably ought to let Borland know. Its at least theoretically possible to have some not all interfaces use reference counting on
.NET, and Borland may do so if it keeps enough code from breaking.
Informant Spotlight
Dead Syntax
In addition to the changes Ive just sketched, some existing syntax
simply wont work on .NET. .NET is all about managed, type safe
code, where the system knows the layout of every structure it may
garbage collect. Thus, the untyped memory functions GetMem,
FreeMem, and ReallocMem wont be supported under .NET. (New
and Dispose will still be supported.) Similarly, untyped var parameters
and the @ and Addr operators will be illegal in Delphi for .NET.
As I understand it, on .NET the record alignment strategy, and hence
the actual size of a record, will depend on the current hardware platform.
This is why you wont be able to use the file of type syntax on .NET.
Using .NETs SOAP serialization code to stream records and objects
in a portable manner is the closest youll be able to get to this type of
random-access record-oriented file. SizeOf may also be affected; it may
not be a compile-time constant on Delphi for .NET. The impression I
got is that this is one of those things thats still being researched.
Obviously enough, inline x86 assembler (BASM) wont be legal
on .NET. Current plans are that Delphi for .NET wont include a
BASM that understands CIL, either. Im not sure if this is a costof-writing-a-CIL-assembler issue, or a more fundamental matter
of BASM being less useful when even your hand-written CIL gets
compiled by the jitter. .NET does include the System.Reflection.Emit
namespace, which allows you to generate CIL at run time.
It may not be possible to implement virtual constructors on .NET.
Obviously, this would break all sorts of sophisticated code, and so
Borland would like to implement this, but apparently there are some
technical barriers they may not be able to overcome. If necessary,
code that currently uses virtual constructors can be rewritten to use
RTTI to find the appropriate constructor.
Finally, some old syntax thats been deprecated for a while the
absolute keyword, the real48 data type, the whole ExitProc chain, and
the old-style object keyword will no longer be supported at all.
Special thanks to Stefan Hoffmeister and Rick Ross for valuable feedback
on the draft of this article.
Jon Shemitz is a consultant and author who lives in Santa Cruz, CA. He is the
author of Kylix: The Professional Developers Guide and Reference (Apress,
2001) and is working on a Delphi for .NET book. You can contact Jon at
http://www.midnightbeach.com.
Delphi at Work
Web Browser / Delphi 6
Building a Browser
Implementing a Custom Web Browser with Delphi 6
elphi 6 allows for syntax overloading in subroutines. As a result, the Web browser
ActiveX control based on IE6 provides multiple ways to call several TWebBrowser
methods, including Navigate.
If you have Internet Explorer 6 (IE6) installed
on your machine, youre better off importing its
native ActiveX control, especially if you want to
take advantage of security features. In the code
provided (see end of article for download details),
Ive named the ActiveX version of the Explorer
object TMSIE6WebBrowser, rather than the default
TWebBrowser, because that is the name of the
existing browser Delphi 6 offers on the Internet
Delphi at Work
&Halton School Board - Upload Tool Login Page
https://upload.haltondsb.on.ca/
&ibiblio - March
http://www.ibiblio.org/
&Welcome to Paul King's Web Page
http://www3.sympatico.ca/pking123/
&Borland Home Page
http://www.borland.com/
&Google
http://www.google.ca/
&OLGA - The On-Line Guitar Archive
http://www.olga.net/
Two menu items are created: one for the bookmark menu and one for
the bookmark-deletion menu. These are anonymous objects, because
they will be added to the bookmarks pop-up menu pmBookmarks using
the pmBookmarks.Items.Add method.
TMenuItem.Create(Self ) creates an instance of a menu item and
stores it in a pre-declared TMenuItem named item. Its Caption property gets the page title, and its Hint property gets the URL. I use the
Hint property strictly for storage, but nothing should stop you from
using this URL as a hint in the pop-up menu.
Because you never know in advance which bookmark is requested
for deletion, a canned response to an OnClick is necessary. For
that reason, I introduce miBookmarkClick, shown in Figure 4.
This simple routine obtains the menu item through the TObject
parameter Sender. It gets the index of the clicked menu item first.
Then it deletes the bookmark by its index. The bookmark.dat file
will be updated when the program exits.
The menu items for deletion were created when the bookmark was
created, under createMenuItem. The caption was set the same way.
When the bookmark is selected for deletion, the deletion should
occur in the bookmark and deletion lists. All you need to do to
navigate to the URL that the Hint property indicates is to cast Sender
as a TMenuItem:
procedure TfrmBrowser.miBookmarkClick(Sender: TObject);
// Universal response to a click on a bookmark menu item.
begin
WebBrowser1.Navigate((Sender as TMenuItem).Hint);
end;
An Extended ComboBox
The purpose of using a TComboBox in place of the text box for
the Location bar is to provide another way of saving previously
visited sites during a session, and to save the user the trouble of
clicking on the Back and Forward buttons countless times. This is
different from bookmarking, in that the behavior of the custom
Delphi at Work
Whether a string is loaded into cbxLocation depends on the
URL of the site visited. Its actually an extended ComboBox
(TComboBoxEx), which accepts icons. If the name is substantially
different from any other URL on the list, that name is added.
This makes the ComboBoxs behavior different from that of
Internet Explorer (see the end of the article for suggestions about
obtaining Internet Explorer behavior in cbxLocation).
When I say the name is substantially different, what I mean
depends on a seemingly arbitrary but effective method consisting
of finding a match within the first two dozen characters of both
URLs. If no such match is found, then the URL is added via:
cbxLocation.ItemsEx.AddItem(URL, 0, 0, 0, 0, nil);
Users should bookmark any URLs they want saved in a more permanent and less arbitrary fashion. The only purpose of this weedingout method is to prevent cluttering the combo-box list with highly
similar or useless URLs. The syntax for this kind of AddItem is:
function AddItem(const Caption: string; const ImageIndex,
SelectedImageIndex, OverlayImageIndex, Indent: Integer;
Data: Pointer): TComboExItem;
This routine makes the status bar rather chatty and therefore not
much different from Internet Explorers. OnStatusTextChange calls this
event, which may be used to update the status bar with new status
messages, including mouse-overs. WebBrowser1StatusTextChange
receives the status text in its parameter list, data type WideString. This
can be transferred directly to the appropriate status-bar panel, as you
just saw in the code snippet.
Detecting Encryption
IE6 is capable of detecting encryption and can even determine the
kind of encryption. Delphi 6s stock TWebBrowser doesnt provide
that function. In this browser, I decide to find ways of telling the user
about the encryption in as much detail as possible if the browser does
or does not detect encryption. There are two ways this browser
does this: through messages on the toolbar, and through the use of
special icons. The security-level value is based on a C++ enum that
is rewritten here as the Delphi-style enumerated type securityLevel.
Figure 9 shows the associated code.
Delphi at Work
function TfrmBrowser.isUniqueBookmark(URL: string):
Boolean;
// Returns True if the URL is unique.
var
unique : Boolean;
i : Integer;
begin
unique := True;
for i := 0 to bmIndex - 1 do
if strcomp(PChar(pmBookmarks.Items[i].Hint),
PChar(URL)) = 0 then
unique := False;
isUniqueBookmark := unique;
end;
type
// Security level icon indices.
secLevelIcons = (globeico = 12, lckMixed, lckUnk,
lck40bit, lck56bit, lckFort, lck128bit, lckCookie,
lckBroken = 25);
procedure TfrmBrowser.WebBrowser1SetSecureLockIcon(
Sender: TObject; SecureLockIcon: Integer);
// Tell user security level of site.
type
// Security Level Enumerations. Start counting from 0:
securityLevel = (secureLockIconUnsecure = 0,
secureLockIconMixed, secureLockIconUnknownBits,
secureLockIcon40Bit, secureLockIcon56Bit,
secureLockIconFortezza, secureLockIcon128Bit);
begin
case securityLevel(SecureLockIcon) of
secureLockIconUnsecure:
OutputSecurityMesg('NO encryption present',
globeico);
secureLockIconMixed:
OutputSecurityMesg(
'Multiple encryption methods used', lckMixed);
secureLockIconUnknownBits:
OutputSecurityMesg('encryption level UNKNOWN',
lckUnk);
secureLockIcon40Bit:
OutputSecurityMesg('40-bit encryption used',
lck40bit);
secureLockIcon56Bit:
OutputSecurityMesg('56-bit encryption used',
lck56bit);
secureLockIconFortezza:
OutputSecurityMesg('Fortezza encryption used',
lckFort);
secureLockIcon128Bit:
OutputSecurityMesg('128-bit encryption used',
lck128bit);
end;
end;
procedure TfrmBrowser.outputSecurityMesg(mesg: string;
iconIdx: secLevelIcons);
begin
StatusBar1.Panels[0].Text := mesg;
tbGoThere.Hint := mesg;
tbGoThere.ImageIndex := Integer(iconIdx);
end;
Events Unseen
Some events related to the browser are what I call unseen events. We
dont see these events happen, but they do happen, with consequences for which you may or may not have coded. Otherwise, the
events are ignored. Coding for unseen events can give the browser the
familiar feel of the commercial browsers (or any behavior you want).
Heres a list of unseen events:
OnProgressChange
OnStatusTextChange
OnTitleChange
OnSetSecureLockIcon
OnPrivacyImpactedStateChange
OnCommandStateChange
An OnCommandStateChange handler that takes into account the
enabling and disabling of Back and Forward buttons is compulsory
for this browser. Not handling this event with respect to the Back or
Forward buttons simply will cause the browser to crash.
Delphi at Work
Constant
Value
Meaning
secureLockIconUnsecure
encryption present
secureLockIconMixed
multiple encryption
methods used
secureLockIconUnknownBits
encryption level
UNKNOWN
secureLockIcon40Bit
secureLockIcon56Bit
secureLockIconFortezza
secureLockIcon128Bit
procedure TfrmBrowser.
WebBrowser1PrivacyImpactedStateChange(Sender: TObject;
bImpacted: WordBool);
// Accounts for two major categories of privacy violations:
// either via the top-level URL (by way of such things as
// insecure cookie access) or via the end user (who might
// initiate navigation from a secure site).
begin
if bImpacted then
begin
tbGoThere.ImageIndex := Integer(lckCookie);
tbGoThere.Hint := 'Un-secure cookie access';
StatusBar1.Panels[0].Text := 'Insecure cookie access'
end
else
begin
StatusBar1.Panels[0].Text :=
'Privacy Impacted by User';
tbGoThere.Hint := 'Privacy Impacted by User';
tbGoThere.ImageIndex := Integer(lckBroken);
end;
end;
The code in this browser was set up so it would save the bookmarks
and exit regardless of the value entered (on Windows 2000, pressing
the title bars X causes caHide to be passed as a parameter). The code
for FormClose is:
procedure TfrmBrowser.FormClose(Sender:Tobject;
var Action: TcloseAction);
begin
if (Action = caFree) or (Action = caHide) then
TbExitClick(Sender);
end;
Delphi at Work
using OnTitleChange. The ComboBox list is volatile; it exists only
while the program is running. Because the list grows as you surf, it
wouldnt make much sense to save the URL list unless its behavior
was reprogrammed to be like that of Internet Explorer. The
OnTitleChange event provides a good opportunity to see if the URL
at which you arrived was the result of the URL being entered (and
not the result of a link or a bookmark). Then, add that URL to the
cbxLocation ComboBox if it is unique and reaches its destination
successfully. The coding details are left to you.
Minor variations on TProgressBar. You can set TProgressBars
Orientation property to vertical (pbVertical ) for a thermometer effect (the
other value is pbHorizontal ). A vertical progress bar with its BorderWidth
property set to 1 or 2 also can serve as a button separator for a more
unusual design effect, saving space in the meantime.
Bookmark recovery. Using the framework shown previously for
bookmark addition and deletion, a similar routine could be written for
bookmark recovery after a deletion before the current session ends. This
would take advantage of the fact that the bookmark file isnt overwritten
until the browser exits. Thus, if the user thinks bookmarks were deleted in
error, the bookmarks can be restored by rereading the bookmark.txt file,
checking for differences between the current bookmarks and the saved
ones, and adding only the bookmarks that arent in the current menu.
Using frames. Creating a separate, modular frame to contain the browser
and the other controls may provide added flexibility to the application
should there be a desire to add more features to the application later. This
assumes, of course, that almost all the methods are coded as part of the
frame unit. Imagine having things like a series of browser instances each
occupying a page within a TTabControl. Designing a browser this way is
a good starting point toward that kind of expandability. Once you create
the frame, what you need to do is to add that frame to the main form or
PageControl page as a control, and set its Alignment property to alClient.
Done this way, however, the browser loses the ability to load a default
page on FormCreate, as mentioned earlier.
type
OLECMDID = (
OLECMDID_OPEN = 1,
OLECMDID_SAVE,
OLECMDID_SAVECOPYAS,
OLECMDID_PRINTPREVIEW,
OLECMDID_SPELL,
OLECMDID_CUT,
OLECMDID_PASTE,
OLECMDID_UNDO,
OLECMDID_SELECTALL,
OLECMDID_ZOOM,
OLECMDID_UPDATECOMMANDS,
OLECMDID_STOP,
OLECMDID_SETPROGRESSMAX,
OLECMDID_SETPROGRESSTEXT,
OLECMDID_SETDOWNLOADSTATE,
);
OLECMDID_NEW,
OLECMDID_SAVEAS,
OLECMDID_PRINT,
OLECMDID_PAGESETUP,
OLECMDID_PROPERTIES,
OLECMDID_COPY,
OLECMDID_PASTESPECIAL,
OLECMDID_REDO,
OLECMDID_CLEARSELECTION,
OLECMDID_GETZOOMRANGE,
OLECMDID_REFRESH,
OLECMDID_HIDETOOLBARS,
OLECMDID_SETPROGRESSPOS,
OLECMDID_SETTITLE,
OLECMDID_STOPDOWNLOAD
Conclusion
By building your own ActiveX browser, you can build in the features
you want, any way you want. I do not mean to suggest that my browser
is an end-all, be-all program. You could write things quite differently
and emphasize different aspects of browsing. In this article, I focused on
conveying security information to the end user. By programming your
own browser, you have significantly more control over the browsers
features, as well as over the look and feel.
The project and associated files referenced in this article are available
on the Delphi Informant Complete Works CD located in INFORM\2002\
AUG\DI200208PK.
Paul Joseph King is a writer, teacher, and consultant living in Oakville, Ontario,
Canada. Readers may reach him at pking123@sympatico.ca.
ExpressLayout Control
A Genuine Alternative to Delphis Form Designer
xpressLayout Control is Developer Express new product for managing form layout
in Delphi applications. The product offers run-time form-customization capabilities,
hierarchical control grouping, support for look-and-feel styles, and more.
ExpressLayout is a hard product to explain. You really
have to see it in action to get a feel for it, and even
after several months of extensive use, you still learn
new things about it as you use it. When I bought
the product, I envisioned it as a method to promote
end-user layout customization. However, Ive found
I dont like to use that feature. Even so, the product
provides other benefits that make it a tool I use
frequently.
When you install ExpressLayout Control, it adds two
new components to Delphis Component palette.
The main one, TdxLayoutControl, is a control container you can drop on your forms. Its used to hold
a set of groups and controls that are arranged semiautomatically for you as you drop them on it. Groups
are containers within the layout control. Think of a
group as a container control that has attributes such
as vertical and horizontal alignment, location, and
For example, I added a layout look-and-feel list to our sample and created
three look-and-feel options: one that resembles Office dialog boxes, a standard one, and one that looks like a Web form (see Figures 4 through 6). As
you may expect, you easily can change the look and feel during run time
and even allow your users the ability to customize it to their hearts desire.
The product comes with complete source code, a help file, and a couple
of demos, one of which shows how to create an interface like that of
Conclusion
This control provides a great alternative to the standard Delphi
form layout. Theres a learning curve involved in understanding
the logic behind the control. But, once you master it, the time
you save when creating complex dialog boxes and forms with
professional layouts is substantial. Creating complex dialogs that
optimize the users capabilities is no longer a chore. ExpressLayout
Control is indispensable for this reason alone.
ModelMaker 6.11
Delphi-specific Two-way UML Tool Gets Even Better
odelMaker: Just your average, feature-rich, low-cost, active-modeling, codegenerating, two-way-editing, ever-improving, Delphi-specific UML tool. I
reviewed ModelMaker 5 in the October 1999 issue of Delphi Informant, and gave it
the highest praise I could manage. Well, I need to come up with some new superlatives, because the product continues to improve.
In this review, well look at diagramming, the
part of ModelMaker that has progressed the most
since version 5. For a look at the products other
features, please see my earlier review, at
http://www.delphizine.com/productreviews/1999/
10/di199910rl_p/di199910rl_p.asp.
I have a friend who eschews UML diagramming
as nothing but pretty pictures. He claims that
the moment the first line of code is written, the
diagrams are at best irrelevant (since theyll most
likely fall out of sync with the class implementations), and at worst, a waste of time and effort
(since they have to be updated). Putting aside
the fact that my friend misses the point of UMLs
value as a pre-implementation analysis tool,
the vast majority of available UML tools lend
credence to his argument. For example, you can
use Visio, and wind up with some pretty pictures,
but it has no code-generating capabilities so youll
have to update your diagrams regularly by hand.
You could also get the industry standard, Rational
Rose, and pay US$4,000 for the privilege of getting no Delphi support.
The pretty picture argument fails, however,
if youre using a two-way, active-modeling tool
34 August 2002 Delphi Informant Magazine
nevertheless detect and display the change. Two-way UML diagramming for Delphi!
Youll find buttons to add diagrams to the model on the toolbar across
the top of the window. ModelMaker currently supports the following
diagrams: Class, Sequence, Use Case, State, Activity, Implementation
(component and deployment), Unit Dependency, and Mind Map. These
last two are not UML diagrams, but are useful tools nonetheless.
The tree view displays a list of all diagrams in the model and allows
you to add or clone diagrams in a hierarchical manner (see Figure 3).
Thus, related diagrams can be grouped under a single parent (all the
Use Case diagrams in Figure 3 are gathered under a single parent).
Mind Maps. Mind Map diagrams are based on the mind mapping technique by Tony Buzan and are powerful brainstorming tools. This type
of diagram consists of branching nodes representing related thoughts.
ModelMaker allows you to create the requisite small and large nodes and
connect them easily. Creating Mind Maps in ModelMaker is simple,
allowing you to keep up with a rapid brainstorming session.
Mind Maps offer support for many elements common to all ModelMaker diagram types (see Figure 4). Ill discuss them here, but they
are available to all diagrams.
From left to right, there are buttons to add packages, units, various types of annotation elements, constraint relations, hyperlinks,
polygons, lines, and images. ModelMakers diagram hyperlinks are
particularly powerful, featuring the ability to link to most elements of
Take a look at the small linked chain icon in the class symbols on the
DataBroker property association arrow in Figure 5. Also, notice the minus
signs in the upper-left corner of the class symbols. The linked chains are
hot spots. Clicking them will result in opening the appropriate editor for
the selected element. Likewise, clicking the minus signs will collapse their
symbols. This allows class diagrams that are manageable, maintainable,
dynamic, and just plain cool. ModelMaker wields a diagramming editor
thats meant for serious productivity.
Sequence diagrams. Sequence diagrams emphasize the time ordering
of messages between objects. In other words, in a Sequence diagram,
objects are arrayed along the x-axis and time progresses downward
through the y-axis; messages between objects are displayed as
labeled arrows. Much like Class diagrams, adding elements within a
Sequence diagram can add them to the code model itself. Therefore,
if youre creating a Sequence diagram and you see the need for class
X to have a new method that class Y will call, you can simply create
the call, and in the process, create the new method. Theres no need
to leave the diagram to create the new method.
Sequence diagrams have a tendency to get rather large once youve
added call returns, annotation, etc., so this is a good place to talk
about ModelMakers new print capabilities. Its now possible to
create diagrams of any page size, and ModelMaker will tile the
output onto multiple pages. This eliminates the need to create
multiple letter-page-sized diagrams.
36 August 2002 Delphi Informant Magazine
ActivePatch 1.1
Cost-effective Patching for Distributed Applications
our team has just finished and deployed its latest application to several thousand
users. One bug slipped through quality assurance, but its a showstopper. How do
you slipstream the patch to your users without asking them to download a 23MB patch?
Catalyst Development Corp. answers this problem with ActivePatch, a product that generates and applies byte-level change patches to your distributed applications.
Once the software is purchased and activated over
the Internet (yes, this form of software registration is becoming the norm, particularly in the
software component market), the product is ready
to be programmatically manipulated. When an
ActivePatch-enabled solution is constructed and
ready for distribution, the products license permits
unlimited client use of its redistributable libraries,
making it a cost-effective version control system
for deployed applications.
Unlike traditional setup utilities, ActivePatch
assumes that the bulk of your application payload
was delivered in its initial installation. It reviews
the changes from the original files and only applies
alterations. This makes the weight of distributing changes considerably smaller. The benefits of
applying patches at the byte level include: reduced
update size, faster distribution of patch (especially
Three Solutions
The ActivePatch CD comes bundled with three
programmatic solutions: 1) a DLL that can be
accessed via standard C library calls; 2) a slightly
larger Microsoft Foundation Class (MFC) Library
object-oriented version; and 3) a 314KB ActiveX
control (its the largest, but the easiest to use).
These files are completely self-contained; they dont
use the MFC or Visual C Runtime library unless
the ActivePatch C++ classes are used. This makes
their distribution in the initial setup program easy.
When using the ActiveX version, the initial setup
program must support a self-registering ActiveX, or
run the REGSVR32 program to properly register
the component.
Although determined Delphi developers can generate a wrapper for the stand-alone DLL version,
most will elect the easy-to-use ActiveX control.
The only caveat with this approach is the potential
security risk its installation might pose on a clients
system. Nefarious hackers, aware of the controls
presence, might activate it via older Internet
Explorers ActiveX scripting capability, target a
trusted installation, such as Microsoft Office, and
as a result, slipstream their own unauthorized files
that damage or completely overwrite trusted files.
Catalyst, and Catalyst would, in turn, freely distribute them (sans the
control or DLL, of course) via the companys Web site.
Conclusion
After the hard work is finished, ActivePatch is quite satisfying to
watch in action. A rewarding level of polish and professional touch
can be attained using the technology, and the peace of mind of
knowing that even the smallest changes can be effortlessly applied to
deployed applications is considerably reassuring.
The only remaining concern is the fact that this product may be
short-lived, especially in a .NET Framework world. One of the
problems that .NET solves is the distribution and version control
nightmare that ActivePatch solves for pre-.NET Win32 executables.
Several articles posted on the Web show how easy it is to leverage the
Common Language Runtime (CLR) to provide much of the same
functionality that ActivePatch provides through its support for distributing and applying new application assemblies. Still, it will take
years for Microsoft to embed the bulky .NET Framework into every
OS that it ships, so the viability of Catalysts solution should remain
effective for some time to come.
Mike Riley is a chief scientist with RR Donnelley, one of North Americas largest printers. He participates in the companys emerging technology strategies
using a wide variety of distributed network technologies, including Delphi 6.
Readers may reach him at mike_riley_@hotmail.com.
File | New
Directions / Commentary
hile the first five Delphi versions arrived at yearly intervals, we had to wait two years for Delphi 6. The reason
for the delay can be expressed in a single word Kylix. Borlands new cross-platform strategy involves a
close relationship between the new Linux development environment and Delphi. Kylix and Delphi have a common
user interface, but more importantly, they share a new group of components called CLX (pronounced clicks). These
cross-platform components make it possible to use the same code to compile applications for Windows with Delphi
or Linux with Kylix. Therein lies Delphi 6s greatest strength: the possibility of developing Windows applications that
can be easily ported to Linux, simply by recompiling in Kylix. Thus, I regard the Delphi 6/Kylix 2 combination as
another great Borland masterpiece, comparable to Borland Pascal 7, its other multi-platform environment.
Enhanced IDE and expanded Component palette. Delphi 6
shares two important qualities with each of the previous versions: enhancements to the IDE to increase productivity and new
components to create cutting-edge applications. For Delphi 6, the
latter is headlined by the new CLX, cross-platform components,
but theres much more. Theres increased support for XML and
XML-related technologies, such as the Document Object Model.
When the new XML support was previewed at the recent Borland
conference, the audience reaction was particularly appreciative.
For a complete overview, read Cary Jensens Delphi 6 article in
Delphi Informants July 2001 issue (http://www.delphizine.com/
features/2001/07/di200107cj_f/di200107cj_f.asp).
Ill limit the enhanced components discussion here to ActionManager. Among other things, the enhanced ActionManager gives you a
centralized means of controlling the various user actions that drive
applications. It also makes it possible for users of applications to
have that same control. Weve all seen applications that allow users
to modify toolbars and menus. With the new ActionManager and
its related components, you can easily add this modern functionality
to your applications. Please see Bill Todds Take Action article in
the April 2002 issue of DI for details (http://www.delphizine.com/
features/2002/04/di200204bt_f/di200204bt_f.asp).
Delphi 6 is impressive and it opens up a whole new world of possibilities, from cross-platform development to increased control over
the user interface. Still, an important question remains for many
developers: Should I upgrade?
In November 2001, I gave a talk on building code-generating Delphi
Experts to the Indianapolis Delphi Users Group (IDUG). I asked
how many people present were using Delphi 6, but only a few raised
their hands. Clearly another question is being pondered by many
developers, Should I upgrade to Delphi 6 now? While I cannot
offer a definitive answer, I can suggest some possible criteria. Multiplatform development needs to be at the top of the list. If youre
planning to develop applications that will run on both Windows
and Linux platforms, I say, What are you waiting for? Similarly, if
you require cutting-edge Internet (i.e. Web Services) and database
development tools, then Delphi 6 (especially the Enterprise Edition)
deserves serious consideration. On the other hand, if your development needs are more modest and youre comfortable with your cur40 August 2002 Delphi Informant Magazine
rent version of Delphi, then it might make sense for you to remain
with that product.
Up to this point, Ive focused on what Delphi 6 means to individual
developers, but lets take a larger view and consider Delphi in the
context of the company that makes it and the developer base that
depends upon it.
Delphi, a Borland barometer? With Borlands success closely wed to
Delphis success, the flagship product can be considered a barometer
indicating the companys health. Several years ago, when Delphi 4 was
released, the company was not in the best shape financially, and many of
its developer customers had questions concerning its vision and priorities. When Borland released Delphi 4, there were some rather troubling
bugs, the most infamous of which was the ItemIndex-bug in
TCustomListBox, as I discussed in a column at the time. Fortunately,
clever developers came up with a work-around even before Borland
released its own fix. Considering the larger problem, I pointed out in the
column that the consensus among many I spoke with at [the annual]
Conference was simply that Delphi 4 was released too soon. There needed
to be more rigorous testing to ensure that this essential tool mission
critical for so many developers was as bug-free as possible. Even at the
cost of delaying the release for a month while beta testing continued.
An important question to ask is, Did Borland learn any lesson
from this? Ill share some evidence that suggests they did. To begin
with, they were willing to acknowledge the mistake, which is always
the first step before taking corrective action. I remember a Borland
speaker at the 2000 conference posing this question to the audience,
When should we release the next version of Delphi? Someone in
the audience shouted, Now!, but the speaker was prepared for that
kind of impatience. He said, Well release it when its ready, which
turned out to be a year later.
Theres further evidence of Borlands increased commitment to quality control. As with previous versions, Borland has released a couple
of patches with Delphi 6 that fixed small problems and provided new
or enhanced functionality. Unfortunately, the first patch also introduced some new bugs. Borland realized it immediately, informed
its user base, withdrew the patch, and had a new patch (minus the
bugs) available within a few days. Many of you are probably aware
of all of this, especially if you subscribe to the various Delphi lists or
File | New
newsgroups. Heres something you may not know: Before releasing
the second patch, Borland invited its cadre of beta testers to resume
active duty and test the new patch before it was released. To me, this
shows that Borland has learned its lesson and is more committed
than ever to providing its customers with a tool in which they can
place their full confidence.
So, should you upgrade? I agree completely with Jensens assessment
that Delphi 6 represents the most significant upgrade to Delphi
since its release. More than the IDE enhancements and new components, I see Delphi 6s quality and cross-platform capabilities as its
strongest features. Worth the wait? Yes, indeed!
To get the most out of Delphi 6, you need to fully understand its
new features. There have been many articles in this magazine that
have exposed the information, but there are also some excellent new
Delphi books. Next month, well take our annual visit to the Delphi
Bookshelf.
Alan C. Moore, Ph.D.
Alan Moore is a professor at Kentucky State University, where he teaches music theory
and humanities. He was named Distinguished Professor for 2001-2002. He has
been named the Project JEDI Director for 2002-2003. He has developed educationrelated applications with the Borland languages for more than 15 years. Hes the
author of The Tomes of Delphi: Win32 Multimedia API (Wordware Publishing, 2000)
and co-author (with John Penman) of an upcoming book in the Tomes series on
Communications APIs. He also has published a number of articles in various technical
journals. Using Delphi, he specializes in writing custom components and implementing multimedia capabilities in applications, particularly sound and music. You can
reach Alan on the Internet at acmdoc@aol.com.