如何在2000下获取打印作业信息(100分)

  • 主题发起人 主题发起人 scx2002112
  • 开始时间 开始时间
S

scx2002112

Unregistered / Unconfirmed
GUEST, unregistred user!
用GetJob和EnumJobs总说未定义,但我已uses过Window单元了
迷茫困惑痛苦中
请高手指教
 
此程序是一个Windows NT/2000的Service程序,它检测Windows NT的打印日志事件,
当有打印任务时,自动将打印信息读取出来保存到数据库中。
本人用的是SQL Server,只有一个表,表结构为:
CREATE TABLE [dbo].[PrintRecord] (
[id] [int] IDENTITY (1, 1) NOT NULL ,
[用户名缩写] [nvarchar] (20) NULL ,
[用户名] [nvarchar] (20) NULL ,
[时间] [smalldatetime] NOT NULL ,
[文档名称] [nvarchar] (100) NULL ,
[打印机] [nvarchar] (100) NULL ,
[端口] [nvarchar] (100) NULL ,
[字节大小] [int] NULL ,
[打印页数] [smallint] NULL
) ON [PRIMARY]
在Service上只有一个ADOConnection和一个ADODataSet连接这个表。
Service的程序:
unit svc;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs,
ExtCtrls, Db, ADODB,syncobjs;
type
TWaitThread=Class;
TService1 = class(TService)
ADOConnection1: TADOConnection;
ADODataSet1: TADODataSet;
ADODataSet1DSDesigner: TWideStringField;
ADODataSet1DSDesigner2: TWideStringField;
ADODataSet1DSDesigner3: TDateTimeField;
ADODataSet1DSDesigner4: TWideStringField;
ADODataSet1DSDesigner5: TWideStringField;
ADODataSet1DSDesigner6: TWideStringField;
ADODataSet1DSDesigner7: TIntegerField;
ADODataSet1DSDesigner8: TSmallintField;
procedure Timer1Timer(Sender: TObject);
procedure ServiceCreate(Sender: TObject);
procedure ServiceDestroy(Sender: TObject);
private
{ Private declarations }
LogHandle:HWND;
Thread:TWaitThread;
public
Counter:Integer;
DataError:Boolean;
function GetServiceController: TServiceController;
override;
procedure PrintEvent(Sender:TObject);
{ Public declarations }
end;

TWaitThread=class(TThread)
private
E:TSimpleEvent;
F:TNotifyEvent;
procedure Execute;
override;
public
constructor Create(AHandle:HWND;
aF:TNotifyEvent);
destructor Destroy;override;
end;

TEventLogRecord=record
Length: DWORD;
Reserved:DWORD;
RecordNumber:DWORD;
TimeGenerated:DWORD;
TimeWritten:DWORD;
EventID:DWORD;
EventType:WORD;
NumStrings:WORD;
EventCategory:WORD;
ReservedFlags:WORD;
ClosingRecordNumber:DWORD;
StringOffset:DWORD;
UserSidLength:DWORD;
UserSidOffset:DWORD;
DataLength:DWORD;
DataOffset:DWORD;
Buf:array [0..1023] of Char;
end;

var
Service1: TService1;
implementation
{$R *.DFM}
procedure ServiceController(CtrlCode: DWord);
stdcall;
begin
Service1.Controller(CtrlCode);
end;

function TService1.GetServiceController: TServiceController;
begin
Result := ServiceController;
end;

procedure TService1.ServiceCreate(Sender: TObject);
begin
Counter:=0;
DataError:=False;
try
if not ADOConnection1.Connected then
ADOConnection1.Connected:=True;
if not ADODataSet1.Active then
ADODataSet1.Active:=True;
LogHandle:=OpenEventLog(nil, PChar('HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/Eventlog/Application/hpmon'));
if LogHandle=NULL then
begin
DataError:=True;
Exit;
end;
Thread:=TWaitThread.Create(LogHandle, PrintEvent);
except
DataError:=True;
end;
end;

procedure TService1.ServiceDestroy(Sender: TObject);
begin
CloseEventLog(LogHandle);
ADODataSet1.Active:=False;
ADOConnection1.Connected:=False;
Thread.Free;
end;

