"There is no default printer selected" 未设置 Windows 默认打印机时出错

"There is no default printer selected" error when Windows default printer is not set up

当没有 Windows 默认打印机设置时,我需要打开打印机对话框。当设置 Windows 默认打印机时,它可以正常使用以下代码。

TPrintDialog *dlgPrint = new TPrintDialog(frmDisplayDetail);
if( dlgPrint->Execute()) { //code here }

但是如果 Windows 中没有默认打印机设置,dlgPrint->Execute() 会抛出异常:

There is no default printer selected

为了检查默认打印机索引,我使用了 Printer()->PrinterIndex。当没有 Windows 打印机设置时,此值变得不可访问:

error E2122 Function call terminated by unhandled exception XXX at address XXX

我做错了什么吗?请提出解决方案。

我正在使用对话框之前检查打印机是否存在:

// check printer interface
TPrinter *prn = Printer(); 
int pxs,pys,i=0;
if (prn==NULL)i=1;
if (prn->Printers==NULL) i=1;
if (prn->Printers->Count<=0) i=1;
if (i) return;
// use dialog
dlg_print->Options.Clear();
dlg_print->Options<<poPrintToFile;
if (!dlg_print->Execute()) return;
// print
prn = Printer();
pxs=prn->PageWidth;
pys=prn->PageHeight;
prn->BeginDoc();
for (i=0;i<dlg_print->Copies;i++)
    {
    if (i) prn->NewPage();
    // here render page into prn->Canvas as image in resolution pxs,pys
    }
prn->EndDoc();

其中 dlg_print 是我放置在表单上的对话框。

异常 "There is no default printer currently selected" 仅由 TPrinter::SetToDefaultPrinter() 方法抛出,当:

  • Win32 API EnumPrinters() 函数在使用(未记录的)PRINTER_ENUM_DEFAULT 标志枚举时失败并显示 ERROR_INVALID_NAME 错误代码。

  • TPrinter::Printers 列表不包含默认打印机。如果上面的 EnumPrinters() 没有报告默认设备,则从 Win32 API GetDefaultPrinter() 函数(Delphi/C++Builder 2009 及更高版本)或 device %windir%\win.ini[windows] 部分的值(Delphi/C++Builder 2007 及更早版本)。

TPrinter::SetToDefaultPrinter() 仅被调用:

  • TPrinter::PrinterIndex getter 如果 FPrinterIndex 成员当前为 -1。

  • TPrinter::PrinterIndex setter 如果 FPrinterIndex 成员当前为 -1,或者 属性 被设置为 -1。

TPrintDialog::Execute()(使用 Win32 API PrintDlg() function) first calls TPrinter::GetPrinter() to get a handle to the DEVMODE of the currently selected printer, which it then uses to initialize the dialog (via the PRINTDLG::hDevMode 字段)。 TPrinter::GetPrinter() 读取 TPrinter::PrinterIndex 属性,所以如果没有当前选择的打印机,也没有默认打印机,则抛出异常。

如果没有配置默认打印机,你基本上就倒霉了,因为你甚至不能将 TPrinter::PrinterIndex 属性 设置为 >= 0 的值,因为它会首先调用 SetToDefaultPrinter() 在检查新值是否与当前值匹配之前。

TPrinter 在 Windows 中没有配置默认打印机时,历史悠久 failing/crashing。要解决此问题,您应该直接调用 Win32 API PrintDlg() 函数。至少到那时,您可以手动调用 TPrinter::GetPrinter()(以获得初始 DEVMODE)并将其包装在 try/catch 块中以丢弃它可能抛出的任何异常。

如果对话框结果显示成功,您可以手动调用TPrinter::SetPrinter()将选定的打印机选项分配给TPrinter用于后续打印。