使用 C# 将文档发送到打印机

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/218556/
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-08-03 18:36:34  来源:igfitidea点击:

Send document to printer with C#

c#printing

提问by Chris Canal

I've been given a requirement for an internal web application to send documents to a printer transparently. The idea would be that the user can select their nearest printer, and the web application would send their print jobs to the printer they selected.

我被要求使用内部 Web 应用程序透明地将文档发送到打印机。这个想法是用户可以选择离他们最近的打印机,Web 应用程序会将他们的打印作业发送到他们选择的打印机。

The first printer we have to roll out against are Canons, so my questions is: How would I go about sending a document to print aross the network to a specific Canon? The type of Cannon is question is an iR5570 and the documents that will be said will mainly be Word and PDFs

我们必须推出的第一台打印机是佳能,所以我的问题是:我将如何将要在网络上打印的文档发送到特定的佳能?Cannon 的类型是 iR5570,将要说的文档主要是 Word 和 PDF

I'm currently working my way through the terrible, IE only Canon Developer site, but I'm kinda hoping someone can point me in the right direction or point me at a 3rd party assembly :)

我目前正在通过可怕的,只有 IE 的佳能开发者网站,但我有点希望有人能指出我正确的方向或将我指向第 3 方大会:)

采纳答案by Joel Coehoorn

The key phrase in that question is 'web application'.

该问题的关键短语是“网络应用程序”。

In a normal web app using only HTML+Javascript over HTTP, you can'tjust send a document directly to a printer. That's one of the reasons web browsers exist, and without that functionality everyone's printer would collect the same kind of junk that a public fax machine does.

在仅通过 HTTP 使用 HTML+Javascript 的普通 Web 应用程序中,您不能直接将文档发送到打印机。这就是 Web 浏览器存在的原因之一,如果没有该功能,每个人的打印机都会像公共传真机一样收集相同类型的垃圾。

So you need some kind of work-around. One option is to build on a common plug-in, like flash, silverlight, java applet, or even something like greasemonkey. Another is a custom plug-in, like a hosted winforms control or custom browser extension.

所以你需要一些变通办法。一种选择是建立在一个通用插件上,比如 flash、silverlight、java 小程序,甚至是像greasemonkey 之类的东西。另一个是自定义插件,如托管的 winforms 控件或自定义浏览器扩展。

You are very fortunate, in that it looks like you have complete control (or knowlege of) the deployment environment, and that this environment if fairly homogenous. This means you have an additional option that others have started to explore. If you can install all of the printers in your environment to the web server, then it's fairly easy using the built-in .Net printer classes (in the System.Drawing.Printingnamespace) to list out those printer, either show them to the user so they can pick or keep some kind of IP to Printer mapping table, and then print directly to that printer from your web app. Note that this scheme may require your app to run at a higher level of trust than would otherwise be required.

您很幸运,因为您似乎完全控制(或了解)部署环境,而且该环境相当同类。这意味着您有其他人已经开始探索的附加选项。如果您可以将环境中的所有打印机安装到 Web 服务器,那么使用内置的 .Net 打印机类(在System.Drawing.Printing命名空间中)列出这些打印机是相当容易的,或者将它们显示给用户以便他们可以选择或保留某种 IP 到打印机的映射表,然后从您的 Web 应用程序直接打印到该打印机。请注意,此方案可能需要您的应用程序以比其他方式所需的更高的信任级别运行。

Now it comes to actually printing your PDF's and word documents. For acrobat, check this link:
http://support.adobe.com/devsup/devsup.nsf/docs/52080.htm(Wayback machine)
Note that it's a little dated, but I believe the concept is still valid. You'll have to experiment some to make sure it works as expected.

现在开始实际打印您的 PDF 和 Word 文档。对于 acrobat,请查看此链接:
http: //support.adobe.com/devsup/devsup.nsf/docs/52080.htm(Wayback 机器)
请注意,它有点过时了,但我相信这个概念仍然有效。您必须进行一些试验以确保它按预期工作。

For Word, I'm not normally a fan of Office interop/automation in a web app. But in this case you're not editing any documents: just loading it up long enough to print. And the fact that you're relying on another scarce resource (the printers) should keep this from scaling beyond what your web server could cope with. So you may have a rare case where Office automation in a web project makes sense.

