AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Delphi Druckaufträge überwachen und Programm starten
Thema durchsuchen
Ansicht
Themen-Optionen

Druckaufträge überwachen und Programm starten

Ein Thema von Oliver1983 · begonnen am 18. Aug 2011 · letzter Beitrag vom 25. Aug 2011
Antwort Antwort
ASM

Registriert seit: 15. Aug 2004
165 Beiträge
 
Delphi 7 Enterprise
 
#1

AW: Druckaufträge überwachen und Programm starten

  Alt 25. Aug 2011, 12:28
...sobald ich das mit DelphiXE Compiliere habe ich ne CPU Auslastung von 25%, nehme ich aber die aus der ZIP Datei ist alles super!!!

Warum?
Danke für den Hinweis auf diese problematische Erfahrung.

Mein Source und das entspr. Compilat ist unter Delphi 7 entstanden.

Ich habe mein Projekt jetzt auch einmal selbst unter Delphi XE (2010) compiliert:
zunächst einmal muss dazu in der Unit SpoolerStatusThreat obligat eine kleine Änderung vorgenommen werden. Es muss der Ergebnistyp der Funktion GetCurrentPrinterName() von "AnsiString" auf "String" (= Widestring) umgestellt werden. Außerdem muss in der Prozedur WatchSpoolerStatus die Anweisung auf pi2.pPrinterName := PWideChar(GetCurrentPrinterName); geändert werden. Wichtig: Wird der Funktionstyp unter Delphi XE nicht von AnsiString auf WideString abgeändert, so versagt das komplette Monitoring.

Mein Test mit den lauffähigen Programmen:
Compiliert unter D7: Auslastung der CPU unter WinXP (SP3): beginnt bei 0,12% geht dann allmählich runter auf 0,08%
Compiliert unter Delphi XE: Auslastung der CPU unter WinXP (SP3): steigt bei beginn des Monitoring (START-Button) auch bei mir schnell auf ca.50% !!

Erfolgreiche Korrektur:
In der Unit SpoolerStatusThreat, Prozedur WatchSpoolerStatus die Repeat-Schleife durch Einfügen eines sleep(10) so bremsen, dass der Prozessor nicht permanent mit Taktzyklen überlastet wird. Das Monitoring bleibt trotzdem voll funktionsfähig erhalten.

Also den Code in der Unit SpoolerStatusThreat für Delphi XE unbedingt ändern auf:
Code:
repeat
  sleep(10); // Pause von 10 Millisekunden neu eingefügt
  PeekMessage(aMsg, 0, 0, 0, PM_REMOVE);
  AppTerminated := (aMsg.message = WM_QUIT);
until AppTerminated or (WaitForSingleObject(hResult, 500) = WAIT_OBJECT_0);
Das Ergebnis nach Änderung:
Compiliert unter Delphi XE, getestet unter WinXP (SP3) auf einem 3 GHz Rechner : Auslastung der CPU nach Beginn des Monitoring beginnt bei 1-2% , sinkt dann rasch ab auf eine Auslastung unter 0,1%.

Gruß,
ASM
  Mit Zitat antworten Zitat
Oliver1983

Registriert seit: 8. Mär 2006
Ort: Hamburg
43 Beiträge
 
Delphi XE Starter
 
#2

AW: Druckaufträge überwachen und Programm starten

  Alt 25. Aug 2011, 12:45
Ich habe mein Projekt jetzt auch einmal selbst unter Delphi XE (2010) compiliert:
zunächst einmal muss dazu in der Unit SpoolerStatusThreat obligat eine kleine Änderung vorgenommen werden. Es muss der Ergebnistyp der Funktion GetCurrentPrinterName() von "AnsiString" auf "String" (= Widestring) umgestellt werden. Außerdem muss in der Prozedur WatchSpoolerStatus die Anweisung auf pi2.pPrinterName := PWideChar(GetCurrentPrinterName); geändert werden. Wichtig: Wird der Funktionstyp unter Delphi XE nicht von AnsiString auf WideString abgeändert, so versagt das komplette Monitoring.
Jep das musste ich auch ändern

Mein Test mit den lauffähigen Programmen:
Compiliert unter D7: Auslastung der CPU unter WinXP (SP3): beginnt bei 0,12% geht dann allmählich runter auf 0,08%
Compiliert unter Delphi XE: Auslastung der CPU unter WinXP (SP3): steigt bei beginn des Monitoring (START-Button) auch bei mir schnell auf ca.50% !!
wow, da bin ich ja noch recht sparsam mit der CPU-Auslastung gewesen

Erfolgreiche Korrektur:
In der Unit SpoolerStatusThreat, Prozedur WatchSpoolerStatus die Repeat-Schleife durch Einfügen eines sleep(10) so bremsen, dass der Prozessor nicht permanent mit Taktzyklen überlastet wird. Das Monitoring bleibt trotzdem voll funktionsfähig erhalten.

