By Only Bolivian Here


2011-05-23 22:22:56 8 Comments

Here's the basic premise:

My user clicks some gizmos and a PDF file is spit out to his desktop. Is there some way for me to send this file to the printer queue and have it print to the locally connected printer?

string filePath = "filepathisalreadysethere";
SendToPrinter(filePath); //Something like this?

He will do this process many times. For each student in a classroom he has to print a small report card. So I generate a PDF for each student, and I'd like to automate the printing process instead of having the user generated pdf, print, generate pdf, print, generate pdf, print.

Any suggestions on how to approach this? I'm running on Windows XP with Windows Forms .NET 4.

I've found this StackOverflow question where the accepted answer suggests:

Once you have created your files, you can print them via a command line (you can using the Command class found in the System.Diagnostics namespace for that)

How would I accomplish this?

11 comments

@Casper Kjær 2018-04-26 13:03:07

The following code snippet is an adaptation of Kendall Bennett's code for printing pdf files using the PdfiumViewer library. The main difference is that a Stream is used rather than a file.

public bool PrintPDF(
    string printer,
    string paperName,
    int copies, Stream stream)
        {
            try
            {
                // Create the printer settings for our printer
                var printerSettings = new PrinterSettings
                {
                    PrinterName = printer,
                    Copies = (short)copies,
                };

            // Create our page settings for the paper size selected
            var pageSettings = new PageSettings(printerSettings)
            {
                Margins = new Margins(0, 0, 0, 0),
            };
            foreach (PaperSize paperSize in printerSettings.PaperSizes)
            {
                if (paperSize.PaperName == paperName)
                {
                    pageSettings.PaperSize = paperSize;
                    break;
                }
            }

            // Now print the PDF document
            using (var document = PdfiumViewer.PdfDocument.Load(stream))
            {
                using (var printDocument = document.CreatePrintDocument())
                {
                    printDocument.PrinterSettings = printerSettings;
                    printDocument.DefaultPageSettings = pageSettings;
                    printDocument.PrintController = new StandardPrintController();
                    printDocument.Print();
                }
            }
            return true;
        }
        catch (System.Exception e)
        {
            return false;
        }
    }

In my case I am generating the PDF file using a library called PdfSharp and then saving the document to a Stream like so:

        PdfDocument pdf = PdfGenerator.GeneratePdf(printRequest.html, PageSize.A4);
        pdf.AddPage();

        MemoryStream stream = new MemoryStream();
        pdf.Save(stream);
        MemoryStream stream2 = new MemoryStream(stream.ToArray());

One thing that I want to point out that might be helpful to other developers is that I had to install the 32 bit version of the pdfuim native dll in order for the printing to work even though I am running Windows 10 64 bit. I installed the following two NuGet packages using the NuGet package manager in Visual Studio:

  • PdfiumViewer
  • PdfiumViewer.Native.x86.v8-xfa

@bdwakefield 2018-08-06 19:00:24

This was a solid answer; and it resolved an issue we were having.

@stomy 2018-09-05 22:14:48

You can use the DevExpress PdfDocumentProcessor.Print(PdfPrinterSettings) Method.

public void Print(string pdfFilePath)
{
      if (!File.Exists(pdfFilePath))
          throw new FileNotFoundException("No such file exists!", pdfFilePath);

      // Create a Pdf Document Processor instance and load a PDF into it.
      PdfDocumentProcessor documentProcessor = new PdfDocumentProcessor();
      documentProcessor.LoadDocument(pdfFilePath);

      if (documentProcessor != null)
      {
          PrinterSettings settings = new PrinterSettings();

          //var paperSizes = settings.PaperSizes.Cast<PaperSize>().ToList();
          //PaperSize sizeCustom = paperSizes.FirstOrDefault<PaperSize>(size => size.Kind == PaperKind.Custom); // finding paper size

          settings.DefaultPageSettings.PaperSize = new PaperSize("Label", 400, 600);

          // Print pdf
          documentProcessor.Print(settings);
      }
}

@iato 2016-06-01 14:06:54

I know Edwin answered it above but his only prints one document. I use this code to print all files from a given directory.

