Printing an external PDF document in VB.net

I know this question has been asked before, but my situation is a bit wonky.

Basically, I'm trying to print a PDF file that I've generated using a previous Windows Form. I can find the file no problem, and I used the following code which I found off MSDN's help forums:

Dim p As New System.Diagnostics.ProcessStartInfo()
p.Verb = "print"
p.WindowStyle = ProcessWindowStyle.Hidden
p.FileName = "C:\534679.pdf" 'This is the file name
p.UseShellExecute = True
System.Diagnostics.Process.Start(p)

So far so good, but everytime I press the button to run this code, it keeps asking me to save it as a PDF file instead, as shown below:

enter image description here

I've also tried adding a PrintDialog to the Windows Form, getting it to pop up, and I can select the printer I want to use from there, but even after selecting the printer it still asks me to print to PDF Document instead.

What am I doing wrong?

1

4 Answers

First, to be able to select a Printer, you'll have to use a PrintDialog and PrintDocument to send graphics to print to the selected printer.

Imports System.Drawing.Printing Private WithEvents p_Document As PrintDocument = Nothing Private Sub SelectPrinterThenPrint() Dim PrintersDialog As New PrintDialog() If PrintersDialog.ShowDialog(Me) = System.Windows.Forms.DialogResult.OK Then Try p_Document = New PrintDocument() PrintersDialog.Document = p_Document AddHandler p_Document.PrintPage, AddressOf HandleOnPrintPage Catch CurrentException As Exception End Try End If End Sub Private Sub HandleOnPrintPage(ByVal sender As Object, ByVal e As PrintPageEventArgs) Handles p_Document.PrintPage Dim MorePagesPending As Boolean = False 'e.Graphics.Draw...(....) 'e.Graphics.DrawString(....) ' Draw everything... If MorePagesPending Then e.HasMorePages = True Else e.HasMorePages = False End If End Sub

That's what I'm doing since I usually have custom objects to print.


But to print PDF Files, you must understand that PDF means absolutely nothing to dotNet. Unlike common images like Bitmaps (.bmp) or Ping images (.png) the dotNet doesn't seem to have any inbuilt parser/decoder for reading, displaying and printing PDF files.

So you must use a third party application, thrid party library or your own custom PDF parser/layout generator in order to be able to send pages to print to your printer.

That's why you can't launch a hidden (not visible) process of Acrobat Reader with the command "print". You won't be able to select a printer but will direct to the default one instead !

