Как распечатать файл pcl в С#?

У меня есть файл PCL, который я сгенерировал с помощью "print to file".

Какой лучший способ программно распечатать этот файл на С#.

(Разумеется, принтер, который я печатаю, поддерживает PCL).

Я знаю, что из приглашения я могу печатать, вызывая:

copy filename.pcl //location/printername

Итак, я бы предположил, что я тоже мог бы сделать то же самое программно (используя копию). Интересно, есть ли более чистый способ сделать это, скажем, используя PrintDocument.

Обратите внимание, что когда я использую PrintDocument:

var pd = new PrintDocument
         {
             DocumentName = @"filename.pcl";
             PrinterSettings = {PrinterName = @"\\location\printername"}
         };


pd.Print();

Я всегда печатаю пустую страницу.

Ответ 1

Эта статья относится к Visual Basic, но достаточно легко следовать, чтобы иметь возможность применить ее к С#, я думаю. В противном случае я с радостью помогу вам с любыми проблемными частями.

Если принтер находится в сети, вот немного забавный пример того, как говорить прямо с ним. Не уверен, что он также работает, если вы просто отправляете байты PCL на принтер.

Ответ 2

Мы используем следующие методы для импорта DLL:

    [DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);

    [DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool ClosePrinter(IntPtr hPrinter);

    [DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] RawPrinter di);

    [DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool EndDocPrinter(IntPtr hPrinter);

    [DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool StartPagePrinter(IntPtr hPrinter);

    [DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool EndPagePrinter(IntPtr hPrinter);

    [DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);

Ответ 3

Мне жаль, что я так поздно пришел к этому вопросу, но у меня есть код, который будет выполнять эту работу. Сначала это не было написано мной. Я получил код с другого сайта помощи программиста, но я не помню, какой из них. Он работает красиво. Вот проект, который создает dll. Для этого выберите "Создать":/Project/Class Library (выберите Visual С# в рамках типов проектов).

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;

namespace PrintRaw
{
   public class RawFilePrint
   {
      // Structure and API declarions:
      [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
      public class DOCINFOA
      {
         [MarshalAs(UnmanagedType.LPStr)]
         public string pDocName;
         [MarshalAs(UnmanagedType.LPStr)]
         public string pOutputFile;
         [MarshalAs(UnmanagedType.LPStr)]
         public string pDataType;
      }
      [DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
      public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);

      [DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
      public static extern bool ClosePrinter(IntPtr hPrinter);

      [DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
      public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);

      [DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
      public static extern bool EndDocPrinter(IntPtr hPrinter);

      [DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
      public static extern bool StartPagePrinter(IntPtr hPrinter);

      [DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
      public static extern bool EndPagePrinter(IntPtr hPrinter);

      [DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
      public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);

      // SendBytesToPrinter()
      // When the function is given a printer name and an unmanaged array
      // of bytes, the function sends those bytes to the print queue.
      // Returns true on success, false on failure.
      public static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount)
      {
         Int32 dwError = 0, dwWritten = 0;
         IntPtr hPrinter = new IntPtr(0);
         DOCINFOA di = new DOCINFOA();
         bool bSuccess = false; // Assume failure unless you specifically succeed.

         di.pDocName = "RAW Document";
         di.pDataType = "RAW";

         if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero))
         {
            if (StartDocPrinter(hPrinter, 1, di))
            {
               if (StartPagePrinter(hPrinter))
               {
                  bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten);
                  EndPagePrinter(hPrinter);
               }
               EndDocPrinter(hPrinter);
            }
            ClosePrinter(hPrinter);
         }
         if (!bSuccess)
         {
            dwError = Marshal.GetLastWin32Error();
         }
         return bSuccess;
      }

      public static bool SendFileToPrinter(string szPrinterName, string szFileName)
      {
         FileStream fs = new FileStream(szFileName, FileMode.Open);
         BinaryReader br = new BinaryReader(fs);
         Byte[] bytes = new Byte[fs.Length];
         bool bSuccess = false;
         IntPtr pUnmanagedBytes = new IntPtr(0);
         int nLength;

         nLength = Convert.ToInt32(fs.Length);
         bytes = br.ReadBytes(nLength);
         pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength);
         Marshal.Copy(bytes, 0, pUnmanagedBytes, nLength);
         bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, nLength);
         Marshal.FreeCoTaskMem(pUnmanagedBytes);
         return bSuccess;
      }

      public static bool SendStringToPrinter(string szPrinterName, string szString)
      {
         IntPtr pBytes;
         Int32 dwCount;
         dwCount = szString.Length;
         // Assume that the printer is expecting ANSI text, and then convert
         // the string to ANSI text.
         pBytes = Marshal.StringToCoTaskMemAnsi(szString);
         SendBytesToPrinter(szPrinterName, pBytes, dwCount);
         Marshal.FreeCoTaskMem(pBytes);
         return true;
      }
   }
}

Теперь, чтобы использовать этот код, добавьте результирующую dll в качестве ссылки на ваш проект, а затем вызовите функции по мере необходимости. Вот некоторый код, где я его использовал, только сегодня:

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace PclFontTest
{
    class Program
    {
        static void Main(string[] args)
        {

            string szPrinterName = @"\\printserver\LaserJet 2420";

            StreamReader sr = new StreamReader(@"C:\Fonts\US20HP.FNT");
            string line = (char)27 + "*c32545D";
            line += sr.ReadToEnd();
            line += (char)27 + "*c5F";

            PrintRaw.RawFilePrint.SendStringToPrinter(szPrinterName, line);


        }
    }
}

Эта программа считывает шрифт PCL из файла. Он обертывает шрифт кодом, чтобы присвоить ему идентификатор шрифта 32545, а затем вызывает функцию dll SendStringToPrinter.