2010-01-11 122 views
36

有沒有辦法在.NET中將ZPL(Zebra編程語言)發送到打印機?將ZPL發送到Zebra打印機的.NET代碼

我有代碼來做到這一點在德爾福,但它不是很漂亮,我寧願不嘗試在.NET中重新創建它,因爲它是。

+3

30k意見?人們必須像我一樣,想知道ZPL是什麼:)。 – kristianp 2014-07-24 07:56:55

+3

@kristianp任何曾經在零售軟件上工作的人遲早會與ZPL爭鬥; – Vedran 2015-06-01 07:27:51

+0

零售或工業/製造印刷 – StingyJack 2017-07-07 18:25:23

回答

11

看看這個帖子:Print ZPL codes to ZEBRA printer using PrintDocument class

具體的OP挑這個功能從答案的線索:

[DllImport("kernel32.dll", SetLastError = true)] 
static extern SafeFileHandle CreateFile(string lpFileName, FileAccess dwDesiredAccess, 
uint dwShareMode, IntPtr lpSecurityAttributes, FileMode dwCreationDisposition, 
uint dwFlagsAndAttributes, IntPtr hTemplateFile); 

private void Print() 
{ 
    // Command to be sent to the printer 
    string command = "^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 
    Byte[] buffer = new byte[command.Length]; 
    buffer = System.Text.Encoding.ASCII.GetBytes(command); 
    // Use the CreateFile external func to connect to the LPT1 port 
    SafeFileHandle printer = CreateFile("LPT1:", FileAccess.ReadWrite, 0, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero); 
    // Aqui verifico se a impressora é válida 
    if (printer.IsInvalid == true) 
    { 
     return; 
    } 

    // Open the filestream to the lpt1 port and send the command 
    FileStream lpt1 = new FileStream(printer, FileAccess.ReadWrite); 
    lpt1.Write(buffer, 0, buffer.Length); 
    // Close the FileStream connection 
    lpt1.Close(); 

} 
+1

對於非Eng符號的支持,必須使用UTF16 BE編碼。 – Alexufo 2014-05-13 07:13:10

+0

是否需要爲此方法安裝打印機驅動程序? – 2015-10-07 15:54:02

9

我管理的項目,與插座做了多年。 Zebra通常使用6101端口。我會查看代碼併發布我可以做的。

public void SendData(string zpl) 
{ 
    NetworkStream ns = null; 
    Socket socket = null; 

    try 
    { 
     if (printerIP == null) 
     { 
      /* IP is a string property for the printer's IP address. */ 
      /* 6101 is the common port of all our Zebra printers. */ 
      printerIP = new IPEndPoint(IPAddress.Parse(IP), 6101); 
     } 

     socket = new Socket(AddressFamily.InterNetwork, 
      SocketType.Stream, 
      ProtocolType.Tcp); 
     socket.Connect(printerIP); 

     ns = new NetworkStream(socket); 

     byte[] toSend = Encoding.ASCII.GetBytes(zpl); 
     ns.Write(toSend, 0, toSend.Length); 
    } 
    finally 
    { 
     if (ns != null) 
      ns.Close(); 

     if (socket != null && socket.Connected) 
      socket.Close(); 
    } 
} 
+4

Zebra移動打印機使用端口6101(QL,RW,MZ等)。較大的打印機通常使用端口9100. – 2010-02-08 21:22:10

+1

我在一個簡單的控制檯應用程序中使用此代碼打印到Zebra LP 2844 Z.我不得不將端口更改爲9100. – Monroecheeseman 2011-02-17 19:25:45

6

因爲在C#和ZPL的搜索結果中仍然顯示出高位,所以應該提到SharpZebra。這只是EPL2,但我提交了一個update,它增加了ZPL支持以及通過套接字打印,Windows打印服務和直接USB打印。

2

VB版(使用端口9100 - 使用Zebra ZM400測試)

Sub PrintZPL(ByVal pIP As String, ByVal psZPL As String) 
    Dim lAddress As Net.IPEndPoint 
    Dim lSocket As System.Net.Sockets.Socket = Nothing 
    Dim lNetStream As System.Net.Sockets.NetworkStream = Nothing 
    Dim lBytes As Byte() 

    Try 
     lAddress = New Net.IPEndPoint(Net.IPAddress.Parse(pIP), 9100) 
     lSocket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, _      ProtocolType.Tcp) 
     lSocket.Connect(lAddress) 
     lNetStream = New NetworkStream(lSocket) 

     lBytes = System.Text.Encoding.ASCII.GetBytes(psZPL) 
     lNetStream.Write(lBytes, 0, lBytes.Length) 
    Catch ex As Exception When Not App.Debugging 
     Msgbox ex.message & vbnewline & ex.tostring 
    Finally 
     If Not lNetStream Is Nothing Then 
      lNetStream.Close() 
     End If 
     If Not lSocket Is Nothing Then 
      lSocket.Close() 
     End If 
    End Try 
End Sub 
0

我用的這兩個

