[c#] .NET code to send ZPL to Zebra printers

Is there a way to send ZPL (Zebra Programming Language) to a printer in .NET?

I have the code to do this in Delphi, but it is not pretty and I would rather not try to recreate it in .NET as it is.

This question is related to c# .net zpl-ii zebra-printers zpl

The answer is


VB Version (using port 9100 - tested on 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

Here is how to do it using TCP IP protocol :

// 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
}

Source : ZEBRA WEBSITE


I've managed a project that does this with sockets for years. Zebra's typically use port 6101. I'll look through the code and post what I can.

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();
    }
}

Figured since this is still showing up high in search results for C# and ZPL I should mention SharpZebra. It's only EPL2, but I've submitted an update that adds ZPL support along with printing via sockets, the Windows Spool Service and direct USB.



This way you will be able to send ZPL to a printer no matter how it is connected (LPT, USB, Network Share...)

Create the RawPrinterHelper class (from the Microsoft article on How to send raw data to a printer by using Visual C# .NET):

using System;
using System.Drawing;
using System.Drawing.Printing;
using System.IO;
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;
    }
}

Call the print method:

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);
    }
}

There are 2 gotchas I've come across that happen when you're sending txt files with ZPL codes to the printer:

  1. The file has to end with a new line character
  2. Encoding has to be set to Encoding.Default when reading ANSI txt files with special characters

    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());
    }
    

I use the combo of these two

    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

@liquide's answer works great.

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

Which I found from the Zebra's ZPL Programmer's Guide Volume 1 (2005) enter image description here


The simplest solution is with copying files to shared printer.
Example in C#:

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

where:

  • inputFilePath - path to ZPL file (special extension is not required);
  • printerPath - path to shared(!) printer, for example: \127.0.0.1\zebraGX

Examples related to c#

How can I convert this one line of ActionScript to C#? Microsoft Advertising SDK doesn't deliverer ads How to use a global array in C#? How to correctly write async method? C# - insert values from file into two arrays Uploading into folder in FTP? Are these methods thread safe? dotnet ef not found in .NET Core 3 HTTP Error 500.30 - ANCM In-Process Start Failure Best way to "push" into C# array

Examples related to .net

You must add a reference to assembly 'netstandard, Version=2.0.0.0 How to use Bootstrap 4 in ASP.NET Core No authenticationScheme was specified, and there was no DefaultChallengeScheme found with default authentification and custom authorization .net Core 2.0 - Package was restored using .NetFramework 4.6.1 instead of target framework .netCore 2.0. The package may not be fully compatible Update .NET web service to use TLS 1.2 EF Core add-migration Build Failed What is the difference between .NET Core and .NET Standard Class Library project types? Visual Studio 2017 - Could not load file or assembly 'System.Runtime, Version=4.1.0.0' or one of its dependencies Nuget connection attempt failed "Unable to load the service index for source" Token based authentication in Web API without any user interface

Examples related to zpl-ii

.NET code to send ZPL to Zebra printers

Examples related to zebra-printers

Send raw ZPL to Zebra printer via USB .NET code to send ZPL to Zebra printers

Examples related to zpl

Send raw ZPL to Zebra printer via USB .NET code to send ZPL to Zebra printers