Patrick's profilePatricks Live-SpaceBlogLists Tools Help

Patricks Live-Space

...

Patrick

No list items have been added yet.
January 20

Case Study: A Facebook Application for Windows Mobile 6

Sehr sympathische Firma:
"The need for a special list control affirmed the value of our general policy of using native code for our applications."
 
Durchaus lesenswerte Case Study zur Facebook Applikation:
 
- Patrick
January 14

Ein Windows Mobile ABC: C wie Certs.cab Nachtrag

Leider muss ich zu dem "Ein Windows Mobile ABC: C wie Certs.cab" einen Nachtrag einstellen.
Die Zertifikate im SDK sind am 31.12.2009 abgelaufen und können daher nicht mehr verwendet werden.
Auf dem Windows Mobile Developer Blog findet man aber ein neues Downloadpaket für aktuelle Zertifikate (Gültig bis zum 31.12.2015).
Da leider keine neue Certs.cab in dem Download dabei ist muss man die Zertifikate nun selbst auf das Gerät bringen bzw. halt seine eigene Certs.cab erstellen. Dazu gibt es auch eine Anleitung.
 
- Patrick
January 01

2010

Ich wünsche allen Lesern erst einmal ein frohes und erfolgreiches neues Jahr 2010!
 
Für mich persönlich fängt das Jahr schon sehr gut an, denn ich habe folgende frohe Botschaft in meinem Postfach gefunden:
 
Sehr geehrte(r) Patrick Getzmann,
herzlichen Glückwunsch! Wir freuen uns, Ihnen den Microsoft® MVP Award 2010 verleihen zu können! Diese Auszeichnung wird an herausragende, führende Mitglieder der technischen Communities verliehen, die ihre wertvollen praktischen Erfahrungen mit anderen Menschen teilen. Wir schätzen Ihren außerordentlich bedeutenden Beitrag in den technischen Communities zum Thema Device Application Development im vergangenen Jahr hoch ein.

Es ist mir eine große Ehre diese Auszeichnung tragen zu dürfen und hoffe Ihr auch in 2010 gerecht werden zu können.
An dieser Stelle möchte ich allen Personen danken die mich unterstützt und angetrieben haben.

In diesem Sinne auf ein erfolgreiches neues Jahr.

December 24

Türchen Nummer 24

Sollte man die Weihnachtsgeschenke für seine Lieben bereits gekauft haben, so kommt man meist zum eher unangenehmen Teil: Dem Verpacken.
Dies gilt jedoch auch für Anwendungen, die auf einem mobilen Gerät installiert werden sollen. Hierfür gibt es das CAB-Datei Format.
 
Um eine entsprechende Installationsdatei zu erstellen, nehmen wir einmal an, dass wir die zu verpackenden Dateien unter c:\HelloWorld abgelegt haben.
Die Dateien, welche dort vorliegen müssen, sind die HelloWorld.exe, welche installiert werden soll, sowie die HelloWorld.inf Datei, welche die Informationen für den CabWizard vorbehält, um eine CAB-Datei erzeugen zu können.

Hier nun der Inhalt der INF-Datei dazu. Hierbei hat die Programmiersprache diesmal keine Relevanz:
[SOURCE FILE]
Name=CHelloWorld.cab
Path=C:\HelloWorld\HelloWorld.cab
AllowUninstall=TRUE
[Version]
Signature="$Chicago$"
CESignature="$Windows CE$"
Provider="Company"
[CEStrings]
AppName="HelloWorld"
InstallDir="%CE1%\CHelloWorld"
[CEDevice]
ProcessorType=0
VersionMin=0.0
VersionMax=0.0
BuildMin=0
BuildMax=0
[SourceDisksNames]
1=,Source1,,
[SourceDisksFiles]
"HelloWorld.exe"=1
[CopyFiles1]
"HelloWorld.exe",,,0x00000001
[DestinationDirs]
CopyFiles1=0,"%CE1%\HelloWorld"
[DefaultInstall]
CopyFiles=CopyFiles1
 
 
Wird nun auf der Kommandozeile der Befehl "c:\Program Files\Microsoft Visual Studio 9.0\SmartDevices\SDK\SDKTools\cabwiz.exe" "Company HelloWorld2.inf" ausgeführt (Pfad ist natürlich hinsichtlich seinen Gegebenheiten anzupassen), so findet sich im entsprechenden Zielordner die CAB-Installationsdatei wieder.
Weitere Informationen zum CAB-Wizard erhalten Sie hier: http://msdn.microsoft.com/de-de/library/cc433670%28VS.71%29.aspx

Patrick & Peter
December 23

Türchen Nummer 23

So kurz vor weihnachten sollte der Weihnachtsbaum hell leuchten. Warum auch nicht dann die LED des Bluetoothmoduls des Gerätes zum Blinken bringen?
Nichts einfacher als das, in dem man das Bluetooth Modul aktiviert.

Dabei gilt zu beachten, dass dieses Beispiel nur auf Geräten funktioniert, die den Microsoft Bluetooth Stack verwenden.

C++

#include "bthutil.h"
#pragma comment(lib, "Bthutil.lib")

...

DWORD dwMode = 0;
BthGetMode(&dwMode);
if(dwMode==BTH_POWER_OFF || dwMode==BTH_CONNECTABLE)
{
    BthSetMode(BTH_DISCOVERABLE);
}



C#

In C# ist es auch an dieser Stelle nötig, mittels P/Invoke auf die nötige DLL zu zu greifen, um auf die entsprechenden Informationen zu erhalten.
Somit hier das Snippet:

...
public enum RadioMode
{
    Off = 0,
    Connectable = 1,
    Discoverable = 2
}

static class Program
{
    [DllImport("BthUtil.dll")]
    private static extern int BthGetMode(out RadioMode dwMode);

    [DllImport("BthUtil.dll")]
    private static extern int BthSetMode(RadioMode dwMode);

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [MTAThread]
    static void Main()
    {
        RadioMode rm = RadioMode.Off;
        BthGetMode(out rm);
        if (rm == RadioMode.Off || rm== RadioMode.Connectable)
        {
            BthSetMode(RadioMode.Discoverable);   
        }
    }
}
...


Patrick & Peter
December 22

Türchen Nummer 22