Private Sub sendData(ByVal zpl As String) 
    Dim ns As System.Net.Sockets.NetworkStream = Nothing 
    Dim socket As System.Net.Sockets.Socket = Nothing 
    Dim printerIP As Net.IPEndPoint = Nothing 
    Dim toSend As Byte() 

    Try 
     If printerIP Is Nothing Then 
      'set the IP address 
      printerIP = New Net.IPEndPoint(IPAddress.Parse(IP_ADDRESS), 9100) 
     End If 

     'Create a TCP socket 
     socket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) 
     'Connect to the printer based on the IP address 
     socket.Connect(printerIP) 
     'create a new network stream based on the socket connection 
     ns = New NetworkStream(socket) 

     'convert the zpl command to a byte array 
     toSend = System.Text.Encoding.ASCII.GetBytes(zpl) 

     'send the zpl byte array over the networkstream to the connected printer 
     ns.Write(toSend, 0, toSend.Length) 

    Catch ex As Exception 
     MessageBox.Show(ex.Message, "Cable Printer", MessageBoxButtons.OKCancel, MessageBoxIcon.Error) 
    Finally 
     'close the networkstream and then the socket 
     If Not ns Is Nothing Then 
      ns.Close() 
     End If 

     If Not socket Is Nothing Then 
      socket.Close() 
     End If 
    End Try 
End Sub 


Private Function createString() As String 
    Dim command As String 

    command = "^XA" 
    command += "^LH20,25" 

    If rdoSmall.Checked = True Then 
     command += "^FO1,30^A0,N,25,25^FD" 
    ElseIf rdoNormal.Checked = True Then 
     command += "^FO1,30^A0,N,35,35^FD" 
    Else 
     command += "^FO1,30^A0,N,50,50^FD" 
    End If 

    command += txtInput.Text 
    command += "^FS" 
    command += "^XZ" 

    Return command 

End Function 
32

這樣的組合,你將能夠發送ZPL到打印機沒有不管它是如何連接(LPTUSB網絡共享 ...)

(上How to send raw data to a printer by using Visual C# .NET從微軟的文章)創建RawPrinterHelper類:

using System; 
using System.Drawing; 
using System.Drawing.Printing; 
using System.Windows.Forms; 
using System.Runtime.InteropServices; 

public class RawPrinterHelper 
{ 
    // Structure and API declarions: 
    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)] 
    public class DOCINFOA 
    { 
     [MarshalAs(UnmanagedType.LPStr)] public string pDocName; 
     [MarshalAs(UnmanagedType.LPStr)] public string pOutputFile; 
     [MarshalAs(UnmanagedType.LPStr)] public string pDataType; 
    } 
    [DllImport("winspool.Drv", EntryPoint="OpenPrinterA", SetLastError=true, CharSet=CharSet.Ansi, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)] 
    public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd); 

    [DllImport("winspool.Drv", EntryPoint="ClosePrinter", SetLastError=true, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)] 
    public static extern bool ClosePrinter(IntPtr hPrinter); 

    [DllImport("winspool.Drv", EntryPoint="StartDocPrinterA", SetLastError=true, CharSet=CharSet.Ansi, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)] 
    public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di); 

    [DllImport("winspool.Drv", EntryPoint="EndDocPrinter", SetLastError=true, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)] 
    public static extern bool EndDocPrinter(IntPtr hPrinter); 

    [DllImport("winspool.Drv", EntryPoint="StartPagePrinter", SetLastError=true, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)] 
    public static extern bool StartPagePrinter(IntPtr hPrinter); 

    [DllImport("winspool.Drv", EntryPoint="EndPagePrinter", SetLastError=true, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)] 
    public static extern bool EndPagePrinter(IntPtr hPrinter); 

    [DllImport("winspool.Drv", EntryPoint="WritePrinter", SetLastError=true, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)] 
    public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten); 

    // 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, false on failure. 
    public static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount) 
    { 
     Int32 dwError = 0, dwWritten = 0; 
     IntPtr hPrinter = new IntPtr(0); 
     DOCINFOA di = new DOCINFOA(); 
     bool bSuccess = false; // Assume failure unless you specifically succeed. 

     di.pDocName = "My C#.NET RAW Document"; 
     di.pDataType = "RAW"; 

     // Open the printer. 
     if(OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero)) 
     { 
      // Start a document. 
      if(StartDocPrinter(hPrinter, 1, di)) 
      { 
       // Start a page. 
       if(StartPagePrinter(hPrinter)) 
       { 
        // Write your bytes. 
        bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten); 
        EndPagePrinter(hPrinter); 
       } 
       EndDocPrinter(hPrinter); 
      } 
      ClosePrinter(hPrinter); 
     } 
     // If you did not succeed, GetLastError may give more information 
     // about why not. 
     if(bSuccess == false) 
     { 
       dwError = Marshal.GetLastWin32Error(); 
     } 
     return bSuccess; 
    } 

    public static bool SendFileToPrinter(string szPrinterName, string szFileName) 
    { 
     // Open the file. 
     FileStream fs = new FileStream(szFileName, FileMode.Open); 
     // Create a BinaryReader on the file. 
     BinaryReader br = new BinaryReader(fs); 
     // Dim an array of bytes big enough to hold the file's contents. 
     Byte []bytes = new Byte[fs.Length]; 
     bool bSuccess = false; 
     // Your unmanaged pointer. 
     IntPtr pUnmanagedBytes = new IntPtr(0); 
     int nLength; 

     nLength = Convert.ToInt32(fs.Length); 
     // Read the contents of the file into the array. 
     bytes = br.ReadBytes(nLength); 
     // Allocate some unmanaged memory for those bytes. 
     pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength); 
     // Copy the managed byte array into the unmanaged array. 
     Marshal.Copy(bytes, 0, pUnmanagedBytes, nLength); 
     // Send the unmanaged bytes to the printer. 
     bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, nLength); 
     // Free the unmanaged memory that you allocated earlier. 
     Marshal.FreeCoTaskMem(pUnmanagedBytes); 
     return bSuccess; 
    } 
    public static bool SendStringToPrinter(string szPrinterName, string szString) 
    { 
     IntPtr pBytes; 
     Int32 dwCount; 
     // 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); 
     return true; 
    } 
} 

