首页 文章

从Zebra打印机读取状态

提问于
浏览
12

我正在开发一个项目,我们需要使用Zebra打印机来处理条形码标签 . 我们正在使用C#,我们在打印方面做得很好,将原始ZPL字符串发送到打印机(使用winspool.drv) .

但是,我们还需要从打印机读取,并没有运气 .

我们需要从打印机获取状态,这是ZPL命令“~HS”的输出,因此我们可以判断内存中有多少标签等待打印 . winspool.drv中的EnumJobs()只在Windows假脱机上有作业,一旦它们被发送到打印机,它们就会从该列表中消失 . 但这并不意味着标签已被打印,因为打印机有一个剥离传感器,一次只打印一个标签,我们显然对将批量标签发送到打印机感兴趣 .

我尝试了类似的东西(使用winspool.drv调用):

OpenPrinter(szPrinterName, out hPrinter, IntPtr.Zero);
WritePrinter(hPrinter, pBytes, dwCount, out dwWritten); // send the string "~HS"
ReadPrinter(hPrinter, data, buff, out pcRead);

但我在ReadPrinter调用中什么也得不到 . 我甚至不知道这是否是正确的方法 .

之前有人解决了这个问题吗?

谢谢 .

5 回答

  • 1

    我面临着同样的问题 . 你有没有关于这个主题的任何事情?

    Axe Perez Parra Castro,我就是这样做的:

    -my printer(zebra 2030)不支持ZPL,所以据我所知,唯一的方法就是向它发送unicode

    • 我列出了我需要的字符,例如
    string enq = Convert.ToChar(5).ToString();
    string esc = Convert.ToChar(27).ToString();
    string nul = Convert.ToChar(0).ToString();
    string rs = Convert.ToChar(30).ToString();
    string lf = Convert.ToChar(10).ToString();
    string cr = Convert.ToChar(13).ToString();
    

    (从en.wikipedia.org/wiki/ASCII获取那些int值)

    • 组成命令 - 例如 sb.Append(esc + enq + Convert.ToChar(7).ToString()); (从打印机手册中,命令<ESC> <ENQ> <7>应该获得固件版本)

    • 发送命令 RawPrinterHelper.SendStringToPrinter(printerName, sb.ToString()); (在我的情况下,printerName是"Zebra TTP 2030")

  • 0

    ReadPrinter 在这种情况下无济于事 . 它将回读您提交给打印机的打印作业,而不是打印机的响应 . 但是,为了完整起见:要使用 ReadPrinter ,必须使用组合的"printer name - job id"语法再次打开打印机:

    OpenPrinter("Zebra,Job 12345", ...);
    ReadPrinter(hPrinter, ...);
    

    这仅在作业12345尚未移除时才有效 .


    至于回答问题,你必须使用 WriteFile 发送数据和 ReadFile 来获得响应 . 要使用这些功能,您需要使用 CreateFile 打开打印机 . 完成后,其余的都是微不足道的 .

    这里的问题是获取必须传递给 CreateFile 的设备路径才能打开打印机 . 如果您的打印机是LPT打印机,那就像 "LPT:" 一样简单,但对于USB打印机,您必须获取设备路径,如下所示:

    \?\ usb#vid_0a5f&pid_0027#46a072900549#{28d78fad-5a12-11d1-ae5b-0000f803a8c2}

    我找到了way to obtain this path,但只有安装了一台打印机才能使用 . 如果你有更多,你需要设备路径和你在控制面板中看到的打印机名称之间的关系,这种关系是我为此创建了一个问题:Figuring which printer name corresponds to which device ID .

  • 0

    大约15年前,我编写了通过Zebra打印机打印的软件 .

    当我们通过RS-232(?标准串行通信)与打印机通信时,这种方式运行良好,所有信息都以及时准确的方式从打印机返回 .

    最近我会使用Epson理货打印机,发现Windows打印机驱动程序笨拙且效率低下 . 我通过GDI直接与打印机通信,一切都令我满意 .

    我说取出中间人,如果你下降一个级别并直接与打印机通信,而不是通过Windows打印机驱动程序进行通信,你将获得更多的成功 .

    希望这可以帮助,

  • 3

    如果你有机会使用 kernel32.dll 并省略usb-driver-bound winspool.srv ,你可以使用这种香草方法:

    using System;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Threading;
    using Microsoft.Win32.SafeHandles;
    
    {
        public class USB
        {
            [DllImport("kernel32.dll", SetLastError = true)]
            internal static extern Int32 CancelIo(SafeFileHandle hFile);
    
            [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            internal static extern IntPtr CreateEvent(IntPtr SecurityAttributes,
                                                      Boolean bManualReset,
                                                      Boolean bInitialState,
                                                      String lpName);
    
            [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            internal static extern Boolean GetOverlappedResult(SafeFileHandle hFile,
                                                               IntPtr lpOverlapped,
                                                               ref Int32 lpNumberOfBytesTransferred,
                                                               Boolean bWait);
    
            [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            internal static extern Boolean ReadFile(SafeFileHandle hFile,
                                                    IntPtr lpBuffer,
                                                    Int32 nNumberOfBytesToRead,
                                                    ref Int32 lpNumberOfBytesRead,
                                                    IntPtr lpOverlapped);
    
            [DllImport("kernel32.dll", SetLastError = true)]
            internal static extern Int32 WaitForSingleObject(IntPtr hHandle,
                                                             Int32 dwMilliseconds);
    
            [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            internal static extern SafeFileHandle CreateFile(String lpFileName,
                                                             UInt32 dwDesiredAccess,
                                                             Int32 dwShareMode,
                                                             IntPtr lpSecurityAttributes,
                                                             Int32 dwCreationDisposition,
                                                             Int32 dwFlagsAndAttributes,
                                                             Int32 hTemplateFile);
    
            [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            internal static extern Boolean WriteFile(SafeFileHandle hFile,
                                                     ref byte lpBuffer,
                                                     Int32 nNumberOfBytesToWrite,
                                                     ref Int32 lpNumberOfBytesWritten,
                                                     IntPtr lpOverlapped);
    
            [DllImport("kernel32.dll", SetLastError = true)]
            internal static extern int GetLastError();
    
            private const Int32 FILE_FLAG_OVERLAPPED = 0X40000000;
            private const Int32 FILE_SHARE_READ = 1;
            private const Int32 FILE_SHARE_WRITE = 2;
            private const UInt32 GENERIC_READ = 0X80000000;
            private const UInt32 GENERIC_WRITE = 0X40000000;
            private const Int32 OPEN_EXISTING = 3;
            private const Int32 WAIT_OBJECT_0 = 0;
            private const Int32 WAIT_TIMEOUT = 0x102;
            private const Int32 ReadBufferSize = 200;
    
            private readonly string _devicePathName;
    
            public USB(string devicePathName)
            {
                this._devicePathName = devicePathName;
            }
    
            public void Send(string data)
            {
                var bData = this.Encoding.GetBytes(data);
                this.Send(bData);
            }
    
            public void Send(byte[] data)
            {
                try
                {
                    var eventObject = CreateEvent(IntPtr.Zero,
                                                  false,
                                                  false,
                                                  String.Empty);
                    var hidOverlapped = GetHidOverlapped(eventObject);
    
                    var unManagedBuffer = Marshal.AllocHGlobal(data.Length);
                    var unManagedOverlapped = Marshal.AllocHGlobal(Marshal.SizeOf(hidOverlapped));
                    Marshal.StructureToPtr(hidOverlapped,
                                           unManagedOverlapped,
                                           false);
    
                    using (var writeHandle = this.GetWriteFileHandle())
                    {
                        var numberOfBytesWritten = 0;
                        var success = WriteFile(writeHandle,
                                                ref data[0],
                                                data.Length,
                                                ref numberOfBytesWritten,
                                                unManagedOverlapped);
                        if (!success)
                        {
                            var result = WaitForSingleObject(eventObject,
                                                             100);
                            switch (result)
                            {
                                case WAIT_OBJECT_0:
                                    success = true;
                                    break;
                                case WAIT_TIMEOUT:
                                    CancelIo(writeHandle);
                                    break;
                            }
                        }
                    }
    
                    Marshal.FreeHGlobal(unManagedOverlapped);
                    Marshal.FreeHGlobal(unManagedBuffer);
                }
                catch (Exception ex)
                {
                    // TODO add logging and enhance the try/catch-closure to a smaller one
                }
            }
    
            private Encoding Encoding
            {
                get
                {
                    return Encoding.ASCII;
                }
            }
    
            public string Read()
            {
                var receivedBytes = 0;
                var receiveBuffer = new byte[ReadBufferSize];
    
                string data;
    
                try
                {
                    var eventObject = CreateEvent(IntPtr.Zero,
                                                  false,
                                                  false,
                                                  String.Empty);
                    var hidOverlapped = GetHidOverlapped(eventObject);
    
                    var unManagedBuffer = Marshal.AllocHGlobal(ReadBufferSize);
                    var unManagedOverlapped = Marshal.AllocHGlobal(Marshal.SizeOf(hidOverlapped));
    
                    Marshal.StructureToPtr(hidOverlapped,
                                           unManagedOverlapped,
                                           false);
    
                    using (var readHandle = CreateFile(this._devicePathName,
                                                       GENERIC_READ,
                                                       FILE_SHARE_READ /* | FILE_SHARE_WRITE*/,
                                                       IntPtr.Zero,
                                                       OPEN_EXISTING,
                                                       FILE_FLAG_OVERLAPPED,
                                                       0))
                    {
                        var success = ReadFile(readHandle,
                                               unManagedBuffer,
                                               receiveBuffer.Length,
                                               ref receivedBytes,
                                               unManagedOverlapped);
                        if (!success)
                        {
                            var result1 = WaitForSingleObject(eventObject,
                                                              300);
                            switch (result1)
                            {
                                case WAIT_OBJECT_0:
                                    GetOverlappedResult(readHandle,
                                                        unManagedOverlapped,
                                                        ref receivedBytes,
                                                        false);
                                    break;
                                case WAIT_TIMEOUT:
                                default:
                                    //CancelIo(_readHandle);
                                    break;
                            }
                        }
                    }
    
                    if (receivedBytes > 0)
                    {
                        Array.Resize(ref receiveBuffer,
                                     receivedBytes);
                        Marshal.Copy(unManagedBuffer,
                                     receiveBuffer,
                                     0,
                                     receivedBytes);
                        data = this.Encoding.GetString(receiveBuffer);
                    }
                    else
                    {
                        data = null;
                    }
    
                    Marshal.FreeHGlobal(unManagedOverlapped);
                    Marshal.FreeHGlobal(unManagedBuffer);
                }
                catch (Exception ex)
                {
                    // TODO add logging and enhance the try/catch-closure to a smaller one
                    data = null;
                }
    
                return data;
            }
    
            private SafeFileHandle GetWriteFileHandle()
            {
                var writeHandle = CreateFile(this._devicePathName,
                                             GENERIC_WRITE | GENERIC_READ,
                                             FILE_SHARE_READ | FILE_SHARE_WRITE,
                                             IntPtr.Zero,
                                             OPEN_EXISTING,
                                             0,
                                             0);
    
                return writeHandle;
            }
    
            private static NativeOverlapped GetHidOverlapped(IntPtr eventObject)
            {
                return new NativeOverlapped
                {
                    OffsetLow = 0,
                    OffsetHigh = 0,
                    EventHandle = eventObject
                };
            }
        }
    }
    

    Otherwise there's a solution available (it's VB.NET though)(但我不知道这是否适用于ZPL / EPL /指纹/ ......打印机),它使用GetPrinterPRINTER_INFO_2 .
    还有pinvoke.net available的翻译 .

  • 0

    我使用了与C的TCP / IP通信,我能够从打印引擎响应 .

相关问题