free web page counters

Windows Mobile Pocket PC Smartphone Programming

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

Tuesday, December 20, 2005

Pocket PC Power Management Series 6: Request the Device to Run: a Gentle Way

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

Pocket PC Power Management Series 6: Request the Device to Run: a Gentle Way

In Pocket PC Power Management Series 5, I showed how to use API SystemIdleTimerReset to force the device not to sleep. However, this technique is an overkill and a waste if used for case-2 programs (which need to run periodically, not continuously). Further, some utilities are known to disrupt SystemIdleTimerReset, for example, Keyguard.

A more gentle way is to request the device to run at certain time, by using the omnipotent CeSetUserNotificationEx (see my Pocket PC Power Management Series 4 for a brief introduction to this API). Hereby I present three ready-to-use functions.

1. How to Use?

If you want to run Pocket IE to browse a URL 10 minutes later, simply call:

ScheduleRunApp(TEXT("\\Windows\\iexplore.exe"), TEXT("URLXXX""), 600);

And remember to clear it after some time:

ClearRunApp(TEXT("\\Windows\\iexplore.exe"));

2. Walkthrough of the functions

  • SecondsAfter: It takes a pointer to SYSTEMTIME and a number of seconds,;
    upon returning, the SYSTEMTIME is modified to be exactly that number of
    seconds after the original time. For example, if original time is 10:00AM
    now, and you want to a time 10:05AM, just pass 300 as the second parameter.
    The function converts SYSTEMTTIME to FILETIME for easy arithmetic operation.

static HRESULT SecondsAfter(SYSTEMTIME* pst, int numSeconds)
{
  FILETIME ft;
  
  // convert to FILETIME then ULONGLONG for calculation
  if (!SystemTimeToFileTime(pst, &ft)) return E_FAIL;
  ULONGLONG ulLongFt = *(ULONGLONG*)&ft;
  ulLongFt += (ULONGLONG)numSeconds * 10000000;
  // 10000000: how many nano seconds per second, divided by 100
  
  // convert back to FILETIMEand SYSTEMTIME
  ft = *(FILETIME*)&ulLongFt;
  if (!FileTimeToSystemTime(&ft, pst)) return E_FAIL;
  return S_OK;
}  
  • ScheduleRunApp: It takes an Executable name, arguments and a number of
    seconds. All parameters are self-explanatory. For example, if you pass 300
    as dwAfterSeconds, the program is scheduled to run 5 minutes after the
    function is called.

static HRESULT ScheduleRunApp(
  LPCTSTR szExeName,
  LPCTSTR szArgs,
  DWORD dwAfterSeconds)
{
  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);
  
  // calculate time
  SYSTEMTIME st = {0};
  GetLocalTime(&st);
  hr = SecondsAfter(&st, dwAfterSeconds);
  if (FAILED(hr)) {
    return hr;
  }
  
  notifTrigger.dwType = CNT_TIME;
  notifTrigger.stStartTime = st;
  
  // timer: execute an exe at specified time
  notifTrigger.lpszApplication = (LPTSTR)szExeName;
  notifTrigger.lpszArguments = (LPTSTR)szArgs;
  
  hNotify = CeSetUserNotificationEx(0, &notifTrigger, NULL);
  // NULL because we do not care the action
  if (!hNotify) {
   hr = E_FAIL;
  } else {
   // close the handle as we do not need to use it further
   CloseHandle(hNotify);
  }  
  return hr;
}  
  • ClearRunApp: I want to emphasize and repeat what I said in Pocket
    PC Power Management Series 4
    regarding CeSetUserNotificationEx. 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 ClearRunApp, which is used to clear previously
    scheduled tasks. Remember: Even if the task already ran, the notification is
    still persisted, unless cleared programmatically.
static HRESULT ClearRunApp(LPCTSTR szExeName)
{
  HRESULT hr = S_OK;
  
  // hold a notification
  PBYTE pBuff = (PBYTE)LocalAlloc(LPTR, 8192);
  
  if (!pBuff) {
    return E_OUTOFMEMORY;
  }
  
  // at most 256 notification handles
  HANDLE hNotifHandlers[256];
  DWORD nNumHandlers, nNumClearedHandlers = 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->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;
}

3. Further thoughts

If you do not need the style of "running a program AFTER some time", rather, what you want is "running a program AT certain time", you can simply modify ScheduleRunApp as needed.



Category: [Power Management]

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




[ [permalink] ]

20 Comments:

At March 27, 2006 2:15 AM, Anonymous Anonymous said...

Hi,

Great series - well done!!

Just one note - your ScheduleRunApp() is leaking a handle each time it is called!

CeSetUserNotificationEx returns a handle if successful and you aren't closing it!

 
At March 29, 2006 12:39 PM, Blogger Lao K said...

Thanks for pointing out! I've modified the source code (also in Series 4) to close the handle.

I complete agree that it is a good habit to always close any handle *so long as* it is not used. However, I am not sure whether the handle returned by CeSetUserNotificationEx is really that critical like a handle to a Kernel Object. For example, if you forget to close a handle to a Thread kernel object, the handle won't be released until the process dies. Those kernel objects are tracked in the process' handle table. So my question is whether the handle returned by CeSetUserNotificationEx is such an object being tracked in the handle table, and pointing to to a data structure maintained only by the kernel; or the handle returned by CeSetUserNotificationEx is just a pseudo number, which does not carry much significance (if you do not need to call CeClearUserNotification to clear it in the same process). My sample code actually clears the notification in a separate process.

Looks like at least one other people had such concern, and Peter Foot said that there is no need to close the handle since it is not a real one.

I posted a question to Microsoft Smart Device Development forum, hoping to get an authoritative answer from within Microsoft.
(http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=321876&SiteID=1)

 
At April 12, 2006 8:55 AM, Anonymous Anonymous said...

Hi, I posted a question about

series 6 on
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=324621&SiteID=1

it's about how to use the unmanaged code. I'm still learning ;)

