13

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

但是,我们还需要从打印机读取数据,但没有运气。

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

我尝试过类似的方法(使用 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 调用中一无所获。我什至不知道这是否是正确的做法。

以前有人解决过这个问题吗?

谢谢。

4

5 回答 5

3

我面临同样的问题。您是否已经管理过有关此主题的任何事情?

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

- 从这里获取 RawPrinterHelper 类http://support.microsoft.com/kb/322091

-我的打印机(斑马 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”)

于 2010-06-01T15:04:14.870 回答
1

ReadPrinter在这种情况下无济于事。它将读回您提交给打印机的打印作业,而不是打印机的响应。但是,为了完整起见:为了使用,您必须再次ReadPrinter打开打印机,使用组合的“打印机名称 - 作业 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}

我找到了一种获取此路径的方法,但它仅在您只安装了一台打印机时才有效。如果您有更多,您将需要设备路径和您在控制面板中看到的打印机名称之间的关系,而这种关系是我还没有想到的。我为此创建了一个问题:确定哪个打印机名称对应于哪个设备 ID

于 2012-05-18T21:08:29.520 回答
0

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

当时,我们通过 RS-232(?标准串行通信)与打印机进行通信,效果很好,所有信息都及时准确地从打印机返回。

最近我在使用 Epson Tally 打印机,发现 Windows 打印机驱动程序笨拙且效率低下。我下降了一个级别并通过 GDI 直接与打印机通信,一切都让我满意。

我说去掉中间人,如果你下拉一个级别并直接与打印机通信,而不是通过windows打印机驱动程序通信,你会取得更大的成功。

希望这可以帮助,

于 2009-12-04T12:14:01.200 回答
0

如果您有机会使用kernel32.dll并省略 usb-driver-boundwinspool.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
            };
        }
    }
}

否则有一个可用的解决方案(虽然它是 VB.NET)(但我不知道这是否适用于 ZPL/EPL/fingerprint/...-printers)GetPrinterPRINTER_INFO_2. pinvoke.net
上也有翻译。

于 2014-10-01T09:01:12.643 回答
0

我已经使用 C++ 的 TCP/IP 通信,并且能够从打印引擎响应。

于 2018-01-10T21:14:37.253 回答