プリンタのオンライン/オフラインの判定ができません

解決


タルト  2013-06-12 20:52:56  No: 44661

プリンタのオンライン/オフラインの判定をするのに
下記のようにしましたが、戻ってくるステータスの値は
0のままです。DELPHI 5, Win XPです。
よろしくお願いいたします。

ListBoxにプリンタが列挙されている状態で
procedure TForm1.ListBox1Click(Sender: TObject);
VAR
  hPrinter   : THandle       ;
  pPrntrInf2 : PPrinterInfo2 ;
  cbNeeded   : Cardinal      ;
BEGIN
  WinSpool.OpenPrinter( PChar( ListBox1.Items[ ListBox1.ItemIndex ] ), hPrinter, NIL ) ;
  IF  hPrinter = INVALID_HANDLE_VALUE  THEN
    EXIT ;
  WinSpool.GetPrinter( hPrinter, 2, NIL, 0, @cbNeeded ) ;
  pPrntrInf2 := AllocMem( cbNeeded ) ;
  TRY
    WinSpool.GetPrinter( hPrinter, 2, pPrntrInf2, cbNeeded, @cbNeeded ) ;
    IF  ( pPrntrInf2^.Status AND PRINTER_STATUS_OFFLINE ) = PRINTER_STATUS_OFFLINE   THEN
      ShowMessage( 'オフライン' ) ;
    FINALLY
      FreeMem( pPrntrInf2 ) ;
      WinSpool.ClosePrinter( hPrinter ) ;
  END ;
END;


タルト  2013-06-14 18:52:45  No: 44662

下記のサイトなどを参考にしてMicrosoftのScript Control
タイプライブラリを取り込んで、DelphiからVBを実行すること
によりプリンタのオン・オフラインを判定することができました。
  迂遠な方法で釈然としませんが、とりあえず必要な情報はえられ
ました。VBに相当するDelphiのコードはどうなるのか引き続き調べて
見たいと思います。
  質問をごらんになって考えてくださった方に御礼申し上げます。

http://www.vbforums.com/showthread.php?532954-RESOLVED-Printer-status-detecting-on-or-off
http://oshiete.goo.ne.jp/qa/120709.html

USES
 MSScriptControl_TLB ;
PROCEDURE TForm1.ListBox1Click( Sender: TObject ) ;
VAR
  VB_Script : STRING ;
  ScriptControl : TScriptControl ;
