请问:如何在win2000下获得打印机的状态!例如:缺纸,联机等(100分)

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

fgh001

Unregistered / Unconfirmed
GUEST, unregistred user!
我已经搜索了n遍了,都是win98下的代码,对于win2000不合适!!!
 
有办法做到,但无实际应用价值。每种打印机的驱动都不同,你做出来又有什么用。
 
我用的是pos58小票机,主要是为了检查是否缺纸以及是否已经联机,
非常有必要!!
 
改用win98甚至dos。 [:)]
 
不知道你用的是驱动程序, 还是控件, 如果是驱动程序, 会有一个说明文档, 里面会
告诉你一些指令来取得打印机的状态! 如果利用控件的话! 也会有一些命令的!
 
用这个函数:FindFirstPrinterChangeNotification,用线程,监视所有打印机,你想要的所有的信息都有,呵呵,注意,只支持2000,NT,不支持9x,我有个现成的模块,可以监视联机,脱机,打印机打印了多少张,还有多少张没有打印。
 
POS58打印机提供了ESC/POS打印集。
例如:LF:打印并换行;
ESC J n :打印并走纸n点行
请问:如何在2000下调用该指令集!!
 
to DelphiSwords:
我非常需要该程序!!!
fgh001@sina.com
 
TO DELPHISWORS:
能否给一份,谢谢,H_LR@163.COM
 
我也用W2K,GZ
 
给你们一个单元吧,是监视打印机的打印状态的,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.
 
能否给个实例:如何调用该单元,我的水平有限,实在不知道怎么调用它!!
 
接受答案了.
 
DelphiSwords兄:
在您给的PMThreads单元中要用到PMConsts单元,能把PMConsts单元也发给我吗?
gdyxz@btamail.net.cn
谢谢!!
 
后退
顶部