The Delphi Bug List

Entry No.
616
VCL - General - Printers - Printing / printers
Bug in Printers unit causes access violation
1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 4.03 5.0 5.01 6.0 6.01 6.02 Kylix 1.0
UnknownExistsExistsExistsExistsExistsExistsExistsExistsExistsExistsExistsExistsExistsN/A
Description
Reported by Jordan Russell
If your PC is connected to a network printer and the system hosting the network printer is not online, the following snippet of code likely will cause an access violation in GDI32.DLL:
uses
  Printers;

procedure TForm1.Button1Click(Sender: TObject);
var
  W: Integer;
begin
  W := Printer.PageWidth;   // AV on this line
  Caption := IntToStr(W);
end;
I say "likely" because, as we all know, access violations can sometimes be difficult to reproduce, although on my Windows 2000 system the access violation occurs almost every time.

The access violation is caused by a bug in the TPrinter.SetPrinter procedure of Printers.pas, in this section of code:

      DeviceMode := GlobalAlloc(GHND,
        DocumentProperties(0, FPrinterHandle, ADevice, StubDevMode,
        StubDevMode, 0));
      if DeviceMode <> 0 then
      begin
        DevMode := GlobalLock(DeviceMode);
        if DocumentProperties(0, FPrinterHandle, ADevice, DevMode^,
          DevMode^, DM_OUT_BUFFER) < 0 then
        begin
          GlobalUnlock(DeviceMode);
          GlobalFree(DeviceMode);
          DeviceMode := 0;
        end
      end;
Notice that if DocumentProperties fails (returns < 0), DeviceMode is freed, but DevMode is never reset back to "nil". Certain functions of TPrinter will then pass this now-invalid pointer to GDI functions, resulting in access violations.

I also tested on Delphi 1 but was not able to reproduce the bug, however that isn't to say the same bug isn't there, since I don't have access to the Delphi 1 VCL source code to check.

Solution / workaround
The solution requires modifying Printers.pas. To fix the bug, you simply need to add a "DevMode := nil;" line above the GlobalUnlock call, i.e.:
      DeviceMode := GlobalAlloc(GHND,
        DocumentProperties(0, FPrinterHandle, ADevice, StubDevMode,
        StubDevMode, 0));
      if DeviceMode <> 0 then
      begin
        DevMode := GlobalLock(DeviceMode);
        if DocumentProperties(0, FPrinterHandle, ADevice, DevMode^,
          DevMode^, DM_OUT_BUFFER) < 0 then
        begin
          DevMode := nil;   // ADD THIS LINE
          GlobalUnlock(DeviceMode);
          GlobalFree(DeviceMode);
          DeviceMode := 0;
        end
      end;
If you decide to make this change, you might as well fix a similar bug in the same procedure too. At the top of the procedure, there is another instance where DeviceMode is freed, but DevMode is not reset back to "nil":
  if ADeviceMode <> DeviceMode then
  begin  // free the devmode block we have, and take the one we're given
    if DeviceMode <> 0 then
    begin
      DevMode := nil;   // ADD THIS LINE
      GlobalUnlock(DeviceMode);
      GlobalFree(DeviceMode);
    end;
    DeviceMode := ADeviceMode;
  end;
I haven't personally seen an access violation occur from this second bug, but the same potential is there.
User-contributed comments
Mike Schoonover
02 May 2001  02:07 AM GMT
I have this exact bug, but I can't figure out how to apply the fix that is
listed. I have tried modifying the printers.pas file, moving it to another
directory and modifying it while adding that directory to the top of the
library path, etc.

Nothing seems to work as described here and on Borland's website. I really
don't want to have to re-compile the entire VCL. Any additional info on how to
modify a VCL source file would be helpful.
Jordan Russell
02 May 2001  08:09 PM GMT
What I've done is create a new directory under delphi\source\vcl called "new" and place the modified Printers.pas there. Then whenever I want to use the new unit in a project, I add "$(DELPHI)\source\vcl\new" to the project's Search Path.
Mike Schoonover
04 May 2001  04:28 AM GMT
I am using C++ Builder 5.0 and tried duplicating your suggestion:

I created a new directory "new" in CBuilder5\Source\Vcl
I placed a modified Printers.pas in that directory.
I added $(BCB)\source\vcl\new to the top of:
Project-Options-Libraries-Include Path,
Project-Options-Libraries-Library Path,
Tools-Environment Options-Library-Library Path

I deleted every compiled file in the executable directory.
I turned off:
Project-Options-Packages-Build with runtime packages

I placed a deliberate syntax error in printers.pas to make sure I would know if it was being compiled.

I tried placing the printers.pas and printers.hpp files in my project's source directory also.