const EVENTLOG_SEQUENTIAL_READ =$0001;
const ENTLOG_SEEK_READ =$0002;
const EVENTLOG_FORWARDS_READ =$0004;
const EVENTLOG_BACKWARDS_READ =$0008 ;
function GetString(var S:String;
P:Pointer):Pointer;
begin
S:=PChar(P);
Result:=Pointer(LongInt(P)+Length(S)+1);
end;

function GetTime(N:DWord):TDateTime;
var
BaseTime:TDateTime;
AddTime:TDateTime;
BS,DS,a:TtIMEStamp;
begin
BaseTime:=EncodeDate(1970,1,1)+EncodeTime(0,0,0,0);
BS:=DateTimeToTimeStamp(BaseTime);
Ds.Time:=(N mod (60*60*24))*1000;
Ds.Date:=N div (60*60*24);
a.Time:=(BS.Time+DS.Time) mod (60*60*24*1000);
a.Date:=(BS.Time+DS.Time) div (60*60*24*1000)+BS.Date+DS.Date;
Result:=TimeStampToDateTime(a);
end;

procedure TService1.PrintEvent(Sender:TObject);
var
ByteRead, LogSize:DWORD;
Buf:array [0..4095] of char;
B,P:^TEventLogRecord;
sAppName:String;
sDoc:String;
sUser:String;
sPrinter:String;
sPort:String;
sSize:String;
sPages:String;
begin
FillChar(Buf, Sizeof(TEventLogRecord), 0);
while (ReadEventLog(LogHandle, EVENTLOG_FORWARDS_READ or EVENTLOG_SEQUENTIAL_READ , 0, @Buf, Sizeof(Buf), ByteRead, LogSize) )do
begin
B:=@Buf;
repeat
if PChar(Pointer(Longint(B)+sizeof(TEventLogRecord)))='Print' then
begin
P:=Pointer(Longint(B)+B^.StringOffset);
if B^.NumStrings=7 then
begin
p := GetString( sAppName, p);
p := GetString( sDoc, p);
p := GetString( sUser, p);
p := GetString( sPrinter, p);
p := GetString( sPort, p);
p := GetString( sSize, p);
p := GetString( sPages, p);
//Memo1.Lines.Add(sAppName+' '+' '+sDoc+' '+sUser+' '+sPrinter+' '+sPort+' '+sSize+' '+sPages);
with ADODataSet1do
begin
Insert;
FieldByName('用户名缩写').asString:=sUser;
FieldByName('时间').asDateTime:=GetTime(B^.TimeGenerated);
FieldByName('文档名称').asString:=sDoc;
FieldByName('打印机').asString:=sPrinter;
FieldByName('端口').asString:=sPort;
FieldByName('字节大小').asInteger:=StrToInt(sSize);
FieldByName('打印页数').asInteger:=StrToInt(sPages);
Post;
end;
end;
end;
B:=Pointer(Longint(B)+B^.Length);
until Longint(B)>=Longint(@Buf)+ByteRead;
end;
end;

constructor TWaitThread.Create(AHandle:HWND;
aF:TNotifyEvent);
begin
Inherited Create(True);
E:=TSimpleEvent.Create;
F:=aF;
if NotifyChangeEventLog(AHandle, E.Handle) then
if Assigned(F) then
Resume;
end;

destructor TWaitThread.Destroy;
begin
E.SetEvent;
Terminate;
WaitFor;
E.Free;
inherited Destroy;
end;
procedure TWaitThread.Execute;
begin
While not Terminateddo
begin
if E.WaitFor(INFINITE)=wrSignaled then
begin
if Terminated then
Exit;
F(Self);
end;
end;
end;

end.

客户端程序可以直接查数据库。我这里不列出客户程序了
 
uses Winspool, Printers;
 
to cwm:能不能只给我获取打印作业信息的那部分
to andy:stauts为什么总为16,我明明没有放纸进去
等一段时间后又报80或84错
to all:再等几天,还没结果就放分了
 
