Windows Mobile

Türchen Nummer 3

Die Adventszeit liegt ja bekanntermaßen in der dunklen Jahreszeit. Umso angenehmer das man mit einem Windows Phone ein wenig Licht  erzeugen kann, beispielsweise in Form einer Taschenlampenapplikation. Was nützt einem jedoch die beste Taschenlampe wenn nach ein paar Sekunden die Hintergrundbeleuchtung erlischt oder sich der Bildschirm komplett ausschaltet?
Mit einem kleinen Griff in die Windows Mobile Trickkiste kann man dies jedoch verhindern.
Ein kleiner Hinweis vorweg:
Die benötigten APIs sind auf jedem Gerät gleich, lediglich der anzusprechende Treiber kann je nach Hersteller variieren.
Als erstes muss man der Hintergrundbeleuchtung mitteilen das Sie doch bitte nicht mehr ausgehen soll. Dies bewerkstelligen wir über die SetPowerRequirement Funktion.
Anschließend müssen wir uns noch um das Standbyverhalten kümmern, schließlich soll das Gerät ja nicht einschlafen. Dazu müssen wir den sogenannten Idle-Timer zurücksetzen.
Die Funktion dazu nennt sich SystemIdleTimerReset.
Hier nun die Schnipsel dazu:
 
C++
#include "pmpolicy.h"
#include "pm.h"
//Bedingung für die Hintergrundbeleuchtung setzen
    //BKL1 ist exemplarisch und kann je nach OEM variieren
    HANDLE hPower = SetPowerRequirement(L"BKL1:", D0, POWER_NAME | POWER_FORCE, NULL, 0);
    //Zusätzlich muss jetzt noch die IDLE Time umgangen werden
    //Aktuellen Batterie Status holen
    SYSTEM_POWER_STATUS_EX pex;
    memset(&pex,0,sizeof(SYSTEM_POWER_STATUS_EX));
    GetSystemPowerStatusEx(&pex,TRUE);
    //Idle Timeout je nach AC Status abfragen
    //Dies funktioniert nur wenn der Wert "DisableGwesPowerOff"
    //unter "[HKEY_LOCAL_MACHINESystemCurrentControlSetControlPower]" != 0 ist.
    DWORD dwIdleTimeout = 30;
    BOOL bRet = FALSE;
    if(pex.ACLineStatus == AC_LINE_ONLINE)
        bRet = SystemParametersInfo(SPI_GETEXTERNALIDLETIMEOUT,0,&dwIdleTimeout,0);
    else
        bRet = SystemParametersInfo(SPI_GETBATTERYIDLETIMEOUT,0,&dwIdleTimeout,0);
    //Idle Timer verringern oder auf 30 Sekunden setzen
    if(dwIdleTimeout == 0)
        dwIdleTimeout = 30;
    else if(dwIdleTimeout > 5)
        dwIdleTimeout -= 5;
    dwIdleTimeout*=1000;
    //Idle Timer reset (Normalerweise in einem Thread…)
    /*while (1)
    {
        SystemIdleTimerReset();
        Sleep(dwIdleTimeout);
    }*/
    //Bedingung für die Hintergrundbeleuchtung wieder freigeben
    ReleasePowerRequirement(hPower);
——————————————————————————–
Die Funktionalität in C# darzustellen ist nicht ganz so einfach, da jede angesprochene Funktion mittels P/Invoke angesprochen werden muss.
Somit ist der Quellcode in C# ein wenig länger:
C#

public class SYSTEM_POWER_STATUS_EX
{
    public byte ACLineStatus;
    public byte BatteryFlag;
    public byte BatteryLifePercent;
    public byte Reserved1;
    public uint BatteryLifeTime;
    public uint BatteryFullLifeTime;
    public byte Reserved2;
    public byte BackupBatteryFlag;
    public byte BackupBatteryLifePercent;
    public byte Reserved3;
    public uint BackupBatteryLifeTime;
    public uint BackupBatteryFullLifeTime;
}
public enum DevicePowerState : int
{
    Unspecified = -1,
    D0 = 0, // Full On: full power, full functionality
    D1, // Low Power On: fully functional at low power/performance
    D2, // Standby: partially powered with automatic wake
    D3, // Sleep: partially powered with device initiated wake
    D4, // Off: unpowered
}
class Program
{
    [DllImport("coredll")]
    private static extern uint GetSystemPowerStatusEx(SYSTEM_POWER_STATUS_EX lpSystemPowerStatus, bool fUpdate);
    [DllImport("coredll", SetLastError=true)]
    private static extern IntPtr SetPowerRequirement(string DeviceName, DevicePowerState State, uint dwDeviceFlags, string Name, ulong Reserved);
    [DllImport("coredll.dll", SetLastError=true)]
    static extern int ReleasePowerRequirement(IntPtr handle);
    [DllImport("coredll.dll", SetLastError=true)]
    static extern void SystemIdleTimerReset();
    [DllImport("coredll.dll")]
    internal static extern int SystemParametersInfo(
    int uiAction,
    int uiParam,
    ref int pvParam,
    int fWinIni);
    public const int SPI_SETBATTERYIDLETIMEOUT = 251;
    public const int SPI_GETBATTERYIDLETIMEOUT = 252;
    public const int SPI_SETEXTERNALIDLETIMEOUT = 253;
    public const int SPI_GETEXTERNALIDLETIMEOUT = 254;
    static void Main(string[] args)
    {
        IntPtr handle = SetPowerRequirement("BKL1:", DevicePowerState.D0, 1, null, 0);
        int dreisig = 30;
        // reset the system’s idle time every 10 seconds so it doesn’t suspend
        Timer timer = new Timer(IdleReset, null, 0, 10000);
        SYSTEM_POWER_STATUS_EX status = new SYSTEM_POWER_STATUS_EX();
        if (GetSystemPowerStatusEx(status, false) == 1)
        {
            if (status.ACLineStatus == (byte)1) //1 == Plugged in
            {
                SystemParametersInfo(SPI_GETEXTERNALIDLETIMEOUT, 0, ref dreisig, 0);
            }
            else //Plugged out
            {
                SystemParametersInfo(SPI_SETBATTERYIDLETIMEOUT, 0, ref dreisig, 0);
            }
        }
        ReleasePowerRequirement(handle);
       
    }
    private static void IdleReset(object state)
    {
        // no suspend
        SystemIdleTimerReset();
    }
}
 
Patrick & Peter
 
P.S.: Der gewiefte Bastler stellt 4 Geräte in einen Adventskranz und startet die Anwendung, so dass spätestens am 4. Advent auch alle Kerzen… ich meine natürlich Displays (solange die Batterie ausreicht) freudig leuchten.

Schreibe einen Kommentar

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s