Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Druckaufträge überwachen und Programm starten (https://www.delphipraxis.net/162347-druckauftraege-ueberwachen-und-programm-starten.html)

Oliver1983 18. Aug 2011 13:29

Druckaufträge überwachen und Programm starten
 
Hi,

nach langem suchen ( drei Tage ) stelle ich nun meine Frage hier mal!

Ich möchte folgendes machen und zwar, soll das Programm den Druckerspooler von Windows überwachen und sobald ein Druckauftrag gesendet worden ist Programm bzw. ein Telnet befehl an die Fritzbox gesendet werden.

Mein Hauptproblem liegt beim überwachen des Spoolers! WinAPI?
Desweiteren Telnet einloggen bei der Fritzbox und einen Telnet befehl ausführen! Dieser Befehl schaltet dann die Steckdose an und somit den Drucker!!!

Bin um jede Hilfe dankbar

Gruß Olli

axellang 19. Aug 2011 11:35

AW: Druckaufträge überwachen und Programm starten
 
Hi,

Zitat:

Zitat von Oliver1983 (Beitrag 1117849)
Hi,

nach langem suchen ( drei Tage ) stelle ich nun meine Frage hier mal!

Bin um jede Hilfe dankbar

Gruß Olli

siehe PrinterSpy und lerne ;-)

Axel

Oliver1983 19. Aug 2011 20:26

AW: Druckaufträge überwachen und Programm starten
 
Das bringt leider gar nichts, gibt es ne möglichkeit das mein Programm auf eine Windows Massage reagiert ohne das ich eine Timer abfrage machen muss? Ich könnte zwar einfach einen Timer nehmen der ständig die Drucker warte schlange überprüft, aber ich weiß nicht in wie fern das System dadurch belasted wird! Oder kann ich es vernachlässigen?

Gruß Olli

axellang 20. Aug 2011 00:13

AW: Druckaufträge überwachen und Programm starten
 
Hi Olli,
Zitat:

Zitat von Oliver1983 (Beitrag 1118175)
Das bringt leider gar nichts, gibt es ne möglichkeit das mein Programm auf eine Windows Massage reagiert ohne das ich eine Timer abfrage machen muss? Ich könnte zwar einfach einen Timer nehmen der ständig die Drucker warte schlange überprüft, aber ich weiß nicht in wie fern das System dadurch belasted wird! Oder kann ich es vernachlässigen?

Gruß Olli

ohne dir jetzt näher treten zu wollen, denke ich das Du die Funktionsweise der Kompo nicht verstanden oder dir die Kompo nicht angesehen hast.
Zitat:

It shows how to use the MSDN-Library durchsuchenFindFirstPrinterChangeNotification and MSDN-Library durchsuchenFindNextPrinterChangeNotification API function to monitor printer queues. Provides a reusable component with an OnJobChange event.
Die Beschreibung sagt alles.

Axel

Luckie 20. Aug 2011 01:11

AW: Druckaufträge überwachen und Programm starten
 
Guck dir hier mal http://assarbad.net/en/stuff -> prtmon3vivi.* an.

ASM 20. Aug 2011 12:57

AW: Druckaufträge überwachen und Programm starten
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

ohne dir jetzt näher treten zu wollen, denke ich das Du die Funktionsweise der Kompo nicht verstanden oder dir die Kompo nicht angesehen hast.
Die Umsetzung der API-Funktionen FindFirstPrinterChangeNotification() und FindNextPrinterChangeNotification() in einen auch tatsächlich arbeitsfähigen Code
ohne erweiterte, präzise Kenntnis der zahlreichen benötigten Parameter ist nicht ganz so einfach, wie unterstellt wird. Insbesondere für die von Oliver1983 beschriebene Aufgabe des permannten Pollings.

Vielleicht entspricht dies hier Deinen Vorstellungen (Source und Bin (D7, für Screen 1280x1024 compiliert)): cf. Anhang.

Der PrintSpooler wird ein einem eigenen Thread überwacht, so dass der Mainthread nicht blockiert ist.
Der Spoolerthreat gibt über eine userdefinierte Message an den Mainthreat die Information, sobald ein neuer Printjob im Spooler vorliegt. Der Mainthread kann dann mit dieser Information anfangen (in der Message-Methode WM_SpoolerStatus()), was gebraucht wird.

Den Spoolermonitor könnte man noch - je nach Bedarf - erheblich erweitern um Rückmeldungen an den Mainthreat, z.B.:
- welcher Drucker mit dem Job beauftragt worden ist
- welches Dokument gedruckt werden soll
- falls ein Job aus dem Spooler entfernt worden ist
usw.

Oliver1983 25. Aug 2011 11:00

AW: Druckaufträge überwachen und Programm starten
 
@ASM

ist schon cool! Aber 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?

Gruß Olli

ASM 25. Aug 2011 12:28

AW: Druckaufträge überwachen und Programm starten
 
Zitat:

Zitat von Oliver1983 (Beitrag 1119535)
...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

Oliver1983 25. Aug 2011 12:45

AW: Druckaufträge überwachen und Programm starten
 
Zitat:

Zitat von ASM (Beitrag 1119563)
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 :)

Zitat:

Zitat von ASM (Beitrag 1119563)
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 :stupid:

Zitat:

Zitat von ASM (Beitrag 1119563)
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

Oliver1983 25. Aug 2011 13:00

AW: Druckaufträge überwachen und Programm starten
 
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 :thumb:


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:30 Uhr.
Seite 1 von 2  1 2      

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