Как установить размер бумаги с помощью WinSpool API? - PullRequest
3 голосов
/ 31 июля 2011

Я не могу использовать API-интерфейс XPS, поскольку программа должна иметь возможность печати в Windows XP.

Я пытаюсь установить размер бумаги от Letter до A4 с помощью WinSpool.

Это мой тестовый код:

var
  H          : THandle;
  I          : TBytes;
  Info       : PPrinterInfo2;
  NeededSize : DWORD;
  DevMode    : PDeviceMode;
  PD         : TPrinterDefaults;
begin
  PD.pDatatype     := nil;
  PD.pDevMode      := nil;
  PD.DesiredAccess := PRINTER_ACCESS_ADMINISTER;
  if not OpenPrinter('Brother HL-5350DN series Printer', H, @PD) then begin
    raise Exception.Create('OpenPrinter error: ' + SysErrorMessage(GetLastError));
  end;
  try
    Assert(not GetPrinter(H, 2, nil, 0, @NeededSize));
    SetLength(I, NeededSize);
    Info := @I[0];
    if not GetPrinter(H, 2, Info, NeededSize, @NeededSize) then begin
      raise Exception.Create('GetPrinter error: ' + SysErrorMessage(GetLastError));
    end;
    DevMode             := Info.pDevMode;
    DevMode.dmFields    := DevMode.dmFields or DM_PAPERSIZE;
    DevMode.dmPaperSize := DMPAPER_A4;
    Info.pSecurityDescriptor := nil; // According to MSDN it has to be niled if we're not going to change it.

    if not SetPrinter(H, 2, Info, 0) then begin
      raise Exception.Create('SetPrinter error: ' + SysErrorMessage(GetLastError));
    end;
  finally
    ClosePrinter(H);
  end;
  TPrintDialog.Create(Self).Execute; // This is just so I can check the paper size
end;

У меня есть две проблемы, связанные с правами доступа.

Если установить PD.DesiredAccess на PRINTER_ACCESS_ADMINISTER, вызов GetPrinter не удастся, ядумаю, это связано с UAC.

Если я установлю его на PRINTER_ACCESS_USE, вызов GetPrinter будет успешным, а структура Info в порядке, но вызов SetPrinter завершится неудачей.

ИнтересноДостаточно, когда я игнорирую результат SetPrinter, в диалоговом окне печати отображается A4 как размер принтера, даже если SetPrinter не удается.

Я делаю это совершенно неправильно, и этого достаточно, чтобы передать правильную настройку PDeviceMode дляOpenPrinter?(Я действительно придумал это после написания этого вопроса: -)

Еще один вопрос относительно VCL:

Если я использую модуль Printers, как я узнаю, насколько большими должны быть буферыбыть переданы в качестве параметров для метода TPrinter.GetPrinter?

Фон :

Система: Windows 7 Professional 64-битный английский с английским языком.

Я пытаюсь печатать на бумаге формата A4 на сетевом принтере (Brother HL-5350DN).

Я установил все настройки принтера на панели управления на бумаге формата A4, но программа Delphi 2009 IПишу по-прежнему получаем размеры бумаги для US Letter.

Другими словами: программа Delphi не соответствует настройкам по умолчанию диспетчера очереди печати. ​​

Если я сначала запускаю TPrinterDialog ивыберите правильный размер бумаги оттуда вручную (в дополнительных настройках принтера) все в порядке.

Программа должна работать без какого-либо пользовательского интерфейса, поэтому я должен решить эту проблему программно или желательно, чтобы программа показалаПросто соблюдайте стандартные настройки диспетчера очереди печати Windows.

Может быть, я пропустил некоторые важные настройки?

Ответы [ 2 ]

7 голосов
/ 18 октября 2011

попробуйте это, ребята, это работает для меня

uses WinSpool,Windows,System;

procedure SetPrinterInfo(APrinterName: PChar);
var

  HPrinter : THandle;
  InfoSize,
  BytesNeeded: Cardinal;
  DevMode    : PDeviceMode;
  PI2: PPrinterInfo2;
  PrinterDefaults: TPrinterDefaults;

begin
  with PrinterDefaults do
  begin
    DesiredAccess := PRINTER_ACCESS_USE;
    pDatatype := nil;
    pDevMode := nil;
  end;
  if OpenPrinter(APrinterName, HPrinter, @PrinterDefaults) then
  try
    SetLastError(0);
    //Determine the number of bytes to allocate for the PRINTER_INFO_2 construct...
    if not GetPrinter(HPrinter, 2, nil, 0, @BytesNeeded) then
    begin
      //Allocate memory space for the PRINTER_INFO_2 pointer (PrinterInfo2)...
      PI2 := AllocMem(BytesNeeded);
      try
        InfoSize := SizeOf(TPrinterInfo2);
        if GetPrinter(HPrinter, 2, PI2, BytesNeeded, @BytesNeeded) then
        begin
          DevMode := PI2.pDevMode;
          DevMode.dmFields := DevMode.dmFields or DM_PAPERSIZE;
          DevMode.dmPaperSize := DMPAPER_A4;
          PI2.pSecurityDescriptor := nil;
          // Apply settings to the printer
          if DocumentProperties(0, hPrinter, APrinterName, PI2.pDevMode^,
                                PI2.pDevMode^, DM_IN_BUFFER or DM_OUT_BUFFER) = IDOK then
          begin
            SetPrinter(HPrinter, 2, PI2, 0);  // Ignore the result of this call...
          end;
        end;
      finally
        FreeMem(PI2, BytesNeeded);
      end;
    end;
  finally
    ClosePrinter(HPrinter);
  end;
end;
1 голос
/ 21 августа 2011

Как писал Дэвид, моя конкретная проблема решается путем установки правильных настроек принтера в Windows.

Я до сих пор не нашел способ установить свойства локальной печати для своего приложения, но это больше не так.обязательно.

Как написал Sertac, вы можете читать и записывать глобальные настройки принтера, используя TPrinter.GetPrinter и TPrinter.SetPrinter.(См. Комментарии к вопросу)

Поскольку никто не предоставил ответ, и проблема теперь решена, я отмечаю это как вики сообщества.Не стесняйтесь улучшать этот ответ.

...