2011-07-31 58 views
3

由於程序必須能夠在Windows XP上打印,因此我無法使用XPS API。如何使用WinSpool API設置紙張大小?

我試圖使用WinSpool從Letter設置紙張大小爲A4。

這是我的測試代碼:

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.DesiredAccessPRINTER_ACCESS_ADMINISTERGetPrinter調用失敗,我想這是由於UAC。

如果我將它設置爲PRINTER_ACCESS_USEGetPrinter調用成功,Info結構正常,但對SetPrinter的調用失敗。

有趣的是,當我忽略SetPrinter的結果時,即使SetPrinter失敗,打印對話框也會將A4報告爲打印機大小。

我在做它完全錯誤,它足以將PDeviceMode正確設置爲OpenPrinter? (其實我寫這個問題:-)

另一個問題是關於VCL後本想出了:

如果我使用Printers單元我怎麼知道緩衝區有多大,必須是那些獲得作爲參數傳遞到TPrinter.GetPrinter方法?

背景

該系統:Windows 7專業版64位英語與英語語言環境。

我試圖在網絡打印機(Brother HL-5350DN)上打印到A4紙。

我已將控制面板中的所有打印機設置設置爲A4紙,但我正在編寫的Delphi 2009程序仍獲取US Letter的紙張尺寸。

換句話說:Delphi程序不考慮打印機假脫機程序的默認設置。

如果我先運行一個TPrinterDialog並從那裏手動選擇正確的紙張尺寸(在高級打印機設置中),一切都很好。

該程序必須運行沒有任何用戶界面,所以我必須以編程方式解決此問題,或者最好該程序應該只是尊重默認的Windows打印機後臺處理程序設置。

也許我錯過了一些重要的設置?

+0

爲什麼你不能使用TPrinter工作? –

+0

@大衛:有一個在TPrinter沒有的PageFormat設置,我可以看到的唯一方法是使用TPrinter.GetPrinter和TPrinter.SetPrinter。我如何知道爲TPrinter.GetPrinter的參數分配了多少空間? –

+0

你究竟想在這裏做什麼?打印機當然知道紙張的大小。用戶從打印機首選項對話框中選擇他們想要的紙盒。您無法更改代碼中的紙張尺寸!如果您將整個故事告訴我們,而不是僅僅爲您的問題的一個小角落提供一個窗口,它可能會對我們有所幫助。 –

回答

1

就像大衛寫道,我的具體問題可以通過在Windows中設置正確的打印機首選項來解決。

我還沒有找到一種方法來爲我的應用程序設置本地打印屬性,但這不再必要。

像塞爾特克寫道,您可以使用TPrinter.GetPrinterTPrinter.SetPrinter來讀寫全局打印機首選項。(見註釋的問題)

因爲沒有人提供了一個anwser和現在的問題解決了,我這標誌着作爲社會的維基。隨意改善這個答案。

7

試試這個傢伙 對我來說

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;