求:旧题新解(打印机的状态问题)100分!!(100分)

  • 主题发起人 主题发起人 foundworld
  • 开始时间 开始时间
F

foundworld

Unregistered / Unconfirmed
GUEST, unregistred user!
在WIN2000中如何获得打印机的状态信息(未连接、未安装、缺纸等)?
已经看过论坛里现有的相关帖子,感觉都不好使,请大家赐教!
 
WIN9X下可以,WIN2000不能。
 
监视打印机的打印状态的,9x, 2000都可以处理,大家看看吧。
unit PMThreads;
interface
uses SysUtils, Windows, Classes, WinSpool, PMConsts;
const
PrinterInfoLevel = 2;
JobInfoLevel = 2;
RefreshInterval: Integer = 10;
type
PJobInfo = ^TJobInfo;
TJobInfo = JOB_INFO_2;
PPrinterInfo = ^TPrinterInfo;
TPrinterInfo = PRINTER_INFO_2;
TJob = class(TObject)
private
FInfo: TJobInfo;
FUpdated: Boolean;
procedure SetUpdated(const Value: Boolean);
public
constructor Create(AInfo: TJobInfo);
function CalcPrinted(AInfo: TJobInfo): Integer;
public
property Updated: Boolean read FUpdated write SetUpdated;
property Info: TJobInfo read FInfo;
end;

TPrinterJobsClass = class of TPrinterJobs;
TPrinterJobs = class(TObject)
private
FHandle: THandle;
public
constructor Create(AHandle: THandle);
virtual;
destructor Destroy;
override;
public
property Handle: THandle read FHandle;
end;

TJobs = class(TPrinterJobs)
private
FJobs: TList;
public
constructor Create(AHandle: THandle);
override;
destructor Destroy;
override;
function AddOrUpdate(AInfo: TJobInfo): Integer;
procedure begin
Updates;
function EndUpdates: Integer;
procedure ClearJob(AName: PChar);
end;

TNotify = class(TPrinterJobs)
private
FPrinter: THandle;
FNotify: THandle;
FOptions: TPrinterNotifyOptions;
FOptionsType: TPrinterNotifyOptionsType;
public
constructor Create(APrinter: THandle);
override;
destructor Destroy;
override;
public
property hPrinter: THandle read FPrinter;
property hNotify: THandle read FNotify;
property Options: TPrinterNotifyOptions read FOptions;
end;

TPrinterThreadClass = class of TPrinterThread;
TPrinterThread = class(TThread)
private
FWindow: HWnd;
FPages: Integer;
FPrinted: Integer;
FPrinters: TStringList;
FJobsClass: TPrinterJobsClass;
function GetAvailable: Integer;
protected
procedure UpdatePrinters;
virtual;
procedure RemovePrinter(AIndex: Integer);
procedure AddPrinter(AName: String);
procedure GetPrinters(AList: TStrings);
procedure SendError;
public
constructor Create(AWindow: HWnd);
virtual;
destructor Destroy;
override;
public
property Printers: TStringList read FPrinters;
property Pages: Integer read FPages write FPages;
property Printed: Integer read FPrinted write FPrinted;
property Available: Integer read GetAvailable;
end;

TPrinter9xThread = class(TPrinterThread)
private
procedure UpdateJobs;
public
constructor Create(AWindow: HWnd);
override;
procedure Execute;
override;
end;

TPrinterNTThread = class(TPrinterThread)
private
FNotifies: array of THandle;
protected
procedure UpdatePrinters;
override;
public
constructor Create(AWindow: HWnd);
override;
destructor Destroy;
override;
procedure Execute;
override;
end;

var
PrinterThreadClass: TPrinterThreadClass;
implementation
const
AFields: array [0..1] of Word = (JOB_NOTIFY_FIELD_TOTAL_PAGES, JOB_NOTIFY_FIELD_PAGES_PRINTED);
{ TJob }
constructor TJob.Create(AInfo: TJobInfo);
begin
inherited Create;
FInfo := AInfo;
FUpdated := True;
end;

function TJob.CalcPrinted(AInfo: TJobInfo): Integer;
begin
Result := AInfo.PagesPrinted - FInfo.PagesPrinted;
FInfo := AInfo;
FUpdated := True;
end;

procedure TJob.SetUpdated(const Value: Boolean);
begin
FUpdated := Value;
end;

