On The Cover: January 2001, Volume 7, Number 1
On The Cover: January 2001, Volume 7, Number 1
On The Cover: January 2001, Volume 7, Number 1
ON THE COVER
6 On the ’Net
Surfing from Delphi: Part I — Bill Todd
Bill Todd shows us how to use IE as an Automation server, and — just
to make it really easy — provides a wrapper for many of the methods
in the IWebBrowser2 interface.
FEATURES
13 OP Tech
Pretty Good Privacy — Mike Riley
Mike Riley provides an introduction to PGP for the Delphi developer,
from its installation and requirements, to a demonstration program, to
suggestions for its use.
REVIEWS
16 Greater Delphi 30 Sleuth QA Suite 2
Easy Pivot Tables — Alex Fedorov and Natalia Elmanova Product Review by Alan C. Moore, Ph.D.
Alex Fedorov and Natalia Elmanova demonstrate the power and flex-
ibility of PivotTable, one of the Microsoft Office Web Components, when
used from Delphi. 33 ExpressQuantumGrid and ExpressInspector
Product Review by Ron Loewy
21 Quick CLX
The Life and Death of TButton — Robert Kozak
Borland’s Robert Kozak begins his regular Kylix column. Focusing on CLX
(pronounced “clicks”), the cross-platform component library, he begins
DEPARTMENTS
with the humble TButton. 2 Delphi Tools
5 Newsline
26 At Your Fingertips 36 Best Practices by Clay Shannon
DBGrid Images, etc. — Bruno Sonnino
38 File | New by Alan C. Moore, Ph.D.
Bruno Sonnino provides us with five tips, including: displaying images
in a DBGrid, Windows taskbar tips, accessing environment variables,
and justifying text.
By Bill Todd
I nteracting with the Web is becoming a more common requirement for applications
every day. Part one of this two-part series looks at controlling Internet Explorer via
Automation from your Delphi application. You’ll use a custom component to wrap the
IWebBrowser2 interface. In part two, you’ll look at embedding a browser in your applica-
tion using the TWebBrowser control.
procedure TIEController.IEOpen;
begin
FIE := CoInternetExplorer.Create;
end;
Figure 9 shows the IEPrint method which calls IEExecWB with the calls IEExecWB with a command ID of OLECMDID_PRINT,
appropriate command ID. In this example, the method takes a and an option of OLECMDEXECOPT_DODEFAULT. If ShowDlg
Boolean parameter that controls whether the printer selection dialog is False, the command option constant is changed to
box is displayed. If the ShowDlg parameter is True, the method OLECMDEXECOPT_DONTPROMPTUSER. The methods of
begin
if not IsIEOpen then IEShow;
FIE.Refresh;
end;
procedure TIEController.IEShow;
begin
IEOpen;
IEVisible := True;
end;
procedure TIEController.IEPrintPreview;
var
V: OleVariant;
begin
IEExecWB(OLECMDID_PRINTPREVIEW,
OLECMDEXECOPT_DODEFAULT, V, V);
end;
procedure TIEController.IESave;
var
V: OleVariant;
begin
IEExecWB(OLECMDID_SAVE, OLECMDEXECOPT_DODEFAULT, V, V);
end;
procedure TIEController.IEStop;
var
V: OleVariant;
begin
IEExecWB(OLECMDID_STOP, OLECMDEXECOPT_DODEFAULT, V, V);
end;
end.
End Listing One
By Mike Riley
W hen asked about privacy in today’s world, Sun Microsystems CEO Scott McNealy
remarked, “You have zero privacy. Get over it.” Of course, if this were really
the case, then Mr McNealy should have no qualms about posting his company’s
confidential internal correspondence on public Internet sites. I haven’t seen this
happen yet. And thanks to the hard work of people like Phil Zimmerman, privacy
and data security can still exist in today’s highly digitized world.
Phil Zimmerman to the Rescue the September 2000 expiration of RSA’s “biprime
Pretty Good Privacy (PGP) is a popular, high- asymmetric cryptography” patent, many other
quality cryptographic tool that is freely available freely available public key software technologies are
for personal use from MIT, and commercially sure to circulate on the ’Net. Until a better public
available for company use from Network Associ- key solution comes along, however, PGP will most
ates. The program’s author, Phil Zimmerman, faced likely be the leader in the field of cross-platform
everything from financial ruin, government agency message encryption for some time to come.
intimidation, and patent infringement allegations
in his effort to release a product to protect basic Obtaining and Installing PGP
e-mail communication from prying eyes. Chroni- Depending on PGP’s intended personal or com-
cled in Simson Garfinkel’s book PGP: Pretty Good mercial use, visit the appropriate Web site listed in
Privacy [O’Reilly, 1994], Phil’s story is a triumph the “Resources” section at the end of this article
in the ongoing battle of democratic freedom versus for details on how to obtain a copy of PGP for
technological Big Brother advances. Microsoft Windows 9x/NT/NT2000. Due to a
recently discovered vulnerability, it’s recommended
Most people unfamiliar with the degree their that version 6.5.8 or higher is used.
personal e-mail accounts are exposed are often
shocked to learn how public their “private” e-mails During the installation procedure, the user is
really are. The analogy of standard, unencrypted asked to create a key pair. It is at this time a
e-mail communications flowing across the public public and private key are created. The public
Internet compared to a paper postcard in the US key is a bit of data that may be posted on a
Mail isn’t that far off. Freely available tools exist public certificate server. The most popular of these
on the Internet today that provide packet-sniffing is http://pgpkeys.mit.edu:11371 for personal use,
capabilities intended for just such snooping. and ldap://certserver.pgp.com for commercial use.
Even companies operating sophisticated commer- However, under no circumstances should the pri-
cial e-mail platforms that provide secure internal vate key counterpart ever be shared. If the private
communication may lose all that expensive protec- key should ever be compromised in any way, imme-
tion if a message is sent to the Internet without any diately revoke the key pair and create a new one. In
form of encryption. fact, it’s a good security practice to have key pairs
expire every 90 days to reduce the threat of tamper-
Because PGP has been freely available for personal ing. To learn more about public and private keys,
and educational use since the early 1990s, its including their generation and proper use, read the
popularity — compared to other cryptographic well-written “Introduction to Cryptography PDF”
messaging solutions — has soared. And with that accompanies the program’s installation.
Before moving on with the Delphi application requirements, make Next, change the SignKeyPass value in the PGPEncodeGetSignKeyPass
sure you can successfully send and receive a signed, encrypted e-mail event to the passphrase used for the selected key pair. A word of warning:
with your newfound secure messaging tool. Just like OOP, learning As noted in the source code listing, it’s a very bad idea to place passwords
how public key cryptography works takes a bit of getting used to. and passphrases in source code. Thus, if automated message encryption
Follow the PGP Encryption/Decryption flow diagram in Figure 1 to is required, consider removing the signature process or investigate an
review a basic understanding of the process. It’s only after using it for effective way to obfuscate the source to limit passphrase visibility.
a while that its value proposition really sinks in. And like OOP, once
you get this technology’s religion, you’re hooked. Lastly, if you are using the NetMaster SMTP control bundled
with Delphi Pro or Enterprise 4.x or higher, change the SMTP
Delphi PGP Program Requirements Host and UserID values to those appropriate to your environ-
Thanks to the dedicated work of Steve “S.R.” Heller, who ment. Assuming all program dependencies have been met, and all
authored the SPGP.DLL that programmatically extends PGP to parameters have been correctly updated for your configuration,
Windows application development environments like Delphi, and build and run the application.
Michael in der Wiesche, who authored a very slick PGP compo-
nent set, leveraging the power of PGP in Delphi applications is Clicking the globe toolbar icon will fetch the DelphiZine.com
a piece of cake. Check out the “Resources” section of this article home page and read it into the top memo field. This URL could
for the Internet location of these works. Once the SPGP.DLL just as easily be an internal corporate intranet address, an XML
has been placed in the Windows system directory, and the PGP data feed, or a CSV file. If the target URL is unavailable for any
components have been installed via the usual Delphi component reason, you can also simply type a message into the top memo field
installation procedure, the power of commercial-grade crypto- as well. Upon doing so, the key toolbar icon will become enabled,
graphic messaging is available to any Delphi developer. allowing you to sign and encrypt the memo field’s contents. The
PGP component suite supports methods for both the encryption
To show just how simple it is to harness this power, I created an of physical files as well as strings in memory. For demonstration
application that illustrates the potential of this robust combination. purposes, the contents of the top memo field are written out to a
pgpdemo.txt file. This practice is not recommended in a production
The PGP Demonstration Application environment, however, as it adds yet another potential security
The PGP Demonstration application (see Figure 2) was constructed vulnerability to an otherwise secure process.
to show the step-by-step processes of capturing Web-based content,
encrypting and signing that content, and sending it through a public The bottom memo field then retrieves the contents of the pgpdemo.txt
Internet e-mail service. The GUI is straightforward, and — quite file, signs and encrypts the file, displays the results of the process in
honestly — unnecessary for anything except to graphically display the the bottom memo field, and saves the results to another file called
steps and outcomes of each phase of the application being processed. pgpdemo.pgp. The contents of this file can also be opened with a text
editor such as Notepad for review. Additionally, double-clicking any file
To test this application using the key pair you established during with a .asc or .pgp extension from within the Windows shell will invoke
the PGP installation, change the CryptKeyIDs and SignKeyID values the PGPTools application and automatically attempt to decrypt the file.
to your key pair e-mail address. Remember to bracket the e-mail
address, and don’t allow an ill-formed e-mail address with any spaces The final step is transmitting the file via an SMTP gateway. If the
or other illegal characters. contents of the top memo field were successfully encrypted and
Conclusion
To be a useful tool in a production environment, the PGP demon-
stration application could be automated to kick off a batch operation
via a Timer event, or Windows Task Scheduler operation. Better yet,
an NT Service could be created to ensure the automated operation
of an encrypted message transmission from within the Windows NT
security and remote management framework.
So the next time someone says, “You have no privacy,” smile and tell
them “Get with it.” ∆
Resources
PGP (Commercial Version) v6.5.8 or higher available from
Network Associates at http://www.pgp.com
PGP (Freeware Version) v6.5.8 or higher available from the MIT
Web site at http://web.mit.edu/network/pgp.html
Steve “S.R.” Heller’s excellent SPGP.DLL v2.5.5 or higher,
available at http://www.oz.net/~srheller/spgp/
Michael in der Wiesche’s superb PGP components v1.3.1
or higher, available at http://home.t-online.de/home/
idw.doc/PGPcomp.htm
PGP: Pretty Good Privacy. Simson Garfinkel’s remarkable story
of Phil Zimmerman’s trials and travails of bringing PGP to
the public, as well as a layman’s introduction to cryptography.
Also includes detailed (albeit dated) descriptions of PGP com-
mand line options. Published by O’Reilly and available at
http://www.oreilly.com/catalog/pgp/
The projects referenced in this article are available on the Delphi Infor-
mant Magazine Complete Works CD located in INFORM\2001\JAN\
DI200101MR.
Mike Riley is a Chief Scientist for RR Donnelley & Sons, one of North America’s
largest printers. He actively participates in the company’s I-net and eMerging
Technology strategies using a wide variety of distributed network technologies,
including Delphi 5.0. Mike can be reached via his public e-mail address,
mike_riley_@hotmail.com.
L ast month we demonstrated how to use two of the Microsoft Office Web Components,
ChartSpace and Spreadsheet, in Delphi applications. The other Office Web Component
of interest for Delphi developers is the PivotTable component that’s used to pivot, filter, and
summarize information from various data sources and present it in meaningful ways.
In this article, we’ll first briefly discuss the Pivot- In Excel, the pivot table fields can be rotated, and
Table services implemented in Microsoft Excel, so the summarized data itself can be filtered to present
you can get an idea of how and when the Pivot- different summaries or details for areas of interest,
Table component should be used. Then we’ll pro- as shown in Figure 1. This allows us to create
vide you with several examples of how to use the different crosstabs for the same data.
PivotTable component in Delphi applications.
Let’s consider, for instance, that we have a table
Excel PivotTable Services that contains sales data, as shown in Figure 2.
To be able to use the PivotTable component, we
need to understand at least the basics of the Pivot- We can create an Excel pivot table using the Pivot-
Table services implemented in Microsoft Excel. Table Wizard that can be activated with the Data
The Excel pivot table is an interactive table usu- | PivotTable and PivotChart Report menu item. The
ally used to summarize or statistically analyze rows of this pivot table can, for example, contain
data. The data can come from a variety of sources, the Product field of a table as its row field, the
including an Excel range or database query. Cells Salesperson field of the table as its column field,
of the pivot table contain summaries for one of and the City field of the table as its filter field
the numeric columns of the data. These sum- (in Excel, such fields are also called page fields), as
maries are based on table rows in which the row shown in Figure 3.
name and the column name for this particular
pivot table cell are the values of the corresponding To create another pivot table view instead of the
data table fields. Such summary tables are also one shown, a user can drag-and-drop fields to and
called crosstabs. from the PivotTable toolbar that becomes extended
with an appropriate field list where the pivot table
layout is edited. Note that a pivot table can have
Filter Fields
no row fields, or no column fields, as well as no
Column Fields filter fields.
// Specify that the OLE Object will be PivotDataAxis PivotGroupAxis PivotFilterAxis PivotCell
PivotTotals
// activated manually and activate it. (PivotTotal)
with OleContainer1 do begin PivotMember
PivotFieldSets PivotFieldSets PivotFieldSets PivotFieldSets
AutoActivate := aaManual; (PivotFieldSet) (PivotFieldSet) (PivotFieldSet) (PivotFieldSet)
DoVerb(ovShow); PivotMembers
end; (PivotMember)
PivotFields PivotFields PivotFields
(PivotField) (PivotField) (PivotField)
Objects
Collections
Using the PivotTable Component PivotTotals
(PivotTotal)
After we’ve placed the PivotTable component on our form within
the TOleContainer component, we can use its properties and Figure 4: Simplified object model of the PivotTable component.
or like this:
PT.CommandText :=
'SELECT * FROM [Product Sales for 1997]';
After that, we have two options. We can show the Fields list box
and allow users to drag and drop fields into the pivot table manually,
or we can do the same thing programmatically. Let’s see how the
latter can be done.
The fields in
PivotTable Fields PivotTable Collection
the pivot table
Row fields RowAxis collection
discussed ear-
Column fields ColumnAxis collection
lier in this arti-
Filter fields FilterAxis collection
cle have the
Totals or Details fields DataAxis collection
appropriate Figure 7: The PivotTable component with calculated totals.
collections Figure 5: PivotTable fields and their collections.
within the Piv- Specifying Colors
otTable component’s object model. This is shown in the table in Now we can make our pivot table more attractive by applying
Figure 5. different colors to its various sections. To do this, we will use the
TotalBackColor, FieldLabelBackColor, MemberBackColor, FieldLabelFont,
The first three collections support the InsertFieldSet method that’s used and SubTotalBackColor properties of the PivotView object:
to specify the data for this set of fields. To specify the data for totals or
detail fields, we can either use the InsertTotal method, or InsertFieldSet // Apply various color settings to
// different pivot table components.
method. The code snippet shown in Figure 6 specifies data for all parts
View.TotalBackColor := 'CornSilk';
of the pivot table. View.FieldLabelBackColor := 'DarkBlue';
View.FieldLabelFont.Color := 'White';
Here we’ve defined that the CategoryName field is used to create View.ColumnAxis.FieldSets[0].Fields[0].SubTotalBackColor :=
the row axis data, the ShippedQuarter field is used to create the 'LightSteelBlue';
View.RowAxis.FieldSets[0].Fields[0].SubTotalBackColor :=
column axis data, and the ProductName and ProductSales fields 'LightSteelBlue';
are used to create details to summarize them interactively. View.MemberBackColor := 'LightGrey';
Calculating Totals and Using Formulas Next, let’s limit possible user manipulations of the pivot table:
At this step, we have specified the data for Row, Column, and Detail
fields of the pivot table. Now we can add total values to it. Here’s // Remove the title bar.
the code that does the job: View.TitleBar.Visible := False;
// Set various properties of the Pivot Table
// to limit user interaction.
// Add a total.
PT.DisplayToolbar := False;
Total := View.AddTotal('Sales Total',
View.FieldSets['ProductSales'].Fields[0], plFunctionSum); PT.AllowPropertyToolbox := False;
View.DataAxis.InsertTotal(Total);
View.Totals['Sales Total'].NumberFormat :='Currency';
The result of calculating summaries and applying colors is shown in
Figure 7.
We’ve added totals for the ProductSales field for any quarter and any
product category, as well as grand totals for all product categories In our first example, we saw how to set the data source, define
and all quarters. In this case, we’ve calculated a sum of the detail a pivot table layout, calculate totals and use formulas, and apply
values. Instead, we could also calculate the maximal or the minimal various colors to the different parts of a pivot table. Let’s now
values, as well as the count of the detail data. move on to a discussion of filters.
PT.ConnectionString :=
'PROVIDER = MSOLAP.2; DATA SOURCE = maindesk;' +
'INITIAL CATALOG=FoodMart 2000';
The following code saves the pivot table into the Customers.GIF file We’ve seen how to use the PivotTable component that is part of Micro-
in the c:\Data folder: soft Office Web Components. We know how to define the data source
for this component, how to set the row, column, and filter fields, how to
PT.ExportPicture('c:\Data\Customers.GIF'); define the data fields, how to create summaries, and how to apply colors
to the different parts of the pivot table. We have also studied how to
Implementing Printing Functionality receive values from the pivot table cells and axes, as well as to make this
The PivotTable component has no native printing capability. How- component more or less interactive in our application. Finally, we also
ever, we can easily implement this functionality by moving the pivot saw how to print the data from a PivotTable component. ∆
table data into Excel, and then using Excel’s printing capability.
The three demonstration projects referenced in this article are available
Of course, all of this is done via Automation. First, let’s declare some on the Delphi Informant Magazine Complete Works CD located in
variables: INFORM\2001\JAN\DI200101AF.
var
Excel : Variant; // An instance of Excel.
WBook : Variant; // Workbook.
WSheet : Variant; // Worksheet.
PageSetup : Variant; // PageSetup object.
By Robert Kozak
W hen I wrote my previous article (“Cross-platform Controls” in the August 2000 issue
of Delphi Informant Magazine) I was overwhelmed by the sheer volume of things
to write about. There was so much, in fact, that I knew an ongoing column was the only
way to properly do CLX any justice. So naturally, I was excited when my proposal to do a
column on CLX was accepted. With this column, we are going to explore the internals of
CLX and discuss some of the issues of Kylix development. It’s my hope that by reading this
column, you will walk away with a better understanding of the internals of CLX.
As I write this, Kylix is still being developed. And differ from the VCL? To answer this, I’ll take a
it’s possible that it has been released by the time common control, TButton, and show what hap-
you read this. This means that there might be dif- pens to it as it is created, used, and destroyed with
ferences between the specifics I’ll provide here and CLX. This way we can delve into CLX and see
the final product. You take that risk when you write what’s going on under the covers. For comparison,
about the latest and greatest. I will do the same for a VCL TButton, since some
of you may not be that familiar with the internals
One of the questions I bet you have is: What is of the VCL.
different about CLX? Specifically, how does CLX
This is going to be a high-level overview. Although
I will get into some of the lower-level code, I’m
procedure TWinControl.UpdateShowing;
not going to mention every property that gets set
var
ShowControl: Boolean; or every method that gets called during the life of a
I: Integer; button. This would just bog us down with details,
begin when what I really want to show are the highlights.
ShowControl := (FVisible or
(csDesigning in ComponentState) and
not (csNoDesignVisible in ControlStyle)) and
Take a look at Listing One (beginning on page
not (csReadingState in ControlState); 25). Here’s a project that introduces the main star
if ShowControl then begin — the Button component. This code will compile
if FHandle = 0 then CreateHandle; { <------- } in Kylix and in Delphi. The uses clause has an
if FWinControls <> nil then
{ $IFDEF } block around it, so it will compile
for I := 0 to FWinControls.Count - 1 do
TWinControl(FWinControls[I]).UpdateShowing; using either CLX or the VCL. The code that cre-
end; ates a Button, uses it, and then destroys it, is the
if FHandle <> 0 then same for a CLX project or a VCL project.
if FShowing <> ShowControl then begin
FShowing := ShowControl;
try
Creating the Button
Perform(CM_SHOWINGCHANGED, 0, 0); Not much here to talk about. In CLX, and in the
except VCL, a button is created the same way:
FShowing := not ShowControl;
raise;
Button := TButton.Create(nil);
end;
end;
end; The constructor for both sets default property values
of the button. In CLX, the constructor also sets a
Figure 1: The VCL TWinControl.UpdateShowing method. property named InputKeys. InputKeys is a mechanism
Figure 6) to be called. In CLX (just as in the VCL) you need a handle Figure 8: CLX TWidgetControl.CreateHandle method.
to display a control, but it’s not the same as a Windows handle.
procedure TButtonControl.SetText(const Value: TCaption);
In CLX, a handle is an opaque reference to the underlying widget begin
control. To get this handle, UpdateShowing calls HandleNeeded (see if Caption <> Value then begin
Figure 7), and then calls CreateHandle. As you can see from Figure 8, QButton_setText(Handle, @Value);
FAccelChar := Char(QButton_accel(Handle));
CreateHandle first calls CreateWidget, which will create the widget.
QButton_setAccel(Handle, 0);
TextChanged;
The next method I want you to notice is InitWidget. Because end;
InitWidget gets called after the widget is created, you can be sure end;
the handle is valid. It’s at this point that you can set properties on Figure 9: The CLX TButtonControl.SetText method.
the widget. For example, say you have a property named Color. In
SetColor you can check with HandleAllocated to see if you have a valid that we call the setText method of the widget control. Notice that
handle. If the handle is allocated, you can make the proper call to set the handle is the first parameter. Next, we store the accelerator, then
the color. If not, you can store the value into a private field variable, clear it from the QButton control. We do this because we’re going to
and in InitWidget you make the call to set the color. handle all of the accelerators in the CLX framework.
Now our Button is created, parented, and ready to rock-and-roll. Next we call a dynamic method named TextChanged as a notification.
Here’s the list of methods called in order to create a Button This equates to the CM_TEXTCHANGED notification message in
component in CLX: the VCL. In fact, most of the component messages from the VCL
UpdateShowing aren’t a part of CLX, and are replaced with dynamic methods. The only
HandleNeeded time we kept a CM_ type message was when it had to be broadcast to
CreateHandle multiple controls. Most of the time, however, the CM_ messages from
CreateWidget the VCL only need to notify a descendant that something happened.
InitWidget
Handling the Event
Setting the Caption The user event handler assignment is the same in the VCL and CLX.
This statement looks straightforward, but its implementation in the It’s just a simple property assignment:
VCL and CLX are very different:
Button.OnClick := ButtonClick;
Button.Caption := 'Hello, World!';
The real fun begins when you press the button and the event
In the VCL, setting the Caption is handled by a method named fires. If you put a breakpoint on the ShowMessage call, and press
SetText in the TControl class. SetText calls SetTextBuf, which in turn the button, you will stop in the middle of the user event handler
issues WM_SETTEXT and CM_TEXTCHANGED messages. named ButtonClick.
In CLX, SetText also handles setting the Caption, but in this case it’s Bring up the Call Stack debug window, and let’s follow this back about
overridden in TButtonControl. Take a look at Figure 9; you can see seven calls. At the top you’ll see you are in ButtonClick. Going backward
By Bruno Sonnino
I f you need to place images in the cells of a DBGrid component, you must accomplish
what is known as “custom drawing.” To do this, you must write an event handler for the
component’s OnDrawColumnCell event.
It’s declared as shown here: a bitmap and draw it on the DBGrid’s canvas. The
Object Pascal implementation is shown in Figure 1,
TDrawColumnCellEvent = procedure(Sender: and the run-time result is shown in Figure 2.
TObject; const Rect: TRect; DataCol:
Integer; Column: TColumn; It’s important to understand how DBGrid’s
State: TGridDrawState) of object; DefaultDrawing property works. If it is set
to True (the default), each cell is drawn before
where Rect is the rectangle where the data OnDrawColumnCell is called. This means that
should be drawn, DataCol is the index of the your custom drawing will take place after the
column to be drawn, Column is the TColumn default drawing has occurred. This is exactly
object relative to the data, and State is the cur- what you want in this case, because the rows also
rent state of the cell. contain text fields. If you set DefaultDrawing to
False, then you would also have to handle the
You must also test if the cell is of type drawing of the text fields.
TGraphicField. If it is, you then assign the field to
Instead of going to all that trouble, it’s perfectly
acceptable to let the DBGrid go through its
procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject;
const Rect: TRect; DataCol: Integer; Column: TColumn;
default drawing first, before calling your custom
State: TGridDrawState); OnDrawColumnCell event handler. This means
var that the text, (GRAPHIC), is initially written to the
Bitmap : TBitmap; cell, but the user never sees it. In fact, you can
begin
take advantage of this behavior. In this example,
// Test if the field is a TGraphicField.
if Column.Field is TGraphicField then the font size of the graphic cell has been set to
with DbGrid1.Canvas do begin 48, so that the cell is the proper size for the
// Clear previous information. graphic that will replace the text.
FillRect(Rect);
// Create the bitmap.
Bitmap := TBitmap.Create; Changing the Application Title
try
// Assign the field contents to the bitmap.
in the Taskbar
Bitmap.Assign(Column.Field); The title of the application that’s shown
// Draw the bitmap in the grid's canvas. in the Windows taskbar is provided by the
Draw(Rect.Left, Rect.Top, Bitmap); Application.Title property. If it isn’t explicitly set,
finally Delphi uses the caption of the main form.
Bitmap.Free;
end; Therefore, to change the title shown in the task-
end; bar, you must change the Application.Title prop-
end;
erty to the text you want. You can be as fancy and
Figure 1: Drawing a bitmap in a DBGrid. creative as you like.
Once you’ve interactively placed the icons in sequence in the Image- There is another trick to this function: rounding errors persist until
List, the code shown in Figure 4 “animates” the icon. You should the next time it’s called. So, before calling the function for the next
set the Timer’s Interval property to a value that provides a smooth line, you must clean the rounding errors, passing 0 as the second and
animation effect (500, for half a second, was used in this example). third parameters.
To print the line if the end of the text or the end of the paragraph
has been reached, there is no special procedure; a simple call
to TextOut will accomplish the task. Figure 9 demonstrates my
JustPrint procedure, which prints justified text. You must pass
three parameters to it:
1) a canvas,
Figure 10: The sample application justifies text on a form. 2) the text to print, and
3) the maximum width of the line.
// BegWord has the beginning of the word.
BegWord := i; Figure 10 shows the accompanying sample application with text
// Search until text is finished or a break is found.
justified on a form.
while (i <= Length(Text)) and
not (Text[i] in [' ', #10, #13]) do
Inc(i); // i is position of end of text or next break. Conclusion
This month I have placed five programming pointers at your finger-
tips to assist you in your Delphi development efforts. It’s now up to
The second step is to determine if the line length, with the new word you to put them to good use. ∆
included, exceeds the maximum line length. As the words fit in the
line, they are included in a variable named LineToPrint. The projects referenced in this article are available on the Delphi Infor-
mant Magazine Complete Works CD located in INFORM\2001\JAN\
This verification can be accomplished like this: DI200101BS.
Sleuth QA Suite 2
Powerful, Flexible Debugging and Profiling Tools
Version 1 of the suite has two tools: CodeWatch to monitor calls to API functions. In the first
is a debugger for finding memory leaks, resource category it can identify memory leaks, resource
leaks, problems with API calls, and more. Stop- leaks, and memory overruns. It includes a data-
Watch is a powerful profiler. New tools are being base of known errors for all Delphi 32-bit com-
added to Suite 2, which should be shipping by pilers so you can exclude them from your analysis
the time you read this article (see “What’s New in and concentrate on leaks in your code. You can
Suite 2” later in this review). also add known leaks to the database.
Each tool comes with the outstanding documen- In the API category, this tool can identify invalid
tation that’s become a TurboPower trademark. parameters or return values for Win32 API func-
That documentation includes a manual with a tion calls. You can have it create a log for all
thorough tutorial for each application to get you Win32 API calls, listing parameter values and
up and running fast. You can run either applica- return values. As you may be aware, not every
tion from within the Delphi IDE, or as a stand- API function works in every Windows version;
alone executable. some can be used only on the NT family. There-
fore, CodeWatch allows you to test platform
Debugging with CodeWatch compliance for Win32 API function calls.
CodeWatch is based on TurboPower’s popular
memory debugger, MemorySleuth. It signifi- This tool provides a great deal of flexibility giving
cantly extends the memory debugging capabili- you control over the errors to report. If your
ties of the older product, and adds new features application uses units for which you don’t have
the source code, you can still include them in
your testing. You can also analyze multiple mod-
ules at the same time, including dynamically
loaded DLLs.
Page Description
Module Shows information about the project mod-
ules used by the application being analyzed,
including name, when it was loaded, version
stamp, code, data size, etc.
Parameters Active only if one of the API function or
& Failures parameter options is selected. Provides a
report on errors resulting from API calls or
improper parameter values. You can also log
API calls receiving helpful information.
Debug Output Shows debug information generated by an
application calling the Windows API function,
OutputDebugString. You can also show inter-
nal Sleuth QA audit messages.
Figure 4: StopWatch’s user interface.
Report Provides comprehensive view of the results
of an application run, summarizing the infor-
Chart window at the lower left, which explains some of the resource
mation displayed in other views. You can
types being monitored. CodeWatch can conveniently take you right
print this report or select other options.
to the line of code where un-released memory is allocated.
Figure 2: CodeWatch’s four pages (views).
Profiling with StopWatch
StopWatch is the long-awaited profiler, a completely new tool from
TurboPower. I’ve tried a number of profilers, but in my opinion
none of them quite measures up to StopWatch. Most of the others
use an approach I would call invasive; they perform their profiling
by inserting lines of code into your source code units to perform the
actual profiling. StopWatch uses a technique called dynamic adaptive
instrumentation, which modifies the unit being profiled at run time.
This approach is fast and leaves your source code untouched.
A particularly nice feature is the collection of graphical display As with CodeWatch, StopWatch also includes an excellent tutorial,
views. One such view — Types, Stats, and Charts — consists a Maze that is begging to be optimized. The most time-consuming
of three re-sizable windows. The Event Browser provides statistics routine, Walk, is listed at the top. If you’re wondering about the
about the memory used, and a chart showing peak usage through- difference between Net Time and Gross Time, it’s quite simple.
out the duration of the project (see Figure 3). If you select this Net Time is the amount of time spent in the routine, excluding
view before beginning analysis of a project, you can watch the any time spent in routines called from within it. Gross Time is
chart create a real-time visual representation of your project’s the amount of time spent in the routine, including the time spent
memory use as the application executes. in routines called from within it. This helps to determine if a
bottleneck is in the routine itself, or in one of the routines it calls.
The screen shot in Figure 3 was taken at the conclusion of a
program run and includes the Session Summary dialog box, option- Like CodeWatch, StopWatch includes charts that let you view
ally displayed on program termination. It shows a summary of the various aspects of a single or multiple profiling runs. Seeing the
various leaks and errors. You’ll note that (most of ) the memory is most time-consuming routines in graphical format makes it easy to
released at the end, as shown in the graph. Note the Customize see where you need to perform optimizations. You can also choose
from the following, related to the current profile: matter if these modules are statically or dynamically loaded. Like
Net Times shows the 10 most time-consuming routines. StopWatch, CoverageAnalyst uses dynamic adaptive instrumenta-
Gross Times is similar to Net Times, but includes time spent tion to modify the module being analyzed at run time. According
in called routines. to TurboPower, coverage analysis was the most popular feature
Call Count shows the 10 most frequently called routines. request for the first version of Sleuth QA Suite.
Averages gives the 10 routines with the highest net average
execution time. LineProfiler, another result of frequent feature requests, allows
timing at the source line level. It also uses dynamic adaptive instru-
You can see the differences in two profiling runs in either text form mentation technology. It times each source line for the routines you
or graphical form, enabling you to determine if your attempts at select, keeping track of times executed, total time spent, maximum
optimization have been successful or not. There’s a Comparison time, minimum time, and the average time for each line.
Chart that lets you graphically compare profiles loaded into the
Comparison view. The final new tool, ActionRecorder, lets you build QA test scripts
by recording keyboard and mouse actions for an application and
Outstanding Documentation for playing them back later. You can initiate playback directly
If you’ve used other TurboPower products, you’re aware of the excel- from the ActionRecorder tool. You can also initiate playback auto-
lent documentation that comes with each of its products. Sleuth QA matically from within any of the four analysis tools after you’ve
Suite is no exception. As mentioned, the manual includes a tutorial launched an application.
for both tools (with all the files you need on disk). The manual
and online Help provide all the information you need to begin to In addition, Sleuth QA Suite 2 now supports 32-bit compilers
use these tools quickly. Sleuth QA Suite goes further by providing from both Borland and Microsoft. The new version supports
a cogent introduction to dealing with memory issues and perform- Visual Basic 6 and Visual C++ 6, giving Delphi developers who
ing code optimization. Once the Suite has shown you where the work with those tools an added bonus. ∆
problems are, the manual gives you important clues about what to
do to solve those problems. The material is so good that I’ve encour-
aged the folks at TurboPower to expand it in future versions. Even
without the extensive improvements in Suite 2, the first version of
Sleuth QA Suite is an essential tool for every Delphi and C++Builder
developer. Before we finish, however, let’s see what Suite 2 brings us.
By Ron Loewy
ExpressQuantumGrid
and ExpressInspector
Faced with a large enterprise application using TdxTreeList, and a DBGrid replacement named
MIDAS, I resumed my quest for the ultimate grid TdxDBGrid. A new version of the suite now
that would provide these capabilities. Enthusiastic offers a data-aware TreeList component, but for
praise for the ExpressQuantumGrid on Borland’s my needs it’s of lesser interest. The most impor-
newsgroups led me to look at the product. tant thing is that the grid control is based on
the same common ancestor, so it can display
ExpressQuantumGrid hierarchical information.
ExpressQuantumGrid includes two main com-
ponents: a TreeList view combination named In a nutshell, TdxDBGrid combines traditional
grid capabilities (tabular view of multiple rows
and columns) with the abilities of a run-time
data/report viewer with features such as grouping,
sorting, and summarization.
ExpressInspector
While a capable grid provides the ability to display
and edit multiple columns in more than one record of
data, sometimes it’s better to provide a single record
data form for editing. In this form you can display
more columns of data omitted from the grid view
because of screen real estate considerations, or provide
bigger areas for editing memo or graphic columns.
Phone: (702) 262-0609 In my opinion, a grid is the most important database UI control,
Web Site: http://www.devexpress.com and ExpressQuantumGrid is a must-have tool in my database com-
Price: ExpressQuantumGrid Suite: Standard, US$299; Professional, ponents arsenal. The ExpressInspector component is not as essential
US$349. ExpressInspector Suite, US$99. for every application, but if your application can use an object
inspector-like interface for single-record editing, this component
is easy to use and capable. I don’t hesitate to recommend it. It’s
I have to admit that I’m impressed with the quality of Developer well built and provides the same exceptional technical support from
Express’ technical support. Any question I submitted was immedi- Developer Express. ∆
ately answered via e-mail and solutions were provided when the
problems were in my code or understanding. The consensus among
Developer Express users on the Borland forums mirrors my experi- Ron is a software developer specializing in Business Intelligence applications.
ence — even when the issues are in the Developer Express code. He can be reached at rloewy@transport.com.
L ike physicians, programmers cannot rest on their laurels. The industry advances far too quickly for anyone to pull
a Rip Van Winkle and snooze through the implementation of popular technologies such as XML, SOAP, COM+, ad
infinitum. “You snooze, you lose” is a maxim that applies very well to the programming profession.
It is just as necessary to lay a strong foundation on which to hairy enough to challenge even Wendl’s powers of concentration.
fasten that knowledge. You need to acquire general principles of One afternoon, I was bent over a program listing while Wendl
programming before you can effectively apply the specifics related to was staring into space, his feet propped up on the desk. Our boss
new technologies and techniques. The principles are best acquired came in and asked, ‘Wendl! What are you doing?’ Wendl said, ‘I’m
through books, where you can commune with those older and wiser. thinking.’ And the boss said, ‘Can’t you do that at home?’”
A list of books which every programmer should read — and peri- The Psychology of Computer Programming by Gerald M. Weinberg
odically re-read — follows. They’re separated into two categories: [Dorset House, 1971] is about programming and software project
old classics and new classics. The old classics certainly aren’t as management, but most of all it’s about programmers and what
old as Stendhal’s The Red and the Black or even Steinbeck’s Grapes makes us tick. Perhaps as important, and even more surprising to
of Wrath, but as far as programming books go, they’re not spring non-programmers (including many managers) is what doesn’t make
chickens either. Although the original year of publication is shown, us tick. This book not only helps you understand yourself and your
many have enjoyed recent revisions. Why no Delphi classics you colleagues better (and even non-programmers, as their motives and
ask? That topic was addressed recently by Alan Moore in his world view are contrasted with those of programmers), but is also
November 2000 “File | New” column. an enjoyable read.
D elphi is more than an outstanding development tool. It’s a community. Nowhere is that more apparent than in
Project JEDI, the Joint Endeavor of Delphi Innovators. JEDI is a project on the move.
A lot has changed since I last wrote about the Project in the June One of those people was Helen Borrie (Australia), who has contin-
1999 Delphi Informant Magazine. If you’ve visited the JEDI Web site ued to be one of the most active and hard-working Jedians. On
(http://www.delphi-jedi.org) lately, you know what I’m talking about. the following Monday she wrote to the DDJ list, letting folks
The site won About.com’s “Best of the Net” award in March 2000. know what had occurred over the weekend. She began: “I’ve been
In listing the award, the Project’s goal was “to extend Delphi’s native astonished - amazed - heartened - all of that - to see how people
access to the Windows API by translating C/C++ headers of popular, have rallied around a perceived problem in the Borland support
but as yet unsupported, technologies into Delphi interface units.” machine and come up so willingly with the beginnings of a strategy
That was JEDI’s original goal, but the Project now encompasses to solve it. What a great weekend!” Then she expressed one of our
much more. I would describe it as “an impressive organization of initial dilemmas: “We here (a team of six Delphi developers with a
international volunteers donating their efforts to improve Delphi and variety of Windows and DOS backgrounds) are just having a little
help their fellow developers.” bit of trouble understanding what the project is aimed at.” Over the
days and weeks that followed the Project was defined and named,
That spirit of community is accentuated by the third-party vendors a president and other administrators selected, and work began on
who have generously contributed their tools and resources, including: the first translations.
Nevrona Designs, who donated licenses for ReportPrinterPro/Rave;
Digital Logikk AS, who donated copies of Time2Help for the Help Ups and downs, reorgs, Borland, and growth. The project had many
Team; and HREF Corporation, for hosting the Web site and provid- ups and downs in its first year. At times members wondered if the
ing their outstanding WebHub technology for the Web Team to use. Project would survive. Several early members deserve special recogni-
These are just three of many donations. Before discussing the exciting tion for managing those challenging times of the first year. Tim
new developments, I should go back and trace the Project’s beginnings Hayes, the first president of the Project, was one of the main driving
for the benefit of readers who may be just finding out about it. forces. Keith Anderson, another founding member, made Internet
support services available to the project. Robert Love organized Birds-
The Power of the Internet of-a-Feather sessions at the 1998 and 1999 Borland Conferences.
One thing is quite clear: Without the Internet there would be no
Project JEDI. In doing research for this column I found Brian The project had one especially low period. In early 1999 it seemed
Dupras’ 9/25/97 message that started it all, one that was posted to all but dead, with almost no discussions on the Internet and little
the former COBB Group DDJ list that I approved as a moderator of activity. Our current president, Thomas Guarino, took the initiative of
that list. It began, “I’ve been using Delphi since its beta days, and I’ve inviting three of us who were still active in Internet JEDI discussions
grown to truly love the product. There’s one thing that concerns me, (Michael Beck, Helen Borrie, and me) to form a new ADMIN Team.
however. Microsoft comes up with new SDKs all the time, most of Our goal was simply to get the project moving again, and we were
which could benefit countless Delphi developers if only we had the remarkably successful.
proper translations and code examples.”
Soon we learned that some folks at Borland had been watching the
Brian went on to explain how frustrating it was to put a lot of effort Project from a distance, wondering if it would survive and whether
into translating a header file, only to have Borland release its own they should get involved. We soon entered into a discussion with
version six months later. He also pointed out how quickly some of members of the Delphi R&D Team about ways we could work
the technologies were evolving and how out-of-date some of Borland’s together. (I covered much of this in my June column, so I won’t go
translations were at that time. To make a long story short, the DDJ into details here.) When Delphi 5 was released, the companion CD
list was flooded with messages that evening, and the notion of getting included one of our conversions. There was also a JEDI Easter egg
together and taking on the task ourselves quickly emerged. A handful included in Delphi 5 (type AJEDI in the About box). Charlie
of us participated in an Internet chat session the next day, resulting in Calvert was one of the most important people at Borland who helped
the beginnings of an organization. foster the new relationship in so many ways.