free web page counters

Windows Mobile Pocket PC Smartphone Programming

==>Click here for the SiteMap<==. Original contents with decent amount of source codes.

Wednesday, November 09, 2005

Pocket PC Power Management Series 4: A Better Way to Catch when the Device Wakes Up

====>SiteMap of this Blog<===

Pocket PC Power Management Series 4: A Better Way to Catch when the Device Wakes Up

In Pocket PC Power Management Series 3, I presented a simple program that depicts when the device runs and when it sleeps. The program uses a rudimentary and inefficient way to achieve the purpose: It spawns a periodically sleeping thread, which is responsible for recording whether itself sleeps through the predefined time frame. If it sleeps longer than expected, it draws the conclusion that the device must have been suspended.

The recommended and efficient way is to use the omnipotent CeSetUserNotificationEx API. If you happen to write any serious Windows Mobile programs, you must either have heard about it, or have used it. Basically it allows the developer to either launch a program, or to display a dialog, or to emit a sound, or to vibrate the device, if certain predefined system events occur, or if the predefined time arrives. I believe the Alarm program shipped with any Pocket PC or Smartphone (for example, the devices I have at hand: Sprint SmartDevice 6600, Sprint SmartDevice 6700, Palm Treo 700w, Cingular 8125, I-Mate SP5, Cingular MPx220, Sprint Samsung i600) must be written based on this API.

Luckily enough, Microsoft includes device wakeup event as one of the system events. The way to make use of the event is a little tweaked, so here is my example and source code, with detailed explanations.

1. Two helper functions to deal with wakeup Notifications: AddWakeupNotification and ClearWakeupNotification

AddWakeupNotification anticipates a constant string, which is the event name. Such name is also used later as the name of an event, as described in msdn documentation for CeSetUserNotificationEx and CE_NOTIFICATION_TRIGGER.

One notorious side-effect of CeSetUserNotificationEx is that the notification will be persisted in a central repository, unless the creator remembers to remove it. I've seen a couple of novice developers forgot to clear the notifications and subject his/her testing device to some really weird behaviors. So I also present ClearWakeupNotification, which also accepts a constan string.

static HRESULT AddWakeupNotification(LPCTSTR szEventName)
{
  HRESULT hr = S_OK;
  HANDLE hNotify = NULL;

  // set a CE_NOTIFICATION_TRIGGER
  CE_NOTIFICATION_TRIGGER notifTrigger;
  memset(&notifTrigger, 0, sizeof(CE_NOTIFICATION_TRIGGER));
  notifTrigger.dwSize = sizeof(CE_NOTIFICATION_TRIGGER);

  TCHAR szNamedEventName[MAX_PATH];
  memset(szNamedEventName, 0, sizeof(TCHAR)*MAX_PATH);
  _tcscat(szNamedEventName, NAMED_EVENT_PREFIX_TEXT);
  _tcscat(szNamedEventName, szEventName);

  notifTrigger.dwType = CNT_EVENT;
  notifTrigger.dwEvent = NOTIFICATION_EVENT_WAKEUP;
  notifTrigger.lpszApplication = szNamedEventName;
  //notifTrigger.lpszArguments = NULL;

  // set the notification
  hNotify = CeSetUserNotificationEx(0, &notifTrigger, NULL);
  // NULL because we do not care what action to take

  if (!hNotify) {
   hr = E_FAIL;
  } else {
   // close the handle as we do not need to use it further
   CloseHandle(hNotify);
  }

  return hr;
}

static HRESULT ClearWakeupNotification(LPCTSTR szEventName)
{
  HRESULT hr = S_OK;

  TCHAR szToCompare[MAX_PATH];
  memset(szToCompare, 0, sizeof(TCHAR)*MAX_PATH);
  _tcscat(szToCompare, NAMED_EVENT_PREFIX_TEXT);
  _tcscat(szToCompare, szEventName);

  // hold a notification
  PBYTE pBuff = (PBYTE)LocalAlloc(LPTR, 8192);

  if (!pBuff) {
      return E_OUTOFMEMORY;
  }

  // at most 256 notification handles -
  // should be more than enough for a typical device
  HANDLE hNotifHandlers[256];
  DWORD nNumHandlers = 0;
  DWORD i = 0;
  int rc = CeGetUserNotificationHandles(hNotifHandlers,
  dim(hNotifHandlers), &nNumHandlers);
  if (!rc) {
      hr = E_FAIL;
      goto FuncExit;
  }

  // iterate all notifications
  // Notice: We do not care about the status of the notification.
  // Just clear it even if it is not filed??
  for (; i<nNumHandlers; i++) {
      // query info for this specific handler
      BOOL bClearThis = FALSE;
      DWORD dwSize = 0;
      rc = CeGetUserNotification(hNotifHandlers[i], 8192, &dwSize, pBuff);
      if (!rc) continue;
  
      PCE_NOTIFICATION_INFO_HEADER pnih = (PCE_NOTIFICATION_INFO_HEADER)pBuff;
      PCE_NOTIFICATION_TRIGGER pNotifTrigger = pnih-&gt;pcent;
  
      // Notice some events with NULL lpszApplication might be inserted!
      if (pNotifTrigger && pNotifTrigger->lpszApplication
          && !_tcsicmp(pNotifTrigger->lpszApplication, szToCompare)) {
          CeClearUserNotification(pnih->hNotification);
      }
  }

FuncExit:
  if (pBuff) {
  LocalFree(pBuff);
  }

  return hr;
}

