通过 USB 将原始文本发送到打印机
Posted
技术标签:
【中文标题】通过 USB 将原始文本发送到打印机【英文标题】:Sending raw text to printer via usb 【发布时间】:2018-11-16 03:10:31 【问题描述】:我正在尝试将 ZPL 命令发送到 Zebra ZT230 打印机。打印机和驱动程序已安装,打印机端口为“USB003”。 PC 通过 Zebra Printer Setup Utilities 或 ZebraDesign 与打印机完美通信。我尝试了以下代码:
Private Declare Function CreateFile Lib "kernel32.dll" (ByVal lpFileName As String, ByVal dwDesiredAccess As FileAccess, _
ByVal dwShareMode As UInteger, ByVal lpSecurityAttributes As IntPtr, ByVal dwCreationDisposition As FileMode, _
ByVal dwFlagsAndAttributes As UInteger, ByVal hTemplateFile As IntPtr) As System.Runtime.InteropServices.SafeHandle
' Command to be sent to the printer
Dim command As String = "^XA^FO10,10,^AO,30,20^FDFDTesting^FS^FO10,30^BY3^BCN,100,Y,N,N^FDTesting^FS^XZ"
' Create a buffer with the command
Dim buffer() As Byte = New Byte((command.Length) - 1)
buffer = System.Text.Encoding.ASCII.GetBytes(command)
' Use the CreateFile external func to connect to the LPT1 port
Dim printer As System.Runtime.InteropServices.SafeHandle = CreateFile("USB003:", FileAccess.ReadWrite, 0, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero)
' Aqui verifico se a impressora � v�lida
If (printer.IsInvalid = true) Then
Return
End If
' Open the filestream to the lpt1 port and send the command
Dim lpt1 As FileStream = New FileStream(printer, FileAccess.ReadWrite)
lpt1.Write(buffer, 0, buffer.Length)
' Close the FileStream connection
lpt1.Close
我在这一行得到一个错误: 昏暗打印机 As System.Runtime.InteropServices.SafeHandle = CreateFile("USB003:", FileAccess.ReadWrite, 0, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero)
错误信息和堆栈跟踪是:
无法封送“返回值”:返回的 SafeHandles 不能是抽象的。
在 PerfectPotatoInventory.vb.PotatoGlobals.CreateFile(String& lpFileName, FileAccess dwDesiredAccess, UInt32 dwShareMode, IntPtr lpSecurityAttributes, FileMode dwCreationDisposition, UInt32 dwFlagsAndAttributes, IntPtr hTemplateFile) 在 PerfectPotatoInventory.vb.PotatoGlobals.PrintLabelsTest() 在 C:\Potatoes\PerfectPotatoInventory.vb\PerfectPotatoInventory.vb\PotatoGlobals.vb:line 798
我正在使用带有目标 x86 和 .Net 3.5 的 VS2008 在 VB.net 中工作。
请指教我做错了什么。
【问题讨论】:
查看SafeFileHandle Class的示例。 【参考方案1】:将此类添加到您的项目中
Imports System.IO
Imports System.Drawing.Printing
Imports System.Runtime.InteropServices
Public Class RAWPOSPrinter
' Structure and API declarions:
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
Structure DOCINFOW
<MarshalAs(UnmanagedType.LPWStr)> Public pDocName As String
<MarshalAs(UnmanagedType.LPWStr)> Public pOutputFile As String
<MarshalAs(UnmanagedType.LPWStr)> Public pDataType As String
End Structure
<DllImport("winspool.Drv", EntryPoint:="OpenPrinterW", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function OpenPrinter(ByVal src As String, ByRef hPrinter As IntPtr, ByVal pd As Long) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="ClosePrinter", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function ClosePrinter(ByVal hPrinter As IntPtr) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="StartDocPrinterW", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function StartDocPrinter(ByVal hPrinter As IntPtr, ByVal level As Int32, ByRef pDI As DOCINFOW) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="EndDocPrinter", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function EndDocPrinter(ByVal hPrinter As IntPtr) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="StartPagePrinter", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function StartPagePrinter(ByVal hPrinter As IntPtr) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="EndPagePrinter", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function EndPagePrinter(ByVal hPrinter As IntPtr) As Boolean
End Function
<DllImport("winspool.Drv", EntryPoint:="WritePrinter", _
SetLastError:=True, CharSet:=CharSet.Unicode, _
ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function WritePrinter(ByVal hPrinter As IntPtr, ByVal pBytes As IntPtr, ByVal dwCount As Int32, ByRef dwWritten As Int32) As Boolean
End Function
' SendBytesToPrinter()
' When the function is given a printer name and an unmanaged array of
' bytes, the function sends those bytes to the print queue.
' Returns True on success or False on failure.
Public Shared Function SendBytesToPrinter(ByVal szPrinterName As String, ByVal pBytes As IntPtr, ByVal dwCount As Int32) As Boolean
Dim hPrinter As IntPtr ' The printer handle.
Dim dwError As Int32 ' Last error - in case there was trouble.
Dim di As DOCINFOW ' Describes your document (name, port, data type).
Dim dwWritten As Int32 ' The number of bytes written by WritePrinter().
Dim bSuccess As Boolean ' Your success code.
' Set up the DOCINFO structure.
di = New DOCINFOW
With di
.pDocName = "RAW DOC"
.pDataType = "RAW"
End With
' Assume failure unless you specifically succeed.
bSuccess = False
If OpenPrinter(szPrinterName, hPrinter, 0) Then
If StartDocPrinter(hPrinter, 1, di) Then
If StartPagePrinter(hPrinter) Then
' Write your printer-specific bytes to the printer.
bSuccess = WritePrinter(hPrinter, pBytes, dwCount, dwWritten)
EndPagePrinter(hPrinter)
End If
EndDocPrinter(hPrinter)
End If
ClosePrinter(hPrinter)
End If
' If you did not succeed, GetLastError may give more information
' about why not.
If bSuccess = False Then
dwError = Marshal.GetLastWin32Error()
End If
Return bSuccess
End Function ' SendBytesToPrinter()
' SendFileToPrinter()
' When the function is given a file name and a printer name,
' the function reads the contents of the file and sends the
' contents to the printer.
' Presumes that the file contains printer-ready data.
' Shows how to use the SendBytesToPrinter function.
' Returns True on success or False on failure.
Public Shared Function SendFileToPrinter(ByVal szPrinterName As String, ByVal szFileName As String) As Boolean
' Open the file.
Dim fs As New FileStream(szFileName, FileMode.Open)
' Create a BinaryReader on the file.
Dim br As New BinaryReader(fs)
' Dim an array of bytes large enough to hold the file's contents.
Dim bytes(fs.Length) As Byte
Dim bSuccess As Boolean
' Your unmanaged pointer.
Dim pUnmanagedBytes As IntPtr
' Read the contents of the file into the array.
bytes = br.ReadBytes(fs.Length)
' Allocate some unmanaged memory for those bytes.
pUnmanagedBytes = Marshal.AllocCoTaskMem(fs.Length)
' Copy the managed byte array into the unmanaged array.
Marshal.Copy(bytes, 0, pUnmanagedBytes, fs.Length)
' Send the unmanaged bytes to the printer.
bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, fs.Length)
' Free the unmanaged memory that you allocated earlier.
Marshal.FreeCoTaskMem(pUnmanagedBytes)
Return bSuccess
End Function ' SendFileToPrinter()
' When the function is given a string and a printer name,
' the function sends the string to the printer as raw bytes.
Public Shared Sub SendStringToPrinter(ByVal szPrinterName As String, ByVal szString As String)
Dim pBytes As IntPtr
Dim dwCount As Int32
' How many characters are in the string?
dwCount = szString.Length()
' Assume that the printer is expecting ANSI text, and then convert
' the string to ANSI text.
pBytes = Marshal.StringToCoTaskMemAnsi(szString)
' Send the converted ANSI string to the printer.
SendBytesToPrinter(szPrinterName, pBytes, dwCount)
Marshal.FreeCoTaskMem(pBytes)
End Sub
End Class
然后在您的代码中,调用以下代码:
RAWPOSPrinter.SendStringToPrinter("<NAME OF PRINTER AS IT APPEARS IN DEVICES AND PRINTERS>", "<YOUR ZEBRA COMMAND STRING>")
【讨论】:
【参考方案2】:使用 Zebra .Net SDK,您可以调用以下函数: PrinterUtil.SendContents 方法(字符串,字符串)
第一个字符串是要发送的 ZPL,第二个字符串是打印机连接字符串。更多细节可以在这里找到: http://techdocs.zebra.com/link-os/2-14/pc_net/
【讨论】:
SDK是否兼容VS2008、x86和.Net 3.5? 由于我只需要发送 ZPL 字符串,我更喜欢基于发布的代码的简单方法。 强大的 Link-OS® 多平台软件开发套件支持在 PC、智能手机和平板电脑上创建应用程序,支持最流行的操作系统。 Link-OS SDK 使创建功能强大的应用程序变得简单直接。多平台 SDK 支持:Java、Objective C、VB、C# 和 .NET 适用于 ios 和 android Link-OS 打印机和 ZC 系列证卡打印机的 Xamarin 跨平台开发工具集 我的错误自述文件指出 Microsoft™ .NET Framework 4.7(或更高版本) 这就是我所害怕的。以上是关于通过 USB 将原始文本发送到打印机的主要内容,如果未能解决你的问题,请参考以下文章
通过 PrintServer 将原始 ZPL 发送到 Zebra 打印机不起作用
使用Visual Basic将原始数据发送到ZPL打印机(MS Access 2000)