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

时间:2008-10-20 14:05:36

标签: c# printing

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

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

我目前正在通过可怕的IE浏览器佳能开发者网站工作,但我有点希望有人可以指出我正确的方向或指向我参加第三方聚会:)

7 个答案:

答案 0 :(得分:6)

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

在仅使用HTML + Javascript over HTTP的普通网络应用中,无法直接将文档发送到打印机。这就是网络浏览器存在的原因之一,如果没有这种功能,每个人的打印机都会收集与公共传真机相同的垃圾。

所以你需要某种解决方法。一种选择是建立一个通用的插件,如flash,silverlight,java applet,甚至像greasemonkey。另一种是自定义插件,如托管的winforms控件或自定义浏览器扩展。

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

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

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

答案 1 :(得分:6)

如今许多打印机和多功能设备都支持直接打印PDF,这可能会解决您的一个问题。只需将PDF发送到打印机即可。实际上,有些人甚至支持发送URL,然后打印机将获取文档并打印出来。 Lexmark肯定会这样做,我认为其他一些供应商也会这样做。这仍然意味着你必须处理Word文档。 Word 2007支持PDF(使用add-in installed from Microsoft)并且我已经以编程方式使用此函数,并在C#中取得了巨大成功。

以下是代码:

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);

最后,如果您的设备不支持PDF打印,那么您可以使用Ghostscript或其他工具将您的PDF转换为PS甚至PCL。不是最大的,因为这意味着运行一些非托管代码或最坏的情况,炮轰并执行GS命令行,也就是说,我们目前在我们的一个Web应用程序中执行此操作并且运行良好。顺便说一句,我们不是为了打印而是为了加入一些PDF文件,但最终它的工作原理是相同的。

答案 2 :(得分:1)

PrintDocument文档包含从 C#打印的详细示例。打印机名称应指向本地打印机或打印机共享。有关打印PDF文档的信息,请参阅printing-to-a-pdf-printer-programatically

答案 3 :(得分:1)

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

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

答案 4 :(得分:1)

检查sql报告服务的功能可能值5分钟。我过去曾用过它来直接渲染pdf。

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

答案 5 :(得分:0)

如果窗口已知有问题的文档类型(应该是DOC和PDF),您可以使用Windows动词来执行此操作吗?

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

答案 6 :(得分:-1)

此代码完美无缺 它使用Adobe阅读器本身打印

提示使用 1-不要忘记为adobe reader提供自己的安装路径 2-使用

从要打印的打印机属性中获取打印机名称

使用这样的类:

PdfFilePrinter p = new PdfFilePrinter();

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

,班级是:

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;
}