Reading status from Zebra Printer

后端 未结 5 1020
日久生厌
日久生厌 2021-01-04 08:52

I\'m working on a project where we need to use a Zebra Printer for barcode labels. We\'re using C#, and we\'re doing OK on the printing side of things, sending raw ZPL stri

5条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2021-01-04 09:29

    If you have the chance to use kernel32.dll and leaving out the usb-driver-bound winspool.srv you could use this vanilla approach:

    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) (but I can't tell if this works with ZPL/EPL/fingerprint/...-printers) which uses GetPrinter with PRINTER_INFO_2.
    There's also a translation at pinvoke.net available.

提交回复
热议问题