begin
  VB_Script := 'GetObject("winmgmts:\\.\root\CIMV2").Get("Win32_Printer=''' + ListBox1.Items[ ListBox1.ItemIndex ] + '''").WorkOffline' ;
  ScriptControl := TScriptControl.Create( Application ) ;
  ScriptControl1.Language := 'VBScript' ;
  IF  ScriptControl1.Eval( VB_Script )  THEN
    ShowMessage( 'オフライン' ) ;
  ScriptControl.Free ;
end;


タルト  2013-06-14 18:58:16  No: 44663

一部訂正
上記コードの最終から5,6行目にある
ScriptControl1はScriptControl
と訂正します。


Harry  2013-06-14 21:49:24  No: 44664

判定はなかなか条件が厳しいようですね。たとえばこちらの話。

プリンターの電源が入っているかの確認 - Visual Basic 掲示板
http://madia.world.coocan.jp/cgi-bin/VBBBS/wwwlng.cgi?print+200306/03060053.txt

要約すると…GetPrinterによるStatusはドライバの仕様でほぼ0のみ、メーカーのユーティリティーを
常駐すれば取れることもある、双方向通信(双方向サポート)が有効でないとダメ、とか。
これを裏付けるような情報がMSにもありました。

プリンタと印刷ジョブの状態の取得方法 - Microsoft サポート
http://support.microsoft.com/kb/160129/ja
>プリンタの状態をより簡単に判断する方法は、PRINTER_INFO 構造体の Status メンバを確認することです。
>この構造体は、GetPrinter 関数によって取得できます。
(中略)
>ただし、通常、Windows のデフォルトのポート モニタは、プリンタの Status メンバの
>PRINTER_STATUS_ERROR ビット以上の情報を設定しません。


Harry  2013-06-14 21:51:32  No: 44665

WMIを使っても、私の環境ではどのプリンタ(実機と仮想のPDF等)も常にOnline&Idleなんですよねー。
もちろんVBScript、Delphiともに。メーカーのユーティリティは電源オフを感知して示してるんですが。
環境:Delphi6 Personal、WindowsXP、Brother MFC-J615N Printer

■VBScript
If GetObject("winmgmts:\\.\root\CIMV2").Get("Win32_Printer=""Brother MFC-J615N Printer""").WorkOffline Then
  WScript.Echo "Offline"
Else
  WScript.Echo "Online"
End If

■Delphi
implementation

{$R *.dfm}

uses
  ComObj;

const
  mWorkOffline: array[Boolean] of String =(
    'Online', 'Offline'
  );
  mPrinterStatus: array[0..7] of String =(
    '*Undefined Value*',
    'Other', 'Unknown', 'Idle', 'Printing', 'Warming Up',
    'Stopped printing', 'Offline'
  );

procedure TForm1.Button1Click(Sender: TObject);
var
  oLocator:  OleVariant;
  oService:  OleVariant;
  oClassSet: OleVariant;
  oClass:    OleVariant;
begin
  oLocator:=CreateOleObject('WbemScripting.SWbemLocator');
  oService:=oLocator.ConnectServer;

  oClassSet:=oService.ExecQuery('Select * From Win32_Printer');

  Memo1.Lines.Add('--------------------------------------');

  // 本当は '\\マシン名\root\cimv2:Win32_Printer.DeviceID="プリンタ名"' らしい
  oClass:=oClassSet.Item('Win32_Printer.DeviceID="'+Edit1.Text+'"');

  Memo1.Lines.Add('プリンタ名:'+VarToStr(oClass.Name));
  Memo1.Lines.Add('WorkOffline:'+mWorkOffline[Boolean(oClass.WorkOffline)]);
  Memo1.Lines.Add('PrinterStatus:'+mPrinterStatus[Integer(oClass.PrinterStatus)]);

  oClass:=   Unassigned;
  oClassSet:=Unassigned;
  oService:= Unassigned;
  oLocator:= Unassigned;
end;

Delphi長杉…。


Harry  2013-06-14 22:08:35  No: 44666

procedure TForm1.Button2Click(Sender: TObject);
var
  oClass: OleVariant;
begin

  oClass:=OleVariant(CreateOleObject('WbemScripting.SWbemLocator')).ConnectServer.
    ExecQuery('Select * From Win32_Printer').Item('Win32_Printer.DeviceID="'+Edit1.Text+'"');

  Memo1.Lines.Add('--------------------------------------');
  Memo1.Lines.Add('プリンタ名:'+VarToStr(oClass.Name));
  Memo1.Lines.Add('WorkOffline:'+mWorkOffline[Boolean(oClass.WorkOffline)]);
  Memo1.Lines.Add('PrinterStatus:'+mPrinterStatus[Integer(oClass.PrinterStatus)]);

  oClass:=Unassigned;
end;


Harry  2013-06-14 22:10:36  No: 44667

↑悔しいので、無理やり短くしてみました。失礼しました。


タルト  2013-06-14 22:49:20  No: 44668

Harryさん、ありがとうございました。
まったく「Delphi長杉…」ですね。
歯がゆいですがしょうがありません。

  ちなみに今回のアプリケーションで使って
いるプリンタはSonyのUP-D897で、連続
ロール紙への印刷になります。
  オフライン判定法がわからないうちは、
一度小さい白字で1行出力してみて、2,3秒後
にSpoolerにJobが残っているようだったら
オフラインとみなしてJobをPurgeしていました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加