Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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:

  • The file has to end with a new line character

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

    Take a look at this thread: Print ZPL codes to ZEBRA printer using PrintDocument class.

    Specifically the OP pick this function from the answers to the thread:

    [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();
    
    // 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";
        // 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

    While debugging, I couldn't find the 9100 port mentioned in docs anywhere so I scanned the open ports of the Zebra printer with nmap 192.168.1.x -p1-10000, but 9100 isn't listed there either. The thing is, it works even if the port doesn't seem to be open with port scanners like Nmap. Can anyone provide a better link to official docs that state the port number? – mik13ST Mar 24 at 14:32

    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
  • 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;
            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();
                    Zebra Mobile printers use port 6101 (QL, RW, MZ, etc).  Larger printers usually use port 9100.
    – James Van Huis
                    Feb 8, 2010 at 21:22
    

    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()
            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
    
        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()
            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"
            command += "^FO1,30^A0,N,50,50^FD"
        End If
        command += txtInput.Text
        command += "^FS"
        command += "^XZ"
        Return command
    End Function
            

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.

  •