In vielen Fenstern und Wohnungen findet man zur Weihnachtszeit eine ganze Menge an Lichterketten und sonstiger beleuchteter Weihnachtsdekoration.
Das manuelle Einschalten dieser vielen Lichterketten und Lämpchen kann eine zeitraubende Beschäftigung werden.
Gleiches gilt auch für Windows Mobile Applikationen die durchgehend laufen sollen. Wenn der Anwender diese Applikationen manuell starten muss dauert dies natürlich auch eine Weile.
Wäre es nicht angenehmer wenn dies automatisch geschehen würde?
Mit folgendem Codeschnipsel kann aus der eigenen Anwendung heraus, beispielsweise per Optionsdialog, eine Autostartverknüpfung angelegt werden.

C++

//Dies ist eigentlich das gleiche Schnipsel wie Türchen Nummer 8
//jedoch wird diesmal die CSIDL_STARTUP verwendet.
//Autostart Ordner auslesen
WCHAR szShortcutPath[MAX_PATH*2] = L"\0";
SHGetSpecialFolderPath(NULL,szShortcutPath,CSIDL_STARTUP,0);
wcscat(szShortcutPath,L"\\MeinShortcut.lnk");
//Modulnamen auslesen
WCHAR szModulePath[MAX_PATH*2] = L"\0";
GetModuleFileName(GetModuleHandle(NULL), szModulePath, MAX_PATH);
//Shortcut erstellen
SHCreateShortcut(szShortcutPath,szModulePath);



In C# ist es diesmal nicht notwendig P/Invoke zu nutzen, um an diese Informationen zu kommen. Die Klasse Environment hierfür reicht völlig.
Hier also das Snippet:

C#

...
[DllImport("coredll.dll")]
private static extern int SHCreateShortcut(StringBuilder szShortcut, StringBuilder szTarget);
...
[MTAThread]
static void Main()
{

   StringBuilder shortcut = new StringBuilder(System.Environment.GetFolderPath(Environment.SpecialFolder.Startup)+@"\MeinShortcut.lnk");
   StringBuilder target = new StringBuilder(@"\windows\calc.exe");
   SHCreateShortcut(shortcut, target);
}
...


Patrick & Peter
December 21

Türchen Nummer 21

Der große Vorteil eines digitalen Adventskalenders ist, dass man volle Kontrolle über alle Türchen
hat und niemand vorab schon mal die "24" öffnen kann.
Eine vollständige Kontrolle bspw. über sämtliche Tasten kann auch mal in einer Windows Mobile Applikation benötigt werden.
Das folgende Codeschnipsel zeigt wie man dies mit der AllKeys API bewerkstelligen kann.

C++

//Alle Tasten abfangen(bspw. in WM_CREATE)
AllKeys(TRUE);

...

//In WM_KEYDOWN und WM_KEYUP den WPARAM prüfen.
//Siehe http://msdn.microsoft.com/en-us/library/bb431750.aspx für Keycodes
case WM_KEYDOWN:
    OutputDebugString(L"WM_KEYDOWN\n");
    //Behandlung für den Tastencode ist hier nicht aufgeführt
    HandleKey(wParam);
    break;
case WM_KEYUP:
    OutputDebugString(L"WM_KEYUP\n");
    //Behandlung für den Tastencode ist hier nicht aufgeführt
    HandleKey(wParam);
    break;

...




Im verwaltetem Code ist es mehr Code nötig, um das gleiche Ziel zu erreichen. Das liegt daran, dass eine Windows Form generell die Verarbeitung von derlei Nachrichten intern bereits durchführt.
Um also auf die internen Window Messages zugreifen zu können, ist es nötig, eine Klasse zu erstellen, die von der Klasse MessageWindow ableitet. Zusätzlich ist auch das P/Invoke notwendig, um die AllKeys-Methode auf zu rufen.
Somit ist es diesmal für das Snippet nötig, eine Anwendung für intelligene Geräte anzulegen, welche eine Geräteanwendung darstellt.
Der Code is dann entsprechend ähnlich abzuändern:

C#

...
using Microsoft.WindowsCE.Forms;
...

public partial class MessageForm : Form
{
    [DllImport("coredll.dll", SetLastError = true)]
    static extern bool AllKeys(bool bAllKeys);
    
    MsgWindow msgWin;

    public MessageForm()
    {
        InitializeComponent();
        AllKeys(true);
        msgWin = new MsgWindow(this);
    }

...

}
...
public class MsgWindow : MessageWindow
{
    public const int WM_KEYDOWN = 0x0100;
    public const int WM_KEYUP = 0x0101;


    private MessageForm msgform;

    public MsgWindow(MessageForm msgform)
    {
        this.msgform = msgform;
    }

    protected override void WndProc(ref Message msg)
    {
        switch (msg.Msg)
        {
            case WM_KEYDOWN:
                MessageBox.Show("Key was down with WPARAM:" + ((int)msg.WParam).ToString() + "and LPARAM:" + ((int)msg.LParam).ToString());
                break;
            case WM_KEYUP:
                MessageBox.Show("Key was up with WPARAM:" + ((int)msg.WParam).ToString() + "and LPARAM:" + ((int)msg.LParam).ToString());
                break;
        }
        base.WndProc(ref msg);
    }
}


Mehr Informationen zur Klasse MessageWindow erhalten Sie hier:

http://msdn.microsoft.com/de-de/library/microsoft.windowsce.forms.messagewindow%28VS.80%29.aspx



Patrick & Peter
December 20

Türchen Nummer 20

Gerade in der Weihnachtszeit sind die Schaufenster derart mit Werbung oder Kunstschnee zugekleistert, das der Blick auf die schönen Dinge dahinter verwehrt ist.
Auch dies gilt für manche Windows Mobile Anwendung, die man im Vollbildmodus betreiben möchte.

C++

