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.

2 Comments

  • Mal abgesehen davon, daß der Code in der WndProc() nicht so ganz funktioniert...



    Warum verwendest Du nicht den Namespace Microsoft.Win32 ?



    Etwa so:



    ...

    // handle/listen to power save modes

    SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(this.OnPowerModeChanged);

    ...



    private void OnPowerModeChanged(object sender, PowerModeChangedEventArgs e) {

    if (e.Mode == PowerModes.Resume) {

    ...

    } else if (e.Mode == PowerModes.Suspend) {

    ...

    }

    }

  • > Mal abgesehen davon, daß der Code in der
    > WndProc() nicht so ganz funktioniert...

    Ging bei mir auch nicht. Bei UserControls habe ich bzgl. Windows-Events schon manchmal probs gehabt.

    Der Tipp von TorstenR war super. Wäre ich so schnell nicht drauf gekommen! ;-x

Comments have been disabled for this content.