Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Send ESC commands to a printer in C#

My application needs to print invoices, then a get the invoice from database, insert information on the invoice in a big string (telling the line, column, etc.) after this I have the string ready to be sent to a printer.

My problem is: I need to put some ESC/P commands/characters in my big string

I tried to do something like this:

        char formFeed = (char)12;
        Convert.ToChar(12);

        MyBigString.Insert(10, formFeed);

Whith this, the line 10 will do a FormFeed, but this doesn't work

NOTE: I send the MybigString all at once to the printer.

To make my code works, I need to send the data line by line to a printer?

Thanks for the help.

PS: Sorry, for my English, I'am a Brazilian developer which don't speak English (yet).

like image 230
Ewerton Avatar asked May 14 '10 21:05

Ewerton


People also ask

What is print command ESC?

✧ ESC command is a standard instruction set made by EPSON for needle printer, which has become an effective industrial standard of the control language of needle printers. ✧ ESC/POS printing command is a simplified version of ESC printing control commands.

What is ESC PR printer?

ESC/P, short for Epson Standard Code for Printers and sometimes styled Escape/P, is a printer control language developed by Epson to control computer printers. It was mainly used in dot matrix printers and some inkjet printers, and is still widely used in many receipt thermal printers.


2 Answers

I've blogged about this before after having to do it myself. Not to toot my own horn too loudly, but I recommend that you read that entry, as I talk about a complex image command with the printer. If you can understand that, you can print anything!

(I talk about ESC/POS, used in retail receipt printers, but the semantics of the discussion applies to ESC/P, the older dot-matrix language, as well.)

In short, use a BinaryWriter instead of a string or you'll get hopelessly confused (as I did) as certain characters get "baked" in the wrong encoding on their way to the printer. (Trust me on this one! Do not use a StringBuilder when trying to talk in ESC/POS.)

Be careful not to use the Write(string) overload of the BinaryWriter as it will prepend the length of the string as a byte in the stream, which is not what you want. (I also blogged about that after learning that the hard way, too, on the same project.)

Then I use some code to send the byte array, as obtained from the BinaryWriter, directly to the printer by P/Invoking:

private static void Print(string printerName, byte[] document)
{
    NativeMethods.DOC_INFO_1 documentInfo;
    IntPtr printerHandle;

    documentInfo = new NativeMethods.DOC_INFO_1();
    documentInfo.pDataType = "RAW";
    documentInfo.pDocName = "Bit Image Test";

    printerHandle = new IntPtr(0);

    if (NativeMethods.OpenPrinter(printerName.Normalize(), out printerHandle, IntPtr.Zero))
    {
        if (NativeMethods.StartDocPrinter(printerHandle, 1, documentInfo))
        {
            int bytesWritten;
            byte[] managedData;
            IntPtr unmanagedData;

            managedData = document;
            unmanagedData = Marshal.AllocCoTaskMem(managedData.Length);
            Marshal.Copy(managedData, 0, unmanagedData, managedData.Length);

            if (NativeMethods.StartPagePrinter(printerHandle))
            {
                NativeMethods.WritePrinter(
                    printerHandle,
                    unmanagedData,
                    managedData.Length,
                    out bytesWritten);
                NativeMethods.EndPagePrinter(printerHandle);
            }
            else
            {
                throw new Win32Exception();
            }

            Marshal.FreeCoTaskMem(unmanagedData);

            NativeMethods.EndDocPrinter(printerHandle);
        }
        else
        {
            throw new Win32Exception();
        }

        NativeMethods.ClosePrinter(printerHandle);
    }
    else
    {
        throw new Win32Exception();
    }
}

Good luck!

like image 182
Nicholas Piasecki Avatar answered Oct 24 '22 03:10

Nicholas Piasecki


Bypassing the printer driver and controlling the printer directly, using its native command language, is a supported scenario. The P/Invoke is explained well in this KB article.

Sure you want to do this? It is uncommon, to put it mildly, usually only attempted with low-cost Point-Of-Sale thermal or matrix printers. If you don't like the mechanics of PrintDocument.PrintPage, nobody does, you could consider my code in this thread. Note the FormFeed method.

like image 5
Hans Passant Avatar answered Oct 24 '22 04:10

Hans Passant