【问题标题】:"There is no default printer selected" error when Windows default printer is not set up未设置 Windows 默认打印机时出现“未选择默认打印机”错误
【发布时间】:2017-07-07 10:10:49
【问题描述】:

当没有 Windows 默认打印机设置时,我需要打开打印机对话框。设置 Windows 默认打印机后,它可以与以下代码一起正常工作。

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

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

没有选择默认打印机

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

错误 E2122 函数调用因地址 XXX 处未处理的异常 XXX 而终止

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

【问题讨论】:

  • 太宽泛了。请发帖MVCE

标签: c++ windows c++builder printers network-printers


【解决方案1】:

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

// 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 是我放置在表单上的对话框。

【讨论】:

  • 我在打开对话框之前检查打印机。在上面的代码中,当没有选择 windows 默认打印机时,dlg_print->Execute() 将返回一个异常“没有选择默认打印机”。这就是我提到的问题。
  • @Santhosh 只是一个愚蠢的问题,但您是否检查过 dlgPrint 是否不为空(因为您是动态创建的)?它在代码中的确切位置(我希望不在表单构造函数中)?
  • 是的,我查过了。它不为空。如果 Printer()->PrinterIndex 属性使用索引正确设置,则 dlg->Execute() 工作正常。我正在检查 PASCAL 代码中的打印机类
  • @Santhosh 在什么情况下?仅当您的应用程序/表单有效且正在运行时才应执行此操作,因此在初始调整大小和激活之后...在某些 VCL 内容尚不存在之前...
  • 问题是TPrintDialog::Execute() 内部读取TPrinter::PrinterIndex 属性,如果Windows 中没有配置默认打印机,则会引发异常。有关详细信息,请参阅我的答案。
【解决方案2】:

只有TPrinter::SetToDefaultPrinter() 方法会抛出“当前没有选择默认打印机”异常,当:

  • 使用(未记录的)PRINTER_ENUM_DEFAULT 标志进行枚举时,Win32 API EnumPrinters() 函数失败并出现 ERROR_INVALID_NAME 错误代码。

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

TPrinter::SetToDefaultPrinter() 仅由以下人员调用:

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

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

TPrintDialog::Execute()(它使用 Win32 API PrintDlg() 函数)首先调用TPrinter::GetPrinter() 来获取当前选定打印机的DEVMODE 的句柄,然后使用它来初始化对话框(通过@987654324 @ 场地)。 TPrinter::GetPrinter() 读取TPrinter::PrinterIndex 属性,所以如果当前没有选择的打印机,也没有默认的打印机,就会抛出异常。

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

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

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

【讨论】:

    猜你喜欢
    • 2011-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-07
    • 2020-03-14
    • 1970-01-01
    相关资源
    最近更新 更多