I am using C++ Builder XE7 VCL.
Around August 11 2016 2:00pm UTC, I started receiving multiple complaints from my user base about printing problems. Most of these printing modules have proven stable for many years, and there were no updates to my project within the past 24 hours. I was able to reproduce similar problems on my development/test environment.
Without going into many details of my project, let me present a very simple printing program that is failing:
void __fastcall TForm1::PrintButtonClick(TObject *Sender)
{
// Test Print:
TPrinter *Prntr = Printer();
Prntr->Title = "Test_";
Prntr->BeginDoc();
Prntr->Canvas->Font->Size = 10;
Prntr->Canvas->TextOut(300,1050,"* * * Printing Test * * *");
if (Prntr->Printing) {
Prntr->EndDoc();
}
}
On the first attempt to print, everything works perfectly as expected. If I click the button a second time, TPrinter produces a small PDF, but the PDF file is actually corrupted and appears to have a file handle stuck to it.
If I click the button a third time, I get no printing and the following error message appears:
Printer is not currently printing.
My own test was done using a PDF printer driver, but the complaints I am receiving from users include a variety of local printers, network printers, PDF printers, etc.
In my actual project, I have try/catch exception handling, so the actual results are slightly different, but substantially similar to this result. The results show the hallmarks of instability and/or memory leaks without much in terms of error messages.
I suspect there may have been some Microsoft Windows updates that are tangling with Embarcadero DLLs, but I have not been able to verify this so far.
Is anyone else having similar problems?
The reason using a
TPrintDialogorTPrinterSetupDialog"works" to fix the error is because they force the singletonTPrinterobject (returned by theVcl.Printers.Printer()function) to release its current handle to a printer if it has one, thus causingTPrinter.BeginDoc()to create a new handle.TPrinterreleases its printer handle when:NumCopies,Orientation, orPrinterIndexproperty is set.SetPrinter()method is called (internally by thePrinterIndexproperty setter andSetToDefaultPrinter()method, and byTPrintDialogandTPrinterSetupDialog).Without doing that, calling
TPrinter.BeginDoc()multiple times will just keep re-using the same printer handle. And apparently something about the recent Microsoft security update has now affected that handle reuse.So, in short, (without uninstalling the Microsoft update) in between calls to
BeginDoc()you need to do something that causesTPrinterto release and recreate its printer handle, and then the problem should go away. At least until Embarcadero can release a patch toTPrinterto address this issue. Maybe they could updateTPrinter.EndDoc()orTPrinter.Refresh()to release the current printer handle (they currently do not).Therefore, the following workaround resolves the printing issue without requiring any changes to the user interface: