2009-12-04 19 views
9

Je travaille sur un projet où nous devons utiliser une imprimante Zebra pour les étiquettes de code à barres. Nous utilisons C#, et nous travaillons bien pour l'impression, en envoyant des chaînes ZPL brutes à l'imprimante (en utilisant winspool.drv).État de lecture de l'imprimante Zebra

Cependant, nous avons également besoin de lire à partir de l'imprimante, et pas de chance là-bas.

Nous devons obtenir le statut de l'imprimante, qui est la sortie de la commande ZPL "~ HS", afin que nous puissions savoir combien d'étiquettes sont en attente de l'impression. EnumJobs() de winspool.drv a uniquement des tâches dans le spool de Windows, et une fois qu'elles sont envoyées à l'imprimante, elles sont supprimées de cette liste. Mais cela ne signifie pas que l'étiquette a été imprimée, car l'imprimante possède un capteur de pelage et imprime seulement une étiquette à la fois, et nous sommes évidemment intéressés à envoyer des lots d'étiquettes à l'imprimante.

J'ai essayé quelque chose comme (en utilisant les appels Winspool.drv):

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

Mais je reçois rien sur l'appel ReadPrinter. Je ne sais même pas si c'est la bonne façon d'y aller.

Quelqu'un là-bas a abordé cela avant?

Merci.

Répondre

1

Il y a environ 15 ans, j'ai écrit un logiciel pour imprimer sur des imprimantes Zebra.

Au moment où nous avons communiqué avec l'imprimante via RS-232 (? Communications série standard), qui a bien fonctionné, toutes les informations sont revenues de l'imprimante en temps opportun et précis.

Récemment, j'ai travaillé avec les imprimantes Epson et j'ai trouvé les pilotes d'imprimante Windows maladroits et inefficaces. J'ai baissé un niveau et communiqué directement avec l'imprimante via GDI, et tout a fonctionné pour ma satisification. Je dis sortir l'homme du milieu, si vous abaissez un niveau et communiquez directement avec l'imprimante, plutôt que de communiquer via les pilotes d'imprimante Windows, vous aurez plus de succès.

Hope this helps,

2

Je suis face au même problème. Avez-vous déjà géré quelque chose sur ce sujet?

Ax Perez Parra Castro, voici comment je l'ai fait:

-get la classe RawPrinterHelper d'ici http://support.microsoft.com/kb/322091

imprimante -mon (Zebra 2030) ne prend pas en charge ZPL, pour autant que je connaître la seule façon est d'envoyer unicode

-J'ai fait une liste de caractères dont j'ai besoin par exemple

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 obtenir ces valeurs de en.wikipedia.org/wiki/ASCII)

-compose la commande - par exemple,sb.Append(esc + enq + Convert.ToChar(7).ToString()); (du manuel de l'imprimante, la commande < ESC> < ENQ> < 7> devrait obtenir la version du firmware)

-send la commande RawPrinterHelper.SendStringToPrinter(printerName, sb.ToString()); (printerName dans mon cas est "Zebra TTP 2030")

+1

et lire? ... c'est ce que cette question est au sujet de ... –

+0

@AndreasNiedermair c'était il y a quelques années, donc je ne me souviens pas des détails. S'il vous plaît voir si ce projet expérimental aide https://www.dropbox.com/s/2h6gj0o08eksbxu/PrintLabel.zip?dl=0 – bfi

1

ReadPrinter ne va pas aider dans cette situation. Il relira le travail d'impression que vous avez envoyé à l'imprimante, et non la réponse de l'imprimante. Cependant, par souci d'exhaustivité: Pour utiliser ReadPrinter, vous devez ouvrir l'imprimante à nouveau, en utilisant le combiné « nom de l'imprimante - id travail » Syntaxe:

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

Cela ne fonctionnera que si le travail 12345 n'a pas encore été supprimé.


Quant à répondre à la question, vous devez utiliser WriteFile pour envoyer des données et ReadFile pour obtenir la réponse. Pour utiliser ces fonctions, vous devez ouvrir l'imprimante avec CreateFile. Après vous avez fait cela, le reste est absolument trivial.

Le problème ici est d'obtenir le chemin de périphérique qui doit être passé à CreateFile afin d'ouvrir l'imprimante. Si votre imprimante est un LPT, qui est aussi simple que "LPT:", mais pour une imprimante USB, vous devez obtenir le chemin de l'appareil, qui ressemble à ceci:

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

J'ai trouvé un way to obtain this path , mais cela ne fonctionne que si vous n'avez qu'une seule imprimante installée. Si vous en avez plus, vous aurez besoin d'une relation entre le chemin de l'appareil et le nom de l'imprimante que vous voyez dans le panneau de contrôle, et cette relation est quelque chose que je n'ai pas encore compris. J'ai créé une question pour cela: Figuring which printer name corresponds to which device ID.

+0

où se trouvent les 'WriteFile' et' ReadFile' - je ne pouvais pas les trouver dans * Winspool .drv * (voir http://msdn.microsoft.com/en-us/library/windows/desktop/dd162861(v=vs.85).aspx) –

+0

Êtes-vous sûr de ne pas pouvoir lire les données avec '. ReadPrinter' ?? http://msdn.microsoft.com/en-us/library/windows/desktop/dd162895(v=vs.85).aspx dit: "La fonction ReadPrinter récupère des données de l'imprimante spécifiée." –

+1

@AndreasNiedermair Oui, il récupère les données de l'imprimante, mais ce sont les données que vous mettez dans cette imprimante vous-même (votre travail d'impression), pas l'imprimante de données peut générer en réponse à l'impression.'WriteFile' et' ReadFile' sont des fonctions Windows générales qui fonctionnent sur de nombreux objets différents y compris les imprimantes, elles sont dans kernel32.dll. – GSerg

0

Si vous avez la chance d'utiliser kernel32.dll et en laissant le pilote USB lié winspool.srv vous pouvez utiliser cette approche de la vanille:

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) (mais je ne peux pas dire si cela fonctionne avec ZPL/EPL/fingerprint/... -printers) qui utilise GetPrinter avec PRINTER_INFO_2. Il y a aussi une traduction à pinvoke.net available.

+0

hmmm! comme solution qui n'est plus disponible. type typique de Microsoft! – AaA

0

J'ai utilisé la communication TCP/IP avec C++, et j'ai été en mesure de répondre à partir du moteur d'impression.