Código .NET para enviar ZPL a impresoras Zebra

¿Hay alguna forma de enviar ZPL (Zebra Programming Language) a una impresora en .NET?

Tengo el código para hacer esto en Delphi, pero no es bonito y prefiero no intentar recrearlo en .NET como está.

Eche un vistazo a este hilo: Imprima códigos ZPL en la impresora ZEBRA utilizando la clase PrintDocument .

Específicamente, el OP elige esta función de las respuestas al hilo:

[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(); } 

De esta forma, podrá enviar ZPL a una impresora sin importar cómo esté conectada ( LPT , USB , red compartida …)

Cree la clase RawPrinterHelper (del artículo de Microsoft sobre Cómo enviar datos sin formato a una impresora utilizando 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; } } 

Llame al método de impresión:

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

Hay dos errores que he encontrado que ocurren cuando envías archivos txt con códigos ZPL a la impresora:

  1. El archivo debe terminar con un nuevo carácter de línea
  2. La encoding debe configurarse en Encoding.Default al leer archivos ANSI txt con caracteres especiales

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

Logré un proyecto que hace esto con sockets durante años. Zebra normalmente usa el puerto 6101. Revisaré el código y publicaré lo que pueda.

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

La solución más simple es copiar archivos a la impresora compartida.
Ejemplo en C #:

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

dónde:

  • inputFilePath: ruta al archivo ZPL (no se requiere una extensión especial);
  • printerPath: ruta a la impresora compartida (!), por ejemplo: \ 127.0.0.1 \ zebraGX

Aquí es cómo hacerlo usando el protocolo 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 } 

Fuente: SITIO WEB DE ZEBRA

Supongo que esto sigue apareciendo alto en los resultados de búsqueda para C # y ZPL, debería mencionar SharpZebra. Es solo EPL2, pero he enviado una actualización que agrega compatibilidad con ZPL junto con la impresión a través de sockets, el servicio de Windows Spool y el USB directo.

Versión VB (utilizando el puerto 9100 – probado en 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 

Hay una respuesta en el sitio web de soporte de Zebra:

https://km.zebra.com/kb/index?page=content&id=SA301&cat=ZISV_PL_ZPL&actp=LIST

Yo uso el combo de estos dos

  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