含蓄的爆米花 · Postgresql: ...· 6 月前 · |
高大的春卷 · 如何在20元小板子上跑Python - 知乎· 1 年前 · |
乐观的灭火器 · python - raise ...· 1 年前 · |
个性的茄子 · string 转化xml ...· 1 年前 · |
发财的西装 · JS数组操作大全对象数组根据某个相同的字段分 ...· 1 年前 · |
我试图在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()
为了缩小问题范围,我创建了一个简单的控制台应用程序。作为一个正常的用户运行,应用程序打印。当作为服务帐户运行时,它会为服务帐户错误。
针对我的问题的 解决方案 是卸载导致问题的驱动程序,并安装一个较旧的驱动程序。
发布于 2014-07-11 21:41:42
令人费解的消息是由.NET框架内的pinvoke代码中的一个bug引起的。失败的底层winapi调用是 函数 。它的pinvoke声明如下所示:
[DllImport("winspool.drv", CharSet=CharSet.Auto, SetLastError=true)]
public static extern int DocumentProperties(...);
SetLastError
属性是错误的。从MSDN链接中可以看出,该函数通过返回一个负值来指示失败。并且没有文档化来设置
GetLastError()
返回的错误代码。
这个错误的后果是,框架将调用
Marshal.GetLastWin32Error()
来获取错误代码,并将得到一个随机值,因为
DocumentProperties()
没有设置它。
0
的值并不是不可能的,它会生成“操作成功完成”异常消息。
因此,您需要忽略异常消息,这当然是非常没有帮助的。不幸的是,与大多数GDI函数一样,这个winapi函数属于一类函数,只产生一个“它不工作”的返回代码。它没有给出寻找这个问题的线索。这种怪癖有一个不太好的理由:当你调用
DocumentProperties()
时,Windows本身几乎不起作用;大部分工作是由打印机驱动程序完成的。在winapi中没有一组用于打印的错误代码。任何事情都是可能的:打印机驱动程序不是细微的代码块。告诉你问题是打印机驱动程序的工作。他们应该通过弹出自己的窗口来做到这一点。从理论上讲,他们是无论如何;激烈的竞争,在那个市场部分没有留下很多钱来支付一个好程序员的工资。
当然,当您从服务中打印时,这是无法工作的。没有任何方法可以看到这样的弹出窗口,这也是微软
强烈反对从服务中打印的核心原因。您和客户的IT人员都没有机会诊断问题。有关从服务中使用
博客帖子
的附加说明,请阅读此
PrintDocument
。
没有人喜欢得到这样的建议,但写在墙上。不要这样做。
发布于 2014-07-17 20:04:05
为了添加到@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);
高大的春卷 · 如何在20元小板子上跑Python - 知乎 1 年前 |