「Windowsが印刷ログを記録するよう設定するには。プリンターのイベントログを読むには。」
Windowsがプリンターへの印刷ログを記録するよう設定するには。
Delphiでプリンターの印刷ログを読むプログラムを作成するには。
回答
以下レジストリを作成すると、Windows OSが印刷ログを記録するようになります。(レジストリ作成には管理者権限が必要です)
\\HKEY_LOCAL_MACHINE\\SYSTEM\CurrentControlSet\Services\EventLog\Microsoft-Windows-PrintService/Operational
上記レジストリを作成して初めて、Windowsが印刷ログを記録するようになるので、上記レジストリを作成する前のログは存在しません。
上記レジストリを作成すると、「イベント ビューアー」からも印刷ログを見ることが出来るようになります。([アプリケーションとサービスログ]⇒[Microsoft]⇒[Microsoft-Windows-PrintService/Operational])
以下ソースを実行してButton1をクリックすると、上記レジストリが無ければ上記レジストリを作成し、印刷ログを読みます。
Windows7以降でUACが有効の場合、実行ファイルを右クリックして管理者として実行をクリックし、昇格しないとレジストリも作成されませんし、
印刷ログも表示されません。
ソース
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, WinApi.IpHlpApi, Vcl.StdCtrls, Vcl.Grids,
Vcl.ExtCtrls, registry;
type
TForm1 = class(TForm)
StringGrid1: TStringGrid;
Panel1: TPanel;
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure get_event_log(SourceName:String;stl:TStringList);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
PEVENTLOGRECORD = ^EVENTLOGRECORD;
EVENTLOGRECORD = packed record
Length : DWORD;
Reserved : DWORD;
RecordNumber : DWORD;
TimeGenerated : DWORD;
TimeWritten : DWORD;
EventID : DWORD;
EventType : WORD;
NumStrings : WORD;
EventCategory : WORD;
ReservedFlags : WORD; //Reserved
ClosingRecordNumber : DWORD;//Reserved
StringOffset : DWORD;
UserSidLength : DWORD;
UserSidOffset : DWORD;
DataLength : DWORD;
DataOffset : DWORD;
end;
TEventLogRecord =EVENTLOGRECORD;
var
Form1: TForm1;
const
EVENTLOG_SEQUENTIAL_READ = 1;
EVENTLOG_SEEK_READ = 2;
EVENTLOG_FORWARDS_READ = 4;
EVENTLOG_BACKWARDS_READ = 8;
function TimeGeneratedToDateTime(aTimeGenerated: DWORD): TDateTime;
implementation
{$R *.dfm}
function TimeGeneratedToDateTime(aTimeGenerated: DWORD): TDateTime;
const
SecondPerDay = 60 * 60 * 24; //一日の秒数
begin
Result := EncodeDate(1970,1,1) + EncodeTime(9,0,0,0);
Result := ((Result * SecondPerDay) + aTimeGenerated) / SecondPerDay;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
stl:TStringList;
stl2:TStringList;
i,c:integer;
r:Integer;
reg:TRegistry;
ret:boolean;
begin
reg:=TRegistry.Create;
reg.RootKey:=HKEY_LOCAL_MACHINE;
//レジストリを作成する。このレジストリを作成すると、印刷ログを保存するようになる
ret:=reg.CreateKey('\SYSTEM\CurrentControlSet\Services\EventLog\Microsoft-Windows-PrintService/Operational');
reg.Free;
Screen.Cursor:=crHourGlass;
StringGrid1.Visible:=False;;
stl:=TStringList.Create;
stl2:=TStringList.Create;
stl.Clear;
stl2.Clear;
stl2.QuoteChar:='"';
stl2.StrictDelimiter:=true;
stl2.Delimiter:=',';
StringGrid1.ColCount:=30;
StringGrid1.Rows[0].CommaText:='日時,イベントID,ソース名,コンピューター名,イベントタイプ,ユーザー名,ドメイン'
+',セキュリティID,アカウント名,アカウントドメイン,ログオンID,オブジェクトサーバー,オブジェクト種類,オブジェクト名'
+',ハンドルID,トランザクションID,アクセス,アクセスマスク,特権,制限されたSID数,プロセスID,プロセス名';
r:=1;
stl.Clear;
get_event_log('Microsoft-Windows-PrintService/Operational',stl);
for i := 0 to stl.Count-1 do
begin
StringGrid1.RowCount:=r+1;
stl2.CommaText:=stl[i];
for c := 0 to stl2.count-1 do
begin
StringGrid1.Cells[c,r]:=stl2[c];
end;
inc(r);
end;
if r>1 then
begin
StringGrid1.FixedRows:=1;
StringGrid1.ColWidths[0]:=100;
StringGrid1.ColWidths[1]:=64;
StringGrid1.ColWidths[2]:=128;
StringGrid1.ColWidths[3]:=64;
StringGrid1.ColWidths[4]:=200;
StringGrid1.ColWidths[5]:=100;
StringGrid1.ColWidths[6]:=100;
StringGrid1.ColWidths[7]:=256;
end;
stl2.Free;
stl.Free;
StringGrid1.Visible:=True;
Screen.Cursor:=crDefault;
end;
procedure TForm1.get_event_log(SourceName: String;stl:TStringList);
const
//最新のログから順次読み込む
READ_FLAG= EVENTLOG_SEQUENTIAL_READ or EVENTLOG_BACKWARDS_READ;
var
eLogHandle: THandle;
logCount: DWORD;
i,j: Integer;
eventID: Integer;
pBuf: PEventLogRecord;
bufSize: Integer;
readNum, readNeed: DWORD;
off:Cardinal;
dwAccountSize, dwDomainSize: DWORD;
szAccount, szDomain: array[0..MAX_PATH] of Char;
ust:String;
dst:String;
us:PSID;
peUse: Cardinal;
st,strn:string;
p:PChar;
gSourceName:string;
gComputername:string;
gTimeGenerated:TDateTime;
gEventType:Word;
gEventTypeSt:string;
gString:string;
b:TBytes;
stl2:TStringList;
begin
stl2:=TStringList.Create;
//システムログのオープン
eLogHandle := OpenEventLog(nil,PWideChar(SourceName));
//ログが開けた場合
if eLogHandle > 0 then
begin
//ログ数を取得
if not GetNumberOfEventLogRecords(eLogHandle, logCount) then
logCount := 0;
//メモリ確保
bufSize := SizeOf(TEventLogRecord);
pBuf := AllocMem(bufSize);
for i := 1 to logCount do
begin
{読み込み}
if not ReadEventLog(eLogHandle, READ_FLAG,
logCount - 1, pBuf, 1, readNum, readNeed) then
begin
if GetLastError = ERROR_INSUFFICIENT_BUFFER then
begin
//メモリの再割り当て
bufSize := readNeed;
ReallocMem(pBuf, bufSize);
if not ReadEventLog(eLogHandle, READ_FLAG,
logCount - 1, pBuf, readNeed, readNum, readNeed) then
begin
Break;//失敗
end;
end
else
begin
//失敗
Break;
end;
end;
//イベントIDを読む
eventID := pBuf^.EventID AND $FFFF;
//イベントタイプ
gEventType:=pBuf^.EventType;
case gEventType of
$1:gEventTypeSt:='EVENTLOG_ERROR_TYPE';
$2:gEventTypeSt:='EVENTLOG_WARNING_TYPE';
$4:gEventTypeSt:='EVENTLOG_INFORMATION_TYPE';
$8:gEventTypeSt:='EVENTLOG_AUDIT_SUCCESS';
$10:gEventTypeSt:='EVENTLOG_AUDIT_FAILURE';
else gEventTypeSt:='EVENTLOG_UnKnown';
end;
//ドメイン、ユーザー名を取得
ust:='';
dst:='';
off:=pBuf^.UserSidOffset;
us:=@(PAnsiChar(pBuf)[off]);
if (pBuf^.UserSidLength>0) then
begin
dwAccountSize:= MAX_PATH;
dwDomainSize:= MAX_PATH;
if (not LookupAccountSid(nil, us, szAccount, dwAccountSize,
szDomain, dwDomainSize, peUse)) then
begin end
else
begin
ust:=(szAccount);
dst:=(szDomain);
end;
end;
//発生日時を取得
gTimeGenerated := TimeGeneratedToDateTime(pBuf^.TimeGenerated);
//ソース名を読み取る
p:=PChar(DWORD(pBuf)+Sizeof(TEventLogRecord));
gSourceName:=StrPas(p);
//コンピューター名を読み取る
p:=PChar(DWORD(pBuf)+Sizeof(TEventLogRecord)+length(gSourceName)*2+2);
gComputername:=StrPas(p);
stl2.Clear;
//文字列を読み取る
gString:='';
st:='';
off:=pBuf^.StringOffset;
if pBuf^.NumStrings>0 then
begin
if pBuf^.NumStrings>1 then
begin
if pBuf^.EventID=302 then
st:=st;
end;
for j := 0 to pBuf^.NumStrings-1 do
begin
p:=PChar(DWORD(pBuf)+off);
st:=StrPas(p);
strn:=st;
strn:=StringReplace(strn,',',' ',[rfReplaceAll]);
strn:=StringReplace(strn,#10,' ',[rfReplaceAll]);
stl2.Add(strn);
gString:=gString+strn;
inc(off,length(st)*2+2);
end;
end;
//バイナリデータを読み取る
setlength(b,pBuf^.DataLength);
for j := 0 to pBuf^.DataLength-1 do
begin
b[j]:=PByte(DWORD(pBuf)+pBuf^.DataOffset+j)^;
end;
if (pBuf^.EventID=307) or (pBuf^.EventID=310) then //307は印刷完了を示す。310は削除されたことを示す
begin
stl.Add(
FormatDateTime('yyyy/mm/dd hh:nn:ss', gTimeGenerated)+','+
inttostr(eventID)+','+gSourceName+','+gComputername+','+
inttostr(gEventType)+'<'+gEventTypeSt+'>'+','+
ust+','+dst+','+stl2.CommaText
);
end;
end;
//メモリ開放
FreeMem(pBuf);
//ログを閉じる
CloseEventLog(eLogHandle);
end;
stl2.Free;
end;
end.