I am trying to print in a C# .NET 3.5 app to a network printer and getting this exception:
The operation completed successfully
What is causing it, and how can it be solved?
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()
To narrow the issue down, I've created a simple console app. Running as a normal user, the app prints. When Run As the service account, it errs for the service account.
The resolution to my problem was to uninstall the driver that is causing the issue, and install an older driver.
The mystifying message is caused by a bug in pinvoke code inside the .NET Framework. The underlying winapi call that fails is the DocumentProperties()
function. The pinvoke declaration for it looks like this:
[DllImport("winspool.drv", CharSet=CharSet.Auto, SetLastError=true)]
public static extern int DocumentProperties(...);
The SetLastError
property is wrong. As you can tell from the MSDN link, the function indicates failure by returning a negative value. And is not documented to set the error code that's returned by GetLastError()
.
The consequence of this bug is that the framework will call Marshal.GetLastWin32Error()
to obtain the error code and will get a random value since DocumentProperties()
didn't set it. A value of 0
is not unlikely, which produces the "The operation completed successfully" exception message.
So you need to ignore the exception message; it is very unhelpful of course. Unfortunately, this winapi function falls into a category of functions, like most GDI functions do, that only produce an "it didn't work" return code. It gives no hint where to look for the problem. There is a half-decent reason for this quirk: Windows itself does very little when you call DocumentProperties()
; most of the work is done by the printer driver. There is no set of error codes set-aside for printing in the winapi. Anything is possible: printer drivers are not subtle chunks of code. It is the job of the printer driver to tell you about problems. They are supposed to do so by popping up their own window. Theoretically they are anyway; the cut-throat competition in that market segment does not leave a lot of money to pay a good programmer's salary these days.
This of course cannot work when you print from a service. There isn't any way to see such a popup window, which is the core reason that Microsoft strongly discourages printing from a service. Neither you nor your customer's IT staff stands a chance to diagnose problems. Read this blog post for additional notes about using PrintDocument
from a service.
Nobody likes to get advice like this, but the writing is on the wall. Don't do it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With