3

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

基本的な注意事項:

1) QPrinter を使用できません。あとがきではなく、生のテキストを書く必要があります。2) プリンターの名前はユーザーが設定するまでわかりません。印刷する文字列のサイズは、ユーザーが作成するまでわかりません。

追加情報:

a) プリンターは動作します。メモ帳、Chrome、ほぼすべてのものから必要なプリンターに印刷できます。b) どんなハックでも喜んで実装します。テキストファイルに書き込んでコピーコマンドを発行するようなものは機能しないようです。つまり、デバイスの初期化に失敗したというエラーが発生します。

これは動作します: notepad /P Documents/test_print.txt これは動作しません: copy Documents\test_print.txt /D:EPSON_TM_T20 copy Documents\test_print.txt /D \MYCOMPUTER\epson_tm_t20 (アクセスが拒否され、プリンターが共有されます) print Documents \test_print.txt (デバイスを初期化できません)

コマンドラインからテキストファイルを印刷するための推奨される方法をほぼすべて試しましたが、うまくいきません。インストール、ドライバーの再インストール、プリンターの追加、ポートをいじって、すべてやり直しました。

明らかに、経験不足のために私が見逃しているWindows印刷についての簡単なことがあります。

私が達成したいことは次のとおりです。

1) 最良のシナリオ (テキストをプリンターに直接書き込む) 2) 2 番目に優れたシナリオ (テキストをファイルに書き込み、プログラムを実行して印刷する)

プログラムはエンドユーザー向けであるため、エンドユーザーのためにこれを自動的に行う方法を見つける必要があるため、powershell からコマンド obscure_configuration を実行した後、タブ 36 のチェックボックス a をクリックすることは期待できません。

どんな助けでも大歓迎です。

/ジェイソン

アップデート

これは、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()) ;
}

: Skizz に謝罪する義務があります。彼が書いた内容は、根本的な問題のデバッグに実際に役立ちました。QByteArray 内の文字は、プリンター用に特別に事前にフォーマットされています。問題は、いくつかの NULL バイトが含まれていることです。それらをプリンターに送信しようとすると、TextOut がテキストを切り捨て、最初の数行だけを印刷します。回答で示唆されているように、WritePrinter を使用すると、null バイトが無視され、void * と長さが受け入れられ、すべてがそこに置かれます。

さらに、PrintDlg の使用を推奨する彼の応答は、正しいプリンター HDC を取得するために機能しました。問題は、ユーザーが最初にプリンターを 1 回選択し、その後、印刷するため、印刷するたびに選択する必要がないことです。たくさんあります(これは販売時点管理です)。

文字列名からプリンター 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;

上記の m_printer_path は、プリント マネージャーから取得したプリンターの名前の文字列表現です。

文字列にはプリンターに必要なすべてのフォーマットが含まれているため、改行やフォーマットについて心配する必要はありません。

この質問に対する 3 つの回答はすべて、実際に最終的な実用的なソリューションを実装するのに非常に役立ちました。私は各回答に賛成票を投じました。

4

5 に答える 5

5

最近のほとんどのプリンターは、与えられたデータのレイアウト処理を一切実行しません。したがって、一連の文字をプリンタに送信すると、せいぜい、ページの横にある1行のテキストがデフォルトのフォントで印刷されます。キャリッジリターンも機能する場合があります。

最近のプリンターが通常行うことは、プリンターが理解し、何をどこでどのように印刷するかを定義する前処理されたデータを使用してページを印刷することです。この前処理はすべてホストPCで実行され、結果はプリンターに送信されます。これが、通常、プリンタードライバーをインストールする理由です。これらのドライバーは、ユーザーデータ(単純なテキストファイルまたはDTPページ)を取得し、プリンターが理解できる言語に変換します。

その結果、生のテキストをプリンタに送信することはおそらく機能しないということです。

次に、プロパティと言語が異なる複数のプリンタを使用するという問題が発生します。

したがって、Windowsでは、これらすべてがプリンタデバイスのコンテキストオブジェクトに抽象化されます。これは、グラフィックデバイスコンテキストと同じインターフェイスを備えていますが、作成方法が異なります。

Win32 APIには、ユーザーがプリンタを選択できるようにするための共通のダイアログがあります。PrintDlgEx関数を使用して、ユーザーがプリンターを選択できるようにします。次に、返されたDCを使用して、ページにテキストを描画します。

于 2012-09-11T15:00:17.823 に答える
3

生データ (プリンター制御コードなど) をプリンターに送信する方法を説明している MSDN の記事がいくつかあります。

于 2012-09-11T21:43:42.370 に答える
1

QPrintを試してみませんか.. Generic Text Onlyドライバーを使用して生のテキストを印刷します

QString prn("^XA^FO121,41^A0N,19,15^FDABC DEFGHIJKLMNOPQRSTUVWXYZ^FS^XZ");
QPrinter printer(QPrinterInfo::defaultPrinter());  //the default printer is "Generic / Text Only"

QTextDocument doc(prn);
doc.print(&printer);
于 2014-01-09T23:57:03.970 に答える
1

あなたは正しい考えを持っています (ただし、一致する必要がStartPageありEndDocます)。問題はTextOut、テキストの行のみを描画することです。長い文字列を複数の行に分割することはありません。それを行う必要があります (またはそれを行うコードを見つけます)。

テキストが常に 1 ページに収まることがわかっている場合は、基本的な改行、タブ拡張などを実行できる呼び出しにTextOut置き換えることができます。DrawTextEx

于 2012-09-11T16:36:50.383 に答える