对于 Word,我通常不喜欢 Web 应用程序中的 Office 互操作/自动化。但在这种情况下,您没有编辑任何文档:只需加载足够长的时间即可打印。并且您依赖另一种稀缺资源(打印机)的事实应该防止其扩展到超出您的 Web 服务器可以处理的范围。因此,您可能会遇到 Web 项目中的 Office 自动化有意义的罕见情况。

回答by Craig.Nicol

If the document types in question are known to windows (as DOC and PDF should be), can you use the windows verbs to do it?

如果所讨论的文档类型是 windows 已知的(如 DOC 和 PDF 应该是),您可以使用 windows 动词来做到这一点吗?

Codeproject PDF example : Automated PDF Conversion using the PDF995 and FreePDF_XP Freeware PrintersMSDN : Verbs and File Associations

Codeproject PDF 示例:使用 PDF995 和 FreePDF_XP 免费软件打印机进行自动 PDF 转换MSDN:动词和文件关联

回答by gimel

The PrintDocumentdocumentation contains a detailed example of printing from C#. The printer name should point to a local printer or a printer share. See printing-to-a-pdf-printer-programaticallyfor printing PDF docs.

所述的PrintDocument文档包含从印刷的详细示例C# 。打印机名称应指向本地打印机或打印机共享。请参阅以编程方式打印到 pdf 打印机以打印 PDF 文档。

回答by Jeffrey L Whitledge

Something has to translate your Word and PDF documents into something that the printer understands. Normally this would be Word itself for the former, and some kind of PDF viewer for the latter. Those programs then need to be instructed on which printer to send the output to.

必须将您的 Word 和 PDF 文档翻译成打印机可以理解的内容。通常,前者是 Word 本身,后者是某种 PDF 查看器。然后需要指示这些程序将输出发送到哪台打印机。

One possible way to go would be to save the documents as Postscript files. Then they could be sent to a Postscript capable printer directly from a C# application. That would probably be the easiest way to do it.

一种可能的方法是将文档保存为 Postscript 文件。然后它们可以直接从 C# 应用程序发送到支持 Postscript 的打印机。这可能是最简单的方法。

回答by MBoy

It might be worth 5 minutes to check through the capabilities of sql reporting service. I have used it in the past to render pdf straight to print.

检查 sql 报告服务的功能可能值得 5 分钟。我过去曾用它来将 pdf 直接打印出来。

http://blogs.msdn.com/bryanke/articles/71491.aspx

http://blogs.msdn.com/bryanke/articles/71491.aspx

回答by Douglas Anderson

Many printers and multifunction devices today support the printing of PDFs directly, this may solve one of your problems. Simply have the PDF sent to the printer. In fact, some even support the sending of a URL and the printer will then go get the document and print it. Lexmark for sure does this and I think a few other vendors do as well. This still mean you have to deal with the Word document. Word 2007 supports PDF (with the add-in installed from Microsoft) and I've used this function programatically with great success in C#.

今天许多打印机和多功能设备都支持直接打印 PDF,这可能会解决您的问题之一。只需将 PDF 发送到打印机即可。事实上,有些甚至支持发送一个 URL,然后打印机会去获取文档并打印它。利盟肯定会这样做,我认为其他一些供应商也这样做。这仍然意味着您必须处理 Word 文档。Word 2007 支持 PDF(带有从 Microsoft 安装加载项),我在 C# 中以编程方式使用此功能并取得了巨大成功。

Here's the code for that:

这是代码:

Microsoft.Office.Interop.Word.ApplicationClass msWord = new Microsoft.Office.Interop.Word.ApplicationClass();

object paramUnknown = Type.Missing;
object missing = Type.Missing;
object paramSaveChangesNo = Microsoft.Office.Interop.Word.WdSaveOptions.wdDoNotSaveChanges;
//object paramFonts = Microsoft.Office.Interop.Word.wde
object paramFormatPDF = Microsoft.Office.Interop.Word.WdSaveFormat.wdFormatPDF;
object paramTrue = true;
object paramReadOnly = true;  
object sourceDoc = @"c:\input.doc"                              
object target = @"c:\output.pdf";

msWord.Visible = false;