Absolutely no success. Either Builder does not recompile from the .pas source files or I am missing a magic switch somewhere.
ronald plevier
16 May 2001  05:53 PM GMT
i have tried the same and i am using delphi 5. i don't now if it's being compiled or not. i realy need to get this problem away. it's voor a school project. and i don't must time. if you can help it would be great.
katia Parra (Brazil)
17 May 2001  06:10 PM GMT
I have changed the file printer.pas I am using delphi 3.
How can I know if it's being compiled or not with the changes?
I realy need to get this problem away, because I have many clients with this problem. Please I Need some Help and I don't have much time.
Jordan Russell
18 May 2001  04:13 PM GMT
Open the new printers.pas and set a breakpoint inside a function/method that your code calls, then run your program. If the breakpoint is reached, you'll know the new printers.pas is being compiled in.
ronald plevier
18 May 2001  06:57 PM GMT
hi. if the printer.pas is compiled but the same error's keep coming. what could be rong. i have done al the thins you told mee to do. but no result.

do you have a idee!!!
Carlos Souza
21 May 2001  06:30 PM GMT
How do i cancel the command : Form1.QuickReport.PrinterSetup; ?

On the PrinterSetupDialog (native Delphi), there's a parameter ".Execute" and i force the program to cancel the operation like :
if not PrinterSetupDialog.Execute then exit;

The problem is : QuickReport don't have the parameter ".Execute" .
How do i cancel ?
katia Parra (Brazil)
22 May 2001  04:51 PM GMT
I added Printers.Pas on my project and Compiled it , and Printers.dcu was created, but the access violation appeared. So, I Removed the file from my project and copied printers.dcu to folders where I found it, but the error occured again. Please help me. There are more solutions????
André
25 Jun 2001  03:17 PM GMT
I'm trying this problem in Delphi 3 too and don't know more what to do. The only way that I see is migrate to Delphi 5. With it I test and didn't get the access violation.
Alan Tucker
16 Jul 2001  06:02 PM GMT
Make the modifications to Printers.pas as listed above,
Then copy the file conrtols.res from $(DELPHI)\Lib to $(DELPHI)\Source\VCL
Then Launch a DOS Box and change the directory to $(DELPHI)\Source\VCL
Run the comand line compiler 'DCC32 Printers.pas'
Delete the controls.res file from $(DELPHI)\Source\VCL, Leave the original file in $(DELPHI)\Lib alone.

This will have produced 'Printers.dcu' in $(DELPHI)\Source\VCL.

Rename The original DCU in $(DELPHI)\Lib and MOVE the new DCU from $(DELPHI)\Source\VCL to $(DELPHI)\Lib.

There is also another copy of this file within $(DELPHI)\Lib\Debug.
Replace this file with a COPY of the newly compiled DCU.

Rebuild your Project.

Don't Forgett to keep copies of the original DCU and PAS files, I renamed them to printers.old as described above.
John Faris
25 Jul 2001  08:51 AM GMT
I applied this fix and it seemed to work, but lately for no apparent reason I seem to be getting a different access violation if the selected network printer is offline. It occurs in unit QRPrntr in the procedure TPrinterSettings.Supported. I have tried to connect this to the reasons for the above AVs without success. Anyone else had this one? For what it is worth I know that I am definitely using the fixed version of the source due to a message box I inserted in the fixed source file.
Mike Rogers
06 Aug 2001  10:33 AM GMT
I seem to get a similar problem running under NT. I've made the changes but the problem actually seems to be the call to DocumentProperties just before the inserted line.
mintardja
13 Aug 2001  08:34 AM GMT
please, help me to somebody knowing about my problem
I have a problem using Quickreport 3.5 with Borland Delphi 6, about printing under windows NT or Windows 2000,
when printing on setting paper size 8,5 X 5,5 (half letter), it ejects whole paper like on paper 8,5 x 11 (1 letter). But when printed under windows 98 is just ok(printed on half paper).
please write to me at mintardja8@hotmail.com

thank's
John Faris
16 Aug 2001  01:52 PM GMT
I just had a windows 2000 user have the same access violation in unit QRPrntr in the procedure TPrinterSettings.Supported. It also a occurred when the network printer was offline. This occurred with the aboev fix applied. So it exists in Win 2000 and NT as per my earlier post.
Ben Mathews
21 Jan 2002  05:03 PM GMT
I have applied the fix and recompiled the printers.dcu. I don't have any problems printing from NT, but Windows 2000 still throws an access violation.

I've used other third party tools to print without problems. Please don't make me re-write all of my reports.
Marco Rodriguez
14 Feb 2002  10:27 PM GMT
Please, help me.

