.NET код для отправки ZPL на принтеры Zebra
Есть ли способ отправить ZPL (язык программирования Zebra) на принтер в.NET?
У меня есть код для этого в Delphi, но он не очень красивый, и я бы предпочел не пытаться воссоздать его в.NET как есть.
9 ответов
Взгляните на эту тему: Распечатайте коды ZPL на принтере ZEBRA, используя класс PrintDocument.
В частности, ОП выбирает эту функцию из ответов в ветке:
[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, Network Share...)
Создайте класс RawPrinterHelper (из статьи 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:
- Файл должен заканчиваться символом новой строки
Кодировка должна быть установлена на 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()); }
Вот как это сделать, используя протокол 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
}
Источник: ЗЕБРА САЙТ
Самым простым решением является копирование файлов на общий принтер.
Пример в C#:
System.IO.File.Copy(inputFilePath, printerPath);
где:
- inputFilePath - путь к ZPL-файлу (специальное расширение не требуется);
- printerPath - путь к общему (!) принтеру, например: \127.0.0.1\zebraGX
Я управлял проектом, который делает это с сокетами в течение многих лет. Зебра обычно использует порт 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();
}
}
Похоже, что это все еще высоко в результатах поиска для C# и ZPL, я должен упомянуть SharpZebra. Это только EPL2, но я представил обновление, которое добавляет поддержку ZPL наряду с печатью через сокеты, службу Windows Spool и прямой USB.
На веб-сайте поддержки Zebra есть ответ:
https://km.zebra.com/kb/index?page=content&id=SA301&cat=ZISV_PL_ZPL&actp=LIST
Версия 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
Я использую комбинацию этих двух
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