public void PrintAllFiles()
{
    System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo();
    info.Verb = "print";
    System.Diagnostics.Process p = new System.Diagnostics.Process();
    //Load Files in Selected Folder
    string[] allFiles = System.IO.Directory.GetFiles(Directory);
    foreach (string file in allFiles)
    {
        info.FileName = @file;
        info.CreateNoWindow = true;
        info.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
         p.StartInfo = info;
        p.Start();
    }
    //p.Kill(); Can Create A Kill Statement Here... but I found I don't need one
    MessageBox.Show("Print Complete");
}

It essentually cycles through each file in the given directory variable Directory - > for me it was @"C:\Users\Owner\Documents\SalesVaultTesting\" and prints off those files to your default printer.

@B.K. 2014-12-11 18:01:59

I know the tag says Windows Forms... but, if anyone is interested in a WPF application method, System.Printing works like a charm.

var file = File.ReadAllBytes(pdfFilePath);
var printQueue = LocalPrintServer.GetDefaultPrintQueue();

using (var job = printQueue.AddJob())
using (var stream = job.JobStream)
{
    stream.Write(file, 0, file.Length);
}

Just remember to include System.Printing reference, if it's not already included. Now, this method does not play well with ASP.NET or Windows Service. It should not be used with Windows Forms, as it has System.Drawing.Printing. I don't have a single issue with my PDF printing using the above code.

I should mention, however, that if your printer does not support Direct Print for PDF file format, you're out of luck with this method.

@Jwosty 2015-08-10 14:47:22

This also works in an ordinary console project.

@B.K. 2015-09-25 21:32:26

@Jwosty Good point.

@sohaiby 2017-06-20 09:16:03

I'm trying to print with my HP LaserJet CP1025nw but it's not working. For a moment, it shows the print job in the print queue with status spooling and then it disappears from there with no print happening

@B.K. 2017-06-20 09:48:26

@sohaiby You would have to review your printer's specs to see if it allows for Direct Print for PDF file format. I would also make sure that you have the most current drivers for your operating system.

@stomy 2018-08-30 19:36:37

Didn't work for Brother MFC-7860DW Printer from LINQPad 5

@B.K. 2018-08-31 06:25:27

@stomy It probably doesn't have Direct-PDF / Direct Print for PDF support. Also, if you're trying to print any other file format, your printer must support direct printing for that. This is a simple printing method, but not a silver bullet for sure. When I was using this years ago, it only worked for some of the printers at work.

@Kendall Bennett 2017-01-19 20:34:20

Adding a new answer to this as the question of printing PDF's in .net has been around for a long time and most of the answers pre-date the Google Pdfium library, which now has a .net wrapper. For me I was researching this problem myself and kept coming up blank, trying to do hacky solutions like spawning Acrobat or other PDF readers, or running into commercial libraries that are expensive and have not very compatible licensing terms. But the Google Pdfium library and the PdfiumViewer .net wrapper are Open Source so are a great solution for a lot of developers, myself included. PdfiumViewer is licensed under the Apache 2.0 license.

You can get the NuGet package here:

https://www.nuget.org/packages/PdfiumViewer/

and you can find the source code here:

https://github.com/pvginkel/PdfiumViewer

Here is some simple code that will silently print any number of copies of a PDF file from it's filename. You can load PDF's from a stream also (which is how we normally do it), and you can easily figure that out looking at the code or examples. There is also a WinForm PDF file view so you can also render the PDF files into a view or do print preview on them. For us I simply needed a way to silently print the PDF file to a specific printer on demand.

public bool PrintPDF(
    string printer,
    string paperName,
    string filename,
    int copies)
{
    try {
        // Create the printer settings for our printer
        var printerSettings = new PrinterSettings {
            PrinterName = printer,
            Copies = (short)copies,
        };

        // Create our page settings for the paper size selected
        var pageSettings = new PageSettings(printerSettings) {
            Margins = new Margins(0, 0, 0, 0),
        };
        foreach (PaperSize paperSize in printerSettings.PaperSizes) {
            if (paperSize.PaperName == paperName) {
                pageSettings.PaperSize = paperSize;
                break;
            }
        }

        // Now print the PDF document
        using (var document = PdfDocument.Load(filename)) {
            using (var printDocument = document.CreatePrintDocument()) {
                printDocument.PrinterSettings = printerSettings;
                printDocument.DefaultPageSettings = pageSettings;
                printDocument.PrintController = new StandardPrintController();
                printDocument.Print();
            }
        }
        return true;
    } catch {
        return false;
    }
}

