win32 C++打印字符串到打印机

J. *_*tin 2 c++ winapi qt

经过几天的网络搜索,我可以准确地将任意字符串打印到Windows上的任意打印机,我终于想出了这段代码.

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";
Run Code Online (Sandbox Code Playgroud)

一些基本的警告:

1)我不能使用QPrinter.我需要写原始文本,没有后记.2)在用户设置之前我不知道打印机的名称,在用户创建之前我不知道要打印的字符串的大小.

附加信息:

a)打印机工作,我可以从记事本,Chrome打印,几乎所有我想要的打印机.b)我愿意实施任何黑客攻击.有人把它写入文本文件并发出复制命令似乎不起作用,也就是说,我得到初始化设备错误失败.

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

我已尝试过几乎所有推荐的方法从命令行打印文本文件,只是不起作用.我已经安装,重新安装了驱动程序,添加了打印机,使用了端口,并再次完成了所有操作.

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

我想要完成的是:

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

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

任何帮助将不胜感激.

/杰森

UPDATE

这是工作代码,在我经过一个云杉之前,它将QByteArray的内容打印到热敏打印机.

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()) ;
}
Run Code Online (Sandbox Code Playgroud)

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

此外,他建议使用PrintDlg的响应确实能够完成正确的打印机HDC,问题在于,用户首先选择一台打印机,然后每次打印时都不需要选择它,因为它们将打印很多(这是一个销售点).

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

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;
Run Code Online (Sandbox Code Playgroud)

在上面,m_printer_path是从Print Manager中获取的打印机名称的字符串表示形式.

由于字符串具有打印机所需的所有格式,因此无需担心新行或任何格式.

这个问题的所有三个答案实际上对实施最终的工作解决方案非常有帮助,我已经对每个答案进行了投票,我很欣赏每个人回答的时间.

Ski*_*izz 5

大多数现代打印机不对它们给出的数据执行任何形式的布局处理.因此,将一系列字符发送到打印机最多只能以某种默认字体打印在页面一侧运行的一行文本.回车也可能有效.

现代打印机通常使用打印机理解的预处理数据打印页面,并定义打印的位置和打印方式.所有这些预处理都在主机PC上完成,结果发送到打印机.这就是您通常安装打印机驱动程序的原因 - 这些驱动程序获取用户数据(无论是简单的文本文件还是DTP页面)并将其转换为打印机能够理解的语言.

这样做的结果是将原始文本发送到打印机可能无法正常工作.

然后你就遇到了拥有不同属性和语言的多台打印机的问题.

因此,在Windows中,所有这些都被抽象到打印机设备上下文对象中.它具有与图形设备上下文相同的界面,但您以不同方式创建它.

Win32 API有一个通用对话框,让用户选择打印机.使用PrintDlgEx功能允许用户选择打印机.然后使用返回的DC将文本绘制到页面.