I have an application running over Windows98, and all's ok. Now, I install this over Windows 2000 and the preview form has the print button disabled, I don't know how I can fix this trouble, and I don't have many time to finish please help me. If you now how I can repair send me your idea at m.rodriguez@tecapro.com Thanks!!
Anas Zamraghdis
25 Feb 2002  10:13 AM GMT
I apply the aboved maintioned modifications, but seems it's not work, because i get the seem error message when I try to print Quick Report.
Anne Sainz
17 Mar 2002  11:39 PM GMT
I had several customers report a bug involving hp deskjet 900 series printers. I was able to verify the problem using Windows ME and an hp deskjet 960c printer, Delphi 1 and QuickReport 1.1a.

The original problem was that reports would not preview or print. I rewrote the printer dialog which allowed reports to preview but they still wouldn't print.

The problem line in QuickReport was line 1396 in procedure TQRPrinter.Init:

if Escape(Printer.Handle,QUERYESCSUPPORT,SizeOf(EscapeFunc), @EscapeFunc,nil) <> 0 then begin


It apparently returned a value other than 0 and skipped the printing process.

It didn't happen on all reports. It turned out that it only happened with reports that had many open tables during the report. When I reduced the number of open tables, the report printed. In my program, I could have up to a total of 7 open tables and the reports printed correctly. If I had more than 7 open tables, the problem occurred.

We have had reports from customers using 932c under Windows 98 and 960c under Windows ME that reports print correctly using the modified program.
KATIA PARRA
04 Jul 2002  05:06 PM GMT
I have a problem. I'm using Delphi 3, QuickReport 2.0k.
When it works in Windows 98, it´s ok, but I installed the Delphi in Windows 2000 Server, and when I called my project(dpr), the following message is showed:
Access Violation at address 10011533 in module 'hpfuint0.dll'. Read of address 00000000...

I put Cancel and My application appeared, but my QuickRep.dfm doesn't appear only the QuickRep.pas and when I tryed do run, the same message appears, when I
tried to carry on a Report.
Hugo Eyng
11 Jul 2002  02:35 PM GMT
I did as is in the comments but it didn´t work!

I recompile de Printers.pas and put the new Printers.dcu in the place where was the old printers.dcu.

Should I do anything more?
Mohana Gopinath
21 Aug 2002  12:11 PM GMT
Tried to solved with the given solution, but still gives Access Violation Error. Please help me, bcoz all of our clients are having Win2000.
Matthew Wood
26 Aug 2002  02:01 AM GMT
I haven't tested this, but you could try setting the DevMode variable back to nil AFTER the memory block has been free'd.

DeviceMode := GlobalAlloc(GHND,
DocumentProperties(0, FPrinterHandle, ADevice, StubDevMode,
StubDevMode, 0));
if DeviceMode <> 0 then
begin
DevMode := GlobalLock(DeviceMode);
if DocumentProperties(0, FPrinterHandle, ADevice, DevMode^,
DevMode^, DM_OUT_BUFFER) < 0 then
begin
GlobalUnlock(DeviceMode);
GlobalFree(DeviceMode);
DeviceMode := 0;
DevMode := nil; // Add this line after the memory has been freed.
end;
end;


And again....


if ADeviceMode <> DeviceMode then
begin // free the devmode block we have, and take the one we're given
if DeviceMode <> 0 then
begin
GlobalUnlock(DeviceMode);
GlobalFree(DeviceMode);
DevMode := nil; // Add this line after the memory has been freed.
end;
DeviceMode := ADeviceMode;
end;
Chang
30 Sep 2002  05:25 PM GMT
I have this question, too. But I modify these code, it's still
has this problem. Use "QuickRep1.Print" is fine, but use "QuickRep1.Preview"
it will pop the Access violation error. What I to do?

Thanks.
Vania R. Formagio
23 Oct 2002  06:58 PM GMT
Access violations in Printers.pas with Windows 2000.

Delphi 4 with QuickReport 3.0.3

I have this question, too. But I modify these code, it's still
has this problem. Use "QuickRep1.Print" is fine, but use "QuickRep1.Preview"
it will pop the Access violation error. What I to do? Please....

Thanks.

Vania R. Formágio
São Paulo - Brasil
Tel: 55 11 3043-0459
email: vania.formagio@taterka.com.br
Viviane
05 Nov 2002  06:59 PM GMT
I had problems with delphi3,my documents aren't printers when I use the printer HP Lazer 1200
Rodrigo F. Silva
12 Nov 2002  07:57 PM GMT
It's unbelievable that a problem that was reported in first time in May 2 2001 causes problems with your users yet (November 12 2002)! And this lines of code not resolve the problem, many users reported this problem after changed the modifications, and the problem persists. I am having problems with my clients because they uses windows 2000 with printer as default printer, and they are in a hurry!!!

How to solve this problem? Is there other mode of solve this???

Thanks

