将ZPL发送到Zebra打印机的.NET代码
有没有办法将ZPL(斑马编程语言)发送到.NET打印机?
我有代码在Delphi中这样做,但它不是很漂亮,我宁愿不尝试在.NET中重新创build它,因为它是。
看看这个线程: 使用PrintDocument类将ZPL代码打印到ZEBRA打印机 。
具体来说,OP从线程的答案中select这个函数:
[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(); }
这样,无论连接如何,您都可以将ZPL发送到打印机( LPT , USB , networking共享 …)
创buildRawPrinterHelper类(从Microsoft文章如何使用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); } }
当你发送包含ZPL代码的txt文件到打印机时,遇到了两个问题:
- 该文件必须以换行符结束
-
当读取带有特殊字符的ANSI txt文件时,Encoding必须设置为Encoding.Default
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()); }
最简单的解决scheme是将文件复制到共享打印机。
C#中的示例:
System.IO.File.Copy(inputFilePath, printerPath);
哪里:
- inputFilePath – ZPL文件的path(不需要特殊扩展名);
- printerPath – 共享(!)打印机的path,例如:\ 127.0.0.1 \ zebraGX
我已经pipe理一个项目,多年来与套接字。 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(); } }
以下是使用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网站
因为这仍然显示在C#和ZPL的search结果高我应该提到SharpZebra。 这只是EPL2,但我已经提交了一个更新 ,增加了ZPL支持以及通过套接字,Windows Spool Service和直接USB打印。
VB版本(使用端口9100 – 在Zebra ZM400上testing)
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
我使用这两个组合
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