Problems with Programming Qt from Kylix 3 C++ Applications

By: Brian Long

Abstract: Kylix 3 (C++) provides access to Qt in a way that is not cross-platform friendly. Here we look at how to overcome this

Problems with Programming Qt from Kylix 3 C++ CLX Apps

Problems with Programming Qt from
Kylix 3 C++ CLX Applications

Brian Long (www.blong.com)

Table of Contents

Click here to download the file associated with this article.


Introduction

A spate of issues have recently come to my attention regarding accessing a certain portion of functionality from C++ applications. In particular, C++ CLX programs that wish to access the underlying Qt API (referred to as the CLXDisplay API) tend to encounter one of a number of problems. For C++Builder 6 programmers, any attempt to access these routines leads immediately to a Stack Overflow (see Problems with Programming Qt from C++Builder 6 CLX Applications, which you can also access through Reference 3 in the Further Reading section at the end of this article). Once this hurdle has been crossed, attempts to use the printer either through Qt or through the high-level TPrinter class prove fruitless (see Reference 4).

Another problem relating to Qt routines is present in the C++ version of Kylix 3. If you plan to write cross-platform CLX applications, which occasionally dip into the CLXDisplay API, you will come unstuck as Kylix 3 uses different definitions for every one of the key data types (the Qt handle classes), forcing you to write conditional code for even the smallest piece of Qt access code.

This article explains the problem with the header, why it occurs and finally how it can be resolved. Since the number of changes to completely rectify the problem is so huge you can access a modified version of the header file that provides an unofficial fix until Borland supply an official patch.

The CLXDisplay API

The Qt.hpp header file is intended to allow access to the CLXDisplay API. This API exposes the functionality of the Qt classes as individual "flattened methods". These are exported by the Qt interface library as a means of providing access to the real methods available in the Qt library. On Windows, C++Builder 6 uses a single DLL called qtintf.dll that contains the interface routines (flat methods) as well as the Qt classes themselves. On Linux, Kylix also uses a single library, libborqt.so by default, although #defining the symbol CLX_USE_LIBQT causes it to use a separate interface library (libqtintf-6.9-qt2.3.so) and a Borland-patched Qt library (libqt.so.2.3.0).

The reason for this intermediate interface layer is simply the fact that the CLX library was originally built up in the Delphi language, which cannot directly handle exported C++ classes. A way of overcoming this is to expose every method as a regular function, which explicitly has one additional parameter to take the object pointer. These flat methods in the interface library are mapped directly through to the corresponding methods in the real classes.

The flat method signatures match an explicit representation of how the this pointer is passed in a normal method call, but being functions they can be called by any programming language (assuming all the expected parameter types are compatible with that language). The Delphi VisualCLX source code uses the CLXDisplay API (in the Qt.pas unit) and C++Builder programmers are required to use it too (through the Qt.hpp header file) in order to access Qt objects directly. You can find out more about using the CLXDisplay API in Reference 1 and Reference 2 from the Further Reading section.

It is advisable to restrict your use of the CLXDisplay API to cases where the VisualCLX components do not offer the functionality you need. If there is a CLX solution to a problem you should always use that instead of overusing the Qt routines.

The Problem

The problem is that the Qt.hpp header file and various additional headers that it uses were manufactured incorrectly. The main Qt.hpp file was created by the Linux Delphi command-line compiler (dcc), which can generate C++ header files that correspond to the interface section of a Delphi unit being compiled. Inside the unit are several thousand import declarations for routines exposed from the Qt interface library.

As has been discussed at length in Reference 3, the header generation functionality in the Delphi compiler is a bit shaky with import declarations of the type used in this unit. The C++Builder 6 CLX issue is solely due to this incorrect behaviour in the Delphi compiler, however with the Kylix 3 C++ product Borland tried to make things a bit better. And whilst you can certainly use the Qt routines without getting a Stack Overflow, you can only do so using symbol names that are inconsistent with those offered by C++Builder 6.

C++Builder 6 was released in February 2002 with a single Qt.hpp header containing everything that was declared in the interface section of the Qt.pas unit. Kylix 3 followed along in July 2002 with a different scheme to avoid the same problems as found in C++Builder 6 (not that any official fixes have been offered for C++Builder 6 CLX programmers). Instead of leaving the entire job of generating the whole Qt.hpp header file down to the dcc compiler, there are now a couple of tools that do the job.