Also den Code in der Unit SpoolerStatusThreat für Delphi XE unbedingt ändern auf:
Code:
repeat
  sleep(10); // Pause von 10 Millisekunden neu eingefügt
  PeekMessage(aMsg, 0, 0, 0, PM_REMOVE);
  AppTerminated := (aMsg.message = WM_QUIT);
until AppTerminated or (WaitForSingleObject(hResult, 500) = WAIT_OBJECT_0);
Das Ergebnis nach Änderung:
Compiliert unter Delphi XE, getestet unter WinXP (SP3) auf einem 3 GHz Rechner : Auslastung der CPU nach Beginn des Monitoring beginnt bei 1-2% , sinkt dann rasch ab auf eine Auslastung unter 0,1%.

Gruß,
ASM
na das werde ich dann gleich mal machen, sind ja doch einige änderungen grins
Oliver
  Mit Zitat antworten Zitat
Oliver1983

Registriert seit: 8. Mär 2006
Ort: Hamburg
43 Beiträge
 
Delphi XE Starter
 
#3

AW: Druckaufträge überwachen und Programm starten

  Alt 25. Aug 2011, 13:00
so hab ich mal gemacht die änderungen, aber ich bekomme immer ne fehlermeldung "Zugriffsverletzung in der ntdll.dll"!

hier mal die spoolerStatusThread Unit:
Delphi-Quellcode:
unit SpoolerStatusThreat;

interface

uses Classes, Windows, Messages, SysUtils, Graphics, StdCtrls, Forms;

type
  TSpoolerMonitor = class(TThread)
  private
    FMsg: string;
    FForm: TForm;
  protected
    procedure Execute; override;
    procedure SpoolerStatus;
  public
    constructor Create(Suspend: boolean); overload;
    constructor Create(Suspend: boolean; Dispatch2Target: TForm); overload;
  public
    procedure exitThread;
  end;

var
  SpoolerMonitor: TSpoolerMonitor;

const
  WM_PRINTJOB_ADDED = WM_USER + 1000;

implementation

uses WinSpool, Printers;

type
  TPrinterDevice = class
    Driver: string;
    Device: string;
    Port: string;
  end;

Var
  pi2: PRINTER_INFO_2;
  pno: PRINTER_NOTIFY_OPTIONS;
  pinfo: PPrinterNotifyInfo;
  pn: array[0..1] of PRINTER_NOTIFY_OPTIONS_TYPE;
  pnf: array[0..100] of WORD;
  jnf: array[0..100] of WORD;

function GetCurrentPrinterName: String;
begin
  Result := TPrinterDevice(Printer.Printers.Objects[Printer.PrinterIndex]).Device;
end;

procedure TSpoolerMonitor.SpoolerStatus;
var
  hResult: THandle;
  Result: LongBool;
  hPrinter: cardinal;
  pdwChange: DWORD;
  ok: boolean;
  AppTerminated: Boolean;
  aMsg: TMsg;
begin
  pdwChange := 0;
  pi2.pPrinterName := PWideChar(GetCurrentPrinterName);
  if OpenPrinter(pi2.pPrinterName, hPrinter, 0) then
    hResult := FindFirstPrinterChangeNotification(hPrinter, PRINTER_CHANGE_JOB, 0, @pno);
  ok:= hResult <> INVALID_HANDLE_VALUE;
  if ok then
    while not terminated do
    begin
      AppTerminated := false;
      repeat
        sleep(10); // Pause von 10 Millisekunden neu eingefügt
        PeekMessage(aMsg, 0, 0, 0, PM_REMOVE);
        AppTerminated := (aMsg.message = WM_QUIT);
      until AppTerminated or (WaitForSingleObject(hResult, 500) = WAIT_OBJECT_0);
      if AppTerminated then exit;
      ok := false;
      pno.Flags := 0;
      Result := FindNextPrinterChangeNotification(hResult, pdwChange, @pno, pointer(pinfo));
      if ord(Result) <> 0 then
      begin
        if (pdwChange and PRINTER_CHANGE_ADD_JOB) > 0 then
          PostMessage(fForm.Handle, WM_PRINTJOB_ADDED, 0, 0);
      end;
    end;
end;

constructor TSpoolerMonitor.Create(Suspend: boolean);
begin
  inherited Create(Suspend);
  FreeOnTerminate := True;
end;

constructor TSpoolerMonitor.Create(Suspend: boolean; Dispatch2Target: TForm);
begin
  inherited Create(Suspend);
  FreeOnTerminate := True;
  FForm := Dispatch2Target;
end;

procedure TSpoolerMonitor.Execute;
var
  aMsg: TMsg;
begin
  inherited;
  SpoolerStatus;
end;

