何となく Blog by Jitta
Microsoft .NET 考

目次

Blog 利用状況
  • 投稿数 - 761
  • 記事 - 18
  • コメント - 37042
  • トラックバック - 222
ニュース
  • IE7以前では、表示がおかしい。div の解釈に問題があるようだ。
    IE8の場合は、「互換」表示を OFF にしてください。
  • 検索エンジンで来られた方へ:
    お望みの情報は見つかりましたか? よろしければ、コメント欄にどのような情報を探していたのか、ご記入ください。
It's ME!
  • はなおか じった
  • 世界遺産の近くに住んでます。
  • Microsoft MVP for Visual Developer ASP/ASP.NET 10, 2004 - 9, 2011
広告

記事カテゴリ

書庫

日記カテゴリ

ギャラリ

その他

わんくま同盟

同郷

 

プリンターのお話し。

直接会ったことのある方々にはお話ししているように、ここ数年、Windows から離れて Linux にかかりっきりです。プリンターに関わっているのですが、その為に、WinSpool.drv 等のプリンターに関わる API をいじらなくてはならないことも。基本、Windows じゃないのですけどね。でも、もう、C++、というか、Visual C++(Managed C++, C++/CLR 含む)は、いじりたくないです。何とか、C# でやっています。

で、プリンターの試験を行っていると、特定の条件で特定のファイルを何度も印刷することがあります。一般社団法人電子情報技術産業協会という協会があるのですが、そこから印刷における標準的なドキュメントが出ているので、それを印刷します。アプリケーションから印刷するとき、印刷ダイアログに「ファイルに出力する」というチェックボックスがあって、これをチェックしたときに出来る .prn ファイル。こいつは、スプーラーが貯め込んでいるファイルとほぼ同じで、ドライバーがプリンター用に作ったデータそのものです(他にスプーラー用の情報ファイルが出来るので、「ほぼ同じ」と表現した)。この .prn ファイルを作っておいて、ポイっと投げてやれば、いちいちアプリケーションを起動したり、印刷設定をし直したり、Microsoft Word だったら終了時に問い合わせがなくなっていいよね!!というのが狙い。ああ、ファイルは、Microsoft Excel、Microsoft PowerPoint、Microsoft Word、Adobe Reader 用のものがあります。それぞれ、別のアプリケーションで開かなきゃいけないのも、1つで事足りるよね!

やり方は、Windows GDI の、Printing and Print Spooler で定義されている、OpenPrinter 関数でプリンターを開き、StartDocPrinter 関数でこれからデータを投げることを通知して、WritePrinter 関数で書き込む、全部書き終わったら ClosePrinter 関数で閉じる、と。アプリケーション フォームには、ファイルを指定する方法と、プリンターを指定する方法を用意しておけばよい、と。そんなに難しいものではありませんね。チャチャっと作っちゃいましょう。

で、作ったのですが、欲が出てきた。プリンターとしての機能の試験をしているので、印刷指示をした後、プリンターが動かないと、プリンター(のファームウェア)が悪いのか、印刷指示が出来ていないのか、わからない(複数のファイルを交互に投げることがあるので、印刷ファイルを列挙するために ListView を使うと、クリックするところによって選択状態が外れてしまい、「印刷指示が出来ていない」という状態が出来てしまった)。プリンター フォルダーを表示していればわかりますが、そうでなくてもたくさん開いているウィンドウを、少なくしたい。ならば、プリンター一覧に、プリンター フォルダーで表示しているのと同じ内容を表示してやれば良いではないか。

ということで、情報を表示させます。EnumPrinters 関数は、PRINTER_INFO という構造体の配列を作って呼び出すと、そこへデータを放り込んでくれます。PRINTER_INFO 構造体は、1~9の9種類あるのですが、いくつかは廃止されています。EnumPrinters 関数に対して有効なのは、1, 2, 4, 5 の4種類です。プリンターの状態は、PRINTER_INFO_2 構造体(英語)に、Status として定義されています。こいつを拾い出しましょう。