@Philip Stratford 2017-01-27 13:54:23

This got me up and running in about 10 minutes.

@Viorel 2017-03-14 09:06:40

Nice solution, thanks! And a very nice Google library, which is also open source, so it may stay around for longer. If anyone is interested in duplex printing, you can easily do this with printerSettings.Duplex = Duplex.Vertical, worked like a charm for us.

@Binod Mahto 2017-04-12 07:07:52

Will this work in IIS environment as well? I have scenario of printing pdf (generated from stream) to network printer through application hosted in IIS. I tried with this code and problem I'm facing is: 1. Document is getting queued to the print job queue with size 0 bytes. 2. Document is getting queued to the print job queue with owner name as machine_name.

@Tez Wingfield 2017-08-16 14:59:00

A little old but I'd like to confirm that running in IIS is fine. I have a Windows Service that polls the physical data(files) abstracts certain information and calls an endpoint on an on-premise MVC5 app, which in turns does the magic...

@TimS 2017-08-17 02:58:38

I installed this library and was literally printing in about 3 minutes.

@Boaz 2018-04-26 13:07:27

Casper's solution tied this answer up for us.

@user1624552 2018-07-06 09:36:37

Where can I download the DLL? i have visual studio 2008, so I cannot use nuget.

@Kendall Bennett 2018-07-08 15:34:15

Nuget packages are just zip files so any zip utility can pull the files out.

@user1624552 2018-07-10 17:30:11

It was working for me! thx! but remember to initialize constructor as document.CreatePrintDocument(PdfPrintMode.ShrinkToMargin)) if you want to avoid left and right margins to be cut off.

@Our Man in Bananas 2015-10-21 13:11:23

this is a late answer, but you could also use the File.Copy method of the System.IO namespace top send a file to the printer:

System.IO.File.Copy(filename, printerName);

This works fine

@Mong Zhu 2016-05-25 14:44:02

Could you elaborate a little? The only thing I get is a file written to the hard disk with the name of printerName...

@Doug Clutter 2017-01-23 23:35:10

For example: File.Copy("myFileToPrint.pdf", "\\myPrintServerName\myPrinterName");

@Atta H. 2018-07-21 19:10:57

I tried that code and it created a copy of the file with name entered into my desktop app's exe folder

@RolandoCC 2014-12-26 15:33:53

The easy way:

var pi=new ProcessStartInfo("C:\file.docx");
pi.UseShellExecute = true;
pi.Verb = "print";
var process =  System.Diagnostics.Process.Start(pi);

@user1027167 2014-09-12 11:09:25

This is a slightly modified solution. The Process will be killed when it was idle for at least 1 second. Maybe you should add a timeof of X seconds and call the function from a separate thread.

private void SendToPrinter()
{
  ProcessStartInfo info = new ProcessStartInfo();
  info.Verb = "print";
  info.FileName = @"c:\output.pdf";
  info.CreateNoWindow = true;
  info.WindowStyle = ProcessWindowStyle.Hidden;

  Process p = new Process();
  p.StartInfo = info;
  p.Start();

  long ticks = -1;
  while (ticks != p.TotalProcessorTime.Ticks)
  {
    ticks = p.TotalProcessorTime.Ticks;
    Thread.Sleep(1000);
  }

  if (false == p.CloseMainWindow())
    p.Kill();
}

@Edwin Groenendaal 2011-05-24 05:40:07

