Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi PowerButton-Event von Windows abfangen und auswerten (https://www.delphipraxis.net/137772-powerbutton-event-von-windows-abfangen-und-auswerten.html)

rakekniven 28. Jul 2009 14:43


PowerButton-Event von Windows abfangen und auswerten
 
Hallo,

ich will bei einer Maschine mit einem Industrie-PC (Emb. Win XP) verhindern, dass dieser herunterfährt, wenn man den Netzschalter (auf der Front) drückt.

Bisher habe ich herausgefunden, dass das Event WM_POWERBROADCAST heißt und nur an die Top-Level-Anwendungen verschickt wird, weshalb ich bei meinem Programm einen global hook installieren muss.
Dafür habe ich dieses Tutorial verwendet: http://www.delphi-treff.de/tutorials...tastatur-hooks

In meiner .exe wird im FormCreate InstallHook aufgerufen sowie in FormDestroy UninstallHook, die beide aus der .dll vom Tutorial stammen:

Delphi-Quellcode:
library KeyboardHook;

uses
  Windows,
  Messages;

var
  HookHandle: Cardinal = 0;
  WindowHandle: Cardinal = 0;

function KeyboardHookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM):
LRESULT; stdcall;
begin
  Result := CallNextHookEx(HookHandle, nCode, wParam, lParam);
  case nCode < 0 of
    TRUE: exit;
    FALSE:
      begin
          sleep(10);
      end;
  end;
end;

function InstallHook(Hwnd: Cardinal): Boolean; stdcall;
begin
  Result := False;
  if HookHandle = 0 then begin
    HookHandle := SetWindowsHookEx(WH_KEYBOARD, @KeyboardHookProc,
    HInstance, 0);
    WindowHandle := Hwnd;
    Result := TRUE;
  end;
end;

function UninstallHook: Boolean; stdcall;
begin
  Result := UnhookWindowsHookEx(HookHandle);
  HookHandle := 0;
end;

exports
  InstallHook,
  UninstallHook;
end.
Kompiliere ich dann beides zusammen und drücke den Netzschalter, passiert nichts.
Wenn ich einen zusätzlichen Button mache, der WM_POWERBROADCAST sendet

Delphi-Quellcode:
SendMessage(HWNC_BROADCAST,WM_POWERBROADCAST,0,0)
passiert auch nichts.

Wo liegt mein Fehler?

Oder muss man einen anderen Weg nehmen?

Gruß

Luckie 28. Jul 2009 14:52

Re: PowerButton-Event von Windows abfangen und auswerten
 
Was soll auch passieren? In deiner KeyboardHookProc machst du ja nichts. Und ob ein KeyboardHook der passende Hook ist, weiß ich nicht. Der Powerknopf am Gehäuse gehört ja nicht zur Tastatur. Und warum ist dein Fenster kein Toplevel Fenster, wenn es eine Form hat?

Davon mal abgesehen, was machst du, wenn der Netzschalter zum ausschalten benutzt wird oder wenn das Netzkabel gezogen wird? Das Auschalten wirst du nicht verhindern können.

Kalfany 28. Jul 2009 15:15

Re: PowerButton-Event von Windows abfangen und auswerten
 
Liste der Anhänge anzeigen (Anzahl: 1)
Darf der PC nur unter bestimmten Umständen nicht über den Power-Knopf heruntergefahren werden oder gilt das immer? für das zweite ließe sich das auch über Windows regeln ...

Systemsteuerung -> Energieoptionen -> Erweitert -> "Beim Drücken des Netzschalters am Computer"

Wobei du das Ausschalten mit "lang drücken" nicht verhindern kannst außer das BIOS lässt da irgendwelche Optionen zu.

Edit: und falls du es wirklich über die Message im eigenen Programm machen willst dann eher so:

Delphi-Quellcode:
procedure WMPowerBroadcast(var Msg : TWMPower); message WM_POWERBROADCAST;
.
.
.
procedure TForm1.WMPowerBroadcast(var Msg: TWMPower);
begin
  Msg.Result := BROADCAST_QUERY_DENY;
