在 VB.net 中打印外部 PDF 文档

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26970825/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 21:05:25  来源:igfitidea点击:

Printing an external PDF document in VB.net

vb.netprinting

提问by Wakka02

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:

基本上,我正在尝试打印使用以前的 Windows 窗体生成的 PDF 文件。我可以找到文件没问题,我使用了以下代码,我在 MSDN 的帮助论坛上找到了:

Dim p As New System.Diagnostics.ProcessStartInfo()
p.Verb = "print"
p.WindowStyle = ProcessWindowStyle.Hidden
p.FileName = "C:4679.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:

到目前为止一切顺利,但每次我按下按钮运行此代码时,它一直要求我将其另存为 PDF 文件,如下所示:

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.

我还尝试将 PrintDialog 添加到 Windows 窗体,让它弹出,我可以从那里选择我想要使用的打印机,但即使在选择打印机后,它仍然要求我打印到 PDF 文档。

What am I doing wrong?

我究竟做错了什么?

采纳答案by Karl Stephen

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

首先,为了能够选择打印机,您必须使用PrintDialogPrintDocument将要打印的图形发送到选定的打印机。

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

但是要打印 PDF 文件,您必须了解 PDF对 dotNet毫无意义。与位图 (.bmp) 或 Ping 图像 (.png) 等常见图像不同,dotNet 似乎没有任何用于读取、显示和打印 PDF 文件的内置解析器/解码器。

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

因此,您必须使用第三方应用程序、第三方或您自己的自定义 PDF 解析器/布局生成器才能将页面发送到您的打印机进行打印。

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 !

这就是您无法使用“打印”命令启动 Acrobat Reader 隐藏(不可见)进程的原因。您将无法选择打印机,而是直接选择默认打印机!

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)

但是,您可以启动Acrobat Reader软件过程只需打开该文件,然后执行打印操作(选择打印机)的Acrobat Reader里面(你在室外的dotNet现在编码)



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

您也可以通过打开 Acrobat Reader 来选择另一台默认打印机,然后在actual working printer. 这应该取消选择您的 FoxIt 东西,转而使用实际的打印机。

回答by depoip

To print massive PDFdocuments with VB.Netyou can use LVBPrintand run it via command line:

要打印大量PDF文档,VB.Net您可以LVBPrint通过command line以下方式使用和运行它:

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

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

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.exeas it doesn't work with massive printings.

我不鼓励使用,AcrRd32.exe因为它不适用于大量打印。

回答by Harval

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.

该示例使用 ProcessStartInfo 和特定打印机打印文件,您可以更改该打印机以在该过程中使用。

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

如果打印过程在 10 秒后仍未完成,我们将终止打印过程。

'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:4679.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

回答by Brenda Montiel

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

我使用此代码在 VB NET 上打印我的 PDF 文件:

    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:

执行此操作时,进程将保持打开状态,并显示一个 adobe 阅读器窗口,用户必须手动关闭该窗口。我想避免用户的交互,只想让他们得到他们的文件。所以,我添加了几行代码来终止进程:

    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:

如果您将 kill process 方法放在 print 方法之后,您将无法打印文档(我猜这是因为进程在发送到打印机之前被终止了)。所以,在这两种方法之间,我添加了这一行:

   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!

有了这个,我的代码可以按我的意愿工作。希望对你有帮助!