直接使用 Printer 物件列印時,若系統未安裝印表機會拋出「I/O 錯誤 1772」例外。預先偵測印表機清單可優雅處理此情況。
uses Printers;
procedure TForm1.ButtonClick(Sender: TObject);
begin
ComboBox1.Clear;
ComboBox1.Items.Assign(Printer.Printers); { 列舉所有已安裝印表機名稱 }
if ComboBox1.Items.Count = 0 then
begin
MessageDlg('您需要安裝印表機才能列印!', mtError, [mbOK], 0);
Exit;
end;
{ 可選:讓使用者從 ComboBox 選擇印表機 }
{ Printer.PrinterIndex := ComboBox1.ItemIndex; }
Form1.Print; { 執行列印 }
end;
Printer.Printers 為 TStrings,直接 Assign 給隱藏的 TComboBox (或 TListBox) 即可取得清單,無需呼叫 API。Count = 0 即表示無印表機,避免觸發 I/O 錯誤。ComboBox1.Visible := False 可隱藏介面元件,僅作為暫存容器。uses Winspool;
function GetDefaultPrinterName: string;
var
Buffer: array[0..255] of Char;
Size: DWORD;
begin
Size := 256;
if GetDefaultPrinter(Buffer, Size) then
Result := Buffer
else
Result := '';
end;
function GetPrinterStatus(PrinterName: string): string;
var
hPrinter: THandle;
pInfo: PPrinterInfo2;
BytesNeeded: DWORD;
begin
Result := '未知';
if OpenPrinter(PChar(PrinterName), hPrinter, nil) then
try
GetPrinter(hPrinter, 2, nil, 0, BytesNeeded);
GetMem(pInfo, BytesNeeded);
try
if GetPrinter(hPrinter, 2, pInfo, BytesNeeded, BytesNeeded) then
case pInfo.Status of
PRINTER_STATUS_PAUSED: Result := '暫停';
PRINTER_STATUS_ERROR: Result := '錯誤';
PRINTER_STATUS_PENDING_DELETION: Result := '刪除中';
PRINTER_STATUS_PAPER_JAM: Result := '卡紙';
PRINTER_STATUS_PAPER_OUT: Result := '缺紙';
PRINTER_STATUS_MANUAL_FEED: Result := '手動進紙';
PRINTER_STATUS_OFFLINE: Result := '離線';
0: Result := '就緒';
else Result := '其他狀態 (' + IntToStr(pInfo.Status) + ')';
end;
finally
FreeMem(pInfo);
end;
finally
ClosePrinter(hPrinter);
end;
end;
善用 Printer.Printers 列舉機制,能在列印前優雅偵測印表機是否存在,避免執行期 I/O 例外中斷程式流程。結合 Winspool API 更可取得詳細狀態,打造專業級列印功能。