2. Wait for the named event

In Windows, events are named. What we need to do here is to create such a named event, and request that the notification subsystem set the named event when the notification event occurs. So the code skeleton is like this:

HRESULT hr = AddWakeupNotification(g_szEventName);
HANDLE hWakeupEvent = CreateEvent(NULL, TRUE, FALSE, g_szEventName);

// some code to wait for the named event
// -- meaning the device just wakes up
// ...

CloseHandle(hWakeupEvent);
hr = ClearWakeupNotification(g_szEventName);

The tricky part is how to wait for the wakeup event. If you really hates multi-threaded programming, I have the following single-thread example for your reference:


HANDLE eventHandles[] = {hWakeupEvent};
DWORD dwEventCount = 1;

TCHAR szBuf[256];
MSG currentMsg;

while (true) {
   ResetEvent(hWakeupEvent);
   DWORD dwRC = MsgWaitForMultipleObjectsEx(dwEventCount,
                   eventHandles, INFINITE, QS_ALLEVENTS, NULL);
   if (WAIT_OBJECT_0 == dwRC) {
       ALERT(TEXT("Aha Wakeup just now!));
   } else if (WAIT_FAILED == dwRC) {
       // XXX wait failed?
   } else if (WAIT_OBJECT_0+dwEventCount == dwRC) {
       int nGetMsg = GetMessage(&currentMsg, NULL, 0, 0);
       if (nGetMsg > 0) {
           TranslateMessage(&currentMsg);
           DispatchMessage(&currentMsg);
       } else if (nGetMsg < 0) {
           // XXX GetMsg failed;
       } else {
           break;
       }
   }
}

Read the above code, you'll find the familiae bolier plate code TranslateMessage() and DispathMessage(). Yes it is right! You can use MsgWaitForMultipleObjectsEx to both respond to the current thread message queue and listen to a list of events. In Windows, a window is associated with a thread, the thread that creates the window. So the "thread message queue" actually is your familiar "windows message queue". Use the powerful MsgWaitForMultipleObjectsEx API, you can achieve the purpose using only one thread to deal with UI, and listen to the wakeup event.

However, the above technique might not work well, and you may notice you'll frequently miss a wake-up event. The reason is obvious. The single thread most probably is processing a windows message (remember the two function calls: TranslateMessage and DispathMessage). If this thread is executing a windows procedure (because of a windows message) when the device wakes up, the thread for sure will miss the wakeup signal!

So a reliable way is to spawn a new thread, and use WaitForSingleObject to listen to the wakeup signal. Of course this thread does not necessary only deal with the wakeup signal. You can make it run other errands by calling WaitForMultipleObjects, but just make sure it should not be a busy thread!


Update: I uploaded series 10 with the two-thread code. The Visual Studio 2005 solution can be downloaded as well.

Category: [Power Management]

====>SiteMap of this Blog<===




[ [permalink] ]

5 Comments:

At March 31, 2006 6:04 PM, Anonymous Anonymous said...

Hi, thank you for the great series on pocket pc power stuff. Really helped me understand why my thing does not work well. I used your single-threaded code, like you said, some wakeup events are missed. Could you kindly show a multi-threaded sample code?

 
At December 11, 2008 4:15 AM, Anonymous Rajkumar said...

You are missing the wakeup event not because of the single threaded approach, but because of the coding bug. Think suppose you have both the events signalled and you processed the message queue event first. Since your are resetting the event everytime before checking the signalled state, you are missing the event. In your code reset the event only if you process the wakeup event.

 
At February 11, 2009 12:12 AM, Blogger uiyui said...

welcome to the wow power leveling cheap Wow gold service site, buy cheap wow gold,wow gold,world of warcraft power leveling buy wow gold

 
At April 12, 2009 7:29 PM, Anonymous world of warcraft gold said...

Weaknesses of World Of Warcraft Gold the client-server model used by World of Warcraft have been wow power levelingexploited in order to crash the cluster of servers that aoc goldmake up a realm. Exploits also include characters being able to instantly Cheapest Wow Goldchange location or teleport. The situationbecame worse cheap wow goldwhen trying to coordinate activities across a number of playersor guilds on the same realm.World of Warcraft Lead Producer, stated that new realms would be introduced to warhammer goldrelieve the burden on existing ones. Existing realms would be upgraded.

Although the game wow gold follows a similar model to others in the genreand was noted for having wow gold cheapmany familiar concepts from roleplaying games, the new approaches gold4powerto reduce pauses between game encounters was well liked. At various times, World of Warcraft players have experienced problems with connecting to and logging in to wow gold for sale the game. Sudden server crashes that would force realms offline also occurred.

 
At November 04, 2009 4:12 PM, Blogger Adi said...

Find Internet Marketing resource hare Online Marketing Strategy | Internet Marketing Tools | Online Marketing Campaign | Online Marketing Business | Online Marketing System | Online Business | Online Home Business | Online Business Tips | Internet Marketing Online

 

Post a Comment

Links to this post:

Create a Link

<< Home