delphiprintingdelphi-xe2quickreports

How can I get the COLLATE setting of a printer driver?


I need to capture a printer driver's settings that a windows machine has set up to determine if they have collate turned on for a particular printer.

I know how to get whether a printer can collate using the DeviceCapabilities call passing in DC_COLLATE but this does not tell me whether the print driver is set to collate or not, only that the printer has the ability to collate, not that it will collate.

Why?

I am trying to work around an issue in QuickReports with Delphi XE2 where our program no longer works the way it did when compiled under Delphi 6. With the Delphi 6 version no matter the settings from QuickReport it ALWAYS obeyed the collate setting in the printer driver. With the Delphi XE2 version it does not.

The user does not have security to change collate settings, it is forced on for them by their sysadmins and these documents need to print collated on the specified printer.

If I can determine if the driver is set to collate always I can just force the collate setting in QuickReport and it will do what I need and thus my question above.

As always I appreciate any ideas.

Cheers!


Solution

  • You need to use the Windows API functions OpenPrinter and GetPrinter. When calling GetPrinter, pass it a PRINTER_INFO_2 record, which will be returned with the pDevMode member set to a DEVMODE; that DEVMODE record contains a flag for whether collation is enabled (among other things).

    Here's an old Borland NG post by TeamB's Dr. Peter Below. It demonstrates updating printer settings to make them permanent, but it includes using OpenPrinter, GetPrinter, ClosePrinter, and PRINTER_INFO_2, as well as using the DEVMODE (referred to as hDevMode in the code below); it should get you started.

    Procedure MakePrintersettingsPermanent;
    var
      hPrinter: THandle;
      Device : array[0..255] of char;
      Driver : array[0..255] of char;
      Port   : array[0..255] of char;
      hDeviceMode: THandle;
      pDevMode: PDeviceMode;
      bytesNeeded: Cardinal;
      pPI: PPrinterInfo2;
      Defaults: TPrinterDefaults;
      retval: BOOL;
    begin
      Assert( Printer.PrinterIndex >= 0 );
      Printer.GetPrinter(Device, Driver, Port, hDeviceMode);
      FillChar( Defaults, Sizeof(Defaults), 0 );
      Defaults.DesiredAccess:= 
        PRINTER_ACCESS_ADMINISTER or PRINTER_ACCESS_USE;
      if not WinSpool.OpenPrinter(@Device, hPrinter, @Defaults ) then
            RaiseLastWin32Error;
      try
        retval := WinSpool.GetPrinter(
          hPrinter,
          2,
          Nil, 0, @bytesNeeded );
        GetMem( pPI, bytesNeeded );
        try
          retval := WinSpool.GetPrinter(
            hPrinter, 2,
            pPI, bytesNeeded, @bytesNeeded );
          If not retval Then 
            RaiseLastWin32Error;
    
          pDevMode := GlobalLock( hDeviceMode );
          Assert( Assigned( pdevmode ));
          try
            Move( pdevmode^, pPI^.pDevMode^, Sizeof( pdevmode^ ));
          finally
            GlobalUnlock( hDevicemode );
          end;
          If not WinSpool.SetPrinter(
            hPrinter, 2,
            pPI,
            0 )
          Then
            RaiseLastWin32error;
        finally
          FreeMem( pPI );
        end;
      finally
        WinSpool.ClosePrinter( hPrinter );
      end;
    end;