thank you.

I saw a new interesting blog about SSL. I'll take a look at it

 
At April 16, 2006 9:08 AM, Anonymous Anonymous said...

Can you tell me more exactly how to use it with c#, I haven't a clue

thus like : make new file, which kind?
...

 
At April 17, 2006 5:17 PM, Anonymous Anonymous said...

sorry, me again, but I'm running out off time...

I want to call it from c# or another way, but how??

Davy.timmermans a t kahosl.be

 
At June 13, 2006 3:20 AM, Anonymous Anonymous said...

Is there any posibility to enable the "View Item" menu item when notification arrives?
I want to use it to launch my application.

 
At October 03, 2007 6:51 AM, Blogger Unknown said...

This comment has been removed by the author.

 
At October 03, 2007 6:52 AM, Anonymous Anonymous said...

AMAZING CODE i must say !!
just 1 help.. I wanted to do the reverse of u r doing up here .. as in .. DETECT an APP which is running..
I mean .. when i click the IE icon from the today screen, i want to get a notification, & so on for every Exe under windows like tasks.exe, tcalc.exe, etc .. PLEASE HELP !!

 
At November 15, 2007 5:20 PM, Blogger Sombat said...

Thanks so much for sharing your knowledge. I have one question.
int the line
" int rc = CeGetUserNotificationHandles(hNotifHandlers,
dim(hNotifHandlers), &nNumHandlers); "

of "ClearRunApp(...)"

I've got an error while compiling.
The error point is at "dim(hNotifHandlers)".

Do you have any suggestion?

Thanks in advance.

 
At April 27, 2009 7:11 PM, Anonymous Anonymous said...

I like play online game, I also gw gold and GuildWars Gold, the Guild Wars Gold is very cheap, and use the GuildWars money can buy many things, I like cheap gw gold, thanks, it is very good.

 
At April 27, 2009 7:12 PM, Anonymous Anonymous said...

