13 Stimmen

Status vom Zebra-Drucker lesen

Ich arbeite an einem Projekt, bei dem wir einen Zebra-Drucker für Barcode-Etiketten verwenden müssen. Wir verwenden C#, und wir tun OK auf der Druckseite der Dinge, senden rohe ZPL-Strings an den Drucker (mit winspool.drv).

Allerdings müssen wir auch vom Drucker lesen, und da haben wir kein Glück.

Wir müssen den Status des Druckers abfragen, d. h. die Ausgabe des ZPL-Befehls "~HS", damit wir wissen, wie viele Etiketten im Speicher auf den Druck warten. Die Funktion EnumJobs() aus winspool.drv enthält nur Aufträge, die sich in der Windows-Spool befinden, und sobald sie an den Drucker gesendet wurden, verschwinden sie aus dieser Liste. Das bedeutet jedoch nicht, dass das Etikett gedruckt wurde, da der Drucker einen Abziehsensor hat und jeweils nur ein Etikett druckt, und wir offensichtlich daran interessiert sind, Stapel von Etiketten an den Drucker zu senden.

Ich habe etwas Ähnliches versucht (unter Verwendung der winspool.drv-Aufrufe):

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

Aber beim Aufruf von ReadPrinter erhalte ich nichts. Ich weiß nicht einmal, ob das der richtige Weg ist.

Hat sich jemand schon einmal mit diesem Thema beschäftigt?

Danke.

3voto

bfi Punkte 289

Ich stehe vor dem gleichen Problem. Haben Sie schon etwas zu diesem Thema erreicht?

Ax Perez Parra Castro, so habe ich es gemacht:

die RawPrinterHelper-Klasse von hier beziehen http://support.microsoft.com/kb/322091

-Mein Drucker (Zebra 2030) unterstützt ZPL nicht. Soweit ich weiß, ist die einzige Möglichkeit, Unicode an ihn zu senden.

-Ich habe eine Liste von Zeichen erstellt, die ich brauche, z. B.

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

(diese int-Werte stammen aus de.wikipedia.org/wiki/ASCII)

-Komposition des Befehls - z.B. sb.Append(esc + enq + Convert.ToChar(7).ToString()); (aus dem Druckerhandbuch, der Befehl < ESC>< ENQ><7> sollte die Firmware-Version ermitteln)

-Senden Sie den Befehl RawPrinterHelper.SendStringToPrinter(printerName, sb.ToString()); (Druckername ist in meinem Fall "Zebra TTP 2030")

0 Stimmen

@AndreasNiedermair es ist schon ein paar Jahre her, daher kann ich mich nicht mehr an die Details erinnern. Bitte schauen Sie, ob dieses experimentelle Projekt hilft dropbox.com/s/2h6gj0o08eksbxu/PrintLabel.zip?dl=0

1voto

GSerg Punkte 73326

ReadPrinter wird in dieser Situation nicht helfen. Er liest den Druckauftrag zurück, den Sie an den Drucker übermittelt haben, und nicht die Antwort des Druckers. Der Vollständigkeit halber sei gesagt, dass Zur Verwendung von ReadPrinter müssen Sie den Drucker öffnen. wieder unter Verwendung der kombinierten Syntax "Druckername - Auftragskennung":

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

Dies funktioniert nur, wenn der Auftrag 12345 noch nicht gelöscht wurde.


Um die Frage zu beantworten, müssen Sie WriteFile um Daten zu senden und ReadFile um die Antwort zu erhalten. Um diese Funktionen zu nutzen, müssen Sie den Drucker mit CreateFile . Wenn Sie das getan haben, ist der Rest absolut trivial.

Das Problem ist hier, den Gerätepfad zu erhalten, der an CreateFile um den Drucker zu öffnen. Wenn Ihr Drucker ein LPT-Drucker ist, ist das so einfach wie "LPT:" Für einen USB-Drucker müssen Sie jedoch den Gerätepfad ermitteln, der wie folgt aussieht:

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

Ich habe eine Weg, um diesen Pfad zu erhalten aber das funktioniert nur, wenn Sie nur einen Drucker installiert haben. Wenn Sie mehrere haben, brauchen Sie eine Beziehung zwischen dem Gerätepfad und dem Druckernamen, den Sie in der Systemsteuerung sehen, und diese Beziehung habe ich noch nicht herausgefunden. Ich habe dazu eine Frage erstellt: Herausfinden, welcher Druckername welcher Geräte-ID entspricht .

0 Stimmen

Wo sind die WriteFile et ReadFile gefunden - ich konnte sie nicht finden in winspool.drv (siehe msdn.microsoft.com/de-us/library/Windows/desktop/ )

0 Stimmen

Sind Sie sicher, dass Sie keine Daten lesen können mit .ReadPrinter ?? msdn.microsoft.com/de-us/library/Windows/desktop/ heißt es: "Die Funktion ReadPrinter holt Daten vom angegebenen Drucker ab."

1 Stimmen

@AndreasNiedermair Ja, es werden Daten vom Drucker abgerufen, aber es sind die Daten, die Sie selbst in den Drucker eingegeben haben (Ihr Druckauftrag), nicht die Daten, die der Drucker möglicherweise als Reaktion auf den Druckauftrag erzeugt. WriteFile et ReadFile sind allgemeine Windows-Funktionen, die mit vielen verschiedenen Objekten, einschließlich Druckern, arbeiten. Sie befinden sich in kernel32.dll.

0voto

Binary Worrier Punkte 49250

Vor etwa 15 Jahren schrieb ich eine Software zum Drucken mit Zebra-Druckern.

Damals kommunizierten wir mit dem Drucker über RS-232 (? standardmäßige serielle Kommunikation), was gut funktionierte, da alle Informationen zeitnah und genau vom Drucker zurückkamen.

Kürzlich musste ich mit Epson-Tally-Druckern arbeiten und fand die Windows-Druckertreiber schwerfällig und ineffizient. Ich ging eine Stufe tiefer und kommunizierte direkt mit dem Drucker über GDI, und alles funktionierte zu meiner Zufriedenheit.

Wenn Sie eine Ebene tiefer gehen und direkt mit dem Drucker kommunizieren, anstatt über Windows-Druckertreiber, werden Sie mehr Erfolg haben.

Ich hoffe, das hilft,

0voto

Wenn Sie die Möglichkeit haben, die kernel32.dll und das Weglassen der Usb-Treiber-gebundenen winspool.srv können Sie diesen Vanilla-Ansatz verwenden:

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
            };
        }
    }
}

Ansonsten gibt es eine Lösung (allerdings in VB.NET) (aber ich kann nicht sagen, ob dies mit ZPL/EPL/Fingerprint/...-Druckern funktioniert), die die GetPrinter con PRINTER_INFO_2 .
Es gibt auch eine Übersetzung unter pinvoke.net verfügbar .

0 Stimmen

Hmmm! als lösung die nicht mehr verfügbar ist. typisch microsoft!

-1voto

Vivek Punkte 235

Ich habe TCP/IP-Kommunikation mit C++ verwendet, und ich war in der Lage, von der Druckmaschine zu antworten.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X