Link to home
Start Free TrialLog in
Avatar of b_vaneck
b_vaneck

asked on

Updating printersettings

Hi,

I'm having a printerproblem. I've created my own printerdialog. Everythings goes ok like selecting a printer, changing the papersize and setting a number of copies. But when I want to change the properties of a printer is all goes wrong... Access Violation...
BTW: I'm working with Delphi 4

Here's my code for changing the properties:
procedure TMyPrintDlg.printInstellingenBtnClick(Sender: TObject);
var
  SpaceNeeded : word; // for pDriverinfo2
  pDBuff : _devicemodeA; // dummy
  aDevMode : PDeviceModeA;
  pDMode : PDEVMODE;
  Driver_info_2 : pDriverinfo2;
  DevModeSize : integer;
  dPtr : Pointer;
  hPrinter : THandle;
begin
  //Printername is a private variable of TMyPrintDlg
  OpenPrinter(PChar(Printername), hPrinter, nil);
  pDMode := GlobalLock(hPrinter);
  GetPrinter(hPrinter, 2, 0, 0, @SpaceNeeded);
  GetMem(Driver_info_2, SpaceNeeded);
  GetPrinter(hPrinter, 2, Driver_info_2, SpaceNeeded, @SpaceNeeded);
  DevModeSize := DocumentProperties(0, hPrinter, PChar(Printername), pDBuff, pDBuff, 0);
  dPtr := allocmem(DevModeSize);
  aDevMode := pDevmode(dPtr);
 
  //all goes ok until this point. When changing the properties of the printer, I get a unexpected Access Violation.
  DocumentProperties(0, hPrinter, PChar(PrinterName), aDevMode^, aDevMode^, DM_IN_BUFFER or DM_IN_PROMPT);
  //update the printersettings
  ResetDC(hPrinter, aDevMode^);
  ClosePrinter(hPrinter);
end;


Thankx in advance,

Benjamin
Avatar of Russell Libby
Russell Libby
Flag of United States of America image

Benjamin,

Im not sure what your trying to do with the GlobalLock on the printer handle.... but its not right. The bigger problems are this:

1.) SpaceNeeded is defined as word, and should be DWORD. (this is the second occurrence of the same problem that I have seen in about a week?....)
2.) for DocumentProperties (the second call) you are specifying DM_IN_BUFFER but are passing in an empty structure??? You have basically told the api to use the values in the buffer (some of which are pointers to char strings) and provided the api with junk... resulting in a gpf.

Try the following, which should work correctly for you.  

var  dwSpaceNeeded:       DWORD;
     dwDMSize:            DWORD;
     dmMode:              TDeviceMode;
     lpdmMode:            PDeviceMode;
     lpPrintInfo2:        PPrinterInfo2;
     hPrinter:            THandle;
     PrinterName:         String;
begin

  // For demo only ** REPLACE WITH YOUR CODE **
  PrinterName:=Printer.Printers[Printer.PrinterIndex];

  // Set structure memory to nil
  lpPrintInfo2:=nil;

  // Open the printer
  if (OpenPrinter(PChar(PrinterName), hPrinter, nil)) then
  begin
     // Get required memory size
     GetPrinter(hPrinter, 2, lpPrintInfo2, 0, @dwSpaceNeeded);
     // Allocate memory
     lpPrintInfo2:=AllocMem(dwSpaceNeeded);
     // Resource protection
     try
        // Get printer info
        GetPrinter(hPrinter, 2, lpPrintInfo2, dwSpaceNeeded, @dwSpaceNeeded);
        // Get dev mode size
        dwDMSize:=DocumentProperties(Handle, hPrinter, PChar(PrinterName), dmMode, dmMode, 0);
        // Allocate memory for the device mode
        lpdmMode:=AllocMem(dwDMSize);
        // Resource protection
        try
           DocumentProperties(Handle, hPrinter, PChar(PrinterName), lpdmMode^, lpdmMode^, DM_OUT_BUFFER or DM_IN_PROMPT);
           // Update the printer settings
           ResetDC(hPrinter, lpdmMode^);
        finally
           // Free allocated memory
           FreeMem(lpdmMode);
        end;
     finally
        // Free allocated memory
        FreeMem(lpPrintInfo2);
     end;
     // Close printer handle
     ClosePrinter(hPrinter);
  end;

end;


--


Regards,
Russell

Avatar of b_vaneck
b_vaneck

ASKER

Well Russell,

I've tried your code and it compiles and runs, but when I change any printer properties it will not keep the changes. When I for instance change the lay-out of a page to landscape, instead of portrait, it still prints on a portrait lay-out. Some way or another it doesn't keep the changes of the printer properties...

Thankx,

Benjamin

You indicated your problem was with an access violation, and I corrected your code so that it was syntactically and functionally correct. Now if you want this to work, then you should not be using ResetDC(...) which was meant to take an HDC handle, not a printer handle.

What you should be using is SetPrinter, passing the following:

SetPrinter(hPrinter, 2, lpdmMode, 0);

----

Russell
Hi Russell,

yes, my code is now syntactically correct and works almost fine. So thanks for that.
But when I try to apply the settings to change the printer properties it will give a winspool.drv error at SetPrinter(hPrinter, 2, lpdmMode, 0);. I tried the program on a different computer and still it give the winspool.drv error. So something goes wrong here.

Thankx,

Benjamin
Do you mind sharing the error then? (it would make it easier to figure the problem out)

Russell
Okay, the full error:

exception raised class EAccessViolation with message 'Access violation at address 73001AE5 in module 'winspool.drv'. Read of address 39464450. Process stopped.
It occurs when clicking the 'OK' button of the printer document properties dialog.

Benjamin
ASKER CERTIFIED SOLUTION
Avatar of Russell Libby
Russell Libby
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hey Russell,

well it worked eventually... So thankx, now I can finally move on to the next problem...

Benjamin