打印机状态监控,永远的疑问...... ( 积分: 200 )

  • 主题发起人 主题发起人 zhizixing
  • 开始时间 开始时间
Z

zhizixing

Unregistered / Unconfirmed
GUEST, unregistred user!
先让我感叹一句:Delphi中打印机状态监控,永远的疑问......
为了解决我的问题(分任务打印上万条数据,分段打,于是要在每阶段监控打印机状态,以决定是否再传送任务),网上到处搜索资料,一周了,无数篇文章,各种方法,无论是利用Delphi自带的函数,windows的API,甚至是汇编,都无果而终,查看了大富翁的几年来的资料(离线的和在线的),却发现这个问题几年来几乎每天都有人在问,却绕来绕去的总是那几套方法,要不就是与操作系统有关,要不就是与打印机有关,要不就是......总之没有一种方法能真正做到...... 我不知道是我没搜到真正的“宝“,还是本来就这样!!!
我已经精疲力尽了,没辙了,我真的想好好睡上一觉......
如果哪位大侠真的有这把”尚方宝剑”,跪求给我发一份!!!!!!
我的E-Mail: zhizixing@vip.sina.com QQ: 83930873 (在线隐身)
虽然我的积分不多,也就200,但我愿意全部奉献上!!!
 
先让我感叹一句:Delphi中打印机状态监控,永远的疑问......
为了解决我的问题(分任务打印上万条数据,分段打,于是要在每阶段监控打印机状态,以决定是否再传送任务),网上到处搜索资料,一周了,无数篇文章,各种方法,无论是利用Delphi自带的函数,windows的API,甚至是汇编,都无果而终,查看了大富翁的几年来的资料(离线的和在线的),却发现这个问题几年来几乎每天都有人在问,却绕来绕去的总是那几套方法,要不就是与操作系统有关,要不就是与打印机有关,要不就是......总之没有一种方法能真正做到...... 我不知道是我没搜到真正的“宝“,还是本来就这样!!!
我已经精疲力尽了,没辙了,我真的想好好睡上一觉......
如果哪位大侠真的有这把”尚方宝剑”,跪求给我发一份!!!!!!
我的E-Mail: zhizixing@vip.sina.com QQ: 83930873 (在线隐身)
虽然我的积分不多,也就200,但我愿意全部奉献上!!!
 
我也正在困惑这个问题啊。。有方案也发我一份啊。。bewill@163.com。。我觉得WINDWOS真是可笑,为什么读一下打印机的状态就这么难。什么烂SDK,封装了你也得让我读得到啊。。。。打印机的状态居然宣称只有2个。。。。典型的微软作法。。。
 
这个问题因扰了我好久
 
正打算发个类似帖子就来到这里,很急着要解决的啊.
 
谁能把cmwdelphier的这段调试一下,适合我用呀。

此程序是一个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.

客户端程序可以直接查数据库。我这里不列出客户程序了
 
为了解决我的问题(分任务打印上万条数据,分段打,于是要在每阶段监控打印机状态,以决定是否再传送任务)
楼主这话是什么意思啊?
我在写相关程序,有空可以交流一下~
 
楼主的意思就是每打印指定数量的记录后(如100)停止发送命令,然后监控打印机状态,确定都打印正确后在传入新的数据吧。
我用
procedure TfrmComBuild.OnPrinterStart;
const
InfoLevel = 1;
FirstJob = 0;
LastJob = 19;
var
Device, Driver, Port : array[0..255] of char;
hDeviceMode: THandle;
Jobs: array [FirstJob..LastJob] of TJobInfo1;
PrinterHandle, BytesNeeded,NumJobs:Cardinal;
begin
Printer.GetPrinter(Device, Driver, Port, hDeviceMode);
if OpenPrinter(@Device,Printerhandle,nil) then
begin
repeat
EnumJobs(PrinterHandle,FirstJob,LastJob+1,InfoLevel,@Jobs,SizeOf(Jobs),BytesNeeded,NumJobs);
Application.ProcessMessages;
until NumJobs<=0;
//打印任务为空
end;
end;
这段代码来实现检测不知道行不行啊,有没有什么限制?(我没要求走完纸,只需要确定打印任务中没有就可以了),自己没有打印机测试,用虚拟打印机速度太快了没法检测。总不能带到客户那里试一下再拿回来改吧[:D]
 
那很简单啊。Job都有一个JobID,100就Stop一下吗~
我发过函数,就不再COPY了~
 
TO:do
ll_paul
没找到你说的函数呀,你贴在哪里了?
你的QQ? 我的是: 83930873 有空交流!
E-Mail: zhizixing@vip.sina.com
各位一样......
 
昨天忘记收信了。加你QQ了~
老兄也北京的?呵呵~
 
我也遇到这样的问题有谁能解决,奉上本人全部分数!!
 

Similar threads

后退
顶部