枚举打印任务:
uses Printers, WinSpool;
// 打印任务状态描述
function PrinterStatusText(Status: Integer): String;
begin
case Status of
0: Result := 'Waiting';
JOB_STATUS_PAUSED: Result := 'Paused';
JOB_STATUS_ERROR: Result := 'Error';
JOB_STATUS_DELETING: Result := 'Deleting';
JOB_STATUS_SPOOLING: Result := 'Spooling';
JOB_STATUS_PRINTING: Result := 'Printing';
JOB_STATUS_OFFLINE: Result := 'Offline';
JOB_STATUS_PAPEROUT: Result := 'Paper Out';
JOB_STATUS_PRINTED: Result := 'Printed';
JOB_STATUS_DELETED: Result := 'Deleted';
JOB_STATUS_BLOCKED_DEVQ: Result := 'Blocked';
JOB_STATUS_USER_INTERVENTION: Result := 'User Intervention';
JOB_STATUS_RESTART: Result := 'Restart';
else
Result := 'Status ' + IntToStr(Status);
end;
end;
// 取指定打印机当前打印任务列表
procedure GetJobs(PrinterName: String;
JobList: TStrings);
type
PJOBArray = ^JOBArray;
JOBArray = array [0..0] of TJobInfo1;
var
pJobs: PJOBArray;
pJobInfo: Pointer;
hPrinter: THandle;
dwNeeded, dwReturned, i: DWORD;
begin
JobList.Clear;
// You need a printer handle, open the printer
if not OpenPrinter(PChar(PrinterName),hPrinter,nil) then
exit;
// First you call EnumJobs() to find out how much memory you need
if not EnumJobs(hPrinter,0, $FFFFFFFF, 1, nil, 0, dwNeeded, dwReturned) then
if GetLastError <> ERROR_INSUFFICIENT_BUFFER then
begin
ClosePrinter( hPrinter );
exit;
end;

// 0 jobs in printer
if dwNeeded = 0 then
begin
ClosePrinter( hPrinter );
exit;
end;

// Allocate enough memory for the JOB_INFO_1 structures plus
// the extra data - dwNeeded from the previous call tells you
// the total size needed
try
GetMem(pJobInfo, dwNeeded );
try
if EnumJobs(hPrinter, 0, $FFFFFFFF, 1, pJobInfo, dwNeeded, dwNeeded, dwReturned) then
begin
pJobs := PJOBArray(pJobInfo);
for i := 0 to dwReturned-1do
with pJobsdo
JobList.AddObject(Format('%s(%s)',[StrPas(pDocument),PrinterStatusText(Status)]),
TObject(JobId));
end;
finally
FreeMem(pJobInfo);
end;
except
end;

ClosePrinter(hPrinter);
end;

//-----------------------------------------------------------------------------
//使用示例,取'HP LaserJet 6L'上的打印任务,加到ListBox1中。
procedure TForm1.Button1Click(Sender: TObject);
begin
GetJobs('HP LaserJet 6L',ListBox1.Lines);
end
 
uses Winspool, Printers;
//枚举打印任务:
function TPrintMai_frm.getjob(): integer;
var
Needed, Returned: DWORD;
i, Count: integer;
tbt: byte;
pNeeded: PDword;
P2: PJobInfo1;
PPI: pPRINTERINFO2;
Printer: TPrinter;
Device, Driver, Port: array[0..255] of Char;
PPr, DevMode: Cardinal;
hPrinter: THandle;
begin
result := 0;
Printer := TPrinter.Create;
//创建Printer对象
try
Printer.GetPrinter(Device, Driver, Port, DevMode);
//取得打印机的名称,驱动程序,端口号
if not OpenPrinter(@device, hPrinter, nil) then
//取得打印机的句柄
begin
ShowMessage('OpenPrinter' + SysErrorMessage(GetLastError));
//Exit;
end;
PNeeded := AllocMem(8024);
//分配内存空间
P2 := AllocMem(8048);
PPI := AllocMem(8048);
//接受打印机信息结构
if not GetPrinter(hPrinter, 2, PPI, 8048, PNeeded) then
//取得打印机队列中的任务数
begin
ShowMessage('GetPrinter' + SysErrorMessage(GetLastError));
end;
//取得打印机状态
if Enumjobs(hPrinter, 0, 1, 2, p2, 8048, Needed, Returned) then
begin
if P2.JobId = 0 then
result := 0;
if P2.JobId > 0 then
begin
result := PPI.cJobs;
end
end
else
ShowMessage('Enumjobs' + SysErrorMessage(GetLastError));
//关闭打印机,释放内存空间
finally
FreeMem(PNeeded);
FreeMem(p2);
FreeMem(PPI);
Printer.Free;
ClosePrinter(hPrinter);
end;
end;
 
多人接受答案了。
 
后退
顶部