//Der folgende Code gilt für Win32 Anwendungen.
//Er ist im IDM_HELP_ABOUT Handler der WM_COMMAND Nachricht
//einer per Visual Studio 2008 Win32 Projekt für intelligente Geräte (Windowsanwendung)
//untergebracht. Der DialogBox Aufruf ist auskommentiert.
//Rückgängig gemacht werden sollte der Fullscrenn Code bspw. über ein Kontextmenu oder beim
//beenden der Applikation
//DialogBox(g_hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, About);
//Fenster muss für SHFullScreen im Vordergrund sein
SetForegroundWindow(hWnd);
//SIP und Taskbar in den Hintergrund legen
SHFullScreen(hWnd,SHFS_HIDESIPBUTTON|SHFS_HIDETASKBAR);
//Die Menübar soll auch weg
HWND hwndMenu = SHFindMenuBar(hWnd);
//Erst die Menübarhöhe holen. Gilt auch für das Starmenü
RECT rcMenue;
GetWindowRect(hwndMenu, &rcMenue);
//Menübar verschieben
SetWindowPos(hwndMenu, NULL,-1, -1,0, 0,SWP_NOZORDER | SWP_NOACTIVATE);
//Jetzt muss unser Fenster noch neu positioniert werden
RECT rect;
GetWindowRect(hWnd,&rect);
rect.top -= rcMenue.bottom - rcMenue.top;
rect.bottom += rcMenue.bottom - rcMenue.top;
MoveWindow(hWnd,rect.left,rect.top,rect.right,rect.bottom,TRUE);




C#

Eine Anwendung zu erstellen, welche eine Vollbilddarstellung liefert ist mit Bordmitteln des .NET Compact
Frameworks bereits einfach realisierbar.
Dies geht sogar so einfach, dass nicht einmal ein Snippet hierfür notwendig ist.
Setzen Sie für die Vollbilddarstellung Ihrer Form einfach die zugehörige Eigenschaft WindowsState auf den
Wert FormWindowState.Maximized. Hierdurch »verschwindet« die Titelzeile Ihrer Anwendung.
Damit sich jedoch kein vielleicht im Hintergrund startendes Programm in den Vordergrund setzt und Ihre
Anwendung überlagert, sollten Sie gleichfalls die Eigenschaft TopMost der Form auf den Wert true setzten.
Wollen Sie gleichfalls die Menüzeile, welche Ihr Anwendungsmenü darstellt und meist auch die virtuelle
Tastatur aktiviert, deaktivieren, ist auch dies ganz einfach. Leider gibt es für das MainMenu keine Eigenschaft
»Enabled«, um dies zu ermöglichen. Stattdessen reicht es, wenn die Eigenschaft Menu der zugehörigen Form auf
den Wert null gesetzt wird, was auch dynamisch aus der Anwendung möglich ist.
Hierdurch wird die Zuweisung eines MainMenu zur Form entfernt, wodurch Sie eine komplette
Vollbilddarstellung Ihrer Anwendung erhalten. Wenn Sie nun Menu wieder das Objekt vom Typ MainMenu
zuweisen, haben Sie wieder Ihren Ursprungszustand hergestellt.

Patrick & Peter
December 19

Türchen Nummer 19

Wer dem Weihnachtstress ein wenig aus dem Weg gehen möchte vermeidet es am besten die Geschenke auf althergebrachte Weise in der Stadt oder sonstigen Einkaufläden zu besorgen.
Nichts ist entspannter als ein Einkaufbummel im Internet. Und wenn man die Einkauftour rechtzeitig beginn bekommt auch keinen Stress mit den Lieferzeiten.
Um aber trotzdem an sein Paket zu kommen muss man natürlich seine eigene Adresse mitteilen.
Gleiches gilt auch für Anwendung die auf Netzwerkdienste zugreifen. Oftmals muss die Anwendung die eigene IP Adresse nicht kennen, da es durch die zugrunde liegenden Protokolle automatisch passiert. Ab und an kann es aber vorkommen dass diese Information benötigt wird.
Dazu kann das folgende Codeschnipsel verwendet werden:

C++

#include "iphlpapi.h"
#pragma comment(lib, "Iphlpapi.lib")

...

//Wir listen mal etwas mehr auf als nur die aktuellen IPs.
//Adapter Information anlegen
PIP_ADAPTER_INFO pAdapterInfo;
ULONG lRetLen = sizeof(PIP_ADAPTER_INFO);
//Benötigte Speichergrösse holen
DWORD dwRet = GetAdaptersInfo(NULL,&lRetLen);
//Informationen zu allen Adaptern holen
pAdapterInfo = (PIP_ADAPTER_INFO) malloc (lRetLen);
dwRet = GetAdaptersInfo(pAdapterInfo,&lRetLen);
if(dwRet == ERROR_SUCCESS)
{
    //Informationen nur für den aktuellen Adapter
    PIP_ADAPTER_INFO pCurrentAdapter = pAdapterInfo;
    while (pCurrentAdapter != NULL )
    {
        //Systemindex
        printf("Adapterindex: %i\n",pCurrentAdapter->Index);
        //Beschreibung
        printf("Beschreibung: %s\n",pCurrentAdapter->Description);
        //IP Addresse
        printf("IP: %s\n",pCurrentAdapter->IpAddressList.IpAddress.String);
        //Gateway
        printf("Gateway: %s\n",pCurrentAdapter->GatewayList.IpAddress.String);
        //Subnet
        printf("Subnet: %s\n",pCurrentAdapter->IpAddressList.IpMask.String);
        //Erweiterte IP Infos anlegen
        PIP_PER_ADAPTER_INFO pPerAdapterInfo;
        lRetLen = sizeof(PIP_PER_ADAPTER_INFO);
        //Benötigte Speichergrösse holen
        dwRet = GetPerAdapterInfo(pCurrentAdapter->Index,NULL,&lRetLen);
        //Erweiterte IP Infos abfragen    
        pPerAdapterInfo = (PIP_PER_ADAPTER_INFO) malloc (lRetLen);
        dwRet = GetPerAdapterInfo(pCurrentAdapter->Index,pPerAdapterInfo,&lRetLen);
        //DNS1
        printf("DNS: %s\n",pPerAdapterInfo->DnsServerList.IpAddress.String);
        //DNS2
        if(pPerAdapterInfo->DnsServerList.Next != NULL)
            printf("DNS2: %s\n",pPerAdapterInfo->DnsServerList.Next->IpAddress.String);
        //Interface anlegen
        MIB_IFROW IfRow;
        memset( &IfRow, NULL, sizeof( MIB_IFROW ) );
        //Index zum abfragen setzen
        IfRow.dwIndex = pCurrentAdapter->Index;
        //Interface abfragen
        GetIfEntry(&IfRow);
        //MAC Adresse
        printf("MAC: %02x-%02x-%02x-%02x-%02x-%02x\n",IfRow.bPhysAddr[0], IfRow.bPhysAddr[1], IfRow.bPhysAddr[2], IfRow.bPhysAddr[3], IfRow.bPhysAddr[4], IfRow.bPhysAddr[5]);
        //Den Namen(ClassID) brauchen wir auch...
        printf("ClassID: %s\n",pCurrentAdapter->AdapterName);
        //Nächster Adapter
        pCurrentAdapter = pCurrentAdapter->Next;
    }
}




