I\'m working on a project where we need to use a Zebra Printer for barcode labels. We\'re using C#, and we\'re doing OK on the printing side of things, sending raw ZPL stri
If you have the chance to use kernel32.dll
and leaving out the usb-driver-bound winspool.srv
you could use this vanilla approach:
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) (but I can't tell if this works with ZPL/EPL/fingerprint/...-printers) which uses GetPrinter with PRINTER_INFO_2
.
There's also a translation at pinvoke.net available.