procedure TSpoolerMonitor.exitThread;
begin
  PostThreadMessage(Self.ThreadID, WM_QUIT, 0, 0);
  if Suspended then Resume;
end;

initialization

  pno.Version := 2;
  pno.Flags := PRINTER_NOTIFY_OPTIONS_REFRESH;
  pno.Count := 200;
  pno.pTypes := @pn;

  pn[0].wType := PRINTER_NOTIFY_TYPE;
  pn[0].Count := 8;
  pn[0].pFields := @pnf;
  pn[1].wType := JOB_NOTIFY_TYPE;
  pn[1].Count := 24;
  pn[1].pFields := @jnf;

  pnf[0] := PRINTER_NOTIFY_FIELD_STATUS;
  pnf[1] := PRINTER_NOTIFY_FIELD_CJOBS;
  pnf[2] := PRINTER_NOTIFY_FIELD_ATTRIBUTES;
  pnf[3] := PRINTER_NOTIFY_FIELD_COMMENT;
  pnf[4] := PRINTER_NOTIFY_FIELD_DEVMODE;
  pnf[5] := PRINTER_NOTIFY_FIELD_LOCATION;
  pnf[6] := PRINTER_NOTIFY_FIELD_SECURITY_DESCRIPTOR;
  pnf[7] := PRINTER_NOTIFY_FIELD_SEPFILE;

  jnf[0] := JOB_NOTIFY_FIELD_DOCUMENT;
  jnf[1] := JOB_NOTIFY_FIELD_STATUS;
  jnf[2] := JOB_NOTIFY_FIELD_MACHINE_NAME;
  jnf[3] := JOB_NOTIFY_FIELD_PORT_NAME;
  jnf[4] := JOB_NOTIFY_FIELD_USER_NAME;
  jnf[5] := JOB_NOTIFY_FIELD_NOTIFY_NAME;
  jnf[6] := JOB_NOTIFY_FIELD_DATATYPE;
  jnf[7] := JOB_NOTIFY_FIELD_PRINT_PROCESSOR;
  jnf[8] := JOB_NOTIFY_FIELD_PARAMETERS;
  jnf[9] := JOB_NOTIFY_FIELD_DRIVER_NAME;
  jnf[10] := JOB_NOTIFY_FIELD_DEVMODE;
  jnf[11] := JOB_NOTIFY_FIELD_STATUS_STRING;
  jnf[12] := JOB_NOTIFY_FIELD_SECURITY_DESCRIPTOR;
  jnf[13] := JOB_NOTIFY_FIELD_PRINTER_NAME;
  jnf[14] := JOB_NOTIFY_FIELD_PRIORITY;
  jnf[15] := JOB_NOTIFY_FIELD_POSITION;
  jnf[16] := JOB_NOTIFY_FIELD_SUBMITTED;
  jnf[17] := JOB_NOTIFY_FIELD_START_TIME;
  jnf[18] := JOB_NOTIFY_FIELD_UNTIL_TIME;
  jnf[19] := JOB_NOTIFY_FIELD_TIME;
  jnf[20] := JOB_NOTIFY_FIELD_TOTAL_PAGES;
  jnf[21] := JOB_NOTIFY_FIELD_PAGES_PRINTED;
  jnf[22] := JOB_NOTIFY_FIELD_TOTAL_BYTES;
  jnf[23] := JOB_NOTIFY_FIELD_BYTES_PRINTED;

end.
25.08.2011 - 14:08
Hat sich grad erledigt, hab noch mal den Source aus der Zip genommen klappt jetzt und CPU auslastung ist jetzt bei 0% gut so
Oliver

