2008-10-20 36 views
7

Tôi đã được yêu cầu cho một ứng dụng web nội bộ để gửi tài liệu đến máy in một cách minh bạch. Ý tưởng sẽ là người dùng có thể chọn máy in gần nhất của họ và ứng dụng web sẽ gửi lệnh in của họ tới máy in mà họ đã chọn.Gửi tài liệu tới máy in bằng C#

Máy in đầu tiên chúng tôi phải tung ra là Canons, vì vậy câu hỏi của tôi là: Tôi sẽ gửi tài liệu để in toàn bộ mạng tới một Canon cụ thể như thế nào? Các loại Cannon là câu hỏi là một iR5570 và các tài liệu sẽ được nói chủ yếu sẽ là Word và PDF

Tôi hiện đang làm việc theo cách của mình thông qua trang web nhà phát triển độc quyền của IE, nhưng tôi hy vọng ai đó có thể chỉ cho tôi đúng hướng hoặc chỉ cho tôi tại hội đồng bên thứ 3 :)

Trả lời

6

Cụm từ khóa trong câu hỏi đó là 'ứng dụng web'.

Trong ứng dụng web thông thường chỉ sử dụng HTML + Javascript qua HTTP, bạn không thể chỉ cần gửi tài liệu trực tiếp tới máy in. Đó là một trong những lý do khiến trình duyệt web tồn tại và không có chức năng đó, máy in của mọi người sẽ thu thập cùng một loại rác mà một máy fax công cộng thực hiện.

Vì vậy, bạn cần một số loại công việc xung quanh. Một tùy chọn là xây dựng trên một plugin phổ biến, như flash, silverlight, applet java hoặc thậm chí là một cái gì đó như greasemonkey. Một trình cắm thêm khác là một trình cắm thêm tùy chỉnh, như một điều khiển winforms được lưu trữ hoặc tiện ích mở rộng trình duyệt tùy chỉnh.

Bạn rất may mắn, có vẻ như bạn có toàn quyền kiểm soát (hoặc biết) môi trường triển khai và môi trường này nếu khá đồng nhất. Điều này có nghĩa là bạn có tùy chọn bổ sung mà người khác đã bắt đầu khám phá. Nếu bạn có thể cài đặt tất cả các máy in trong môi trường của bạn vào máy chủ web, thì nó khá dễ dàng bằng cách sử dụng các lớp máy in .Net (trong không gian tên System.Drawing.Printing) để liệt kê ra các máy in đó, hoặc hiển thị chúng cho người dùng để họ có thể chọn hoặc giữ một số loại IP tới bảng ánh xạ Máy in, rồi in trực tiếp vào máy in đó từ ứng dụng web của bạn. Lưu ý rằng chương trình này có thể yêu cầu ứng dụng của bạn chạy ở mức độ tin cậy cao hơn so với yêu cầu khác.

Hiện tại, thực tế bạn đang in tài liệu PDF và tài liệu từ của mình. Đối với acrobat, hãy kiểm tra liên kết này:
http://support.adobe.com/devsup/devsup.nsf/docs/52080.htm (máy Wayback)
Lưu ý rằng nó hơi nhỏ, nhưng tôi tin rằng khái niệm vẫn hợp lệ. Bạn sẽ phải thử nghiệm một số để đảm bảo nó hoạt động như mong đợi.

Đối với Word, tôi thường không phải là người hâm mộ của Office interop/automation trong ứng dụng web. Nhưng trong trường hợp này bạn không chỉnh sửa bất kỳ tài liệu nào: chỉ cần tải nó lên đủ lâu để in. Và thực tế là bạn đang dựa vào một tài nguyên khan hiếm khác (các máy in) nên giữ điều này khỏi việc mở rộng quy mô vượt ra ngoài những gì máy chủ web của bạn có thể đối phó. Vì vậy, bạn có thể có một trường hợp hiếm hoi khi tự động hóa Office trong một dự án web có ý nghĩa.

+0

