code .NET pour envoyer ZPL aux imprimantes Zebra
-
20-09-2019 - |
Question
Yat-il un moyen d'envoyer ZPL (Zebra Programming Language) à une imprimante dans .NET?
Je le code pour faire en Delphi, mais ce n'est pas assez et je préférerais ne pas essayer de le recréer dans .NET comme il est.
La solution
Jetez un oeil à ce sujet: imprimer des codes ZPL à l'aide de l'imprimante ZEBRA classe PrintDocument.
Plus précisément l'OP choisir cette fonction des réponses au fil:
[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();
}
Autres conseils
De cette façon, vous serez en mesure d'envoyer ZPL à une imprimante, peu importe la façon dont il est connecté ( LPT , USB , Réseau Partager . ..)
Créer la classe RawPrinterHelper (de l'article Microsoft sur Comment envoyer des données brutes à une imprimante en utilisant Visual C # .NET ):
using System;
using System.Drawing;
using System.Drawing.Printing;
using System.IO;
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;
}
}
Appelez la méthode d'impression:
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);
}
}
Il y a 2 gotchas que j'ai rencontré qui se produisent quand vous envoyez des fichiers txt avec les codes ZPL à l'imprimante:
- Le fichier doit se terminer par un caractère de nouvelle ligne
-
L'encodage doit être réglé sur Encoding.Default lors de la lecture des fichiers ANSI txt avec des caractères spéciaux
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()); }
J'ai réussi un projet qui fait cela avec des prises pendant des années. Zebra utilisent généralement le port 6101. Je vais regarder dans le code et après ce que je peux.
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 solution la plus simple est avec la copie des fichiers à l'imprimante partagée.
Exemple en C #:
System.IO.File.Copy(inputFilePath, printerPath);
où:
- inputFilePath - chemin vers le fichier ZPL (extension spéciale n'est pas nécessaire);
- printerPath - chemin vers l'imprimante partagée, par exemple: \ 127.0.0.1 \ zebraGX (!)
Voici comment le faire en utilisant le protocole 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
}
Source: ZEBRA SITE INTERNET
Figured puisque cette montre toujours en place dans les résultats de recherche pour C # et ZPL je faut mentionner SharpZebra. Il est seulement EPL2, mais je l'ai présenté une mise à jour href="http://sharpzebra.codeplex.com/SourceControl/PatchList.aspx" qui ajoute le support ZPL ainsi que l'impression via prises de courant, le service Spool Windows et USB directe.
VB Version (en utilisant le port 9100 - testé sur 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
Il y a une réponse sur le site Web de support Zebra:
https://km.zebra.com/kb/ index? page = contenu & id = SA301 & cat = ZISV_PL_ZPL & PTCA = LIST
J'utilise le combo de ces deux
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