C# PrintDocument.Print导致Win32Exception操作成功完成
我正在尝试将C#.NET 3.5应用程序打印到网络打印机上,出现以下异常: 操作已成功完成 是什么原因造成的,如何解决C# PrintDocument.Print导致Win32Exception操作成功完成,c#,printing,C#,Printing,我正在尝试将C#.NET 3.5应用程序打印到网络打印机上,出现以下异常: 操作已成功完成 是什么原因造成的,如何解决 System.ComponentModel.Win32Exception: The operation completed successfully at System.Drawing.Printing.PrinterSettings.GetHdevmodeInternal() at System.Drawing.Printing.PrinterSettings.G
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()
- 该帐户具有使用网络打印机打印的权限。已为每个人设置打印权限
- 打印机已被删除并重新创建
- 后台打印与直接打印到打印机的设置已双向切换
- 机器上的其他打印机工作正常
- 网络上的其他客户端和同一台计算机上的应用程序可以打印到此打印机而不会出现问题
我的问题的解决方案是卸载导致问题的驱动程序,然后安装一个旧的驱动程序。如果没有代码和一个异常说明一切正常,很难回答。因此,我将给出一些解决问题的方法
令人迷惑的消息是由.NET Framework中pinvoke代码中的错误引起的。失败的底层winapi调用是。它的pinvoke声明如下所示:
[DllImport("winspool.drv", CharSet=CharSet.Auto, SetLastError=true)]
public static extern int DocumentProperties(...);
SetLastError
属性错误。从MSDN链接可以看出,函数返回负值表示失败。并且没有记录设置由GetLastError()
返回的错误代码
此错误的结果是框架将调用Marshal.GetLastWin32Error()
来获取错误代码,并将获取一个随机值,因为DocumentProperties()
没有设置它。值0
不太可能,这会产生“操作已成功完成”异常消息
因此,您需要忽略异常消息;当然,这是毫无帮助的。不幸的是,与大多数GDI函数一样,这个winapi函数属于只生成“it't not work”返回代码的函数类别。它没有给出在哪里寻找问题的提示。这种怪癖有一个半合理的原因:当您调用DocumentProperties()
时,Windows本身做得很少;大部分工作由打印机驱动程序完成。winapi中没有为打印而预留的错误代码集。任何事情都是可能的:打印机驱动程序不是细微的代码块。打印机驱动程序的任务是告诉您有关问题的信息。他们应该通过弹出自己的窗口来做到这一点。理论上,他们无论如何都是;如今,该细分市场的激烈竞争并没有留下多少钱来支付一名优秀程序员的薪水
当您从服务打印时,这当然不起作用。没有任何方法可以看到这样的弹出窗口,这是Microsoft极力阻止从服务打印的核心原因。您和客户的IT人员都没有机会诊断问题。有关从服务中使用PrintDocument
的更多说明,请阅读本手册
没有人喜欢得到这样的建议,但这是明摆着的。不要这样做。为了补充@HansPassant的答案,下面是引发异常的确切代码: Microsoft参考源
private IntPtr GetHdevmodeInternal(字符串打印机){
//创建DEVMODE
int modeSize=SafeNativeMethods.DocumentProperties(NativeMethods.NullHandleRef,NativeMethods.NullHandleRef,printer,IntPtr.Zero,NativeMethods.NullHandleRef,0);
if(modeSize<1){
抛出新的InvalidPrinterException(此);
}
IntPtr handle=SafeNativeMethods.GlobalAlloc(SafeNativeMethods.GMEM_MOVEABLE,(uint)modeSize);//不能是我也有这个问题。在我的例子中,我使用了一个单独的线程来打印报告,并通过“ManualResetEvent”将其与主线程同步。(我采用这种方式是因为.Net强制将打印逻辑划分为“打印页”方法
该错误是由于打印机驱动程序与此多线程环境之间的不兼容(我无法解释其来源)造成的
我通过将打印逻辑方法签名从“void”更改为“IEnumerable”来解决这个问题,并突破了收益率返回,这是一种类似于“CoRoutines”的方法"Unity3d游戏引擎。这样,就不必创建多个线程,我的打印代码也会被组织起来。我以前遇到过这个错误-错误消息真的有误导性。我想你已经完成了,但如果你不发布一些代码,我会给你回复。@p.campbell抱歉,我没有。我记得没有文档在这些主题上会非常令人沮丧,所以很抱歉,我不能提供更多帮助。我当时在半相关的印刷主题上发布了一些旧问题,不确定这些问题是否相关,或者您是否已经检查过。不确定为什么会被否决,但您只是帮助我解决了一个我今天正在处理的问题s、 出于测试目的,我在UI线程上启动了我的打印,它确实工作了,从另一个线程返回到启动打印,并将打印机的驱动程序更新到HP的最新官方版本,现在可以工作了。我以前使用的是HP的universal PCL6 6.2.6。该驱动程序不喜欢在多线程环境中调用。6.2.1,sorry.HP通用打印PCL 6(v6.2.1)
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(); // <--------
}
}