|
Delphi Programming / Object Pascal

[掲載 2009年03月18日] [更新 2013年10月23日] Delphi サンプルプログラム集 |
| 010_PRINTER_INFO 構造体とプリンタの列挙 |
| 動作確認等 |
Windows 7 U64(SP1) + Delphi XE Pro |
 |
010_Printer_Info_Structure.zip [3,947 KB] 2013年10月23日版 (EXE 同梱) |
プリンタ情報構造体、PRINTER_INFO_X (X は数字)を使用してプリンタを列挙したり、その情報を取得するサンプルプログラムです。この構造体は 9 までありますが、Delphi の WinSpool.pas で定義されているのは 6 までです。
サンプルでは、原則 Windows 9X 関係の説明と処理コードは省略しています。
PRINTER_INFO 構造体を含め、プリンタ、印刷関係の関数の詳しい説明は、MSDN ライブラリを参考にしてください。これらの関数を使用するには uses に WinSpool が必要です。
変数の型名は、MSDN ライブラリの表記を用いています。Delphi では別の型名を使用しなけれならない場合があります。テストプログラムのコード、あるいは、コード補完機能等で確認してください。
以下は、このサンプルプログラムで使用している関数の簡単な説明です。
プリンタの情報を取得する際、物理プリンタと直接通信することはありません。プリンタドライバとの通信となります。プリンタドライバが提供していない情報は取得できません。また、プリンタドライバに印刷ジョブを送信しないと取得できない情報もあります。プリンタドライバによっては、実際の物理プリンタの状態を取得可能にしているものもあります。
物理プリンタと直接通信する方法もあります。プリンタデバイスに直接コマンドを送信します。それには、プリンタのメーカーが提供している、それらのコマンド類の仕様を知る必要があります。
MS-DOS の時代は、この方法で印刷のプログラムを作成していました。したがって、プリンタメーカーあるいは、プリンタによって印刷のコードが違うこともありました。
本ページで扱う、プリンタ関係情報の列挙用 Windows API は 2 回の呼び出しが必要です。1 回目は情報の格納に必要なメモリサイズの取得、次に実際の情報取得です。この手順は、多くの Windows API で使われる手法です。 |
| 利用可能なプリンタ、プリントサーバー、ドメイン、プリントプロバイダを列挙する関数です。関数が成功すると True を返します。引数は、左から順番に下表の内容となっています。 |
| Flags |
DWORD |
列挙するプリンタオブジェクトの種類を、次の表の値の組合せで指定する
Level4 では 、PRINTER_ENUM_CONNECTIONS と PRINTER_ENUM_LOCAL のみ使用可能 |
| pName
|
LPTSTR |
nil またはプリントプロバイダ、サーバ名、ドメイン名
この値と Lebel の値と、Flags の組合せによって取得できる列挙リストが異なる
詳細は MSDN ライブラリの記事を参照 |
| Level |
DWORD |
プリンタ情報構造体のタイプ番号
PRINTER_INFO_1 の内容を取得したい場合は 1
PRINTER_INFO_2 の内容を取得したい場合は 2
... |
| pPrinterEnum |
LPBYTE |
プリンタ情報構造体のバッファ
関数実行後、このバッファに複数の構造体の配列が格納される
各構造体がプリンタオブジェクトに関するデータを表わす |
| cbBuf |
DWORD |
バッファのサイズをバイト数で指定する |
| pcbNeeded
|
LPDWORD |
関数が成功すると、コピーされたバイト数が格納される
0 を与えると必要なバイト数を返す |
| pcReturned |
LPDWORD |
関数実行後、構造体の数が格納される |
表2
EnumPrinters 関数の Flags パラメータで指定するプリンタオブジェクトの種類 |
| PRINTER_ENUM_LOCAL |
pName パラメータを無視し、ローカルにインストールされているプリンタを列挙する |
| PRINTER_ENUM_NAME |
pName で指定したプリンタを列挙する
pName にはサーバー、ドメイン、プリントプロバイダのいずれかを指定する
pName が nil の場合、使用可能なプリントプロバイダ列挙 |
| PRINTER_ENUM_SHARED |
共有属性のプリンタを列挙する
単独では使用できない。他の値と組み合わせて使用する |
| PRINTER_ENUM_DEFAULT |
Win 9X 用 |
| PRINTER_ENUM_CONNECTIONS |
接続続を確立しているプリンタのリストを列挙する |
| PRINTER_ENUM_NETWORK
|
Lebel の 値が 1 の時のみ有効な値
コンピュータと同じドメイン内のネットワークプリンタを列挙する |
| PRINTER_ENUM_REMOTE |
Lebel の値が 1 の時のみ有効な値
コンピュータと同じドメイン内の、ネットワークプリンタとプリントサーバーを列挙する |
EnumPrinters 関数の使用例です。
使用可能なプリンタ全ての数と、共有プリンタの数を取得して表示します。 |
 |
図1
設計時画面 |
 |
