…というお題でぐぐっても結構な数がヒットするし、解決方法はいろいろあるようだ。フリーウェアでよさげなものもある。
車輪の再発明というのは基本的に行わないのだが、金の絡んだ頼まれ仕事だと、「フリーウェア使って!」つーわけにもいかなかったりするし、事前・事後処理が必要だったりもするので、仕方が無いので自前でナントカすることにした。 のだが。 Webを漁ってみると、どうも思ったとおりにいかないという記録も多い。 結局、引っかかるところはみな同じなわけである。 対象ファイルがひとつふたつならいいのだが、数千ファイル想定の連続印刷の場合、前の印刷が完了してから、次の印刷を開始しないとキューが溜まり過ぎて破綻する恐れがある。 特に俺の場合、後流でキューファイルを操作する必要があり、できれば「溜めたく」ない。 またできるだけ安価にやりたいので、Acrobat Readerを使って…というセンが真っ先に思いつくが、コイツがなかなか難物である。 Adobeのドキュメントを読むと、AcroRd32.exeにはコマンドラインオプションがあるので一瞬バッチファイルでずらずら並べりゃいいやシメシメと思うが、これが書いてある通りに動かない(/tオプションとか。バージョンにもよるのかもしれないが、Acrobat7でなきゃいけないという条件なので)。 こちらの期待通りに動いてくれないので、印刷が終わったという情報が上手く得られず、印刷終了を待って次の印刷つーことが難しい。 結局のところ、
Acrobat Reader自体はActiveXなのでCOMインタフェイスを持っているから、殆どの言語から生成してメソッドを呼べる。ところが印刷関係のメソッドは印刷終了の戻り値もなきゃコールバックも出来ないらしく、「印刷終了」の感知が難しいのである。 うううううううむ。と10分ばかり考え込んでしまったが、仕方が無いのでこうすることにした。 発想を変えて、Acrobat自体の終了報告には頼らずに、出した結果の方を監視することにしたのである。
まずは、出力しているプリンタの状態を見て登録されているジョブ数を確認する関数を用意する。Win API の GetPrinter を使うが、ここでは出し先がネットワークプリンタなので、PrinterInfo2構造体へ突っ込む。 //============================================================================= // プリンタのステータスとジョブ数返す。 // PrinterName : プリンタ名 // JobCount(var): 登録されているジョブ数 // 戻り:ステータス //============================================================================= function PrinterStatus(const PrinterName: String; var JobCount: Cardinal): LongWord; var Count: LongWord; hPrinter: THandle; JobInfoCount: LongWord; JobInfo2: PJobInfo2; PrinterInfo2: PPrinterInfo2; begin Result := 0; if OpenPrinter(PChar(PrinterName),hPrinter,nil) then begin Count := 0; GetPrinter(hPrinter,2,nil,0,@Count); GetMem(PrinterInfo2,Count); GetPrinter(hPrinter,2,PrinterInfo2,Count,@Count); FreeMem(PrinterInfo2); Count := 0; EnumJobs(hPrinter,0,1,2,nil,0,Count,JobInfoCount); GetMem(JobInfo2,Count); EnumJobs(hPrinter,0,1,2,JobInfo2,Count,Count,JobInfoCount); JobCount := JobInfoCount; if (JobInfoCount > 0) and (JobInfo2.Status <> 0) then begin if (JobInfo2.Status and JOB_STATUS_BLOCKED_DEVQ) <> 0 then Result := Result or PRINTER_STATUS_ERROR; if (JobInfo2.Status and JOB_STATUS_DELETING) <> 0 then Result := Result or PRINTER_STATUS_PENDING_DELETION; if (JobInfo2.Status and JOB_STATUS_ERROR) <> 0 then Result := Result or PRINTER_STATUS_ERROR; if (JobInfo2.Status and JOB_STATUS_OFFLINE) <> 0 then Result := Result or PRINTER_STATUS_OFFLINE; if (JobInfo2.Status and JOB_STATUS_PAPEROUT) <> 0 then Result := Result or PRINTER_STATUS_PAPER_OUT; if (JobInfo2.Status and JOB_STATUS_PAUSED) <> 0 then Result := Result or PRINTER_STATUS_PAUSED; if (JobInfo2.Status and (JOB_STATUS_PRINTING or JOB_STATUS_RESTART)) <> 0 then Result := Result or PRINTER_STATUS_PRINTING; if (JobInfo2.Status and JOB_STATUS_USER_INTERVENTION) <> 0 then Result := Result or PRINTER_STATUS_USER_INTERVENTION; end; FreeMem(JobInfo2); ClosePrinter(hPrinter); end end; //============================================================================= // PrinterNameのプリンタの印刷ジョブ数を返す関数 //============================================================================= function TForm1.GetPrintJobCount(PrinterName: String): Cardinal; var aJobCount: Cardinal; PrnStat: LongWord; begin aJobCount := 0; PrnStat := PrinterStatus(PrinterName, aJobCount ); // ホントはステータス(PrnStat)をみるべきだが、めんどいので略 Result := aJobCount; end; こういう関数を用意し、大筋こんな感じでループ内で監視することにした。 PrintCount := GetPrintJobCount(Printername); // 印刷前の取得数を印字待ちなしと看做す AcroPDF1.LoadFile(WideString(FileName)); // ファイルをロードして AcroPDF1.printAllFit(True); // ダイアログなし印刷で // データのポスト待ち if GetPrintJobCount(Printername)=PrintCount then begin while True do begin Application.ProcessMessages; if GetPrintJobCount(Printername)>PrintCount then break; Sleep(1); end; end; // 終了待ち while True do begin Application.ProcessMessages; if GetPrintJobCount(Printername)<=PrintCount then break; Sleep(1); end; どうもなんともカッコ悪いうえに、動作環境の仮定が多く、破綻するケースが容易に想像できる方法であるが(核爆)、しょせん一発モノなんで(笑) いちおう、1万ファイル程度処理してみたが上手くいったのでよかったよかった。
by SIGNAL-9
| 2008-03-27 15:52
| TIPSとかKludgeとか
|
カテゴリ
全体 一般の話題 奇妙な論理 奇談・異聞 秋葉原 研究(笑) 町歩き 古い話 東電災害 電算機関係の話題 情報保護・セキュリティ 読んだり見たり TIPSとかKludgeとか 拙作ソフトウェア 未分類 最新の記事
記事ランキング
以前の記事
最新のトラックバック
その他のジャンル
ブログジャンル
画像一覧
|
ファン申請 |
||