如何通过USB使用C#将原始ZPL发送到斑马打印机

本文关键字:打印机 ZPL 原始 USB 何通过 使用 | 更新日期: 2023-09-27 18:20:49

我是一名初级C#程序员。我有一个项目需要我通过USB将原始命令发送到Zebra打印机LP2844并使其工作。我做了很多研究,并试图找到一种方法来做到这一点。我使用的代码来自http://support.microsoft.com/kb/322091,但没有起作用。根据我的测试,我似乎已经向打印机发送了命令,但它没有响应并打印。我对此一无所知。有人能帮我吗?

我正在使用按钮直接发送命令

private void button2_Click(object sender, EventArgs e)
{
    string s = "A50,50,0,2,1,1,N,'"9129302'"";
    // Allow the user to select a printer.
    PrintDialog pd = new PrintDialog();
    pd.PrinterSettings = new PrinterSettings();
    if (DialogResult.OK == pd.ShowDialog(this))
    {
        // Send a printer-specific to the printer.
        RawPrinterHelper.SendStringToPrinter(pd.PrinterSettings.PrinterName, s);
        MessageBox.Show("Data sent to printer.");
    }
}

如何通过USB使用C#将原始ZPL发送到斑马打印机

EDIT:要解决更新问题,您遇到的问题是使用SendStringToPrinter,它会向打印机发送ANSI字符串(以null结尾),而这不是打印机所期望的。根据官方EPL2编程指南第23页(根据您的示例,这是您真正在做的,而不是ZPL)。

每个命令行都必须以换行符(LF)字符结束(12月10日)。大多数基于PC的系统在按下Enter键时发送CR/LF按下。回车(CR)字符被打印机忽略并且不能代替LF使用。

因此,您必须修改SendStringToPrinter以在字符串末尾发送'n而不是'0,或者您必须自己构建ASCII字节数组并使用RawPrinterHelper.SendBytesToPrinter(就像我在下面的原始答案中所做的那样)。

因此,为了修复您发布的简单示例,我们更改了您的函数调用,我们还必须通过发送P1'n 来告诉打印机实际打印

private void button2_Click(object sender, EventArgs e)
{
    string s = "A50,50,0,2,1,1,N,'"9129302'"'n";
    s += "P1'n";
    // Allow the user to select a printer.
    PrintDialog pd = new PrintDialog();
    pd.PrinterSettings = new PrinterSettings();
    if (DialogResult.OK == pd.ShowDialog(this))
    {
        var bytes = Encoding.ASCII.GetBytes(s);
        // Send a printer-specific to the printer.
        RawPrinterHelper.SendBytesToPrinter(pd.PrinterSettings.PrinterName, bytes, bytes.Length);
        MessageBox.Show("Data sent to printer.");
    }
}
//elsewhere
public static class RawPrinterHelper
{
    //(Snip) The rest of the code you already have from http://support.microsoft.com/kb/322091
    [DllImport("winspool.Drv", EntryPoint="WritePrinter", SetLastError=true, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
    public static extern bool WritePrinter(IntPtr hPrinter, byte[] pBytes, Int32 dwCount, out Int32 dwWritten );

    private static bool SendBytesToPrinter(string szPrinterName, byte[] bytes, Int32 dwCount)
    {
        Int32 dwError = 0, dwWritten = 0;
        IntPtr hPrinter = new IntPtr(0);
        DOCINFOA di = new DOCINFOA();
        bool bSuccess = false;
        di.pDocName = "Zebra Label";
        di.pDataType = "RAW";

        if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero))
        {
            if (StartDocPrinter(hPrinter, 1, di))
            {
                if (StartPagePrinter(hPrinter))
                {
                    bSuccess = WritePrinter(hPrinter, bytes, dwCount, out dwWritten);
                    EndPagePrinter(hPrinter);
                }
                EndDocPrinter(hPrinter);
            }
            ClosePrinter(hPrinter);
        }
        if (bSuccess == false)
        {
            dwError = Marshal.GetLastWin32Error();
            throw new Win32Exception(dwError);
        }
        return bSuccess;
    }
}

我用Zebra的旧EPL2语言做到了这一点,但它应该与ZPL非常相似。也许它会让你朝着正确的方向开始。

