8

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

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

我目前正在通过糟糕的、仅限 IE 的佳能开发者网站工作,但我有点希望有人能指出我正确的方向或将我指向第 3 方集会:)

4

7 回答 7

6

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

在仅通过 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.

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.Printing namespace) 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.

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.

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.

于 2008-10-20T14:40:55.063 回答
6

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

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.

于 2008-10-21T13:10:23.063 回答
1

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

于 2008-10-20T14:21:19.520 回答
1

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

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

于 2008-10-20T14:23:04.087 回答
1

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

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

于 2008-10-20T14:39:58.920 回答
0

如果有问题的文档类型是 Windows 已知的(DOC 和 PDF 应该是),你可以使用 windows 动词来做到这一点吗?

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

于 2008-10-20T14:16:52.430 回答
-1

This code works perfectly It uses Adobe reader itself to print

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

use the class like this:

PdfFilePrinter p = new PdfFilePrinter();

p.PdfFileName = @"c:\1.pdf";
p.Print();
p.PdfFileName = @"c:\2.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;
}
于 2012-07-04T09:09:43.503 回答