Geändert von Oliver1983 (25. Aug 2011 um 13:09 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von chaosben
chaosben

Registriert seit: 27. Apr 2005
Ort: Görlitz
1.358 Beiträge
 
Delphi XE2 Professional
 
#4

AW: Druckaufträge überwachen und Programm starten

  Alt 25. Aug 2011, 13:07
Hier hätten wir noch ein Stück simplen kurzen Code:
Delphi-Quellcode:
TMyThread = class(TThread)
  protected
    FPrinter : THandle;
    procedure Execute; override;
  public
    constructor Create(APrinter : THandle); reintroduce;
  end;

//...

constructor TMyThread.Create(APrinter : THandle);
begin
  FPrinter := APrinter;
  inherited Create(false);
end;

procedure TMyThread.Execute;
var
  change : THandle;
  changed : Cardinal;
  info : Pointer;
  s : String;
begin
  change := FindFirstPrinterChangeNotification(FPrinter, PRINTER_CHANGE_JOB, 0, nil);
  while not Terminated do
  begin
    if WaitForSingleObject(change, 500) <> WAIT_TIMEOUT then
    begin
      if FindNextPrinterChangeNotification(change, changed, nil, info) then
      begin
        case changed of
          PRINTER_CHANGE_ADD_JOB: s := 'add job';
          PRINTER_CHANGE_SET_JOB: s := 'set job';
          PRINTER_CHANGE_DELETE_JOB: s := 'delete job';
          PRINTER_CHANGE_WRITE_JOB: s := 'write job';
        end;
        Synchronize(procedure begin ShowMessage(s) end);
        FreePrinterNotifyInfo(info);
      end;
    end;
  end;

  FindClosePrinterChangeNotification(change);
end;
Getestet unter Win7_64 mit D2009 .. funzt
Benjamin Schwarze
If I have seen further it is by standing on the shoulders of Giants. (Isaac Newton)
  Mit Zitat antworten Zitat
Oliver1983

Registriert seit: 8. Mär 2006
Ort: Hamburg
43 Beiträge
 
Delphi XE Starter
 
#5

AW: Druckaufträge überwachen und Programm starten

  Alt 25. Aug 2011, 13:18
Hier hätten wir noch ein Stück simplen kurzen Code:
Delphi-Quellcode:
TMyThread = class(TThread)
  protected
    FPrinter : THandle;
    procedure Execute; override;
  public
    constructor Create(APrinter : THandle); reintroduce;
  end;

//...
Getestet unter Win7_64 mit D2009 .. funzt
D.h. einfacher geschrieben als ASM? oder muss ich das zu dem Projekt von ASM zufügen?

Gruß Olli

Danke für eure Hilfe
Oliver
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.757 Beiträge
 
Delphi 12 Athens
 
#6

AW: Druckaufträge überwachen und Programm starten

  Alt 25. Aug 2011, 13:19
Hier hätten wir noch ein Stück simplen kurzen Code:
Delphi-Quellcode:
TMyThread = class(TThread)
  protected
    FPrinter : THandle;
    procedure Execute; override;
  public
    constructor Create(APrinter : THandle); reintroduce;
  end;

//...
Getestet unter Win7_64 mit D2009 .. funzt
D.h. einfacher geschrieben als ASM? oder muss ich das zu dem Projekt von ASM zufügen?
Nein, der Code tut auch so, was er soll.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Oliver1983

Registriert seit: 8. Mär 2006
Ort: Hamburg
43 Beiträge
 
Delphi XE Starter
 
#7

AW: Druckaufträge überwachen und Programm starten

  Alt 25. Aug 2011, 14:12
So das ist ja jetzt Super das das alles geklärt ist! So nun möchte ich aber das ein Index zurück gegeben wird wenn der einen Print job findet und danach wenn dieser fertig ist! Welcher Drucker das ist!

Die installierten Drucker lese ich so aus:

Delphi-Quellcode:
procedure TForm1.Btn_lese_alle_DruckerClick(Sender: TObject);
var
 i : integer;
begin
 Combobox1.Clear;

 for i := 0 to Printers.Printer.Printers.Count-1 do
  begin
   combobox1.Items.Add(Printers.Printer.Printers.Strings[i]);
  end;

end;
Somit habe ich den Index der Drucker gleich mit, übernehme den Index von der Combobox, da dieser gleich ist wie der von den Windows Druckern!!!

Das ist meine alte funktion:

Delphi-Quellcode:
function print_jobs(printer_index: integer) : integer;
type
  PJobs = ^TJobs;
  TJobs = array[0..0]of TJobInfo2;
var
  Needed, JobCounter : DWORD;
  i : Integer;
  Device, Driver, Port : array[0..255] of char;
  hPrinter, hDeviceMode : THandle;
  Buffer : Pointer;
  Job : PJobs;
const
  NoJobs = 100;
begin
//TEIL1

  Printer.PrinterIndex := printer_index;
  Printer.GetPrinter(Device, Driver, Port, hDeviceMode);
  if WinSpool.OpenPrinter(@Device, hPrinter, nil) then
  begin
    EnumJobs(hPrinter, 0, NoJobs, 2, nil, 0, Needed, JobCounter);
    GetMem(Buffer, Needed);
   // Buffer := AllocMem(Needed);

    try
      Job := Buffer;

      if EnumJobs(hPrinter, 0, NoJobs, 2, Buffer, Needed, Needed, JobCounter) then
        begin
        Form1.LabeledEdit2.Text := IntToStr(JobCounter);
        if JobCounter > 0 then
         begin
           result := 1;
         end;
          for i := 0 to JobCounter - 1 do
            begin
            if Job[i].pDocument <> nil then
              Form1.LabeledEdit3.Text := IntToStr(Job[i].TotalPages);
            end;
        end;

    finally
      FreeMem(Buffer, Needed);
    end;

   WinSpool.ClosePrinter(hPrinter);
  end;

 sleep(10);
end;
Gruß Olli
Oliver
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:58 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz