我要为客户开发一个打印监控程序,基本功能如下:
我要对局域网中有若干台打印机实施监控。
1.针对打印机必须能够检索出有哪些用户使用了该台打印机,打印的时间,打印的文件名,
纸张的大小。
2.针对用户必须能检索出该用户都使用过哪些打印机,打印的时间,打印的文件名,
纸张的大小。
请问如何实现??
我要对局域网中有若干台打印机实施监控。
1.针对打印机必须能够检索出有哪些用户使用了该台打印机,打印的时间,打印的文件名,
纸张的大小。
2.针对用户必须能检索出该用户都使用过哪些打印机,打印的时间,打印的文件名,
纸张的大小。
请问如何实现??
1)使用clietnsocket和serversocket这两个控件做一个客户机/服务器通信程序在服务端里用api函数实时侦测本机的打印状态(时间,文件名,纸张的大小等),在所监控的机器上都安装这个服务端程序。
2)使用客户端软件来连接这些机器,返回这些机器的所有侦测的信息。
以上方法即可实现你的功能。
当有打印任务时,自动将打印信息读取出来保存到数据库中。
本人用的是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;interfaceuses
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 ADODataSet1 do
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 Terminated do
begin
if E.WaitFor(INFINITE)=wrSignaled then
begin
if Terminated then Exit;
F(Self);
end;
end;
end;end.
客户端程序可以直接查数据库。我这里不列出客户程序了。
这段代码我在大富翁上也见过,但是好像不能运行,你自己试过吗?
您有能运行的例程吗?