Problems Printing from BCB6 CLX Apps
Problems Printing from
C++Builder 6 CLX Applications
Brian Long (www.blong.com)
Table of Contents
Click
here to download the file associated with this article.
The Problem
I recently wrote an
article about a problem in C++Builder 6 that makes all the routines in the
Qt.hpp header unusable. Whilst looking into that issue I bumped into another
C++Builder 6 CLX application problem.
This time the provided functionality in the TQPrinter
class is completely non-functional. Any attempts to call upon the printer object
(available through the Printer()
function) to perform any printing function or get any printing information yielded
disappointing results. For example this code tries to get the printer page size
in mm and then in pixels, before invoking the printer setup dialog:
TPrinter *printer = Printer();
const int PrinterPageWidth = printer->PageWidth;// result 0
const int PrinterPageHeight = printer->PageHeight;// result 0
const double mmPerInch = 25.39999999999999;
const double PrinterPageWidthMM =
PrinterPageWidth * mmPerInch / printer->XDPI;// result NAN
const double PrinterPageHeightMM =
PrinterPageHeight * mmPerInch / printer->YDPI;// result NAN
ShowMessage(String().sprintf(
"Page size (w x h):\n%.0f x %.0f (mm)\n%d x %d (pixels)",
PrinterPageWidthMM, PrinterPageHeightMM,
PrinterPageWidth, PrinterPageHeight));
printer->ExecuteSetup();
Unfortunately it produces this unhelpful message and then does nothing more.
The setup dialog does not appear.

If you try and access the Qt printing support directly using the CLXDisplay
API (the routines in the Qt.hpp header) you will only get Stack Overflows for
your trouble, unless you've already fixed the problem, as covered in the other
article.
If you get the Qt header working correctly you can call the Qt printing routines
directly, as in this code that does the equivalent of the previous code snippet
using the Qt API:
TPrinter *printer = Printer();
TQPrintAdapter *printAdapter =
ynamic_cast<TQPrintAdapter *>(printer->PrintAdapter);
if (printAdapter)
{
QPaintDeviceMetricsH *metrics = printAdapter->DeviceMetrics;
// full page size
QPrinter_setFullPage((QPrinterH *)printer->Handle, true);
const int PrinterPageWidth =
QPaintDeviceMetrics_width(metrics);// result 0
const int PrinterPageHeight =
QPaintDeviceMetrics_height(metrics);// result 0
const int PrinterPageWidthMM =
QPaintDeviceMetrics_widthMM(metrics);// result 0
const int PrinterPageHeightMM =
QPaintDeviceMetrics_heightMM(metrics);// result 0
ShowMessage(String().sprintf(
"Page size (w x h):\n%d x %d (mm)\n%d x %d (pixels)",
PrinterPageWidthMM, PrinterPageHeightMM,
PrinterPageWidth, PrinterPageHeight));
}
QPrinter_setup((QPrinterH *)printer->Handle, NULL);
Unfortunately the problem still hits us. All these routines simply return 0
and so we get exactly the same result: a message full of useless information
and no setup dialog.
The Reason
It seems this problem is one that should not be occurring. The same problem
was true of Delphi 6 CLX applications in the initial release of the product
and after the first Update Pack. It turned out to be due to some internal problems
in the Qt interface library (qtintf.dll). This original version shipped with
Delphi has version information in it identifying it as version 6.0.0.0.
Delphi 6 Update Pack 2 supplied a new version of this library, version 6.0.6.240,
which rectifies the problem. This Update Pack came out about a month after C++Builder
was released, but none of the currently released C++Builder 6 Update Packs (and
there are at least three of them around, perhaps even four by now) supply the
DLL to programmers who do not use Delphi. This means C++Builder 6 CLX applications
are using an old, broken version of the DLL and so still have to face the broken
printer support.
The Solution
The solution to the problem is simple. Replace your old qtintf.dll with the
updated version. You can get the newer version by
clicking here. This attachment contains the DLL as well as a trivial Delphi
6 CLX application. The application does nothing interesting, but supplying it
legitimises my uploading of the DLL, since the application needs it to run.
It also needs the Delphi 6 or C++Builder 6 runtime packages to execute, but
only C++Builder 6 programmers are likely to download it so that shouldn't be
a problem.
After switching DLLs the behaviour of either section of code from above is
to produce this correct information about the printer page setup:

and then invoke the printer setup dialog, which in my case looks like this:

Further Reading
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.
Connect with Us