2010-01-11 3 views
36

Есть ли способ отправить ZPL (язык программирования Zebra) на принтер в .NET?Код .NET для отправки ZPL на принтеры Zebra

У меня есть код для этого в Delphi, но это не очень, и я бы предпочел не пытаться воссоздать его в .NET, как есть.

+3

30 тыс. Просмотров? Люди должны быть похожими на меня и задавались вопросом, что такое ZPL :). – kristianp

+3

@kristianp. Любой, кто когда-либо должен был работать в розничном программном обеспечении, рано или поздно заканчивается в битве с ZPL;) – Vedran

+0

Розничная или промышленная/производственная печать – StingyJack

ответ

11

Посмотрите эту тему: Print ZPL codes to ZEBRA printer using PrintDocument class.

В частности ОП выбрать эту функцию из ответов на резьбу:

[DllImport("kernel32.dll", SetLastError = true)] 
static extern SafeFileHandle CreateFile(string lpFileName, FileAccess dwDesiredAccess, 
uint dwShareMode, IntPtr lpSecurityAttributes, FileMode dwCreationDisposition, 
uint dwFlagsAndAttributes, IntPtr hTemplateFile); 

private void Print() 
{ 
    // Command to be sent to the printer 
    string command = "^XA^FO10,10,^AO,30,20^FDFDTesting^FS^FO10,30^BY3^BCN,100,Y,N,N^FDTesting^FS^XZ"; 

    // Create a buffer with the command 
    Byte[] buffer = new byte[command.Length]; 
    buffer = System.Text.Encoding.ASCII.GetBytes(command); 
    // Use the CreateFile external func to connect to the LPT1 port 
    SafeFileHandle printer = CreateFile("LPT1:", FileAccess.ReadWrite, 0, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero); 
    // Aqui verifico se a impressora é válida 
    if (printer.IsInvalid == true) 
    { 
     return; 
    } 

    // Open the filestream to the lpt1 port and send the command 
    FileStream lpt1 = new FileStream(printer, FileAccess.ReadWrite); 
    lpt1.Write(buffer, 0, buffer.Length); 
    // Close the FileStream connection 
    lpt1.Close(); 

} 
+1

Для поддержки символов «англ. Command» не обязательно должны быть закодированы в UTF16 BE. – Alexufo

+0

Необходимо ли установить драйвер принтера для этого метода? –

9

Я руководил проектом, который делает это с сокетами в течение многих лет. Обычно Zebra использует порт 6101. Я просмотрю код и опубликую, что смогу.

public void SendData(string zpl) 
{ 
    NetworkStream ns = null; 
    Socket socket = null; 

    try 
    { 
     if (printerIP == null) 
     { 
      /* IP is a string property for the printer's IP address. */ 
      /* 6101 is the common port of all our Zebra printers. */ 
      printerIP = new IPEndPoint(IPAddress.Parse(IP), 6101); 
     } 

     socket = new Socket(AddressFamily.InterNetwork, 
      SocketType.Stream, 
      ProtocolType.Tcp); 
     socket.Connect(printerIP); 

     ns = new NetworkStream(socket); 

     byte[] toSend = Encoding.ASCII.GetBytes(zpl); 
     ns.Write(toSend, 0, toSend.Length); 
    } 
    finally 
    { 
     if (ns != null) 
      ns.Close(); 

     if (socket != null && socket.Connected) 
      socket.Close(); 
    } 
} 
+4

Принтеры Zebra Mobile используют порт 6101 (QL, RW, MZ и т. Д.). Большие принтеры обычно используют порт 9100. –

+1

Я использовал этот код в простом консольном приложении для печати на Zebra LP 2844 Z. Мне пришлось изменить порт на 9100. – Monroecheeseman

6

Фигурные, так как это все еще показывает высоко в результатах поиска для C# и ZPL я должен упомянуть SharpZebra. Это только EPL2, но я представил update, который добавляет поддержку ZPL, а также печать через сокеты, службу Windows Spool и прямой USB.

2

VB версии (с использованием порта 9100 - проверено на Zebra ZM400)

Sub PrintZPL(ByVal pIP As String, ByVal psZPL As String) 
    Dim lAddress As Net.IPEndPoint 
    Dim lSocket As System.Net.Sockets.Socket = Nothing 
    Dim lNetStream As System.Net.Sockets.NetworkStream = Nothing 
    Dim lBytes As Byte() 

    Try 
     lAddress = New Net.IPEndPoint(Net.IPAddress.Parse(pIP), 9100) 
     lSocket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, _      ProtocolType.Tcp) 
     lSocket.Connect(lAddress) 
     lNetStream = New NetworkStream(lSocket) 

     lBytes = System.Text.Encoding.ASCII.GetBytes(psZPL) 
     lNetStream.Write(lBytes, 0, lBytes.Length) 
    Catch ex As Exception When Not App.Debugging 
     Msgbox ex.message & vbnewline & ex.tostring 
    Finally 
     If Not lNetStream Is Nothing Then 
      lNetStream.Close() 
     End If 
     If Not lSocket Is Nothing Then 
      lSocket.Close() 
     End If 
    End Try 
