VS2010, MFC, SDI で印刷アプリを作っています。
複数ページの印刷で、何ページから何ページまで印刷したかを記録する必要があり、印刷
したページ番号を、配列 m_nPrintedPage[] に格納してみました。
CMyProjView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
if (pDC->IsPrinting())
{
m_nPrintedPage[m_nPPAray] = pInfo->m_nCurPage;
m_nPPAray++; // 印刷開始前に m_nPPAray = 0; としています。
...(印刷のためのコード)...
}
}
結果を OnEndPrinting() 関数内で調べたところ、同じページ番号が2回ずつ格納されて
いました。
例:(3~5ページを印刷した場合) m_nPrintedPage[] = {3, 3, 4, 4, 5, 5, 0, 0...}
この動作は正しいでしょうか?
OnPrepareDC() はページ毎に2回ずつ実行されると考えていいでしょうか?
(印刷は正常に行われています。)
解説を見てもそのようなことは書かれていません。
例:マルチページドキュメント
https://msdn.microsoft.com/ja-jp/library/vstudio/w7wzay73(v=vs.110).aspx
ご存じの方がいらっしゃいましたらご教授ください。
よろしくお願いいたします。
ITO 様、有り難うございます。
教えて戴いたページは、CPrintInfo::m_nCurPage の説明です。
「フレームワークは、ドキュメントのページごとにこのメンバーに異なる値を指定して、
CView::OnPrepareDC と CView::OnPrint を呼び出します。」と書いてあります。
これが、『フレームワークは・・・ CView::OnPrepareDC を2度呼び出す』と書いてあれ
ば納得なのですが・・・
>CMyProjView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
失礼しました。
ここで実際に処理していたのですね。
>OnPrepareDC() はページ毎に2回ずつ実行されると考えていいでしょうか?
うーーん、
たまたま2回だったということはないでしょうか?
https://technet.microsoft.com/en-us/lync/aa248127(v=vs.60)
ここでは、「OnPrint()」で処理するように書いてありますね。
OnPaint() の中で、印刷したページ番号を格納しました。
CMyProjView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
if (pDC->IsPrinting())
{
m_nPrintedPage[m_nPPAray] = pInfo->m_nCurPage;
m_nPPAray++; // 印刷開始前に m_nPPAray = 0; としています。
...(印刷のためのコード)...
}
}
結果:(3~5ページを印刷した場合) m_nPrintedPage[] = {3, 4, 5, 0, 0, 0, 0, 0...}
これで解決です。
ありがとうございました。
解決したようなので今さらですが。
VS2008 ですが MFC のソースを見てみると
viewprnt.cpp の CView::OnFilePrint() で OnPrepareDC() を
ページごとに 2 回呼び出しているように読めます。
K様、有り難うございます。
やはりそうですか。
OnPrepareDC() が2回呼び出されるのは異常ではないと、安心しました。
OnPrint() の中で、印刷したページ番号を取得できたとして解決としましたが、その後、
例えば3ページ印刷しようとして用紙が1枚しかセットされておらず、印刷が中断した場
合でも、OnPaint() は3ページ分動作してしまうことが判りました。
これでは目的に合わないので、最初から考え直すことにしました。
> viewprnt.cpp の CView::OnFilePrint() で OnPrepareDC() を
> ページごとに 2 回呼び出しているように読めます。
なるほど、フォロー助かります。
>例えば3ページ印刷しようとして用紙が1枚しかセットされておらず、印刷が中断した
>場合でも、OnPaint() は3ページ分動作してしまうことが判りました。
おそらくもうテッパンさんの 印刷処理は終了しています。
https://msdn.microsoft.com/ja-jp/library/cc428280.aspx
ここの、ジョブ/スプールの処理になっていると思います。
http://support.microsoft.com/kb/160129/JA
これもかな?
キャンセルされたかどうかを調べるのは難しいと思います。
教えて戴いた印刷ジョブ/スプールを理解しようと努力しましたが、プリンタ側で何ペー
ジまで印刷できて何ページから印刷できていないかの情報を取得するのは至難の業と、諦
めることにしました。
皆様、ありがとうございました。
うーーん、
プリンタ側は、何ページからは関係ないですね。
そこは、
>結果:(3~5ページを印刷した場合) m_nPrintedPage[] = {3, 4, 5, 0, 0, 0, 0, 0...}
この値を信用するしかないと思います。
あとは、実際に印刷されたページ数(途中キャンセルの有無)をチェックすればいいと思
いますが、どうでしょうか?
あきらめるな!、と励まして戴いて有り難うございます。
実際に印刷されたページ数を取得しようと、コードを一応書いてみたのですが、始めのと
ころでつまづいています。
CMyProjView::EndPrinting(CDC* /*pDC*/, CPrintInfo* pInfo)
{
DWORD cByteNeeded;
PRINTER_INFO_2 *pPrinterInfo = NULL;
GetPrinter(pInfo->m_pPD, 2, NULL, 0, &cByteNeeded); ←この行でエラー
pPrinterInfo = (PRINTER_INFO_2 *)malloc(cByteNeeded);
・・・以下、GetPrinter()、EnumJobs() まで
}
pInfo->m_pPD がいけないかと、OpenPrinter() でハンドルを取得してみても同じです。
HANDLE hPrinter;
OpenPrinter(_T(EPSON EP-301), &hPrinter, NULL); ←この関数は成功
GetPrinter(hPrinter, 2, NULL, 0, &cByteNeeded); ←この行でエラー
コードを OnPrint() の中に書いても、GetPrinter() がエラーは同じです。
お気づきのことがありましたらご教授ください。
GetPrinter() のエラーコードは、6番、ERROR_INVALID_HANDLE となっています。
失礼しました。訂正します。エラーコードは、
GetPrinter(pInfo->m_pPD,... のとき、ERROR_INVALID_HANDLE です。
OpenPrinter(_T(EPSON EP-301), &hPrinter, NULL);
GetPrinter(hPrinter, 2, NULL, 0, &cByteNeeded);
のとき、122番、ERROR_INSUFFICIENT_BUFFER になります。
GetPrinter(hPrinter, 2, NULL, 0, &cByteNeeded);
の戻りが ERROR_INSUFFICIENT_BUFFER であるのは予定の結果なんですね。
お手本「プリンタと印刷ジョブの状態の取得方法」
http://support.microsoft.com/kb/160129/JA
の中の
GetPrinter(hPrinter, 2, (LPSTR)pPrinterInfo, cByteNeeded, &cByteUsed)
3番目の引数が (LPSTR) は誤記で、(LPBYTE) が正みたい。
EnumJobs() のあと、PagesPrinted を取得するところで奮戦中です。
EnumJobs() のあとに、次のコードを入れてやってみましたが、何ページ印刷しても、結
果は 0 ページとなります。
DWORD result = pJobStorage->PagesPrinted;
wchar_t test[16];
_itow_s(result, test, 16, 10);
MessageBox(CString(test));
印刷が終わる前に結果が表示されてしまいます。
ちなみに、result = pJobStorage->TotalPages; をやると、印刷するトータル枚数が正し
く表示されます。
EndPrinting() の中にコードを書いていますが、これがいけないのでしょうか。
ネットを検索すると、”PagesPrinted は not reliable”という記事が出ています。
当方、Windows 8.1 です。