//open .doc
msWord.Documents.Open(ref sourceDoc, ref paramUnknown, ref paramReadOnly, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown);

//so it won't show on the taskbar
msWord.Application.Visible = false;
msWord.WindowState = Microsoft.Office.Interop.Word.WdWindowState.wdWindowStateMinimize;

//save .doc to new target name and format
msWord.ActiveDocument.SaveAs(ref targetDoc, ref paramFormatPDF, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramTrue, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown, ref paramUnknown);

msWord.ActiveDocument.Close(ref missing, ref missing, ref missing);

msWord.Quit(ref paramSaveChangesNo, ref paramUnknown, ref paramUnknown);

Lastly, if your device doesn't support PDF printing then you could use Ghostscript or other tools to convert your PDF to PS or even PCL. Not the greatest as this mean running a little unmanaged code or worst case, shelling out and executing the GS command line, that being said, we currently do this in one of our web apps and it works well. As an aside, we don't do it for print but rather the joining of a number of PDFs togheter, but in the end it will work the same.

最后,如果您的设备不支持 PDF 打印,那么您可以使用 Ghostscript 或其他工具将您的 PDF 转换为 PS 甚至 PCL。不是最好的,因为这意味着运行一些非托管代码,或者在最坏的情况下,退出并执行 GS 命令行,话虽如此,我们目前在我们的一个 Web 应用程序中执行此操作,并且运行良好。顺便说一句,我们不是为了打印而这样做,而是为了将许多 PDF 合并在一起,但最终它的工作方式是一样的。

回答by masoud Cheragee

This code works perfectly It uses Adobe reader itself to print

此代码完美运行它使用 Adob​​e Reader 本身进行打印

Hints to use 1- don't forget to provide your own install path to adobe reader 2- Get printer name from Properties of the Printer you want to print with

使用提示 1- 不要忘记提供您自己的 adobe reader 安装路径 2- 从要打印的打印机的属性中获取打印机名称

use the class like this:

像这样使用这个类:

PdfFilePrinter p = new PdfFilePrinter();

p.PdfFileName = @"c:.pdf";
p.Print();
p.PdfFileName = @"c:.pdf";
p.Print();

and the class is :

课程是:

