【问题标题】:PrintDocument.Print results in Win32Exception The operation completed successfullyPrintDocument.Print 导致 Win32Exception 操作成功完成
【发布时间】:2010-11-26 21:53:21
【问题描述】:

我正在尝试在 C# .NET 3.5 应用程序中打印到网络打印机并收到此异常:

操作成功完成

是什么原因造成的,如何解决?

System.ComponentModel.Win32Exception: The operation completed successfully
   at System.Drawing.Printing.PrinterSettings.GetHdevmodeInternal()
   at System.Drawing.Printing.PrinterSettings.GetHdevmode(PageSettings pageSettings)
   at System.Drawing.Printing.PrintController.OnStartPrint(PrintDocument document, PrintEventArgs e)
   at System.Windows.Forms.PrintControllerWithStatusDialog.OnStartPrint(PrintDocument document, PrintEventArgs e)
   at System.Drawing.Printing.PrintController.Print(PrintDocument document)
   at System.Drawing.Printing.PrintDocument.Print()
  • 该帐户有权使用网络打印机进行打印。已设置每个人都可以打印的权限。
  • 打印机已被删除并重新创建。
  • 后台打印与直接打印到打印机的设置已在两种方式之间切换。
  • 机器上的其他打印机工作正常
  • 网络上的其他客户端和同一台计算机上的应用程序可以毫无问题地打印到这台打印机。

为了缩小问题范围,我创建了一个简单的控制台应用程序。以普通用户身份运行,应用程序打印。以服务帐户身份运行时,服务帐户会出错

我的问题的解决方案是卸载导致问题的驱动程序,并安装旧版驱动程序。

【问题讨论】:

  • 我之前遇到过这个错误——这个错误信息真的很误导人。我想你已经完成了,但如果你不发布一些代码,我会回复你。
  • @p.campbell 对不起,我没有。我记得缺乏关于这些主题的文档非常令人沮丧,所以很抱歉我无法提供更多帮助。我当时发布了一些关于半相关印刷主题的旧问题,不确定这些问题是否相关,或者您是否已经检查过它们。

标签: c# printing


【解决方案1】:

很难回答没有代码和一个说你一切正常的异常。所以我只是提供一些想法来追踪问题

  1. 在本地打印机上对其进行测试,以确保应用程序正常工作。
  2. 尝试使用记事本或类似工具打印到联网打印机
  3. 再次检查运行应用程序的用户是否有权打印到网络打印机。
  4. 在另一台联网打印机上测试(在为该打印机执行 2 和 3 之后)

【讨论】:

    【解决方案2】:

    神秘的消息是由 .NET Framework 中的 pinvoke 代码中的错误引起的。失败的底层 winapi 调用是DocumentProperties() function。它的 pinvoke 声明如下所示:

    [DllImport("winspool.drv", CharSet=CharSet.Auto, SetLastError=true)]
    public static extern int DocumentProperties(...);
    

    SetLastError 属性错误。从 MSDN 链接可以看出,该函数通过返回负值来指示失败。并且没有记录设置GetLastError()返回的错误代码。

    这个bug的后果是框架会调用Marshal.GetLastWin32Error()来获取错误码,并且会得到一个随机值,因为DocumentProperties()没有设置它。 0 的值并非不可能,这会产生“操作成功完成”异常消息。

    所以你需要忽略异常信息;当然,这是非常无益的。不幸的是,这个 winapi 函数属于一类函数,就像大多数 GDI 函数一样,只会产生“它不起作用”的返回码。它没有提示在哪里寻找问题。这个怪癖有一个正当的理由:当你调用DocumentProperties() 时,Windows 本身做的很少;大部分工作由打印机驱动程序完成。在 winapi 中没有为打印预留的错误代码集。一切皆有可能:打印机驱动程序不是微妙的代码块。告诉您问题是打印机驱动程序的工作。他们应该通过弹出自己的窗口来做到这一点。理论上它们无论如何都是;如今,该细分市场的激烈竞争并没有留下很多钱来支付好程序员的薪水。

    当您从服务打印时,这当然不起作用。没有任何方法可以看到这样的弹出窗口,这是 Microsoft 强烈 不鼓励从服务打印的核心原因。您和您客户的 IT 人员都没有机会诊断问题。阅读此blog post,了解有关在服务中使用PrintDocument 的更多说明。

    没有人喜欢得到这样的建议,但写在墙上。 不要这样做

    【讨论】:

      【解决方案3】:

      要添加到@HansPassant 的答案,这里是引发异常的确切代码:

      微软参考源,PrinterSettings.cs

      private IntPtr GetHdevmodeInternal(string printer) {
          // Create DEVMODE
          int modeSize = SafeNativeMethods.DocumentProperties(NativeMethods.NullHandleRef, NativeMethods.NullHandleRef, printer, IntPtr.Zero, NativeMethods.NullHandleRef, 0);
          if (modeSize < 1) {
              throw new InvalidPrinterException(this);
          }
          IntPtr handle = SafeNativeMethods.GlobalAlloc(SafeNativeMethods.GMEM_MOVEABLE, (uint)modeSize); // cannot be <0 anyway
          IntPtr pointer = SafeNativeMethods.GlobalLock(new HandleRef(null, handle));
      
          //Get the DevMode only if its not cached....
          if (cachedDevmode != null) {
              Marshal.Copy(cachedDevmode, 0, pointer, devmodebytes);
          }
          else  {
              int returnCode = SafeNativeMethods.DocumentProperties(NativeMethods.NullHandleRef, NativeMethods.NullHandleRef, printer, pointer, NativeMethods.NullHandleRef, SafeNativeMethods.DM_OUT_BUFFER);
              if (returnCode < 0) {
                  throw new Win32Exception();  // <--------
              }
          }
      

      【讨论】:

        【解决方案4】:

        我也有这个问题。在我的例子中,我使用了一个单独的线程来打印报告,并通过“ManualResetEvent”将它与主线程同步。 (我开发这种方式是因为 .Net 强制将打印逻辑划分为“PrintPage”方法...)。

        由于打印机驱动程序和这个多线程环境之间的不兼容(我无法解释原因)而发生错误。

        我通过将打印逻辑方法签名从“void”更改为“IEnumerable”解决了这个问题,并突破了 yield return,一种类似于 Unity3d 游戏引擎的“CoRoutines”的方法。这样一来,就不需要创建多个线程,而且我的打印代码也井井有条。

        【讨论】:

        • 不知道为什么这被否决了,但你只是帮我解决了我工作了好几天的问题。出于测试目的,我在 UI 线程上启动了我的打印,它确实工作,返回从另一个线程启动打印并将打印机的驱动程序更新到 HP 的最新官方版本,它现在可以工作了。我之前使用的是 HP 的通用 PCL6 6.2.6。该驱动程序不喜欢在多线程环境中被调用。
        • 6.2.1,对不起。 HP 通用打印 PCL 6 (v6.2.1)
        猜你喜欢
        • 2012-01-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-12
        相关资源
        最近更新 更多