Rodrigo F. Silva
Rod Barrett
22 Dec 2002  08:19 PM GMT
I added the fix in Delphi 4 and 6, both under Windows 2000 and it worked.
Here is what I did.
Find printers.pas under the Delphi folder.
Open it in Notepad.
Search for the line :
GlobalUnlock(DeviceMode);

Above the search result add the line
DevMode := nil;

You will add this line in 3 places not 2!
Save the file and open your project.
Select Project | Build <project name>
Select an unavailble printer as the default printer.
Run your program... Viola...
Michael Higgins
27 Feb 2003  01:47 PM GMT
I seem to have this bug also in Delphi 3. I do not have the source code for Delphi 3, but do have it for delphi 5. I want to stay with D3 for this program as it is a more compact executable.

Can I modify the D5 printers.pas and put it into D3? And How?

Bye
BO
28 Apr 2003  09:04 AM GMT
Had the same error (access violation) when printing to a network printer when there is no connection to network
I added the fixes to printers.pas. This works fine on Win-98, but on Windows-XP i had to add one more line to prevent the access violation:

procedure TPrinter.SetState(Value: TPrinterState);
type
TCreateHandleFunc = function (DriverName, DeviceName, Output: PChar;
.
.
.
if Assigned(CreateHandleFunc) then
with TPrinterDevice(Printers.Objects[PrinterIndex]) do
begin
if DevMode <> nil then // <---- Line added ----------------
DC := CreateHandleFunc(PChar(Driver), PChar(Device), PChar(Port), DevMode)
else RaiseError(SInvalidPrinter);
if DC = 0 then RaiseError(SInvalidPrinter);
if FCanvas <> nil then FCanvas.Handle := DC;
end;
State := Value;
end;
end;
Grant
09 May 2003  04:17 PM GMT
Is there anybody can show the procedure to make the modified printers.pas working under C++ Builder 6.0?

I've searched Printers.dcu, and found the location are different for Delphi 6 and BCB6.
BCB6: $(BCB6)\Lib\Obj
Delphi6: $(Delphi6)\Lib

I followed the suggested procedure of Alan Tucker in Delphi 6, and copy the new printers.dcu to $(BCB6)\Lib\Obj.

But I still get an access violation error.

Should I do anything more?
Grant
11 May 2003  02:05 PM GMT
After rebooting the computer, it works.

Sorry for bothering you all.
Alberto (Brazil)
29 Oct 2004  06:34 PM GMT
I have an application running over Windows 98, Delphi 5, using Paradox (.DB) database and NetWare Novell 4.11. Now, i am using a HP DeskJet 7260 printer (USB cable). My problem is: if i use the Paradox database in NetWare Novell 4.11 drive map (M:\DataBase\...) and i try to print, appears the message "Printer selected is not valid". If i put this Paradox database in local hd (C:\DataBase\...), print ok.

What´s the problem ? Please, help me.

Thank´s

email: garibaldo@pop.com.br
Amitrajit Banerjee
21 Jan 2005  09:54 AM GMT
Hi ppl,

I am facing a similar problem, Borland C++ Builder 6 ships with Quick reports 3.0 so old and out dated that nothing need to be said abt it. I am an onfortunate soul who has to use QR with C++ builder (don't lauth). I tried all that was told in this site, but nothing worked....can anyone help me, my clients are after my ass....

mail me at tutan@rediffmail.com
Jerry Blumenthal
26 Mar 2005  10:12 PM GMT
I modified the following line in printers, hoping to fix the bug:
if AnsiUpperCase(TPrinterDevice(Objects[I]).Device) =
AnsiUpperCase(Device) then

I know that line was compiled in my app. When my one user who is having this problem (not on a network but has XP Home), tries to access the unit that calls PRINTERS, she gets the "No default printer" error message, as above. But only when she logs on as an administrator!!! When she logs on with lesser priveleges, she does not get the error!!!

Why? Anyone know?

jerry@blumenthalsoftware.com
Jerry Blumenthal
26 Mar 2005  10:13 PM GMT
I modified the following line in printers, hoping to fix the bug:
if AnsiUpperCase(TPrinterDevice(Objects[I]).Device) =
AnsiUpperCase(Device) then

I know that line was compiled in my app. When my one user who is having this problem (not on a network but has XP Home), tries to access the unit that calls PRINTERS, she gets the "No default printer" error message, as above. But only when she logs on as an administrator!!! When she logs on with lesser priveleges, she does not get the error!!!

Why? Anyone know?

jerry@blumenthalsoftware.com
v
14 Jun 2005  09:23 PM GMT
v
Latest update of this entry: 2002-02-28

Post a comment on this bug


Index page
Delphi Bug List home page
The Delphi Bug Lists are presently maintained by Jordan Russell, who has taken over this task from Reinier Sterkenburg since August 2000.
All feedback is appreciated. See also the feedback section of the Delphi Bug List home page.