|
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
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
|
|