PrintDocument.Print导致Win32Exception操作成功完成

Pri*_*his 10 c# printing

我试图在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()
Run Code Online (Sandbox Code Playgroud)
  • 该帐户有权使用网络打印机进行打印.为Everyone设置权限以进行打印.
  • 打印机已被删除并重新创建.
  • 假脱机与直接打印到打印机的设置已经双向切换.
  • 机器上的其他打印机工作正常
  • 网络上的其他客户端和同一台计算机上的应用程序可以毫无问题地打印到此打印机.

为了缩小问题范围,我创建了一个简单的控制台应用程序.作为普通用户运行,应用程序打印.当运行作为服务帐户,它犯错服务帐户.

在此输入图像描述

解决我的问题是卸载,导致该问题的驱动程序,并安装一个较旧的驱动程序.

Han*_*ant 17

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

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

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

此错误的后果是框架将调用Marshal.GetLastWin32Error()以获取错误代码并将获得随机值,因为DocumentProperties()没有设置它.值0不是不太可能,这会产生"操作成功完成"异常消息.

所以你需要忽略异常消息; 当然,这是非常无益的.不幸的是,这个winapi函数属于一类函数,就像大多数GDI函数一样,只产生"它不起作用"的返回代码.它没有提示在何处寻找问题.这个怪癖有一个不太合适的原因:当你打电话时,Windows本身很少DocumentProperties(); 大多数工作都是由打印机驱动程序完成的.在winapi中没有用于打印的错误代码集.一切皆有可能:打印机驱动程序不是微妙的代码块.打印机驱动程序的工作是告诉您有关问题的信息.他们应该通过弹出自己的窗口来实现这一目标.理论上他们无论如何; 如今市场细分市场的激烈竞争并没有留下很多钱来支付这些天的优秀程序员工资.

当您从服务打印时,这当然不起作用.没有任何方法可以看到这样的弹出窗口,这是微软强烈反对从服务打印的核心原因.您和您客户的IT员工都没有机会诊断问题.阅读此博客文章,了解有关使用PrintDocument服务的其他说明.

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


ant*_*duh 5

要添加@ HansPassant的答案,以下是引发异常的确切代码:

Microsoft Reference Source,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();  // <--------
        }
    }
Run Code Online (Sandbox Code Playgroud)


Nif*_*fle 1

如果没有代码并且有一个异常表明一切正常,则很难回答。所以我只会给出一些想法来找出问题所在

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