LoginSignup
oota_torao
@oota_torao (太田 とらお)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Windowsのプリンタ制御について

Windows10でプリンタ制御をしています。
印刷自体はできるのですが、印刷中やエラー状態を取得することが出来ません。
アプリの中で印刷中やエラー状態を画面で表示したいので
プリンタの状態を取得する方法は無いでしょうか?

開発環境は以下の通りです。
Windows10
python3.9
ブラザーのプリンタをイーサネットで接続しPortをTCP/IPポートで接続しています。

例)
WindowsのAPIを呼び出す為にwin32printingを使用しています。
印刷する為に以下のコードを実行します。

printer_name = win32print.GetDefaultPrinter()
hPrinter = win32print.OpenPrinter( printer_name )
hDC = win32ui.CreateDC ()
hDC.StartDoc(image_path)
hDC.StartPage()
// ここで画像を作成して screenは印刷する画像イメージです。
dib = ImageWin.Dib( screen )
dib.draw( hDC.GetHandleOutput(), (0, 0, int(screen.width*2), int(screen.height*2)) )

hDC.EndPage ()
hDC.EndDoc ()
hDC.DeleteDC ()

ジョブに追加されるので以下の処理をループさせて
プリンタの状態を取得しようとGetPrinterしていますが取得できません。

pr_ret = win32print.GetPrinter( hPrinter, 6 )
print( f"プリンタステータス:0x{pr_ret['Status']:08x}" )

発生している問題

印刷ジョブを実行した後、印刷中のステータスになるかと思ったのですが
全くステータスが取得できていません。
その他、用紙なし等も取得できません。

win32printのGetPrinterは状態を取得する関数だと思っているのですが
呼び出すタイミングや呼び出し方に制限があるのでしょうか?

0

2Answer

私がやるなら、、、
手動で印刷、オフライン、用紙なしの状態にしておいて、以下コード(コピペです)が期待通りとなるか試しますね。

pr_ret = win32print.GetPrinter( hPrinter, 6 )
print( f"プリンタステータス:0x{pr_ret['Status']:08x}" )
0

Comments

  1. @oota_torao

    Questioner
    ありがとうございます。

    試したところ期待通りになりませんでした。
    win32print.GetPrinterではプリンタのステータスが取れないってことなんでしょうか…

    やり方にこだわりは無いので、エラー系を取得できる方法が他にあればとは思っておるのですが
  2. ありがとうございます、予想通り、条件は絞れましたね。時間あったら試してみます。
  3. @oota_torao

    Questioner
    imagouさんありがとうございます。

    確かに6対応してないですね…
    Statusがある2で試してみます。


    他にも調べておるのですが
    SNMPというのでプリンタの状態を取得できる可能性があるのか見ています。
  4. @oota_torao

    Questioner
    2も同じ動作をしていました。
  5. @oota_torao

    Questioner
    どうやら、プリンタのポートによって動作が違うようです。
    完全解決とはなっておりませんが値が返ってくる場合ありました。

    値が返ってくる場合
    WSDポート※レスポンスが遅いのはありますが状態の取得が出来ているようです。

    値が返ってこない場合
    TCP/IPポート
    USBポート

  6. @oota_torao

    Questioner
    imagouさんありがとうございます。

    とりあえず、プリンタの情報は取れております。

    ただ、PythonからPowerShellを実行は経験がなく
    簡単に呼び出してみたところstdoutには結果がでましたが
    プログラム側で使うことが出来ておりません。

    その辺り調べてみます。
  7. Pythonから(PowerShellというか)WMIを呼ぶにせよ、Win32 APIを呼ぶにせよ、いくらでもネットに情報はあると思いますので、頑張ってみてください!
  8. @oota_torao

    Questioner
    試してみました。

    以下の様にpowershellから
    os.system( "powershell -Command Get-WmiObject Win32_Printer >> .out.txt" )
    で一度テキストにしてから
    再度読み込み対応してみました。

    結果、TCP/IPではPrinterStatusが返ってくる時と来ない時がある。
    用紙切れ等のエラー状態が返ってこないという結果になりました。

    PrinterStatusとして 3または4
    >ウェブサイトから抜粋
    >アイドル ( 3)
    >
    >アイドル - 詳細については、以下の「解説」セクションを参照してください。
    >
    >印刷 (4)
    4が一瞬だけ送られてきて、その後3になってしまうようです。
    用紙を抜いた状態だとずっと3が返ってきています。

    エラー検知をしたいのですが…
  9. pywin32をお使いだと思うのですが、自身でWin32 APIをゴリゴリと呼んでみたらどうなるんでしょうね?
    VC++で試すのが手っ取り早い気もしますが(すみません、適当に書いています)。

    いずれにせよ、TCP/IPでダメなときがある問題がついて回るのなら、使い物にならないのかもですけれども。
  10. @oota_torao

    Questioner
    諸々ありがとうございます。

    基本的にWin32APIで記載している…つもりです…

    Win32APIを呼び出すようなやり方でPythonで記載しています。

    win32printing.GetPrinterがWin32APIなのでそれで取れないのがもう解せないってなっております(笑

    そもそも、WindowsOS自体がプリンタの制御をそんなに頻度高くやっていないのか?と
    思っており
    ならば、SNMPで直接プリンタからデータを取れないのか?って思っているところです。

    プリンタメーカーのブラザーが出しているプリンタのステータスを見るツールをみると
    状態が取れているので取れる方法はあるけれど、公開されている方法ではないということなんだと思います。

即興で書いてみました。ctypesを使ってゴリゴリ呼ぶ方式です。
これでもタイムリーに取れないってことであれば、Windowsの仕様でしょう。

import sys
import ctypes
import ctypes.wintypes

class PRINTER_INFO_6(ctypes.Structure):
  _fields_ = [
    ("dwStatus", ctypes.wintypes.DWORD),
  ]

winspool = ctypes.WinDLL("Winspool.drv")
PrinterName = ctypes.wintypes.LPSTR(b"プリンター名")
hPrinter = ctypes.wintypes.HANDLE()
dwNeeded = ctypes.wintypes.DWORD()

ret = winspool.OpenPrinterA(PrinterName.value, ctypes.byref(hPrinter), None)
if ret == 0:
  raise Exception("OpenPrinterA failed")

winspool.GetPrinterA(hPrinter, 6, None, 0, ctypes.byref(dwNeeded))
Printer=(ctypes.c_ubyte * dwNeeded.value)()
ret = winspool.GetPrinterA(hPrinter, 6, Printer, dwNeeded, ctypes.byref(dwNeeded))
if ret == 0:
  raise Exception("GetPrinterA failed")

pInfo = ctypes.cast(Printer, ctypes.POINTER(PRINTER_INFO_6))
dwStatus = pInfo.contents.dwStatus
print("dwStatus:", dwStatus)

ベンダのSDKを使えば確実ですかね。

0

Your answer might help someone💌