End Sub 
0

Я использую комбо этих двух

Private Sub sendData(ByVal zpl As String) 
    Dim ns As System.Net.Sockets.NetworkStream = Nothing 
    Dim socket As System.Net.Sockets.Socket = Nothing 
    Dim printerIP As Net.IPEndPoint = Nothing 
    Dim toSend As Byte() 

    Try 
     If printerIP Is Nothing Then 
      'set the IP address 
      printerIP = New Net.IPEndPoint(IPAddress.Parse(IP_ADDRESS), 9100) 
     End If 

     'Create a TCP socket 
     socket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) 
     'Connect to the printer based on the IP address 
     socket.Connect(printerIP) 
     'create a new network stream based on the socket connection 
     ns = New NetworkStream(socket) 

     'convert the zpl command to a byte array 
     toSend = System.Text.Encoding.ASCII.GetBytes(zpl) 

     'send the zpl byte array over the networkstream to the connected printer 
     ns.Write(toSend, 0, toSend.Length) 

    Catch ex As Exception 
     MessageBox.Show(ex.Message, "Cable Printer", MessageBoxButtons.OKCancel, MessageBoxIcon.Error) 
    Finally 
     'close the networkstream and then the socket 
     If Not ns Is Nothing Then 
      ns.Close() 
     End If 

     If Not socket Is Nothing Then 
      socket.Close() 
     End If 
    End Try 
End Sub 


Private Function createString() As String 
    Dim command As String 

    command = "^XA" 
    command += "^LH20,25" 

    If rdoSmall.Checked = True Then 
     command += "^FO1,30^A0,N,25,25^FD" 
    ElseIf rdoNormal.Checked = True Then 
     command += "^FO1,30^A0,N,35,35^FD" 
    Else 
     command += "^FO1,30^A0,N,50,50^FD" 
    End If 

    command += txtInput.Text 
    command += "^FS" 
    command += "^XZ" 

    Return command 

End Function 
32

Таким образом, вы будете иметь возможность отправлять ZPL к принтеру нет независимо от того, как он подключен (LPT, USB, Network Share ...)

Создать класс RawPrinterHelper (из статьи Microsoft на How to send raw data to a printer by using Visual C# .NET):

using System; 
using System.Drawing; 
using System.Drawing.Printing; 
using System.Windows.Forms; 
using System.Runtime.InteropServices; 

public class RawPrinterHelper 
{ 
    // 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 = "My C#.NET RAW Document"; 
     di.pDataType = "RAW"; 

     // Open the printer. 
     if(OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero)) 
     { 
      // Start a document. 
      if(StartDocPrinter(hPrinter, 1, di)) 
      { 
       // Start a page. 
       if(StartPagePrinter(hPrinter)) 
       { 
        // Write your bytes. 
        bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten); 
        EndPagePrinter(hPrinter); 
       } 
       EndDocPrinter(hPrinter); 
      } 
      ClosePrinter(hPrinter); 
     } 
     // If you did not succeed, GetLastError may give more information 
     // about why not. 
     if(bSuccess == false) 
     { 
       dwError = Marshal.GetLastWin32Error(); 
     } 
     return bSuccess; 
    } 

    public static bool SendFileToPrinter(string szPrinterName, string szFileName) 
    { 
     // Open the file. 
     FileStream fs = new FileStream(szFileName, FileMode.Open); 
     // Create a BinaryReader on the file. 
     BinaryReader br = new BinaryReader(fs); 
     // Dim an array of bytes big enough to hold the file's contents. 
     Byte []bytes = new Byte[fs.Length]; 
     bool bSuccess = false; 
     // Your unmanaged pointer. 
     IntPtr pUnmanagedBytes = new IntPtr(0); 
     int nLength; 

     nLength = Convert.ToInt32(fs.Length); 
     // Read the contents of the file into the array. 
     bytes = br.ReadBytes(nLength); 
     // Allocate some unmanaged memory for those bytes. 
     pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength); 
     // Copy the managed byte array into the unmanaged array. 
     Marshal.Copy(bytes, 0, pUnmanagedBytes, nLength); 
     // Send the unmanaged bytes to the printer. 
     bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, nLength); 
     // Free the unmanaged memory that you allocated earlier. 
     Marshal.FreeCoTaskMem(pUnmanagedBytes); 
     return bSuccess; 
    } 
    public static bool SendStringToPrinter(string szPrinterName, string szString) 
    { 
     IntPtr pBytes; 
     Int32 dwCount; 
     // How many characters are in the string? 
     dwCount = szString.Length; 
     // Assume that the printer is expecting ANSI text, and then convert 
     // the string to ANSI text. 
     pBytes = Marshal.StringToCoTaskMemAnsi(szString); 
     // Send the converted ANSI string to the printer. 
     SendBytesToPrinter(szPrinterName, pBytes, dwCount); 
     Marshal.FreeCoTaskMem(pBytes); 
     return true; 
    } 
} 