{ TPrinterJobs }
constructor TPrinterJobs.Create(AHandle: THandle);
begin
inherited Create;
FHandle := AHandle;
end;

destructor TPrinterJobs.Destroy;
begin
ClosePrinter(FHandle);
inherited;
end;

{ TJobs }
constructor TJobs.Create(AHandle: THandle);
begin
inherited;
FJobs := TList.Create;
end;

destructor TJobs.Destroy;
var
I: Integer;
begin
for I := 0 to FJobs.Count-1do
TObject(FJobs).Free;
FJobs.Free;
inherited;
end;

procedure TJobs.begin
Updates;
var
I: Integer;
begin
for I := 0 to FJobs.Count-1do
TJob(FJobs).Updated := False;
end;

function TJobs.EndUpdates: Integer;
var
I: Integer;
AJob: TJob;
begin
Result := 0;
for I := FJobs.Count-1do
wnto 0do
begin
AJob := FJobs;
if not AJob.Updated then
begin
if AJob.Info.Status = JOB_STATUS_PRINTING then
Inc(Result, AJob.Info.TotalPages);
FJobs.Delete(I);
AJob.Free;
end;
end;
end;

function TJobs.AddOrUpdate(AInfo: TJobInfo): Integer;
var
I: Integer;
AJob: TJob;
begin
Result := 0;
for I := FJobs.Count-1do
wnto 0do
begin
AJob := FJobs;
if AJob.Info.JobId = AInfo.JobId then
begin
Inc(Result, AJob.CalcPrinted(AInfo));
Exit;
end;
end;
FJobs.Add(TJob.Create(AInfo));
end;

procedure TJobs.ClearJob(AName: PChar);
var
I: Integer;
AJob: TJob;
begin
for I := FJobs.Count-1do
wnto 0do
begin
AJob := FJobs;
if StrIComp(AJob.Info.pMachineName, AName) = 0 then
begin
SetJob(Handle, AJob.Info.JobId, 0, nil, JOB_CONTROL_CANCEL);
FJobs.Delete(I);
end;
end;
end;

{ TNotify }
constructor TNotify.Create(APrinter: THandle);
begin
inherited;
//OptionsType
FillChar(FOptionsType, SizeOf(FOptionsType), 0);
with FOptionsTypedo
begin
wType := JOB_NOTIFY_TYPE;
Count := 2;
pFields := @AFields;
end;

//Options
FillChar(FOptions, SizeOf(FOptions), 0);
with FOptionsdo
begin
Version := 2;
Flags := PRINTER_NOTIFY_OPTIONS_REFRESH;
Count := 1;
pTypes := @FOptionsType;
end;

FNotify := FindFirstPrinterChangeNotification(APrinter, 0, 0, @FOptions);
end;

destructor TNotify.Destroy;
begin
FindClosePrinterChangeNotification(FNotify);
FNotify := INVALID_HANDLE_VALUE;
inherited;
end;

{ TPrinterThread }
constructor TPrinterThread.Create(AWindow: HWnd);
begin
inherited Create(True);
FreeOnTerminate := True;
FPrinters := TStringList.Create;
FWindow := AWindow;
FPages := 1;
FPrinted := 0;
end;

destructor TPrinterThread.Destroy;
var
I: Integer;
begin
for I := 0 to FPrinters.Count-1do
FPrinters.Objects.Free;
inherited;
end;

procedure TPrinterThread.AddPrinter(AName: String);
var
P: TPrinterJobs;
AHandle: THandle;
begin
if OpenPrinter(PChar(AName), AHandle, nil) then
begin
P := FJobsClass.Create(AHandle);
FPrinters.AddObject(AName, P);
end;
end;

procedure TPrinterThread.RemovePrinter(AIndex: Integer);
begin
FPrinters.Objects[AIndex].Free;
FPrinters.Delete(AIndex);
end;

function TPrinterThread.GetAvailable: Integer;
begin
Result := FPages - FPrinted;
end;

