Чтение статуса с принтера Zebra - PullRequest
12 голосов
/ 04 декабря 2009

Я работаю над проектом, в котором нам нужно использовать принтер Zebra для этикеток со штрих-кодом. Мы используем C #, и мы хорошо работаем над печатью, отправляя необработанные строки ZPL на принтер (используя winspool.drv).

Однако нам также нужно читать с принтера, и не повезло.

Нам нужно получить статус от принтера, который является выводом команды ZPL "~ HS", чтобы мы могли определить, сколько этикеток находится в памяти и ожидает печати. У EnumJobs () из winspool.drv есть только задания на буфере 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 ]

3 голосов
/ 01 июня 2010

Я столкнулся с той же проблемой. Вы уже успели что-нибудь по этому вопросу?

Axe Perez Parra Castro, вот как я это сделал:

- получите класс RawPrinterHelper отсюда http://support.microsoft.com/kb/322091

-Мой принтер (Zebra 2030) не поддерживает ZPL, поэтому, насколько я знаю, единственный способ - это отправить на него юникод

-Я составил список нужных мне символов, например

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();

(получить значения int из en.wikipedia.org/wiki/ASCII)

- составить команду - например, sb.Append(esc + enq + Convert.ToChar(7).ToString()); (из руководства по принтеру команда <7> должна получить версию прошивки)

- отправить команду RawPrinterHelper.SendStringToPrinter(printerName, sb.ToString()); (имя принтера в моем случае - «Zebra TTP 2030»)

1 голос
/ 19 мая 2012

ReadPrinter не поможет в этой ситуации. Он прочитает задание на печать, отправленное вами на принтер, а не ответ принтера. Однако для полноты картины: для использования ReadPrinter необходимо снова открыть принтер , используя комбинированный синтаксис «имя принтера - идентификатор задания»:

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}

Я нашел способ получить этот путь , но он работает, только если у вас установлен только один принтер. Если у вас есть больше, вам понадобится связь между путем к устройству и именем принтера, которое вы видите на панели управления, и это отношение я пока не понял. Я создал для этого вопрос: Определение того, какое имя принтера соответствует какому идентификатору устройства .

0 голосов
/ 11 января 2018

Я использовал TCP / IP-связь с C ++, и мне удалось ответить из механизма печати.

0 голосов
/ 01 октября 2014

Если у вас есть возможность использовать kernel32.dll и не использовать привязку к USB-драйверу 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
            };
        }
    }
}

В противном случае доступно решение (хотя это VB.NET) (но я не могу сказать, работает ли оно с ZPL / EPL / fingerprint /...- принтерами), которое использует GetPrinter с PRINTER_INFO_2.
Также доступен перевод на pinvoke.net .

0 голосов
/ 04 декабря 2009

Около 15 лет назад я написал программное обеспечение для печати на принтерах Zebra.

В то время, когда мы общались с принтером по RS-232 (? Стандартная последовательная связь), который работал хорошо, вся информация возвращалась с принтера своевременно и точно.

Недавно я поработал с принтерами Epson и обнаружил, что драйверы для Windows-принтеров неуклюжи и неэффективны. Я опустил уровень и связался напрямую с принтером через GDI, и все работало на мое удовлетворение.

Я говорю, убери посредника, если ты опустишь уровень и свяжешься с принтером напрямую, а не через драйверы принтера Windows, у тебя будет больше успеха.

Надеюсь, это поможет,

...