調用打印方法:

private void BtnPrint_Click(object sender, System.EventArgs e) 
{ 
    string s = "^XA^LH30,30\n^FO20,10^ADN,90,50^AD^FDHello World^FS\n^XZ"; 

    PrintDialog pd = new PrintDialog(); 
    pd.PrinterSettings = new PrinterSettings(); 
    if(DialogResult.OK == pd.ShowDialog(this)) 
    { 
     RawPrinterHelper.SendStringToPrinter(pd.PrinterSettings.PrinterName, s); 
    } 
} 

有2個陷阱我遇到這種情況發生時,你'將帶有ZPL代碼的txt文件發送到打印機:

  1. 文件ha s到結束與新行字符
  2. 編碼必須設置ANSI閱讀txt文件時有特殊字符

    public static bool SendTextFileToPrinter(string szFileName, string printerName) 
    { 
        var sb = new StringBuilder(); 
    
        using (var sr = new StreamReader(szFileName, Encoding.Default)) 
        { 
         while (!sr.EndOfStream) 
         { 
          sb.AppendLine(sr.ReadLine()); 
         } 
        } 
    
        return RawPrinterHelper.SendStringToPrinter(printerName, sb.ToString()); 
    } 
    
+0

應該可以直接從while循環中調用SendStringToPrinter而無需將整個輸入文件讀取到內存中。 (如果有人用Zebra打印機可以確認它的工作原理,請編輯答案或讓我知道) – Vedran 2017-06-01 08:02:53

+0

我試試這個到USB,沒關係,但是當我在LPT中嘗試時,它沒有打印,但沒有發現任何錯誤。任何可能的錯誤? – Vic 2017-06-29 09:48:01

+0

嗨,我用你的代碼,但打印機不打印任何東西,打印機發送請求到後臺打印,但不打印,你能幫忙嗎? – Esmigol 2017-12-15 18:28:51

11

的最簡單的解決方案是與將文件複製到共享打印機。
實施例C#:

System.IO.File.Copy(inputFilePath, printerPath); 

其中:

  • inputFilePath - 路徑ZPL文件(不需要特殊的擴展);
  • printerPath - 路徑共享打印機,例如(!):\ 127.0.0.1 \ zebraGX
+0

這對我有效,我已經爲我的標籤創建了文件。 – 2014-04-29 19:14:09

+0

這在vb.net中適用於我。漂亮和簡單的1班輪。我有提供給我的.zpl文件,我需要將它們發送給斑馬打印機, – Zyren 2015-10-29 22:25:53

+0

這太神奇了,比其他解決方案更加整潔。它與EasyPost等已經生成ZPL文件進行打印的服務完美協作。我可以使用「\\ machine-name \\ printer-name」打印到網絡上另一臺計算機共享的打印機。 – blackorchid 2016-11-04 15:47:29

8

下面是使用TCP IP協議來做到這一點:

// Printer IP Address and communication port 
    string ipAddress = "10.3.14.42"; 
    int port = 9100; 

// ZPL Command(s) 
    string ZPLString = 
    "^XA" + 
    "^FO50,50" + 
    "^A0N50,50" + 
    "^FDHello, World!^FS" + 
    "^XZ"; 

    try 
    { 
    // Open connection 
    System.Net.Sockets.TcpClient client = new System.Net.Sockets.TcpClient(); 
    client.Connect(ipAddress, port); 

    // Write ZPL String to connection 
    System.IO.StreamWriter writer = 
    new System.IO.StreamWriter(client.GetStream()); 
    writer.Write(ZPLString); 
    writer.Flush(); 

    // Close Connection 
    writer.Close(); 
    client.Close(); 
} 
catch (Exception ex) 
{ 
    // Catch Exception 
} 

來源:ZEBRA WEBSITE

相關問題