Aktualisierung: Dem Entwickler von phoneAlarm hat dieser Blogeintrag bzw. Vorschlag gefallen. In Version 2 soll diese Funktionalität in phoneAlarm enthalten sein. Ein SDK habe ich auch gleich noch vorgeschlagen... :)
---
Leider unterstützt Windows Mobile von Haus aus keine Profile. Profile meint, dass z. B. während der Zeit von 23 Uhr - 6 Uhr ein mobiles Gerät weder auf Anrufe noch auf SMS bzw. MMS durch irgendetwas an Tönen aufmerksam machen soll. Es soll also still sein und GSM könnte während dieser Zeit gleich auch noch deaktiviert sein. Am nächsten Morgen soll dann automatisch alles zurückgesetzt und GSM wieder aktiviert werden. "Normalerweise" müsste bei Windows Mobile hier wieder die PIN eingegeben werden, aber ist das eine gute User Experience?
Eine Anwendung, die Profile unterstützt und das sogar gut, ist phoneAlarm von pocketMax. Sehr gut deswegen, weil sich Profile mit Standorten verknüpfen lassen. Verlässt man z. B. den Einflussbereich von Funkzellen, die Zuhause in der Nähe sind, könnte automatisch auf das Profil Geschäftlich geschaltet werden. Erreicht man die Funkzellen Zuhause wieder, dagegen zurück aufs Profil Zuhause. Unabhängig davon können Profile automatisch geschaltet werden, z. B. wenn im Terminkalender ein Termin einer bestimmten Kategorie steht. Ist die Kategorie beispielweise Besprechung wird eben auf Stumm aber mit Vibrationsalarm während dieses Zeitraumes geschaltet. phoneAlarm bietet unglaublich viele Variationen durch vielfältige Einstellungsmöglichkeiten. Das ist User Experience! Wer seinen Terminkalender pflegt, muss nie wieder darüber nachdenken, welches Profil gerade am besten an sein sollte. Die Profile lassen sich auch manuell wählen und zusätzlich dazu der Ton abschalten mittels "Ton aus bis".
Für mich persönlich ist bei mobilen Geräten schon nervig, dass eine Synchronisation in Abhängigkeit vom Standort nicht von Haus geht. Lösungen für Kunden habe ich schon entwickelt, durchaus auch sehr komplexe, aber etwas Einfaches für die Endanwender fehlt. O. k., we change the mobile world or go home!; und so habe ich eben etwas an Anwendungscode geschrieben, der phoneAlarm hier ergänzt¹.
phoneAlarm kann also in Abhängigkeit von z. B. einer Funkzelle ein
Profil starten. Es startet bei mir, wenn ich Zuhause bin und 22 Uhr ist, dass Profil Sync an. Das Profil aktiviert Bluetooth und ActiveSync kann es auch starten. Alles gut, könnte man denken, doch ahh, dass mobile ActiveSync kann nicht über Parameter gesteuert werden! Es gibt zwar einiges an über Suchmaschinen erreichbaren Tipps, aber die Synchronisation starten per ActiveSync über Bluetooth mittels ein paar an Parametern geht scheinbar nicht. Einer dieser Tipps ist z. B. die Ergänzung der Verknüpfung zu ActiveSync:
repllog.exe /remote
Doch es funktioniert nicht und so muss etwas Anwendungscode her. phoneAlarm startet dann die zu entwickelnde Anwendung und nicht mehr direkt ActiveSync. Dieses muss also von der zu entwickelnden Anwendung übernommen werden, welche auch nach dem Start von ActiveSync die Nachricht an dieses schickt: Über Bluetooth verbinden.
Nach 10 Minuten wird bei mir auf das Profil Sync aus geschaltet
und damit Bluetooth wieder abgeschaltet und ActiveSync beendet, was auch über phoneAlarm erledigt werden kann. Um 23 Uhr wird dann auf das Profil Nacht geschaltet und der MDA Touch schweigt bis zum nächsten Morgen.
Wie funktioniert das Ganze? Per P/Invoke. ActiveSync findet sich auf einem mobilen Gerät im Verzeichnis \Windows als Datei repllog.exe {1}. Diese Datei wird verwendet, um ActiveSync zu starten {2}. Hier wird etwa fünf Sekunden gewartet und an dieser Stelle könnte der Anwendungscode noch optimiert werden, so dass überprüft wird, ob ActiveSync gestartet wurde. Für den Normalfall sollte es aber so reichen {3}.
Jetzt muss noch nach das Fensterhandle von ActiveSync ermittelt {4} und eine entsprechende Nachricht an dieses geschickt werden {5}. Die Parameter kommen dabei nicht von ungefähr, sondern müssen, da wie sooft nicht dokumentiert, mit Werkzeugen dafür ermittelt werden. Wie das funktioniert, ist aber nicht Teil dieses Artikels. ActiveSync kann übrigens mit einer Nachricht auch beendet werden {6}. Doch dieses muss gar nicht verwendet werden. Es reicht, es entweder über phoneAlarm über Programm schließen zu beenden oder an zu lassen. Über das Profil Zuhause², wird Bluetooth deaktiviert und damit so auch das mobile Gerät "ausgedockt". ActiveSync kann ruhig an bleiben, es läuft im Hintergrund und tut nichts. Das ist auch das Standardverhalten, auch wenn mobile Geräte wie der HTC Touch neuerdings erlauben, die mobilen Anwendungen direkt immer zu beenden, anstatt sie in den Hintergrund mit (X) zu schicken.
Unter Programm ausführen muss also nur die mobile Anwendung ActiveSyncBT eingetragen werden:
\programme\activesyncbt\activesyncbt.exe ActiveSyncBluetoothConnect
Das funktioniert super so. Mit den Entwicklern von phoneAlarm stehe ich jedenfalls auch in Kontakt. Mal schauen, vielleicht wird es in der nächsten Version direkt in phone Alarm eingebaut!? :)
using System;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;
namespace ActiveSyncBT
{
class Program
{
const string ACTIVESYNC = @"\windows\repllog.exe"; // {1}
const uint WM_COMMAND = 0x00000111;
static void Main(string[] args)
{
if (args.Length == 0)
{
return;
}
if (string.IsNullOrEmpty(args[0]))
{
return;
}
if (args[0] == "ActiveSyncBluetoothConnect")
{
ActiveSyncBluetoothConnect();
}
if (args[0] == "ActiveSyncBluetoothDisconnect")
{
ActiveSyncBluetoothDisconnect();
}
}
private static void ActiveSyncBluetoothConnect()
{
StartActiveSync(); // {2}
Thread.Sleep(5000); // {3}
IntPtr hwnd = FindWindow("ActiveSync", null); // {4}
int wParamStatus = 42020;
int lParamStatus = 2080867584;
SendMessage(hwnd, WM_COMMAND, wParamStatus, lParamStatus); // {5}
}
private static void ActiveSyncBluetoothDisconnect()
{
IntPtr hwnd = FindWindow("ActiveSync", null);
int wParamStatus = 42020;
int lParamStatus = 2080866256;
SendMessage(hwnd, WM_COMMAND, wParamStatus, lParamStatus); // {6}
}
[DllImport("coredll.dll")]
public static extern IntPtr FindWindow(string className, string windowName);
[DllImport("coredll.dll")]
public static extern int SendMessage(
IntPtr hWnd, uint WM_COMMAND, int wParamStatus, int lParamStatus);
public static void StartActiveSync()
{
Process ActiveSync = Process.Start(ACTIVESYNC, "");
}
}
}
using System;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;
namespace ActiveSyncBT
{
class Program
{
const string ACTIVESYNC = @"\windows\repllog.exe";
const uint WM_COMMAND = 0x00000111;
static void Main(string[] args)
{
if (args.Length == 0)
{
return;
}
if (string.IsNullOrEmpty(args[0]))
{
return;
}
if (args[0] == "ActiveSyncBluetoothConnect")
{
ActiveSyncBluetoothConnect();
}
if (args[0] == "ActiveSyncBluetoothDisconnect")
{
ActiveSyncBluetoothDisconnect();
}
}
private static void ActiveSyncBluetoothConnect()
{
StartActiveSync();
Thread.Sleep(5000);
IntPtr hwnd = FindWindow("ActiveSync", null);
int wParamStatus = 42020;
int lParamStatus = 2080867584;
SendMessage(hwnd, WM_COMMAND, wParamStatus, lParamStatus);
}
private static void ActiveSyncBluetoothDisconnect()
{
IntPtr hwnd = FindWindow("ActiveSync", null);
int wParamStatus = 42020;
int lParamStatus = 2080866256;
SendMessage(hwnd, WM_COMMAND, wParamStatus, lParamStatus);
}
[DllImport("coredll.dll")]
public static extern IntPtr FindWindow(string className, string windowName);
[DllImport("coredll.dll")]
public static extern int SendMessage(IntPtr hWnd, uint WM_COMMAND, int wParamStatus, int lParamStatus);
public static void StartActiveSync()
{
Process ActiveSync = Process.Start(ACTIVESYNC, "");
}
}
}
¹ Bild "Microsoft - change the world or go home!" im Original entworfen durch Hugh MacLeod von Stormhoek und angepasst von Torsten Weber.
² Nach 10 Minuten um 22:10 Uhr.
ActiveSyncBT.zip (1,77 KB)
ActiveSyncBT_Code.zip (4,18 KB)