Вызвать метод печати:

private void BtnPrint_Click(object sender, System.EventArgs e) 
{ 
    string s = "^XA^LH30,30\n^FO20,10^ADN,90,50^AD^FDHello World^FS\n^XZ"; 

    PrintDialog pd = new PrintDialog(); 
    pd.PrinterSettings = new PrinterSettings(); 
    if(DialogResult.OK == pd.ShowDialog(this)) 
    { 
     RawPrinterHelper.SendStringToPrinter(pd.PrinterSettings.PrinterName, s); 
    } 
} 

Есть 2 подводных камней я сталкивался, что произойдет, когда вы 'отправка текстовых файлов с кодами ZPL на принтер:

  1. Файл ha s до конца с новой строки
  2. Encoding должен быть установлен в Encoding.Default при чтении ANSI текстовые файлы со специальными символами

    public static bool SendTextFileToPrinter(string szFileName, string printerName) 
    { 
        var sb = new StringBuilder(); 
    
        using (var sr = new StreamReader(szFileName, Encoding.Default)) 
        { 
         while (!sr.EndOfStream) 
         { 
          sb.AppendLine(sr.ReadLine()); 
         } 
        } 
    
        return RawPrinterHelper.SendStringToPrinter(printerName, sb.ToString()); 
    } 
    
+0

Должно быть возможно вызвать SendStringToPrinter на строку непосредственно из цикла while без необходимости считывать весь входной файл в память. (если кто-то с принтером Zebra может подтвердить, что он работает, отредактируйте ответ или дайте мне знать) – Vedran

+0

Я пробую это на USB, это нормально, но когда я пытаюсь в LPT, он не печатал, но не делал ошибок. Любая возможная ошибка? – Vic

+0

Привет, я использовал ваш код, но принтер ничего не печатает, принтер отправляет запрос на катушку, но не печатает, можете ли вы помочь? – Esmigol

11

Самое простое решение с копированием файлов на общем принтере.
Пример на C#:

System.IO.File.Copy(inputFilePath, printerPath); 

где:

  • inputFilePath - путь к файлу ZPL (специальное расширение не требуется);
  • printerPath - путь к общему принтеру, например (!): \ 127.0.0.1 \ zebraGX
+0

Это сработало для меня, я уже создавал файлы для своих ярлыков. –

+0

Это работало для меня в vb.net. красивый и простой 1 лайнер. У меня есть .zpl файлы, которые мне предоставляются, и мне нужно было отправить их на принтер Zebra, – Zyren

+0

Это потрясающе, так много опережающих, чем другие решения. Он отлично работает с такими сервисами, как EasyPost, которые уже создают файл ZPL для печати. Я смог распечатать на принтере, совместно используемом с другого компьютера в сети, только с именем «\\ имя_команды \\ имя-принтера». – blackorchid

8

Вот как сделать это с помощью протокола TCP IP:

// Printer IP Address and communication port 
    string ipAddress = "10.3.14.42"; 
    int port = 9100; 

// ZPL Command(s) 
    string ZPLString = 
    "^XA" + 
    "^FO50,50" + 
    "^A0N50,50" + 
    "^FDHello, World!^FS" + 
    "^XZ"; 

    try 
    { 
    // Open connection 
    System.Net.Sockets.TcpClient client = new System.Net.Sockets.TcpClient(); 
    client.Connect(ipAddress, port); 

    // Write ZPL String to connection 
    System.IO.StreamWriter writer = 
    new System.IO.StreamWriter(client.GetStream()); 
    writer.Write(ZPLString); 
    writer.Flush(); 

    // Close Connection 
    writer.Close(); 
    client.Close(); 
} 
catch (Exception ex) 
{ 
    // Catch Exception 
} 

Источник: ZEBRA WEBSITE