win32 C++ 打印字符串到打印机 [英] win32 C++ print string to printer

查看:101
本文介绍了win32 C++ 打印字符串到打印机的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在网上搜索了几天关于如何在 Windows 上将任意字符串打印到任意打印机的确切方法后,我终于想出了这段代码.

After a few days of searching the net on how exactly I can go about printing an arbitrary string to an arbitrary printer on windows, I finally came up with this code.

LPBYTE pPrinterEnum;
DWORD pcbNeeded, pcbReturned;
PRINTER_INFO_2 *piTwo = NULL;
HDC printer;
EnumPrinters(PRINTER_ENUM_LOCAL,NULL,2,NULL,0,&pcbNeeded,&pcbReturned);
pPrinterEnum = new BYTE[pcbNeeded];
if (!EnumPrinters(PRINTER_ENUM_LOCAL,NULL,2,pPrinterEnum,pcbNeeded,&pcbNeeded,&pcbReturned)) {
    qDebug() << "In Print, could not enumerate printers";
} else {
    piTwo = ((PRINTER_INFO_2*)pPrinterEnum);
    for (int i = 0; i < pcbReturned; i++) {
        QString name = QString::fromWCharArray(piTwo[i].pPrinterName);
        if (this->m_printer_path == name) {
            const WCHAR * driver = L"WINSPOOL\0";
            printer = CreateDC(NULL,piTwo[i].pPrinterName,NULL,NULL);
        }
    }
}
if (printer == 0) {
    qDebug() << "No Printer HDC";
    return;
} else {
    qDebug() << "Printer seems okay!";
}

qDebug() << "Starting Document";
DOCINFO di;
memset( &di, 0, sizeof( di ) );
di.cbSize = sizeof( di );
WCHAR * text = new WCHAR[ba.length()];
QString(ba).toWCharArray(text);
StartDoc(printer,&di);
    qDebug() << "Writing text";
    TextOut(printer,0, 0, text, ba.length());
    qDebug() << "Text Written";
EndPage(printer);
qDebug() << "Page ended";
DeleteDC(printer);
qDebug() << "DC Deleted";

一些基本警告:

1) 我不能使用 QPrinter.我需要写原始文本,没有附言.2)直到用户设置我才知道打印机的名称,直到用户创建它我才知道要打印的字符串的大小.

1) I cannot use QPrinter. I need to write raw text, no postscript. 2) I do not know the name of the printer until the user sets it, and I do not know the size of the string to print until the user creates it.

附加信息:

a) 打印机工作正常,我可以从记事本、Chrome 打印,几乎所有东西都可以打印到我想要​​的打印机上.b) 我愿意实施几乎任何 hack.像把它写到一个文本文件并发出复制命令似乎不起作用,即我得到了一个无法初始化设备错误.

a) The printer works, I can print from Notepad, Chrome, just about everything to the printer that I want. b) I am willing to implement just about any hack. Ones like write it to a text file and issue the copy command don't seem to work, that is, I get a failed to initialize device error.

这有效:记事本/P Documents/test_print.txt这不起作用:复制 Documents\test_print.txt/D:EPSON_TM_T20copy Documents\test_print.txt/D \MYCOMPUTER\epson_tm_t20(导致访问被拒绝,打印机被共享)打印 Documents\test_print.txt(无法初始化设备)

This works: notepad /P Documents/test_print.txt This does not work: copy Documents\test_print.txt /D:EPSON_TM_T20 copy Documents\test_print.txt /D \MYCOMPUTER\epson_tm_t20 (leads to access denied, printer is shared) print Documents\test_print.txt (Unable to initialize device)

我已经尝试了几乎所有推荐的从命令行打印文本文件的方法,但都行不通.我已经安装、重新安装了驱动程序、添加了打印机、弄乱了端口并重新完成了所有操作.

I have tried just about every recommended way to print a text file from the command line, just doesn't work. I have installed, reinstalled driver, added printer, mucked with ports and done it all again.

显然,由于缺乏经验,我缺少一些关于 Windows 打印的简单内容.

Obviously there is something simple about windows printing that I am missing due to inexperience.

我想要完成的是:

1) 最佳场景(直接将文本写入打印机)2)次佳方案(将文本写入文件,然后执行一些程序为我打印)记事本在打印输出的底部增加了令人讨厌的空间,浪费纸张.

1) Best Scenario( Directly write text to the printer) 2) Second best scenario (Write text to a file, then execute some program to print it for me) Notepad adds an annoying amount of space to the bottom of the printout wasting paper.

由于该程序是针对最终用户的,我必须找到一种方法为他们自动执行此操作,因此我不能指望他们在从 powershell 运行命令 Obblec_configuration 后单击选项卡 36 中的复选框 a.

