Send ESC commands to a printer in C#

后端 未结 3 1544
长情又很酷
长情又很酷 2020-12-03 16:16

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

3条回答
  •  盖世英雄少女心
    2020-12-03 16:29

    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!

提交回复
热议问题