Код .NET для отправки ZPL на принтеры Zebra

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

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


person Vaccano    schedule 11.01.2010    source источник
comment
30к просмотров? Люди должны быть такими, как я, и задавались вопросом, что такое ZPL :).   -  person kristianp    schedule 24.07.2014
comment
@kristianp Любой, кому когда-либо приходилось работать над розничным программным обеспечением, рано или поздно оказывается в битве с ZPL;)   -  person Vedran    schedule 01.06.2015
comment
Розничная или промышленная/производственная печать   -  person StingyJack    schedule 07.07.2017


Ответы (10)


Взгляните на эту тему: Печатайте коды 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();

}
person Darin Dimitrov    schedule 11.01.2010
comment
Для поддержки неанглийских символов command должны быть закодированы в UTF16 BE. - person Alexufo; 13.05.2014
comment
Нужно ли устанавливать драйвер принтера для этого метода? - person Raize Ahamed; 07.10.2015
comment
пытается сделать что-то подобное - стоит проверить! - person SammuelMiranda; 25.06.2018

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

Создайте класс RawPrinterHelper (из статьи Microsoft о Как отправлять необработанные данные на принтер с помощью 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;
    }
}

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

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 на принтер:

  1. Файл должен заканчиваться символом новой строки
  2. Для кодировки должно быть установлено значение 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());
    }
    
person Vedran    schedule 11.10.2012

Вот как это сделать с использованием протокола 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.

person Erwin Draconis    schedule 16.04.2015

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

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

где:

  • inputFilePath - путь к файлу ZPL (специальное расширение не требуется);
  • printerPath - путь к общему(!) принтеру, например: \127.0.0.1\zebraGX
person liquide    schedule 09.09.2013
comment
Это сработало для меня, я уже создавал файлы для своих этикеток. - person Derrick Moeller; 29.04.2014
comment
Это сработало для меня в vb.net. красивый и простой 1 лайнер. У меня есть файлы .zpl, которые мне предоставили, и мне нужно было отправить их на принтер Zebra, - person Zyren; 30.10.2015
comment
Это удивительно, намного аккуратнее, чем другие решения. Он отлично работает с такими сервисами, как EasyPost, которые уже генерируют файл ZPL для печати. Я смог печатать на принтере, совместно используемом с другого компьютера в сети, используя только \\machine-name\\printer-name. - person blackorchid; 04.11.2016
comment
Это сработало - большое спасибо. Мне пришлось переименовать расширение файла в .prn. - person Gail Foad; 09.03.2020

Я управлял проектом, который делает это с сокетами в течение многих лет. 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();
    }
}
person Austin Salonen    schedule 11.01.2010
comment
Мобильные принтеры Zebra используют порт 6101 (QL, RW, MZ и т. д.). Большие принтеры обычно используют порт 9100. - person James Van Huis; 09.02.2010
comment
Я использовал этот код в простом консольном приложении для печати на Zebra LP 2844 Z. Мне пришлось изменить порт на 9100. - person Monroecheeseman; 17.02.2011

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

person rkone    schedule 14.12.2010

Версия 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
person scanbcc    schedule 21.12.2011

Ответ @liquide отлично работает.

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

Которое я нашел в Руководстве программиста Zebra ZPL, том 1 (2005 г.) введите здесь описание изображения

person Bluto    schedule 30.07.2019

На сайте поддержки Zebra есть ответ:

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

person Bluby    schedule 31.01.2013
comment
Эта страница защищена авторскими правами, что делает незаконным копирование найденного там кода. (Или, по крайней мере, это выглядит так.) - person Vaccano; 31.01.2013

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

    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
person Calvin    schedule 09.07.2012