Using Mini-Applications with Notification

< BACK  NEXT >
[oR]

In general it is best not to run large applications using CeRunAppAtTime, since the user may be confused by a new application suddenly appearing and may cause an out-of-memory error. Instead, you should create a "mini-application" with no user interface and have this application run at the specified time. The "mini-application" can then notify the main application through a private message of the event, or perhaps perform some scheduled task.

Listing 7.2 shows the code for a "mini-application" called Notify.exe. This is a Windows CE application with a WinMain function that registers a new windows message using the RegisterWindowMessage function. The RegisterWindowMessage function is passed a string and returns a message number. Any application that calls RegisterWindowMessage with the same string will always receive back the same message number, and so the message can be used for communication between applications. Next, the WinMain function calls SendMessage using the special window handle HWND_BROADCAST. This sends the message number in nNotifyMsg to all top-level windows. WinMain returns and the mini-application ends. The code for Notify.exe is located on the CDROM in the folder \Notify.

Listing 7.2 Notify.exe "Mini-application" used for notification
 #include <windows.h> int WINAPI WinMain(HINSTANCE hInstance,     HINSTANCE hPrevInstance,     LPWSTR lpCmdLine, int nShowCmd) {   UINT nNotifyMsg =     RegisterWindowMessage(_T("MSG_NOTIFY"));   SendMessage(HWND_BROADCAST, nNotifyMsg, 0, 0);   return 0; } 

An application can use the CeRunAppAtTime function to run Notify.exe at a specified time:

 CeRunAppAtTime(_T("\\Notify.exe"), &sysTime)) 

To respond to the broadcast SendMessage from Notify.exe an application must use RegisterWindowMessage when it first starts, using the same string as used in Notify.exe.

   nNotifyMsg = RegisterWindowMessage(_T("MSG_NOTIFY")); 

Next, the application must add code to the window message procedure for its top-level, main application window to handle the message number held in nNotifyMsg.

 if(message == nNotifyMsg) {   cout   "Notification: Application has run"          endl; } 

The technique described here only responds to Notify.exe if the application in question is running, otherwise the broadcast message will be ignored. The mini-application can check if the application is running, and if not, call CreateProcess to runit.

 HWND hWnd = FindWindow(_T("Examples"), NULL); PROCESS_INFORMATION pi; if(hWnd == NULL)   CreateProcess(_T("\\Examples.exe"), NULL,     NULL, NULL, FALSE,0, NULL,     NULL, NULL, &pi); SendMessage(HWND_BROADCAST, nNotifyMsg, 0, 0); 

The function FindWindow is passed the class name "Examples" of the main application window in "Examples.exe". A returned NULL handle indicates that the window could not be found, and therefore the application is not running. In this case, CreateProcess is called to run Examples.exe. (See Chapter 5 for more information on CreateProcess.) Unfortunately, the application Examples.exe will not receive the notification message! This is because CreateProcess returns before the application has initialized and created the main window. This is a classic synchronization problem. A simple solution would be to add a "while" loop after CreateProcess but before SendMessage.

 if(hWnd == NULL) {   CreateProcess(_T("\\Examples.exe"), NULL,     NULL, NULL, FALSE,0, NULL,     NULL, NULL, &pi);   while(FindWindow(_T("Examples"), NULL) == NULL)     Sleep(100); } SendMessage(HWND_BROADCAST, nNotifyMsg, 0, 0); 

In this case, the program loops until FindWindow returns a non-NULL handle, and sleeps the thread for 100 milliseconds on each loop iteration to avoid hogging the CPU. However, this solution is not ideal because:

  • The loop will continue forever if the main application window in Examples.exe could not be created.

  • The call to the Sleep function introduces unnecessary delays.

  • Although the window will have been created when SendMessage is called, the WM_CREATE message may not have been processed. Therefore, the window may not be properly initialized when the notification is received.

The correct solution is to use a synchronization event, which is shown in Listing 7.3. An event is created which is manually signaled (the FALSE parameter) that will be initially non-signaled (the 0 parameter). The event is given a name so that the same event can be used in the Example.exe application. The WaitForSingleObject function is used to wait on the event to be signaled, with a timeout of 5000 milliseconds. The Example application will signal this event when initialization is complete and the application is ready to receive a notification. Events are described in more detail in Chapter 6.

Listing 7.3 Notify.exe with synchronization
 #include <windows.h> int WINAPI WinMain(HINSTANCE hInstance,     HINSTANCE hPrevInstance,     LPWSTR lpCmdLine, int nShowCmd) {   UINT nNotifyMsg =     RegisterWindowMessage(_T("MSG_NOTIFY"));   HWND hWnd = FindWindow(_T("Examples"), NULL);   PROCESS_INFORMATION pi;   HANDLE hEvent;   if(hWnd == NULL)   {     // create non-signaled event     hEvent = CreateEvent(NULL, TRUE,         0, _T("Examples_Event"));     if(CreateProcess(_T("\\Examples.exe"),         NULL, NULL, NULL,         FALSE,0, NULL, NULL, NULL, &pi))     {       CloseHandle(pi.hProcess);       CloseHandle(pi.hThread);       if(WaitForSingleObject(hEvent, 5000)           == WAIT_FAILED)         MessageBox(NULL,           _T("Example start failed "),           NULL, MB_OK);       CloseHandle(hEvent);     }     else       MessageBox(NULL,         _T("Could not start Example.exe"),         NULL, MB_OK);   }   SendMessage(HWND_BROADCAST, nNotifyMsg, 0, 0);   return 0; } 

The Example.exe application will signal the event when initialization is completed, which could be, for example, when WM_CREATE has been handled.

   case WM_CREATE:     HANDLE hEvent;     hEvent = CreateEvent(NULL,       TRUE, 0, _T("Examples_Event"));     ResetEvent(hEvent);     CloseHandle(hEvent);     break; 

The CreateEvent function is called, which will open the event created in Notify.exe as it is passed the same name. The ResetEvent function is called to signal the event, and this will unblock Notify.exe's call to WaitForSingleObject.

An alternative approach would be for Example.exe to run itself from CeRunAppAtTime. Then, when the Example.exe is run at the specified time, it would need to determine if it is the first instance running by calling FindWindow. If it were the first instance, Example.exe would go ahead and do the necessary processing and then quit. If it is the second instance, it should notify the first instance using SendMessage, and then quit. The first instance can then perform the necessary processing. This approach has several disadvantages:

  • Loading the application may be slow if it is large.

  • The application may take significant amounts of memory, and for a brief time, there may be two instances requiring up to twice as much memory.

  • The application will need to work out whether the user interface should be displayed depending on how the application was started.


< BACK  NEXT >


Windows CE 3. 0 Application Programming
Windows CE 3.0: Application Programming (Prentice Hall Series on Microsoft Technologies)
ISBN: 0130255920
EAN: 2147483647
Year: 2002
Pages: 181

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net