procedure TPrinterThread.GetPrinters(AList: TStrings);
var
Buffer, PrinterInfo: PChar;
Flags, Count, NumInfo: DWORD;
I: Integer;
Level: Byte;
begin
if Win32Platform = VER_PLATFORM_WIN32_NT then
begin
Flags := PRINTER_ENUM_CONNECTIONS or PRINTER_ENUM_LOCAL;
Level := 4;
end else
begin
Flags := PRINTER_ENUM_LOCAL;
Level := 5;
end;
Count := 0;
EnumPrinters(Flags, nil, Level, nil, 0, Count, NumInfo);
if Count = 0 then
Exit;
GetMem(Buffer, Count);
try
if EnumPrinters(Flags, nil, Level, PByte(Buffer), Count, Count, NumInfo) then
begin
PrinterInfo := Buffer;
for I := 0 to NumInfo - 1do
begin
if Level = 4 then
with PPrinterInfo4(PrinterInfo)^do
begin
AList.Add(pPrinterName);
Inc(PrinterInfo, sizeof(TPrinterInfo4));
end
else
with PPrinterInfo5(PrinterInfo)^do
begin
AList.Add(pPrinterName);
Inc(PrinterInfo, sizeof(TPrinterInfo5));
end;
end;
end else
SendError;
finally
FreeMem(Buffer, Count);
end;
end;

procedure TPrinterThread.UpdatePrinters;
var
AList: TStrings;
I: Integer;
begin
AList := TStringList.Create;
try
GetPrinters(AList);
for I := FPrinters.Count-1do
wnto 0do
begin
if AList.IndexOf(FPrinters) = -1 then
RemovePrinter(I);
end;
for I := 0 to AList.Count-1do
begin
if FPrinters.IndexOf(AList) = -1 then
AddPrinter(AList);
end;
finally
AList.Free;
end;
end;

procedure TPrinterThread.SendError;
begin
PostMessage(FWindow, WM_THREADERROR, GetLastError, 0);
end;

{ TPrinter9xThread }
constructor TPrinter9xThread.Create(AWindow: HWnd);
begin
FJobsClass := TJobs;
inherited;
end;

procedure TPrinter9xThread.Execute;
begin
while not Terminateddo
begin
UpdatePrinters;
UpdateJobs;
Sleep(RefreshInterval);
end;
end;

procedure WriteJobToFile(Buf: Pointer;
BufSize: Integer);
const
FileIndex: Integer = 1;
OldBuf: Pointer = nil;
OldBufSize: Integer = 0;
var
AStream: TFileStream;
begin
if (BufSize <> OldBufSize) or not CompareMem(OldBuf, Buf, SizeOf(TJobInfo)) then
begin
AStream := TFileStream.Create(Format('c:/job%d.dat', [FileIndex]), fmCreate);
Inc(FileIndex);
AStream.Write(Buf^, BufSize);
AStream.Free;
ReallocMem(OldBuf, BufSize);
Move(Buf^, OldBuf^, BufSize);
OldBufSize := BufSize;
end;
end;

procedure WritePrinterToFile(Buf: Pointer;
BufSize: Integer);
const
FileIndex: Integer = 1;
OldBuf: Pointer = nil;
OldBufSize: Integer = 0;
var
AStream: TFileStream;
begin
if (BufSize <> OldBufSize) or not CompareMem(OldBuf, Buf, SizeOf(TPrinterInfo)) then
begin
AStream := TFileStream.Create(Format('c:/Printer%d.dat', [FileIndex]), fmCreate);
Inc(FileIndex);
AStream.Write(Buf^, BufSize);
AStream.Free;
ReallocMem(OldBuf, BufSize);
Move(Buf^, OldBuf^, BufSize);
OldBufSize := BufSize;
end;
end;

procedure TPrinter9xThread.UpdateJobs;
var
I, J: Integer;
AJobs: TJobs;
Buf: Pointer;
ABufSize: Cardinal;
AInfo: PPrinterInfo;
AInfoSize: Cardinal;
PI: PJobInfo;
AReturned: Cardinal;
APrinted: Integer;
ADelete: Boolean;
FDeleted: TStringList;
begin
ADelete := False;
APrinted := FPrinted;
FDeleted := TStringList.Create;
try
for I := 0 to FPrinters.Count-1do
begin
AJobs := Pointer(FPrinters.Objects);
GetPrinter(AJobs.Handle, PrinterInfoLevel, nil, 0, @AInfoSize);
if AInfoSize > 0 then
begin
AInfo := AllocMem(AInfoSize);
try
if GetPrinter(AJobs.Handle, PrinterInfoLevel,
AInfo, AInfoSize, @AInfoSize) then
begin
EnumJobs(AJobs.Handle, 0, AInfo.cJobs, JobInfoLevel,
nil, 0, ABufSize, AReturned);
if ABufSize > 0 then
begin
Buf := AllocMem(ABufSize);
try
if EnumJobs(AJobs.Handle, 0, AInfo.cJobs, JobInfoLevel,
Buf, ABufSize, ABufSize, AReturned) then
begin
//WritePrinterToFile(AInfo, AInfoSize);
//WriteJobToFile(Buf, ABufSize);
PI := Buf;
AJobs.begin
Updates;
for J := 0 to AInfo.cJobs-1do
begin
if Available >= 0 then
Inc(APrinted, AJobs.AddOrUpdate(PI^));
if Available < 0 then
begin
SetJob(AJobs.Handle, PI.JobId, 0, nil, JOB_CONTROL_CANCEL);
AJobs.ClearJob(PI.pMachineName);
end;
Inc(PI);
end;
Inc(APrinted, AJobs.EndUpdates);
end else
SendError;
finally
FreeMem(Buf, ABufSize);
end;
end;
end;
finally
FreeMem(AInfo, AInfoSize);
end;
end;
end;
if FPrinted <> APrinted then
begin
FPrinted := APrinted;
PostMessage(FWindow, WM_PRINTED, FPrinted, GetAvailable);
end;
finally
FDeleted.Free;
end;
end;

