我正在开发一个项目,我们需要使用Zebra打印机来处理条形码标签。 我们正在使用C#,我们在打印方面做得很好,将原始ZPL字符串发送到打印机(使用winspool.drv)。
但是,我们还需要从打印机上读取,没有运气。
我们需要从打印机获取状态,这是ZPL命令“~HS”的输出,因此我们可以判断内存中有多少标签等待打印。 winspool.drv中的EnumJobs()只在Windows假脱机上有作业,一旦它们被发送到打印机,它们就会从该列表中消失。但这并不意味着标签已被打印,因为打印机有一个剥离传感器,并且一次只打印一个标签,我们显然对将批量标签发送到打印机感兴趣。
我尝试过(使用winspool.drv调用):
OpenPrinter(szPrinterName, out hPrinter, IntPtr.Zero);
WritePrinter(hPrinter, pBytes, dwCount, out dwWritten); // send the string "~HS"
ReadPrinter(hPrinter, data, buff, out pcRead);
但我在ReadPrinter调用中什么也得不到。我甚至不知道这是否是正确的方法。
之前有人解决了这个问题吗?
感谢。
答案 0 :(得分:3)
我面临同样的问题。你有没有关于这个问题的任何事情?
Axe Perez Parra Castro,我就这样做了:
- 从这里http://support.microsoft.com/kb/322091
获取RawPrinterHelper类-my printer(zebra 2030)不支持ZPL,所以据我所知,唯一的方法就是向它发送unicode
- 我列出了我需要的字符。
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();
(从en.wikipedia.org/wiki/ASCII获取那些int值)
- 组成命令 - 例如sb.Append(esc + enq + Convert.ToChar(7).ToString());
(来自打印机手册,命令< ESC>< ENQ>< 7>应该获得固件版本)
- 发送命令RawPrinterHelper.SendStringToPrinter(printerName, sb.ToString());
(在我的情况下,printerName是“Zebra TTP 2030”)
答案 1 :(得分:1)
ReadPrinter
无济于事。它将回读您提交给打印机的打印作业,而不是打印机的响应。但是,为了完整起见:要使用ReadPrinter
,您必须使用组合的“打印机名称 - 作业ID”语法打开打印机 :
OpenPrinter("Zebra,Job 12345", ...);
ReadPrinter(hPrinter, ...);
只有在尚未删除作业12345时才能使用此功能。
至于回答问题,您必须使用WriteFile
发送数据,并使用ReadFile
来获取回复。要使用这些功能,您需要使用CreateFile
打开打印机。在你完成之后,其余部分绝对是微不足道的。
此处的问题是获取必须传递给CreateFile
的设备路径才能打开打印机。如果您的打印机是LPT打印机,那就像"LPT:"
一样简单,但对于USB打印机,您必须获得设备路径,如下所示:
\\?\usb#vid_0a5f&pid_0027#46a072900549#{28d78fad-5a12-11d1-ae5b-0000f803a8c2}
我找到了way to obtain this path,但只有在安装了一台打印机的情况下才有效。如果你有更多,你需要设备路径和你在控制面板中看到的打印机名称之间的关系,这种关系是我还没有想到的。我已经为此创建了一个问题:Figuring which printer name corresponds to which device ID。
答案 2 :(得分:0)
大约15年前,我编写了通过Zebra打印机打印的软件。
当我们通过RS-232(?标准串行通讯)与打印机通信时,该打印机运行良好,所有信息都以及时准确的方式从打印机返回。
最近我会使用Epson理货打印机,发现Windows打印机驱动程序笨拙且效率低下。我放下了一个级别并通过GDI直接与打印机通信,一切都令我满意。
我说取出中间人,如果你下降一个级别并直接与打印机通信,而不是通过Windows打印机驱动程序进行通信,你将获得更多的成功。
希望这有帮助,
答案 3 :(得分:0)
如果你有机会使用kernel32.dll
而忽略了usb-driver-bound winspool.srv
,你可以使用这种香草方法:
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)(但我无法判断这是否适用于ZPL / EPL /指纹/ ...打印机)GetPrinter
使用PRINTER_INFO_2
。
还有pinvoke.net available的翻译。
答案 4 :(得分:0)
我使用了与C ++的TCP / IP通信,我能够从打印引擎响应。