Send raw ZPL to Zebra printer via USB

守給你的承諾、 提交于 2019-11-27 05:22:35

问题


Typically, when I plug in my Zebra LP 2844-Z to the USB port, the computer sees it as a printer and I can print to it from notepad like any other generic printer. However, my application has some bar code features. My application parses some input and generates an in-memory string of ZPL. How would I send this ZPL data to my USB device?


回答1:


I found the answer... or at least, the easiest answer (if there are multiple). When I installed the printer, I renamed it to "ICS Label Printer". Here's how to change the options to allow pass-through ZPL commands:

  1. Right-click on the "ICS Label Printer" and choose "Properties".
  2. On the "General" tab, click on the "Printing Preferences..." button.
  3. On the "Advanced Setup" tab, click on the "Other" button.
  4. Make sure there is a check in the box labeled "Enable Passthrough Mode".
  5. Make sure the "Start sequence:" is "${".
  6. Make sure the "End sequence:" is "}$".
  7. Click on the "Close" button.
  8. Click on the "OK" button.
  9. Click on the "OK" button.

In my code, I just have to add "${" to the beginning of my ZPL and "}$" to the end and print it as plain text. This is with the "Windows driver for ZDesigner LP 2844-Z printer Version 2.6.42 (Build 2382)". Works like a charm!




回答2:


I've found yet an easier way to write to a Zebra printer over a COM port. I went to the Windows control panel and added a new printer. For the port, I chose COM1 (the port the printer was plugged in to). I used a "Generic / Text Only" printer driver. I disabled the print spooler (a standard option in the printer preferences) as well as all advanced printing options. Now, I can just print any string to that printer and if the string contains ZPL, the printer renders the ZPL just fine! No need for special "start sequences" or funky stuff like that. Yay for simplicity!




回答3:


Visual Studio C# solution (found at http://support.microsoft.com/kb/322091)

Step 1.) Create class RawPrinterHelper...

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

Step 2.) Create a form with text box and button (text box will hold the ZPL to send in this example). In button click event add code...

private void button1_Click(object sender, EventArgs e)
        {
            // Allow the user to select a printer.
            PrintDialog pd = new PrintDialog();
            pd.PrinterSettings = new PrinterSettings();
            if (DialogResult.OK == pd.ShowDialog(this))
            {
                // Send a printer-specific to the printer.
                RawPrinterHelper.SendStringToPrinter(pd.PrinterSettings.PrinterName, textBox1.Text);
                MessageBox.Show("Data sent to printer.");
            }
            else
            {
                MessageBox.Show("Data not sent to printer.");
            }
        }

With this solution, you can tweak to meet specific requirements. Perhaps hardcode the specific printer. Perhaps derive the ZPL text dynamically rather than from a text box. Whatever. Perhaps you don't need a graphical interface, but this shows how to send the ZPL. Your use depends on your needs.




回答4:


You haven't mentioned a language, so I'm going to give you some some hints how to do it with the straight Windows API in C.

First, open a connection to the printer with OpenPrinter. Next, start a document with StartDocPrinter having the pDatatype field of the DOC_INFO_1 structure set to "RAW" - this tells the printer driver not to encode anything going to the printer, but to pass it along unchanged. Use StartPagePrinter to indicate the first page, WritePrinter to send the data to the printer, and close it with EndPagePrinter, EndDocPrinter and ClosePrinter when done.




回答5:


ZPL is the correct way to go. In most cases it is correct to use a driver that abstracts to GDI commands; however Zebra label printers are a special case. The best way to print to a Zebra printer is to generate ZPL directly. Note that the actual printer driver for a Zebra printer is a "plain text" printer - there is not a "driver" that could be updated or changed in the sense we think of most printers having drivers. It's just a driver in the absolute minimalist sense.




回答6:


I spent 8 hours to do that. It is simple...

You shoud have a code like that:

private const int GENERIC_WRITE = 0x40000000;

//private const int OPEN_EXISTING = 3;
private const int OPEN_EXISTING = 1;
private const int FILE_SHARE_WRITE = 0x2;
private StreamWriter _fileWriter;
private FileStream _outFile;
private int _hPort;

Change that variable content from 3 (open file already exist) to 1 (create a new file). It'll work at Windows 7 and XP.




回答7:


Install an share your printer: \localhost\zebra Send ZPL as text, try with copy first:

copy file.zpl \localhost\zebra

very simple, almost no coding.




回答8:


You can use COM, or P/Invoke from .Net, to open the Winspool.drv driver and send bytes directly to devices. But you don't want to do that; this typically works only for the one device on the one version of the one driver you test with, and breaks on everything else. Take this from long, painful, personal experience.

What you want to do is get a barcode font or library that draws barcodes using plain old GDI or GDI+ commands; there's one for .Net here. This works on all devices, even after Zebra changes the driver.



来源:https://stackoverflow.com/questions/4442122/send-raw-zpl-to-zebra-printer-via-usb

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!