2009-12-04 9 views
9

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

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

Wir müssen den Status vom Drucker abrufen, der die Ausgabe an den ZPL-Befehl "~ HS" ist, damit wir feststellen können, wie viele Etiketten im Speicher warten, um gedruckt zu werden. Die EnumJobs() von winspool.drv hat nur Aufträge auf der Windows-Spool, und sobald sie an den Drucker gesendet werden, sind sie aus dieser Liste gegangen. Aber das bedeutet nicht, dass das Etikett gedruckt wurde, da der Drucker einen Schälsensor hat und nur ein Etikett nach dem anderen druckt, und wir sind natürlich daran interessiert, Etikettenschätze an den Drucker zu senden.

Ich habe so etwas wie (mit den winspool.drv Anrufe) versucht:

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

Aber ich habe nichts auf dem ReadPrinter Anruf. Ich weiß nicht einmal, ob das der richtige Weg ist.

Jemand da draußen hat das schon mal angepackt?

Danke.

Antwort

1

Vor etwa 15 Jahren habe ich Software geschrieben, um Zebra-Drucker zu drucken.

Zu der Zeit, als wir mit dem Drucker über RS-232 (? Standard serielle Kommunikation) kommunizierten, was gut funktionierte, kamen alle Informationen zeitnah und genau vom Drucker zurück.

Vor kurzem würde ich mit Epson Tally-Drucker arbeiten, und fand die Windows-Druckertreiber unbeholfen und ineffizient. Ich ließ ein Level herunter und kommunizierte direkt mit dem Drucker über GDI, und alles funktionierte zu meiner Zufriedenheit.

Ich sage, nehmen Sie den mittleren Mann, wenn Sie eine Ebene herunter und kommunizieren mit dem Drucker direkt, anstatt über Windows-Druckertreiber kommunizieren, werden Sie mehr Erfolg haben.

hoffe, das hilft,

2

Ich bin vor dem gleichen Problem. Hast du schon etwas zu diesem Thema geschafft?

Ax Perez Parra Castro, das ist, wie ich es tat:

-get der RawPrinterHelper Klasse von hier http://support.microsoft.com/kb/322091

-my Drucker (Zebra 2030) nicht ZPL unterstützen, so weit, wie ich weiß der einzige Weg ist, Unicode zu senden

-Ich habe eine Liste von Zeichen, 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(); 

(erhalten diejenigen Werte von en.wikipedia.org/wiki/ASCII int)

-compose dem Befehl - zsb.Append(esc + enq + Convert.ToChar(7).ToString()); (aus dem Druckerhandbuch, den Befehl < ESC> < ENQ> < 7> sollte die Firmware-Version erhalten)

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

+1

und lesen? ... darum geht es bei dieser Frage ... –

+0

@AndreasNiedermair es war vor ein paar Jahren, so dass ich mich nicht an die Details erinnere. Bitte sehen Sie, ob dieses experimentelle Projekt https://www.dropbox.com/s/2h6gj0o08eksbxu/PrintLabel.zip?dl=0 – bfi

1

ReadPrinter wird in dieser Situation nicht helfen. Es liest den Druckauftrag zurück, den Sie an den Drucker gesendet haben, nicht die Antwort des Druckers. Doch für die der Vollständigkeit halber: Um ReadPrinter zu verwenden, müssen Sie den Drucker öffnen wieder, mit dem kombinierten „Druckername - Job-ID“ Syntax:

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

Dies wird nur 12345, wenn der Job arbeiten wurde noch nicht entfernt.


Was die Frage zu beantworten, müssen Sie WriteFile verwenden, um Daten zu senden und zu ReadFile die Antwort zu bekommen. Um diese Funktionen zu verwenden, müssen Sie den Drucker mit CreateFile öffnen. Nachdem Sie das getan haben, ist der Rest absolut trivial.

Das Problem hier ist, den Gerätepfad zu erhalten, der an CreateFile weitergegeben werden muss, um den Drucker zu öffnen. Wenn der Drucker eine LPT ist, das ist so einfach wie "LPT:", aber für einen USB-Drucker müssen Sie den Gerätepfad zu erhalten, die wie folgt aussieht:

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

ich gefunden habe, ein way to obtain this path , aber es funktioniert nur, wenn Sie nur einen Drucker installiert haben. Wenn Sie mehr haben, benötigen Sie eine Beziehung zwischen dem Gerätepfad und dem Druckernamen, den Sie in der Systemsteuerung sehen, und diese Beziehung ist etwas, was ich noch nicht gedacht habe. Ich habe eine Frage dazu erstellt: Figuring which printer name corresponds to which device ID.

+0

hilft, wo sich 'WriteFile' und' ReadFile' befinden - ich konnte sie in * winspool nicht finden .drv * (siehe http://msdn.microsoft.com/en-us/library/windows/desktop/dd162861(v=vs.85).aspx) –

+0

sind Sie sicher, dass Sie keine Daten mit 'lesen können. ReadPrinter' http://msdn.microsoft.com/en-us/library/windows/desktop/dd162895(v=vs.85).aspx sagt: "Die ReadPrinter-Funktion ruft Daten vom angegebenen Drucker ab." –

+1

@AndreasNiedermair Ja, es ruft Daten vom Drucker ab, aber es sind die Daten, die Sie selbst in diesen Drucker einlegen (Ihren Druckauftrag), nicht den Datendrucker, der als Antwort auf den Druckauftrag erzeugt wird.'WriteFile' und' ReadFile' sind allgemeine Windows-Funktionen, die auf vielen verschiedenen Objekten einschließlich Druckern arbeiten, sie sind in kernel32.dll. – GSerg

0

Wenn Sie die Chance haben kernel32.dll zu verwenden und das Weglassen der usb-Fahrer gebundene winspool.srv Sie diesen Vanille-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 
      }; 
     } 
    } 
} 

Otherwise there's a solution available (it's VB.NET though) (aber ich kann nicht sagen, ob dies mit ZPL Werken/EPL/fingerprint/...- Drucker), die GetPrinter mit PRINTER_INFO_2 verwendet.
Es gibt auch eine Übersetzung unter pinvoke.net available.

+0

hmmm! als Lösung, die nicht mehr verfügbar ist. typische Art von Microsoft! – AaA

0

Ich habe TCP/IP-Kommunikation mit C++ verwendet, und ich konnte von der Druck-Engine reagieren.