7

我的应用程序需要打印发票,然后从数据库中获取发票,在发票上插入一个大字符串中的信息(告诉行、列等),然后我准备好将字符串发送到打印机。

我的问题是:我需要在我的大字符串中放入一些 ESC/P 命令/字符

我试图做这样的事情:

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

        MyBigString.Insert(10, formFeed);

有了这个,第 10 行将执行 FormFeed,但这不起作用

注意:我一次将 MybigString 全部发送到打印机。

为了使我的代码正常工作,我需要将数据逐行发送到打印机吗?

谢谢您的帮助。

PS:对不起,对于我的英语,我是一个不会说英语的巴西开发人员(还)。

4

3 回答 3

6

在不得不自己做之后,我之前在博客上写过这个。不要把我自己的喇叭吹得太大声,但我建议您阅读该条目,因为我谈到了打印机的复杂图像命令。如果你能理解这一点,你可以打印任何东西!

(我谈论的是用于零售收据打印机的 ESC/POS,但讨论的语义也适用于 ESC/P,即较旧的点阵语言。)

简而言之,使用 aBinaryWriter而不是 a ,string否则您会感到非常困惑(就像我所做的那样),因为某些字符在到达打印机的途中会以错误的编码“烘烤”。StringBuilder(相信我这一点!尝试在 ESC/POS 中交谈时不要使用 a 。)

注意不要使用Write(string)重载,BinaryWriter因为它会将字符串的长度作为字节添加到流中,这不是您想要的。(在同一个项目中,我也以艰难的方式了解到这一点后,我也写了一篇博客。)

然后我使用一些代码通过 P/Invokingbyte将从 中获得的数组BinaryWriter直接发送到打印机:

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();
    }
}

祝你好运!

于 2010-05-14T21:42:07.353 回答
5

绕过打印机驱动程序并使用其本机命令语言直接控制打印机是受支持的方案。这篇知识库文章很好地解释了 P/Invoke 。

你确定要这样做吗?委婉地说,这种情况并不常见,通常只尝试使用低成本的销售点热敏打印机或矩阵打印机。如果你不喜欢 PrintDocument.PrintPage 的机制,没人喜欢,你可以考虑我在这个线程中的代码。请注意 FormFeed 方法。

于 2010-05-14T22:05:40.130 回答
0

“....OpenPrinter(printerName.Normalize(), out printerHandle, IntPtr.Zero)...”

可能也需要将 IntPtr.Zero 设置为 raw。

打印机,尤其是点阵打印机,可以直接使用DOS、CMD方式,打印更简单快捷,也可以使用基本的ESC/0x1b命令代码来控制打印机,。. 等等

作为windowos/graphic,通过设置openprinter(,,printer_defaults)和doc-inf可以是图形和raw,请参考win32 sdk参考。

对于任何原始打印,它可以使用 ESC 命令(请参阅打印机手册详细信息)来打印任何图形,就像 Windows 驱动程序所做的那样。

作为原始打印,它只是附加前 20 个 ascii 中的任何一个,例如 oxoc(formfeed) 0x0doa(0x0a, 0x0d, \n 或换行符) 每个打印机都有轻微的 ESC 命令差异,但使用主 ESC 命令对大多数 Dot 来说都是罚款矩阵类似。

作为原始模式示例如下, FormFeed , \n & \r

字符 cFormfeed=0x0c; // 或 \f

char cStr[]="1=文本,......@\n2=文本.....\r\f3=文本......."; //使用 \f 不使用 cFormfeed 你可以解决

cStr > lpt1; //输出到打印机 dos 或 cmd 方法,原因必须使 lpt1 可用。

打印出来将是

第一页

1=文字,......@

2=文本.....

在第 2 页是

3=文本.......

希望这能有所帮助,祝你好运。

于 2013-04-19T12:46:42.750 回答