I like play online game, I also buy habbo gold and habbo credits, the habbo gold is very cheap, and use the habbo coins can buy many things, I like cheap habbo credits, thanks, it is very good.

 
At April 27, 2009 7:12 PM, Anonymous Anonymous said...

I like play online game, I also buy hero gold and hero gold, the hero online gold is very cheap, and use the hero online money can buy many things, I like hero money, thanks, it is very good.

 
At April 27, 2009 7:12 PM, Anonymous Anonymous said...

I like play online game, I also buy kal geons and kal gold, the kal online geons is very cheap, and use the kal online gold can buy many things, I like kalonline Geons, thanks, it is very good.

 
At April 27, 2009 7:13 PM, Anonymous Anonymous said...

Now do you worried about that in the game do not had enough Sword of the New World Vis to play the game, now you can not worried, my friend told me a website, in here you can buy a lot Sword of the New World Gold and only spend a little money, do not hesitate, it was really, in here we had much cheap snw vis, we can sure that you will get the Sword of the New World money, quick to come here to buy vis.

 
At May 13, 2009 10:52 AM, Anonymous Guide for World of Warcraft Gold said...

great post!

 
At May 13, 2009 6:12 PM, Anonymous Anonymous said...

I like the Tales Of Pirates gold, in the game Tales Of Pirates money is very important, if you have cheap Tales Of Pirates gold, you will become stronger. You can buy weapons with the buy Tales Of Pirates Gold, so when you have many buy Tales Of Pirates Gold, you will improve your level quickly.

 
At May 16, 2009 11:55 PM, Anonymous Anonymous said...

Hi,

The ScheduleRunApp runs in principle like a charm, but I have one major problem. For some reason, the PDA does not wake up after setting a notification with ScheduleRunApp("JustAProgram").

ScheduleRunApp("JustAProgram") only works fine when the device stays on, or is in sleep mode with the external power connected.

Please help,

Huub

 
At May 17, 2009 12:02 PM, Anonymous Anonymous said...

I just figured it out!

When the notification hits, the application is started but the device goes into suspend mode almost immediately. I use SetSystemPowerState() to force the device to go into power on mode.

Cheers,

Huub

 
At June 02, 2009 4:44 AM, Anonymous Tom Bradley said...

Hi Lao K,

Firstly, I'd like to thank you for an awesome series on power management!

I've been battling with Motorola(Symbol) over a major power saving issue. What they have done is whenever a TCP or UDP data packet is sent or received, they force a reset of the system idle timer. So, as you can imagine if the device were set to sleep after 5 minutes and a mail client checked for mail every 4 minutes the device would never sleep.

Please correct me if I'm wrong but doesn't that go against the design of the OS & Power Manager?

This is causing major problems with our application that retains an open connection for pushing data from our servers to our mobile devices. The application sends a keep alive packet every 45 seconds to let the server know the device is within GPRS range and online.

Motorola seem very reluctant to change this stating it's "the desired and better behavior for MOST customers".

They also state that it would be "impossible to transfer big file since the terminals will suspend before finishing". Surely this is why an application transfering a large file should call SystemIdleTimerReset function.

Please note, this feature is only implemented on 2 devices (the MC70 & MC9090). Motorola claim that these two devices are "focused in different environments where the user needs and preferences are different".

Personally, I can't think of any scenario in which you'd want to force this functionality. Regardless of environment.

I don't really know where to go next on this issue. Motorola are not listening.

Any help or comments would be greatly appreciated.

Thanks in advance

Tom Bradley

 
At July 25, 2009 5:52 AM, Anonymous Anonymous said...

I am grateful to you for this great content.aöf thanks radyo dinle cool hikaye very nice sskonlycinsellik very nice ehliyet turhoq home free kadın last go korku jomax med olsaoy hikaye lesto go mp3 indir free only film izle

 

Post a Comment

<< Home