2009-12-04 33 views
9

sto lavorando su un progetto in cui abbiamo bisogno di usare una stampante Zebra per codici a barre. Stiamo usando C# e stiamo facendo bene sul lato stampa, inviando stringhe ZPL non formattate alla stampante (usando winspool.drv).stato Lettura da Zebra stampante

Tuttavia, abbiamo anche bisogno di leggere dalla stampante, e senza fortuna lì.

Abbiamo bisogno di ottenere lo stato dalla stampante, che è l'output del comando ZPL "~ HS", in modo che possiamo dire quante etichette sono in memoria in attesa di essere stampati. I EnumJobs() da winspool.drv ha solo posti di lavoro alle finestre spool, e una volta che sono inviati alla stampante, se ne sono andati da quella lista. Ma questo non significa che l'etichetta sia stata stampata, dal momento che la stampante ha un sensore di distacco e stampa solo un'etichetta alla volta, e ovviamente siamo interessati a inviare lotti di etichette alla stampante.

ho provato qualcosa di simile (utilizzando le chiamate Winspool.drv):

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

ma ottengo nulla sulla chiamata ReadPrinter. Non so nemmeno se questo sia il modo giusto di affrontarlo.

Qualcuno là fuori affrontato prima?

Grazie.

risposta

1

Circa 15 anni fa ho scritto software per stampare throught stampanti Zebra.

Al momento della comunicazione con la stampante su RS-232 (? Comunicazioni seriali standard), che funzionava bene, tutte le informazioni venivano restituite dalla stampante in modo tempestivo e accurato.

Recentemente mi piacerebbe lavorare con le stampanti Epson tally, e abbiamo trovato il driver della stampante Windows goffo ed inefficiente. Ho abbassato un livello e comunicato direttamente con la stampante tramite GDI, e tutto ha funzionato per la mia soddisfazione.

Dico portare fuori l'uomo di mezzo, se abbassi un livello e comunichi direttamente con la stampante, piuttosto che comunicare tramite i driver di stampa di Windows, avrai più successo.

Spero che questo aiuti,

2

sto affrontando lo stesso problema. Hai già gestito qualcosa su questo argomento?

Ax Perez Parra Castro, questo è come ho fatto:

-get classe RawPrinterHelper da qui http://support.microsoft.com/kb/322091

stampante -my (zebra 2030) non supporta ZPL, quindi per quanto mi sapere che l'unico modo è inviare un unicode

-ho fatto una lista di caratteri che mi servono ad es.

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

(ottenere tali valori int da en.wikipedia.org/wiki/ASCII)

-compose il comando - esempiosb.Append(esc + enq + Convert.ToChar(7).ToString()); (dal manuale della stampante, il comando < ESC> < ENQ> < 7> dovrebbe ottenere la versione del firmware)

-Inviare il comando RawPrinterHelper.SendStringToPrinter(printerName, sb.ToString()); (printerName nel mio caso è "Zebra TTP 2030")

+1

e lettura? ... questo è ciò che riguarda questa domanda ... –

+0

@AndreasNiedermair è stato qualche anno fa, quindi non ricordo i dettagli. Si prega di vedere se questo progetto sperimentale aiuta https://www.dropbox.com/s/2h6gj0o08eksbxu/PrintLabel.zip?dl=0 – bfi

1

ReadPrinter non aiuterà in questa situazione. Rileggerà il lavoro di stampa inviato alla stampante, non la risposta della stampante. Tuttavia, per ragioni di completezza: Per poter utilizzare ReadPrinter, è necessario aprire la stampante nuovo, utilizzando il combinato "nome della stampante - id lavoro" Sintassi:

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

questo funziona solo se il lavoro 12345 non è stato ancora rimosso


Come per rispondere alla domanda, è necessario utilizzare WriteFile per inviare i dati e ReadFile per ottenere la risposta. Per utilizzare queste funzioni, è necessario aprire la stampante con CreateFile. Dopo averlo fatto, il resto è assolutamente banale.

Il problema qui è ottenere il percorso del dispositivo che deve essere passato a CreateFile per aprire la stampante. Se la stampante è uno LPT, che è così semplice come "LPT:", ma per una stampante USB è necessario ottenere il percorso del dispositivo, che assomiglia a questo:

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

ho trovato un way to obtain this path , ma funziona solo se hai una sola stampante installata. Se ne hai di più, avrai bisogno di una relazione tra il percorso del dispositivo e il nome della stampante che vedi nel pannello di controllo, e quella relazione è qualcosa che non ho ancora capito. Ho creato una domanda per questo: Figuring which printer name corresponds to which device ID.

+0

dove si trovano 'WriteFile' e' ReadFile' - Non sono riuscito a trovarli in * winspool .drv * (vedi http://msdn.microsoft.com/en-us/library/windows/desktop/dd162861(v=vs.85).aspx) –

+0

sei sicuro di non poter leggere i dati con '. ReadPrinter' ?? http://msdn.microsoft.com/en-us/library/windows/desktop/dd162895(v=vs.85).aspx dice: "La funzione ReadPrinter recupera i dati dalla stampante specificata." –

+1

@AndreasNiedermair Sì, recupera i dati dalla stampante, ma sono i dati che hai inserito in quella stampante (il tuo lavoro di stampa), non la stampante di dati potrebbe generare in risposta al lavoro di stampa.'WriteFile' e' ReadFile' sono funzioni di Windows per scopi generali che funzionano su molti oggetti diversi, incluse le stampanti, sono in kernel32.dll. – GSerg

0

Se avete la possibilità di utilizzare kernel32.dll e tralasciando il driver USB-bound winspool.srv si potrebbe usare questo approccio alla vaniglia:

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) (ma non posso dire se questo funziona con ZPL/Stampanti EPL/impronte digitali /...-) che utilizza GetPrinter con PRINTER_INFO_2.
C'è anche una traduzione allo pinvoke.net available.

+0

hmmm! come soluzione che non è più disponibile. tipico tipo di microsoft! – AaA

0

Ho usato la comunicazione TCP/IP con C++ e sono stato in grado di rispondere dal motore di stampa.