As a consequence, Qt.hpp now contains no declarations of routines available in the Qt interface library. Instead, all the CLXDisplay API routines are spread across a multitude of header files with .hb and .hhk file extensions. Each Qt class that has methods has a corresponding .hb file (such as qprinter.hb). If the Qt class offers hooks then it will also have a .hhk file (for example qwidget.hb and qwidget.hhk).

Because of the content of all these various header files, C++ Qt program code is now inconsistent between Win32 and Linux. For example, this simple statement should invoke the printer setup dialog and works fine in C++Builder 6 (assuming you have taken account of the required fixes described in Reference 3 and Reference 4):

#include <QPrinters.hpp>
...
QPrinter_setup((QPrinterH *)Printer()->Handle, NULL);

Of course you would generally never make such a call since the TPrinter object returned by the Printer() function offers an ExecuteSetup() method that does this for you, but this statement serves as an example.

The function call corresponds directly to this Delphi code that will work in Delphi 6 and 7 and also in the Delphi language version of Kylix (any object reference type in Delphi is represented explicitly as an object pointer in C++):

uses
  Qt, QPrinters;
...
QPrinter_setup(QPrinterH(Printer.Handle), nil);

However to get the same behaviour in Kylix 3 C++ you need to either use this line:

#include <QPrinters.hpp>
...
QPrinter_setup((QPrinter__ *)Printer()->Handle, NULL);

or this line:

#include <QPrinters.hpp>
...
QPrinter_setup((::QPrinterH)Printer()->Handle, NULL);

As you can see the QPrinterH handle class is no longer defined the same way. No longer is it a class type in the Qt namespace, but it's actually defined as a pointer type in the global namespace. However a new symbol called QPrinter__ is also available, which seems to have the same purpose as the QPrinterH does in C++Builder. This is all very awkward, and requires code to look something like this for cross-platform compatibility:

#include <QPrinters.hpp>
...
#ifdef _Windows
  QPrinter_setup((QPrinterH *)Printer()->Handle, NULL);
#endif
#ifdef __linux__
  QPrinter_setup((QPrinter__ *)Printer()->Handle, NULL);
#endif

or even like this:

#include <QPrinters.hpp>
...
#ifdef _Windows
  QPrinter_setup((QPrinterH *)Printer()->Handle, NULL);
#endif
#ifdef __linux__
  QPrinter_setup((::QPrinterH)Printer()->Handle, NULL);
#endif

Clearly this makes any amount of cross-platform Qt programming very tedious, having to write everything twice, slightly different each time, so we will look for a solution to the problem.

Why Did It Happen?

The Delphi to C++ translation support in the dcc32.exe works well in many cases, but not for DLL import declarations (as described in the Reference 3). This causes a big problem since the Qt.pas unit is made up of over 3300 import declarations. It seems that to avoid the problems caused by this bug, the C++ Qt interface library functionality was made available slightly differently. Every single import declaration in Qt.pas is followed by the Delphi $EXTERNALSYM compiler directive to ensure that the dcc/dcc32.exe generated header contains no trace of the corresponding C++ import declaration, however all the Qt handle classes are generated in the Kylix 3 header just as they are in C++Builder 6, within the Qt namespace.

Instead of letting the Delphi compiler add the import declarations into the main Qt.hpp file some other utility runs through each of the real Qt header files in order to produce the external declarations in separate header files. Each of these headers is included by Qt.hpp thanks to the presence of additional compiler directives in Qt.pas. Ahead of the import declarations for each Qt class in Qt.pas is a $HPPEMIT directive to generate a specific #include for a .hb file, and also sometimes a .hhk file. The Qt.pas unit has sections like this:

