![]() |
Hibernate und Standby erkennen
Hab zwar schon einiges gefunden, wie man das Herunterfahren erkennen kann (WINDOWS_SESSION_END und Co.),
allerdings bekommt man nirgends ein Ereignis, wenn der Rechner in den Standby, oder Ruhezustand gefahren wird. Ich würde einfach gerne mein Programm in einen Pausemodus versetzen, wenn derartiges passiert. PS: der MediaPlayer (ich glaub seit v7) kann ja auch sowas. |
Re: Hibernate und Standby erkennen
Folgendes ist nötig, um auf den Standby oder Ruhezustand (Hibernation) reagieren zu können
(inkl. Nachricht, wenn das System aus diesem wieder zurückgeholt wird): Zuerst muss die Windows-Nachrichtenabfrage überschrieben werden:
Delphi-Quellcode:
Die genaue Funktion sieht in der Implementierung so aus:
Form1...
procedure WndProc(var MyMessage: TMessage); override;
Delphi-Quellcode:
In der obigen Funktion gehe ich auf die Anfrage zum Standby und Ruhezustand ein.
procedure TForm1.WndProc(var MyMessage: TMessage);
begin if MyMessage.Msg = WM_POWERBROADCAST then begin // windows powermanagement message if (MyMessage.WParam = PBT_APMQUERYSUSPEND) or (MyMessage.WParam = PBT_APMQUERYSTANDBY) then begin // windows want to go into standby or hibernation mode // Hier hin, was getan werden muss, bevor Windows in den Standby darf, // z.B. Netzwerk- oder Datenbankverbindungen trennen, Timer abstellen, etc. MyMessage.Result := 1; // allow standby/hibernation // MyMessage.Result := BROADCAST_QUERY_DENY; // deny standby/hibernation end else if (MyMessage.WParam = PBT_APMRESUMECRITICAL) or (MyMessage.WParam = PBT_APMRESUMESUSPEND) or (MyMessage.WParam = PBT_APMRESUMESTANDBY) then begin // windows returns from standby or hibernation // Hier z.B. Verbindungen wiederherstellen end; end; inherited WndProc(MyMessage); end; Durch abfragen von PBT_APMSUSPEND oder PBT_APMSTANDBY kann man noch etwas ausführen, kurz bevor der PC definitiv in den Standby geht. Sollten die Konstanten nicht verfügbar sein, hier die Deklaration:
Delphi-Quellcode:
Näheres zu den einzelnen Konstanten gibts im Windows SDK unter WM_POWERBROADCAST
PBT_APMQUERYSUSPEND = $0000;
PBT_APMQUERYSTANDBY = $0001; PBT_APMQUERYSUSPENDFAILED = $0002; PBT_APMQUERYSTANDBYFAILED = $0003; PBT_APMSUSPEND = $0004; PBT_APMSTANDBY = $0005; PBT_APMRESUMECRITICAL = $0006; PBT_APMRESUMESUSPEND = $0007; PBT_APMRESUMESTANDBY = $0008; PBTF_APMRESUMEFROMFAILURE = $00000001; PBT_APMBATTERYLOW = $0009; PBT_APMPOWERSTATUSCHANGE = $000A; PBT_APMOEMEVENT = $000B; PBT_APMRESUMEAUTOMATIC = $0012; Nachtrag: Windows wartet was um die 10-20 Sekunden auf die Antwort deine Programms, von daher würde ich nix großartig rechenintensives machen ;) |
Re: Hibernate und Standby erkennen
Das geht auch einfacher ;)
Einfach in den Klassenrumpf von TForm1 (bzw. der hauptform halt)
Delphi-Quellcode:
Darin kann man dann alles machen, was man auch in der Windowproc hätte machen können. Entzerrt einiges.
procedure WMPowerBroadcast(var Msg: TMessage); message WM_POWERBROADCAST;
|
Re: Hibernate und Standby erkennen
Jo, funktioniert perfekt :)
dankö :angel: |
Re: Hibernate und Standby erkennen
Hi!
Den Code würde ich gerne in die Codelib übernehmen, allerdings scheint es ein Problem mit Windows Vista zu geben. Im MSDN findet sich Zitat:
Zitat:
![]() Ein Test unter Vista zeigt auch, dass oben stehender Code wohl nicht mehr funktioniert... Kann das jemand widerlegen oder hat vllt. anderen/funktionierenden Code, der auch unter Vista funktioniert? Ciao, Frederic |
Re: Hibernate und Standby erkennen
tatsächlich wird unter Vista das Abfangen von standby- und sleepmode nicht mehr supportet.
schade... ...oder kann jemand das gegenteil behaupten ? |
Re: Hibernate und Standby erkennen
Wieso hat Windows dieses denn entfernt o.O
ein Programm, welches "ausversehn" ein Runterfahren (Standby/Hypernate) verhindert, kann so doch garnicht mehr darauf reagieren und die Behinderung beseitigen? |
AW: Hibernate und Standby erkennen
Wie sieht es denn z.Z. aus? Läuft der oben vor 3 Jahren genannte Code immernoch weder unter Vista noch Windows 7? Gibt es alternativen?
|
AW: Hibernate und Standby erkennen
Laut MSDN gibt es jetzt
![]()
Delphi-Quellcode:
procedure WMPowerBroadcast(var Msg: TMessage); message WM_POWERBROADCAST;
Delphi-Quellcode:
Allerdings hab ich nichts gefunden um festzustellen, ob das System in den Ruhezustand oder Standby wechselt. APMSUSPEND kommt bei beiden und gibt laut MSDN keine Auskunft darüber.
//Beispiel-Routine
procedure TfrmMain.WMPowerBroadcast(var Msg: TMessage); begin case Msg.wParam of PBT_APMSUSPEND: begin //System wird in einen Energiesparmodus versetzt end; PBT_APMRESUMESUSPEND: begin //System ist wieder aufgewacht end; PBT_APMRESUMEAUTOMATIC: begin //Nach dem Aufwachen wurde eine Benutzeraktivität festgestellt end; end; end; Hat jemand eine Idee wie man das rausfinden kann? |
AW: Hibernate und Standby erkennen
Ist das wichtig, ob Standby oder Ruhezustand? Windows 7 wechselt in der Standardeinstellung "Energie sparen" in den Ruhezustand UND Standbymodus gleichzeitig. Und wacht dann aus dem Standby oder -wenn zwischendrin der Strom weg war- aus dem Ruhezustand wieder auf.
|
AW: Hibernate und Standby erkennen
In dem Fall ist es gewünscht, da ich gerne ein kleines Log meiner Batterie und Rechnernutzung erstellen würde, um das im Nachhinein auswerten zu können (also ein "Batterie-Benchmark"). Ich aktiviere den Ruhezustand/Standby via Startmenü oder Energiespartaste manuell, in dem Fall greift die Automatik von Windows 7 sowieso nicht. Das aber jedes mal dem Programm von Hand mitzuteilen wäre extrem lästig, deswegen dieser Ansatz.
|
AW: Hibernate und Standby erkennen
Wenn das Programm nur für dich ist, könntest du den Ruhezustand oder Standby über das Programm selbst aufrufen.
Vielleicht mit zwei Desktopverknüpfungen, die mittels Parameter dem Programm sagen, den Log zu starten und den Rechner in den gewünschten Modus zu versetzen. Aber andererseits ist es bestimmt möglich, zu erkennen, welcher Modus aktiv war (vielleicht aus der Ereignisanzeige von Windows?). Wie läuft das eigentlich bei dem hybriden Modus. Wenn mein Laptop in diesem ist, wann entscheidet Windows den Standby aufzugeben und in den Ruhezustand zu wechseln? Wenn die Batterie leer ist oder schon vorher, wenn "abzusehen" ist, dass in nächster Zeit ich das Laptop nicht mehr anschalten werde? Oder ist das erst 3 Tage in der Tasche im Standby und hat dann keine Energie mehr? |
AW: Hibernate und Standby erkennen
hi,
ich verwende folgende kleine freie komponente, mit der kann man auch shutdowns verhindern, aber es hat events für wakeupfromhibernate und wakeupfromstandby... Hier gibts das teil: ![]() gruß tom |
AW: Hibernate und Standby erkennen
Hallo,
jetzt habe ich auch das Problem, dass ich Energiesparmodus und Ruhezustand verhindern muss. So funktioniert das leider nicht:
Delphi-Quellcode:
ALle 3 Messages werden gefeuert, aber Msg.Result := BROADCAST_QUERY_DENY bewirkt nichts. Wo ist da der Haken?
procedure TForm1.WMPowerBroadcast(var Msg: TMessage);
var t: TextFile; begin case Msg.wParam of PBT_APMSUSPEND: begin // System wird in einen Energiesparmodus versetzt Msg.Result := BROADCAST_QUERY_DENY; AssignFile(t,'D:\BROADCAST_QUERY_DENY.TXT'); Rewrite(t); WriteLn(t,TimeToStr(Now)+' ==> Msg.wParam.BROADCAST_QUERY_DENY'); CloseFile(t); end; PBT_APMRESUMESUSPEND: begin //System ist wieder aufgewacht ShowMessage('Energiesparmodus: Hurrraaa wir leben wieder'); end; PBT_APMRESUMEAUTOMATIC: begin //Nach dem Aufwachen wurde eine Benutzeraktivität festgestellt ShowMessage('Energiesparmodus: ...und aktiv sind wir auch schon wieder ;-)'); end; end; end; |
AW: Hibernate und Standby erkennen
Ohne es je gemacht zu haben, ich würde sagen so ist es schon zu spät. Da ist die Entscheidung sich schlafen zu legen schon gefallen.
Du musst vorher ![]() |
AW: Hibernate und Standby erkennen
Ab Vista muss man mit
Delphi-Quellcode:
arbeiten
SetThreadExecutionState
![]() |
AW: Hibernate und Standby erkennen
Ab WIN7:
![]() |
AW: Hibernate und Standby erkennen
Zitat:
Vielleicht liege ich auch daneben. |
AW: Hibernate und Standby erkennen
Vielen Dank für die Antworten!
Mann oh Mann ist das wieder eine komplizierte Sache. Ich hoffte schon, das (Programmierer-)Leben könnte ausnahmsweise auch mal freundlich zu einem sein. Vielleicht (sehr wahrscheinlich sogar) habe ich mich auch falsch bzw. unvollständig ausgedrückt, denn so richtig "komplett" verhindern will ich Hibernate und Standby nicht. Es geht um folgendes: Vorhanden ist eine MDI-Anwendung die eine Client-Server-Datenbank verwendet. Was machen die Kunden? Sie haben mehrere MDI's geöffnet, und womöglich noch ein modales Fenster, das von einem MDI-Fenster aus geöffnet wurde. Dann ist Mittagspause, und keiner schert sich darum, wenigstens einen laufenden Editiervorgang zu benden, bevor man den Arbeitsplatz verlässt. Da kann man predigen was man will :cyclops: Wenn sie dann von der Mittagspause zurück kommen und der PC ist im Standby....ist natürlich die Verbindung zum DB-Server abgebrochen. Nun kann ich ja nicht bei jedem Editiervorgang oder Fensterwechsel (MDIChildCount > 0) usw. mit SetThreadExecutionState regieren, das wäre overkill. Wenn bei PBT_APMSUSPEND MDIChildCount 0 ist, dann schließe ich einfach die DB-Verbindung und gut isses, aber was tun wenn MDICHildCount > 0 ist, und noch modale Fenster offen sind? Ich denke, da muss ich jetzt ansetzen, weil mit SetThreadExecutionState komme ich wohl nicht weiter. Es sei denn, jemand hätte eine geniale Idee? |
AW: Hibernate und Standby erkennen
Ja gut aber WAS willst du denn machen? Wenn ein MDI-Child offen ist willst du Standby nicht verhindern, aber du willst auch kein Standby haben. :gruebel: Du musst dich für eins entscheiden.
Oder hoffst du auf eine Datenbankverbindung die den Standby überlebt? Keine Ahnung ob sowas geht, aber darauf würde ich nicht wetten. |
AW: Hibernate und Standby erkennen
Adhoc sehe ich zwei Möglichkeiten:
Auf die Schnelle mal dahingetippt
Delphi-Quellcode:
unit System.PowerManagement;
interface uses System.Generics.Collections; type TPowerModeOption = ( Display, System, Away ); TPowerModeOptions = set of TPowerModeOption; IPowerManagementToken = interface [ '{F6326420-9BE9-4CAE-9EC8-0E6C4EE1B265}' ] function GetOptions( ): TPowerModeOptions; property Options: TPowerModeOptions read GetOptions; end; IPowerManagementService = interface procedure SetOptions( PowerModeOptions: TPowerModeOptions ); end; PowerManagement = class sealed private type TInternalPowerManagementToken = class private FOptions: TPowerModeOptions; public constructor Create( Options: TPowerModeOptions ); destructor Destroy; override; property Options: TPowerModeOptions read FOptions; end; TPowerManagementToken = class( TInterfacedObject, IPowerManagementToken ) private function GetOptions( ): TPowerModeOptions; private FToken: TInternalPowerManagementToken; public constructor Create( Options: TPowerModeOptions ); destructor Destroy; override; end; TNullService = class( TInterfacedObject, IPowerManagementService ) private { IPowerManagementService } procedure SetOptions( PowerModeOptions: TPowerModeOptions ); end; private class var _Service : IPowerManagementService; class var _Tokens : TList<TInternalPowerManagementToken>; class var _CurrentOptions: TPowerModeOptions; class constructor Create( ); class destructor Destroy( ); class procedure TokensNotify( Sender: TObject; const Item: TInternalPowerManagementToken; Action: TCollectionNotification ); public class function GetToken( const PowerModeOptions: TPowerModeOptions ): IPowerManagementToken; end; implementation uses {$IFDEF MSWINDOWS} System.PowerManagement.Win, {$ENDIF} System.SysUtils; { PowerManagement.TPowerManagementToken } constructor PowerManagement.TPowerManagementToken.Create( Options: TPowerModeOptions ); begin inherited Create( ); if Options <> [ ] then FToken := TInternalPowerManagementToken.Create( Options ); end; destructor PowerManagement.TPowerManagementToken.Destroy; begin FToken.DisposeOf( ); inherited; end; function PowerManagement.TPowerManagementToken.GetOptions: TPowerModeOptions; begin if Assigned( FToken ) then Result := FToken.Options else Result := [ ]; end; { PowerManagement } class constructor PowerManagement.Create; begin {$IFDEF MSWINDOWS} _Service := TWindowsPowerManagementService.Create; {$ELSE} _Service := TNullService.Create; {$ENDIF} _Tokens := TList<TInternalPowerManagementToken>.Create( ); _Tokens.OnNotify := TokensNotify; _CurrentOptions := [ ]; end; class destructor PowerManagement.Destroy; begin _Service.SetOptions( [ ] ); _Tokens.Free; end; class function PowerManagement.GetToken( const PowerModeOptions: TPowerModeOptions ): IPowerManagementToken; var lToken: TPowerManagementToken; begin lToken := TPowerManagementToken.Create( PowerModeOptions ); Result := lToken; end; class procedure PowerManagement.TokensNotify( Sender : TObject; const Item: TInternalPowerManagementToken; Action : TCollectionNotification ); var lToken : TInternalPowerManagementToken; lOptions: TPowerModeOptions; begin lOptions := [ ]; for lToken in _Tokens do begin lOptions := lOptions + lToken.FOptions; end; if _CurrentOptions <> lOptions then begin _Service.SetOptions( lOptions ); _CurrentOptions := lOptions; end; end; { PowerManagement.TNullService } procedure PowerManagement.TNullService.SetOptions( PowerModeOptions: TPowerModeOptions ); begin // do nothing end; { PowerManagement.TInternalPowerManagementToken } constructor PowerManagement.TInternalPowerManagementToken.Create( Options: TPowerModeOptions ); begin inherited Create; FOptions := Options; _Tokens.Add( Self ); end; destructor PowerManagement.TInternalPowerManagementToken.Destroy; begin _Tokens.Remove( Self ); inherited; end; end.
Delphi-Quellcode:
unit System.PowerManagement.Win;
interface uses Winapi.Windows, System.SysUtils, System.PowerManagement; type TWindowsPowerManagementService = class( TInterfacedObject, IPowerManagementService ) private { IPowerManagementService } procedure SetOptions( PowerModeOptions: TPowerModeOptions ); end; implementation { TWindowsPowerManagementService } procedure TWindowsPowerManagementService.SetOptions( PowerModeOptions: TPowerModeOptions ); var esFlags: Cardinal; lResult: Cardinal; begin esFlags := 0; if TPowerModeOption.Display in PowerModeOptions then esFlags := esFlags or ES_DISPLAY_REQUIRED; if TPowerModeOption.System in PowerModeOptions then esFlags := esFlags or ES_SYSTEM_REQUIRED; if TPowerModeOption.Away in PowerModeOptions then esFlags := esFlags or ES_AWAYMODE_REQUIRED; if esFlags <> 0 then esFlags := esFlags or ES_CONTINUOUS; lResult := SetThreadExecutionState( esFlags ); if lResult = 0 then raise Exception.Create( 'Could not set ThreadExecutionState' ); end; end.
Delphi-Quellcode:
unit Forms.MainForm;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, System.PowerManagement, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; type TForm1 = class( TForm ) CheckBox1: TCheckBox; CheckBox2: TCheckBox; CheckBox3: TCheckBox; SetModeButton: TButton; ClearModeButton: TButton; procedure ClearModeButtonClick( Sender: TObject ); procedure SetModeButtonClick( Sender: TObject ); private FToken: IPowerManagementToken; public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.ClearModeButtonClick( Sender: TObject ); begin FToken := nil; end; procedure TForm1.SetModeButtonClick( Sender: TObject ); var lOptions: TPowerModeOptions; begin lOptions := [ ]; if CheckBox1.Checked then lOptions := lOptions + [ TPowerModeOption.Display ]; if CheckBox2.Checked then lOptions := lOptions + [ TPowerModeOption.System ]; if CheckBox3.Checked then lOptions := lOptions + [ TPowerModeOption.Away ]; FToken := PowerManagement.GetToken( lOptions ); end; end. |
AW: Hibernate und Standby erkennen
Danke @Sir Rufo für das Beispiel. Um auf Anhieb zu verstehen, wie du das meinst, muss ich erst mal meinen Kenntnisstand etwas vertiefen. Schöne Aufgabe für das Wochenende.
Zitat:
|
AW: Hibernate und Standby erkennen
@mm1256
Eigentlich ganz einfach: In jeder Form-Instanz die jetzt den Ruhezustand doof finden würde, holst du dir einfach ein Token
Delphi-Quellcode:
.
FToken := PowerManagement.GetToken( [ TPowerModeOption.System ] );
Es ist egal ob du dir das Token holst, wenn die Instanz erzeugt wird, oder erst zum Zeitpunkt wenn du einen Ruhezustand-Kritischen Moment erreichst. Wenn es der Form-Instanz dann wieder egal ist, ob das System in den Ruhezustand geht, dann einfach das Token auf
Delphi-Quellcode:
setzen.
nil
Die
Delphi-Quellcode:
-Klasse sorgt nun dafür, dass der Modus ab einem Token eingeschaltet wird und auch wieder ausgeschaltet wird, wenn es kein Token mehr gibt.
PowerManagement
|
AW: Hibernate und Standby erkennen
Vielen Dank Sir Rufo für die Erklärung! :thumb:
Jetzt hätte ich nur noch ein Problem zu lösen: Die Anwendung verwendet insgesamt (grob geschätzt) etwa 150 Formulare, aufgeteilt auf mehrere Module (Exen). Viele von den Formularen sind vererbt. Das reduziert zwar den Aufwand etwas, ist mir aber trotzdem noch etwas zu hoch. Aber, für ein kleineres Projekt in dem ich auch diese Anforderung habe, werde ich es mal ausprobieren! |
AW: Hibernate und Standby erkennen
Du kannst dir diese Funktionalität auch mit einer Unit hineinbringen
Delphi-Quellcode:
und diese Unit einfach nur noch nach der
unit Vcl.BaseForm;
interface uses System.PowerManagement, Vcl.Forms; type TForm = class( Vcl.Forms.TForm ) private FToken: IPowerManagementToken; function GetPowerModeOptions: TPowerModeOptions; procedure SetPowerModeOptions( const Value: TPowerModeOptions ); protected function GetDefaultPowerMode( ): TPowerModeOptions; virtual; property PowerModeOptions: TPowerModeOptions read GetPowerModeOptions write SetPowerModeOptions; public procedure AfterConstruction; override; end; implementation { TForm } procedure TForm.AfterConstruction; begin FToken := PowerManagement.GetToken( GetDefaultPowerMode( ) ); inherited; end; function TForm.GetDefaultPowerMode: TPowerModeOptions; begin Result := [ ]; end; function TForm.GetPowerModeOptions: TPowerModeOptions; begin Result := FToken.Options; end; procedure TForm.SetPowerModeOptions( const Value: TPowerModeOptions ); begin if PowerModeOptions <> Value then FToken := PowerManagement.GetToken( Value ); end; end.
Delphi-Quellcode:
in die uses Liste aufnehmen. Dann brauchst du bei den Forms, die so etwas benötigen entweder nur die
Vcl.Forms
Delphi-Quellcode:
zu überschreiben oder du setzt einfach den Wert der Eigenschaft
GetDefaultPowerMode
Delphi-Quellcode:
.
PowerModeOptions
;) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:41 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