C#

In C# geht dies ebenfalls ganz einfach, auch wenn es wild aussieht:

using System.Net;
...
IPHostEntry enty = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress ipadress in enty.AddressList)
{
    Console.WriteLine("IP: " + ipadress.ToString());   
}



Patrick & Peter
December 18

Türchen Nummer 18

 Freitag, 18. Dezember 2009
Nach einem längeren Abend am Glühweinstand kann es in seltenen Fällen dazu kommen, dass man seinen eigenen Namen am nächsten Morgen vergessen hat.
Gut, wenn dieser im mobilen Gerät gespeichert ist.
Das folgende Beispiel funktioniert natürlich nur dann, wenn der Benutzername in den Besitzerinformationen hinterlegt wurde.

C++

//State & Notification Broker Header Datei
#include "snapi.h"
//Registry Hilfsfunktionen
#include "regext.h"

...

//Per Registry Helfer Funktion und den State&Notification Broker Konstanten
//die Besitzerinformationen auslesen. Setzt natürlich voraus das der Anwender diese Informationen auch eingegeben hat.
TCHAR szUserName[MAX_PATH] = L"\0";
if(RegistryGetString(SN_OWNERNAME_ROOT,SN_OWNERNAME_PATH,SN_OWNERNAME_VALUE,szUserName,MAX_PATH)==S_OK)
    _tprintf(L"Username: %s\n",szUserName);
else
    _tprintf(L"Fehler bei RegistryGetString\n");




C#

Mittels SnAPI ist das Auslesen mittels managed Code ganz einfach, wenn zuvor die Verweise zu den Bibliotheken Microsoft.WindowsMobile und Microsoft.WindowsMobile.Status hinzugefügt wurden.

Somit besteht das Snippet dann wieder aus einer Zeile ausführbarem Code:

using Microsoft.WindowsMobile.Status;
...
Console.WriteLine((string)SystemState.GetValue(SystemProperty.OwnerName));


Patrick & Peter
December 17

Türchen Nummer 17

Bei einem leckerem warmen Kakao trifft man manchmal Freunde, die man lange nicht mehr gesehen, oder jedoch aus den Augen verloren hat.
Also schnell die Telefonnummern ausgetauscht, bevor man sich wieder verliert.
Wenn man aber seine eigene Nummer nicht auswendig kennt und sich auch nicht selbst als Kontakt aufgeführt hat (Wobei dies zum Versenden seiner eigenen Kontaktdaten sehr praktisch ist) muss man
sich mühsam über die Menüdialoge der Telefonapplikation zur eigenen Rufnummer vorarbeiten.
Wäre es also nicht schön wenn man die Rufnummer aus dem eigenen Code heraus anzeigen lassen könnte? Hier das passende Codeschnipsel dazu:

Es gilt jedoch zu beachten, dass die vorgestellte Funktionalität möglicherweise nicht bei allen funktioniert, da dies ggfs. sogar providerabhängig ist.

C++

//Da dies ein Snippet ist inkludiere ich hier einfach die komplette CPP Datei des SDK Samples
#include "C:\Programme\Windows Mobile 6 SDK\Samples\Common\CPP\Win32\GetPhoneNumber\GetPhoneNumber.cpp"

...

//Der Aufruf setzt vorraus das die Telefonnummer in die SIM einprogrammiert
//ist. Wird ggf. nicht von jeder SIM bzw. Provider unterstützt.
//Durch verwendung von AT Kommandos ist diese Nummer auch
//editierbar.
SHGetPhoneNumber(szNumber, MAX_LOADSTRING, 1);
_tprintf(L"Nummer: %s\n",szNumber);




C#

In .NET ist auch diese Aufgabe wieder einmal nicht ganz trivial zu lösen.
Um Ihnen jedoch Menge Tipparbeit zu ersparen, laden Sie sich bitte die MSDN Bibliothek zur Phonefunktionalität unter http://www.microsoft.com/downloads/details.aspx?FamilyId=40CF068B-66CA-4F26-87A1-15B67F2F7AE6&displaylang=en herunter, fügen die dort enthaltene Klasse Phone.cs ihrem Projekt hinzu.
Da der hinzugefügte Code jedoch direkte Speicheroperationen durchführt, ist es notwendig in ihren Projekteigenschaften die Option "Unsicheren Code zulassen" zu aktivieren.

Der zu erstellende Code reduziert sich somit auf eine Zeile auführbaren Code.

...
using Microsoft.Wireless;
...
Console.WriteLine(Sim.GetPhoneNumber().Address);
...


Patrick & Peter
December 16

Türchen Nummer 16

Gerade in der Weihnachtszeit kommt man in der Stadt kaum voran, ohne auf irgendwelchen dynamischen Plakatwänden auf die aktuellsten Angebote aufmerksam gemacht zu werden.
Anstatt jedoch Werbung darzustellen, ist es unter Windows Mobile manchmal durchaus sinnvoll, den Benutzer mithilfe einer Notification auf eine bestimmte Gegebenheit hinzuweisen.

C++

// {070A46B7-1C4F-441e-AAE2-5BD96D03477A}
static const GUID CLSID_MyBubble =  { 0x70a46b7, 0x1c4f, 0x441e, { 0xaa, 0xe2, 0x5b, 0xd9, 0x6d, 0x3, 0x47, 0x7a } };

...