Since the program is for end users, I have to find a way to do this automagically for them, so I can't expect them to click checkbox a in tab 36 after running command obscure_configuration from a powershell.

任何帮助将不胜感激.

/杰森

更新

这是工作代码,在我稍微整理一下之前,它将 QByteArray 的内容打印到热敏打印机.

This is the working code, before I go through an spruce it up a bit, which prints the contents of a QByteArray to a thermal printer.

qDebug() << "Executing windows code";
BOOL     bStatus = FALSE;
DOC_INFO_1 DocInfo;
DWORD      dwJob = 0L;
DWORD      dwBytesWritten = 0L;
HANDLE     hPrinter;
wchar_t * name = new wchar_t[this->m_printer_path.length()+1];
this->m_printer_path.toWCharArray(name);
name[this->m_printer_path.length() + 1] = 0;
qDebug() << "opening printer";
bStatus = OpenPrinter(name,&hPrinter, NULL);

if (bStatus) {
    qDebug() << "Printer opened";
    DocInfo.pDocName = L"My Document";
    DocInfo.pOutputFile = NULL;
    DocInfo.pDatatype = L"RAW";
    dwJob = StartDocPrinter( hPrinter, 1, (LPBYTE)&DocInfo );
    if (dwJob > 0) {
        qDebug() << "Job is set.";
        bStatus = StartPagePrinter(hPrinter);
        if (bStatus) {
            qDebug() << "Writing text to printer";
            bStatus = WritePrinter(hPrinter,ba.data(),ba.length(),&dwBytesWritten);
            EndPagePrinter(hPrinter);
        } else {
            qDebug() << "could not start printer";
        }
        EndDocPrinter(hPrinter);
        qDebug() << "closing doc";
    } else {
        qDebug() << "Couldn't create job";
    }
    ClosePrinter(hPrinter);
    qDebug() << "closing printer";
} else {
    qDebug() << "Could not open printer";
}
if (dwBytesWritten != ba.length()) {
    qDebug() << "Wrong number of bytes";
} else {
    qDebug() << "bytes written is correct " << QString::number(ba.length()) ;
}

注意:我真的要向斯基兹道歉,他写的东西实际上有助于调试基本问题.QByteArray 中的字符是专门为打印机预先格式化的,问题是,它们包含几个 NULL 字节.当尝试将它们发送到打印机时,这会导致 TextOut 截断文本,只打印前几行.使用 WritePrinter,如答案中所建议的那样忽略空字节并接受一个 void * 和一个长度,并将其全部放在那里.

Note: I do owe an apology to Skizz, what he wrote was actually helpful in debugging the fundamental issue. The characters in the QByteArray are preformatted specifically for the printer, the problem is, they contain several NULL bytes. When trying to send them to the printer, this causes TextOut to truncate the text, only printing the first few lines. Using WritePrinter, as suggested in the answer ignores null bytes and accepts a void * and a length, and just puts it all there.

此外,他的回答推荐使用 PrintDlg 确实可以实现正确的打印机 HDC,问题是,用户首先选择打印机一次,然后每次打印时都不需要选择它,因为它们将大量印刷(这是一个销售点).

Further, his response recommending the use of PrintDlg did work to fectch the correct printer HDC, the issus is that, the user first chooses a printer once, and then doesn't need to choose it each time they print, because they will be printing alot (It's a Point of Sale).

从字符串名称获取打印机 HDC 的问题是由于没有将所有重要的 NULL 字节添加到 wchar_* 中,这是通过这种方式解决的:

The problem with getting the printer HDC from the string name was due to not adding the all important NULL byte to wchar_* which was solved this way:

wchar_t * name = new wchar_t[this->m_printer_path.length()+1];
this->m_printer_path.toWCharArray(name);
name[this->m_printer_path.length() + 1] = 0;

在上面,m_printer_path 是从打印管理器中获取的打印机名称的字符串表示.

In the above, m_printer_path is a string representation of the name of the printer taken from Print Manager.

因为字符串具有打印机所需的所有格式,所以无需担心换行或任何格式.

Because the string has all the formatting necessary for the printer, there's no need to worry about new lines, or any formatting.

这个问题的所有三个答案实际上都对实施最终可行的解决方案非常有帮助,我对每个答案都投了赞成票,我感谢每个人花费的时间做出回应.

All three answers to this question were actually very helpful in implementing the final working solution, and I have voted up each answer, and I appreciate the time each person took in responding.

推荐答案

有几篇 MSDN 文章描述了如何将原始数据(打印机控制代码等)发送到打印机.

There are a couple of MSDN articles describing how to send raw data (printer control codes, etc.) to a printer.

这篇关于win32 C++ 打印字符串到打印机的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