public class Label
{
    #region Print logic. Taken from http://support.microsoft.com/kb/322091
    //Snip stuff unchanged from the KB example.   
    [DllImport("winspool.Drv", EntryPoint="WritePrinter", SetLastError=true, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
    public static extern bool WritePrinter(IntPtr hPrinter, byte[] pBytes, Int32 dwCount, out Int32 dwWritten );     
    private static bool SendBytesToPrinter(string szPrinterName, byte[] Bytes, Int32 dwCount)
    {
        Int32 dwError = 0, dwWritten = 0;
        IntPtr hPrinter = new IntPtr(0);
        DOCINFOA di = new DOCINFOA();
        bool bSuccess = false;
        di.pDocName = "Zebra Label";
        di.pDataType = "RAW";

        if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero))
        {
            if (StartDocPrinter(hPrinter, 1, di))
            {
                if (StartPagePrinter(hPrinter))
                {
                    bSuccess = WritePrinter(hPrinter, Bytes, dwCount, out dwWritten);
                    EndPagePrinter(hPrinter);
                }
                EndDocPrinter(hPrinter);
            }
            ClosePrinter(hPrinter);
        }
        if (bSuccess == false)
        {
            dwError = Marshal.GetLastWin32Error();
            throw new Win32Exception(dwError);
        }
        return bSuccess;
    }
    #endregion
    public byte[] CreateCompleteCommand(bool headerAndFooter)
    {
        List<byte> byteCollection = new List<byte>();
        //Static header content describing the label.
        if (headerAndFooter)
        {
            byteCollection.AddRange(Encoding.ASCII.GetBytes("'nN'n"));
            byteCollection.AddRange(Encoding.ASCII.GetBytes(String.Format("S{0}'n", this.Speed)));
            byteCollection.AddRange(Encoding.ASCII.GetBytes(String.Format("D{0}'n", this.Density)));
            byteCollection.AddRange(Encoding.ASCII.GetBytes(String.Format("q{0}'n", this.LabelHeight)));
            if (this.AdvancedLabelSizing)
            {
                byteCollection.AddRange(Encoding.ASCII.GetBytes(String.Format("Q{0},{1}'n", this.LableLength, this.GapLength)));
            }
        }
        //The content of the label.
        foreach (var command in this.Commands)
        {
            byteCollection.AddRange(command.GenerateByteCommand());
        }
        //The footer content of the label.
        if(headerAndFooter)
            byteCollection.AddRange(Encoding.ASCII.GetBytes(String.Format("P{0}'n", this.Pages)));
        return byteCollection.ToArray();
    }
    public bool PrintLabel(string printer)
    {
        byte[] command = this.CreateCompleteCommand(true);
        return SendBytesToPrinter(printer, command, command.Length); 
    }
    public List<Epl2CommandBase> Commands { get; private set; }
    //Snip rest of the code.
}
public abstract partial class Epl2CommandBase
{
    protected Epl2CommandBase() { }
    public virtual byte[] GenerateByteCommand()
    {
        return Encoding.ASCII.GetBytes(CommandString + ''n');
    }
    public abstract string CommandString { get; set; }
}

public class Text : Epl2CommandBase 
{
    public override string CommandString
    {
        get
        {
            string printText = TextValue;
            if (Font == Fonts.Pts24)
                printText = TextValue.ToUpperInvariant();
            printText = printText.Replace("''", "''''"); // Replace ' with ''
            printText = printText.Replace("'"", "'''""); // replace " with '"
            return String.Format("A{0},{1},{2},{3},{4},{5},{6},'"{7}'"", X, Y, (byte)TextRotation, (byte)Font, HorziontalMultiplier, VertricalMultiplier, Reverse, printText);
        }
        set
        {
            GenerateCommandFromText(value);
        }
    }
    private void GenerateCommandFromText(string command)
    {
        if (!command.StartsWith(GetFactoryKey()))
            throw new ArgumentException("Command must begin with " + GetFactoryKey());
        string[] commands = command.Substring(1).Split(',');
        this.X = int.Parse(commands[0]);
        this.Y = int.Parse(commands[1]);
        this.TextRotation = (Rotation)byte.Parse(commands[2]);
        this.Font = (Fonts)byte.Parse(commands[3]);
        this.HorziontalMultiplier = int.Parse(commands[4]);
        this.VertricalMultiplier = int.Parse(commands[5]);
        this.ReverseImageColor = commands[6].Trim().ToUpper() == "R";
        string message = String.Join(",", commands, 7, commands.Length - 7);
        this.TextValue = message.Substring(1, message.Length - 2); // Remove the " at the beginning and end of the string.
    }
    //Snip
}

如果人们试图从上面的答案中获得该片段:

        [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);
        [DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern bool WritePrinter(IntPtr hPrinter, byte[] pBytes, Int32 dwCount, out Int32 dwWritten);