Send ESC commands to a printer in C#

2020-01-29 08:57发布

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).

3条回答
放我归山
2楼-- · 2020-01-29 09:36

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!

查看更多
等我变得足够好
3楼-- · 2020-01-29 09:47

"....OpenPrinter(printerName.Normalize(), out printerHandle, IntPtr.Zero)..."

might needed to set IntPtr.Zero to raw too.

Printers, especially dot matrix, it can be direct using DOS, CMD method, which much simplest and faster for printing also can using basic ESC/0x1b command codes to controll the printer,. . etc.

as windowos/graphic, it can be graphics and raw by setting openprinter(,,printer_defaults) printer_defaults and doc-inf, pls refer win32 sdk references.

for any raw printing it can uses ESC command (refer to printer manual details) to print any graphic as what windows driver did.

as printing raw, it just append any of the first 20 ascii, such as oxoc(formfeed) 0x0doa(0x0a, 0x0d, \n or newline) each printer has slight ESC commands differences but using the master ESC command is fined for most of Dot matrix similar.

as raw mode example follows, FormFeed , \n & \r

char cFormfeed=0x0c; // or \f

char cStr[]="1=text,......@\n2=text.....\r\f3=text......."; //use \f not using cFormfeed you can work it out

cStr > lpt1; //output to printer dos or cmd method, of cause must get the lpt1 available.

print out will be

first page

1=text,......@

2=text.....

at 2nd page is

3=text.......

hope this can be help, good luck.

查看更多
虎瘦雄心在
4楼-- · 2020-01-29 09:56

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.

查看更多
登录 后发表回答