发送原始ZPL指令打印斑马标签失败:指令被直接输出
Zebra打印机WPF打印ZPL指令不解析问题
开发了一个C# WPF应用,用于通过Zebra打印机打印标签。标签对应的ZPL代码已生成,在记事本、Notepad++等文本编辑器中打印该代码时,标签能正常输出;但在WPF应用中执行相同打印操作时,ZPL指令被直接打印在标签上,而非解析为预期的标签内容。
XAML文件代码
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:ZebraTesting" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <Grid.RowDefinitions> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <Grid Grid.Row="1"> <Grid.ColumnDefinitions> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <Button Content="TEST-1" Name="test1" Click="test1_Click"></Button> <Button Grid.Column="1" Content="TEST-2" Name="test2" Click="test2_Click"></Button> </Grid> </Grid> </Window>
CS文件代码
using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Printing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace ZebraTesting { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void test1_Click(object sender, RoutedEventArgs e) { System.Windows.Controls.PrintDialog prnt = new PrintDialog(); prnt.PageRangeSelection = PageRangeSelection.AllPages; prnt.UserPageRangeEnabled = false; Nullable<bool> result = prnt.ShowDialog(); if (result == true) { PrintDocument pdoc = new PrintDocument(); pdoc.PrintPage += ProvideContent; pdoc.Print(); } } public void ProvideContent(object sender, PrintPageEventArgs e) { string zpl = "^XA" + Environment.NewLine + "^A0N,23,31^FDAsset ID:^FS" + Environment.NewLine + "^XZ" + Environment.NewLine; e.Graphics.DrawString(zpl, new Font("Arial", 10), System.Drawing.Brushes.Black, 0, 0, new StringFormat()); } private void test2_Click(object sender, RoutedEventArgs e) { System.Windows.Controls.PrintDialog prnt = new PrintDialog(); prnt.PageRangeSelection = PageRangeSelection.AllPages; prnt.UserPageRangeEnabled = false; Nullable<bool> result = prnt.ShowDialog(); if (result == true) { string zpl = "^XA" + Environment.NewLine + "^A0N,23,31^FDAsset ID:^FS" + Environment.NewLine + "^XZ" + Environment.NewLine; var doc = new FlowDocument(); doc.ColumnWidth = prnt.PrintableAreaWidth; Paragraph p = new Paragraph(); p.Inlines.Add(zpl); doc.Blocks.Add(p); prnt.PrintDocument(((IDocumentPaginatorSource)doc).DocumentPaginator, "Label A0000001"); //doc.Blocks.Add(new Paragraph(new Run(zpl))); //prnt.PrintDocument(((IDocumentPaginatorSource)doc).DocumentPaginator, "Label A0000001"); //prnt.PrintDocument((Section)XamlReader.Parse(zpl)); } } } }
问题现象
ZPL指令被原样打印,未输出预期文本。

解决方案
你的代码问题在于:用WPF的PrintDialog结合DrawString或FlowDocument打印时,是把ZPL文本当成普通字符串渲染成图像后发送给打印机,而Zebra打印机需要直接接收原始ZPL指令才能解析执行。
可以通过直接向打印机发送原始字节流的方式解决,以下是具体实现:
1. 添加RawPrinterHelper辅助类
这个类用于向打印机发送原始格式的数据:
using System; using System.Runtime.InteropServices; using System.Windows; public class RawPrinterHelper { [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, int 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, int dwCount, out int dwWritten); public static bool SendStringToPrinter(string szPrinterName, string szString) { IntPtr pBytes; int dwCount = szString.Length; pBytes = Marshal.StringToCoTaskMemAnsi(szString); bool success = SendBytesToPrinter(szPrinterName, pBytes, dwCount); Marshal.FreeCoTaskMem(pBytes); return success; } public static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, int dwCount) { int dwError = 0, dwWritten = 0; IntPtr hPrinter = new IntPtr(0); DOCINFOA di = new DOCINFOA(); bool bSuccess = false; di.pDocName = "ZPL Label"; di.pDataType = "RAW"; if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero)) { if (StartDocPrinter(hPrinter, 1, di)) { if (StartPagePrinter(hPrinter)) { bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten); EndPagePrinter(hPrinter); } EndDocPrinter(hPrinter); } ClosePrinter(hPrinter); } if (!bSuccess) { dwError = Marshal.GetLastWin32Error(); MessageBox.Show($"打印失败,错误码:{dwError}"); } return bSuccess; } }
2. 修改按钮点击事件
替换原来的test1_Click方法,使用RawPrinterHelper发送ZPL指令:
private void test1_Click(object sender, RoutedEventArgs e) { System.Windows.Controls.PrintDialog prnt = new PrintDialog(); prnt.PageRangeSelection = PageRangeSelection.AllPages; prnt.UserPageRangeEnabled = false; if (prnt.ShowDialog() == true) { string zpl = "^XA" + Environment.NewLine + "^A0N,23,31^FDAsset ID:^FS" + Environment.NewLine + "^XZ" + Environment.NewLine; // 获取选中的打印机名称 string printerName = prnt.PrintQueue.Name; RawPrinterHelper.SendStringToPrinter(printerName, zpl); } }
原理说明
记事本等编辑器打印ZPL时,是将文本以RAW格式直接发送给打印机,打印机收到后会直接解析执行ZPL指令;而你的原有WPF代码是将ZPL作为普通文本渲染成图像再发送,打印机只会打印渲染后的文本内容。使用RawPrinterHelper可以直接将ZPL字符串以RAW格式发送到打印机,让Zebra设备正确解析执行指令。
内容的提问来源于stack exchange,提问作者arpit pandya
相关产品推荐
相关产品推荐