You can however launch the Acrobat Reader process just to open the file, and do the printing manipulations (select a printer) inside Acrobat Reader (you're outside dotNet coding now)


A workaround for your may aslo to select another default printer by opening Acrobat Reader, and print one blank page on an actual working printer. This should deselect your FoxIt thing in favour of an actual printer..

To print massive PDF documents with VB.Net you can use LVBPrint and run it via command line:

For Example:

C:\temp\gsbatchprint64\gsbatchprintc.exe -P \\server\printer -N A3 -O Port -F C:\temp\gsbatchprint64\Test*.pdf -I Tray3

I use the following function in my application:

 ' print a pdf with lvbrint Private Function UseLvbPrint(ByVal oPrinter As tb_Printer, fileName As String, portrait As Boolean, sTray As String) As String Dim lvbArguments As String Dim lvbProcessInfo As ProcessStartInfo Dim lvbProcess As Process Try Dim sPrinterName As String If portrait Then lvbArguments = String.Format(" -P ""{0}"" -O Port -N A4 -F ""{1}"" -I ""{2}"" ", sPrinterName, fileName, sTray) Else lvbArguments = String.Format(" -P ""{0}"" -O Land -N A4 -F ""{1}"" -I ""{2}"" ", sPrinterName, fileName, sTray) End If lvbProcessInfo = New ProcessStartInfo() lvbProcessInfo.WindowStyle = ProcessWindowStyle.Hidden ' location of gsbatchprintc.exe lvbProcessInfo.FileName = LvbLocation lvbProcessInfo.Arguments = lvbArguments lvbProcessInfo.UseShellExecute = False lvbProcessInfo.RedirectStandardOutput = True lvbProcessInfo.RedirectStandardError = True lvbProcessInfo.CreateNoWindow = False lvbProcess = Process.Start(lvbProcessInfo) ' ' Read in all the text from the process with the StreamReader. ' Using reader As StreamReader = lvbProcess.StandardOutput Dim result As String = reader.ReadToEnd() WriteLog(result) End Using Using readerErr As StreamReader = lvbProcess.StandardError Dim resultErr As String = readerErr.ReadToEnd() If resultErr.Trim() > "" Then WriteLog(resultErr) lvbProcess.Close() Return resultErr End If End Using If lvbProcess.HasExited = False Then lvbProcess.WaitForExit(3000) End If lvbProcess.Close() Return "" Catch ex As Exception Return ex.Message End Try End Function

I discourage on using AcrRd32.exe as it doesn't work with massive printings.

0

This code will help you to print in a specific printer.

The sample print a file using a ProcessStartInfo and a specific printer you can change the printer to use in the process.

If the print process is not finished after 10 seconds we kill the print process.

'Declare a printerSettings
Dim defaultPrinterSetting As System.Drawing.Printing.PrinterSettings = Nothing
Private Sub cmdPrint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdPrint.Click Try dim fileName As String = "C:\534679.pdf" 'Get de the default printer in the system defaultPrinterSetting = DocumentPrinter.GetDefaultPrinterSetting 'uncomment if you want to change the default printer before print 'DocumentPrinter.ChangePrinterSettings(defaultPrinterSetting) 'print your file If PrintFile(fileName, defaultPrinterSetting) then msgbox ("your print file success message") else msgbox ("your print file failed message") end if Catch ex As Exception mssbox(ex.Message.toString) End Try
End Sub
Public NotInheritable Class DocumentPrinter Shared Sub New() End Sub Public Shared Function PrintFile(ByVal fileName As String, printerSetting As System.Drawing.Printing.PrinterSettings) As Boolean Dim printProcess As System.Diagnostics.Process = Nothing Dim printed As Boolean = False Try If PrinterSetting IsNot Nothing Then Dim startInfo As New ProcessStartInfo() startInfo.Verb = "Print" startInfo.Arguments = defaultPrinterSetting.PrinterName ' <----printer to use---- startInfo.FileName = fileName startInfo.UseShellExecute = True startInfo.CreateNoWindow = True startInfo.WindowStyle = ProcessWindowStyle.Hidden Using print As System.Diagnostics.Process = Process.Start(startInfo) 'Close the application after X milliseconds with WaitForExit(X) print.WaitForExit(10000) If print.HasExited = False Then If print.CloseMainWindow() Then printed = True Else printed = True End If Else printed = True End If print.Close() End Using Else Throw New Exception("Printers not found in the system...") End If Catch ex As Exception Throw End Try Return printed End Function ''' <summary> ''' Change the default printer using a print dialog Box ''' </summary> ''' <param name="defaultPrinterSetting"></param> ''' <remarks></remarks> Public Shared Sub ChangePrinterSettings(ByRef defaultPrinterSetting As System.Drawing.Printing.PrinterSettings) Dim printDialogBox As New PrintDialog If printDialogBox.ShowDialog = Windows.Forms.DialogResult.OK Then If printDialogBox.PrinterSettings.IsValid Then defaultPrinterSetting = printDialogBox.PrinterSettings End If End If End Sub ''' <summary> ''' Get the default printer settings in the system ''' </summary> ''' <returns></returns> ''' <remarks></remarks> Public Shared Function GetDefaultPrinterSetting() As System.Drawing.Printing.PrinterSettings Dim defaultPrinterSetting As System.Drawing.Printing.PrinterSettings = Nothing For Each printer As String In System.Drawing.Printing.PrinterSettings.InstalledPrinters defaultPrinterSetting = New System.Drawing.Printing.PrinterSettings defaultPrinterSetting.PrinterName = printer If defaultPrinterSetting.IsDefaultPrinter Then Return defaultPrinterSetting End If Next Return defaultPrinterSetting End Function
End Class
1

I used this code to print my PDF files on VB NET:

 Dim PrintPDF As New ProcessStartInfo PrintPDF.UseShellExecute = True PrintPDF.Verb = "print" PrintPDF.WindowStyle = ProcessWindowStyle.Hidden PrintPDF.FileName = dirName & fileName 'fileName is a string parameter Process.Start(PrintPDF)

When you do this, process remains open with a adobe reader window that users have to close manually. I wanted to avoid user's interaction, just want them to get their documents. So, I added a few code lines to kill process:

 Private Sub killProcess(ByVal processName As String) Dim procesos As Process() procesos = Process.GetProcessesByName(processName) 'I used "AcroRd32" as parameter If procesos.Length > 0 Then For i = procesos.Length - 1 To 0 Step -1 procesos(i).Kill() Next End If End Sub

If you put the kill process method right after the print method you won't get your document printed (I guess this is because process is killed before it is sent to printer). So, between these 2 methods, I added this line:

 Threading.Thread.Sleep(10000) ' 10000 is the milisecs after the next code line is executed

And with this my code worked as I wanted. Hope it helps you!

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like