public class PdfFilePrinter
{
    /// <summary>
    /// Initializes a new instance of the <see cref="PdfFilePrinter"/> class.
    /// </summary>
    public PdfFilePrinter()
    {
        adobeReaderPath = @"C:\Program Files\Adobe\Reader 9.0\Reader\AcroRd32.exe";
        printerName = "HP LaserJet P2055 Series PCL6";
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="PdfFilePrinter"/> class.
    /// </summary>
    /// <param name="pdfFileName">Name of the PDF file.</param>
    public PdfFilePrinter(string pdfFileName)
    {
        this.PdfFileName = pdfFileName;
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="PdfFilePrinter"/> class.
    /// </summary>
    /// <param name="pdfFileName">Name of the PDF file.</param>
    /// <param name="printerName">Name of the printer.</param>
    public PdfFilePrinter(string pdfFileName, string printerName)
    {
        this.pdfFileName = pdfFileName;
        this.printerName = printerName;
    }

    /// <summary>
    /// Gets or sets the name of the PDF file to print.
    /// </summary>
    public string PdfFileName
    {
        get { return this.pdfFileName; }
        set { this.pdfFileName = value; }
    }
    string pdfFileName;

    /// <summary>
    /// Gets or sets the name of the printer. A typical name looks like '\myserver\HP LaserJet PCL5'.
    /// </summary>
    /// <value>The name of the printer.</value>
    public string PrinterName
    {
        get { return this.printerName; }
        set { this.printerName = value; }
    }
    string printerName;

    /// <summary>
    /// Gets or sets the working directory.
    /// </summary>
    public string WorkingDirectory
    {
        get { return this.workingDirectory; }
        set { this.workingDirectory = value; }
    }
    string workingDirectory;

    /// <summary>
    /// Prints the PDF file.
    /// </summary>
    public void Print()
    {
        Print(-1);
    }

    /// <summary>
    /// Prints the PDF file.
    /// </summary>
    /// <param name="milliseconds">The number of milliseconds to wait for completing the print job.</param>
    public void Print(int milliseconds)
    {
        if (this.printerName == null || this.printerName.Length == 0)
            this.printerName = PdfFilePrinter.defaultPrinterName;

        if (PdfFilePrinter.adobeReaderPath == null || PdfFilePrinter.adobeReaderPath.Length == 0)
            throw new InvalidOperationException("No full qualified path to AcroRd32.exe or Acrobat.exe is set.");

        if (this.printerName == null || this.printerName.Length == 0)
            throw new InvalidOperationException("No printer name set.");

        // Check whether file exists.
        string fqName = String.Empty;
        if (this.workingDirectory != null && this.workingDirectory.Length != 0)
            fqName = Path.Combine(this.workingDirectory, this.pdfFileName);
        else
            fqName = Path.Combine(Directory.GetCurrentDirectory(), this.pdfFileName);
        if (!File.Exists(fqName))
            throw new InvalidOperationException(String.Format("The file {0} does not exist.", fqName));

        // TODO: Check whether printer exists.

        try
        {
            DoSomeVeryDirtyHacksToMakeItWork();

            //acrord32.exe /t          <- seems to work best
            //acrord32.exe /h /p       <- some swear by this version
            ProcessStartInfo startInfo = new ProcessStartInfo();
            startInfo.FileName = PdfFilePrinter.adobeReaderPath;
            string args = String.Format("/t \"{0}\" \"{1}\"", this.pdfFileName, this.printerName);
            //Debug.WriteLine(args);
            startInfo.Arguments = args;
            startInfo.CreateNoWindow = true;
            startInfo.ErrorDialog = false;
            startInfo.UseShellExecute = false;
            if (this.workingDirectory != null && this.workingDirectory.Length != 0)
                startInfo.WorkingDirectory = this.workingDirectory;

            Process process = Process.Start(startInfo);
            if (!process.WaitForExit(milliseconds))
            {
                // Kill Adobe Reader/Acrobat
                process.Kill();
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    /// <summary>
    /// For reasons only Adobe knows the Reader seams to open and shows the document instead of printing it
    /// when it was not already running.
    /// If you use PDFsharp and have any suggestions to circumvent this function, please let us know.
    /// </summary>
    void DoSomeVeryDirtyHacksToMakeItWork()
    {
        if (PdfFilePrinter.runningAcro != null)
        {
            if (!PdfFilePrinter.runningAcro.HasExited)
                return;
            PdfFilePrinter.runningAcro.Dispose();
            PdfFilePrinter.runningAcro = null;
        }
        // Is any Adobe Reader/Acrobat running?
        Process[] processes = Process.GetProcesses();
        int count = processes.Length;
        for (int idx = 0; idx < count; idx++)
        {
            try
            {
                Process process = processes[idx];
                ProcessModule module = process.MainModule;

                if (String.Compare(Path.GetFileName(module.FileName), Path.GetFileName(PdfFilePrinter.adobeReaderPath), true) == 0)
                {
                    // Yes: Fine, we can print.
                    PdfFilePrinter.runningAcro = process;
                    break;
                }
            }
            catch { }
        }
        if (PdfFilePrinter.runningAcro == null)
        {
            // No: Start an Adobe Reader/Acrobat.
            // If you are within ASP.NET, good luck...
            PdfFilePrinter.runningAcro = Process.Start(PdfFilePrinter.adobeReaderPath);
            PdfFilePrinter.runningAcro.WaitForInputIdle();
        }
    }
    static Process runningAcro;

    /// <summary>
    /// Gets or sets the Adobe Reader or Adobe Acrobat path.
    /// A typical name looks like 'C:\Program Files\Adobe\Adobe Reader 7.0\AcroRd32.exe'.
    /// </summary>
    static public string AdobeReaderPath
    {
        get { return PdfFilePrinter.adobeReaderPath; }
        set { PdfFilePrinter.adobeReaderPath = value; }
    }
    static string adobeReaderPath;

    /// <summary>
    /// Gets or sets the name of the default printer. A typical name looks like '\myserver\HP LaserJet PCL5'.
    /// </summary>
    static public string DefaultPrinterName
    {
        get { return PdfFilePrinter.defaultPrinterName; }
        set { PdfFilePrinter.defaultPrinterName = value; }
    }
    static string defaultPrinterName;
}