Pascal Newsletter #15 - 31-JAN-2001
INDEX
1. A FEW WORDS FROM THE EDITOR
2. JFCONTROLS LIBRARY
- DOWNLOAD
- INSTALLATION
- RUNNING THE DEMO
- MY FIRST EXAMPLE
- CENTRALIZED ADMINISTRATION OF RESOURCES
- FEATURES OF JFCONTROLS LIBRARY
- COST AND PAYMENT METHODS
3. ERROR HANDLING IN DELPHI 5 (II)
- DEFAULT EXCEPTION HANDLER
- API ERRORS
- API ERRORS AS EXCPETIONS
- CUSTOM EXCEPTIONS
- OTHER ERRORS
4. WINDOWSE - ADVANCED WINDOWS ANALYSER!
- GREATIS SOFTWARE
- WINDOWSE
- LICENSE
5. A DBGRID WITH A CHECKBOX
6. BORLAND HAS JUST ANNOUNCED AVAILABILITY OF KYLIX
________________________________________________________________________
1. A FEW WORDS FROM THE EDITOR
In this issue I'm glad to present JfControls Library, a components
package that will help you build applications with a very professional
look and functionality.
---------------------------------------------
I M P O R T A N T A N N O U N C E M E N T
---------------------------------------------
Before writing this article, I contacted the makers of this library and
convinced them to do a drawing ("raffle") with one license of their
library (including three months of free updates), and as a special
courtesy, the subscribers of this newsletter that participate in the
drawing will be given two numbers and can get more numbers by referring
other participants. To participate, or get more information:
http://www.latiumsoftware.com/jfcontrols/index.php?lang=en
Regards,
Ernesto De Spirito
eds2008 @ latiumsoftware.com
________________________________________________________________________
JfControls Library. Multi-language. Multi-appearance. Skins. Privileges.
More than 40 integrated and customizable components. Impressive GUI.
Centralized resources administration. Multiple programming problems
solved. For Delphi 3-2006 & C++ Builder 3-6. http://www.jfactivesoft.com
________________________________________________________________________
2. JFCONTROLS LIBRARY
Looking for Delphi links to publish in the past issue I came across
JfActiveSoft:
http://www.jfactivesoft.com/
My first thought was "just another components package", but I started
reading the features and they looked interesting, so I decided to
download it and give it a try... Well, I can anticipate you that it's
not just another components package! It really impressed me so much
that I decided to write about these controls, but I can't tell you in
words what they look like. You'll have to see them by yourself...
DOWNLOAD
========
http://www.jfactivesoft.com/endownload.htm
Download the following files:
* General program for installation (JfSetup)
* JfControls library Trial (available for D3, D4 and D5)
* Demo program of the JfControls library
This is enough to see the demo, but now that you are there, also
download the following files because quite probably you'd like to have
them after seeing the demo:
* JfControls Library Help (available for D3, D4 and D5)
* Tutorial in PDF format of the JfControls library
Both files are available in English and Spanish
INSTALLATION
============
The installation is really easy. First of all you have to install
JfSetup (the general program for installations). This will create a
group named JfActiveSoft in your Start menu where you'll find JfSetup.
Then you have to decompress the rest of archives in a temporary folder
and run JfSetup to install them in your system (use the 'Add' button).
And this is it. You don't have to configure Delphi, edit .inc files,
compile units, install packages or anything...
RUNNING THE DEMO
================
Now that you have the components installed, run Delphi and open the
the demo project, which is usually located at:
C:\Program files\JfActiveSoft\JfControls_Demo\JfDemoSt.dpr
Press F9 and start exploring the demo... I recommend you to click on
"Components for menus" and then select "TJfMainMenu". Use the mouse to
navigate thru ALL the options in the menus and submenus because there
are some interesting things to see... You can also play a bit with the
options in the dialog box... Click "Configuration" in the top menu,
select "Colors configuration (Themes)", choose a color scheme and click
"OK". Click "Configuration" again and this time select "Language
selection" and then choose for example "Spanish" and click "OK". Now
click on "Configuración" and choose "Selección de idioma", choose
"Ingles" and click on "Aceptar" to restore the English configuration.
MY FIRST EXAMPLE
================
How difficult would be to make something like that demo with these
components? Start a new project and see it by yourself...
In the Components Palette you'll see three new tabs: JfStandard,
JfAdditional and JfDataControls that hold about 40 components in total,
but in this example we are only going to use a few components of the
JfStandard tab.
First of all, drop a TJfCApplication and TJfCForm component to your form.
The main form of your application should have a TJfCApplication component
and every form should have a TJfCForm component. It's not completely
necessary actually, but some features depend on this.
Now we are going to add a background to the form:
* Click the JfCForm1 component you've just dropped
* In the Object Inspector look for the SetBackground property and click
its ellipsis (...) button. You'll see the "SetsBackGround" dialog.
* Click "Add". You'll see the "Add BackGround" dialog.
* If you want to can provide a name and description for the background
(for example "Standard Background 1" and "Simple gradient"
respectively).
* In the Style combo choose "bgsHorzOut"
* Select the Start and End colors (you can click on the color-picker
buttons to select the colors). In the "Result Background" area you'll
see a preview of your background.
* Click "OK" to add the new background. You'll see it in the list.
* Click "OK" to select this background for the form.
The new background will be visible when you run the application, so
press F9 to see it. Stop the application and now drop a TJfCLabel to your
form. Now we are going to set the font for the label. It might seem a
bit complicated at first, but you'll realize the advantage later:
* Click the JfCLabel1 component you've just dropped
* In the Object Inspector look for the Text property and click the
"plus" (+) button.
* Find the SetFont property and click its ellipsis (...) button. You'll
see the "SetsFont" dialog.
* If you want to can provide a name and description for the font (for
example "Font1" and "Times New Roman 14 Bold" respectively).
* Click on the little button next to the Font to open the dialog
* Select "Times New Roman", "Bold" and "14" and click OK.
* Click "OK" to add the new font. You'll see it in the list.
* Click "OK" to select this font for the label.
Now set the background for the label following a similar procedure like
you did with the JfCForm1 component, adding a new background to the
list.
Now set the shape of the label:
* Set AutoSize to False.
* Open the Shape object property (clicking the "plus" (+) button).
* Set the Visible property of the shape to True.
* Set the Shape property of the shape to shaArrow.
* Open the Brush object property of the shape.
* Click its ellipsis (...) button of the SetBackground property of
the Brush. You'll see the "SetsBackground" dialog.
* Select the background you first gave to the form and click "OK".
* Resize the label so that the caption text fits inside the arrow.
Drop a TJfBitBtn to your form and set its font:
* Click the JfBitBtn1 component you've just dropped
* In the Object Inspector look for the Text property and if necessary
click the "plus" (+) button to open the options.
* Find the SetFont property and click its ellipsis (...) button. You'll
see the "SetsFont" dialog.
* You can add a new font as you've done before, but this time simply
choose the one we set for the label and click OK.
Now set the background of button with the SetBackground property, but
this time selecting an existing one (the one of the label, or the one
of the form).
CENTRALIZED ADMINISTRATION OF RESOURCES
=======================================
As you can see, there's a centralized list of backgrounds and also a
list of fonts, that act as a repository for those kind of resources.
There are also repositories for images, colors and string constants.
These repositories are called "packages" (don't mistake them with Delphi
packages). It takes some steps to add a new resource, but once you've
done it, they are easy to use it, speeding up the design of your
application.
This model has an important side-effect, which is one of the reasons why
JfControls were designed this way: if you modify a resource, all
components that share it will automatically be "updated". For example,
click the SetFont property of the button, click the "Modify" button and
then change the font to Arial and click "OK" to apply the changes and
"OK" to select the font. As you can see, the change applied also to the
label, because they both share the same font resource. In the case of
string constants, there's also a repository for them, and for example
this allows translation.
There's another important side-effect, which is perhaps the main reason
for the existence of JfControls: in the case of the image repository,
each image is loaded only once and used many times, being friendly with
system resources.
FEATURES OF JFCONTROLS LIBRARY
==============================
* Packages administration for configuration.
It's possible to store all type of configurations for the components
in "packages". These "warehouses" can be saved as files apart from the
application or in the DFM files of Delphi that later on are integrated
in the own executable one. When the packages are kept in independent
files of the executable, they have the advantage of being able to be
selected at run time, and this way an application can change its
language or appearance.
* Multilanguage in run and design time.
The packages technology give you the possibility to develop
applications with support for several languages. Easily you will be
able to build applications that changes in run and design time of one
to other language. The library has incorporated special properties
editors to facilitate the translation.
* Multiconfiguration in run and design time for backgrounds, colors,
fonts and images.
An application made with the JfControls library has the capacity of
change its appearance in run and design time
* Centralized configuration of colors, fonts, backgrounds, images,
strings, messages and texts.
The packages technology allows to make groups of common elements.
There are packages for configuration of colors, fonts, backgrounds and
images. This way a color, font or image can be used in different
places of application, windows, controls, etc.
* Transparencies administration in all the components.
All the controls of JfControls library, panels, edition fields,
RadioGroups, selection list, check box, etc., allow to make
transparencies with the background of the container in which they are.
* Container package of images that admits simultaneously graphic formats
of any type.
The images package is able to contain all type of graphic formats that
are or can be installed in Delphi. The JfControls library by default
supports the ICO, BMP, WMF, JPG formats, but the installation of
another freeware or shareware packages will make the library support
additional formats. There are some special functions to carry out
their registration inside the library.
* Variables package for manual and automatic configurations of
application.
There's a special type of package that is able to save variables of
all types in a nested structure, like in the Windows registry, and
it is used to automatically save the positions and sizes of windows
and others significant window elements, and at same time it's good as
a container for the variables that the user wish to save in it.
It has like advantage over the Windows registry that it's independent
of the operating system, it's managed in memory, it's transparent to
the developer and it's easily portable.
* Regional configuration imbued in the library.
The regional configuration is independent of the operating system, so
that -if you wish- the application is not subject to Windows formats
of dates, times, numbers, etc. All these is saved in the language
packages and it's independent of the language that you select.
* Label associated to all the controls.
All controls of the JfControls library have an associated label, which
is completely customizable and can be placed anywhere you like it.
* Multiple procedures and functions that simplify the development of
applications.
There are several procedures and functions that facilitate the manage
of windows and configuration packages of the library. The JfControls
library has been developed thinking in voluminous applications replete
of windows, for which one should use the auto-creation characteristic
of Delphi windows only in few occasions and it's better if you don't
use it, because the application will run most quickly and will use
better Windows resources.
The procedures and functions that are included in the library improve
the administration of windows creation and destruction, and they
alleviate the load on system resources, also allowing dynamic changes
of style. There also are functions to manage strings, dates, numbers,
messages, exceptions and more.
* Multiple traditional problems resolved.
The JfControls library is not limited to incorporating a group of
components and controls for application development, but also have
fixed all the traditional problems that take place during the
elaboration of a project, problems relative to graphics, as the
administration of diverse graphic formats from the databases and their
visualization in the TJfDBImage component, positioning of MDI-child
windows, automatization of the parent-MDI window's buttons,
administration of backgrounds in main MDI windows, colors and fonts in
administration of messages and in administration of errors, correction
of flicks in the repainted of forms and controls, etc.
* New mask administration with multi-location.
The JfControls library incorporates a new masks system, much more easy
to use, because the controls have the possibility to know the data type
that they will manage through their DataType property, but masks
administration is not limited to a local control in the component, but
rather it can be based in the definitions that you have made at the
level of all the application, at the level of the window in which the
control is or in a local mode.
These capacities enable an application to change at a global level the
definition of masks for all the windows or for some in short, making
more easy to work, for example, with several different periods of
date, with different decimal types for money, etc., inside of one
application.
* Data type administration in all the controls.
All the controls have a DataType property that indicate them the data
types they will manage. This, together with their Value property of
Variant type, give them possibilities of format and use much
more easy. The data types at the moment supported are: Integer,
Currency, Double, DateTime, String, Binary and Memo.
* Special optimization system of the operating system resources.
The JfControls library executes a series of special procedures in the
graphics administration, so that the library gets a liberation of
system resources, enabling applications to use a lot of quantity of
graphics without draining the resources of the machine and giving the
possibility to carry out application much bigger.
* 30 components completely customizable.
The components of JfControls library share the properties that allow
them to use the configurations defined in packages, so they can be
completely customizable. All the components have common properties to
define the text, associate label, masks, transparency, resize,
position, privileges and visibility.
* 11 components linked to data.
The data components are linked to data sources that have been
implemented using the standard data links of the VCL, so they are
compatible with any dataset developed starting from the version 3 of
Delphi. This way the data components can be used with the BDE, IBX,
ADO Express or any other group of components derived of the standard
Delphi dataset.
* Menu bar completely customizable.
The menu bars have been totally reprocessed to achieve a distinction
touch and functionality that you won't be found in traditional
applications. Their capacity and easiness of configuration will give
you the possibility to create applications that will be distinguished
very easily from others. Several menu bars can simultaneously exist
in the same window, with different alignments and different scroll
possibilities.
The menus of JfControls library allow banners at any level, including
the main bar of a menu. They have alignment capacity and they can have
backgrounds with gradients, images and solid colors. The texts allow
angles, different styles and colors. The submenu borders can be
defined and they can have images in the different options.
The menu bar controls automatically the buttons in MDI child windows,
they can be changed of shape, background, etc. The same capacity of
configuration has been implemented in the popups.
* More than 40 shape types for labels and buttons.
Most of the library's controls allow to take different shapes or to
incorporate different shapes in their interior. This way, for example,
the TJfSpeedButton, TJfLabel or TJfCheckBox components can take more
than 40 types shapes and the TJfListBox component when working in
CheckBox mode allows each mark to have a certain shape. The shapes can
have image backgrounds, gradient or solid colors, and they can
incorporate lines of different sizes, styles and colors.
* Embedded forms.
The TJfScrollBox component has special procedures to manage other
windows in its interior. These procedures automate the creation and
destruction of the forms and negotiate the location of window inside
the component.
* Control for visualization of images that resists any graphic format
type.
The TJfImage component has been transformed and improved to make it
able to manage any graphic format type installed in Delphi, it can
even work in format-autodetection mode. The database version of this
component has the same functionality and it's able to save in the
same table field any graphic format simultaneously.
* TJfPageControl component with exclusive customization possibilities.
The TJfPageControl component allows a complete customization for its
tabs, they can take the buttons style with different shapes and
backgrounds, or a more traditional style. The tabs can be in any
position, to be multiline or in scroll mode.
* StatusBar completely customizable and with defaulted information
types.
The TJfStatusBar component is completely customizable, it allows
backgrounds and styles for any internal panel, letter types,
multiline text, defaulted information (Time, Bloq.num, Num.Caps,
etc.), embedded progress bar, images and much more.
* TJfLabel component with shapes, text with angle, images and multiline.
The TJfLabel component is a highly sophisticated label control,
simultaneously it's able to manage embedded shapes, accessory labels,
text with angle, multiline text, shade, backgrounds with images,
gradient, water marks, solid colors, shines, annexed images,
privileges, masks, data types and defaulted information.
Most controls have associated a label that can be placed in any
position and has the same functionality, almost as complete as the
TJfLabel component.
* Edition field with incorporated buttons.
The TJfEdit component is a edition field with transparency, masks
administration, data type to manage, backgrounds with images,
gradient, solid colors, shade, enclosed image, associated label, 6
enclosed buttons (Calendar, calculator, maintenance, relationship,
customizable 1, customizable 2) completely customizable, privilege of
centered access, different styles for borders, special property for
the execution of data, when is pressed the ENTER key, without
necessity of passing the focus to the following control, capacity to
specify a period of time so that the OnChange event takes place
(synchronizations with fields of a database).
* Buttons bar of administration and navigation for the components of
images, texts and databases.
In JfControls library there are several button bars that are good to
manage the characteristics of load, recording and erasing of TJfMemo,
TJfRichEdit and TJfImage controls. There is also the traditional
navigation bar for the registries administration in a data source. In
all of them you can configure the shape of the buttons, the background
and their visibility. These bars connect with the referenced controls.
* Enlarged administration of rich texts.
The TJfRichEdit component is for multiline rich text edition and
allows solid color for background, shade, totally customizable
associated label, privilege of centered access, inclusion of images
next to the text, insertion of OLE objects, dialog box with a complete
environment to edit rich text and traditional mode of handling.
* Progress bar completely customizable.
The TJfProgressBar component is a progress bar that has been
completely rewrite and allows backgrounds with images, gradient, solid
colors, transparencies, shades, associated label, privilege of
centered access, orientation of the bar and blocks movement, different
block size, backgrounds completely customizable for blocks and
different border types.
* Privileges administration.
The TJfCApplication component allows a centered administration of
access and visualization privileges of all the library controls. You
can create definitions of permits and connect several controls to any
of them, this way the handling of that permit automatically produces
a status change in all the controls linked to it.
One of the most widespread uses in the privileges administration is
the capacity to give some permits or others, according to the user
that uses the application, facilitating the work of granting and
removing the visibility or the handling of controls.
* Customizable calculator and calendar incorporated.
There is a customizable calculator and calendar that can be executed
from the buttons of edition fields or from the TJfCApplication
component. The calendar allows resizing so you can see more or less
months. Both components are coupled automatically to the
characteristics of the regional configuration indicated in the
TJfCApplication component.
* Administration of image-shaped forms.
There are new components to create image-shaped forms. The windows
generated this way can take any shape that you can imagine. You'll
surely impress your users. The shapes of the windows can be changed at
run time. Buttons can manage different images and backgrounds for each
one of their status. Mouse detection can be carried out within regions
or within the total area of button. The TJfBitBtn component can even
take shaped forms.
* Visual manual.
There's a complete tutorial very visual which facilitates the
adaptation to the components handling, while introducing you, step by
step, in the development of your applications.
* Complete context help from Delphi.
The context help is complete, so that you will be able to see the
explanations of all classes, properties, methods, events, procedures
and functions of JfControls library.
* Compatibility.
The library is compatible with Delphi 3 to 5, and Windows 95, 98, Me,
NT and 2000.
COST AND PAYMENT METHODS
========================
The JfControls Library with 3 months of free updates costs Euros 195.33
/ $ 180.23 USD, and the annual updates subscription costs Euros 126.21 /
$ 116.45 USD. Library+Sources are now available for sale and they cost
Euros 390.66 / $ 362.34 USD.
You can pay online if you have Visa, Mastercard, 4B, American Express or
Virtual Cash credit card. If you have another credit card or don't wish
to pay online, there's a printable form at
http://www.jfactivesoft.com/ensales.htm
that you have to complete and send by fax to +34 96 6655275. You can
also pay them by a bank transfer:
Banesto Plaza de Crevillente, 3 - Elche (Alicante) - Spain
Entity 0030 Branch 3125 Account : 33-0387300273.
Include Euros 16.83 / $ 15.05. for bank wire fee.
You have to send the transfer voucher by fax to +34 96 6655275.
________________________________________________________________________
3. ERROR HANDLING IN DELPHI 5 (II)
The first part of this article was published in the last issue:
http://www.latiumsoftware.com/en/pascal/0014.php
DEFAULT EXCEPTION HANDLER
=========================
Appart from trapping an exception to display the corresponding error
message, a try..except..end block allows applications to perform some
clean-up or finalization code, habitually to free allocated resources
(close open files, release memory, etc.). For example, in the following
procedure we free the string list whether an exception occurred or not:
procedure TForm1.Button1Click(Sender: TObject);
var
StringList: TStringList;
begin
StringList := nil;
try
StringList := TStringList.Create;
StringList.LoadFromFile('');
ShowMessage(StringList.Text);
except on e: exception do
HandleError(Sender, e);
end;
StringList.Free; // Finalization code.
end;
For procedures that doesn't need to free resources, for example like
this one:
procedure TForm1.Button2Click(Sender: TObject);
var
i: integer;
begin
i := 0;
ShowMessage(IntToStr(10 div i));
end;
...you don't need to use a try block, and you can still trap exceptions.
The trick is done by assigning an OnException event handler for the
Application object. To simplify this task for the programmer I wrote a
procedure HandleApplicationExceptions that assigns to OnException a
procedure that shows the corresponding error message and saves it in the
errors log. To make use of it, you simply have to call this procedure
for example when your program starts:
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1},
ErrHndlr in 'ErrHndlr.pas';
{$R *.RES}
begin
Application.Initialize;
HandleApplicationExceptions; // Activate the error handler
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
For those of you who might be interested in the implementation details,
in the ErrHndlr unit I defined HandleApplicationExceptions as follows:
procedure HandleApplicationExceptions;
begin
Application.OnException := AppExceptionHandler.Handler;
end;
It simply assigns the OnException property of the Application object to
the address of the AppExceptionHandler.Handler method. I had to declare
a little class to provide this procedure of type TExceptionEvent (the
type of the OnException property), declared in the Forms unit:
type
TExceptionEvent = procedure(Sender: TObject; E: Exception) of object;
I declared this class in the implementation section of ErrHndlr as
follows:
type
TAppExceptionHandler = class(TObject)
public
procedure Handler(Sender: TObject; E: Exception);
end;
var
AppExceptionHandler: TAppExceptionHandler;
procedure TAppExceptionHandler.Handler(Sender: TObject; E: Exception);
begin
HandleError(Sender, E, nil);
end;
The method just calls the HandleError(Sender,E,Address) procedure
presented in the past issue.
NOTE: I didn't create the instance AppExceptionHandler because we
don't need it since we never access properties of this object, so
it doesn't have to exist.
Using this event handler, the line appended to the errors log for the
error produced in TForm1.Button2Click would look like the following
Mon 08-Jan-2001 15:39:28 - EDivByZero: Division by zero [Form1]
@ 44748F
API ERRORS
==========
Windows API functions don't use Delphi exceptions. Rather they report
error conditions in their return value. Most of them return 0 (or False)
if unsuccessful and you can get the error code by calling GetLastError
immediately aftwards (before calling any other API function). To obtain
the corresponding error message you can pass this code to the function
SysErrorMessage.
You can use the errors and raise exceptions, like I'll show you below,
but I also decided to write a couple of overloaded functions to handle
api errors directly:
procedure HandleError(ApiError: integer); overload;
var
Address: Pointer;
begin
asm // Address := %ReturnAddress%;
mov ecx, [ebp+4]; // ECX := (EBP+4)^;
mov Address, ecx; // Address := ECX;
end;
HandleError(nil, ApiError, Address);
end;
procedure HandleError(Sender: TObject; ApiError: integer); overload;
var
Address: Pointer;
begin
asm // Address := %ReturnAddress%;
mov ecx, [ebp+4]; // ECX := (EBP+4)^;
mov Address, ecx; // Address := ECX;
end;
HandleError(Sender, ApiError, Address);
end;
Both are wrappers that provide the Address parameter for the following
procedure:
procedure HandleError(Sender: TObject; ApiError: Integer;
Address: Pointer); overload;
var
ErrMessage: string;
begin
ErrMessage := SysErrorMessage(ApiError);
ShowErrorBox(ErrMessage);
SaveError(Sender, 'Error WinAPI #' + IntToStr(ApiError)
+ ': ' + ErrMessage, Address);
end;
This procedure is similar to the HandleError(Sender,E,Address) procedure
that I presented in the last issue.
Here is an example of use of HandleError with API errors:
procedure TForm1.Button3Click(Sender: TObject);
var
Handle: THandle;
Buffer: array [0..511] of char;
BytesRead: longword;
begin
Handle := CreateFile('project1.dpe', GENERIC_READ,
FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
if Handle = INVALID_HANDLE_VALUE then
HandleError(Sender, GetLastError)
else begin
if not ReadFile(Handle, Buffer, 511, BytesRead, nil) then
HandleError(Sender, GetLastError)
else begin
Buffer[BytesRead] := #0;
ShowMessage(Buffer);
end;
CloseHandle(Handle);
end;
end;
The line appended to the errors log will look like this:
Mon 08-Jan-2001 15:41:06 - Error WinAPI #2: The system can't find the
specified file [Form1.Button3] @ 445C31
API ERRORS AS EXCPETIONS
========================
Another way of handling API erros is by raising an exception when they
occur so we can use the exception handling mechanism we've seen before.
For example:
procedure TForm1.Button4Click(Sender: TObject);
var
Handle: THandle;
Buffer: array [0..511] of char;
BytesRead: longword;
begin
Handle := INVALID_HANDLE_VALUE;
try
Handle := CreateFile('project1.dpe', GENERIC_READ,
FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
if Handle = INVALID_HANDLE_VALUE then
raise Exception.Create(SysErrorMessage(GetLastError));
if not ReadFile(Handle, Buffer, 511, BytesRead, nil) then
raise Exception.Create(SysErrorMessage(GetLastError));
Buffer[BytesRead] := #0;
ShowMessage(Buffer);
except on e: Exception do
HandleError(Sender, e);
end;
CloseHandle(Handle);
end;
The line appended to the errors log will look like the following:
Mon 08-Jan-2001 15:42:17 - Exception: The system can't find the
specified file [Form1.Button4] @ 445DEA
CUSTOM EXCEPTIONS
=================
Raising exceptions this way is a bit expensive in code size. We can
define a procedure to simplify things a little bit:
procedure RaiseApiError(ApiError: integer);
begin
raise Exception.Create(SysErrorMessage(ApiError))
end;
Then you can use it this way:
procedure TForm1.Button4Click(Sender: TObject);
...
if Handle = INVALID_HANDLE_VALUE then
RaiseApiError(GetLastError);
if not ReadFile(Handle, Buffer, 511, BytesRead, nil) then
RaiseApiError(GetLastError);
...
end;
The problem with converting API errors to exceptions is that we lose the
error code information because the Exception class doesn't define a
field with an error number. For this reason I defined a base class for
custom exceptions that provides two more fields: one for an error number
and another one for the caller address:
type
ECustomError = class(Exception)
public
Number: Integer;
Address: Pointer;
constructor Create(const ErrMessage: string; Address: Pointer);
overload;
constructor Create(const ErrMessage: string; Number: Integer = 0);
overload;
constructor Create(const ErrMessage: string; Number: Integer;
Address: Pointer); overload;
end;
procedure RaiseCustomError(const ErrMessage: string;
Number: Integer = 0);
implementation
constructor ECustomError.Create(const ErrMessage: string;
Address: Pointer);
begin
Create(ErrMessage, 0, Address);
end;
constructor ECustomError.Create(const ErrMessage: string;
Number: Integer; Address: Pointer);
begin
inherited Create(ErrMessage);
Self.Number := Number;
Self.Address := Address;
end;
{W+}
constructor ECustomError.Create(const ErrMessage: string;
Number: Integer);
var
Address: Pointer;
begin
asm // Address := %ReturnAddress%;
mov ecx, [ebp+4]; // ECX := (EBP+4)^;
mov Address, ecx; // Address := ECX;
end;
Create(ErrMessage, Number, Address);
end;
procedure RaiseCustomError(const ErrMessage: string; Number: Integer);
var
Address: Pointer;
begin
asm // Address := %ReturnAddress%;
mov ecx, [ebp+4]; // ECX := (EBP+4)^;
mov Address, ecx; // Address := ECX;
end;
raise ECustomError.Create(ErrMessage, Number, Address);
end;
We can now derive an EApiError class from ECustomError:
type
EApiError = class(ECustomError)
public
constructor Create(ApiError: Integer); overload;
constructor Create(ApiError: Integer; Address: Pointer); overload;
end;
procedure RaiseApiError(ApiError: integer);
implementation
constructor EApiError.Create(ApiError: Integer; Address: Pointer);
begin
inherited Create(SysErrorMessage(ApiError), ApiError, Address);
end;
constructor EApiError.Create(ApiError: Integer);
var
Address: Pointer;
begin
asm // Address := %ReturnAddress%;
mov edx, [ebp+4]; // EDX := (EBP+4)^;
mov Address, edx; // Address := EDX;
end;
Create(ApiError, Address);
end;
{W+}
procedure RaiseApiError(ApiError: integer);
var
Address: Pointer;
begin
asm // Address := %ReturnAddress%;
mov edx, [ebp+4]; // EDX := (EBP+4)^;
mov Address, edx; // Address := EDX;
end;
raise EApiError.Create(ApiError, Address);
end;
Now RaiseApiError raises an EApiError exception that includes the error
code and the address where the exception was risen, so we just have to
make a little modification to our old HandleError(Sender,E,Address)
procedure:
procedure HandleError(Sender: TObject; E: Exception;
Address: Pointer); overload;
begin
ShowErrorBox(E.Message);
if E is ECustomError then with ECustomError(E) do
SaveError(Sender, E.ClassName + ' #' + IntToStr(Number)
+ ': ' + Message, Address)
else
SaveError(Sender, E.ClassName + ': ' + E.Message, Address);
end;
Now the line appended to the errors log when an API error occurs would
look like this:
Mon 08-Jan-2001 15:42:17 - EApiError #2: The system can't find the
specified file [Form1.Button4] @ 445C31
OTHER ERRORS
============
There are other errors that might occur in an application and that one
would like to save in an errors log. Mainly these are internal errors,
programming errors, logic errors, or whatever you call them.
You can use RaiseCustomError to raise them as an exception, like for
example:
procedure TForm1.Button5Click(Sender: TObject);
begin
if (GetTickCount And 1) <> 0 then
RaiseCustomError('An error condition occurred');
end;
Because we didn't use a try block, the exception will be captured by
the OnException event handler of the Application object, and the line
appended to the errors log might look like this:
Mon 08-Jan-2001 15:42:17 - ECustomError #0: An error condition
occurred [Form1] @ 445EE1
Like in the case of API errors, I also wrote a couple of procedures to
handle these errors without making use of exceptions:
procedure HandleError(const ErrMessage: string); overload;
var
Address: Pointer;
begin
asm // Address := %ReturnAddress%;
mov ecx, [ebp+4]; // ECX := (EBP+4)^;
mov Address, ecx; // Address := ECX;
end;
HandleError(nil, ErrMessage, Address);
end;
procedure HandleError(Sender: TObject; const ErrMessage: string);
overload;
var
Address: Pointer;
begin
asm // Address := %ReturnAddress%;
mov ecx, [ebp+4]; // ECX := (EBP+4)^;
mov Address, ecx; // Address := ECX;
end;
HandleError(Sender, ErrMessage, Address);
end;
They both get the address parameter to call HandleError:
procedure HandleError(Sender: TObject; const ErrMessage: string;
Address: Pointer); overload;
begin
ShowErrorBox(ErrMessage);
SaveError(Sender, ErrMessage, Address);
end;
You can use of these procedures as shown here:
procedure TForm1.Button5Click(Sender: TObject);
begin
ShowMessage('Initialization code');
if (GetTickCount And 1) <> 0 then
HandleError(Sender, 'An error condition occurred');
ShowMessage('Finalization code');
end;
The line appended to the errors log might look like this:
Mon 08-Jan-2001 15:42:17 - An error condition occurred [Form1]
@ 445EE1
- - - - - - - - - - - - - - - - - - - - -
I hope you've found this article useful. If you have doubts or questions
you can subscribe to our low-traffic free mailing list. This is the only
forum for intermediate-level Delphi programmers on the Web (Delphi
hackers are also welcome :-)). If you know much of Delphi but you are
still far from being a guru this forum is for you:
http://groups.yahoo.com/group/delphi-en
If you want to join the group, the best way is to subscribe from the
web since you can access the special features available at the web site
(a Yahoo! ID is required and you can get yours free by registering as a
Yahoo! user), but if you don't want to register or if you don't have
full Internet access you also can subscribe by email:
http://groups.yahoo.com/group/delphi-en/join
delphi-en-subscribe@yahoogroups.com
________________________________________________________________________
4. WINDOWSE - ADVANCED WINDOWS ANALYSER!
GREATIS SOFTWARE
================
Greatis Software is a rapidly growing company based in Yaroslavl,
Russia, that specializes in system software development and special
software for developers. Their web page is http://www.greatis.com and
there you can find a lot of freeware application and components, some
of them with source code.
WINDOWSE
========
One of the applications you can find there is WinDowse, an extremely
convenient tool for obtaining necessary technical information about any
window (remember that a component is itself a window). When you place
the mouse cursor on a window, WinDowse will show you all parameters of
the window, window class, parents and children including:
* "Window" tab
- Text or caption
- Process ID
- Exe filename
- Application instance
- Window handle
- Parent window handle
- Window function address
- Window menu handle
- Coordinates in parent
- Coordinates in screen
- Window size
- Window client area size
- Window style and extended style
* "Class" tab
- Class name
- Class function address
- Icon and small icons handles
- Cursor handle
- Background brush handle
- Module handle
- Class style.
* "Parents" tab
- List of parent hierarchy
* "Children" tab
- List of children of current window
* "Graphics" tab
- Absolute (screen) cursor position
- Relative cursor position on window coordinates
- Relative cursor position on window client area coordinates
- Color of the pixel under mouse cursor
- Screen capture tools: display, zoom, copy, save
All parameters can be shown in hexadecimal, decimal or binary formats.
Upon activation, WinDowse displays a continuos readout as the user moves
the mouse about the screen - switching back and forth between separate
or nested windows. At any time the continuous readout can be frozen by a
click of the mouse, and the data for that window studied in detail.
WinDowse also allows results to be copied directly to the clipboard.
Each field of the analysis is supplied with context-sensitive help
explaining "what is".
LICENSE
=======
WinDowse 4.1 is FREE. Full source code for Delphi costs $19.95(US).
To order the sources visit http://www.greatis.com/windowsebuy.htm
For more information, contact Greatis Software: b-team@greatis.com
________________________________________________________________________
5. A DBGRID WITH A CHECKBOX
In the last issue I promised to show how to place checkboxes for boolean
fields in a DBGrid. Although the code is usable, of course it would be
better to use some professional component like one of those you can
surely find in the net. The purpose of this article is simply to present
an example of the use of some properties of the DBGrid, Column and Field
objects.
The first thing we have to take care of is displaying the checkbox. For
this purpose we should trap the OnDrawColumnCell of the DBGrid:
procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject;
const Rect: TRect; DataCol: Integer; Column: TColumn;
State: TGridDrawState);
begin
ChkDBGridDrawColumnCell(Sender as TDBGrid, Rect,
DataCol, Column, State);
end;
ChkDBGridDrawColumnCell is a procedure I declared in a separate unit:
procedure ChkDBGridDrawColumnCell(DBGrid: TDBGrid;
const Rect: TRect; DataCol: Integer; Column: TColumn;
State: TGridDrawState);
var
X, Y, Index: integer;
Field: TField;
begin
Field := Column.Field;
if (Field <> nil) and (Field.DataType = ftBoolean) then begin
// Fill the cell with the background color
DBGrid.Canvas.FillRect(Rect);
// Determine the position of the graphic inside the cell
case Column.Alignment of
taRightJustify:
X := Rect.Right - 2 - 16;
taCenter:
X := (Rect.Right - Rect.Left - 16) div 2 + Rect.Left;
else // taLeftJustify:
X := Rect.Left + 2;
end;
Y := (Rect.Bottom - Rect.Top - 16) div 2 + Rect.Top;
// Determine the image to be used
if Field.AsBoolean then Index := 1 else Index := 0;
// Draw the graphic
Form1.ImageList1.Draw(DBGrid.Canvas, X, Y, Index);
end else // Default drawing
DBGrid.DefaultDrawColumnCell(Rect, DataCol, Column, State);
end;
What this procedure does is first checking if the cell corresponds to a
boolean field and -if so- it draws a checked or unchecked checkbox using
the corresponding image taken from an image list. The code is similar to
the one I presented in the last issue in the article DRAWING CELLS IN A
DBGRID. For other columns it simply calls DefaultDrawColumnCell.
Now we have to face a problem: whenever the user presses a key or clicks
in a selected cell, or presses F2, the grid goes into "editor mode".
This is so because normally the grid has the option dgEditing activated
(see the Options property). To override this behavior we have to turn
off the dgEditing option when the user selects a cell that corresponds
to a boolean field, and then turn it on again when the user leaves the
cell. For this purpose we have to trap the OnColEnter and OnColExit
events:
procedure TForm1.DBGrid1ColEnter(Sender: TObject);
begin
ChkDBGridColEnter(Sender as TDBGrid);
end;
procedure TForm1.DBGrid1ColExit(Sender: TObject);
begin
ChkDBGridColExit(Sender as TDBGrid);
end;
Again I called procedures defined in a separate unit:
procedure ChkDBGridColEnter(DBGrid: TDBGrid);
var
Field: TField;
begin
Field := DBGrid.SelectedField;
if (Field <> nil) and (Field.DataType = ftBoolean) then
DBGrid.Options := DBGrid.Options - [dgEditing];
end;
procedure ChkDBGridColExit(DBGrid: TDBGrid);
var
Field: TField;
begin
Field := DBGrid.SelectedField;
if (Field <> nil) and (Field.DataType = ftBoolean) then
DBGrid.Options := DBGrid.Options + [dgEditing];
end;
You only have to use these procedures if your DBGrid uses the dgEditing
option.
Finally, we have to provide a way for the user to toggle the value of
the field, for example clicking the cell with the mouse or pressing the
space bar. We can do it trapping the OnCellClick and OnKeyPress events:
procedure TForm1.DBGrid1CellClick(Column: TColumn);
begin
ChkDBGridCellClick(Column);
end;
procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: Char);
begin
ChkDBGridKeyPress(Sender as TDBGrid, Key);
end;
The procedures are defined as follows:
procedure ChkDBGridCellClick(Column: TColumn);
var
Field: TField;
begin
Field := Column.Field;
if (Field <> nil) and (Field.DataType = ftBoolean)
and Field.CanModify and not Column.ReadOnly then
with Field.Dataset do begin
if State = dsBrowse then
Edit;
Field.AsBoolean := not Field.AsBoolean;
end;
end;
procedure ChkDBGridKeyPress(DBGrid: TDBGrid; var Key: Char);
var
Field: TField;
begin
Field := DBGrid.SelectedField;
if (Field <> nil) and (Field.DataType = ftBoolean) then
if (Key = ' ') and Field.CanModify and
not DBGrid.Columns[DBGrid.SelectedIndex].ReadOnly then
with Field.Dataset do begin
if State = dsBrowse then
Edit;
Field.AsBoolean := not Field.AsBoolean;
end;
end;
________________________________________________________________________
6. BORLAND HAS JUST ANNOUNCED AVAILABILITY OF KYLIX
Kylix will come in three versions:
* Kylix Desktop Developer (for Linux GUI development) U$S 999.
* Kylix Server Developer (for web application development) U$S 1,999.
* Open Edition (for open source and free software (GPL) developers).
The first two will be will be generally available before the end of the
first quarter 2001 (Borland has announced shipments for February 22) and
they are available for shopping right now at the Borland site:
http://shop.borland.com/Category/0,1257,3-15-1080,00.html
The Open Edition version will be available by mid-2001 for free download
(or for purchase at $99 with hardcopy documentation and CD).
What is the difference between Kylix Desktop Developer and Kylix Server
Developer? Basically,
- The Server edition comes with NetCLX (Internet components, including
Apache support) that aren't available in the Desktop edition.
- The Server edition will support IBM DB2, Oracle 8i, InterBase and
MySQL, while the Desktop edition will only support the latter two.
What do they have in common?
- Both editions will come with CLX source code
- System Requirements:
* Intel Pentium 200 MHz (P2 400 MHz recommended)
* 64 MB RAM (128 MB recommended)
* CD-ROM drive
* 175 MB hard disk space or 155 MB full install
* VGA or higher resolution monitor
* Mouse or other pointing device
- Supported Linux Distributions:
* Red Hat 6.2 or higher
* Mandrake 7.2 or higher
* SuSE 7.0 or higher
More information: http://www.borland.com/kylix/
________________________________________________________________________
YOU CAN HELP US
We need your help to keep this newsletter going and growing. You can
help by referring the newsletter to your colleagues:
http://www.latiumsoftware.com/en/pascal/delphi-newsletter.php
Or you can help by voting for us in some or all of these rankings to
give more visibility to our web site and thus increase the number of
subscriptions to this newsletter:
http://www.programmingpages.com/?r=latiumsoftwarecomenpascal
http://top100borland.com/in.php?who=20
It's just a few seconds for you that REALLY mean a lot to us.
________________________________________________________________________
If you haven't received the full source code examples for this issue,
you can get them from http://www.latiumsoftware.com/en/file.php?id=p15
________________________________________________________________________
This newsletter is provided "AS IS" without warranty of any kind. Its
use implies the acceptance of our licensing terms and disclaimer of
warranty you can read at http://www.latiumsoftware.com/en/legal.php
where you will also find a note about legal trademarks. Articles are
copyright of their respective authors and they are reproduced here with
their permission. You can redistribute this newsletter as long as you do
it in full (including copyright notices), without changes, and gratis.
________________________________________________________________________
Main page: http://www.latiumsoftware.com/en/pascal/delphi-newsletter.php
Group home page: http://groups.yahoo.com/group/pascal-newsletter/
Subscribe/join: pascal-newsletter-subscribe@yahoogroups.com
Unsubscribe/leave: pascal-newsletter-unsubscribe@yahoogroups.com
Problems with your subscription? eds2008 @ latiumsoftware.com
________________________________________________________________________
Latium Software http://www.latiumsoftware.com/en/index.php
Copyright (c) 2001 by Ernesto De Spirito. All rights reserved.
________________________________________________________________________
|