という修正を施して、実行しました。Statu に0が返ってきています。USB で接続したプリンターの、USB ケーブルを抜きました。プリンター フォルダーでは、「オフライン」表示に変わりました。PRINTER_INFO_2 構造体は…0のままです。なんで?

Bing って回ったところ、どうも、ドライバーが正しい情報を返していないらしいです。なんてこったい!!そうすると、ちゃんと「オフライン」と表示されるプリンター フォルダーは、どこから情報を得ているんだろう?

ついでに書いておくと、WMI で、Win32_Printer にアクセスすると、同じように情報が取れます。HTML と組み合わせて Windows Sidebar Gadget にすれば、コンパクトにプリンターの状態を監視することも可能です。とはいえ、ネットワーク プリンターの場合、他の人が印刷しているのはわからないのですが。あ、それもドライバーがプリンターと通信していればわかるのか。Web Service on Devices に対応しているなら、デバイスに直接尋ねに行くから、必ず正しいステータスがわかるのね。

おっともうひとつ。上記方法では、EnumPrinters を実行したときのプリンターの状態しかわかりません。それで情報が取れるのを確認してから、FindFirstPrinterChangeNotification 関数などを使おうとしていたのですが、ドライバーが情報を返していないのなら、仕方ないですよね。


なんて原稿を用意した後、メールの整理をしていたら、2008年9月に、こんな問い合わせをしていた。なんてこったい、FindFirstPrinterChangeNotification 関数を使えだって!

[お問い合わせの概要]
メーカー提供のポートモニタに対して WMI の Win32_Printer:PrinterStatus を問い合わせると、印刷後 "Unknown"となり、標準の TCP/IP ポートモニタと異なるが、この原因を解明する方法、対処方法を知りたい。


[回答]
ポート モニタを含めて、スプーラ サービス内のステータスに依存して、WMI の Win32_Printer:PrinterStatus の値が異なることがございます。また、このようなスプーラ サービスのステータスは、拡張コンポーネントに依存性が高く、本件では、ポート モニタやランゲージ モニタに依存している可能性が高いと思われます。

具体的な例といたしまして、これらのプリント モニタは、少なくとも EndDocPort 関数内にて、SetJob 関数に以下のコマンドを指定する必要がございます。
    ポート モニタ: JOB_CONTROL_SENT_TO_PRINTER
    ランゲージ モニタ: JOB_CONTROL_LAST_PAGE_EJECTED

また、このコマンドの指定のタイミングや順番などに依存して、標準の TCP/IP ポートモニタとは異なる可能性がございます。併せまして、標準の TCP/IP ポートモニタでは、SNMP でプリンタのステータスを監視し、その状態をスプーラ サービスのステータスに反映するため、ステータスの差異が発生する可能性がございます。


続きまして、本件では、印刷が開始できる状態なのかどうかを判断するために、Win32_Printer:PrinterStatus を確認されているとお伺いいたしました。このステータスは、一般的なステータスに分類分けをされておりますが、細かなステータスをチェックすることができません。印刷が開始できる状態なのかどうかを判断は、プリンタに依存するステータスもあるため、プリンタの細かなステータスで、判断されたほうがよいかと存じ上げます。

そのような細かなステータスを取得する観点より、Win32_Printer:PrinterState は、スプーラ サービスから取得した情報 (PRINTER_INFO_6 構造体) の値となっておりますため、より詳細な状態をチェックすることが可能でございます。ただ、このプロパティは、obsolete であり将来的には、未サポートとなる可能性がございますことをご注意ください。


また、Win32 API とはなりますが、以下にご案内申し上げますサンプル コードにて、コントロールパネルの [プリンタと FAX] にて表示されるプリンタ キューの情報と同等な方法で、同等な情報が取得可能でございます。

    Microsoft サポートオンライン「PrintMon.exe Demonstrates the Win32 Spooler API」
    http://support.microsoft.com/kb/196805/en-us(英語)
    ※ Windows 9x/Me では、ポーリング形式
    ※ Windows 2000 以降では、イベント形式 (FindFirstPrinterChangeNotification/FindNextPrinterChangeNotification)

以上のとおりお伝えいたします。

投稿日時 : 2012年1月25日 22:35
コメント
タイトル
名前
Url
コメント