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 WM_POWERBROADCAST wie verwenden? (https://www.delphipraxis.net/202398-wm_powerbroadcast-wie-verwenden.html)

ULIK 30. Okt 2019 11:01

WM_POWERBROADCAST wie verwenden?
 
Hallo,

ich habe eine wirklich dumme Frage: ich habe eine kleine Testanwendung, die nichts weiter machen soll, als auf WM_POWERBROADCAST Messages zu hören und in ein Memo zu schreiben, was empfangen wurde.

Delphi-Quellcode:
procedure TForm1.WMPowerbroadcast(var Message: TMessage);
begin
  memLog.Lines.Add('PowerBroadcast received');

  case Message.WParam of
    PBT_APMQUERYSUSPEND: memLog.Lines.Add('PBT_APMQUERYSUSPEND');
    PBT_APMQUERYSTANDBY: memLog.Lines.Add('PBT_APMQUERYSTANDBY');
    PBT_APMQUERYSUSPENDFAILED: memLog.Lines.Add('PBT_APMQUERYSUSPENDFAILED');
    PBT_APMQUERYSTANDBYFAILED : memLog.Lines.Add('PBT_APMQUERYSTANDBYFAILED');
    PBT_APMSUSPEND: memLog.Lines.Add('PBT_APMSUSPEND');
    PBT_APMSTANDBY: memLog.Lines.Add('PBT_APMSTANDBY');
    PBT_APMRESUMECRITICAL: memLog.Lines.Add('PBT_APMRESUMECRITICAL');
    PBT_APMRESUMESUSPEND: memLog.Lines.Add('PBT_APMRESUMESUSPEND');
    PBT_APMRESUMESTANDBY: memLog.Lines.Add('PBT_APMRESUMESTANDBY');
    PBT_APMBATTERYLOW: memLog.Lines.Add('PBT_APMBATTERYLOW');

    PBT_APMPOWERSTATUSCHANGE: memLog.Lines.Add('PBT_APMPOWERSTATUSCHANGE');
    PBT_APMOEMEVENT: memLog.Lines.Add('PBT_APMOEMEVENT');
    PBT_APMRESUMEAUTOMATIC: memLog.Lines.Add('PBT_APMRESUMEAUTOMATIC');
  end;
end;
Wenn ich das unter W10 laufen lassen und dann den Rechner in den Energiesparmodus oder Ruhemodus versetze, dann wird rein gar nichts aufgezeichnet. Auch ein Zuklappen des Laptopdeckels scheint keine Message zu generieren. Einzig wenn man das Netzteil an/absteckt, dann wir eine Message mit PBT_APMPOWERSTATUSCHANGE empfangen.

Ich nehm an, ich mach irgendeinen Fehler, nur welchen? Ich steh grad völlig auf dem Schlauch.

Ach so: Delphi ist XE 10.2.3

HolgerX 30. Okt 2019 15:16

AW: WM_POWERBROADCAST wie verwenden?
 
Hmm

Lies mal hier zu PBT_APMQUERYSUSPEND:

https://docs.microsoft.com/en-us/win...pmquerysuspend

Zitat:

Support for this event was removed in Windows Vista
https://docs.microsoft.com/en-us/win...powerbroadcast

WM_POWERBROADCAST scheint auch nur noch folgende event identifiers zu unterstützen:

PBT_APMPOWERSTATUSCHANGE
PBT_APMRESUMEAUTOMATIC
PBT_APMRESUMESUSPEND
PBT_APMSUSPEND
PBT_POWERSETTINGCHANGE


Auch kann seit Vista hiermit kein Suspend mehr damit unterbunden werden...

ULIK 30. Okt 2019 15:48

AW: WM_POWERBROADCAST wie verwenden?
 
Danke für den Hinweis. Inzwischen bin ich auch schlauer: selbst
PBT_APMRESUMEAUTOMATIC
PBT_APMRESUMESUSPEND
PBT_APMSUSPEND
werden nicht empfangen. Damit das wieder geht muß sich die Anwendung mit RegisterSuspendResumeNotification anmelden und entsprechend wieder abmelden (UnRegisterSuspendResumeNotification). Dies wäre angeblich seit Windows 8 so.
Dummerweise ist diese API nicht in Delphi 10.2 enthalten. Hab das mal selbst gemacht und siehe da, schon werden beim Schließen des Laptopdeckels wieder PBT_APMSUSPEND und anschließend beim Öffnen PBT_APMRESUMEAUTOMATIC und PBT_APMRESUMESUSPEND empfangen.

Hier mal etwas Code:
Delphi-Quellcode:
var
  hLibrary: THandle = 0;

  RegisterSuspendResumeNotification: function(hRecipient: THandle; flags: DWORD): HPOWERNOTIFY; stdcall = nil;
  UnRegisterSuspendResumeNotification: function(hNotification: HPOWERNOTIFY): Bool; stdcall = nil;

...

  hLibrary := LoadLibrary('user32.dll');
  if hLibrary <> 0 then
  begin
    RegisterSuspendResumeNotification := GetProcAddress(hLibrary, 'RegisterSuspendResumeNotification');
    UnRegisterSuspendResumeNotification := GetProcAddress(hLibrary, 'UnregisterSuspendResumeNotification');
  end;
Der Aufruf erfolgt dann z.B. im FormCreate mit
Delphi-Quellcode:
hNotification := RegisterSuspendResumeNotification(Handle, DEVICE_NOTIFY_WINDOW_HANDLE);
; entsprechend dann
Delphi-Quellcode:
UnRegisterSuspendResumeNotification(hNotification)
im FormDestroy


Frohes Schaffen!

TurboMagic 30. Okt 2019 18:17

AW: WM_POWERBROADCAST wie verwenden?
 
Wo in die Delphi RTL würden diese fehlenden API Deklarationen rein gehören?
Macht es Sinn, einen QP Feature request dazu zu erfassen?

TurboMagic 30. Okt 2019 21:38

AW: WM_POWERBROADCAST wie verwenden?
 
Dann darf mal jemand von euch einen QP feature request
zur Aufnahme dieser WinAPI Funktionen schreiben. Ich tu's
nicht, da kenne ich mich ein wenig zu wenig aus und habe
außerdem eh' schon sehr viele QP reports ;-)

=> Freiwillige vor, damit das demnächst "out of the box" geht! ;-)

