在Windows Mobile设备上,当设备的备用电池电量非常低时,系统会弹出一个关键的系统通知气球,并在导航栏中显示一个图标,以通知用户系统备用电池电量严重不足。这是一个关键的设备状态,用户需要迅速采取行动更换/充电备用电池,以避免潜在的数据丢失。
然而,市场上的一些设备要么没有提供更换备用电池的途径,要么即使更换了电池,每次设备重启时,通知气球也会频繁弹出,这在很多情况下是虚假的,给用户带来困扰。
虽然用户确认弹出通知后,通知会消失,但对于以Kiosk模式(全屏模式)运行的应用程序来说,情况就不同了。在这种情况下,通知气球不会弹出,但图标会显示在导航栏中,而且无法消除。
找到了一个简单的解决方法来应对上述情况。可以根据自己的需要使用这个解决方法。
解决方法的逻辑相当简单,但涉及到一些技巧。逻辑是通过枚举系统通知,找到“备用电池电量非常低”通知的句柄,如果找到了,就从系统中程序性地移除这个通知。
首先,要谨慎地建立一个机制,以区分这个通知弹出的虚假情况和用户应该采取适当行动以防止潜在数据丢失的实际条件。
其次,可能需要一种方法来从文本形式获取通知的COM接口的CLSID。可以使用代码片段中所示的CLSIDFromString()函数。这个函数已经在ole32.lib和oleaut32.lib库中实现。可能也想在项目中包含objbase.h头文件。
此外,SHNotificationGetData()函数调用需要传入一个唯一的通知ID,而没有这个ID。不同的平台供应商为这个相同的通知分配了不同的ID,这使得猜测变得更加困难。因此,在解决方法中,尝试从0开始,每次失败调用后ID递增1。在尝试过的所有平台上,不到2000次尝试就能找到匹配的ID。可能想先为开发的平台进行实验,以获得一个概念。如果平台供应商可以提供这个ID值,那就太好了。如果没有,仍然可以使用使用的方法。
已经在eVC++ 3.0和4.0项目中成功使用了这种方法,适用于多个供应商的Windows Mobile2002/2003/2003SE设备。
void RemoveLowBattMessage()
{
SHNOTIFICATIONDATA shnd;
CLSID clsid;
LRESULT result;
DWORD dwID = 0;
if(0 == CLSIDFromString(TEXT("{A877D663-239C-47a7-9304-0D347F580408}"), &clsid)) {
memset(&shnd, 0, sizeof(shnd));
shnd.cbStruct = sizeof(SHNOTIFICATIONDATA);
do {
result = SHNotificationGetData(&clsid, dwID, &shnd);
if(ERROR_SUCCESS == result) {
SHNotificationRemove(&clsid, dwID);
if(shnd.pszHTML) free((void*) shnd.pszHTML);
shnd.pszHTML = NULL;
if(shnd.pszTitle) free((void*) shnd.pszTitle);
shnd.pszTitle = NULL;
} else {
dwID++;
}
} while((ERROR_SUCCESS != result) && (dwID < 2000));
}
}