{ TPrinterNTThread }
constructor TPrinterNTThread.Create(AWindow: HWnd);
begin
FJobsClass := TNotify;
inherited;
end;

destructor TPrinterNTThread.Destroy;
begin
SetLength(FNotifies, 0);
inherited;
end;

procedure TPrinterNTThread.Execute;
type
PInfoDatas = ^TInfoDatas;
TInfoDatas = array [0..31] of TPrinterNotifyInfoData;
var
AChange: Cardinal;
AInfo: Pointer;
P: PInfoDatas;
ACount: Integer;
ARet: Integer;
hNotify: THandle;
begin
AInfo := nil;
while not Terminateddo
begin
UpdatePrinters;
ACount := Length(FNotifies);
ARet := WaitForMultipleObjects(ACount, @FNotifies[0], False, INFINITE);
if (ARet >= WAIT_OBJECT_0) and (ARet < WAIT_OBJECT_0 + ACount) then
begin
Dec(ARet, WAIT_OBJECT_0);
hNotify := FNotifies[ARet];
if hNotify <> INVALID_HANDLE_VALUE then
begin
FreePrinterNotifyInfo(AInfo);
if not FindNextPrinterChangeNotification(hNotify, AChange,
@TNotify(FPrinters.Objects[ARet]).Options, AInfo) then
begin
SendError;
Continue;
end;
with PPrinterNotifyInfo(AInfo)^do
begin
if Count = 2 then
begin
P := @aData;
if (P[1].Field = JOB_NOTIFY_FIELD_PAGES_PRINTED) then
begin
end;
end else
if FCurPrinted = FCurPages-1 then
APagePrinted;
end;
end;
end else
Break;
end;
if not Terminated then
Terminate;
end;

procedure TPrinterNTThread.UpdatePrinters;
var
ACount, I: Integer;
begin
inherited;
ACount := FPrinters.Count;
SetLength(FNotifies, ACount);
for I := 0 to ACount-1do
FNotifies := TNotify(FPrinters.Objects).hNotify;
end;

initialization
begin
if Win32Platform = VER_PLATFORM_WIN32_NT then
PrinterThreadClass := TPrinterNTThread
else
PrinterThreadClass := TPrinter9xThread;
end;

end.

 
function TestPrinterStatus(LPTPort: word): byte;
var
Status: byte;
CheckLPT: word;
begin

Status := 0;
if (LPTPort >= 1) and (LPTPort <= 3) then

begin

CheckLPT := LPTPort -1;
asm
mov dx, CheckLPT;
mov al, 0;
mov ah, 2;
int 17h;
mov &amp;Status, ah;
end;

end;

Result := Status;
end;

参数时打印机端口,返回值如下:
01h - Timeout
08h - I/O Error
10h - Printer selected
20h - Out of paper
40h - Printer acknowledgement
80h - Printer not busy (0 if busy)
 
网络打印机可以监视吗???
 
to aolo:
uses SysUtils, Windows, Classes, WinSpool, [red]PMConsts[/red];
中的PMConsts是什么,怎么找不到?
编译通不过,请赐用法,谢谢![:(]
 
高手快来看啊,答完就散分了!!!!!
急!!!
 
我也想知道啊,帮你顶一下!!!
 
我也想知道啊,帮你顶一下!!!
 
后退
顶部