Отправить документ на принтер с C # - PullRequest
8 голосов
/ 20 октября 2008

Мне было задано требование для внутреннего веб-приложения прозрачно отправлять документы на принтер. Идея заключается в том, что пользователь может выбрать ближайший принтер, а веб-приложение отправит свои задания на печать на выбранный принтер.

Первым принтером, с которым нам приходится сталкиваться, являются Canons, поэтому мои вопросы таковы: как мне поступить, чтобы отправить документ для печати по сети определенному Canon? Тип Cannon - это вопрос iR5570, и в основном будут представлены документы Word и PDF

В настоящее время я пробираюсь через ужасный, только для IE, сайт разработчика Canon, но я надеюсь, что кто-то может указать мне правильное направление или указать на стороннюю сборку

Ответы [ 7 ]

6 голосов
/ 21 октября 2008

Многие принтеры и многофункциональные устройства сегодня поддерживают печать PDF-файлов напрямую, это может решить одну из ваших проблем. Просто отправьте PDF на принтер. Фактически, некоторые даже поддерживают отправку URL-адреса, и принтер затем отправляется за документом и распечатывает его. Lexmark наверняка делает это, и я думаю, что некоторые другие поставщики делают то же самое. Это все еще означает, что вы должны иметь дело с документом Word. Word 2007 поддерживает PDF (с установленной надстройкой от 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, что, как говорится, в настоящее время мы делаем это в одном из наших веб-приложений, и это работает хорошо. Кроме того, мы делаем это не для печати, а скорее для объединения нескольких PDF-файлов, но в итоге все будет работать одинаково.

6 голосов
/ 20 октября 2008

Ключевая фраза в этом вопросе - «веб-приложение».

В обычном веб-приложении, использующем только HTML + Javascript через HTTP, вы не можете просто отправить документ непосредственно на принтер. Это одна из причин, по которой существуют веб-браузеры, и без этой функции все принтеры собирали бы тот же мусор, что и общедоступный факсимильный аппарат.

Так что вам нужен какой-то обходной путь. Один из вариантов - использовать общий плагин, такой как flash, silverlight, java-апплет или даже что-то вроде greasemonkey. Другой - пользовательский плагин, такой как размещенный элемент управления winforms или пользовательское расширение браузера.

Вам очень повезло, так как похоже, что вы полностью контролируете (или знаете) среду развертывания, и что эта среда достаточно однородна. Это означает, что у вас есть дополнительная опция, которую другие начали изучать. Если вы можете установить все принтеры в вашей среде на веб-сервер, то довольно просто использовать встроенные классы принтеров .Net (в пространстве имен System.Drawing.Printing), чтобы вывести список этих принтеров, либо показать их пользователю, так что они могут выбрать или сохранить какую-то таблицу сопоставления IP-адресов с принтером, а затем распечатать их непосредственно на этот принтер из вашего веб-приложения. Обратите внимание, что эта схема может требовать, чтобы ваше приложение работало с более высоким уровнем доверия, чем требовалось бы в противном случае.

Теперь речь идет о фактической печати документов PDF и Word. Для акробата, проверьте эту ссылку:
http://support.adobe.com/devsup/devsup.nsf/docs/52080.htm (Wayback machine)
Обратите внимание, что это немного устарело, но я считаю, что концепция все еще в силе. Вам придется поэкспериментировать с некоторыми, чтобы убедиться, что все работает так, как ожидалось.

Для Word я обычно не фанат взаимодействия / автоматизации Office в веб-приложении. Но в этом случае вы не редактируете какие-либо документы: просто загружаете их достаточно долго для печати. И тот факт, что вы полагаетесь на другой дефицитный ресурс (принтеры), не позволит масштабировать его за пределы того, с чем ваш веб-сервер мог бы справиться. Таким образом, у вас может быть редкий случай, когда автоматизация Office в веб-проекте имеет смысл.

1 голос
/ 20 октября 2008

Проверка возможностей службы отчетов sql может стоить 5 минут. Я использовал его в прошлом, чтобы сделать PDF прямо для печати. ​​

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

1 голос
/ 20 октября 2008

Что-то должно преобразовать ваши документы Word и PDF в то, что принтер понимает. Обычно это был бы сам Word для первого и какой-то просмотрщик PDF для второго. Затем эти программы необходимо указать, на какой принтер отправлять вывод.

Один из возможных способов - сохранить документы в виде файлов Postscript. Затем они могут быть отправлены на принтер с поддержкой Postscript непосредственно из приложения C #. Это, наверное, самый простой способ сделать это.

1 голос
/ 20 октября 2008

Документация PrintDocument содержит подробный пример печати с C # . Имя принтера должно указывать на локальный принтер или общий ресурс принтера. Подробнее о печати документов в формате PDF см. печать на принтер в формате pdf .

0 голосов
/ 04 июля 2012

Этот код отлично работает Он использует Adobe Reader для печати

Советы по использованию 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;
}
0 голосов
/ 20 октября 2008

Если типы документов, о которых идет речь, известны окнам (как должно быть в DOC и PDF), можете ли вы использовать глаголы окон для этого?

Пример Codeproject PDF: автоматическое преобразование PDF с использованием бесплатных принтеров PDF995 и FreePDF_XP MSDN: глаголы и ассоциации файлов

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...