Friday, May 9, 2008

How to Print File/String in C# ?

A C# developer often requires developing an application or a feature in a product that will print the documents. Sometimes we require printing a single line using the printer, this situation may arise when we want to print some status on a pre-printed form. Here is a code which will print the file or print a string using the default printer installed on the machine.
Comments are added to each line of code so as to make it easy to understand !

========================CODE============================
#region Reference

using System;
using System.Drawing.Printing;
using System.Runtime.InteropServices;
using System.Diagnostics;
// Add a reference to the System.Management dll.
using System.Management;

#endregion Reference

namespace PrinterHelper
{
/// <summary>
/// Contains common functions for accessing printer
/// </summary>
public class PrinterHelper
{
#region Member Variables & Method Signatures

// String data to be printed.
static string prnData = string.Empty;

//Add the printer connection for specified pName.
[DllImport("winspool.drv")]
public static extern bool AddPrinterConnection(string pName);

//Set the added printer as default printer.
[DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool SetDefaultPrinter(string Name);

#endregion Member Variables & Method Signatures

#region Public Methods
#region Print File
/// <summary>
/// Sends the file to the printer choosed.
/// </summary>
/// <param name="fileName">Name & path of the file to be printed.</param>
/// <param name="printerPath">The path of printer.</param>
/// <param name="numCopies">The number of copies send to printer.</param>
public bool PrintFile(string fileName, string printerPath, int numCopies)
{
// Check if the incomming strings are null or empty.
if (string.IsNullOrEmpty(fileName) string.IsNullOrEmpty(printerPath))
{
return false;
}

//Instantiate the object of ProcessStartInfo.
Process objProcess = new Process();
try
{
// Set the printer.
AddPrinterConnection(printerPath);
SetDefaultPrinter(printerPath);
//Print the file with number of copies sent.
for (int intCount = 0; intCount < numCopies; intCount++)
{
objProcess.StartInfo.FileName = fileName;
objProcess.StartInfo.Verb = "Print";
objProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
objProcess.StartInfo.UseShellExecute = true;
objProcess.Start();
}
// Return true for success.
return true;
}
catch (Exception ex)
{
// Log the exception and return false as failure.
return false;
}
finally
{
// Close the process.
objProcess.Close();
}
}

#endregion Print File

#region SendStringToPrinter

/// <summary>
/// Sends a string to the printer.
/// </summary>
/// <param name="szString">String to be printed.</param>
/// <returns>Returns true on success, false on failure.</returns>
public bool SendStringToPrinter(string szString)
{
try
{
PrintDocument prnDocument;
string printername;
//Get the default printer name.
prnDocument = new PrintDocument();
printername = Convert.ToString(prnDocument.PrinterSettings.PrinterName);
if (string.IsNullOrEmpty(printername))
throw new Exception("No default printer is set.Printing failed!");
prnData = szString;
prnDocument.PrintPage += new PrintPageEventHandler(prnDoc_PrintPage);
prnDocument.Print();
return true;
}
catch (COMException comException)
{
//Log the exception
return false;
}
catch (Exception sysException)
{
//Log the exception
return false;
}
}

/// <summary>
/// Printes the page.
/// </summary>
/// <param name="sender">object : Sender event</param>
/// <param name="e">PrintPageEventArgs</param>
static void prnDoc_PrintPage(object sender, PrintPageEventArgs e)
{
System.Drawing.Font fnt = new System.Drawing.Font(System.Drawing.FontFamily.GenericSerif, 10);
e.Graphics.DrawString(prnData, fnt, System.Drawing.Brushes.Black, 0, 0);
}

#endregion SendStringToPrinter

#endregion Public Methods
}
}
Your comments are always welcome !

25 comments:

Unknown said...

Sandeep:

Thank you for the excellent piece of code. It works but with one hitch.

While trying a print labels in pdf format, it opens a blank Adobe Reader that is unwanted. Is there a way we can avoid it?

Thank you for your help.

Lakshmi Narayanan V.

Sandeep Aparajit said...

We can use the following code to suppress the window. Please try this:
// Do not create the black window.
objProcess.CreateNoWindow = true;

This piece of code should be plugged in the PrintFile() method before the objPorcess.Start().

Thanks for your comments Lakshmi!

Unknown said...

Sandeep:

I tried your suggestion but did not succeed. In order to make it work, I set the properties for the process object as such:

objProcess.WaitForExit(10000);
objProcess.CloseMainWindow();

This did the trick. Also, I modified the PrintFile function to print my pdf to a specific printer without making it a default. My function is attached. It is in C#.

public bool PrintFile1(string fileName, string printerPath)
{
// Check if the incomming strings are null or empty.
if (string.IsNullOrEmpty(fileName) || string.IsNullOrEmpty(printerPath))
{
return false;
}

//Instantiate the object of ProcessStartInfo.
Process objProcess = new Process();

try
{
//the command line to print PDF files without displaying the print dialog
//AcroRd32.exe /t "C:\test.pdf" "\\servername\printername"
ProcessStartInfo starter = new ProcessStartInfo("AcroRd32.exe", "/t \"" + fileName + "\" \"" + printerPath + "\"");

objProcess.StartInfo = starter;
objProcess.Start();

//close Acrobat window
objProcess.WaitForExit(10000);
objProcess.CloseMainWindow();

return true;
}
catch (Exception ex)
{
// Log the exception and return false as failure.
return false;
}
finally
{
// Close the process.
objProcess.Close();
}
}

Anonymous said...

hi
this is really a good code
but i want the functionality like after completing the printing the acrobat reader should be closed.
will this code work for me

ChristineM said...

Hi Sandeep,
The Code did really help...Thanks a lot..
But in my case I am using a Dot Matrix Printer...I need to continuosly print strings one after the other with linefeeds(let us assume a realtime ALARM LOG). On implementing your code I find a formfeed occurs after every single line. Can you please suggest something related to this...

Thanks Anyway buddy...
Regards
Surya

Anonymous said...

Very Nice,
It took a while for me to find this piece of code.
Since I was printing to a file instead of a paper printer I added a delegate to test if the file was printed out then I closed acrobat. Here's what you have to do:

In PrinterHelper Class:
public delegate bool PrintedOutTest();

Add delegate to PrintFile1 declaration:
public bool PrintFile1(string fileName, string printerPath, PrintedOutTest FinishedPrinting)

Add this bit of modified code:
//**************
//close Acrobat window
do
{
objProcess.WaitForExit(1000);
} while (!FinishedPrinting());

// Wait for 5 seconds after file is printed then continue
System.Threading.Thread.Sleep(5000);

objProcess.CloseMainWindow();
******************/

Call PrintFile1 it like this:
// This assumes that you know where and what the "printedfile" is going to printed.
PrintFile1(PrintThisFile, PrinterName, delegate() { return System.IO.File.Exists(printedfile); });

Sandeep Aparajit said...

Good one.. Thx!

Anonymous said...

Nice code!
Btw, in order to avoid popup acrobat window when do printing, to our experience, only adobe reader v7.1 can do it. But you need to make sure the product machine has 7.1 installed as well as your develop machine in the build process before deployement. We also tried a different way, on production machine, install Foxit reader, then associate foxit.exe to your pdf file in print process. This way can also avoid a pop up window.

Anonymous said...

Is there a way to make this work at a website?

Anonymous said...

Make it a webservice

Anonymous said...

thanks yar i'm trying print data froom a file... but not succeeded now i think using this i can do that ...... any way thnks for the help-sandeep{this is my name :-)}

Anonymous said...

can anyone know if i want the status of printer Ex. which file are failed to print..then ho wi will do this...

thanx...

Anonymous said...

this will work for all types of files(txt,doc,pdf)?

Sandeep Aparajit said...

Yes, it will work for all types of files.

Shopathome said...

Hi Sandeep,

I am using the following code for printing pdf file, it give the error:
"No process is associated with this object ".
Please help me to solve this problem

PrintDialog pd = new PrintDialog();
pd.PrinterSettings = new PrinterSettings();
if (DialogResult.OK == pd.ShowDialog(this))
{
//Print the file to the printer.
//PrintDocument pdc;
StringBuilder strPath = new StringBuilder();
strPath = strPath.Append("/t ");
strPath = strPath.Append("\"");
strPath = strPath.Append(strFilePath);
strPath = strPath.Append("\" \"");
strPath = strPath.Append(pd.PrinterSettings.PrinterName);
strPath = strPath.Append("\"");
Process objP = new Process();
objP.StartInfo.FileName = strFilePath; // FileName(.pdf) to print.
objP.StartInfo = new ProcessStartInfo("acrord32.exe", strPath.ToString());
objP.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; //Hide the window.
//!! Since the file name involves a nonexecutable file(.pdf file), including a verb to specify what action to take on the file.
//The action in our case is to "Print" a file in a selected printer.
//!! Print the document in the printer selected in the PrintDialog !!//
objP.StartInfo.Verb = "print";
//objP.StartInfo.Arguments = "";
//objP.StartInfo.Arguments = "/t \"" + strFilePath + "\" \"" + pd.PrinterSettings.PrinterName + " \"";//pd.PrinterSettings.PrinterName;
//objP.StartInfo.UseShellExecute = true;
objP.StartInfo.CreateNoWindow = true;//!! Don't create a Window.
objP.WaitForExit(10000);
objP.Start();//!! Start the process !!//
objP.CloseMainWindow();
}

Thanks
Krishna
krishnareddyganta@yahoo.co.in

Anonymous said...

Hi sandeep,

I am trying to run your code and its giving error. I am new to .NET.

Can you please help me with some example code which u can send to me ?

Thanx
Surya
surya.choudhary@gmail.com

Anonymous said...

Hi Sandeep,

Is it possible to format a string for printing partially bold, partially underline, etc?

Elmar

Lex Li said...

Everyone is warned that the tricks described in this blog mainly apply to client side applications (Console/WinForms/WPF) but can lead to serious problems if used in ASP.NET.

Anonymous said...

Great Job Sandeep! This code really of big help... :)



hootie {:)&

Anonymous said...

Thank you, Sandeep.

siva's blog said...

Hi Sandeep,

First I would like you to thank for this code.

It worked well.

But how to save the page settings with the help of your program.

We have a requirements like firstly it should prompt for the page settings dialog and if the page settings is changed based on the page settings the page should be printed.

For example if I changed the pagesettings orientation to landscape then it should print in landscape.

Anticipating for your reply.

Thanks in advance.

Regards,
Siva

Anonymous said...

in some machines it is not working , any solutions

Anonymous said...

what if i need to send a string to client printer, which is not configured in my machine?

Unknown said...

hi it is not working on server

Anonymous said...

Que buen Aporte amigo. Mil Gracias.

Post a Comment