Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PrintDocument.Print results in Win32Exception The operation completed successfully

Tags:

c#

printing

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()
  • the account has permissions to print using the network printer. The permissions are set for Everyone to print.
  • the printer has been deleted and recreated.
  • the setting for spooling vs printing directly to the printer has been toggled both ways.
  • other printers on the machine work fine
  • other clients on the network and apps on this same machine can print to this printer without issue.

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.

enter image description here

The resolution to my problem was to uninstall the driver that is causing the issue, and install an older driver.

like image 915
Prithis Avatar asked Sep 09 '09 16:09

Prithis


1 Answers

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.

like image 171
Hans Passant Avatar answered Oct 13 '22 01:10

Hans Passant