{$HPPEMIT '#include 

"qwidget.hb"'}
{$HPPEMIT '#include "qwidget.hhk"'}
function QWidget_create(parent: QWidgetH; name: PAnsiChar; f: WFlags): QWidgetH; cdecl;
{$EXTERNALSYM QWidget_create}
procedure QWidget_destroy(handle: QWidgetH); cdecl;
{$EXTERNALSYM QWidget_destroy}
function QWidget_winId(handle: QWidgetH): Cardinal; cdecl;
{$EXTERNALSYM QWidget_winId}

{$HPPEMIT '#include "qapplication.hb"'}
{$HPPEMIT '#include "qapplication.hhk"'}
function QApplication_argc(handle: QApplicationH): Integer; cdecl;
{$EXTERNALSYM QApplication_argc}
function QApplication_argv(handle: QApplicationH): PPAnsiChar; cdecl;
{$EXTERNALSYM QApplication_argv}
function QApplication_style(): QStyleH; cdecl;
{$EXTERNALSYM QApplication_style}

{$IFDEF MSWINDOWS}
function QApplication_winEventFilter(handle: QApplicationH; p1: PMsg): Boolean; cdecl;
{$ENDIF}
{$IFDEF MSWINDOWS}
{$EXTERNALSYM QApplication_winEventFilter}
{$ENDIF}

{$IFDEF LINUX}
function QApplication_x11EventFilter(handle: QApplicationH; p1: PEvent): Boolean; cdecl;
{$ENDIF}
{$IFDEF LINUX}
{$EXTERNALSYM QApplication_x11EventFilter}
{$ENDIF}

{$HPPEMIT '#include "qwidget.hb"'}
{$HPPEMIT '#include "qwidget.hhk"'}
function QWidget_hook_create(handle: QObjectH): QWidget_hookH; cdecl;
{$EXTERNALSYM QWidget_hook_create}
procedure QWidget_hook_destroy(handle: QWidget_hookH); cdecl;
{$EXTERNALSYM QWidget_hook_destroy}

{$HPPEMIT '#include "qapplication.hb"'}
{$HPPEMIT '#include "qapplication.hhk"'}
function QApplication_hook_create(handle: QObjectH): QApplication_hookH; cdecl;
{$EXTERNALSYM QApplication_hook_create}
procedure QApplication_hook_destroy(handle: QApplication_hookH); cdecl;
{$EXTERNALSYM QApplication_hook_destroy}
procedure QApplication_hook_hook_lastWindowClosed(handle: QApplication_hookH; hook: QHookH); cdecl;
{$EXTERNALSYM QApplication_hook_hook_lastWindowClosed}

Notice that for each Qt class the headers are included twice? The generated Qt.hpp file does indeed include all these .hb/.hbk files twice unnecessarily.

The code that is actually placed into Qt.hpp during the header generation is fine, as it stands, since effort has been made to ensure that it does not contain invalid import declarations as happened in C++Builder 6. Instead it just contains the various type definitions made use of by the Qt routines, all within the Qt namespace. This is an example Qt handle class from Qt.hpp:

class DELPHICLASS QWidgetH;
class PASCALIMPLEMENTATION QWidgetH : public QObjectH 
{
	typedef QObjectH inherited;
	
public:
	#pragma option push -w-inl
	/* TObject.Create */ inline __fastcall QWidgetH(void) : 

QObjectH() { }
	#pragma option pop
	#pragma option push -w-inl
	/* TObject.Destroy */ inline __fastcall virtual 

~QWidgetH(void) { }
	#pragma option pop
	
};

So next we need to look at these .hb and .hhk files to locate the source of the problem.

A .hb file is a Borland-generated header that declares import declarations for a given Qt class's methods. For example the QTimer class is surfaced with the file qtimer.hb:

#ifndef C_QTIMER_H
#define C_QTIMER_H

/****************************************************************************
** QTimer C bindings generated from reading C++ file 'qtimer.h'
**
** Created: Tue Jul 30 19:22:32 2002
**      by: The Qt Meta Object Compiler ($Revision: 2.53 $)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/

C_EXPORT QTimerH QTimer_create(QObjectH parent, const char* name);
C_EXPORT void QTimer_destroy(QTimerH handle);
C_EXPORT bool QTimer_isActive(QTimerH handle);
C_EXPORT int QTimer_start(QTimerH handle, int msec, bool sshot);
C_EXPORT void QTimer_changeInterval(QTimerH handle, int msec);
C_EXPORT void QTimer_stop(QTimerH handle);
C_EXPORT void QTimer_singleShot(int msec, QObjectH receiver, const char* member);

#endif

A .hhk file defines the hook routines used to install hooks for a given Qt class. For example, the QTimer hook routines are defined in qtimer.hhk:

#ifndef C_QTIMERK_H
#define C_QTIMERK_H

/****************************************************************************
** QTimer_hook C bindings generated from reading C++ file 'qtimer.hk'
**
** Created: Tue Jul 30 19:23:37 2002
**      by: The Qt Meta Object Compiler ($Revision: 2.53 $)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/

typedef struct QTimer_hook__ { int dummy; } *QTimer_hookH;
/****************************************************************************
** QTimer_hook C bindings generated from reading C++ file 'qtimer.hk'
**
** Created: Tue Jul 30 19:23:37 2002
**      by: The Qt Meta Object Compiler ($Revision: 2.53 $)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/

C_EXPORT QTimer_hookH QTimer_hook_create(QObjectH handle);
C_EXPORT void QTimer_hook_destroy(QTimer_hookH handle);
C_EXPORT void QTimer_hook_hook_timeout(QTimer_hookH handle, QHookH hook);

#endif

You need to remember that these headers are included in Qt.hpp before the generated definitions of all the Qt handle classes. In fact any $HPPEMIT directive causes the output to appear at the start of the header before any of the translated items. Consequently all these routines will need definitions of all the handle classes to work with, since that's what they mainly deal in.

To cater for this the qtypes.h header has a multitude of additional auto-generated type declarations appended to it as shown below. qtypes.h is #included by Qt.hpp thanks to another $HPPEMIT directive in Qt.pas.

/****************************************************************************
** QWidget C bindings generated from reading C++ file 'qwidget.h'
**
** Created: Mon Dec 6 16:31:03 1999
**      by: The Qt Meta Object Compiler (1.1)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/

typedef struct QWidget__ { int dummy; } *QWidgetH;

/****************************************************************************
** QApplication C bindings generated from reading C++ file 'qapplication.h'
**
** Created: Mon Dec 6 16:30:45 1999
**      by: The Qt Meta Object Compiler (1.1)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/

typedef struct QApplication__ { int dummy; } *QApplicationH;

/****************************************************************************
** QTimer C bindings generated from reading C++ file 'qtimer.h'
**
** Created: Mon Dec 6 16:31:02 1999
**      by: The Qt Meta Object Compiler (1.1)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/

typedef struct QTimer__ { int dummy; } *QTimerH;

Additionally, the .hhk files contain definitions of the hook classes in a similar fashion, as we can see above. You might notice these seem to be dummy type declarations (which are not made in any specific namespace). You might also notice that unlike the proper handle class types auto-generated in Qt.hpp, these handle types are actually pointer types. For example, QWidgetH has a class type definition in the Qt namespace (in Qt.hpp) but a pointer type definition in the global namespace (in qtypes.h); a pointer that points to a dummy QWidget__ struct. This is inconsistent.

The consequence of these inconsistent dummy (placeholder) type declarations is that all the import declarations are defined incorrectly (when compared with the C++Builder 6 versions, or what you would expect by examining the Delphi declarations).

For example, this import declaration from earlier:

C_EXPORT QTimerH QTimer_create(QObjectH parent, const char* name);

should in truth be defined like this to keep in line with the the way the Qt interface routines are exported and how the auto-generated handle types are defined.

extern "C" QTimerH *QTimer_create(QObjectH *parent, 

const char* name);

Because of the disparity of the extern declarations, we have to write the code differently in each product.

On top of all of this is the fact that the Kylix 3 C++ product only surfaces the real exported name of each of the Qt interface library routine. In the original Qt classes there are many overloaded methods and constructors, for example the QImage class offers 7 constructors. However the Qt interface library exports standard routines that must be uniquely named, so in fact the Qt interface routines to access these 7 constructors are defined like this (taken from Qt.pas):

function QImage_create(): QImageH;
  external QtShareName name QtNamePrefix + 'QImage_create';
function QImage_create(width: Integer; height: Integer; depth: Integer;
  numColors: Integer; bitOrder: QImageEndian): QImageH;
  external QtShareName name QtNamePrefix + 'QImage_create2';
function QImage_create(p1: PSize; depth: Integer; numColors: Integer;
  bitOrder: QImageEndian): QImageH;
  external QtShareName name QtNamePrefix + 'QImage_create3';
function QImage_create(fileName: PWideString; format: PAnsiChar): QImageH;
  external QtShareName name QtNamePrefix + 'QImage_create4';
function QImage_create(data: QByteArrayH): QImageH;
  external QtShareName name QtNamePrefix + 'QImage_create6';
function QImage_create(data: PByte; w: Integer; h: Integer; depth: Integer;
  colortable: QRgbH; numColors: Integer; bitOrder: QImageEndian): QImageH;
  external QtShareName name QtNamePrefix + 'QImage_create7';
function QImage_create(p1: QImageH): QImageH;
  external QtShareName name QtNamePrefix + 'QImage_create9';

Each one is exported with a slightly different name and this is the name you must call from Kylix 3 C++. This is quite unlike C++Builder 6, which attempts to provide overloaded C++ wrapper routines to turn these exports back into same-named routines and remove the requirement to know which numbered routine takes which parameters. This means that code is even less cross-platform friendly than it could be. For example this code creates a button, displays it and updates it, and is designed to be cross-platform inasmuch as how the shipping products require it:

void __fastcall TForm1::Button1Click(TObject 

*Sender)
{
  TRect r(5, 5, 85, 25);
  WideString Caption = "Hello";
#ifdef _Windows
  QPushButtonH *Btn = QPushButton_create(Handle, "MyButton");
  QWidget_setGeometry(Btn, &r);
  QButton_setText(Btn, PWideString(&Caption));
  QWidget_show(Btn);
#endif
#ifdef __linux__
  QPushButton__ *Btn = QPushButton_create((QWidget__ *)Handle, "MyButton");
  QWidget_setGeometry2((QWidget__ *)Btn, &r);
  QButton_setText((QButton__ *)Btn, PWideString(&Caption));
  QWidget_show((QWidget__ *)Btn);
#endif
}

The Windows code calls QWidget_setGeometry but the Linux code has to call QWidget_setGeometry2. And with all the extra typecasts required in the Linux code, things are not looking good. So even if we fix the Qt type definitions somehow we will still be left with the job of creating overloaded wrappers for all the routines like this (and there are over 600 of them).

Fixing The Problem

The most straightforward approach to rectifying this problem is to use the original Qt.pas Delphi unit and generate an entire standalone Qt.hpp header file in the same way I described in the Reference 3.

In order to do this we must remove all the $EXTERNALSYM directives that are after every import declaration in the unit and also remove the $HPPEMIT directives that include the plethora of unhelpful custom headers as well as qtypes.h. That would change a section like the one shown above to this:

function QWidget_create(parent: QWidgetH; 

name: PAnsiChar; f: WFlags): QWidgetH; cdecl;
procedure QWidget_destroy(handle: QWidgetH); cdecl;
function QWidget_winId(handle: QWidgetH): Cardinal; cdecl;
function QApplication_argc(handle: QApplicationH): Integer; cdecl;
function QApplication_argv(handle: QApplicationH): PPAnsiChar; cdecl;
function QApplication_style(): QStyleH; cdecl;
{$IFDEF MSWINDOWS}
function QApplication_winEventFilter(handle: QApplicationH; p1: PMsg): Boolean; cdecl;
{$ENDIF}
{$IFDEF MSWINDOWS}
{$ENDIF}

{$IFDEF LINUX}
function QApplication_x11EventFilter(handle: QApplicationH; p1: PEvent): Boolean; cdecl;
{$ENDIF}
{$IFDEF LINUX}
{$ENDIF}

function QWidget_hook_create(handle: QObjectH): QWidget_hookH; cdecl;
procedure QWidget_hook_destroy(handle: QWidget_hookH); cdecl;
function QApplication_hook_create(handle: QObjectH): QApplication_hookH; cdecl;
procedure QApplication_hook_destroy(handle: QApplication_hookH); cdecl;
procedure QApplication_hook_hook_lastWindowClosed(handle: QApplication_hookH; hook: QHookH); cdecl;

In order to get all the Linux-specific declarations in the header we will need to use the Kylix Delphi compiler, dcc, to generate the header file. Additionally, since Kylix 3 and Delphi 7 alter the way they generate a header file for a Delphi unit, Kylix 2 must be used in order to generate an appropriately formed header file. Kylix 2's dcc will generate import declarations for all the routines, as well as inline wrapper routines, which are overloaded as necessary to match the original Pascal import declarations in the Qt.pas unit, however Kylix 3's dcc will not. These inline wrappers will call down to the actual import declarations. This isn't a straightforward process, as the generation of these import declarations and inline wrappers has its own problems, but from there we can use the same process of fixing as was done for C++Builder 6 in Reference 3.

Having run this through the mill I can inform you that Qt.hpp exposes 3380 routines from the Qt interface library, of which about 640 are overloads. The result is a new Qt.hpp header file you can find by clicking here.

Proof Of The Pudding

They say the proof of the metaphorical pudding is in the eating so let's tuck in. Examples of some simple Qt programming follow and will now compile in both C++Builder 6 as well as the C++ IDE in Kylix 3:

More sample code to show it all works follows. The first event handler selects the entire contents of a multi-selection listbox (one that has the MultiSelect property set to True), whilst the second creates and shows a button.

void __fastcall TForm1::Button1Click(TObject *Sender)
{
  if (!ListBox1->MultiSelect)
    ListBox1->MultiSelect = true;
  QListBox_selectAll((QListBoxH*)ListBox1->Handle, true);
}

void __fastcall TForm1::Button2Click(TObject *Sender)
{
  QPushButtonH *Btn = QPushButton_create(Handle, "MyButton");
  QWidget_setGeometry(Btn, 5, 5, 85, 25);
  WideString Caption = "Hello";
  QButton_setText(Btn, PWideString(&Caption));
  QWidget_show(Btn);
}

It should be reiterated that using the Qt routines (the CLXDisplay API) when VisualCLX offers methods to do the same job is ill-advised. However sometimes you need to dip into the vast amount of additional routines when CLX doesn't cater for something. The examples shown here are simple cases to show that things are working correctly, rather than representations of realistic code snippets.

Parting Comments

You should bear in mind that the C++Builder product places certain restrictions on the usage of the CLXDisplay API. In the deploy.rtf and deploy.txt files you can see this clause:

2.6 Restrictions on CLXDisplay API (Qt.pas) Usage
CLXDisplay API, the Qt.pas interface to the Qt runtime, is only licensed for use in VisualCLX applications or a component that derives from TControl in the QControls unit. A VisualCLX application is an application that uses the TApplication object and uses at least one component derived from TControl. You are not licensed to use Qt.pas to create applications or components that exclusively call the Qt.pas interfaces. A separate commercial development license from Trolltech is required for use of Qt.pas in any manner other than authorized above.

So you are forbidden from building a pure Qt application using the CLXDisplay API without additional licensing. But as long as you access Qt routines from a VisualCLX application things are fine.

One final thought I will share is that I find it more than a bit concerning that the underlying API behind Borland's cross-platform component library, CLX, does not itself support cross-platform coding in the shipping Kylix 3 and C++Builder 6 products (at least not in any practical way). This is only the case with the C++ products; the Win32 Delphi product and Delphi version of Kylix 3 successfully support cross-platform coding.

This problem, as well the other ones I've recently unearthed (see References 3 & 4 in the next section), smacks of a lack of QA on the products, which is always a disturbing revelation.

Further Reading/References

  1. How CLX Uses Qt, Brian Long, The Delphi Magazine , June 2001 (Issue 70).
  2. Programming Kylix with the CLXDisplay API , Bruno Sonnino.
  3. Problems with Programming Qt from C++Builder 6 CLX Applications, Brian Long.
    This article looks at a problem preventing C++Builder 6 CLX applications from directly accessing the routines in Qt.hpp (the CLXDisplay API).
  4. Problems Printing from C++Builder 6 CLX Applications, Brian Long.
    This article looks at a problem preventing CLX applications created in C++Builder 6 from being able to use the printer, and how to overcome it.

About Brian Long

Brian Long used to work at Borland UK, performing a number of duties including Technical Support on all the programming tools. Since leaving in 1995, Brian has been providing training and consultancy on Borland's RAD products ever since, and is now moving into the .NET world.

Besides authoring a Borland Pascal problem-solving book published in 1994, Brian is a regular columnist in The Delphi Magazine and has had numerous articles published in Developer's Review, Computing, Delphi Developer's Journal and EXE Magazine. He was nominated for the Spirit of Delphi 2000 award and was voted Best Speaker at Borland's BorCon 2002 conference in Anaheim, California by the conference delegates.

There are a growing number of conference papers and articles available on Brian's Web site, so feel free to have a browse.

In his spare time (and waiting for his C++ programs to compile) Brian has learnt the art of juggling and making inflatable origami paper frogs.


Server Response from: ETNASC03