【问题标题】:.NET code to send ZPL to Zebra printers将 ZPL 发送到 Zebra 打印机的 .NET 代码
【发布时间】:2011-01-03 22:04:15
【问题描述】:

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

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

【问题讨论】:

  • 30k 次观看?人们一定和我一样,想知道 ZPL 是什么 :)。
  • @kristianp 任何不得不在零售软件上工作的人迟早都会与 ZPL 发生争执;)
  • 零售或工业/制造印刷

标签: c# .net zpl-ii zebra-printers zpl


【解决方案1】:

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

创建 RawPrinterHelper 类(来自How to send raw data to a printer by using Visual C# .NET 上的 Microsoft 文章):

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 代码的 txt 文件发送到打印机时,我遇到了两个问题:

  1. 文件必须以换行符结尾
  2. 在读取带有特殊字符的 ANSI txt 文件时,必须将编码设置为 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());
    }
    

【讨论】:

  • 我在 USB 上试试这个,没关系,但是当我在 LPT 中尝试时,它没有打印但没有抛出任何错误。任何可能的错误?
  • 您好,我使用了您的代码,但打印机不打印任何内容,打印机将请求发送到假脱机但不打印,您能帮忙吗?
  • 需要注意的是,上面的代码适用于 Zebra 证卡打印机,而证卡打印机无法做到这一点
  • 我尝试了一切,但这确实有效!谢谢。
  • 这是已删除的 MS kb 文章的存档版本:web.archive.org/web/20150303123140/http://support.microsoft.com/…
【解决方案2】:

看看这个帖子:Print ZPL codes to ZEBRA printer using PrintDocument class

具体来说,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();

}

【讨论】:

  • 为了支持非英文符号command必须用UTF16 BE编码。
  • 这种方式需要安装打印机驱动吗?
  • 尝试做这样的事情 - 值得一试!
  • 单据中是否有指定打印机名称、标签个数、条码列数的选项,请帮忙!
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

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

    地点:

    • inputFilePath - ZPL 文件的路径(不需要特殊扩展名);
    • printerPath - 共享(!)打印机的路径,例如:\127.0.0.1\zebraGX

    【讨论】:

    • 这对我有用,我已经在为我的标签创建文件了。
    • 这在 vb.net 中对我有用。漂亮而简单的 1 班轮。我有提供给我的 .zpl 文件,我需要将它们发送到斑马打印机,
    • 这太棒了,比其他解决方案要简洁得多。它与已经生成 ZPL 文件进行打印的 EasyPost 等服务完美配合。我可以使用“\\machine-name\\printer-name”打印到网络上另一台机器共享的打印机。
    • 这很有效 - 非常感谢。我不得不将我的文件扩展名重命名为 .prn。
    【解决方案5】:

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

    【讨论】:

    • Zebra 移动打印机使用端口 6101(QL、RW、MZ 等)。较大的打印机通常使用端口 9100。
    • 我在一个简单的控制台应用程序中使用此代码打印到 Zebra LP 2844 Z。我确实必须将端口更改为 9100。
    【解决方案6】:

    想通了,因为这在 C# 和 ZPL 的搜索结果中仍然很高,我应该提到 SharpZebra。它只是 EPL2,但我提交了一个 update,它添加了 ZPL 支持以及通过套接字、Windows 假脱机服务和直接 USB 打印。

    【讨论】:

      【解决方案7】:

      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
      

      【讨论】:

        【解决方案8】:

        @liquide 的回答效果很好。

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

        我从 Zebra 的 ZPL 程序员指南第 1 卷 (2005) 中找到的

        【讨论】:

          【解决方案9】:

          【讨论】:

          • 此页面拥有版权,因此复制那里的代码是非法的。 (或者至少看起来是这样的。)
          【解决方案10】:

          我用这两个的组合

              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
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-05-25
            • 1970-01-01
            • 2015-02-10
            • 2011-11-16
            • 1970-01-01
            • 1970-01-01
            • 2023-03-19
            相关资源
            最近更新 更多