Printing an external PDF document in VB.net

50,492

Solution 1

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..

Solution 2

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

http://www.lvbprint.de/html/gsbatchprint1.html

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.

Solution 3

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
Share:
50,492
Wakka02
Author by

Wakka02

Updated on September 18, 2020

Comments

  • Wakka02
    Wakka02 almost 4 years

    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?

    • Steve
      Steve over 9 years
      This happens because your default printer is the Foxit Reader PDF printer that doesn't print anything but creates a PDF file. Try to set as default a real printer.
  • Maiken Roskilde
    Maiken Roskilde over 8 years
    The code is its current form does not work unfortunately.