weblogs.asp.net
Ausgeschlafen - Reagieren auf Windows Events beim Systemstart nach Standby/Hibernate
Gerade bastle ich an einer kleinen Anwendung, mit der ich mir im System Tray immer die aktuell günstigsten Call-by-Call-Nummern anzeigen lassen kann. Wenn ich dann einen Anruf machen möchte, muss ich nur die Maus über das Tray Icon bewegen und sehe schon, welche Vorwahl ich wählen muss. Das finde ich einfacher, als eine Seite wie www.telefontarife.de im Browser aufzurufen oder gar ein Tarifvergleichsprogramm zu installieren.
Mein kleines Programm soll einfach im Hintergrund laufen, ein Tray Icon zeigen und periodisch seine Daten durch Zugriff auf ein Informationsangebot im Internet aktualisieren. Das ist auch alles kein Problem - solange ich meinen Laptop nicht schlafen lege. Meist fahre ich den Rechner am Tagesende (oder auch zwischendurch) nicht herunter, sondern schalte ihn nur in den Standby- oder Hibernate-Modus.
Wenn ich ihn aus einem dieser Modi wieder erwecke, läuft meine Anwendung zwar noch, aber das Timer-Control feuert nicht mehr periodisch. Das Programm aktualisiert seine Daten also nicht mehr automatisch.
Da andere Programme aber sehr wohl auf die Erweckung aus einem der Schlummerzustände reagieren (Outlook holt dann z.B. die Email ab), dachte ich mir, dass auch meine Anwendung sich über diese Systemzustandsänderung informieren lassen könnte. Wie könnte sie aber an die Ereignisse, die Windows zu diesem Zweck sicherlich wirft, herankommen? Die Antwort liegt im Windows Platform SDK unter dem Stichwort "Power Management".
Windows meldet Ereignisse des Power Management Systems mit der Windows Nachricht WM_POWERBROADCAST an alle Anwendungen:
define WM_POWERBROADCAST 0x0218
Der wparam der Nachricht enthält dann einen der folgenden Werte:
define PBT_APMQUERYSUSPEND 0x0000
define PBT_APMQUERYSTANDBY 0x0001
define PBT_APMQUERYSUSPENDFAILED 0x0002
define PBT_APMQUERYSTANDBYFAILED 0x0003
define PBT_APMSUSPEND 0x0004
define PBT_APMSTANDBY 0x0005
define PBT_APMRESUMECRITICAL 0x0006
define PBT_APMRESUMESUSPEND 0x0007
define PBT_APMRESUMESTANDBY 0x0008
define PBTF_APMRESUMEFROMFAILURE 0x00000001
define PBT_APMBATTERYLOW 0x0009
define PBT_APMPOWERSTATUSCHANGE 0x000A
define PBT_APMOEMEVENT 0x000B
define PBT_APMRESUMEAUTOMATIC 0x0012
Davon sind für meine Zwecke PBT_APMRESUMESUSPEND und PBT_APMRESUMESTANDBY interessant. Die erhält meine Anwendung, wenn der Rechner aufgeweckt wird.
Um auf die Power-Management-Nachricht zu reagieren, muss ich dann nur die WndProc()-Methode meines Anwendungsfensters überschreiben:
Public Class Form1
Inherits System.Windows.Forms.Form
...
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
Const WM_POWERBROADCAST As Integer = &H218
Const PBT_APMRESUMESUSPEND As Integer = 7
Const PBT_APMRESUMESTANDBY As Integer = 8
If m.Msg = WM_POWERBROADCAST Then
If m.WParam.ToInt32 = PBT_APMRESUMESTANDBY Or m.WParam.ToInt32 = PBT_APMRESUMESUSPEND Then
Timer1.Enabled = False
Timer1.Enabled = True
End If
End If
MyBase.WndProc(m)
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
' aktuelle Tarifdaten laden...
End Sub
End Class
Die WndProc()-Methode schaltet dann nur meinen Timer aus und wieder an und schon läuft alles wieder automatisch - bis zur nächsten Schlafenszeit.