2008-10-20 150 views
7

Me han dado un requisito para que una aplicación web interna envíe documentos a una impresora de forma transparente. La idea sería que el usuario pueda seleccionar su impresora más cercana y la aplicación web envíe sus trabajos de impresión a la impresora que seleccionó.Enviar documento a la impresora con C#

La primera impresora con la que tenemos que luchar son los cánones, por lo que mi pregunta es: ¿cómo podría enviar un documento para imprimir la red a una Canon específica? El tipo de Cannon es una pregunta es un iR5570 y los documentos que se dirán principalmente serán Word y PDF

Actualmente estoy trabajando en mi camino a través del terrible, IE único sitio de Desarrollador de Canon, pero estoy esperando que alguien puede señalarme en la dirección correcta o señalarme en una asamblea de terceros :)

Respuesta

6

La frase clave en esa pregunta es 'aplicación web'.

En una aplicación web normal que solo utiliza HTML + Javascript a través de HTTP, no puede simplemente envíe un documento directamente a una impresora. Esa es una de las razones por las que existen navegadores web, y sin esa funcionalidad, la impresora de todo el mundo recolectaría el mismo tipo de basura que una máquina de fax pública.

Así que necesitas algún tipo de solución alternativa. Una opción es crear un complemento común, como flash, silverlight, java applet o incluso algo así como greasemonkey. Otro es un complemento personalizado, como un control de formas de pago alojadas o una extensión de navegador personalizada.

Usted es muy afortunado, ya que parece que tiene control total (o conocimiento) del entorno de despliegue, y que este entorno es bastante homogéneo. Esto significa que tiene una opción adicional que otros han comenzado a explorar. Si puede instalar todas las impresoras de su entorno en el servidor web, entonces es bastante fácil utilizar las clases de impresora .Net integradas (en el espacio de nombres System.Drawing.Printing) para enumerar esas impresoras, o bien muéstreselos al usuario para que puedan elija o guarde algún tipo de tabla de asignación de IP a Impresora, y luego imprima directamente en esa impresora desde su aplicación web. Tenga en cuenta que este esquema puede requerir que su aplicación se ejecute a un nivel más alto de confianza de lo que se requeriría de otra manera.

Ahora se trata realmente de imprimir sus documentos PDF y de Word. Para acrobat, consulte este enlace:
http://support.adobe.com/devsup/devsup.nsf/docs/52080.htm (Wayback machine)
Tenga en cuenta que está un poco anticuado, pero creo que el concepto sigue siendo válido. Tendrás que experimentar algunos para asegurarte de que funciona como se espera.

Para Word, normalmente no soy seguidor de Office interop/automation en una aplicación web. Pero en este caso no está editando ningún documento: simplemente lo cargue el tiempo suficiente para imprimir. Y el hecho de que confíe en otro recurso escaso (las impresoras) debería evitar que esto vaya más allá de lo que podría soportar su servidor web. Por lo tanto, es posible que tenga un caso raro en el que la automatización de Office en un proyecto web tenga sentido.

+0

Tengo control total del entorno de implementación, es una aplicación de intranet interna. Office interop/autmation es horrible, y mientras los documentos son generados por C#, usamos Aspose.Words. Puedo aceptar el uso de interop.automation para imprimir, intentarlo. –

+1

Si ya tiene Aspose, entonces puede verificar si es compatible con la impresión. –

+0

Pero definitivamente estoy de acuerdo en que en el 99% de los casos la interoperabilidad de la oficina es horrible. –

1

La documentación PrintDocument contiene un ejemplo detallado de la impresión desde C#. El nombre de la impresora debe apuntar a una impresora local o a un recurso compartido de impresora. Consulte printing-to-a-pdf-printer-programatically para imprimir documentos PDF.

+0

¿Esto solo funciona con el archivo txt? –

+0

El primer ejemplo muestra un documento de texto (líneas), pero la clase PrintDocument usa un objeto Graphics para dibujar. Significa que puede usar la potencia de espacios de nombres System.Drawing (GDI +). – gimel

+0

ah, ya veo ... pero supongo que el formato propietario (como MS Word) no es compatible con esta clase. –

1

Algo tiene que traducir sus documentos de Word y PDF en algo que la impresora entienda. Normalmente, esto sería Word para el primero y algún tipo de visor de PDF para este último. Esos programas necesitan ser instruidos sobre a qué impresora enviar la salida.

Una manera posible de hacerlo es guardar los documentos como archivos Postscript. Luego, podrían enviarse a una impresora con capacidad Postscript directamente desde una aplicación C#. Esa sería probablemente la forma más fácil de hacerlo.

6

Muchas impresoras y dispositivos multifuncionales admiten actualmente la impresión de archivos PDF directamente, esto puede resolver uno de sus problemas. Simplemente envíe el PDF a la impresora. De hecho, algunos incluso admiten el envío de una URL y la impresora irá a obtener el documento e imprimirlo. Lexmark seguramente hace esto y creo que algunos otros proveedores también lo hacen. Esto todavía significa que tiene que tratar con el documento de Word. Word 2007 es compatible con PDF (con add-in installed from Microsoft) y he utilizado esta función de forma programática con gran éxito en C#.

Aquí está el código para que:

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

Por último, si el dispositivo no admite la impresión PDF entonces usted podría utilizar Ghostscript u otras herramientas para convertir su PDF a PS o incluso PCL. No es el mejor ya que esto significa ejecutar un pequeño código no administrado o el peor de los casos, bombardear y ejecutar la línea de comandos GS, dicho esto, actualmente hacemos esto en una de nuestras aplicaciones web y funciona bien. Por otro lado, no lo hacemos para imprimir sino para unir varios archivos PDF, pero al final funcionará de la misma manera.

-1

Este código funciona perfectamente Utiliza Adobe propio lector para imprimir

Consejos para usar 1- no se olvide de proporcionar su propia ruta de instalación de Adobe Reader 2- Obtener nombre de la impresora Propiedades de la impresora que desea imprimir con

uso de la clase como esta:

PdfFilePrinter p = new PdfFilePrinter(); 

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

y la clase es:

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

'Este código funciona perfectamente' - ligeramente Omproptimista – jwg

+0

Estoy bastante seguro de que está trabajando se puede contactar para ayudar en el asunto en lugar de -1 –

Cuestiones relacionadas