//SHNOTIFICATIONDATA Struktur anlegen
SHNOTIFICATIONDATA bubble = {0};
bubble.cbStruct = sizeof(bubble);
bubble.dwID = 1;
//Anzeigen bis der Benutzer es ausblendet
bubble.npPriority = SHNP_INFORM;
bubble.csDuration = -1;
bubble.hicon = NULL;
//Eine eigene GUID angeben
bubble.clsid = CLSID_MyBubble;
bubble.grfFlags = 0;
//Inhalt festlegen
bubble.pszTitle = L"Türchen Nummer 16";
bubble.pszHTML = L"<html><body>Das ist Türchen Nummer <b> 16</b><br><br> in unserem Adventskalender.</body></html>";
//Softkey festlegen
bubble.rgskn[0].pszTitle = L"Ausblenden";
bubble.rgskn[0].skc.wpCmd = 1;
SHNotificationAdd(&bubble);

...

//Wir blenden es jetzt selber aus
SHNotificationRemove(&CLSID_MyBubble,1);



C#

In .NET gibt es in der Microsoft.WindowsCE.Forms Bibliothek eine Notification-Klasse, die einen Wrapper für verwalteten Code darstellt, jedoch funktioniert diese ein wenig anders.
Anstatt nun den Softkey einstellen zu können, verwendet dieses Beispiel den speziellen Namen des HTML-Inputbuttons "cmd:1", welcher die Notification schließt.
Ausgelöst wird die Notifikation durch eine Schaltfläche.

Hier nun das Snippet:


...
Notification nf = new Notification();
...

private void btnNotify_Click(object sender, EventArgs e)
{
    nf.InitialDuration = 0;
    nf.Critical = false;
    nf.Caption = "Türchen Nummer 16";
    nf.Text = "<html><body>Das ist Türchen Nummer <b> 16</b><br><br> in unserem Adventskalender.<br><input type=button name='cmd:1' value='Schliessen'></body></html>";
    nf.Visible = true;
...
    //Wir blenden es nun selbst aus
    nf.Visible = false;
}




Patrick & Peter
December 15

Türchen Nummer 15

Je nachdem wie groß der Familien und Freundeskreis muss man sich gerade während der Vorweihnachtszeit eine ganze Menge an Geschenkideen, Weihnachtsmarktbesuchen, Weihnachtsfeiern und sonstigen
Termin notieren. Wohl dem der ein Windows Phone sein eigen nennt und jederzeit Zugriff auf seine Termine, Notizen und Kontaktdaten hat.
Nichts ist jedoch ärgerlicher als das man bei der Eingabe von Text noch manuell die Tastatur anzeigen lassen muss nachdem man in ein Textfeld geklickt hat.
Wie man ein solches Verhalten in seiner eigenen Applikation verhindern kann zeigen die folgenden Codeschnipsel:

C++

//Keyboard anzeigen (bspw. wenn wir den Focus bekommen)
SHSipPreference(hwndEdit,SIP_UP);
...
//Keyboard ausblenden(bspw. wenn wir den Focus verlieren)
SHSipPreference(hwndEdit,SIP_DOWN);



C#

Damit wir den Status des Softkeyboards, bzw. die SIP sauber setzen können, gilt es dieses Mal eine mobile Windows Forms Anwendung zu erstellen.
Zusätzlich ist es notwendig einen Verweis auf die Bibliothek "Microsoft.WindowsCE.Forms" hinzuzufügen.
Wurden 2 Schaltflächen ebenfalls hinzufgefügt, so sieht der zu erstellende Code, wie folgt aus:

using Microsoft.WindowsCE.Forms;
...
InputPanel panel = new InputPanel();

private void btnSHowSIP_Click(object sender, EventArgs e)
{
    panel.Enabled = true;
}

private void btnHideSIP_Click(object sender, EventArgs e)
{
    panel.Enabled = false;
}

...


Patrick & Peter
December 14

Türchen Nummer 14

Gerade in dieser kalten Jahreszeit kann es passieren, dass man draußen in der Kälte ohne Handschuhe nichts mehr fühlt, da die Finger taub werden.
Auch unter Windows Mobile möchte man manchmal die Eingaben über das Touchscreen, solange es sich um ein Professional oder Classic Gerät handelt, verhindern und das Touchscreen quasi "taub" stellen.
Dabei gilt bei diesem Snippet zu beachten, dass das vorgestellte Beispiel OEM spezifisch ist, so dass es u.U. nicht auf jedem Gerät funktioniert.

C++

//Funktionsdeklaration
typedef VOID (*TOUCHPANELDISABLE)();

...

//Touch.DLL(Treiber) ist OEM spezifisch!
//Touch.DLL laden
HINSTANCE hTouch=LoadLibrary(L"touch.dll");
//Funktionszeiger auf die TouchPanelDisable Funktion holen
TOUCHPANELDISABLE pTouchPanelDisable=(TOUCHPANELDISABLE)GetProcAddress(hTouch, _T("TouchPanelDisable"));
//Touchpanel deaktivieren
pTouchPanelDisable();
//Touch.DLL entladen
FreeLibrary(hTouch);
//Ein wenig warten
Sleep(30000);
//Warmstart durchführen.
//TouchPanelEnable ist nicht aufrufbar da von GWES die Callback benötigt werden würde.
ExitWindowsEx(EWX_REBOOT,0);



C#

Aufsetzend auf unser vorheriges Türchen würde das Beispiel in verwaltetem Code, wie folgt, aussehen:

[DllImport("touch")]
private static extern void TouchPanelDisable();


static void Main(string[] args)
{
    TouchPanelDisable();
    Thread.Sleep(30000);
    ExitWindowsEx(EWX_REBOOT, 0);

}



Patrick & Peter
December 13

Türchen Nummer 13

Gerade in der Weihnachtszeit ist es möglich, dass die Kälte einen eben angesprungenen Wagen wieder ausgehen lässt, wodurch dieser neu gestartet werden muss.
Auch Windows Mobile Geräte sind vor einem Warmstart manchmal nicht gefeit.

C++

ExitWindowsEx(EWX_REBOOT,0);



C#

Auch im .NET Compact Framework gibt es eigentlich kaum mehr zu schreiben, als die zugehörigen P/Invoke Signaturen.
Somit hier das Snippet:

[DllImport("aygshell.dll")]
private static extern bool ExitWindowsEx(uint uFlags, int dwReserved);

const uint EWX_REBOOT = 0x00000002;
const uint EWX_POWEROFF = 0x00000008;