You can tell Acrobat Reader to print the file using (as someone's already mentioned here) the 'print' verb. You will need to close Acrobat Reader programmatically after that, too:

private void SendToPrinter()
{
   ProcessStartInfo info = new ProcessStartInfo();
   info.Verb = "print";
   info.FileName = @"c:\output.pdf";
   info.CreateNoWindow = true;
   info.WindowStyle = ProcessWindowStyle.Hidden;

   Process p = new Process();
   p.StartInfo = info;
   p.Start();

   p.WaitForInputIdle();
   System.Threading.Thread.Sleep(3000);
   if (false == p.CloseMainWindow())
      p.Kill();
}

This opens Acrobat Reader and tells it to send the PDF to the default printer, and then shuts down Acrobat after three seconds.

If you are willing to ship other products with your application then you could use GhostScript (free), or a command-line PDF printer such as http://www.commandlinepdf.com/ (commercial).

Note: the sample code opens the PDF in the application current registered to print PDFs, which is the Adobe Acrobat Reader on most people's machines. However, it is possible that they use a different PDF viewer such as Foxit (http://www.foxitsoftware.com/pdf/reader/). The sample code should still work, though.

@dev 2012-11-06 16:06:07

Why this code is not working on server side ?

@Edwin Groenendaal 2012-11-08 14:35:49

@Mvcdev the code relies on: a) Acrobat (or another reader) being installed on the server, and b) invocation of an interactive application (e.g. Adobe Acrobat), which may not work if the user account your code runs under is not interactive. In that case, a command-line tool is your best bet (www.commandlinepdf.com as mentioned above)

@dev 2012-11-08 16:09:09

Actually it's working but what i did with iis is not good if i publish the web site. This site is only for inside network. there are couple step i did. 1) I changed the Application Pools Asp.NET v4.0 identity to LocalSystem. 2) I applied username and password in <processModel> inside machine.config file. 3) I have changed Registry using this site ( support.microsoft.com/?kbid=184291 ). N it's working fine for me using your code. Please advice me if something is wrong here ?

@Edwin Groenendaal 2012-11-08 16:53:13

@Mvcdev it looks like you have resolved point b) in my above comment, which is you've replaced the identity that the ASP.NET worker process runs under to an interactive account. If you only use the web site internally this is probably not an issue; but if you ever need to publish it, you will need to find another solution.

@dev 2012-11-08 17:22:49

Right now all i know is they want to use internally. n Thanks for your reply.

@user1027167 2014-09-12 11:00:44

WaitForInputIdle() has no effect. It seems that p is in idle-Mode after Start(). Only the sleep for 3 seconds allows Adobe to finish the spooling. This might be a problem for large documents.

@B.K. 2014-11-04 14:29:06

Is there a way to get the status of the job out of this? How can I find out if the documented printed or if there was an error?

@SteveCav 2015-07-30 05:37:03

"Process has exited, so the requested information is not available."

@Mong Zhu 2016-05-30 13:38:02

@user1027167 that is especially a problem if you need to print multiple documents @EdwinGroenendaal How would you proceed if you want to print multiple documents? in the command shell it is possible to write them all after the printername: print /D:printerName file1.pdf file2.pdf file3.pdf

@Peck_conyon 2017-04-10 01:10:00

I get "no application is associated with the specified file for this operation" Error even I have a printer connected

@danyolgiax 2011-05-23 23:00:37

@nikolai.serdiuk 2018-01-17 13:14:01

don't work with xfa pdf

@Neil 2011-05-23 22:29:11

System.Diagnostics.Process.Start can be used to print a document. Set UseShellExecute to True and set the Verb to "print".

@Only Bolivian Here 2011-05-23 22:33:40

Can you elaborate? I can't understand where I should set UseShellExecute to true.

@Tim Destan 2011-05-23 22:59:12

The Process.Start method can take a ProcessStartInfo object as argument, which has these properties.

@Only Bolivian Here 2011-05-23 23:05:12

@Tim Destan: I'm really at a loss here, is this Verb and UseShellExecute actually properties of the ProcessStartInfo class? Do you have some sample code?

@Hans Passant 2011-05-23 23:27:06

It already defaults to true.

Related Questions

Sponsored Content

15 Answered Questions

[SOLVED] How to print to stderr in Python?

14 Answered Questions

[SOLVED] How to flush output of print function?

1 Answered Questions

1 Answered Questions

2 Answered Questions

[SOLVED] How to send multiple files to the printer with one Process call

1 Answered Questions

VB.net - print pdf file with printer with paper size

1 Answered Questions

[SOLVED] Printing a file and configure printer settings

3 Answered Questions

[SOLVED] How to print a pdf in C# by using

2 Answered Questions

[SOLVED] How to Print PDF file without print preview in java

Sponsored Content