Send ESC commands to a printer in C#

心已入冬 提交于 2019-11-28 10:21:18

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.

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!

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

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