図2
実行画面
|
リスト1
EnumPrinters 関数を使用して、使用可能なプリンタ全ての数と、共有プリンタの数を取得 |
unit PrintersCountUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Printers, WinSpool, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//=============================================================================
// 使用可能なプリンタ数を求める
//
// TPrinterのPrinters.Countを使用
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
Cnt : Integer;
begin
Cnt := Printer.Printers.Count;
MessageBox(Handle, PChar(IntToStr(Cnt)), '情報', MB_ICONINFORMATION);
end;
//=============================================================================
// 使用可能なプリンタ数を求める
//
// EnumPrinters APIを使用
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
Flags : Cardinal;
dwNeeded : Cardinal;
dwReturn : Cardinal;
pPinfo4 : PPrinterInfo4;
begin
dwNeeded := 0;
dwReturn := 0;
//プリンタ情報を得る準備
Flags := PRINTER_ENUM_CONNECTIONS or PRINTER_ENUM_LOCAL;
dwNeeded := 0;
//バッファ長を得る
EnumPrinters(Flags, nil, 4, nil, 0, dwNeeded, dwReturn);
if dwNeeded <> 0 then begin
//構造体の配列に必要なバイト数を確保
GetMem(pPinfo4, dwNeeded);
try
//プリンタ情報(Level=4)を取得
EnumPrinters(Flags,
nil,
4,
Pointer(pPinfo4),
dwNeeded,
dwNeeded,
dwReturn);
finally
FreeMem(pPinfo4);
end;
end;
MessageBox(Handle, PChar(IntToStr(dwReturn)), '情報', MB_ICONINFORMATION);
end;
//=============================================================================
// 使用可能なプリンタ数の共有プリンタ数求める
//
// EnumPrinters APIを使用
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
Flags : Cardinal;
dwNeeded : Cardinal;
dwReturn : Cardinal;
pPinfo4 : PPrinterInfo4;
begin
dwNeeded := 0;
dwReturn := 0;
//プリンタ情報を得る準備
Flags := PRINTER_ENUM_LOCAL or PRINTER_ENUM_SHARED;
dwNeeded := 0;
//バッファ長を得る
EnumPrinters(Flags, nil, 4, nil, 0, dwNeeded, dwReturn);
if dwNeeded <> 0 then begin
//構造体の配列に必要なバイト数を確保
GetMem(pPinfo4, dwNeeded);
try
//プリンタ情報(Level=4)を取得
EnumPrinters(Flags,
nil,
4,
Pointer(pPinfo4),
dwNeeded,
dwNeeded,
dwReturn);
finally
FreeMem(pPinfo4);
end;
end;
MessageBox(Handle, PChar(IntToStr(dwReturn)), '情報', MB_ICONINFORMATION);
end;
end.
| 02_WinSpool.OpenPriner 関数 |
| 指定されたプリンタまたはプリントサーバーを識別するハンドルを取得する関数です。WinSpool.pas で定義されています。ここで取得したプリンタのハンドルを SetPrinter や GetPrinter で使用します。関数が成功すると True を返します。このハンドルは使用が終了したら、ClosePrinter で閉じなけれなりません。 |
| pPrinterName |
LPTSTR |
プリンタ名またはプリントサーバー名 |
| phPrinter |
LPHANDL |
関数が成功すると、この変数にプリンタオブジェクトまたはプリントサーバーオブジェクトを表すハンドルを返す |
| pDefault |
LPPRINTER_
DEFAULTS |
LPPRINTER_DEFAULTS 構造体
以下のメンバーがある
DesiredAccess, pDatatype, pDevMode
nil でもよい |
表4
LPPRINTER_DEFAULTS 構造体の DesiredAccess メンバーで指定可能な値 |
| PRINTER_ACCESS_ADMINISTER |
管理作業等、アクセス権などの指定の場合に指定 |
| PRINTER_ACCESS_USE |
基本的な印刷作業を行う場合に指定 |
| PRINTER_ALL_ACCESS |
SYNCHRONIZE を除き、すべての管理作業と基本的な印刷作業を行う場合に指定 |
| WRITE_DAC等 |
特定の制御アクセス権を認める場合に指定 |
| 03_WinSpool.GetPrinter 関数 |
指定したプリンタの情報を取得します。同名の関数が Printers.pas にもありますが、本項目で説明する GetPrinter は WinSpool.pas で定義されているものです。この関数を使用する前に OpenPrinter でプリンタのハンドルを取得し、関数実行後、ClosePrinter でのハンドルを閉じる操作が必要です。
関数は、成功すると True を返します。 |
| hPrinter |
HANDLE |
調査対象のプリンタを識別するハンドルを指定する。この値はOpenPrinter 関数を使って取得する |
| Level |
DWORD |
バッファに格納する構造体の番号を指定する
PRINTER_INFO_1 の内容を取得したい場合は 1
PRINTER_INFO_2 の内容を取得したい場合は 2
...
指定可能な値は 1, 2, 3, 4, 5, 7 のいずれか |
| pPrinter |
LPBYTE |
プリンタの情報を受取るプリンタ情報構造体のバッファ
格納内容は Level の値によって異なる |
| cbBuf |
DWORD |
バッファのサイズをバイト単位で指定する |
| pcbNeeded |
LPDWORD |
プリンタ情報のサイズ (バイト単位) を受け取る変数へのポインタを指定する。0 を渡すと GetPrinter は失敗するが、必要なバッファサイズをこの変数に返す。
GetPrinter が成功すると、バッファ内に格納されたバイト数をこの変数に返す。 |
| 04_WinSpool.SetPrinter 関数 |
指定されたプリンタのデータ設定または状態の変更(印刷の一時停止、印刷の再開、全ジョブの削除)を実行します。
同名の関数が Printers.pas にもありますが、本項目の SetPrinter は WinSpool.pas で定義されているものです。この関数を使用する前に OpenPrinter でプリンタのハンドルを取得し、関数実行後、ClosePrinter でのハンドルを閉じる操作が必要です。 関数は、成功するとTrue を返します。 |
| hPrinter |
HANDLE |
操作対象のプリンタを識別するハンドルを指定する。この値はOpenPrinter 関数を使って取得する |
| Level |
DWORD |
pPrinter が受け取るプリンタ情報構造体の番号を指定する。
PRINTER_INFO_1 の内容を設定する場合は 1
PRINTER_INFO_2 の内容を設定する場合は 2
...
指定可能な値は 1, 2, 3, 4, 5, 7 のいずれか
Command に 0 以外の値を指定するときは 必ず 0 とする |
| pPrinter |
LPBYTE |
プリンタに設定するデータ、または Command に指定するコマンドの情報を格納するバッファ。
バッファ内のデータの種類は Level の値によって決まる。 |
| Command |
DWORD |
実行するアクションを表す値を指定する。
Level に 0 以外の値を指定したときは必ず 0 とする。
その場合プリンタの状態はそのままで、Level と pPrinter の指定に従ってプリンタデータが再設定される。ただし、ユーザの権限によっては設定できない内容もある。 |
表7
SetPrinter 関数の Command パラメータに指定可能な値 |
| PRINTER_CONTROL_PAUSE |
プリンタを一時停止する |
| PRINTER_CONTROL_PURGE |
プリンタのすべての印刷ジョブを削除する |
| PRINTER_CONTROL_RESUME |
一時停止しているプリンタを再開する |
| PRINTER_CONTROL_SET_STATUS |
pPrinter で指定した値でプリンタの状態を設定する |
SetPrinter 関数の使用例です。
プリンタ名のリストから、選択したプリンタを一時停止、一時停止解除を行います。 |
 |
