On The Cover: October 2002, Volume 8 Number 10
On The Cover: October 2002, Volume 8 Number 10
On The Cover: October 2002, Volume 8 Number 10
ON THE COVER
5
First Look
26
Greater Delphi
FEATURES
REVIEWS
11
33
CodeRush 5 and 6
37
Abbrevia 3
DEPARTMENTS
16
Delphi at Work
22
Delphi Tools
40
Symposium
Borland Makes News, Deals, Waves
Recently, I was wandering through the local Borders. Nothing unusual
there; I tend to haunt bookstores. What was unusual was that Borland
CEO, Dale Fuller, caught my eye or at least a picture of him did.
There he was, dressed in black as always, looking stylish on the cover
of Fast Company magazine. The headline screamed BACK IN THE
BLACK and promised to describe How You Can Get on the Road to
Recovery. Exciting stuff!
Why? It was the first time I had seen Borland mentioned in a positive
light in a magazine on a newsstand (other than in this magazine) since
well since I cant remember. By the way, you can check out the
article, Borland Software: Back in the Black by Linda Tischler, at
http://www.fastcompany.com/online/60/borland.html. Among other
things you get Fullers frank appraisal of Borlands state when he first
took the reins: [Borland] wasnt on the ropes, it was hanging by a rope.
It wasnt even still twitching. It also chronicles his sharp strategy for
getting 125 million dollars from Microsoft.
As an aside, I could not stifle a rueful smile at this quote from investment analyst, Audrey Snell, senior vice president and codirector of
research at Brean Murray & Co.: I knew that they had great products
and a large installed user base, but they had also had lousy management
for a long time. It takes real talent to run a software company into the
ground, because youre dealing with a perfect business model: 85% gross
margins, 30% operating margins, 20% net margins, tons of free cash
flow. You have to be really and truly asleep at the switch to lose that.
Snell now rates Borland as ...a strong buy ... It has correctly identified
three of the major trends in the industry for the next 10 years: the growth
of wireless, the importance of cross-platform development, and the
development of Web services to facilitate e-commerce. Those could be
gigantic businesses.
For longer than I care to think about, Borland had been off the radar
of the technical press, or any press for that matter. The last time there
was a flurry of coverage was when then-CEO, Del Yocam, renamed the
company to Inprise. All the propellerhead pundits jumped in to say what
a bad idea that was, and how Borland er, Inprise was doomed. And
they were right; Inprise was going nowhere fast. I used to joke (again,
ruefully) that Inprise was a fitting name because it stood for Inept Enterprise. The once proud and mighty Borland was at its nadir.
Thankfully, things have changed dramatically. Dale Fuller has Borland not
only back in the black, but on the right track as well. Borland is making
news again, and the news is good. Take these articles for instance: Borland,
IBM set bundles for developers by Margaret Kane (http://news.com.com/
2100-1001-954322.html), and Borland, BEA shake hands on Java by
Wylie Wong (http://news.com.com/2100-1001-949713.html). Both are
from CNET Networks, Inc. The only deals discussed by previous Borland
execs were ones involving sale of the company (remember the Corel
fiasco?). Happily, this is all well in the past; Fuller is making bold strategic
moves and the media are taking note.
Borlands canny early embrace of Microsofts .NET initiative provides further cause for good press. A case in point is another CNET
piece by Wylie Wong, Borland to wield tools against Microsoft
(http://news.com.com/2100-1001-954958.html). In it, Wong
describes Borlands Galileo project the as-yet-unnamed Delphi
for .NET product, set to roll out in the first quarter of next year.
In brief, under Dale Fullers leadership, Borland is raising its profile
and looking good.
Thanks for reading.
Delphi
T O O L S
New Products
and Solutions
Book Picks
.NET Security
Jason Bock, Pete Stromquist, Tom
Fischer, and Nathan Smith
Apress
ISBN: 1-59059-053-8
Cover Price: US$44.95
(310 pages)
www.apress.com
Windows XP in a Nutshell
David A. Karp, Tim OReilly,
and Troy Mott
OReilly
ISBN: 0-596-00249-1
Cover Price: US$29.95
(616 pages)
www.oreilly.com
Delphi
T O O L S
New Products
and Solutions
Book Picks
Web Services Essentials
Ethan Cerami
OReilly
ISBN: 0-672-32060-6
Cover Price: US$59.99
(700 pages, CD-ROM)
www.samspublishing.com
First Look
Delphi 7 Studio
Delphi 7 Studio
Borlands Lucky Number
ince Delphis release in February of 1995, Borland has been relatively consistent
in shipping a new version of Delphi every 12 to 16 months. The notable exception
to this was Delphi 6, which was released almost two years after Delphi 5, in large
part because of the resources Borland committed to creating Kylix, Delphis Linuxenvironment cousin. With Delphi 7 Studio, Borland is back on track. The products
anticipated September release comes 15 months after Delphi 6, despite two releases
of Kylix in the past year.
In this first look, Ill take Delphi 7 Studio out
for a test drive, to examine its updated and new
features. This article is based on a beta version
of Delphi 7 Studio. The actual shipping product
may differ from the copy I reviewed. Ive tried
to report which features appear in which version
of the product, but you may find it helpful to
refer to the product-feature matrix available from
Borlands Delphi site at http://www.borland.com/
delphi/index.html.
First Look
displays a list of symbols, such as variables,
methods, and properties that are in scope
of your active cursor, permitting you to
select from the list instead of typing the
entire symbol reference. With Delphi 7
Studio, you can customize the colors of
the various symbol elements that appear
in this list.
Updated IDE
The IDE has
been tweaked
to incorporate a
small but welcome
collection of new
features. One of
the more obvious
is the updated
look, incorporating
XP-style colors in
its menus. Another
little update
will please those
developers who are
tired of working
with cramped
Component
Figure 2: The Components dialog box.
palettes: A new
drop-down list
appears when a page of the Component palette contains more
components than can be displayed at one time (see Figure 1).
The components that otherwise would not be visible on the Indy
Clients page of the Component palette are displayed using this
drop-down list.
Another updated feature is available in the Components dialog box,
shown in Figure 2. You display this dialog box by selecting View |
Component List from Delphis main menu. Now, you can select a
range of consecutive components by selecting the component at the
beginning of the range and then S-clicking the last one in the
range. Or, you can select or deselect two or more non-contiguous
components by C-clicking them. After selecting two or more
components from the component list, clicking Add to form places
those components on the current form, frame, or data module.
Some of the biggest and most welcome additions to the IDE
are found in the Code Insight feature of the Code editor. Lets
consider code completion first. The code-completion feature
6 October 2002 Delphi Informant Magazine
First Look
licenses to deploy applications that use
DataSnap components to communicate
between two or more machines.
Database Updates
With this release, Borland is officially deprecating Borland SQL
Links for Windows, the native-language drivers that Borland
Database Engine (BDE) users can use to access remote database
servers. In short, Borland will no longer update its existing SQL
Links for Windows drivers. This will affect you only if you are
using SQL Links for Windows now and want to upgrade your
database server to a version not supported by the current version
of SQL Links for Windows. If that happens, youll have to fall
back on one of Delphis other client-server data options, such as
dbExpress, ActiveX Data Objects (ADO), InterBase Express, or a
third-party solution.
As for additions, there are several associated with database development. For starters, Delphi 7 Studio now includes several updated
dbExpress drivers and one new driver. The updated drivers are for
DB2 7.2, Informix SE, InterBase 6.5, MySQL 3.23.49, and Oracle
9i. The new dbExpress driver is for SQL Server 2000.
One of the components that relies on dbExpress drivers, SQLClientDataSet, is being replaced by a new, lightweight component
named SimpleDataSet. (SQLClientDataSet is still available, but
does not appear on the Component palette by default.) To put
it plainly, the SimpleDataSet component has a better design
than SQLClientDataSet, and developers who dont need all the
features the combination of SQLConnection, SQLDataSet,
DataSetProvider, and ClientDataSet offers will be pleased with
this new component.
On the DataSnap front, Borland has added a new connection
component named SOAPConnection. Using this component,
DataSnap client applications can use DataSnap servers
implemented as a Web Service.
Those who use the Enterprise and Architect versions of Delphi
7 Studio will be pleased to learn that these products include a
full deployment license for DataSnap application servers. With
these versions, it will no longer be necessary to obtain additional
7 October 2002 Delphi Informant Magazine
First Look
First Look
to interact seamlessly with code compiled with any other CILcompliant compiler. A beta edition of the .NET version of the runtime library is included with the preview compiler. Borland hopes
to ship a .NET version of the VCL sometime later this year, taking
Delphi developers one step closer to 100 percent .NET compatibility.
For the time being, Delphi can import existing .NET classes as
COM objects. Similarly, managed assemblies can use Delphi 7
compiled objects, also through COM interfaces.
And Professional edition users are going to love this news: Full
Web Service support for building clients and servers can be found
in Delphi 7 Studio Professional. This is true for both the Delphi
and Kylix products. Thank you, Borland!
First Look
document object model (DOM) support; XML transformations;
TeamSource for source-code version control; language-translation
tools; and ModelMaker, a unified modeling language (UML) design
tool. (See the August 2002 issue of Delphi Informant Magazine for a
recent review of ModelMaker.) The Enterprise edition of Delphi is the
second-most-popular version, and it provides a high-end solution for
almost all your development needs.
With Delphi 7 Studio, Borland is releasing a new, high-end
edition called Delphi 7 Studio Architect. It contains everything in
the Enterprise edition, plus Bold for Delphi. Bold for Delphi is a
development framework that generates true business objects based
on UML class diagrams. (For a recent review of Bold for Delphi,
see the July 2002 issue of Delphi Informant Magazine.) With
ModelMaker, Bold for Delphi gives Delphi 7 Studio Architect
users a design-to-deployment solution for building applications
based on UML class diagrams. This approach to development
is commonly called model-driven architecture (MDA), and it
represents state-of-the-art software development.
Conclusion
Delphi 7 Studio is an important new release. With many updates
and enhancements, including support for XP themes and .NETrelated compiler warnings, this release is going to be hard to resist.
I think Simon Thornhill, vice president and general manager of
the RAD Products Group at Borland, said it best: With Delphi
7 Studio, Borland continues to give developers the means to
begin moving to the future of .NET without abandoning their
past. Keep this in mind the next time you speak to a Visual Basic
developer who is going to have to relearn VB or adopt a completely
new language, such as C# or even Delphi. Windows and Linux
executables, Web Service extensions, Web Services, and .NET soon
will all be available using the Delphi language. Delphi continues to
be the right choice for modern software development.
By Bill Todd
Choosing a Database
Checklists for Selecting the Best Database for a Task
common question among Delphi developers is: Which database should I use?
It would be an easier question to answer if there werent so many choices. This
article examines how to determine which database is right for you and your application. At the end of this article I hope youll have a checklist that you can use to make
a good choice based on your needs.
I was going to write this article without mentioning any database by name, but found it too
difficult. When I do mention a particular product,
however, its as an example only. If you look at the
significant players in all segments of the database
market, there are no bad products. Instead, there
is a variety of products with different features. A
particular feature may be an advantage for one type
of application and a disadvantage for another.
The Basics
Does the database support multiple simultaneous users? If the application is multi-user, you
should eliminate all desktop databases from your
list of candidates and focus on database servers. Client-server applications reduce network
traffic and provide better performance with
many simultaneous users. Most importantly,
the chances of a system crash causing a corrupt
database are much lower with a database server,
particularly if the PC that hosts the database software is dedicated to that task, has an
uninterruptible power supply, and is physically
secure. SQL database servers are available in
every price range, including free, so you have no
reason not to use one.
Character
Description
Atomicity
Consistency
The database will always be left in a consistent state. If the database server crashes, all
active transactions will roll back automatically when the server restarts, so the state of
the database will be as it was before any of
the active transactions began.
Isolation
Durability
locking pages or even entire tables not individual rows. Obviously, this can severely limit concurrent access to data.
What lock types does the database use, and how do they coexist? When considering a locking-model database, it is critical to
understand how locks conflict with one another. What happens
when one user places one type of lock on a row, page, or table,
and a second user tries to place the same or a different type
of lock on the same object? The best way to understand lock
conflicts is with a lock-conflict table that shows all the lock types
down the left side and across the top. Each cell in this grid would
represent an attempt to place two locks simultaneously, and the
cells would contain explanations of what happens when the locks
are attempted. This may sound like a trivial task, but it isnt. For
example, the last time I looked at IBMs DB2, it had 12 different lock types. That means you have 144 different combinations
of locks to consider! Even worse, if you want to understand what
conflicts you may encounter, you need to understand which lock
types your application will use at what times.
Transactions
Does the database support transactions? Be careful here. Some
databases claim to support transactions when they really dont. A true
transaction must exhibit four characteristics, sometimes called the
ACID test (see Figure 1).
What transaction-isolation levels does the database support? Again,
you need to be careful in evaluating transaction-isolation levels. Some
database vendors use transaction-isolation levels that dont exactly
match those defined by the American National Standards Institute
(ANSI). For example, InterBases snapshot transaction-isolation level
provides the same consistent view of the data as ANSI serializable
isolation, but doesnt guarantee that a sequential order of execution
of concurrent transactions will produce the same result. To add to
the confusion, ANSI-standard repeatable-read isolation may not
give you the behavior you expect. Figure 2 shows the ANSI-standard
transaction-isolation levels.
What happens when the transaction log gets full?
If the database uses a transaction log, what happens if it gets full?
Will the transaction log expand dynamically? If not, what do you
have to do to increase the size of the transaction log?
Can the log size be increased while the database is in use?
Description
Read uncommitted
Read committed
Repeatable read
Serializable
Can you place the transaction log on a separate drive from the
database files so that both the database and the log will not be
lost if a single hard drive fails?
SQL Implementation
Does the database support triggers? Triggers, like stored procedures, are functions written in the databases procedure and trigger language. But triggers are executed automatically when data is
inserted, deleted, or updated. Check for features such as:
Hardware Failure
Does the database support replication? If the database supports
replication, does it support synchronous replication, asynchronous replication, or both? Synchronous replication updates the
target database instantly when the source database changes. If
synchronous replication is used, what happens if the connection
to the target database is lost? Will you be unable to make any
changes to the source database? Will changes be logged and replicated when the target database comes back online?
Asynchronous replication logs changes in the source database and replicates them to the target database later. The disadvantage of asynchronous replication is that the target database is always behind the source
database by some period of time. The advantage is that you dont need
a permanent connection between the source and target databases.
Note that for databases that dont support a separate transaction
log, replication may be the only way to provide up-to-the-minute
recovery if a catastrophic hardware failure occurs.
What options are available for backing up the database?
Can the database be backed up while its in use?
14 October 2002 Delphi Informant Magazine
Other Features
There are other important questions you should include on your
checklist. They may include the following:
Can you import and export data in XML format?
What other data formats do you need to import and export
routinely? Does the database support them?
What tools are provided for importing and exporting data?
Are gateways available for other databases with which you
need to exchange data?
Does the database interface to the development tools you use?
Is there an ODBC driver?
Is there an OLE DB driver?
Is there a dbExpress driver?
Is there a native component suite for Delphi?
Are there case tools that support this database?
Conclusion
The key to choosing the right database for your project or organization is to first create a thorough definition of your requirements.
While not exhaustive, this checklist gives you a place to start. As
you define your requirements, alter this list to make it match your
needs, and youll have a useful tool for comparing products.
Bill Todd is president of The Database Group, Inc., a database consulting and
development firm based near Phoenix. He is co-author of four database programming books, author of more than 90 articles, a contributing editor to Delphi
Informant Magazine, and a member of Team B, which provides technical support
on the Borland Internet newsgroups. Bill is a nationally known trainer and is a frequent speaker at Borland Developer Conferences in the United States and Europe.
He has taught Delphi programming classes across the country and overseas.
Readers may reach him at [email protected].
Delphi at Work
XML / DOMs / Interfaces / Delphi 6
By Keith Wood
ast month, I introduced the concept of XML building blocks components designed to
work with XML documents expressed as Document Object Models (DOMs). Theyre built
around two basic interfaces: IXMLProducer defines components that generate DOMs for
use by other components; and IXMLConsumer defines components that accept an existing
DOM and read, alter, or otherwise process it.
By implementing both interfaces in the one component, you can create chains of objects that make
small, well-defined contributions to the XML processing. Then, you can combine these in different
ways to customize the functionality of a particular
application. The components supply published
properties and so can be connected and configured
at design time. That leaves a single call to the first
producer to start the entire sequence.
Database to XML
Delphi at Work
The TXBBSQL component extends TXMLBuildingBlock and adds
properties (see Listing One on page 20) to identify the database with
which to work (DatabaseName) and the SQL query to submit (SQL).
Additional properties let you specify the names of the top-level (TagName) and record-level (RecordTagName) elements, and indicate how
the data is presented (FieldFormat), as elements or as attributes. The
Consumer property is promoted to published visibility so you can
connect this component to another one for further processing of the
generated XML document.
In the CreateDocument method (required for the IXMLProducer
interface), a TQuery object is created, initialized with the database
name and query, and opened. Its fields are examined, and any memo
fields are assigned an event handler to return their content properly
(usually, DisplayText returns the class name for these fields). For each
record, you create a new DOM element and add it to the document.
Then, for each field, you create an element and text, an element and
attributes, or just attributes, depending on the format requested.
When completed, the DOM is sent to any consumer registered with
the class. Figure 1 shows the results of querying the Biolife database
by piping the output of the TXBBSQL component into a tree view.
Each field is presented as a separate sub-element.
Text to XML
Straight text files are another common source of material for XML
documents. The TXBBTextFile class derives from TXMLBuildingBlock
(see Figure 2). TXBBTextFile allows you to set the name of the file to
read (FileName), and allows you to set whether the content is enclosed in
a CDATA section in the XML (AsCDATA). Inherited properties are published to make them available: TagName for the top-level element name,
OnTagCreate to let you modify that element, and Consumer to pass on
the new document for further processing.
You override the CreateDocument method to read in the text from
the nominated file and add it as the text content (enclosed in a
CDATA section if requested) of the top-level element in a new
document. The name of the original file is added as an attribute
of the main element for future reference. Then the resulting XML
document is sent on to the registered consumer of this component.
Figure 3 shows the outcome of wrapping a text file in XML and
displaying it in a Memo component.
Delphi at Work
extended so it can contain multiple fields,
which are then expressed as child elements or
attributes within the DOM.
Each field contains a name and a format
separated by an equals sign (=), and vertical bars
(|) separate multiple fields. To create attributes,
the name must start with an at symbol (@). If
no fields are present, the converted value just
becomes the text for the time-stamp element
itself. Otherwise, attributes or child elements are
created with their text content set to the specified part of the current date and time. Figure 4
shows the results of adding a time stamp to the
text file loaded earlier. This time, its presented
in a tree view, with the Format value being
year=yyyy|month=MM|day=dd.
Figure 4: The results of adding a time stamp.
Delphi at Work
{ Pass DOM document to several consumers. }
TXBBFork = class(TXMLBuildingBlock)
private
FConsumers: TXBBConsumerCollection;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure DocumentReady(Document: IDOMDocument);
override;
published
property Consumers: TXBBConsumerCollection
read Fconsumers write FConsumers;
end;
{ Copy document and pass it on to each consumer. }
procedure TXBBFork.DocumentReady(Document: IDOMDocument);
var
Index: Integer;
begin
for Index := 0 to FConsumers.Count - 1 do
if Assigned(FConsumers.Items[Index].Consumer) then
FConsumers.Items[Index].Consumer.DocumentReady(
Document.CloneNode(True) as IDOMDocument);
end;
through Delphi and the Object Inspector. The items have a Consumer
property, just like the basic building blocks, and a Name property
thats simply for reference purposes at design time. If you need to add
items at run time, you can use the following code:
of the article for details on downloading it) lets you experiment with
the XML building blocks. The left side of the form shows a wiring
diagram for the building blocks. Just check off the ones you want to
use. The merge and fork components are incorporated automatically
as necessary. Components at the top are the XML producers, those in
the middle modify a DOM that is passing through, and those at the
bottom are the ultimate consumers of the DOM. Several components appear as buttons on the form and have properties that can
be altered at run time. Clicking a button brings up an appropriate
dialog box for the TXBBSQL component, as shown in Figure 8.
Experiment with the combinations to see how the building blocks work
together. A sample XML document (movie-watcher.xml) is supplied
for loading, along with its Document Type Definition and a couple of
appropriate XSL transformations. Click the Go button to start a run after
selecting the components to use and setting their properties.
Conclusion
The XML building-block components are designed to make it easier
to work with XML documents in DOM format. Theyre based on two
interfaces that generate DOMs and then work with them. When combined in the one component, these interfaces let you construct chains of
components that create a DOM, modify it, and then present the results.
Last month, you saw components that:
performed the basic loading of an existing XML document
applied an XSL transformation to a DOM
wrote out a DOM to a file or stream
In this article, you see components that:
create DOMs from alternate data sources
modify the DOM by adding a time-stamp element
merge several parts to form a new document
create copies of a document for separate, subsequent processing
Next month, Ill finish up with more XML building blocks that present
the contents of a DOM in GUI controls. The data can be easily sent to
a tree view, a string grid, a memo field, and a Web browser. Its all just a
few mouse clicks away with these plug-and-play components.
xbbFork.Consumers.Add.Consumer := xbbWriter;
Demonstration
The demonstration program that comes with this article (see the end
19 October 2002 Delphi Informant Magazine
The files referenced in this article are available on the Delphi Informant
Magazine Complete Works CD located in INFORM\2002\OCT\
DI200210KW.
Delphi at Work
Keith Wood hails from Brisbane, Australia. He is a consultant using Delphi
and Java. He started using Borlands products with Turbo Pascal on a
CP/M machine. His book, Delphi Developers Guide to XML, covers many
aspects of XML from a Delphi point of view. You can reach him via e-mail at
[email protected].
{ Create new DOM from SQL query. The DatabaseName and SQL
properties retrieve data which is then made into an XML
document. The top-level tag is named according to the
TagName property, or from the DatabaseName if blank. Each
row from the query becomes an element under this, using
RecordTagName as its name, or 'record' if blank. Fields
from the query then become child elements of the record,
with names taken from field name, and contents as text or
CDATA section (if they contain '<' or '>') nodes. }
TXBBSQL = class(TXMLBuildingBlock)
private
FDatabaseName: string;
FFieldFormat: TXBBFieldFormat;
FOnRecordTagCreate: TXBBRecordTagCreateEvent;
FRecordTagName: string;
FSQL: TStrings;
procedure GetText(Sender: TField; var Text: string;
DisplayText: Boolean);
public
constructor Create(AOwner: TComponent); overload;
override;
constructor Create(AOwner: TComponent;
const TagName: string); reintroduce; overload;
constructor Create(AOwner: TComponent;
const DatabaseName: string; const SQL: TStrings;
const TagName: string = ''); reintroduce; overload;
destructor Destroy; override;
procedure CreateDocument; override;
published
property Consumer;
property DatabaseName: string
read FDatabaseName write FDatabaseName;
property FieldFormat: TXBBFieldFormat read FfieldFormat
write FFieldFormat default xfText;
property RecordTagName: string
read FRecordTagName write FRecordTagName;
property SQL: TStrings read FSQL write FSQL;
property TagName;
property OnRecordTagCreate: TXBBRecordTagCreateEvent
read FOnRecordTagCreate write FOnRecordTagCreate;
property OnTagCreate;
end;
{ Run query against database and convert results to XML. }
procedure TXBBSQL.CreateDocument;
var
Document: IDOMDocument;
RecordElement, FieldElement: IDOMElement;
Query: TQuery;
Index: Integer;
RecTagName, FieldName, FieldValue: string;
begin
if (DatabaseName = '') or (SQL.Text = '') then
raise EXBBException.Create(
'Missing database name or SQL');
RecTagName := IfThen(
RecordTagName <> '', RecordTagName, 'record');
Document := NewDocument(
IfThen(TagName <> '', TagName, DatabaseName));
Query := TQuery.Create(nil);
with Query do
try
DatabaseName := Self.DatabaseName;
SQL
:= Self.SQL;
Open;
for Index := 0 to FieldCount - 1 do
if Fields[Index] is TMemoField then
Fields[Index].OnGetText := GetText;
while not Eof do begin
{ Create an element for each record. }
RecordElement := IDOMElement(
Document.DocumentElement.AppendChild(
Document.CreateElement(RecTagName)));
if Assigned(OnRecordTagCreate) then
OnRecordTagCreate(Self, RecordElement, Query);
for Index := 0 to FieldCount - 1 do begin
FieldName := Fields[Index].DisplayName;
FieldValue := EscapeText(
Fields[Index].DisplayText);
case FieldFormat of
xfText:
{ And then a sub-element for each field. }
begin
FieldElement := IDOMElement(
RecordElement.AppendChild(
Document.CreateElement(FieldName)));
FieldElement.AppendChild(
Document.CreateTextNode(FieldValue));
end;
xfElement:
{ Add field values as attributes on
separate elements. }
begin
FieldElement := IDOMElement(
RecordElement.AppendChild(
Document.CreateElement(FieldName)));
FieldElement.setAttribute(
value, FieldValue);
end;
xfAttributeOnly:
{ Add field values as attributes
on the record element. }
RecordElement.setAttribute(
FieldName, FieldValue);
end; // case FieldFormat...
end; // for Index := 0 to FieldCount 1...
Next;
end; // while not Eof...
Close;
DocumentReady(Document);
finally
Free;
end;
end;
{ Retrieve contents of a memo field. }
procedure TXBBSQL.GetText(Sender: TField; var Text: string;
DisplayText: Boolean);
begin
Text := TMemoField(Sender).AsString
end;
Delphi at Work
<day>07</day></timestamp>.
Prefix a name with '@' to make it an attribute instead.
For example, a format of '@year=yyyy|@month=MM|@day=dd'
creates the following structure:
<timestamp year="2002" month="03" day="07"/>. }
TXBBTimestamp = class(TXMLBuildingBlock)
private
FFormat: string;
FInsertAtStart: Boolean;
procedure SetFormat(const Value: string);
protected
function ProcessDocument(const Document: IDOMDocument):
IDOMDocument; override;
public
constructor Create(AOwner: TComponent;
const Format: string = ''; const TagName: string = '');
reintroduce; overload;
published
property Consumer;
property Format: string read FFormat write SetFormat;
property InsertAtStart: Boolean
read FInsertAtStart write FInsertAtStart;
property TagName;
end;
{ Add a timestamp element (or subtree) to the document. }
function TXBBTimestamp.ProcessDocument(
const Document: IDOMDocument): IDOMDocument;
var
Element: IDOMElement;
DateTime: TDateTime;
{ Format consists of several fields to generate multiple
date parts beneath the timestamp element. }
procedure AddSubFormats(MainElement: IDOMElement);
var
Index: Integer;
Name, SubFormat, WorkFormat: string;
begin
WorkFormat := Format;
repeat
Index := Pos('=', WorkFormat);
if Index = 0 then
Exit;
Name := Copy(WorkFormat, 1, Index - 1);
Delete(WorkFormat, 1, Index);
Index := Pos('|', WorkFormat);
if Index = 0 then
Index := Length(WorkFormat) + 1;
SubFormat := Copy(WorkFormat, 1, Index - 1);
Delete(WorkFormat, 1, Index);
if Name[1] = '@' then
MainElement.SetAttribute(Copy(Name, 2,
Length(Name)), FormatDateTime(SubFormat, DateTime))
else
MainElement.AppendChild(Document.CreateElement(
Name)).AppendChild(Document.CreateTextNode(
FormatDateTime(SubFormat, DateTime)));
until WorkFormat = '';
end;
begin
DateTime := Now;
Element := Document.CreateElement(IfThen(TagName <> '',
TagName, 'timestamp'));
if Pos('=', Format) = 0 then
Element.AppendChild(Document.CreateTextNode(
FormatDateTime(Format, DateTime)))
else
AddSubFormats(Element);
if InsertAtStart then
Document.DocumentElement.InsertBefore(
Element, Document.DocumentElement.FirstChild)
else
Document.DocumentElement.AppendChild(Element);
Result := Document;
end;
By Shane Miller
Creating a Class
You can use what youve done so far to create a class that will hold
information about the current user logged on to the PC. To start,
create a class named TCurrentUserInfo (shown in Figure 5). Your
main unit will create an instance of this class; then it can query
its properties.
The properties of this class are set in the FillValues procedure.
FillValues gets the current user name of the person logged on to the
PC (code snippet shown in Figure 6), and utilizes that user name in
the query to Active Directory.
The query selects the name, distinguishedName, PrimaryGroupID,
and MemberOf fields from the server, where sAMAccountName is
equal to the user name of the user who is currently logged on to the
PC. The distinguished name holds the path to the user definition.
For example, if a user is created in the organizational unit, HelpDesk,
then that users distinguished name would be something like:
CN=Shane Miller, OU=HelpDesk, DC=domain, DC=com
There are two functions you need to create in order to get the
RootDSE. They are GetDefaultPath and GetObject (shown in
Figure 3). Youll also need to add ActiveX and ComObj to your units
uses clause in order for these functions to work. The GetDefaultPath
function uses the GetObject function to get an instance of IADs. IADs
23 October 2002 Delphi Informant Magazine
Datamodule1.ADOQuery1.Open;
if (not IsEmpty) then begin
fUsername := FieldByName('Name').AsString;
fOrgUnit := GetContainerFromString(
FieldByName('distinguishedName').AsString);
fAccountName := FieldByName('sAMAccountName').AsString;
// Get groups.
MemberOf := FieldByName('MemberOf').AsVariant;
// Get the primary group via the primary group token.
Num := FieldByName('PrimaryGroupID').AsInteger;
Conclusion
Accessing Active Directory via ADO is a very convenient way of
getting information you need. Through examples on Microsofts site,
you should be able to figure out how to pull any information you
need for any Active Directory object.
The project referenced in this article is available on the Delphi Informant
Magazine Complete Works CD located in INFORM\2002\OCT\
DI200210SM.
Shane Miller works at St. Vincent Hospital in Green Bay, WI, supervising the
development group in the Information Services department. He develops mainly
in Delphi, Kylix, PHP, and C++ and participates in a number of open-source
projects, such as Lazarus (http://lazarus.freepascal.org). Readers may reach Shane
via e-mail at [email protected].
Greater Delphi
Object Picker / Active Directory / COM / Delphi 6
hen Active Directory was introduced in Windows 2000, Microsoft needed a new
dialog box to allow selections from the Active Directory, similar to the dialog
boxes provided for file selection, printer selection, and so forth. The resulting dialog
box is the object picker.
Most of Microsofts applications, such as the
Active Directory Users and Computers tool, use
this new dialog box in one way or another, so
its likely youve already seen it. The good news
is that the object picker dialog box is exposed
through the Windows API and is documented
fully, so you can and should use it. This
article introduces the object picker dialog box
and demonstrates how you can use it in your
own applications. It assumes youre familiar
with Active Directory and COM programming.
Object Picker
Object picker is a very versatile dialog box. You
can program it to allow selection of most Active
Directory objects, such as users, computers,
and groups, as well as selections from the local
computer, e.g. locally defined user accounts. In
addition, the object picker has many options
that allow you to fine-tune its behavior. These
options include enabling or disabling multiple
selection, and restricting the scope from which
the user can choose objects. Figure 1 shows the
object picker in action, for selection of users and
groups from my computer.
The Look-in drop-down list allows you to set the
scope from which objects can be selected. You
can program the object picker to allow selections from only a single scope or from multiple
scopes. You can think of a scope as a sub-tree in
the Active Directory object hierarchy, such as
the global catalog, the domain, the workgroup,
or a computer. In Figure 1, the scope is set to
DELPHI, which is the local computer. Therefore, the object picker displays only those objects
that are defined on the local computer.
Greater Delphi
IDsObjectPicker = interface (IUnknown)
['{0c87e64e-3b7a-11d2-b9e0-00c04fd8dbf7}]
// Sets scope, filter, etc. for use with next
// invocation of dialog box.
function Initialize(const pInitInfo: DSOP_INIT_INFO):
HRESULT; stdcall;
// Creates the modal DS Object Picker dialog box.
function InvokeDialog(hwndParent: HWND;
out ppdoSelections: IDataObject): HRESULT; stdcall;
end;
var
// The Object Picker COM object.
ObjPicker: IDsObjectPicker;
begin
// 1. Initialize COM.
CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
// 2. Create the Object Picker object.
if SUCCEEDED(CoCreateInstance(CLSID_DsObjectPicker, nil,
CLSCTX_INPROC_SERVER, IID_IDsObjectPicker,
ObjPicker)) then begin
// Use the Object Picker here.
end;
// 12. Uninitialize COM.
ObjPicker := nil;
CoUninitialize;
end;
TDsOpInitInfo = record
pwzTargetComputer: PWSTR;
cDsScopeInfos: ULONG;
aDsScopeInfos: PDSOP_SCOPE_INIT_INFO;
flOptions: ULONG;
end;
1..N
TDsOpScopeInitInfo = record
flType: ULONG;
flScope: ULONG;
FilterFlags: DSOP_FILTER_FLAGS;
end;
TDsOpFilterFlags = record
Uplevel: DSOP_UPLEVEL_FILTER_FLAGS;
flDownlevel: ULONG;
end;
TDsOpUpLevelFilterFlags = record
flBothModes: ULONG:
flMixedModeOnly: ULONG;
flNativeModeOnly: ULONG;
end;
Initialization
Now that you have an interface for the object picker object, you
must initialize it. In this context, initialization is the means by
which you tell the object picker about the scopes, filters, and
various other options. Guess what? You use the Initialize method
to do this. The Initialize method takes only a single parameter
of type TDsOpInitInfo. This record contains various levels of
nested records and is rather complex. To help you understand
the big picture before diving into the details, Figure 4 outlines
the relationship between all these records. The declaration of
the TDsOpInitInfo record is shown in Figure 5. As we examine
TDsOpInitInfo, Ill explain the declaration of the nested records.
Greater Delphi
type
PDSOP_INIT_INFO = ^DSOP_INIT_INFO;
_DSOP_INIT_INFO = record
cbSize: ULONG;
pwzTargetComputer: PWSTR;
cDsScopeInfos: ULONG;
aDsScopeInfos: PDSOP_SCOPE_INIT_INFO;
flOptions: ULONG;
cAttributesToFetch: ULONG;
apwzAttributeNames: PWSTR;
end;
DSOP_INIT_INFO = _DSOP_INIT_INFO;
PCDSOP_INIT_INFO = PDSOP_INIT_INFO;
TDsOpInitInfo = DSOP_INIT_INFO;
PDsOpInitInfo = PDSOP_INIT_INFO;
The cbSize member is used for versioning and should be set to the size,
in bytes, of the TDsOpInitInfo structure, using the SizeOf function.
Usually, you will set the pwzTargetComputer to nil, in which case the
object picker defaults to the local computer. However, you can set
it to the name of any computer in the Active Directory. In the latter
case, the object picker dialog box behaves as if it was invoked on the
specified computer to determine the joined domain and enterprise.
This is especially useful when creating a remote administration utility.
The flOptions member can be set to a combination of the following flags:
DSOP_FLAG_MULTISELECT If this flag is set, the user
can select multiple objects. If this flag is cleared, the user can
select only a single object.
DSOP_FLAG_SKIP_TARGET_COMPUTER_DC This
flag determines whether the target computer is included in
the Look-in drop-down list. You should set this flag only if the
target computer is not a domain controller.
I am going to ignore the cAttributesToFetch and apwzAttributeNames
members for now. Ill have more to say about them later.
The two remaining members, cDsScopeInfos and aDsScopeInfos,
are used to specify the scopes and their associated filters. The
aDsScopeInfos field is a pointer to an array of TDsOpScopeInitInfo
records, and cDsScopeInfo specifies the number of elements in
this array. Each element in the array specifies one or more scopes
that appear in the Look-in drop-down list (again, see Figure 1)
and the filter that applies to those scopes. So, each element
describes a location from which objects can be selected, and the
type of objects that can be selected from it. Figure 6 shows the
declaration of the TDsOpScopeInitInfo structure.
28 October 2002 Delphi Informant Magazine
Greater Delphi
type
_DSOP_UPLEVEL_FILTER_FLAGS = record
flBothModes: ULONG;
flMixedModeOnly: ULONG;
flNativeModeOnly: ULONG;
end;
DSOP_UPLEVEL_FILTER_FLAGS = _DSOP_UPLEVEL_FILTER_FLAGS;
TDsOpUpLevelFilterFlags = DSOP_UPLEVEL_FILTER_FLAGS;
PDsOpUpLevelFilterFlags = ^DSOP_UPLEVEL_FILTER_FLAGS;
_DSOP_FILTER_FLAGS = record
Uplevel: DSOP_UPLEVEL_FILTER_FLAGS;
flDownlevel: ULONG;
end;
DSOP_FILTER_FLAGS = _DSOP_FILTER_FLAGS;
TDsOpFilterFlags = DSOP_FILTER_FLAGS;
PDsOpFilterFlags = ^DSOP_FILTER_FLAGS;
Next, initialize the two scopes. The first scope adds the domain to
the Look-in drop-down list and sets a filter to display just users. The
29 October 2002 Delphi Informant Magazine
second scope adds the global catalog (that is, the entire directory)
to the Look-in drop-down list, and sets a filter to display only
security groups. Note that youre specifying all three up-level filters,
so this code will work for all up-level type domains (see Figure 10).
So far, youve set up the scopes. What remains is calling the
Initialize method:
if SUCCEEDED(ObjPicker.Initialize(InitInfo)) then begin
// Display dialog box and process selection.
end;
end;
ObjPicker := nil;
CoUninitialize();
end;
Greater Delphi
Up-level flag
Description
DSOP_FILTER_COMPUTERS
Includes
computer objects
DSOP_FILTER_USERS
Includes user
objects
DSOP_FILTER_CONTACTS
Includes contact
objects
Down-level flag
Description
DSOP_DOWNLEVEL_FILTER_COMPUTERS
Includes
computer objects
DSOP_DOWNLEVEL_FILTER_LOCAL_GROUPS
DSOP_DOWNLEVEL_FILTER_ANONYMOUS
Includes the
well-known
security principal
Anonymous
var
ObjPicker: IDsObjectPicker;
ScopeInitInfo: array [0..1] of TDsOpScopeInitInfo;
InitInfo: TDsOpInitInfo;
DataObj: IDataObject;
begin
CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
if SUCCEEDED(CoCreateInstance(CLSID_DsObjectPicker, nil,
CLSCTX_INPROC_SERVER, IID_IDsObjectPicker,
ObjPicker)) then begin
...
const
ALL_SECURITY_GROUPS =
DSOP_FILTER_DOMAIN_LOCAL_GROUPS_SE or
DSOP_FILTER_BUILTIN_GROUPS
DSOP_FILTER_GLOBAL_GROUPS_SE or
DSOP_FILTER_UNIVERSAL_GROUPS_SE;
// 1st scope, users from enterprise domain.
FillChar(ScopeInitInfo[0], SizeOf(TDsOpScopeInitInfo),0);
ScopeInitInfo[0].cbSize := SizeOf(TDsOpScopeInitInfo);
ScopeInitInfo[0].flType :=
DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN;
ScopeInitInfo[0].FilterFlags.Uplevel.flMixedModeOnly :=
DSOP_FILTER_USERS;
ScopeInitInfo[0].FilterFlags.Uplevel.flBothModes :=
DSOP_FILTER_USERS;
ScopeInitInfo[0].FilterFlags.Uplevel.flNativeModeOnly :=
DSOP_FILTER_USERS;
// 2nd scope, security accounts from global catalog.
FillChar(ScopeInitInfo[1], SizeOf(TDsOpScopeInitInfo),0);
ScopeInitInfo[1].cbSize := SizeOf(TDsOpScopeInitInfo);
ScopeInitInfo[1].flType :=
DSOP_SCOPE_TYPE_GLOBAL_CATALOG;
ScopeInitInfo[1].FilterFlags.Uplevel.flMixedModeOnly :=
ALL_SECURITY_GROUPS;
ScopeInitInfo[1].FilterFlags.Uplevel.flBothModes :=
ALL_SECURITY_GROUPS;
ScopeInitInfo[1].FilterFlags.Uplevel.flNativeModeOnly :=
ALL_SECURITY_GROUPS;
Greater Delphi
// Code to create and initialize the object picker omitted.
if SUCCEEDED(ObjPicker.Initialize(InitInfo)) then
begin
// 6. display dialog box
HR := ObjPicker.InvokeDialog(0, DataObj);
if HR = S_OK then
begin
// 7. User selected one or more objects and clicked
// OK; process the selection here.
end
else if HR = S_FALSE then
begin
// User cancelled the dialog box, no selection.
ShowMessage('Dialog cancelled');
end
else
begin
// An error occured, the user never saw the dialog box;
// raise an exception.
OleCheck(HR);
end;
end;
Figure 12: Invoking the object picker dialog box and testing
the result.
var
Format: TFormatEtc;
Medium: TStgMedium;
SelectionList: PDsSelectionList;
...
Format.cfFormat :=
RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST);
Format.ptd := nil;
Format.dwAspect := DVASPECT_CONTENT;
Format.lindex := -1;
Format.tymed := TYMED_HGLOBAL;
FillChar(Medium, SizeOf(Medium), 0);
Medium.tymed := TYMED_HGLOBAL;
if SUCCEEDED(DataObj.GetData(Format, Medium)) then begin
SelectionList := GlobalLock(Medium.hGlobal);
try
// Do something with the selection list here...
finally
GlobalUnlock(Medium.hGlobal);
ReleaseStgMedium(Medium);
end;
end;
Retrieving Attributes
One of the most common things youll do with the selected
objects is simply retrieve information about them by reading a
number of attributes. The people at Microsoft recognized this
and allow you to perform this action automatically with the
object picker. That means theres no need for additional code
that uses ADSI or LDAP to bind to the objects and query the
desired attributes manually. To see how this works, you need to
reexamine the declaration of the TDsOpInitInfo record (shown
in Figure 5), and look at the two fields we ignored previously:
cAttributesToFetch and apwzAttributeNames.
The apwzAttributeNames field is a pointer to an array of nullterminated Unicode strings that name the attributes to retrieve
for each selected object. The cAttributesToFetch field indicates
31 October 2002 Delphi Informant Magazine
type
PDS_SELECTION = ^DS_SELECTION;
_DS_SELECTION = record
pwzName: PWSTR;
pwzADsPath: PWSTR;
pwzClass: PWSTR;
pwzUPN: PWSTR;
pvarFetchedAttributes: POleVariant;
flScopeType: ULONG;
end;
DS_SELECTION = _DS_SELECTION;
TDsSelection = DS_SELECTION;
PDsSelection = PDS_SELECTION;
PDS_SELECTION_LIST = ^DS_SELECTION_LIST;
_DS_SELECTION_LIST = record
cItems: ULONG;
cFetchedAttributes: ULONG;
aDsSelection: array [0..ANYSIZE_ARRAY-1]
of DS_SELECTION;
end;
DS_SELECTION_LIST = _DS_SELECTION_LIST;
TDsSelectionList = DS_SELECTION_LIST;
PDsSelectionList = PDS_SELECTION_LIST;
Greater Delphi
Name: Domain Admins
ADSPath: GC://sensur.org:3268/CN=Domain Admins,CN=Users,DC=sensur,DC=org
Class: group
UPN:
Name: Marcel van Brakel
ADSPath: LDAP://sensur.org/CN=Marcel van Brakel,CN=Users,DC=sensur,DC=org
Class: user
UPN: [email protected]
const
MaxVariantArray = (MaxInt div SizeOf(OleVariant)) - 1;
type
TOleVariantArray =
array [0..MaxVariantArray] of OleVariant;
POleVariantArray = ^TOleVariantArray;
var
Attributes: array [0..1] of WideString;
DisplayName, EmailAddress: OleVariant;
...
begin
...
// 4. Initialize attributes, request displayname
// and email address.
Attributes[0] := WideString('displayName');
Attributes[1] := WideString('mail');
InitInfo.cAttributesToFetch := 2;
InitInfo.apwzAttributeNames := @Attributes[0];
...
ObjPicker.Initialize(InitInfo);
ObjPicker.InvokeDialog(Handle, DataObj);
...
Assert(SelectionList.cFetchedAttributes = 2);
for I := 0 to SelectionList.cItems - 1 do begin
{$R-}Selection := SelectionList.aDsSelection[I];{$R+}
DisplayName := POleVariantArray(
Selection.pvarFetchedAttributes)^[0];
EmailAddress := POleVariantArray(
Selection.pvarFetchedAttributes)^[1];
if VarIsEmpty(DisplayName) or
VarIsEmpty(EmailAddress) then
Error;
// Call imaginary SendMail function.
SendEmail(DisplayName, EmailAddress);
end;
Conclusion
References
For more information, the following URLs may be helpful:
Project JEDI http://www.delphi-jedi.org
My Web site http://members.chello.nl/m.vanbrakel2
Microsoft Platform SDK http://msdn.microsoft.com
The component referenced in this article is available on the Delphi
Informant Magazine Complete Works CD located in INFORM\
2002\OCT\DI200210MB.
CodeRush 5 and 6
RADified Editor of Your Dreams
everal years ago, I had the pleasure of reviewing the initial CodeRush beta (code-named
Raptor). A lot has changed since those Delphi 3 days. Building on a solid foundation, the
folks at Eagle Software have added some amazing new tools to this product, particularly in
the area of form design. Best of all, CodeRushs open architecture allows you to add your
own tools, transforming Delphi in amazing ways. When I reviewed the beta, I wrote that
CodeRush RADifies Delphi so much that it seems as if youve jumped forward at least one
Delphi generation simply by adding CodeRush to the development environment. That hasnt
gone unnoticed in the Delphi community: CodeRush has won the Best Add-in category of
Delphi Informant Magazines Readers Choice Awards for three years running.
When I began working on this review, I was working with a mature, full-featured version of CodeRush
5 under Delphi 5. (I know many developers are still
working with Delphi 5, so Ill address CodeRush 5
features for that version of Delphi.) As with earlier
CodeRush incarnations, I had to pinch myself to make
Figure 1: With its keyboard templates, configurable toolbar, navigation tools, and
more, CodeRush may be the editor of your dreams.
33 October 2002 Delphi Informant Magazine
CodeRush 3 provided more than 600 keyboard templates; CodeRush 5 includes nearly 1,000. These templates are shortcuts to
Delphi keywords, Visual Component Library (VCL) identifiers, and
Object Pascal structures. You wont believe how much they speed
up the editing process until youve used them for a while. And these
templates are so intuitive, I often can figure things out without
checking the reference. Further, they are grouped logically within
template rules that provide a strong conceptual framework. For
example, the Assignment Operations group lets you use the equals
sign with various letter combinations to assign values to common
variables (e.g. "=f" expands to ":= False;"); the Code Blocks
group allows you to work with all the standard blocks: begin..end,
try..except, try..finally, if, for loops, and others. Theres even a Template Coach Plug-in that watches what you type in the editor and
makes suggestions about templates you may not know exist.
The editor of your dreams includes the clipboard of your dreams. The
CodeRush clipboard keeps the last nine items cut or copied to the Windows Clipboard. You can browse this clipboard, paste the contents of any
pane into the Delphi editor, and even edit or lock the contents of a pane.
34 October 2002 Delphi Informant Magazine
Conclusion
Who needs CodeRush? It might make more sense to ask who
doesnt need it. I think any Delphi developer could benefit from
this feature-rich tool. With the new form-design features, I cant
imagine a single Delphi developer who wouldnt derive immediate benefit. For any developer who writes a significant amount of
Object Pascal code, coding without CodeRush is like coding with
one hand tied behind your back.
I honestly dont think theres a downside to CodeRush. However,
there is one area I should mention. As with any full-featured
tool, expect a considerable learning curve; if you want to receive
its full benefits, you must be prepared to invest some time to
learn CodeRushs features. But dont worry. An excellent tutorial
explains every feature in detail and includes many helpful links, so
you can be productive quickly. You dont need to learn everything
about CodeRush to begin to derive a significant productivity
boost. Ten minutes spent with the tutorial every day will pay huge
dividends in increased productivity as you learn additional ways
of using this multi-dimensional tool.
CodeRushs goal since the start has been to allow you to code at the
speed of thought. This goal may seem unattainable, but I think youll
be amazed at how dramatically CodeRush improves your productivity, and it keeps getting better. No one is more attuned to customer
desires than the folks at Eagle Software. So, if you do much coding
in Delphi, CodeRush should be at the top of your list of add-ons.
Once youve become accustomed to using it, I think youll come to
the same conclusion so many of the rest of us have: Using CodeRush
with Delphi is the only way to code.
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 education-related
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 about 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 [email protected].
Abbrevia 3
A Complete Compression Solution
ile compression has been around for a long time, since the arc files of the 1980s.
Its purpose was the same then as today: to allow quicker transfer of files over the
Internet. By the mid-to-late 1990s, Phil Katzs PKZIP tool had become the de facto
standard, having replaced earlier and slower algorithms.
But what do you need if you want to add
support to your Delphi or Kylix applications for
Class
Description
TAbZipBrowser
TAbUnzipper
TAbZipper
TAbZipKit
TAbCabBrowser
TAbCabExtractor
TAbMakeCab
TAbCabKit
Figure 2: This example program, running under Kylix, demonstrates tools for viewing and manipulating a PKZIP archive.
Class or Component
Description
TAbArchiveItem
TAbArchiveStreamHelper
TAbZipItem
TAbZipArchive
TAbGZipItem
TAbGZipArchive
TAbGZipStreamHelper
TAbTarItem
TAbTarArchive
TAbCabItem
TAbCabArchive
TAbMeter
TAbMakeSelfExe
TAbDirDlg
Conclusion
Abbrevia 3 is a powerful and flexible encryption and decryption
library. For adding data compression to your applications,
Abbrevia 3 provides the complete solution. It supports all the
most popular methods of compression and decompression and
provides both low-level routines and high-level classes and
components to access these operations. You can learn more
about this library by visiting the TurboPower Web site. You can
download a trial version from the site. As with the companys
other products, TurboPower provides a 60-day money-back
guarantee, the most generous in the industry.
File | New
Directions / Commentary
he genesis of this article was the 2001 Borland Conference in Long Beach, California. I was in a large corridor
reading a bulletin board, and noticed a particular announcement from a placement firm specializing in Delphi
programmers. I thought: This is encouraging; a little respect for Delphi for a change. Then something unexpected
happened. A guy walked up to me and asked me what I thought about his ad. I spent the next half hour or so
talking with Aram Janigian, learning about his company and the Delphi job market.
The focus of this article is on the Delphi job market and the various
resources available for job seekers. Since Ive had only limited personal
experience (my Delphi work is mainly in research and education) I have
drawn from two Internet lists to which I subscribe. One is the Delphi
Advocacy Group (TDAG) at [email protected]. The other is one
of the best sources of information on Delphi jobs, the Delphi Job List at
http://www.elists.org/mailman/listinfo/delphi-jobs. People post a variety
of messages to this list, from resumes to recruitment announcements,
relocation hopes, and general information about a new job.
Recruiting Delphi developers. We can get some clues about the
Delphi job market by considering the job notices themselves. Such
notices can be simple or detailed. For example, heres a brief notice
for a short-term contract: Creating WWW and desktop-based
applications in Delphi, ASP and SQL Server, experience in COM,
MTS would be beneficial. Good communication and problem
solving skills, with the ability to rapidly master new environments.
Most notices offer more specifics. Heres one that Ive abbreviated
slightly. It begins with the position title (Senior Programmer Analyst),
a salary range, company location, and information on job benefits. Its
followed by the Job Description and Required Experiences.
JOB DESCRIPTION:
Understand user and system requirements.
Develop program specifications.
Perform program development.
Strong application development experience is the key.
The ideal candidate would be someone who can perform object-oriented
programming using Delphi or JAVA running on W/NT System.
REQUIRED EXPERIENCES:
Manufacturing or data collection experience.
Application design.
Application development.
Program testing.
It concludes with additional experience that would be considered
pluses, and contact information.
40 October 2002 Delphi Informant Magazine
The recruiter for the company that wrote the second, more
detailed, notice shared with me some of the typical approaches.
She pointed out that most recruiters use the actual posting the
company sends them with a few minor changes to disguise the
company its from. [Our company] uses a format we call the
dimensional search to help us write our postings ... although I
have to admit sometimes it is difficult to get all the information
you want from a client. But thats why you see such a variety of
postings and information. All postings have job title, description,
and requirements (depending on the job board). When you leave
a posting vague, you get a wide response of resumes some
recruiters prefer this. Ive found that in this market, being as
descriptive as possible causes a better flood of resumes. Not
everyone agrees on this of course.
The world of Delphi jobs. What level of developers are
companies looking for? Regarding active Delphi developers, Mr.
Janigian provides the following breakdown of PDA placements:
Our permanent placements are broken down into the following
mix: 75% are Senior Delphi Developers with 3 to 7 years of
Delphi development experience, strong RDBMS experience and
Web deployment skills, 10% are Intermediate Delphi Developers
with 2 to 3 years of experience, 10% are Junior Delphi Developers
with 1 to 2 years of experience, 5% are Team Leaders and Project
Managers with 7 years of functional and technical experience.
Online resources. In recent years the number of Internet sites that
include Delphi job information has mushroomed. Ill mention
just a few. delphiworld.com (http://www.delphiworld.com) is a
free site for companies looking for developers. If youre looking
for a site with links to Delphi and IT job sites, go to the UNDU
job list at http://www.undu.com/deljobs.htm. Delphi Sites and
Resource Links (http://calitzbros.com/dpsites.htm) has links to
Delphi job sites and many other Delphi-related sites (a number
of these links no longer work). Borland has a rather active
newsgroup devoted to Delphi jobs (news://forums.inprise.com/
borland.public.delphi.jobs). And there are a number of
Delphi sites that have job pages; for example, the Informant
File | New
Communications Group page at http://careers.informant.com.
There are many more sites out there; a Google search for Delphi
Jobs produced over 3,000 references.
Personal Delphi Agents. Originally known as permIT, Personal
Delphi Agents (PDA) specializes in placing Delphi developers of
all levels with clients throughout the United States. The company
was started in response to the need to provide something beyond
temporary consulting permanent IT staffing. Their first
involvement with the Delphi community took place in mid-1998
in a big way: they recruited 80 Delphi developers for a Fortune 500
financial company in Cincinnati, Ohio that was converting Visual
Basic applications into Web-enabled Delphi applications. By March
2001, PDA had 1,500 Delphi developers in their resume database.
PDA continues to grow and is now offering Delphi Certification
Examinations. I contributed a series of questions along with
other writers such as Marco Cant and Cary Jensen. Naturally,
I had the opportunity to try the exam. Although there was more
emphasis on database issues than I expected, I found the test to
be quite comprehensive. You can learn more about PDA from its
Internet site at http://www.PersonalDelphiAgents.com.
Clearly, Delphi provides an excellent basis for many types of
development, but most projects require the use of additional
technologies. People often put database skills at the top of the
list. Mr. Janigian stresses that Database skills are very important.
70% of our clients and Delphi developers are using Microsoft
SQL Server 7.0/2000, 20% are using Oracle 7.0/8.0/8i and 5%
are using Sybase, Informix, DB2, and everything else.
Although Delphi may suffice as the primary development tool,
other technologies especially database technologies are
essential for any developer who wants to be competitive. I remain
committed to discussing those languages and resources. In past
columns Ive written about many ancillary technologies, including
UML, XML, and HTML. Looking to the future, I plan to write
about .NET later this year. Until next time.
Alan C. Moore, Ph.D.