static void Main(string[] args)
{

    ExitWindowsEx(EWX_REBOOT, 0);

}



Patrick & Peter
December 12

Türchen Nummer 12

Türchen Nummer 12
So, die erste Hälfte der Türchen ist jetzt offen.
Wer jetzt noch nicht in Weihnachtsstimmung ist kann wohl nur noch durch intensive Beschallung dazu versetzt werden.
Nichts leichter als das.
Mit dem folgenden Codeschnipsel kann man sich auch unter Windows Mobile von Weihnachtsmusik berieseln lassen:
 
C++
//WAV Datei in Endlosschleife und asynchron vom API Aufruf abspielen
sndPlaySound(L"\\Windows\\JingleBells.wav",SND_FILENAME|SND_LOOP|SND_ASYNC);
...
//OK, genug! WAV stoppen.
sndPlaySound(NULL,SND_FILENAME);
 
------------------------------------
 
C#
 
Damit die Schnippsel gleich bleiben, wird hier eine Lösung mittels P/Invoke angeboten, welche auch für das .NET CF 2.0 gilt. Das .NET CF 3.5 allerdings birng eine neue Klasse Soundplayer-Klasse (System.Media.SoundPlayer http://msdn.microsoft.com/en-us/library/system.media.soundplayer.aspx) mit, welche alternativ verwendbar wäre.
Nun aber zum Snippet.
[DllImport("coredll.dll")]
public static extern int PlaySound(
    string szSound,
    IntPtr hModule,
    int flags);
static void Main(string[] args)
{
   PlaySound("\\Windows\\JingleBells.wav", IntPtr.Zero,(int) (PlaySoundFlags.SND_FILENAME | PlaySoundFlags.SND_LOOP | PlaySoundFlags.SND_ASYNC));
   ...
   //Das reicht
   PlaySound(null, IntPtr.Zero, (int)(PlaySoundFlags.SND_FILENAME));
}
 
Patrick & Peter
December 11

Türchen Nummer 11

Haben Sie dieses Jahr keine Lust auf den alten Vorwurf man würde immer das gleiche verschenken?
Soll es diese Jahr ein einzigartiges Geschenk werden?

Tja, da können wir leider auch nicht weiterhelfen. Wohl aber wenn es um eine einzigartige ID geht,
die in einem Windows Mobile Programm verwendet werden soll. Und zwar eine sogenannte GUID (Globally Unique Identifier).
Oftmals finden diese GUIDs während der Entwicklungszeit Verwendung, aber ab und an können diese auch mal zur Laufzeit benötigt werden.

Mit folgendem Codeschnipsel kann eine solche GUID erstellt werden:

C++

#include "objbase.h"
#pragma comment(lib, "ole32.lib")

...

//GUID erstellen
GUID myGUID;
HRESULT hr = CoCreateGuid(&myGUID);
//GUID in String umwandeln
WCHAR szGUID[MAX_PATH] = L"\0";
StringFromGUID2(myGUID,szGUID,MAX_PATH);
wprintf(L"Neue GUID: %s\n",szGUID);




C#

In C# eine Guid zu erzeugen ist glücklicherweise auch nicht so schwer.
Hier das Snippet:

static void Main(string[] args)
{
    Guid guid = Guid.NewGuid();
    Console.WriteLine(guid.ToString());

}



Patrick & Peter
December 10

Türchen Nummer 10

Eine oft ausgeübte Weihnachtstradition ist das Wichteln. Wem ein einfaches "Zettel aus dem Hut" ziehen zu langweilig ist kann
ja auch ein kleines Programm schreiben um die Wichtel automatisch und zufällig auszuwählen.
Doch oftmals ist das "zufällig" eher wenig vom Zufall bestimmt.
Wie man jedoch richtige Zufallszahlen erzeugen kann zeigt das folgende Codeschnipsel:

C++
#include <wincrypt.h>
...
//Erzeuge 100 Zufallszahlen
for(int i=0;i<100;i++)
{
 DWORD dwRandomSeed = 0;
 HCRYPTPROV hCrypt; 
 if (CryptAcquireContext(&hCrypt, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
 {
  if (CryptGenRandom(hCrypt, 2, (BYTE*)&dwRandomSeed))
  {
   //Zufallszahlen nur zwischen 0 & 1000
   wprintf(L"RandomNumber %d\n",dwRandomSeed%1000);
  }
  CryptReleaseContext(hCrypt, 0);
 }
}
------------------------------------
C#
Im .NET CF kann man sich diesmal glücklich schätzen, einmal ohne P/Invoke auszukommen, da der Security-Namespace einen entsprechende Klasse bereits bereitstellt.
Hier das zugehörige Snippet:
using System.Security.Cryptography;
...
static void Main(string[] args)
{
    RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
    for (int i = 0; i < 100; i++)
    {
        byte[] randomBytes = new byte[4];
        // Generiere 4 zufällige Bytes.
        rng.GetBytes(randomBytes);
        // Konvertiere 4 bytes in ein Integer (32 bit).
        int seed = (randomBytes[0] & 0x7f) << 24 |
                    randomBytes[1] << 16 |
                    randomBytes[2] << 8 |
                    randomBytes[3];
        // Nur Zahlen zwischen unter 1000;
        seed = seed % 1000;
        Console.WriteLine(seed.ToString());
    }
}

Patrick & Peter
December 09

Türchen Nummer 9

Nicht nur Weihnachtsgeschenke sollten einzigartig sein, sondern auch Geräte um diese beispielsweise für Kopierschutzfunktionen unterscheiden zu können.
Daher hat jedes Windows Mobile Gerät eine eindeutige und einmalige ID.
Diese über die KernelIOControl Funktion abzufragen ist allerdings nur für privilegiert signierte Applikationen zulässig.
Als Ausgleich dafür gibt es jedoch die GetDeviceUniqueID Funktion.
Allerdings liefert diese nicht dieselbe ID zurück wie der KernelIoControl Aufruf, sondern anhand von der Applikation übergeben Zusatzdaten einen eindeutigen Hash der ID.
Ruft man mit seiner Anwendung also die GetDeviceUniqueID Funktion immer mit den gleichen Parametern auf erhält man auch immer den gleichen einzigartigen Hash auf dem Gerät, selbst wenn es resettet oder sogar geflasht wird.
Hier nun der Codeschnipsel dazu:
C++
#include "getdeviceuniqueid.h"
//GetDeviceUniqueID gibt nicht die eigentlich ID zurück sondern eine
//eigene ID die aus der Device ID sowie von der Anwendung zusätzlich
//übergebenen Daten besteht. Solange die Zusatzdaten gleich sind erhält
//Die Anwendung auch immer die selbe ID zurück, selbst nach einem Firmwareupdate
#define APPDATA "MEINAPPDATAUID"
#define APPDATALEN 14
//Device ID Variable anlegen
BYTE bDeviceID[GETDEVICEUNIQUEID_V1_OUTPUT];
DWORD cbSize = sizeof(bDeviceID);
//DeviceID Hash abfragen
HRESULT hr = GetDeviceUniqueID(reinterpret_cast<PBYTE>(APPDATA), APPDATALEN, GETDEVICEUNIQUEID_V1, bDeviceID, &cbSize);
---------------------------------------------------
 
C#
Eigentlich könnte man sich bereits denken, dass man an dieser Stelle auch P/Invoke benötigen wird, um diese Funktionalität aus verwaltetem Code heraus zu lesen. ;-)
Hier somit das Snippet:
class Program
{
    [DllImport("coredll.dll")]
    private extern static int GetDeviceUniqueID([In, Out] byte[] appdata,
                           int cbApplictionData,
                            int dwDeviceIDVersion,
                            [In, Out] byte[] deviceIDOuput,
                            out uint pcbDeviceIDOutput);
    private static byte[] GetDeviceID(string AppString)
    {
        // Call the GetDeviceUniqueID
        byte[] AppData = Encoding.Unicode.GetBytes(AppString);
        int appDataSize = AppData.Length;
        byte[] DeviceOutput = new byte[20];
        uint SizeOut = 20;
        GetDeviceUniqueID(AppData, appDataSize, 1, DeviceOutput, out SizeOut);
        return DeviceOutput;
    }
    static void Main(string[] args)
    {
        byte[] id = GetDeviceID("MEINAPPDATAUID");
    }
}
Patrick & Peter
December 08

Türchen Nummer 8

Wenn man mal ehrlich ist bedeutet die Adventszeit für die meisten Leute puren Stress.
Da man also eh schon unter Zeitdruck steht sollte man wenigstens nicht lange nach seiner Applikation suchen müssen. Mit einer Verknüpfung  findet man die Anwendung einfach und schnell zum Beispiel über das Startmenü.
Daher hier der Codeschnipsel um eine Verknüpfung anzulegen:

C++

//Startmenu Ordner auslesen
WCHAR szShortcutPath[MAX_PATH*2] = L"\0";
SHGetSpecialFolderPath(NULL,szShortcutPath,CSIDL_PROGRAMS,0);
wcscat(szShortcutPath,L"\\MeinShortcut.lnk");
//Modulnamen auslesen
WCHAR szModulePath[MAX_PATH*2] = L"\0";
GetModuleFileName(GetModuleHandle(NULL), szModulePath, MAX_PATH);
//Shortcut erstellen
SHCreateShortcut(szShortcutPath,szModulePath);



Die einfachste Lösung in diesem Fall ist es, ebenfalls SHCreateShortcut via P/Invoke anzusprechen.
Somit sieht das Snippet, wie folgt, aus:

C#

...
using System.Runtime.InteropServices;

[DllImport("coredll.dll")]
private static extern int SHCreateShortcut(StringBuilder szShortcut, StringBuilder szTarget);

static void Main(string[] args)
{

StringBuilder shortcut = new StringBuilder(@"\MeinShortcut.lnk");
StringBuilder target = new StringBuilder(@"\windows\calc.exe");
SHCreateShortcut(shortcut, target);
}
...


In diesem Beispiel wurde das dynamische Auslesen des Anwendungsnamens und der Windows-Ordners ausgelassen, da dies bereits in anderen Snippets behandelt wurde.
Wer jedoch gerne mal ein Shortcut in verwaltetem Code “auf die harte Tour” erstellen möchte, sollte sich folgenden Link einmal anschauen.

Patrick & Peter
December 07

Türchen Nummer 7

Beim Versenden der Nikolaus SMS gestern jemanden vergessen?
In diesem Fall sollte man dringend zum Telefon greifen und denjenigen direkt anrufen.
Da einfach nur Telefonieren ein wenig zu simpel wäre hier noch ein Codeschnipsel wie man den Anruf aus seiner Anwendung heraus starten kann:

C++

#include "astdtapi.h"
#pragma comment(lib, "cellcore.lib")



tapiRequestMakeCall (L"+49xxxxxxxx",NULL,L"Nikolaus",NULL);


C#

In verwalteten Anwendungen geht dies genauso einfach, wenn man einen Verweis zur Bibliothek „Microsoft.WindowsMobile.Telephony“ vorab hinzufügt.
Leider lässt sich der Anzeigename hier nicht vorgeben. Der boolsche Wert beschreibt, ob der Anwender vorab gefragt werden soll, ob er den Anruf tätigen möchte.

static void Main(string[] args)
{

    Microsoft.WindowsMobile.Telephony.Phone myPhone = new Microsoft.WindowsMobile.Telephony.Phone();
    myPhone.Talk("0123456789", true);
}

Patrick & Peter

December 06

Türchen Nummer 6 (Nikolaus)

Heute ist Nikolaustag!
Wenn das mal kein Grund ist heute allen seinen Freunden und Bekannten eine Nikolaus-SMS zu senden.
Womit wir auch schon direkt beim Codeschnipsel wären. Denn heute zeigen wir das senden von SMS über die Windows Mobile API:

C++

#include "sms.h"
#pragma comment(lib, "sms.lib")

bool SMSSendSMS(LPCWSTR pcNumber,LPCWSTR pcText)
{
    //SMS API initialisieren
    HRESULT hr = NULL;
    SMS_HANDLE SMSHandle = NULL;
    HANDLE SMSEvent = NULL;
hr = SmsOpen(SMS_MSGTYPE_TEXT, SMS_MODE_SEND, &SMSHandle, &SMSEvent);
    SMS_ADDRESS adr;
    //SMS Adresse erstellen
    memset (&adr, 0, sizeof (adr));
    adr.smsatAddressType = SMSAT_INTERNATIONAL;
    lstrcpy(adr.ptsAddress, pcNumber);
    //SMS Text Struktur erstellen
    TEXT_PROVIDER_SPECIFIC_DATA tpsd;
    tpsd.dwMessageOptions = PS_MESSAGE_OPTION_NONE;
    tpsd.psMessageClass = PS_MESSAGE_CLASS1;
    tpsd.psReplaceOption = PSRO_NONE;
    tpsd.dwHeaderDataSize = 0;
    //SMS senden
    hr = SmsSendMessage(SMSHandle, NULL, &adr, NULL, (BYTE *)pcText, wcslen(pcText) * sizeof (TCHAR), (BYTE *)&tpsd, 12, SMSDE_OPTIMAL, SMS_OPTION_DELIVERY_NONE,NULL);
    //SMS API deinitialsieren
    hr = SmsClose(SMSHandle);
    return true;
}



SMSSendSMS(L"+49xxxxxxxxx",L"Alles Gute zum Nikolaustag!");




C#

Das Windows Mobile SDK bietet dem verwalteten Entwickler hier auch wieder eine Bibliothek. Diese (Microsoft.WindowsMobile.PocketOutlook) muss somit als Verweis dem Projekt hinzugefügt werden. Der Rest ist ein Kinderspiel:

using Microsoft.WindowsMobile.PocketOutlook;
...
static void Main(string[] args)
{

SmsMessage sms = new SmsMessage("+49xxxxxxxxx",
"Alles Gute zum Nikolaus")
    sms.Send();
}

In diesem Sinne alles Gute zum Nikolaustag!

Patrick & Peter
December 05

Türchen Nummer 5

Wer in der Adventszeit mal in die Innenstadt zum Einkaufen geht könnte meinen die Welt steht Kopf.
Da man das aber nun mal nicht verhindern kann heißt es also sich anzupassen.
Und wenn man schon dabei ist: Warum nicht auch mal die eigene Windows Mobile Anwendung auf den Kopf stellen?
Mit folgenden Codeschnipseln ist dies schnell getan:

C++

//DEVMODE Struktur anlegen und säubern
DEVMODE devMode;
memset(&devMode,0,sizeof(DEVMODE));
devMode.dmSize   = sizeof(DEVMODE);
//Bildschirmorientierung auslesen
devMode.dmFields = DM_DISPLAYORIENTATION;
ChangeDisplaySettingsEx(NULL, &devMode, NULL, CDS_TEST,  NULL);
//Aktuelle orientierung speichern
DWORD dwOld = devMode.dmDisplayOrientation;
//Bildschirmorientierung setzen
devMode.dmFields = DM_DISPLAYORIENTATION;
switch(devMode.dmDisplayOrientation)
{
case DMDO_0:
    devMode.dmDisplayOrientation = DMDO_180;
    break;
case DMDO_90:
    devMode.dmDisplayOrientation = DMDO_270;
    break;
case DMDO_180:
    devMode.dmDisplayOrientation = DMDO_0;
    break;
case DMDO_270:
    devMode.dmDisplayOrientation = DMDO_90;
    break;
}
ChangeDisplaySettingsEx(NULL,&devMode,NULL,CDS_RESET,NULL);
//Warten
Sleep(15000);
//Ursprüngliche orientierung wieder setzen
devMode.dmFields = DM_DISPLAYORIENTATION;
devMode.dmDisplayOrientation = dwOld;
ChangeDisplaySettingsEx(NULL,&devMode,NULL,CDS_RESET,NULL);



C#

Um dies in einer verwalteten Anwendung zu erreichen, gilt es, die Bibliothek „System.WindowsCE.Forms“ als Verweis hinzuzufügen.

using Microsoft.WindowsCE.Forms;

static void Main(string[] args)
{

    ScreenOrientation currentOrientation = SystemSettings.ScreenOrientation;
    switch (currentOrientation)
    {
        case ScreenOrientation.Angle0:
            SystemSettings.ScreenOrientation = ScreenOrientation.Angle180;
            break;
        case ScreenOrientation.Angle180:
            SystemSettings.ScreenOrientation = ScreenOrientation.Angle0;
            break;
        case ScreenOrientation.Angle270:
            SystemSettings.ScreenOrientation = ScreenOrientation.Angle90;
            break;
        case ScreenOrientation.Angle90:
            SystemSettings.ScreenOrientation = ScreenOrientation.Angle270;
            break;
        default:
            break;
    }
    System.Threading.Thread.Sleep(1500);
    SystemSettings.ScreenOrientation = currentOrientation;
    
}


Patrick & Peter
December 04

Türchen Nummer 4

„Von drauß` vom Walde komme ich her…“ heißt es im einem der bekanntesten Weihnachtsgedichten.
Schön wenn man so genau weiß, wo man „herkommt“. Denn oft genug muss man seinen eigenen Anwendungsordner kennen, um beispielsweise den Ablageort für Konfigurationsdateien oder den Speicherort für Logdateien zu bestimmen.
Nicht einfacher als das. Mit den folgenden Codeschnipseln kann man ganz einfach und ohne großen Aufwand den Ordner bestimmen aus dem die Anwendung gestartet wurde.

C++

//Vollständigen Modulnamen auslesen
WCHAR szPath[MAX_PATH] = L"\0";
if(GetModuleFileName(GetModuleHandle(NULL), szPath, MAX_PATH))
{
    //Das Backslash suchen(rückwärts) und abschneiden
    WCHAR *pszPath = wcsrchr(szPath, '\\');
    if(pszPath)
        *(pszPath + 1) = '\0';
    //In szPath steht nun der Ordner
    wprintf(L"Pfad: %s\n",szPath);
}



C#

In C# ist es ein bisschen weniger Code, da zum Filtern des reinen Ordnernamens, hier bereits eine Klasse existiert.

using System.Reflection;


static void Main(string[] args)
{

    string executable = Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName;
    Console.Write(“Pfad: “+Path.GetDirectoryName(executable));
    
}


Patrick & Peter
December 03

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_MACHINE\System\CurrentControlSet\Control\Power]" != 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.
 
No list items have been added yet.