C# 将 ZPL 发送到 Zebra 打印机的 .NET 代码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2044676/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 22:57:51  来源:igfitidea点击:

.NET code to send ZPL to Zebra printers

c#.netzpl-iizebra-printerszpl

提问by Vaccano

Is there a way to send ZPL (Zebra Programming Language) to a printer in .NET?

有没有办法将 ZPL(Zebra 编程语言)发送到 .NET 中的打印机?

I have the code to do this in Delphi, but it is not pretty and I would rather not try to recreate it in .NET as it is.

我有在 Delphi 中执行此操作的代码,但它并不漂亮,我宁愿不尝试在 .NET 中按原样重新创建它。

采纳答案by Darin Dimitrov

Take a look at this thread: Print ZPL codes to ZEBRA printer using PrintDocument class.

看看这个线程:使用 PrintDocument 类将 ZPL 代码打印到 ZEBRA 打印机

Specifically the OP pick this function from the answers to the thread:

特别是OP从线程的答案中选择了这个函数:

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

}

回答by Austin Salonen

I've managed a project that does this with sockets for years. Zebra's typically use port 6101. I'll look through the code and post what I can.

多年来,我一直在管理一个使用套接字执行此操作的项目。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();
    }
}

回答by rkone

Figured since this is still showing up high in search results for C# and ZPL I should mention SharpZebra. It's only EPL2, but I've submitted an updatethat adds ZPL support along with printing via sockets, the Windows Spool Service and direct USB.

考虑到这仍然在 C# 和 ZPL 的搜索结果中显示很高,我应该提到 SharpZebra。它只是 EPL2,但我提交了一个更新,增加了 ZPL 支持以及通过套接字、Windows 后台打印服务和直接 USB 打印。

回答by scanbcc

VB Version (using port 9100 - tested on Zebra ZM400)

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

回答by Calvin

I use the combo of these two

我使用这两个的组合

    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

回答by Vedran

This way you will be able to send ZPL to a printer no matter how it is connected (LPT, USB, Network Share...)

这样,无论打印机如何连接(LPTUSB网络共享...),您都可以将 ZPL 发送到打印机

Create the RawPrinterHelper class (from the Microsoft article on How to send raw data to a printer by using Visual C# .NET):

创建 RawPrinterHelper 类(来自 Microsoft 文章How to send raw data to a printer by using 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;
    }
}

Call the print method:

调用打印方法:

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


There are 2 gotchas I've come across that happen when you're sending txt files with ZPL codes to the printer:

当您将带有 ZPL 代码的 txt 文件发送到打印机时,我遇到了两个问题:

  1. The file has to end with a new line character
  2. Encoding has to be set to Encoding.Default when reading ANSI txt files with special characters

    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());
    }
    
  1. 文件必须以换行符结尾
  2. 读取带有特殊字符的 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());
    }
    

回答by liquide

The simplest solution is with copying files to shared printer.
Example in C#:

最简单的解决方案是将文件复制到共享打印机。
C# 中的示例:

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

where:

在哪里:

  • inputFilePath - path to ZPL file (special extension is not required);
  • printerPath - path to shared(!) printer, for example: \127.0.0.1\zebraGX
  • inputFilePath - ZPL 文件的路径(不需要特殊的扩展名);
  • printerPath - 共享(!)打印机的路径,例如:\127.0.0.1\zebraGX

回答by Erwin Draconis

Here is how to do it using TCP IP protocol :

以下是使用 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 WEBSITE

来源:斑马网站

回答by Bluto

@liquide's answer works great.

@liquide 的回答很有效。

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

Which I found from the Zebra's ZPL Programmer's Guide Volume 1 (2005) enter image description here

我从 Zebra 的 ZPL 程序员指南第 1 卷(2005 年)中找到的 enter image description here