How to Silently Print PDFs using Adobe Reader and C#






4.72/5 (12 votes)
Silently print PDFs.
Introduction
This tip is merely to show a way in which you can launch Adobe and send a PDF straight to the printer in one fail swoop without using a third party solution (PdfSharp/iTextSharp...etc...).
Background
After reviewing some of Adobe's documentation on command line switches, I was able to throw together a bit of code that would send a PDF straight to the printer without any user interaction. Attempting to send a post script straight to the printer can get nasty/complicated so this is meant to be an easy solution on how to take a newly created PDF/existing PDF from your app and send it directly to the printer.
- http://partners.adobe.com/public/developer/en/acrobat/sdk/pdf/intro_to_sdk/DeveloperFAQ.pdf
- http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/pdf_open_parameters.pdf
The Code Explained
The code below is used in a console application. I know it could be easily incorporated into any GUI based desktop application as well.
Usage
- Print all PDFs from a defined directory:
- Simply print the PDF file:
string[] files = Directory.GetFiles(@"c:\temp");
foreach (string file in files.Where(file => file.ToUpper().Contains(".PDF")))
{
Pdf.PrintPDFs(file);
}
Pdf.PrintPDFs(filename);
Explained:
I am going to make an assumption that the basics of using the Process
class are understood.
//Define location of adobe reader/command line switches to launch adobe in "print" mode
proc.StartInfo.FileName = @"C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe";
proc.StartInfo.Arguments = String.Format(@"/p /h {0}", pdfFileName);
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.FileName
proc.StartInfo.Arguments
- /p <filename> => means open and go straight to print dialog
- /h => open adobe reader as a minimized window
KillAdobe("AcroRd32");
The value should be the absolute path to your Adobe Reader instance (should work with Acrobat as well). As far as I can tell in my research, most of the current versions of Adobe Reader should support the command line switches
These are your command line switches to be applied to Adobe Reader:
Occasionally in my usage of this code, Adobe Reader likes to stick around for whatever reason. I guess it appears proc.Close()
does not have any affect on the reader, my thinking is that this is due to it trying to close in the middle of printing a file...however my brute force way to make sure the reader doesn't linger is to kill it.
So you grab all the processes that start with your process name (in our case AcroRdr32
) and call the .Kill
method for the process.
foreach (Process clsProcess in Process.GetProcesses().Where(
clsProcess => clsProcess.ProcessName.StartsWith(name)))
{
clsProcess.Kill();
return true;
}
Code in its Entirety
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PdfPrinter
{
class Program
{
static void Main(string[] args)
{
string[] files = Directory.GetFiles(@"c:\temp");
foreach (string file in files.Where(
file => file.ToUpper().Contains(".PDF")))
{
Pdf.PrintPDFs(file);
}
}
}//END Class
public class Pdf
{
public static Boolean PrintPDFs(string pdfFileName)
{
try
{
Process proc = new Process();
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
proc.StartInfo.Verb = "print";
//Define location of adobe reader/command line
//switches to launch adobe in "print" mode
proc.StartInfo.FileName =
@"C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe";
proc.StartInfo.Arguments = String.Format(@"/p /h {0}", pdfFileName);
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.Start();
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
if (proc.HasExited == false)
{
proc.WaitForExit(10000);
}
proc.EnableRaisingEvents = true;
proc.Close();
KillAdobe("AcroRd32");
return true;
}
catch
{
return false;
}
}
//For whatever reason, sometimes adobe likes to be a stage 5 clinger.
//So here we kill it with fire.
private static bool KillAdobe(string name)
{
foreach (Process clsProcess in Process.GetProcesses().Where(
clsProcess => clsProcess.ProcessName.StartsWith(name)))
{
clsProcess.Kill();
return true;
}
return false;
}
}//END Class
}//END Namespace
Points of Interest
This is my first article/tip on CodeProject so I appreciate any feedback on how to improve this.
History
- 05/27/2013 - Published article.
- 05/27/2013 - Fixed minor code sample issue.