free web page counters

Windows Mobile Pocket PC Smartphone Programming

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

Sunday, April 09, 2006

Pocket PC Power Management Series 10: A Better Way to Catch when the Device Wakes Up - Multi-Thread Code with Visual Studio 2005 Solution Download

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

Pocket PC Power Management Series 10: A Better Way to Catch when the Device Wakes Up - Multi-Thread Code with Visual Studio 2005 Solution Download

In Pocket PC Power Management Series 4: A Better Way to Catch when the Device Wakes Up, I present a nice way to catch when the device wakes up. The sample code use CeSetUserNotificationEx to register a named event; when Windows CE OS wakes up, OS fires the event. The code has only one thread, calling MsgWaitForMultipleObjectsEx to both listen to the wakeup event, and process windows message queue. As warned at the end of that post, the single thread might be busy thus missing wakeup events.

Some readers mailed me wondering whether I can provide a fully-functional sample code with two threads such that wakeup event can be always reliably caught. A reader also left a comment asking for the two-thread code. Here I am :)

The VS2005 solution is a Zip file. Extracting it you'll get .sln, .vcproj and source code. Project settings cover Pocket PC 2003 platform and Pocket PC 5.0 platform. For PPC2003 platform, secchk.lib and ccrtrtti.lib are added.

The executable can be run on both Pocket PC 2003 device and Pocket PC 5.0 device. You can use your Pocket IE to download the executable file directly into your device, then run it there.

This is a screen cut when the program runs. All windows messages posted to the main windows (along with the timestamp) are logged to the screen. Besides, any wakeup event (along with the timestamp when the event is fired) are also logged to the screen.

Below is a quick walkthrough of the source code:

The thread that is dedicated to listening to the wakeup signal. Notice it calls WaitForMultipleObjects to actually listen to two events, the other one being the shutdown signal. This also demonstrates how to gracefully shutdown a thread without relying on a global boolean that the thread periodically polling against.


static DWORD WakeupEventListener(LPVOID lpData)
{
  TCHAR szBuf[256];
  PEVENTHANDLES pEventHandles = (PEVENTHANDLES)lpData;

  while (TRUE) {
     ResetEvent(pEventHandles->hWakeupEvent);
     DWORD dwResult = WaitForMultipleObjects(2, (HANDLE*)pEventHandles, FALSE, INFINITE);
     if (WAIT_OBJECT_0 == dwResult) {
        _tcscpy(szBuf, TEXT("Wakeup at "));
        FormatCurrentTime(szBuf+_tcslen(szBuf));
        _tcscat(szBuf, TEXT("\r\n\r\n"));
        OutputString(szBuf);
     } else if (WAIT_OBJECT_0+1 == dwResult) {
        break;
     } else {
        // WAIT_ABANDONED and WAIT_FAILED
        // Abondoned is not possible, failed most probably means the Handle is closed
        if (WAIT_FAILED == dwResult) {
           // ... do something error processing
        }
     }    
  }

  return S_OK;
}

Start and stop the wakeup event listener thread.


static HRESULT StartWakeupEventListener(const PEVENTHANDLES pEventHandles, HANDLE& hThread)
{
  DWORD dwDummy = 0;
  hThread = CreateThread(NULL, 0, WakeupEventListener, (LPVOID)pEventHandles, 0, &dwDummy);
  // need to error handling if thread creation failed

  return S_OK;
}

static HRESULT StopWakeupEventListener(const PEVENTHANDLES pEventHandles, HANDLE& hThread)
{
  DWORD dwMilliSec = 2000;
  if (hThread) {
     PulseEvent(pEventHandles->hThreadStop);
     DWORD dwResult = WaitForSingleObject(hThread, dwMilliSec);
     if (WAIT_OBJECT_0 != dwResult) {
        // error or timeout. terminate the thread anyway
        TerminateThread(hThread, -1);
     }

     CloseHandle(hThread);
     hThread = NULL;
  }

  return S_OK;
}

Main logic during program starts up:

  • to create the wakeup event
  • to create shutdown signal
  • to start the wakeup event listener thread

and before the program quits:

  • to stop the wakeup event listener thread,
  • to destroy the wakeup event
  • to destroy the shutdown signal


{
  HRESULT hr = ClearWakeupNotification(g_szEventName);
  hr = AddWakeupNotification(g_szEventName);
  HANDLE hWakeupEvent = CreateEvent(NULL, TRUE, FALSE, g_szEventName);
  HANDLE hThreadStopEvent = CreateEvent(NULL, TRUE, FALSE, TEXT("ThreadStop"));
  EVENTHANDLES eventHandles = {hWakeupEvent, hThreadStopEvent};
  HANDLE hWakeupEventListenerThread = NULL;
  hr = StartWakeupEventListener(&eventHandles, hWakeupEventListenerThread);


  // ..........

  hr = StopWakeupEventListener(&eventHandles, hWakeupEventListenerThread);
  // thread handle already closed
  hr = ClearWakeupNotification(g_szEventName);
  CloseHandle(hWakeupEvent);
  CloseHandle(hThreadStopEvent);
}



Category: [Power Management]

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