図3
設計時画面 |
 |
図4
一時停止を実行 |
 |
図5
プリンタの状態が一時停止となる |
 |
図6
一時停止解除 |
リスト2
WinSpool.SetPrinter 関数を使用して、プリンタの一時停止、一時停止解除 |
unit StopRealPrintUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Printers, WinSpool, ValEdit, ExtCtrls, Grids;
type
TForm1 = class(TForm)
Panel2: TPanel;
ListBox1: TListBox;
Panel3: TPanel;
Button1: TButton;
Button2: TButton;
Button3: TButton;
procedure FormShow(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//=============================================================================
// プリンタのリストを作成
//
// ここでは簡単にしてTPrinterオブジェクト(クラス)を使用
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
begin
ListBox1.Items.Clear;
ListBox1.Items.Assign(Printer.Printers);
ListBox1.ItemIndex := 0;
end;
//=============================================================================
// Listboxで選択したプリンタを一時停止にする
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
hPrinter : Cardinal;
Pdef : PRINTER_DEFAULTS;
PrinterName : String;
ACommand : DWORD;
begin
if ListBox1.ItemIndex<0 then exit;
//対象のプリンタ名
PrinterName := ListBox1.Items[ListBox1.ItemIndex];
//WindowsNT系の場合アクセス権が必要
ZeroMemory(@Pdef, Sizeof(PRINTER_DEFAULTS));
Pdef.DesiredAccess := PRINTER_ALL_ACCESS;
//アクセス権を指定して対象のプリンタのハンドルを取得
WinSpool.OpenPrinter(PChar(PrinterName), hPrinter, @Pdef);
if hPrinter <> 0 then begin
try
ACommand := PRINTER_CONTROL_PAUSE;
//Commandを使用するのでLevelは0とする
if WinSpool.SetPrinter(hPrinter, 0, nil, ACommand) then begin
MessageBox(Handle, '一時停止しました', '情報', MB_ICONINFORMATION);
end;
finally
WinSpool.ClosePrinter(hPrinter);
end;
end;
end;
//=============================================================================
// Listboxで選択したプリンタを一時停止を解除[印刷の再開]にする
// プリンタの状態が[準備完了]となる
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
hPrinter : Cardinal;
Pdef : PRINTER_DEFAULTS;
PrinterName : String;
ACommand : DWORD;
begin
if ListBox1.ItemIndex<0 then exit;
//対象のプリンタ名
PrinterName := ListBox1.Items[ListBox1.ItemIndex];
//WindowsNT系の場合アクセス権が必要
ZeroMemory(@Pdef, Sizeof(PRINTER_DEFAULTS));
Pdef.DesiredAccess := PRINTER_ALL_ACCESS;
//アクセス権を指定して対象のプリンタのハンドルを取得
WinSpool.OpenPrinter(PChar(PrinterName), hPrinter, @Pdef);
if hPrinter <> 0 then begin
try
ACommand := PRINTER_CONTROL_RESUME;
//Commandを使用するのでLevelは0とする
if WinSpool.SetPrinter(hPrinter, 0, nil, ACommand) then begin
MessageBox(Handle, '一時停止を解除しました', '情報', MB_ICONINFORMATION);
end;
finally
WinSpool.ClosePrinter(hPrinter);
end;
end;
end;
//=============================================================================
// Listboxで選択したプリンタをの状態を取得
// ここでは一時停止だけを検査
//
// GetPrinterの説明にはPRINTER_INFO_6は指定できないようになっているであるが、
// では、PRINTER_INFO_6の情報取得はどうするのか、ということでテスト
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
hPrinter : Cardinal;
PrinterName : String;
dwNeeded : DWORD;
InfoLevel : Cardinal;
pPinfo6 : PPrinterInfo6;
begin
if ListBox1.ItemIndex<0 then exit;
InfoLevel := 6;
pPinfo6 := nil;
//対象のプリンタ名
PrinterName := ListBox1.Items[ListBox1.ItemIndex];
//対象のプリンタのハンドルを取得
WinSpool.OpenPrinter(PChar(PrinterName), hPrinter, nil);
if hPrinter <> 0 then begin
try
//構造体に必要なバッファサイズを取得
WinSpool.GetPrinter(hPrinter, InfoLevel, nil, 0, @dwNeeded);
//構造体の配列に必要なバイト数を確保
GetMem(pPinfo6, dwNeeded);
//PRINTER_INFO_6構造体の情報を取得して表示
//時刻など表示形式は指定していないので注意
if WinSpool.GetPrinter(hPrinter,
InfoLevel,
pPinfo6,
dwNeeded,
@dwNeeded) then begin
if (pPinfo6.dwStatus and
PRINTER_STATUS_PAUSED) = PRINTER_STATUS_PAUSED then begin
MessageBox(Handle, '一時停止中です', '情報', MB_ICONINFORMATION);
end else begin
MessageBox(Handle, '一時停止中ではありません', '情報', MB_ICONINFORMATION);
end;
end;
finally
FreeMem(pPinfo6);
WinSpool.ClosePrinter(hPrinter);
end;
end;
end;
end.
表8
PRINTER_INFO_1 構造体のメンバー |
| Flags |
DWORD |
取得データに関する情報の値
詳細は MSDN ライブラリの記事参照 |
| pDescription |
LPTSTR |
構造体の内容説明の内容を表す文字列 |
| pName |
LPTSTR |
構造体の名前。プリンタ名 |
| pComment |
LPTSTR |
追加情報 |
PRINTER_INFO_1 構造体のテストプログラムです。
指定したプロバイダのプリンタ名を列挙します。 |
 |
図7
設計時画面 |
 |
図8
実行画面
- 上で取得したプリンタプロバイダを指定してプリンタ名を列挙したのが下
|
リスト3
PRINTER_INFO_1 構造体のメンバから指定プロバイダのプリンタを列挙 |
unit Printer_Info1_EnumUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Printers, WinSpool;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Memo1: TMemo;
Memo2: TMemo;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//=============================================================================
// プリンタの情報取得 PRINTER_INFO_1構造体から
//
// 第2引数をnilにして使用可能なプリントプロバイダを取得する場合
// ここでは構造体のpNameしか取得していないが、他の値も同様に取得できる
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
Flags : Cardinal;
dwNeeded : Cardinal;
dwReturn : Cardinal;
pPinfo1 : PPrinterInfo1;
pWork : PPrinterInfo1;
i : Integer;
S : String;
begin
Memo1.Lines.Clear;
pPInfo1 := nil;
dwNeeded := 0;
dwReturn := 0;
Flags := PRINTER_ENUM_NAME;
//dwNeededを0にして必要なバッファサイズを取得
//第2引数をnilにして使用可能なプリントプロバイダを取得する場合
EnumPrinters(Flags,
nil,
1,
pPInfo1,
dwNeeded,
dwNeeded,
dwReturn);
if dwNeeded=0 then exit;
//構造体の配列に必要なバイト数を確保
GetMem(pPinfo1, dwNeeded);
try
if EnumPrinters(Flags,
nil,
1,
pPinfo1,
dwNeeded,
dwNeeded,
dwReturn) then begin
pWork := pPinfo1;
for i := 0 to dwReturn - 1 do begin
S := String(pWork.pName);
Memo1.Lines.Add(S);
//次の構造体の配列に移動
Inc(pWork);
end;
end else begin
MessageBox(Handle, PChar(SysErrorMessage(GetLastError)), '', 0);
end;
finally
FreeMem(pPinfo1);
end;
end;
//=============================================================================
// プリンタの情報取得 PRINTER_INFO_1構造体から
//
// プリントプロバイダを指定して、そのプリンタのリストを取得
// ここでは構造体のpNameしか取得していないが、他の値も同様に取得できる
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
Flags : Cardinal;
pName : PWideChar;
dwNeeded : Cardinal;
dwReturn : Cardinal;
pPinfo1 : PPrinterInfo1;
pWork : PPrinterInfo1;
i : Integer;
S : String;
begin
Memo2.Lines.Clear;
pPInfo1 := nil;
dwNeeded := 0;
dwReturn := 0;
pName := 'Windows NT Local Print Providor';
Flags := PRINTER_ENUM_NAME;
//dwNeededを0にして必要なバッファサイズを取得
EnumPrinters(Flags,
pName,
1,
pPInfo1,
dwNeeded,
dwNeeded,
dwReturn);
if dwNeeded=0 then exit;
//構造体の配列に必要なバイト数を確保
GetMem(pPinfo1, dwNeeded);
try
if EnumPrinters(Flags,
pName,
1,
pPinfo1,
dwNeeded,
dwNeeded,
dwReturn) then begin
pWork := pPinfo1;
for i := 0 to dwReturn - 1 do begin
S := string(pWork.pName);
Memo2.Lines.Add(S);
//次の構造体の配列に移動
Inc(pWork);
end;
end else begin
MessageBox(Handle, PChar(SysErrorMessage(GetLastError)), '', 0);
end;
finally
FreeMem(pPinfo1);
end;
end;
end.
PRINTER_INFO_1 構造体のメンバーの値を表示するサンプルです。
プリンタのリストは、ListBox1.Items.Assign (Printer.Printers) でも取得可能です。 |
 |
図9
設計時画面 |
 |
図10
実行画面
|
リスト4
PRINTER_INFO_1 構造体のメンバーの値を取得する |
unit Printer_Info1_GetPrinterUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Printers, WinSpool, ValEdit, ExtCtrls, Grids;
type
TForm1 = class(TForm)
Panel1: TPanel;
Button1: TButton;
Panel2: TPanel;
ListBox1: TListBox;
Panel3: TPanel;
ValueListEditor1: TValueListEditor;
procedure Button1Click(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//=============================================================================
// プリンタのリストを作成
//
// ここでは簡単にしてTPrinterオブジェクト(クラス)を使用
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
PrinterName : String;
i : Integer;
begin
ListBox1.Items.Clear;
for i := 0 to Printer.Printers.Count - 1 do begin
PrinterName := Printer.Printers[i];
ListBox1.Items.Add(PrinterName)
end;
end;
//=============================================================================
// ListBox1をクリックしたら、そのプリンタの情報を表示
//=============================================================================
procedure TForm1.ListBox1Click(Sender: TObject);
var
hPrinter : Cardinal;
PrinterName : String;
dwNeeded : DWORD;
pPinfo1 : PPrinterInfo1;
begin
pPinfo1 := nil;
//対象のプリンタ名
PrinterName := ListBox1.Items[ListBox1.ItemIndex];
//対象のプリンタのハンドルを取得
WinSpool.OpenPrinter(PChar(PrinterName), hPrinter, nil);
if hPrinter <> 0 then begin
try
//構造体に必要なバッファサイズを取得
WinSpool.GetPrinterW(hPrinter, 1, nil, 0, @dwNeeded);
//構造体の配列に必要なバイト数を確保
GetMem(pPinfo1, dwNeeded);
//PRINTER_INFO_1構造体の各メンバーの情報を取得して表示
if WinSpool.GetPrinter(hPrinter, 1, pPinfo1, dwNeeded, @dwNeeded) then begin
ValueListEditor1.Cells[1, 1] := pPInfo1.pDescription;
ValueListEditor1.Cells[1, 2] := pPInfo1.pName;
ValueListEditor1.Cells[1, 3] := pPInfo1.pComment;
end;
finally
FreeMem(pPinfo1);
WinSpool.ClosePrinter(hPrinter);
end;
end;
end;
end.
表9
PRINTER_INFO_2 構造体のメンバー |
| pServerName |
LPTSTR |
サーバ名
nil の場合はローカルプリンタ |
| pPrinterName |
LPTSTR |
プリンタ名 |
| pShareName |
LPTSTR |
共有名 |
| pPortName |
LPTSTR |
ポート名
複数ある場合はカンマ区切りの文字列 |
| pDriverName |
LPTSTR |
プリンタドライバ名 |
| pComment |
LPTSTR |
プリンタの簡単な説明 |
| pLocation |
LPTSTR |
プリンタの物理的な場所 |
| pDevMode |
LPDEVMODE |
用紙の向きや解像度等、プリンタのデフォルトのデータを定義する DEVMODE 構造体 |
| pSepFile |
LPTSTR |
区切りページを作成する場合、そのファイルが使用される名前。このページは別々の印刷ジョブをプリンタに送信するために使用される |
| pPrintProcessor |
LPTSTR |
プリントプロセッサ名 |
| pDatatype |
LPTSTR |
印刷ジョブのデータを記録するために使用するタイプの指定 |
| pParameters |
LPTSTR |
デフォルトのプリントプロセッサのパラメータ |
| pSecurityDescriptor |
- |
SECURITY_DESCRIPTOR 構造体 |
| Attributes |
DWORD |
プリンタの属性を表す値の組合せ
詳細は MSDN ライブラリの記事参照 |
| DefaultPriority |
DWORD |
印刷ジョブのプライオリティ |
| StartTime |
DWORD |
プリンタ印刷ジョブ開始時刻(グリニッジ標準時間) |
| UntilTime |
DWORD |
プリンタ印刷ジョブ終了時刻(グリニッジ標準時間) |
| Status |
DWORD |
プリンタの状態を表す値の組合せ
PINTER_INFO_6 構造体では、単独でこの値の取得可能 |
| cJobs |
DWORD |
印刷ジョブのキュー番号 |
| AveragePPM |
DWORD |
1 分あたりの平均印刷ページ数 |
| プリンタ名のリストから、選択したプリンタの PRINTER_INFO_2 構造体のメンバーの値を表示するサンプルです。 |
 |
図11
設計時画面 |
 |
図12
実行画面
|
リスト5
PRINTER_INFO_2 構造体のメンバの値を取得 |
unit Printer_Info2_EnumUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Printers, WinSpool, ValEdit, ExtCtrls, Grids;
type
TForm1 = class(TForm)
Panel1: TPanel;
Button1: TButton;
Panel2: TPanel;
ListBox1: TListBox;
Panel3: TPanel;
ValueListEditor1: TValueListEditor;
procedure Button1Click(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//=============================================================================
// プリンタの情報取得 PRINTER_INFO_2構造体から
//
// 第2引数をnilにして使用可能なプリントプロバイダを取得する場合
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
Flags : Cardinal;
dwNeeded : Cardinal;
dwReturn : Cardinal;
pPinfo2 : PPrinterInfo2;
pWork : PPrinterInfo2;
i : Integer;
S : String;
begin
ListBox1.Items.Clear;
pPInfo2 := nil;
dwNeeded := 0;
dwReturn := 0;
Flags := PRINTER_ENUM_NAME;
//dwNeededを0にして必要なバッファサイズを取得
EnumPrinters(Flags,
nil,
2,
pPInfo2,
dwNeeded,
dwNeeded,
dwReturn);
if dwNeeded = 0 then exit;
//構造体の配列に必要なバイト数を確保
GetMem(pPinfo2, dwNeeded);
try
if EnumPrinters(Flags,
nil,
2,
pPinfo2,
dwNeeded,
dwNeeded,
dwReturn) then begin
pWork := pPinfo2;
for i := 0 to dwReturn - 1 do begin
S := String(pWork.pPrinterName);
ListBox1.Items.Add(S);
//次の構造体の配列に移動
Inc(pWork);
end;
end else begin
MessageBox(Handle, PChar(SysErrorMessage(GetLastError)), '', 0);
end;
finally
FreeMem(pPinfo2);
end;
end;
//=============================================================================
// ListBox1をクリックしたら、そのプリンタの情報を表示
//=============================================================================
procedure TForm1.ListBox1Click(Sender: TObject);
var
hPrinter : Cardinal;
PrinterName : WideString;
dwNeeded : DWORD;
pPinfo2 : PPrinterInfo2;
begin
pPinfo2 := nil;
//対象のプリンタ名
PrinterName := ListBox1.Items[ListBox1.ItemIndex];
//対象のプリンタのハンドルを取得
WinSpool.OpenPrinter(PChar(PrinterName), hPrinter, nil);
if hPrinter <> 0 then begin
try
//構造体に必要なバッファサイズを取得
WinSpool.GetPrinter(hPrinter, 2, nil, 0, @dwNeeded);
//構造体の配列に必要なバイト数を確保
GetMem(pPinfo2,dwNeeded);
//PRINTER_INFO_2構造体の各メンバーの情報を取得して表示
//時刻など表示形式は指定していないので注意
if WinSpool.GetPrinterW(hPrinter, 2, pPinfo2, dwNeeded, @dwNeeded) then begin
ValueListEditor1.Cells[1,1] := pPInfo2.pServerName;
ValueListEditor1.Cells[1,2] := pPInfo2.pPrinterName;
ValueListEditor1.Cells[1,3] := pPInfo2.pShareName;
ValueListEditor1.Cells[1,4] := pPInfo2.pPortName;
ValueListEditor1.Cells[1,5] := pPInfo2.pDriverName;
ValueListEditor1.Cells[1,6] := pPInfo2.pComment;
ValueListEditor1.Cells[1,7] := pPInfo2.pLocation;
ValueListEditor1.Cells[1,8] := pPInfo2.pSepFile;
ValueListEditor1.Cells[1,9] := pPInfo2.pPrintProcessor;
ValueListEditor1.Cells[1,10] := pPInfo2.pParameters;
ValueListEditor1.Cells[1,11] := IntTostr(pPInfo2.DefaultPriority);
ValueListEditor1.Cells[1,12] := IntToStr(pPInfo2.StartTime);
ValueListEditor1.Cells[1,13] := IntToStr(pPInfo2.UntilTime);
ValueListEditor1.Cells[1,14] := IntToStr(pPInfo2.cJobs);
ValueListEditor1.Cells[1,15] := IntToStr(pPInfo2.AveragePPM);
end;
finally
FreeMem(pPinfo2);
WinSpool.ClosePrinter(hPrinter);
end;
end;
end;
end.
| プリンタのセキュリティ情報を格納する構造です。Windows NT 系のみで使用可能です。 |
表10
PRINTER_INFO_3 構造体のメンバー |
| pSecurityDescriptor |
PSECURITY_DESCRIPTOR |
SECURITY_DESCRIPTOR構造体 |
| プリンタ名、サーバー名、リモート/ローカルのどちらかなど、最小限のプリンタ情報を格納する構造体です。Windows NT 系のみで使用可能です。 |
表11
PRINTER_INFO_4構造体のメンバー |
| pPrinterName |
DWORD |
プリンタ名 (ローカルまたはリモート) |
| pServerName |
LPTSTR |
サーバ名 |
| Attributes |
DWORD |
取得するプリンタオブジェクトの種類で、ローカルかリモートかを指定する
値については MSDN ライブラリの記事を参照
PRINTER_INFO_2 の値も検出できる。 |
EnumPrinters 関数の引数に、PRINTER_INFO_4 を指定して、プリンタ名を列挙するサンプルです。
Attributes 属性が PRINTER_ATTRIBUTE_HIDDEN でないものだけを列挙します。 |
 |
図13
設計時画面 |
 |
図14
実行画面 |
リスト6
PRINTER_INFO_4 構造体を使用して、プリンタ名を列挙 |
unit Printer_Info4_EnumUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Printers, WinSpool, ExtCtrls;
type
TForm1 = class(TForm)
Panel1: TPanel;
Button1: TButton;
Panel2: TPanel;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//=============================================================================
// プリンタの情報取得 PRINTER_INFO_4構造体から
//
// ローカルのプリンタと現在接続が確立されているもの
// この場合ネットワークのものも含む
// PRINTER_INFO_4の時に指定可能なのはこの2つのみ
//
// 中村氏がDelphi MLで見えないプリンタがあると言うので見えないプリンタを表示し
// ないようにしている。この見えないプリンタは、確認したことがあり、なるほどと
// その時は思ったのであるが、状況については失念
// 使用可能なプリンタがリストできればいいと考えていたので...
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
Flags : Cardinal;
dwNeeded : Cardinal;
dwReturn : Cardinal;
pPinfo4 : PPrinterInfo4;
pWork : PPrinterInfo4;
i : Integer;
S : String;
begin
Memo1.Lines.Clear;
pPInfo4 := nil;
dwNeeded := 0;
dwReturn := 0;
//列挙対象プリンタの種類
Flags := PRINTER_ENUM_LOCAL or PRINTER_ENUM_CONNECTIONS;
//dwNeededを0にして必要なバッファサイズを取得
EnumPrinters(Flags,
nil,
4,
pPInfo4,
dwNeeded,
dwNeeded,
dwReturn);
if dwNeeded=0 then exit;
//構造体の配列に必要なバイト数を確保
GetMem(pPinfo4, dwNeeded);
try
if EnumPrinters(Flags,
nil,
4,
pPinfo4,
dwNeeded,
dwNeeded,
dwReturn) then begin
pWork := pPinfo4;
for i := 0 to dwReturn - 1 do begin
if (pWork.Attributes and PRINTER_ATTRIBUTE_HIDDEN) = 0 then begin
S := string(pWork.pPrinterName);
Memo1.Lines.Add(S);
end;
//次の構造体の配列に移動
Inc(pWork);
end;
end else begin
MessageBox(Handle, PChar(SysErrorMessage(GetLastError)), '', 0);
end;
finally
FreeMem(pPinfo4);
end;
end;
end.
| プリンタ属性、タイムアウトの設定などのプリンタ情報を格納する構造体です。 |
表12
PRINTER_INFO_5 構造体のメンバー |
| pPrinterName |
LPTSTR |
プリンタ名 |
| pPortName |
LPTSTR |
ポート名
複数ある場合はカンマ区切り |
| Attributes |
DWORD |
プリンタの属性の組合せ。PINTER_INFO_2 構造体の Attibutes でも同じ値が取得できる
値については MSDN ライブラリの記事を参照 |
| DeviceNotSelectedTimeou |
DWORD |
Windows NT 系では未使用 |
| TransmissionRetryTimeout |
DWORD |
Windows NT 系では未使用 |
| 上のサンプルと同じく、EnumPrinters 関数の引数に、PRINTER_INFO_5 を指定して、プリンタ名を列挙するサンプルです。 |
 |
図15
設計時画面 |
 |
図16
実行画面 |
リスト7
PRINTER_INFO_5 構造体を使用してプリンタ名を列挙 |
unit Printer_Info5_EnumUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Printers, WinSpool, ExtCtrls;
type
TForm1 = class(TForm)
Panel1: TPanel;
Button1: TButton;
Panel2: TPanel;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//=============================================================================
// プリンタの情報取得 PRINTER_INFO_5構造体から
//
// PRINTER_INFO_4はWindows 9X系では使用できないのでこちらを使用することになる
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
Flags : Cardinal;
dwNeeded : Cardinal;
dwReturn : Cardinal;
pPinfo5 : PPrinterInfo5;
pWork : PPrinterInfo5;
i : Integer;
S : String;
begin
Memo1.Lines.Clear;
pPInfo5 := nil;
dwNeeded := 0;
dwReturn := 0;
//列挙対象プリンタの種類
Flags := PRINTER_ENUM_LOCAL or PRINTER_ENUM_CONNECTIONS;
//dwNeededを0にして必要なバッファサイズを取得
EnumPrinters(Flags,
nil,
5,
pPInfo5,
dwNeeded,
dwNeeded,
dwReturn);
if dwNeeded = 0 then exit;
//構造体の配列に必要なバイト数を確保
GetMem(pPinfo5, dwNeeded);
try
if EnumPrinters(Flags,
nil,
5,
pPinfo5,
dwNeeded,
dwNeeded,
dwReturn) then begin
pWork := pPinfo5;
for i := 0 to dwReturn - 1 do begin
S := string(pWork.pPrinterName);
Memo1.Lines.Add(S);
//次の構造体の配列に移動
Inc(pWork);
end;
end else begin
MessageBox(Handle, PChar(SysErrorMessage(GetLastError)), '', 0);
end;
finally
FreeMem(pPinfo5);
end;
end;
end.
プリンタの状態を格納する構造体です。
このプリンタの状態は、PRINTER_INFO_2 構造体の Status パラメータの値からも取得できます。 |
表13
PRINTER_INFO_6 構造体のメンバー |
| dwStatus |
DWORD |
値については MSDN ライブラリの記事を参照 |
表14
プリンタの状態を表す dwStatus の値 |
| PRINTER_STATUS_BUSY |
プリンタはヒジー |
| PRINTER_STATUS_DOOR_OPEN |
プリンタのカバーが開いている |
| PRINTER_STATUS_ERROR |
未使用 |
| PRINTER_STATUS_INITIALIZING |
プリンタの初期化中 |
| PRINTER_STATUS_IO_ACTIVE |
このプリンタはアクティブな入力出力状態 |
| PRINTER_STATUS_MANUAL_FEED |
手動フィードの状態 |
| PRINTER_STATUS_NO_TONER |
トナーがない |
| PRINTER_STATUS_NOT_AVAILABLE |
印刷ができない状態 |
| PRINTER_STATUS_OFFLINE |
オフライン |
| PRINTER_STATUS_OUT_OF_MEMORY |
プリンタのメモリ不足 |
| PRINTER_STATUS_OUTPUT_BIN_FULL |
ビンが用紙がある |
| PRINTER_STATUS_PAGE_PUNT |
現在のページを印刷できない |
| PRINTER_STATUS_PAPER_JAM |
紙詰まり |
| PRINTER_STATUS_PAPER_OUT |
用紙切れ |
| PRINTER_STATUS_PAPER_PROBLEM |
用紙に問題がある |
| PRINTER_STATUS_PAUSED |
一時停止中 |
| PRINTER_STATUS_PENDING_DELETION |
削除の保留中 |
| PRINTER_STATUS_POWER_SAVE |
省電力モード |
| PRINTER_STATUS_PRINTING |
印刷中 |
| PRINTER_STATUS_PROCESSING |
SetPrinter 関数からのコマンドを処理中 |
| PRINTER_STATUS_SERVER_UNKNOWN |
状態不明 |
| PRINTER_STATUS_TONER_LOW |
トナーが不足 |
| PRINTER_STATUS_USER_INTERVENTION |
ユーザ要求に対するエラー |
| PRINTER_STATUS_WAITING |
印刷待ち状態 |
| PRINTER_STATUS_WARMING_UP |
ウォーミングアップ中 |
PRINTER_INFO_2 構造体のメンバーの Status は、プリンタの状態を表す値の組合せが取得できることになっていますが、本ページのサンプルコードではプリンタの状態の取得はできません。
プリンタ装置とのインターフェイスにポートモニタというがあります。ポートモニタは、プリンタ装置とのデータ転送を担当します。印刷ジョブがポートモニタを経由して、プリンタ装置に送信された時にエラーが発生すると、ポートモニタは印刷ジョブの状態情報として記録します。それを印刷スプーラがプリントキューに報告することにより、Status メンバーの値をセットします。
つまり、プリントキューに印刷ジョブがない状態の時は、常に印刷ジョブの受け入れが可能という結果となります。
サンプルプログラム集の [722_PDF 文書の印刷] では、印刷ジョブを開始してから現在のジョブ数を取得を取得しています。その PDF のサンプルのように、プリンタの状態の取得は、印刷ジョブを開始してから取得することになります。この時、EnumJobs 関数あるいは、GetJob 関数からの情報も必要となるかも知れません。
詳しくは、以下の Microsoft サポートの記事を参考にしてください。 |
|