end;

worker 28. Jul 2009 15:32

Re: PowerButton-Event von Windows abfangen und auswerten
 
Zitat:

Zitat von Kalfany
Systemsteuerung -> Energieoptionen -> Erweitert -> "Beim Drücken des Netzschalters am Computer"

Der entsprechende Registry-Eintrag dazu lautet:
Zitat:

HKCU\Control Panel\PowerCfg\GlobalPowerPolicy\\Policies
Der Wert für 'Nichts machen' wäre bspw.
Zitat:

"Policies"=hex:01,00,00,00,00,00,00,00,03,00,00,00 ,00,00,00,80,00,00,00,00,03,\
00,00,00,00,00,00,80,02,00,00,00,03,00,00,00,00,00 ,00,00,02,00,00,00,03,00,\
00,00,00,00,00,00,02,00,00,00,01,00,00,00,00,00,00 ,00,02,00,00,00,01,00,00,\
00,00,00,00,00,01,00,00,00,03,00,00,00,02,00,00,00 ,04,00,00,c0,01,00,00,00,\
04,00,00,00,01,00,00,00,0a,00,00,00,00,00,00,00,03 ,00,00,00,01,00,01,00,01,\
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 ,00,00,00,00,02,00,00,00,\
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 ,00,00,00,03,00,00,00,00,\
00,d6,ff,12,00

rakekniven 28. Jul 2009 15:47

Re: PowerButton-Event von Windows abfangen und auswerten
 
Zitat:

Zitat von Kalfany
Darf der PC nur unter bestimmten Umständen nicht über den Power-Knopf heruntergefahren werden oder gilt das immer? für das zweite ließe sich das auch über Windows regeln ...

Systemsteuerung -> Energieoptionen -> Erweitert -> "Beim Drücken des Netzschalters am Computer"

Wobei du das Ausschalten mit "lang drücken" nicht verhindern kannst außer das BIOS lässt da irgendwelche Optionen zu.

Diese Einstellungen kannten wir schon. Wir möchten einfach keine Windows-Dialoge im Vordergrund haben.
Unsere Anwendung läuft Fullscreen ohne Taskleiste.
Die Powertaste haben wir in Windows abgestellt ("Nichts machen") möchten aber die Nachricht dass die Taste gedrückt wurde selbst auswerten und einen eigenen Abfragedialog anzeigen.

Edit: und falls du es wirklich über die Message im eigenen Programm machen willst dann eher so:

Delphi-Quellcode:
procedure WMPowerBroadcast(var Msg : TWMPower); message WM_POWERBROADCAST;
.
.
.
procedure TForm1.WMPowerBroadcast(var Msg: TWMPower);
begin
  Msg.Result := BROADCAST_QUERY_DENY;
end;
Der Student wird morgen gleich "weiterforschen".

Danke und Gruß

worker 28. Jul 2009 15:50

Re: PowerButton-Event von Windows abfangen und auswerten
 
Lies Dir meinen Beitrag durch; dann brauchst Du keinen Dialog im Vordergrund (sofern Du Zugriff auf die Registry hast).

rakekniven 28. Jul 2009 15:51

Re: PowerButton-Event von Windows abfangen und auswerten
 
Zitat:

Zitat von Luckie
Was soll auch passieren? In deiner KeyboardHookProc machst du ja nichts. Und ob ein KeyboardHook der passende Hook ist, weiß ich nicht. Der Powerknopf am Gehäuse gehört ja nicht zur Tastatur.

Sorry, wahrscheinlich ist da ein Copy&Paste-Fehler passiert.

Zitat:

Zitat von Luckie
Und warum ist dein Fenster kein Toplevel Fenster, wenn es eine Form hat?

Unser Fenster läuft Fullscreen ohne Border und Icons. Ist es dann noch ein Toplevel-Fenster?

Zitat:

Zitat von Luckie
Davon mal abgesehen, was machst du, wenn der Netzschalter zum ausschalten benutzt wird oder wenn das Netzkabel gezogen wird? Das Auschalten wirst du nicht verhindern können.

Der PC hat keinen Netzschalter und das Netzkabel ist nicht zugänglich.
Es ist ein Maschinensteuerungs-PC. In meinem vorherigen Posting habe ich etwas mehr dazu geschrieben.

Danke und Gruß

rakekniven 28. Jul 2009 15:54

Re: PowerButton-Event von Windows abfangen und auswerten
 
Zitat:

Zitat von worker
Lies Dir meinen Beitrag durch; dann brauchst Du keinen Dialog im Vordergrund (sofern Du Zugriff auf die Registry hast).

Der Windows-Dialog soll nicht erscheinen. Dazu haben wir Deine Einstellung schon gemacht. Zugriff auf die Registry haben wir, aber wir möchten doch einen eigenen Dialog, den es schon gibt und über einen Button aufgerufen wird, anzeigen.

Gruß

P.S. Diese Anforderung zum Handling ist speziell, wie gesagt es ist eine Maschinensteuerung. Doch das auswerten der Windows-Message beim Drücken des Power-Knopfes sollte doch eine normale Programmiersache sein, oder?

jfheins 28. Jul 2009 16:00

Re: PowerButton-Event von Windows abfangen und auswerten
 
Du kannst auch diese Einstellung wieder zurücksetzen und dann das OnCloseQuery-Event auswerten. Zum Beispiel standardmäßig False (glaub ich) zurückgeben, und dem User einen Dialog präsentieren. Wenn er das dann doch möchte, kannst du das Herunterfahren wieder anstoßen ;)

P.S.: imho sollte das Teil ein Top-Level-Fenster sein, auch ohne Titelleiste und Border - top-level schließt vor allem die ganzen kleinen dinger (buttons, edits, usw.) aus...

Luckie 28. Jul 2009 20:35

Re: PowerButton-Event von Windows abfangen und auswerten
 
Zitat:

Zitat von rakekniven
Unser Fenster läuft Fullscreen ohne Border und Icons. Ist es dann noch ein Toplevel-Fenster?

Ja, dann ist es ein Toplevel Fenster.

himitsu 28. Jul 2009 20:58

Re: PowerButton-Event von Windows abfangen und auswerten
 
Wenn die Powertaste abgestellt wurde, dann wird doch auch keine WM_POWERBROADCAST-Botschaft verschickt, da dann ja nichts passiert.

WM_POWERBROADCAST ist nur eine Reaktion auf das Drücken des Tasters oder auf irgendwas, welches den PC z.B. runterfahren will ... diese Nachricht hat also nix mit der Taste selber zu tun.

Das drücken des Gehäuse-Power-Knöpfchens dürfte eher irgendeinen Interupt auslösen und an den kommt man wohl nur über einen Treiber? :gruebel:

hathor 29. Jul 2009 05:56

Re: PowerButton-Event von Windows abfangen und auswerten
 
...oder man fragt den Embedded Controller direkt ab - das Byte ist aber bei jedem PC/Notebook an einer anderen Stelle, denn es gibt keine Normung.

himitsu 29. Jul 2009 07:20

Re: PowerButton-Event von Windows abfangen und auswerten
 
Zitat:

Zitat von hathor
...oder man fragt den Embedded Controller direkt ab - das Byte ist aber bei jedem PC/Notebook an einer anderen Stelle, denn es gibt keine Normung.

irgendwer muß ja wissen wo es liegt ... das BIOS vielleicht/vermutlich?

rakekniven 29. Jul 2009 07:28

Re: PowerButton-Event von Windows abfangen und auswerten
 
Zitat:

Zitat von Luckie
Zitat:

Zitat von rakekniven
Unser Fenster läuft Fullscreen ohne Border und Icons. Ist es dann noch ein Toplevel-Fenster?

