2008. augusztus 7., csütörtök

Selecting a printer


Problem/Question/Abstract:

PrinterIndex selects the current printer but also applies the properties of the currently active printer.

Answer:

Q: How to change the current printer ?

A: Printer.PrinterIndex := Printer.Printers.IndexOf('printername'); ???

The answer is certainly correct, but there is also a problem. This problem came up when developing a label printing program for DHL shipping labels using the form design and print library WPForm&Report under Delphi 5: although the mentioned code selects the printer (this is good) it also applies the properties of the standard printer to the newly selected printer. So any preselected paper format is lost and the printer (in our case it was a big Siemens label printer) used a wrong paper format.

Although it took a while to find this ot, the solution was not too difficult:

The only possible solution for us was making a copy of the original printers.pas file and changing it. The new printer unit was linked to the project instead of the old one. (I know, such a change is unfortunate but there are no virtual methods in the TPrinter object so overriding of the method 'SetPrinterIndex' is not possible)

This code shows you the necessary changes. The idea was to read out the properties of the newly selected printer before it is activated for printing.

procedure TWPFPrinter.SetPrinterIndex(Value: Integer);
var
  DrvHandle: THandle;
  ExtDevCaps: TFarProc;
  DriverName: string;
  ExtDevCode: Integer;
  OutDevMode: PDevMode;
  ADevice: array[0..256] of Char;
  StubDevMode: TDeviceMode;
begin
  CheckPrinting(False);
  if (Value = -1) or (PrinterIndex = -1) then
    SetToDefaultPrinter
  else if (Value < 0) or (Value >= Printers.Count) then
    RaiseError(SPrinterIndexError);
  FPrinterIndex := Value;
  FreeFonts;
  SetState(psNoHandle);
  // ------------------------------------------------------------------------
  // Now we load the currently selected properties of the
  // newly selected printer.
  // otherwise the same 'DeviceMode' memory block to initialize the new printer
  // ------------------------------------------------------------------------
  if DeviceMode <> 0 then
  begin
    GlobalUnlock(DeviceMode);
    GlobalFree(DeviceMode);
    DeviceMode := 0;
  end;
  // ------------------------------------------------------------------------
  // This code was copied from the SetPrinters procedure
  // ------------------------------------------------------------------------
  with TPrinterDevice(Printers.Objects[PrinterIndex]) do
    StrCopy(ADevice, PChar(Device));
  if OpenPrinter(ADevice, FPrinterHandle, nil) then
  begin
    if DeviceMode = 0 then // alloc new device mode block if one was not passed in
    begin
      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;
    end;
    if DeviceMode 0 then
      SetPrinterCapabilities(DevMode^.dmFields);
  end;
end;

Nincsenek megjegyzések:

Megjegyzés küldése