Grüße

TurboMagic

ULIK 31. Okt 2019 10:20

AW: WM_POWERBROADCAST wie verwenden?
 
Hier mal eine etwas komplettere Unit
Delphi-Quellcode:
{-----------------------------------------------------------------------------
  Name:         uPowerManagement
  Author:       UK

  Description:
    Hilfsunit, die die Funktionen zum Registrieren der WM_POWERBROADCAST
    Messages bereitstellt (ab Win 8 nötig): dadurch empfängt diese BroadcastMessages
    für Suspend und Resume

    Aufruf erfolgt dann z.b. im FormCreate/Destroy mit dem Form-Handle, das die
    Message verarbeiten soll:


    procedure TForm1.FormCreate(Sender: TObject);
    begin
      RegisterPowermanagement(Handle);
    end;

    procedure TForm1.FormDestroy(Sender: TObject);
    begin
      UnregisterPowermanagement;
    end;

  History:
    2019-10-30  UK Unit created.
-----------------------------------------------------------------------------}

unit uPowerManagement;

interface

uses
  Winapi.Windows,
  System.SysUtils;

procedure RegisterPowermanagement(AMainForm: HWND);
procedure UnregisterPowermanagement;

implementation

var
  hLibrary: THandle = 0;
  hNotification: HPOWERNOTIFY = nil;

  RegisterSuspendResumeNotification: function(hRecipient: THandle; flags: DWORD): HPOWERNOTIFY; stdcall = nil;
  UnRegisterSuspendResumeNotification: function(hNotification: HPOWERNOTIFY): Bool; stdcall = nil;

{-----------------------------------------------------------------------------
  Procedure:  goIsWindows8OrHigher
  Author:     UK
  Description: Erkennung Windowsversion (nur eine Möglichkeit)
  Arguments:
  Result:     Boolean
  Exceptions: -
-----------------------------------------------------------------------------}

function goIsWindows8OrHigher: Boolean;
begin
  Result := ((Win32MajorVersion = 6) and (Win32MinorVersion >= 2)) or
             (Win32MajorVersion > 6);
end;
{-----------------------------------------------------------------------------
  Procedure:  RegisterPowermanagement
  Author:     UK
  Description:
  Arguments:  AMainForm : HWND - Fensterhandle Anwendung
  Result:     None
  Exceptions: -
-----------------------------------------------------------------------------}

procedure RegisterPowermanagement(AMainForm: HWND);
begin
  if goIsWindows8OrHigher then // Erkennen, daß man unter Windows 8 und höher ist.
  begin
    if Assigned(RegisterSuspendResumeNotification) then
    begin
      hNotification := RegisterSuspendResumeNotification(AMainForm, DEVICE_NOTIFY_WINDOW_HANDLE);
      if hNotification <> nil then
        // Logging: SiUnit.LogString(lvDebug, 'Info', 'Powermanagement successfully registered')
      else
        ;// Logging: LogLastOSError('RegisterSuspendResumeNotification');
    end
    else
      ;// Logging: SiUnit.LogWarning('RegisterSuspendResumeNotification not registered');
  end;
end;

{-----------------------------------------------------------------------------
  Procedure:  UnregisterPowermanagement
  Author:     UK
  Description:
  Arguments:
  Result:     None
  Exceptions: -
-----------------------------------------------------------------------------}

procedure UnregisterPowermanagement;
begin
  if goIsWindows8OrHigher then
  begin
    if Assigned(UnRegisterSuspendResumeNotification) then
    begin
      if (hNotification <> nil) then
      begin
        if UnRegisterSuspendResumeNotification(hNotification) then
          // Logging: SiUnit.LogString(lvDebug, 'Info', 'Powermanagement successfully unregistered')
        else
          // Logging: SiUnit.LogError('Failed to unregister notification: ' + LastWin32Error);
      end
      else
        // Logging: SiUnit.LogWarning('UnRegisterSuspendResumeNotification: no notification registered');
    end
    else
      // Logging: SiUnit.LogWarning('UnRegisterSuspendResumeNotification not registered');
  end;
