Professional Documents
Culture Documents
ON THE COVER
5
FEATURES
12
Sound+Vision
16
On the Net
20
REVIEWS
24
28
31
Code Co-op
DEPARTMENTS
2
34
Delphi Tools
File | New by Alan C. Moore, Ph.D.
Delphi
T O O L S
New Products
and Solutions
Book Picks
Delphi Developers
Guide to XML
Keith Wood
Wordware Publishing
ISBN: 1-55622-812-0
Cover Price: US$59.95
(530 pages, CD-ROM)
www.wordware.com
ISBN: 0-7897-2566-5
Cover Price: US$39.99
(436 pages)
www.quepublishing.com
Delphi
T O O L S
New Products
and Solutions
Book Picks
Learn Pascal in Three Days,
Third Edition
Sam A. Abolrous
Wordware Publishing
ISBN: 1-55622-805-8
Cover Price: US$29.95
(324 pages, CD-ROM)
www.wordware.com
ISBN: 0-07-219294-1
Cover Price: US$29.99
(466 pages)
www.osborne.com
Delphi
T O O L S
New Products
and Solutions
Book Picks
Advanced Delphi Developers
Guide to ADO
Alex Fedorov and
Natalia Elmanova, Ph.D.
Wordware Publishing
ISBN: 1-55622-758-2
Cover Price: US$59.95
(643 pages, CD-ROM)
www.wordware.com
Bluetooth Revealed
Brent A. Miller and
Chatschik Bisdikian
Prentice Hall PTR
ISBN: 0-13-090294-2
Cover Price: US$44.99
(303 pages)
www.phptr.com
By Bill Todd
The BLOB
Working with InterBases Binary Data Type
ne of the more useful features of most modern databases is their ability to store
binary data, i.e. data of any type, format, or size. Its useful because its versatile; you
can use a binary field to hold anything from a WordPerfect document to an MP3 file.
InterBase was actually the first database to feature
such a field type, and refers to it as a BLOB. Heres
how its defined in the InterBase documentation:
InterBase provides the binary large object (BLOB)
data type to store data that cannot easily be stored
in one of the standard SQL data types. A BLOB is
used to store very large data objects of indeterminate and variable size, such as bitmapped graphics
images, vector drawings, sound files, video segments, chapter or book-length documents, or any
other kind of multimedia information.
The basic tools for getting a lot of BLOB data into
and out of a database table are the LoadFromFile
and SaveToFile methods of TBlobField. If the only
thing you want to do with a BLOB is load an external file containing the BLOB data into a database
table, or save the BLOB data in a database table to
an external file, these are the only methods youll
need. However, you can do a lot more with BLOBs
using native Delphi components. This article takes
a look at techniques for getting BLOB data into
and out of fields in database records, memory, files,
and Delphi components.
The sample application that accompanies this
article uses an InterBase database, the InterBase
Express components, and a ClientDataSet, but
Figure 2: Code for the Load File button of the Bitmap form.
procedure TfrmBmp.SetImageSize;
begin
if dbiBmp.Picture.Height > dbiBmp.Picture.Width then
begin
if dbiBmp.Picture.Height > 0 then begin
dbiBmp.Height := pnlBmp.Height - 2;
dbiBmp.Width := Trunc(dbiBmp.Height *
(dbiBmp.Picture.Width / dbiBmp.Picture.Height));
dbiBmp.Left := (pnlBmp.Width-dbiBmp.Width) div 2;
dbiBmp.Top := 1;
end;
end
else
if dbiBmp.Picture.Width > 0 then
begin
dbiBmp.Width := pnlBmp.Width - 2;
dbiBmp.Height := Trunc(dbiBmp.Width *
(dbiBmp.Picture.Height / dbiBmp.Picture.Width));
dbiBmp.Top := (pnlBmp.Height-dbiBmp.Height) div 2;
dbiBmp.Left := 1;
end;
end;
The Save File button on the Bitmap form uses code thats almost
identical. The only difference is that it uses a TSaveDialog and calls
the SaveToFile method.
Windows bitmaps are the easiest type of graphic to work with in
Delphi, because they can be displayed using the DBImage data-aware
component. The only trick to displaying bitmaps is to decide how
you want to handle the size of the image in relation to the size of
the DBImage component. There are two choices. First, you can show
the bitmap actual size by setting the Stretch property of the DBImage
to False. If the bitmap is larger than the DBImage component, youll
only see part of the image. This is likely to be unsatisfactory since
theres no way to add scroll bars to the DBImage to let users move
to other areas of the image.
6 January 2002 Delphi Informant Magazine
In the sample database used to write this article, all of the images
were produced by a digital camera and are 1,600 pixels wide
by 1,200 pixels high. To fit the entire image into the DBImage
component, a second option is used. The Stretch property is set
to True, which causes the image to be resized to fit the DBImage
components size. The problem with this technique is that the
picture will appear to be distorted if the aspect ratio, the ratio of
width to height, of the DBImage doesnt match the aspect ratio of
the bitmap.
Solving the aspect ratio problem is easy if all of the images have
the same orientation. All you have to do is make sure you set
the Width and Height properties of the DBImage to match the
aspect ratio of your bitmaps at design time. The sample database
contains bitmaps in both portrait and landscape orientation. To
solve the problem, the SetImageSize method, shown in Figure 4, is
method sets the width of the DBImage to the width of the panel
minus two, and calculates the height to maintain the aspect ratio.
To get a bitmap thats displayed in a DBImage into the Clipboard, call
the CopyToClipboard method of the DBImage component. To paste
a bitmap from the Clipboard into the DBImage, call the DBImages
PasteFromClipboard method. The code from the Bitmap forms Copy
and Paste buttons OnClick event handlers is shown in Figure 5.
called from the AfterScroll event handler of the cdsBlob ClientDataSet. The DBImage has a Picture property of type TPicture
thats a reference to the TPicture object that holds the bitmap.
SetImageSize uses the Picture.Height and Picture.Width properties
of the DBImage to determine if the image orientation is portrait
or landscape. If the orientation is portrait, the method sets the
height of the DBImage to the height of the panel that contains
it minus two pixels, and calculates the width of the DBImage
to preserve the aspect ratio. If the orientation is landscape, the
7 January 2002 Delphi Informant Magazine
Figure 10: The Copy and Paste buttons OnClick event handlers
from the JPEG form.
Conclusion
Working with database BLOB fields in Delphi is both easy and
flexible, once you understand the tools that are available and how
to use them. You can store any string of bytes in a BLOB field
regardless of what the bytes represent. They could be a picture,
a Word document, sound, a movie, an array, a Pascal record, or
anything else that can be stored in a binary file on a computer. The
sample application that accompanies this article doesnt include a
database because of the size of the graphic BLOBs (the test database
for this article was 24MB). Instead, a backup of an empty database
is included in the file BLOB2.GBK. Restore this backup using
IBConsole or GBAK to create an empty database to use with the
sample application.
The sample application referenced in this article is available on the
Delphi Informant Magazine Complete Works CD located in INFORM\
2002\JAN\DI200201BT.
Sound+Vision
DirectShow / DirectX / COM / Delphi 3-6
By Jon Webb
irectShow is Microsofts multimedia architecture and part of the DirectX API. It allows us
to record and play multimedia files and streams, and to control multimedia devices such
as TV tuners and DVD players. This article will introduce the concepts used in DirectShow,
and demonstrate how to build a DirectShow audio/video player application.
Weve all seen (and sometimes cursed) Delphis
built-in TMediaPlayer control. Its based on the
MCI API, which was developed for 16-bit Windows. The MCI API and its sister API, Video
for Windows, werent sufficiently extensible to
cope with emerging multimedia technologies.
DirectShow is the successor to these two APIs,
and gives us much greater flexibility.
You may have used DirectShow before without even
knowing it. Mostly because of the re-branding frenzy
of Microsoft marketing, the same technology has
been known as Quartz, Active Movie, DirectX Media
and now DirectShow. To make things difficult for
us developers, evidence of these multiple personalities
can be found throughout the library.
DirectShow makes heavy use of COM. To understand this article, you should be familiar with using
COM interfaces. You wont need to create any
interfaces yourself, but if you arent comfortable using
COM you may want to look up COM Interfaces
in the Delphi online help, review chapter 44 in the
Delphi manual, check out Eric Harmons excellent Delphi COM Programming, or read Alessandro
Federicis Introduction to COM in the September
2001 issue of Delphi Informant Magazine.
Sound+Vision
streams. The DirectShow SDK documentation describes the COM
interfaces of each standard filter in detail. The SDK also describes
many interfaces to which third-party drivers should adhere.
the Internet (see end of article for details). Put the headers in a
folder of their own, and add that folder to the library path. There
arent any components to install.
Filters have pins that connect them to other filters, much like the
pins of components in an electronic circuit. In some cases, the
pins actually do represent hardware pins. For example, a sound
card filter typically has pins that represent the physical connections (line-in, microphone, CD audio, and so on). Pins carry data
in one or more formats, such as PCM audio at various bit rates,
or compressed video with various dimensions. When two filters
are connected, they can automatically negotiate which format
will be exchanged. Alternatively, the programmer can choose a
specific format to connect the two filters, as long as both filters
understand that format, of course.
If you are running Windows 2000, you may notice that Delphi keeps
stopping at a breakpoint in the kernel. This breakpoint was accidentally
left in by the Microsoft programmers, and youll need the IDE Expert
called Win2kDebugBreakpointsFix to circumvent this problem.
Preparing Delphi
To use DirectShow in Delphi, youll need the JEDI DirectShow
headers. These translated C++ headers can be downloaded from
13 January 2002 Delphi Informant Magazine
The application described here can play video files (AVI, MPEG,
WMV), audio files (WAV, MP3, WMA), and filter graph files
(GRF) created by GraphEdit. It can also use a URL as a source,
such as an MP3 file on a Web server. The end-user needs the
relevant codecs installed, of course.
Because we let DirectShow do most of the work for us, the application
is deceptively simple. It contains only a Menu component for opening
a file or a URL, a Panel to display the video stream, a Panel to contain
some start/stop/pause speedbuttons, and an OpenDialog component
to allow the user to select a file to open.
The event handlers for the Open | File and Open | URL menu
items both call a method named OpenFileOrUrl, which takes the
file name or URL as its only parameter. This is by far the most
important part of the application; its in this method that the filter
graph is built.
Sound+Vision
Interface
Usage
IFilterGraph
IMediaControl
IVideoWindow
IMediaSeeking
IMediaEventEx
if Supports(FilterGraph, IID_IVideoWindow,
VideoWindow) then
with VideoWindow do begin
// Make our video panel the owner.
put_Owner(pnlVideo.Handle);
// Make the video window a child window.
put_WindowStyle(WS_CHILD);
// Make it fit into our video panel.
SetWindowPosition(0, 0, pnlVideo.ClientWidth,
pnlVideo.ClientHeight);
end;
Well need the IMediaControl interface to run, stop, and pause the
graph. Remember, the IFilterGraph interface was provided by the
filter graph object, so we can use it to query for the IMediaControl
interface, and any other interface we might need:
MediaControl := FilterGraph as IMediaControl;
Displaying Video
If the media file were rendering contains a video stream, the
graph will publish an IVideoWindow interface so we can control
the appearance of the video display. We can use Delphis Supports
function to test whether the IVideoWindow interface is supported.
The code snippet in Figure 3 checks whether the interface is available. If so, it makes the video window a child of the panel on our
form, and sets the coordinates and dimensions so that the video
fits into the panel. When the panel is resized, its OnResize event
calls SetWindowPosition again to adjust the video dimensions.
streams support seeking in this way, so wed need test for this
using the CheckCapabilities method. For the sake of brevity, Ill
leave it up to you to add that feature to the application.
After running, stopping, or pausing the graph we call UpdateButtons to enable or disable our buttons depending on the graph state.
We can find out whether the graph is running, paused, or stopped
with the GetState method on the IMediaControl interface:
var GraphState: TFilter_State;
...
MediaControl.GetState(500, GraphState);
sbPlay.Enabled := GraphState in [State_Stopped,
State_Paused];
sbPause.Enabled := GraphState = State_Running;
sbStop.Enabled := GraphState in [State_Running,
State_Paused];
Handling Events
When we reach the end of the file, we need to update the buttons
and rewind the file to the beginning. We need to be notified when
the graph has finished playing our media file. To this end, the filter
graph has an IMediaEventEx interface with which we can register
for notification messages using the SetNotifyWindow method:
const WM_GRAPHNOTIFY = WM_USER + 1;
...
with FilterGraph as IMediaEventEx do
SetNotifyWindow(Handle, WM_GRAPHNOTIFY, 0);
Sound+Vision
if Supports(FilterGraph, IMediaEventEx, MediaEventEx) then
with MediaEventEx do begin
repeat
// Get the event.
hr := GetEvent(EventCode, Param1, Param2, 0);
if Succeeded(hr) then
begin
// Check the event code.
if EventCode = EC_COMPLETE then
// End of file; click on Stop.
sbStop.Click
else
if EventCode in [EC_PAUSED, EC_ERRORABORT] then
UpdateButtons;
// Free the event parameters.
FreeEventParams(EventCode, Param1, Param2);
end; // if succeeded.
until not Succeeded(hr);
end; // with MediaEventEx.
Conclusion
This article has introduced DirectShow and has demonstrated a very
simple DirectShow application (see Figure 5). With a minimum
amount of code we can play back many different media sources.
In Part II well tackle a more advanced project using DirectShow.
Well learn how to build a filter graph ourselves, enumerate
devices and filters, display filter property pages, and capture still
images from a Webcam. See you then.
Resources
Download the Win2kDebugBreakpointsFix IDE expert
The project referenced in this article is available on the Delphi Informant Magazine Complete Works CD located in INFORM\2002\JAN\
DI200201JW.
the graph state (see Figure 4). Dont confuse DirectShow events
with Delphi events; they have nothing in common.
In this example, we werent interested in the event parameters,
but DirectShow allocates them for us anyway. The call to
FreeEventParams is very important. It frees resources allocated
when GetEvent was called. Refer to the DirectShow SDK documentation for a list of event codes.
On the Net
WebSnap / HTML / InterBase / Delphi 6 Enterprise
By Corbin Dunn
his is the first part of a two-part article series that demonstrates how to create an
online survey using the new WebSnap capabilities of Delphi 6 Enterprise edition.
This months article introduces WebSnap by comparing it to the Web Broker technology available in previous versions of Delphi, explains how to build the sample InterBase database, and begins to construct the survey application itself.
Traditional Delphi Web Broker applications commonly involve embedding HTML directly into the
Pascal source code. A developer also will use PageProducer tags and transparent tags to generate the
desired result in response to an action. This works
well, but has some significant drawbacks.
Any changes to the Web page (such as a new phone
number) might require a complete recompilation
of the project to apply the update. If the project is
an ISAPI DLL, the process requires that the DLL
be unloaded from memory in order to replace it.
Depending on the version of Internet Information
Server (IIS), this might require completely rebooting the computer.
Another drawback is that with Web Broker, the
Delphi developer and Web developer are often the
same person. Therefore, theres no easy way to have
a Delphi developer create the applications business
logic while a Web developer creates the Web-based
user interface.
WebSnap changes the way Web development is
done in Delphi. First of all, it separates the Web
interface from the application by keeping a separate
HTML file associated with each Web page. Unlike
Web Broker, WebSnap allows you to have multiple
Web modules, with each one typically representing
an actual page in the final Web application. WebSnap also gives you the power of server-side scripting to access Delphi components, thus eliminating
any need to have HTML embedded in the Delphi
application. That means youre free to pass the
HTML design off to a Web developer who doesnt
know anything about Delphi.
16 January 2002 Delphi Informant Magazine
Introduction to WebSnap
The basic concept of WebSnap is to use adapter
components as a scriptable interface into your
application. You can use server-side scripting
embedded in HTML to access the adapter components, and build complex HTML results from any
kind of data. An adapter exposes data through
adapter fields, and allows updates through HTML
forms and the use of adapter actions.
You should use TAdapter if you want to write all
the logic to access and update data from your
application. TPagedAdapter is the same as a TAdapter,
but goes further by allowing your data to be spread
across multiple Web pages similar to how search
engines have multiple page buttons at the bottom
of the results. TDataSetAdapter is incredibly powerful
and can give you scriptable access to a TDataSet
instantly. It even includes a set of default database
actions, such as DeleteRow, Insert, NextRow,
FirstRow, etc. Finally, the TLoginFormAdapter is
a specialized adapter containing default fields for
the login name, password, and next page. It
interacts with some of the other standard WebSnap
components (WebUserList, EndUserSessionAdapter,
and SessionService) to provide instant login control
to a Web site. Once you have an adapter, you can
write custom server-side script to interface with it, or
you can use an AdapterPageProducer component to
create script for you automatically.
As previously mentioned, WebSnap introduces
the concept of multiple Web modules in a single
project. In previous versions of Delphi, you had to
put all your logic inside a single Web module. You
typically would use actions to return a dynamic
On the Net
/* Table: SURVEY, Owner: SYSDBA */
CREATE TABLE "SURVEY" (
"SURVEY_ID"
INTEGER NOT NULL,
"DESCRIPTION" VARCHAR(255) NOT NULL,
CONSTRAINT "SURVEYS_PK" PRIMARY KEY ("SURVEY_ID")
);
/* Table: SURVEY_DATA, Owner: SYSDBA */
CREATE TABLE "SURVEY_DATA" (
"SURVEY_DATA_ID" INTEGER NOT NULL,
"SURVEY_ID"
INTEGER NOT NULL,
"DESCRIPTION"
VARCHAR(255) NOT NULL,
"VOTES"
INTEGER DEFAULT 0 NOT NULL,
CONSTRAINT "SURVEY_DATA_PK"
PRIMARY KEY ("SURVEY_DATA_ID")
);
CREATE GENERATOR "GEN_SURVEY_ID";
CREATE GENERATOR "GEN_SURVEY_DATA_ID";
SET TERM ^ ;
Web page to the end user. With WebSnap, each page in the Web
application typically will be in a separate Web module, and will
perform some specific logic.
The best way to start learning WebSnap is through a sample application. Its common to see Web sites with quick information polls. Creating a simple voting site, as seen in Figure 1, is easy with WebSnap.
From the InterBase tab on the Component palette, drop an IBDatabase component and make the following changes with the Object
Inspector:
Set the Name to MainDatabase.
Set the DatabaseName to be the newly created InterBase database.
Prepend the DatabaseName with localhost to ensure the connection is done remotely. If you dont do this, your application
may not work as an ISAPI DLL.
Add the following parameters to allow an automatic login:
user_name=sysdba and password=masterkey.
Set LoginPrompt to False.
Next, add an IBTransaction component to the Web data module, and
make the following changes:
On the Net
Double-click on the tblSurvey component to bring up the Fields
Editor. Right-click on the Fields Editor and select Add all fields.
Select the SURVEY_ID field and, in the Object Inspector, expend
the ProviderFlags property. Set pfInKey to True. This provider flag
is what WebSnap uses to determine which field in a TDataSet is
the primary key, in order to do updates and locates on a particular
row. In the Events for tblSurvey, add the following code to the
AfterPost event to allow a refresh of the data after posting:
procedure TWebData.tblSurveyAfterPost(DataSet: TDataSet);
begin
DataSet.Close;
DataSet.Open;
end;
From the Data Access tab, add a DataSource, and make the following changes:
Set the Name to be dtsrcSurvey.
Set the DataSet to be tblSurvey.
Figure 3: Linking SURVEY_IDs using the Field Link Designer.
From the InterBase tab, add another IBTable component, and make
the following changes:
Set the Name to tblSurveyData.
Set the Database to MainDatabase.
Set the TableName to SURVEY_DATA.
Set the MasterSource to dtsrcSurvey.
Double-click on the MasterFields property in the Object Inspector
and link the SURVEY_IDs as shown in Figure 3. This sets up the
master-detail relationship.
In the Events, set the AfterPost event to tblSurveyAfterPost.
Add all the fields for the tblSurveyData component, and set the
pfInKey ProviderFlag for the SURVEY_DATA_ID field, similar to how
it was done for tblSurvey.
At this point, weve set up a traditional master-detail relationship
using the IBExpress components. Now we need to use adapters to
interface with the data from server-side script. From the WebSnap tab,
drop a DataSetAdapter component and make the following changes:
Set the Name to SurveyAdapter.
Set the DataSet to be tblSurvey.
Add another DataSetAdapter with the following changes:
Set the Name to SurveyDataAdapter.
Set the DataSet to tblSurveyData.
Set the MasterAdapter to SurveyAdapter.
The MasterAdapter property allows WebSnap to realize a masterdetail relationship is taking place. The property also hides proper
state information into the Web page.
The DataSetAdapter components add a lot of functionality thats
available from server-side script automatically. You can access all
the fields in the database, and you can access standard DataSet
actions such as Apply, Delete, and Edit. Ill cover this next month
in Part II, when we start writing some script.
The stored procedure, ADD_VOTE, was created earlier in order to
add a vote for a given option. We want to expose this with a scriptable
interface. To do that, add an IBStoredProc component from the InterBase tab to the Web data module and make the following changes:
Set the Name to strdprcAddVote.
Set the Database to MainDatabase.
Set the StoredProcName to ADD_VOTE.
On the Net
To expose the stored procedure to server-side scripting, well use
a traditional adapter. Add an adapter from the WebSnap tab to
the Web data module and change its name to AddVoteAdapter.
Select AddVoteAdapter and double-click on the Data value field to
bring up the Fields Editor. Whenever a user votes, we need to pass
information back to the Web application. With WebSnap, this
information is passed via an adapters AdapterField. Right-click on
one of the Fields Editor panes and select New Component. Doubleclick on AdapterField. In the Fields Editor, select AdapterField
and, with the Object Inspector, change the name to SurveyDataId.
SurveyDataId will be the survey option for which someone is
voting. Add another AdapterField and name it SurveyId. SurveyId
will be the survey for which the user is adding a vote, and it will
be used to display the current results after the user votes.
We now need a way to execute some code whenever the user
wants to vote. Select AddVoteAdapter on the Web data module, and
double-click on Actions in the Object Inspector. Right-click in one
of the action-editor panes and select Add New Component. Doubleclick the default AdapterAction in the dialog box that appears. In
the Object Inspector, change the name of the AdapterAction1 to
AddVoteAction. Double-click on the OnExecute event and add the
code seen in Figure 4.
All AdapterFields have an ActionValue property that represents the
data sent from a Web page. The ActionValue property will be nil if
nothing is sent from the page, so its important to always check it
for nil before using it.
We will add a little more code to the Web data module. Select
WebData and double-click on the OnDeactivate event. Add the
following code to commit the InterBase transaction:
procedure TWebData.WebDataModuleDeactivate(
Sender: TObject);
begin
if MainTransaction.InTransaction then
MainTransaction.Commit;
end;
Conclusion
Thats all we have room for in this article. In Part II of this article
series, well see how to add script to the main page, and get into the
implementation details of creating the survey pages. See you then.
The project and database referenced in this article are available on the
Delphi Informant Magazine Complete Works CD located in INFORM\
2002\JAN\DI200201CD.
Corbin Dunn has worked for Borland Software Corporation for three years. He
started in Developer Support and is now a quality-assurance engineer for the
rapid-application-development product group, where hes currently working on
WebSnap. Readers may reach him at cdunn@borland.com.
n an ideal world, your programs would work flawlessly every time. Unfortunately
however, no matter how hard you try, any piece of software you develop will never
be error-free. You can minimize the number of errors your code causes, but you
cannot always ensure code you use performs its task without errors. Even if you could,
there will always be a class of errors that cannot be prevented, only detected. One of
the most prevalent examples is in the area of network programming, where all kinds
of errors can occur seemingly at random.
This two-part article series is all about detecting
and handling errors generated in the Windows
API. Although COM is sometimes considered
Pascal
Description
VOID
N/A
BOOL
DWORD
Boolean
Longword
HANDLE
LPVOID
THandle
Pointer
Contents
Description
31-30
Severity
29
Customer Flag
28
27-16
Reserved
Facility
15-0
Status Code
You should call this function immediately after the failed API call.
If you call any other Windows API function after a failed call, you
run the risk that the error code will be overwritten by one of those
21 January 2002 Delphi Informant Magazine
// MessageId: ERROR_INVALID_FUNCTION
// MessageText: Incorrect function.
ERROR_INVALID_FUNCTION = 1; // dderror
{$EXTERNALSYM ERROR_INVALID_FUNCTION}
// MessageId: ERROR_FILE_NOT_FOUND
// MessageText:
// The system cannot find the file specified.
ERROR_FILE_NOT_FOUND = 2;
{$EXTERNALSYM ERROR_FILE_NOT_FOUND}
// MessageId: ERROR_PATH_NOT_FOUND
// MessageText:
// The system cannot find the path specified.
ERROR_PATH_NOT_FOUND = 3;
{$EXTERNALSYM ERROR_PATH_NOT_FOUND}
Error Messages
In addition to the raw, numerical error codes, Windows also
provides error messages in text form for each of the standard
Windows error codes. These textual messages are stored as
resources, MESSAGETABLE resources to be precise, in system
DLLs. These MESSAGETABLE resources are a general-purpose
resource type, similar to the STRINGTABLE resource type. They
store a list of strings, each of which is associated with a numerical
Conclusion
Error detection and handling play an extremely important role
when interfacing with the Windows API. This month, Ive shown
you how to detect error conditions after calling a Windows API
function, and how to retrieve a message text describing the error.
In Part II, Ill conclude the series with a look at retrieving mes-
Marcel van Brakel is an independent contractor specializing in Windows systemlevel development using Delphi. Hes a contributing member of Project JEDI
(http://www.delphi-jedi.org) and is the founder of the JEDI Code Library. You can
write to him at brakelm@chello.nl, or visit members.chello.nl/m.vanbrakel2.
f you need a help-authoring tool that does it all, Help & Manual is the tool for you. Its
not only easy to use, it also creates 16- and 32-bit Windows help, HTML help, an HTML
file, an RTF file, and a printed manual from a single source.
Figure 1 shows Help & Manuals main form with
a help project open. The main form is divided into
three panels. The upper, left panel shows the table
of contents for your help file. Below the table of
contents is the pop-up topics panel. Pop-up topics
in Help & Manual are any topics you dont want
included in the table of contents. To the right of the
contents and pop-up topics panels is a tabbed notebook with tabs for Help text and Topic options.
The Help text tab contains the editor where you
write your help topics.
When you create a new project in Help & Manual,
the wizard shown in Figure 2 appears. The radio
buttons let you choose to create a new help project,
import an existing Windows help project, decompile and import an existing Windows help file, or
import an RTF file created in Microsoft Word.
Help Topics
If you dont like the default topics that appear in
the table of contents, just delete the ones you dont
want, or rename and rearrange them to suit your
needs. You can change the name of any chapter
or topic in the table of contents by right-clicking
and choosing Edit from the context menu, or by
double-clicking on the topic or chapter name. To
reorganize the chapters and topics, just drag and
drop. To add a chapter or topic, right-click on an
existing chapter or topic and choose Add Before or
Add After from the pop-up menu.
I like to outline my help files before I start writing
the topic text, and the Help & Manual table-ofcontents panel is an excellent tool for building an
outline of your help file. Once you have the topics
and chapters organized the way you want them, its
a simple matter to move through the topics and add
the text. Another advantage of this approach is that
having all the topics listed in the table of contents
before you start writing makes it a snap to create
links as you go. You also can right-click topics on
the table of contents and choose Mark Item from the
pop-up menu. This causes the topic to appear in bold
in the table of contents, and provides a convenient
way to mark topics to which you must return later.
the caption you enter appears in both the table of contents and the
non-scrolling region at the top of the help topic. This is much easier
than most help-authoring tools, which require you to define a nonscrolling region if you want one. Help & Manual correctly assumes
that the vast majority of help topics will have a non-scrolling region
at the top and puts it in for you automatically. You can click in the
25 January 2002 Delphi Informant Magazine
Browse Sequences
Another great feature of Help & Manual is that it automatically creates the browse sequences for all of your topics based on their order
in the table of contents. This means that most of the time, you wont
have to spend your time creating browse sequences to allow users to
move through your topics in a logical order. If you do need to create
your own browse sequences, its very easy to do. Choose Options |
Project | Winhelp Options and click on the Browse tab shown in Figure
5. Click the New button to add a browse sequence and then add
topics from the Available topics list to this sequence by double-clicking
them, or by dragging and dropping them. Help & Manual creates
a browse sequence automatically for all topics you dont include in
browse sequences you define. You can test your browse sequences
at design time using the forward and back buttons on the Help &
Manual toolbar. Being able to test links and browse sequences without compiling your help file can save a lot of time.
Help & Manual provides syntax highlighting for Pascal, C++, Visual
Basic, and SQL. Just paste or type the code into your help topic, highlight it, click the drop-down Syntax Highlight button on the toolbar, and
choose the correct language.
To create any type of file from your Help & Manual project, choose File |
Make Help File to display the Make dialog box shown in Figure 6.
The five buttons at the left side of the dialog box let you choose the
type of output you want to produce. Selecting a button also changes the
options that are available in the dialog box. To create a Windows help
file, you must have the Microsoft Windows help compiler installed. To
create an HTML help file you must have the Microsoft HTML help
compiler installed. Both compilers are available free from the Microsoft
Web site, and the Help & Manual help tells you exactly where to get
them. The check boxes at the right edge of the dialog box let you specify
which topics will be included in or excluded from the file youre creating.
Printing a Manual
To print a hard copy of the manual, just choose File | Print Manual.
I was really impressed with the printed manual Help & Manual
generated. It was formatted nicely, and included a complete table of
contents and index.
The only thing you would have to add to a Help & Manual hard
copy is a cover page. Every aspect of a printed manual is configurable.
You can specify anything you want for the page-header and pagefooter text, including where you want the page number to appear.
The print-layout options are impressive, also. You can print your
manual with two pages side by side on legal paper in landscape mode,
26 January 2002 Delphi Informant Magazine
Help & Manual lets you create all the documentation for your project
from a single source. The built-in WYSIWYG editor makes creating
and organizing help topics easy, and, once the writing is done, you
can produce Windows help, HTML help, and a printed manual with
just a few mouse clicks. Being able to import a Delphi project to
build your table of contents and list of topics is the icing on the cake.
EC Software
Suedtirolerstrasse 1 b
5201 Seekirchen
Austria
Phone: +43-6212-7838
Fax: +43-6212-4724
E-Mail: office@ec-software.com
Web Site: http://www.ec-software.com
Price: single-user license, US$199; additional-user license, US$69.
At this point, you can delete any components you do not want
included as topics in your help file. Here, you also get to choose
from three options that control how the topics will be added to
your help project. The first option adds all the topics to the table of
contents. The second option adds all the topics to the list of pop-up
topics. The third option adds the forms to the table of contents and
the components on the forms to the pop-up topics.
You also get to choose how your topic IDs will be generated.
The first option will create the topic IDs from each components
HelpContext property if a value has been assigned to HelpContext.
The second option uses FormName.ComponentName as the topic
ID. Importing your Delphi project is an easy way to get a relevant
table of contents to start with. But also, by creating a topic for
every visible component of every form, importing your Delphi
project helps you ensure nothing is skipped.
Conclusion
Help & Manual is an outstanding product. It is a stand-alone
help-authoring tool, so no particular word processor is required. Its
WYSIWYG topic editor lets you see exactly what your help topic is
going to look like in the finished help file. Help & Manual is very
easy to learn and very easy to use. I can create a help system faster
using Help & Manual than with any other product Ive tried. If you
hate writing documentation (or even if you dont) Help & Manuals
ability to create Windows help, HTML help, an HTML file, an RTF
file, and a printed manual from a single source really makes documentation easy. Being able to import a Delphi project to build your
table of contents and list of topics is the icing on the cake.
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 80 articles, a contributing editor to Delphi Informant
Magazine, and a member of Team B, which provides technical support on the
Borland Internet newsgroups. Todd 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.
27 January 2002 Delphi Informant Magazine
APAX
APAX incorporates the functionality of the APRO
libraries into an ActiveX package to make it suitable
for use in environments that support that interface,
Figure 3: Developers
can also use the
APAX control invisibly.
Figure 4: Setting
up a data trigger
to capture the text
string available.
Figure 2: Communicating using the APAX control.
suite. The APAX controls interface will appear in the same format in
any of these environments. As shown in Figure 1, the control drops onto
your form, ready and willing to communicate.
Those who arent ActiveX developers may be surprised to find a
functional object inserted into the project. Users of the Async
component libraries will be accustomed to installing and configuring each element of what we see here: the Terminal object, the
Dialer object, etc. What do you give up by using this prefabricated
object over the component parts? Nothing.
Straightforward serial communications are at the core of APAX. Figure 2
shows a simple communications program built using the APAX control.
The majority of the controls settings were modified using the Properties
dialog box and did not require coding. The toolbar has been turned off,
so the user will go to the provided buttons to control the program. The
modem-status lights have been left on and track the communications
status of the device automatically without any coding. Though the APAX
control displays a full terminal interface by default and is fully featured in
this configuration, its not necessary to use it this way.
Figure 3 shows the placement of the control so it will be transparent when the application is executed. In this configuration, the
application can address an instance of the object without the use
of the visible interface.
The standard controls that gather and display the Winsock port call
the APAX methods for their communication needs, but do not use
the terminal, toolbar, or status bar. This invisible use of the APAX
control gives the developer the flexibility to implement his or her user
interface via the standard controls, while using the rich communications library that the control supplies.
Data Triggers
The quality and reliability of the TurboPower Async libraries is usually reason enough to recommend the product in either form, but
one outstanding feature truly sets it apart from products that compet29 January 2002 Delphi Informant Magazine
Standard Features
APAX supports the full range of features a developer expects to
find when considering a component or library. APAX completely
controls the byte stream, regardless of the port through which it
travels. The developer can choose to let the control manage most
of the details, and APAX is happy to do so. For more technically
demanding applications, APAX has an interface to all the lowlevel capabilities necessary to control the data flow into or out of
an application. A well-designed dispatch-logging service is built
into APAX, and nothing is more useful than a byte-by-byte log
file from which you can examine the data flow when debugging a
serial communications application. To round out the basic group
of features, the APAX control provides a customizable terminal
interface and a full range of file transfer protocols.
Although components provided by the compiler vendor may
supersede this feature, APAX also supports communications via
Winsock. Supplying an IP address and a port number turns the
terminal window of the control into a capable telnet application.
APAX can act as either a client or server in this mode for either
making calls or listening for them. Another Windows-based
standard is supported in Telephony Application Programming
Interface (TAPI). The TAPI DLLs are intended to simplify com-
Conclusion
TurboPower Software extends its winning streak with APAX.
TurboPowers years of asynchronous communications expertise make
this package a definite winner. While most Delphi developers will
opt for the Async Professional libraries to take advantage of the flexibility of numerous separate components, Object Pascal developers
should not dismiss APAX. For the programmer who wants to add
serial communications to an application without the learning curve
of APRO, the ActiveX control is ideal. This control also should
make an impact on other developer camps that rely on the ActiveX
package. The control is an outstanding performer and comes with
TurboPowers usual excellent and thorough documentation. Usage
examples are provided for Delphi, VB, and Visual C++.
Code Co-op
Affordable, Server-less Version Control
pend any time at all on Borlands delphi.thirdparty-tools newsgroup, and you will
see that two of the most frequently asked questions regard what reporting tool to
use, and what version control software (VCS) to use. While it should be fairly obvious
what I would suggest for the former, for the latter I can now make a new suggestion.
Code Co-op by Reliable Software is a version control package that deserves some
mention in these discussions, and in the following paragraphs Ill tell you why.
Code Co-op saw its inception when two developers living in different countries (one in the
United States and the other in Poland) needed
to do some collaborative development. Lacking
a common server needed by standard VCS packages, these two developers created a system that
kept a code repository on each of their machines
and used e-mail scripts to keep the source code
in synch. That was the birth of Code Co-op,
and while the product has grown since then, the
basis of the software is still a server-less VCS.
given position in the progress of the files. This is called by many different
names in various VCS packages: cutting a label, setting a bookmark,
adding a version, etc. Its a feature often used when you want to
indicate a definitive point in your development, such as when you reach
a release point. This benchmark is the code that was in version 2.3 of
our product. The VCS package should allow you to retrieve all the files
in a project as they were at the time of that benchmark. Thus you can get
the files as they were for version 2.3 and try to figure out how you broke
version 2.4.
Differencing is an important part of version control. This is the ability
to display the differences between two versions of a file. Many packages
provide e-mail services to send notifications to your team members
when changes have been made to the source code.
Another common feature is the ability to add comments when
checking in or adding files to a project. This can be helpful when
reading over a large number of check-ins to find a specific one. More
advanced VCS products provide the ability to add those comments
to your source code files automatically as they are checked in.
Finally, integration into your IDE can be an important convenience. With the ability to check files in and out, add comments,
add and remove files, etc. directly from your IDE, you are saved
the inconveniences of closing a file you want to change, leaving
the IDE to launch your VCS, checking out the file, reopening it
in the IDE, making your changes, and so on. Instead, you can just
check out a file you have open right from your IDE.
What makes Code Co-op stand apart is the fact that all synchronization and notification is handled via e-mail scripts. When you
check in a set of changes, Code Co-op compares the previous version of the file and the new version, then sends a script to all other
members of the project, containing only the information required
to duplicate the changes in the other members files. Likewise,
when a set of changes are received by a member, an acknowledgement script is generated. Because theres no centralized server,
Code Co-op cannot have true pessimistic locking; on the occasion
when two (or more) project members attempt to check-in changes
to the same file, the first script received wins, while the other
scripts are rejected, requiring that project members correct the
collision.
In spite of this de facto optimistic scheme, Code Co-op requires
you to check out files before working on them. This is an
annoyance, as it in essence saddles users with the worst of both
approaches. Another annoyance for me was the barrage of scripts
flying back and forth as files are managed. Your e-mail client will
essentially become analogous to a server messaging hub using
Code Co-op, but this is understandable given the nature of the
product and I became used to the flurry. Plus, I got in the habit
of having Code Co-ops Dispatcher handle all messages before I
began checking e-mail. Usually this resulted in not seeing the messages, because the Dispatcher would clean them up after it finished
processing its scripts.
Conclusion
Given some of the annoyances Ive mentioned, it may seem as
though Im unimpressed with Code Co-op. On the contrary, I
File | New
Directions / Commentary
orn in California, Cary Jensen grew up in San Mateo, on the San Francisco peninsula just north of Silicon Valley.
He attended college at California State University at Hayward, where he studied experimental psychology and
statistics. While there, he developed an interest in computers software interface issues, in particular. After graduation, he accepted a research fellowship at prestigious Rice University in Houston, Texas, where he received a masters
degree and doctorate of philosophy in human factors psychology, specializing in human-computer interaction.
Jensen and his wife, Loy Anderson, started Jensen
Data Systems, Inc. immediately after completing
their degrees in 1988. Anderson also has a Ph.D.
in human factors psychology from Rice. Their
company specializes in database-application
development, consulting, and training. Because
Jensen is based in Houston, many of his early
database applications focused on the oil-andgas, medical, and aerospace industries. However, he also has worked for
companies specializing in insurance, law, manufacturing, banking, and
finance.
Most people know Jensen from his many books. In their first year,
Jensen and Anderson wrote several training courses, which led to their
first book deal. Since then, the two have written 18 books, including
their latest, Building Kylix Applications [Osborne/McGraw-Hill], which
became available last July. Jensen also has written more than 50 software
training courses, and more than 150 magazine articles.
During the past eight years, Jensen has earned an international reputation as a speaker and trainer, first of Paradox and then Delphi.
He wrote material and was principle trainer for the Borland/
Softbite Delphi World Tours, Borland Developer Days, and the
Delphi Development Seminars. Hes a regular speaker at software
conferences and workshops in North America and Europe, and he
presented at his 11th consecutive Borland Conference in July. He
continues to write for Delphi Informant Magazine, offer training
seminars, develop software, and provide consulting services.
Delphi Informant: Youve worked as a developer and a trainer for
many years, specializing in database applications. Please share with
us some of your experiences, going back to the days you were
working with Paradox.
Jensen: I had a profound realization in our first year of business.
I wrote a natural-gas transportation tracking system called
GasTrack, and, several months after its deployment, the client
asked me to upgrade the system. It was then that I saw how
the software had changed peoples lives. It showed me that, when
done right, software can help people be more productive, with less
work. The employees enjoyed their jobs more, and the company
was more profitable.
DI: Each new Delphi version has introduced new features and
enhancements, beginning with 32-bit support in Delphi 2. Besides
this obvious one, what do you feel was the most important feature
added to Delphi since the original version?
34 January 2002 Delphi Informant Magazine
File | New
DI: Youve been on the Borland Conference advisory board for a while.
Whats that like? What advice can you give the would-be presenter at a
future conference?
Jensen: Its hard work evaluating the many excellent abstracts and trying
to put together a great program. But its also fun, and the advisory board
always consists of talented and interesting people.
My advice to people who want to speak at BorCon is this: Demonstrate
your ability to write and speak in public. Write articles for magazines
and user-group newsletters. Speak at user-group meetings and regional
conferences. Show the board you can effectively communicate your
knowledge. Being an expert is one thing, but being able to share that
information with others requires different skills.
DI: There was tremendous excitement about Kylix when Borland
announced a Delphi version for Linux development. Now that Kylix is
out, what do you think? Is it all you had hoped it would be? What
reactions do you see from developers?
Jensen: Kylix is incredible. Its everything Borland set out to accomplish
and more. The reaction from developers who are using it is very positive.
Its a great tool. However, until recently, it was too expensive for many to
buy just to kick the tires. Borland really needs to find a way to get Kylix
into the hands of as many people as possible.
DI: Youve worked a lot with Kylix yourself, including training sessions
and your new book. Please share some of your personal experiences,
including what you liked most and least.
Jensen: If you know Delphi, youve got a great start on building Linux
applications with Kylix. You will have to learn a lot about Linux, but
most of your development skills will transfer nicely. I believe Kylix will
grow like JBuilder. Initially, JBuilder had a nice, small following. During
the years, its feature set has expanded, and its now the number one Java
tool. Have you seen JBuilder 5? It rocks.
DI: Lets talk about Linux and the ongoing war between it and Microsoft
Windows. How do you view this? Do you see Linux making significant
strides in the next year or two, and do you see this happening in areas
other than Web development?
Jensen: In the short run, one of the biggest areas where Linux is going to
make a splash is in dedicated systems. A lot of people are not interested
in paying for the Windows license when the user never interacts directly
with the OS. Long-term, workstation development will depend on other
factors, such as how GNOME matures. Itll be interesting.
DI: You are a well-respected author. What advice would you give to the
aspiring technical writer?
Jensen: Dont get me started (laughing). I could talk about writing for
days. I love to write, but its hard work harder than most people
realize. Anybody who wants to write should enjoy the process and be
prepared to take the necessary time to do it right. Thats number one.
Number two is this: Have an agreement with a publisher before you
write. Dont write a book and then shop it around. Find your publisher, agree on the scope and nature of the book, and then write.
DI: How do you view the future of computing in the next five years?
Weve examined the Windows/Linux issue, but there are others. Do
35 January 2002 Delphi Informant Magazine
Alan Moore is Professor of Music at Kentucky State University, where he teaches music
theory and humanities. He was named Distinguished Professor for 2001-2002. He
has developed education-related applications with the Borland languages for more
than 15 years. He is 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.