3

Let's say I have a .NET-based Windows application without a GUI (e.g., a Windows service, a console application or a web service), and I need to print something (e.g., an automatically created invoice) on a physical printer.

Which classes of the BCL would I use? This is what I have found so far:

  • System.Drawing.Printing.PrintDocument Class: The documentation explicitly mentions that this is for printing in Windows Forms applications. In particular, it mentions that WPF applications should use classes from the System.Printing namespace instead.
  • System.Printing Namespace: The documentation explicitly mentions that these classes are "...not supported for use within a Windows service or ASP.NET application or service."

So, what should I use to print from non-GUI applications? (And why in the world are the printing classes "tied" to the UI framework anyway?)

Heinzi
  • 167,459
  • 57
  • 363
  • 519
  • I guess they both rely on the UI libraries for rendering and layout. Many of the objects used to build a print document are the same as those use to display stuff on the screen. (and ASP doesn't render anything, it leaves that to the browser) – Robin Bennett Sep 12 '19 at 15:21

1 Answers1

1

It should work just fine from a console app. But yeah, Windows service or ASP.NET aren't so easy.

There are some suggestions here, but not easy ones (like using P/Invoke to use the C++ libraries to print, which was my first idea). You might be able to find people who have already done that if you search.

This answer recommends a third-party product: DevExpress' XtraReports.

There is also this guy on Reddit that described how he solved this exact thing. You could send him a message on Reddit and see if you can get his code somehow.

This example uses Microsoft.Office.Interop.Word to print Word documents from a Windows service. Seems "hacky", but I don't see why it wouldn't work:

public class WordPrintTask  
{  
 private static object locker = new Object();  
 public WordPrintTask() { }  
 public void PrintWord()  
 {  
   try  
   {  
     // Kill opened word instances.  
     if (KillProcess("WINWORD"))  
     {  
       // Thread safe.  
       lock (locker)  
       {  
         string fileName = "D:\\PrinterDocs\\TEST.docx";  
         string printerName = "\\\\10.0.0.89\\PRINTER1020";  
         if (File.Exists(fileName))  
         {  
           Application _application = new Application();  
           _application.Application.ActivePrinter = printerName;  
           object oSourceFilePath = (object)fileName;  
           object docType = WdDocumentType.wdTypeDocument;  
           object oFalse = (object)false;  
           object oMissing = System.Reflection.Missing.Value;  
           Document _document = _application.Documents.Open(ref oSourceFilePath,  
                              ref docType,  
                              ref oMissing,  
                              ref oMissing,  
                              ref oMissing,  
                              ref oMissing,  
                              ref oMissing,  
                              ref oMissing,  
                              ref oMissing,  
                              ref oMissing,  
                              ref oMissing,  
                              ref oMissing,  
                              ref oMissing,  
                              ref oMissing,  
                              ref oMissing,  
                              ref oMissing);  
           // Print  
           _application.PrintOut(ref oFalse, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing,  
                             ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing,  
                             ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing);  
           object saveOptions = WdSaveOptions.wdDoNotSaveChanges;  
           _document.Close(ref oFalse, ref oMissing, ref oMissing);  
           if (_application != null)  
           {  
             object oSave = false;  
             Object oMiss = System.Reflection.Missing.Value;  
             _application.Quit(ref oSave, ref oMiss, ref oMissing);  
             _application = null;  
           }  
           // Delete the file once it is printed  
           File.Delete(fileName);  
         }  
       }  
     }  
   }  
   catch (Exception ex)  
   {  
     KillProcess("WINWORD");  
   }  
   finally  
   {  
   }  
 }  
 private static bool KillProcess(string name)  
 {  
   foreach (Process clsProcess in Process.GetProcesses().Where(p => p.ProcessName.Contains(name)))  
   {  
     if (Process.GetCurrentProcess().Id == clsProcess.Id)  
       continue;  
     if (clsProcess.ProcessName.Contains(name))  
     {  
       clsProcess.Kill();  
       return true;  
     }  
   }  
   return true;  
 }  
}
Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84
  • Wow, didn't think it would be *that* complicated. BTW, [automating Office from unattended code isn't supported either](https://stackoverflow.com/a/8709255/87698), so the MS Word option is not valid. – Heinzi Sep 16 '19 at 09:30