Tôi có toàn quyền kiểm soát môi trường triển khai, đó là ứng dụng mạng nội bộ nội bộ. Văn phòng interop/autmation là khủng khiếp, và trong khi các tài liệu được tạo ra bởi C#, chúng tôi sử dụng Aspose.Words. Tôi có thể chấp nhận bằng cách sử dụng interop.automation cho in ấn, sẽ cung cấp cho nó một thử. –

+1

Nếu bạn đã có Aspose, bạn có thể kiểm tra xem nó có hỗ trợ in hay không. –

+0

Nhưng chắc chắn đồng ý rằng trong 99% các trường hợp interop văn phòng là khủng khiếp. –

1

Các tài liệu PrintDocument chứa một ví dụ chi tiết in ấn từ C#. Tên máy in phải trỏ đến máy in cục bộ hoặc chia sẻ máy in. Xem printing-to-a-pdf-printer-programatically để in tài liệu PDF.

+0

điều này chỉ hoạt động với tệp txt? –

+0

Ví dụ đầu tiên chứng minh tài liệu văn bản (dòng), nhưng lớp PrintDocument sử dụng đối tượng Đồ họa để vẽ. Nó có nghĩa là bạn có thể sử dụng sức mạnh của System.Drawing (GDI +) không gian tên. – gimel

+0

ah Tôi thấy .. nhưng tôi đoán định dạng sở hữu (như MS Word) không được hỗ trợ sử dụng lớp này? –

1

Điều gì đó phải dịch tài liệu Word và PDF của bạn thành thứ gì đó mà máy in hiểu được. Thông thường đây sẽ là chính Word cho cái cũ, và một số loại trình xem PDF cho cái sau. Những chương trình đó sau đó cần phải được hướng dẫn trên máy in để gửi đầu ra.

Một cách có thể thực hiện là lưu tài liệu dưới dạng tệp Postscript. Sau đó, chúng có thể được gửi đến máy in có khả năng Postscript trực tiếp từ ứng dụng C#. Đó có lẽ là cách dễ nhất để làm điều đó.

6

Nhiều máy in và thiết bị đa chức năng hiện nay hỗ trợ việc in tệp PDF trực tiếp, điều này có thể giải quyết một trong những vấn đề của bạn. Chỉ cần gửi PDF tới máy in. Trong thực tế, một số thậm chí hỗ trợ việc gửi một URL và máy in sau đó sẽ đi lấy tài liệu và in nó. Lexmark chắc chắn làm điều này và tôi nghĩ rằng một vài nhà cung cấp khác làm là tốt. Điều này vẫn có nghĩa là bạn phải đối phó với tài liệu Word. Word 2007 hỗ trợ PDF (với add-in installed from Microsoft) và tôi đã sử dụng chức năng này theo chương trình với thành công lớn trong C#.

Dưới đây là đoạn code cho rằng:

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

Cuối cùng, nếu điện thoại của bạn không hỗ trợ in ấn PDF sau đó bạn có thể sử dụng Ghostscript hoặc các công cụ khác để chuyển đổi PDF sang PS hoặc thậm chí PCL. Không phải là lớn nhất vì điều này có nghĩa là chạy một mã không được quản lý hoặc trường hợp xấu nhất, bắn phá và thực thi dòng lệnh GS, điều đó đang được nói, chúng tôi hiện đang làm điều này trong một trong các ứng dụng web của chúng tôi và nó hoạt động tốt. Như một sang một bên, chúng tôi không làm điều đó cho in ấn mà là sự tham gia của một số PDF togheter, nhưng cuối cùng nó sẽ làm việc như nhau.

-1

Mã này hoạt động hoàn hảo Nó sử dụng Adobe reader bản thân để in

gợi ý để sử dụng 1- đừng quên để cung cấp đường dẫn cài đặt của riêng bạn để adobe reader tên máy in 2- Nhận từ Properties của máy in bạn muốn in với

sử dụng lớp như thế này:

PdfFilePrinter p = new PdfFilePrinter(); 

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

và lớp là:

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

'Mã này hoạt động hoàn hảo' - hơi overoptimistic – jwg

+0

Tôi khá chắc chắn công việc của nó, bạn có thể liên hệ để giúp các vấn đề thay vì -1 –

Các vấn đề liên quan