end;

initialization

  hLibrary := LoadLibrary('user32.dll');
  if hLibrary <> 0 then
  begin
    RegisterSuspendResumeNotification := GetProcAddress(hLibrary, 'RegisterSuspendResumeNotification');
    UnRegisterSuspendResumeNotification := GetProcAddress(hLibrary, 'UnregisterSuspendResumeNotification');
  end;

finalization

  FreeLibrary(hLibrary);

end.
Ob man dafür jetzt einen QP Request schreiben sollte, bin ich mir nicht sicher. Es ist halt schon eine sehr spezielle Situation, daß man auf Suspend/Resume reagieren muß. Wenn dann sollte das jedenfalls in Winapi.Windows rein (da gibt's bereits ähnliche Deklarationen für das Powermanagement).
Aber das Ganze hier unter einem Vorbehalt: damit funktioniert es bei mir. Ob das aber nun wirklich der korrekte Weg ist, auf Suspend / Resume zu reagieren bin ich mir auch nicht 100% sicher. Dazu kenn ich mich zu wenig in dem Zeug aus.
Vieleicht können hier ja noch die Experten was beisteuern. :-)

amigage 20. Dez 2019 11:38

AW: WM_POWERBROADCAST wie verwenden?
 
Hallo,

vielen Dank für den Thread. Dieser ist für mich sehr interessant, da ich mich aktuell auch mit dem Ermitteln von Ruhezustand und Erwachen beschäftige.
Mein Problem ist jedoch, dass ich kein Programm mit einem sichtbaren Fenster verwende, sondern einen Windows-Dienst. In dem Fall habe ich kein Handle des aktuellen Fensters.


Ich habe bereits im Netzt recherchiert und bin eigentlich nur auf "ist nicht möglich" gestoßen.
Aber es muss doch eine Möglichkeit geben, dass ein mit TService erstellter Dienst den Windows Ruhezustand ermitteln kann.

Über sachdienliche Hinweise würde ich mich freuen.

Gruß,
amigage

HolgerX 20. Dez 2019 14:37

AW: WM_POWERBROADCAST wie verwenden?
 
Hmm..

Was hindert dich daran per

AllocateHWnd

ein Fensterhandle zu holen und dies dann für die Aufrufe zu verwenden?

Ich habe einige nicht sichtbare Komponenten, welche so ohne 'Form' Windowsmessages erhalten und verarbeiten können..

Michael II 20. Dez 2019 15:07

AW: WM_POWERBROADCAST wie verwenden?
 
Zitat:

Zitat von ULIK (Beitrag 1450531)
Danke für den Hinweis. Inzwischen bin ich auch schlauer: selbst
PBT_APMRESUMEAUTOMATIC
PBT_APMRESUMESUSPEND
PBT_APMSUSPEND
werden nicht empfangen.

Danke für deine Info. Aber: Ich verwende WM_POWERBROADCAST seit vielen Jahren in einem Onlinespiel ohne "RegisterSuspendResumeNotification" und es funktioniert auch im Insider Build Version 10.0.19041 (soeben getestet). Ich schliesse den Deckel, mein Programm empfängt WM_POWERBROADCAST wParam=PBT_APMSUSPEND. Ich öffne den Deckel und melde mich an und prüfe: Mein Programm empfängt zuerst PBT_APMRESUMESUSPEND und danach PBT_APMRESUMEAUTOMATIC. Dein Code aus #1 sollte also funktionieren.

Hast du eventuell bei der Deklaration message WM_POWERBROADCAST; vergessen (?).


Delphi-Quellcode:
type
  TMeinForm = class(TForm)
   ...
  procedure WMPowerBroadcast(var Msg: TMessage); message WM_POWERBROADCAST;


procedure TMeinForm.WMPowerBroadcast(var Msg: TMessage);
begin
  try
    case Msg.wParam of
    PBT_APMSUSPEND: &#8230;.
    PBT_APMRESUMESUSPEND: &#8230;.
    PBT_APMRESUMEAUTOMATIC: &#8230;.

ULIK 20. Dez 2019 16:34

AW: WM_POWERBROADCAST wie verwenden?
 
Hallo,

Zitat:

Hast du eventuell bei der Deklaration message WM_POWERBROADCAST; vergessen (?).
das glaub ich nicht, denn PBT_APMPOWERSTATUSCHANGE ist ja durchgekommen. Im eigentlichen Programm war das auch schon mal alles funktionierend ohne das Register... eingebaut; ich bin darüber gestolpert, weil es auf einmal nicht mehr funktioniert hat. Entweder war das temporär bei Windows 10 deaktiviert und geht nun wieder oder es ist noch was anderes. Jedenfalls klappt's mit RegisterSuspendResumeNotification wieder :-)


Frohe Weihnachten!
Uli


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:27 Uhr.
Seite 1 von 2  1 2   

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