Ja, dann ist es ein Toplevel Fenster.

Bei meiner Recherche habe ich den Begriff "toplevel" gefunden und dass nur solche Anwendungen Windows-Messages wie WM_POWERBROASCAST empfangen können. Mein Testprogramm ist Form1.Align:=alClient und Form1.BorderIcons:=[].
Darauf habe ich einen Test-Button der die Message sendet. Darauf reagiert meine Prozedur

Delphi-Quellcode:
procedure WMPowerBroadcast(var Msg:TWMPower);
  message WM_POWERBROADCAST;


procedure TForm1.WMPowerBroadcast(var Msg:TWMPower);
begin
  Msg.Result:=BROADCAST_QUERY_DENY;
  ShowMessage('procedure TForm1.WMPowerBroadcast(var Msg:TWMPower);');
end;
wenn ich den Test-Button im Programm drücke, aber nicht wenn ich den PowerButton drücke und auch nicht, wenn ich den "Ausschalten"-Button drücke, der auf Start > Computer ausschalten... erscheint (wie weiter oben jmd schrieb).



Eine andere Empfangs-Prozedur, die ich in meiner Nachforschung entdeckt habe ist:

Delphi-Quellcode:
procedure wndproc(var msg:Tmessage);
begin
  inherited;
  if msg.msg = WM_POWERBROADCAST then
  begin
    ShowMessage('procedure wndproc(var msg:Tmessage);');
    msg.result:=BROADCAST_QUER_DENY;
  end;
end;
Diese wird beim manuellen senden der Message gar nicht erst aufgerufen. Verwende ich WndProc falsch oder überschreibe ich sie nicht richtig?



Zitat:

Zitat von himitsu
Wenn die Powertaste abgestellt wurde, dann wird doch auch keine WM_POWERBROADCAST-Botschaft verschickt, da dann ja nichts passiert.

WM_POWERBROADCAST ist nur eine Reaktion auf das Drücken des Tasters oder auf irgendwas, welches den PC z.B. runterfahren will ... diese Nachricht hat also nix mit der Taste selber zu tun.

Das drücken des Gehäuse-Power-Knöpfchens dürfte eher irgendeinen Interupt auslösen und an den kommt man wohl nur über einen Treiber? :gruebel:

Auf dem Delphi-PC habe ich die Taste so eingestellt, dass das Auswahl-Menü erscheint, damit ich merke, ob die Taste reagiert hat. Diese Einstellung ist im Grund aber egal, da auf den Druck der Taste reagiert werden soll und nicht auf eines der möglichen Events.
Wie weiter oben in diesem Post genauer beschrieben, reagiert das Programm aber auch nicht, wenn ich auf "Ausschalten" gehen und somit, laut deiner Aussage, das WM_POWERBROADCAST-Event auslöse.


Zitat:

Zitat von hathor
...oder man fragt den Embedded Controller direkt ab - das Byte ist aber bei jedem PC/Notebook an einer anderen Stelle, denn es gibt keine Normung.

Zitat:

Zitat von himitsu
Zitat:

Zitat von hathor
...oder man fragt den Embedded Controller direkt ab - das Byte ist aber bei jedem PC/Notebook an einer anderen Stelle, denn es gibt keine Normung.

irgendwer muß ja wissen wo es liegt ... das BIOS vielleicht/vermutlich?

Der Power-Taster ist direkt auf das Netzteil verdrahtet (lt. unserem PC-Hersteller). Und das Netzteil ist mit dem Mainboard verbunden. Welcher Chip/Bus das ist, wissen wir nicht genau, aber Windows bekommt es ja mit.

Es gibt eine Message, laut meinen Recherchen-Quellen ist es WM_POWERBROADCAST, was auch schon in einem älteren Thread im Forum (erfolgreich?) in einem ähnlichen Zusammenhang verwendet wurde.

edit:
Dieser Thread ist es: http://www.delphipraxis.net/internal...ht=powerbutton


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:06 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz