Windows CE Notification API的使用方法

來源:互聯網
上載者:User

1 引言
      以Windows CE 為作業系統的掌上型電腦(如PocketPC或HPC),除具備PC的功能外,還具備很強的自身控制能力。Windows CE API超越微軟其他動作系統的 API的一個方面是他提供了一個強有力的通知介面(Notification API),該介面允許應用程式自己安排自己在某個確定的時間運行,或在某個系統事件發生時運行,這使得我們能夠應用他來設計研發各種進階控製程式,比如按時間或預訂的事件來自動開啟/關閉電腦,或按時間或預訂的事件來自動開啟/關閉一個或多個應用程式,乃至控制一個或多個應用程式的運行流程。
2  通知API的解析
      所謂通知是作業系統對發生的某個事件所發出的響應訊號。Windows CE對定時器事件發出的響應訊號即“定時器事件通知”,而對系統事件發出的響應訊號即“系統事件通知”。定時器事件表明已到達指定時間,系統事件表明發生了系統級事件,如添加或刪除了某裝置,系統時間更改了,和其他裝置發生同步,檢測到RS232口串連等。假如我們要在給定的時間直接運行某個應用程式(不用使用者幹涉),就能夠簡單地使用“定時器事件通知”,而當我們需要監控一些系統事件的發生時,就要使用″系統事件通知″。特別需要強調的是:除非不安裝電池或處於死機狀態,否則掌上型電腦的電源始終不關閉;當使用者按下關閉電源開關或不使用時,機器也只是處於休眠狀態而並沒有真正切斷電源(在休眠狀態下,他僅提供能保持其時鐘、應用程式及RAM中儲存的資料所需的最少能量)。因此,對於註冊使用“定時器事件通知”或″系統事件通知″的程式,即使系統是關閉的,當定時器事件到達時或發生系統事件時,要啟動並執行應用程式也會啟動。
      上述的“定時器事件通知”的使用雖然方便,但有時不能滿足使用者的需要。比如對於複雜的控制流程程,不但到了指定時間要運行應用程式,而且要根據使用者的不同反應進行不同的控制。因此,Windows CE還提供了第三種通知介面: ″使用者通知″。″使用者通知″也使用定時器事件,但和“定時器事件通知”不同,“使用者通知”發生時必須被使用者確認,從而到了“使用者通知”指定的時間可根據使用者的不同反應進行不同的流程式控制制。比如,當使用者僅需在指定的時間作一下提示,則使用“使用者通知”的應用程式可設計為以四種方式(閃動LED,震動裝置,播放聲音和顯示提示框)提示使用者,而且使用者可隨時變更提示方式。又比如,當使用者需要不但在指定的時間作一下提示,還要在使用者做出確認後才使程式繼續運行,這就只能使用“使用者通知”而不能使用“定時器事件通知”。
    當我們把自己研發的程式註冊到特定的事件通知後,作業系統將在該事件發生時產生一個通知。系統使用通知和使用者和其他程式通訊。Windows CE共提供了六個通知介面:
CeSetUserNotification
CeGetUserNotificationPreferences
CeClearUserNotification
CeHandleAppNotifications
CeRunAppAtTime和CeRunAppAtEvent

前四個為″使用者通知″所使用,後兩個分別為“定時器事件通知”和″系統事件通知″所使用。下面分別介紹這六個API的使用方法:
(1)函數CeSetUserNotification用於註冊使用者通知,其原型是:
    HANDLE CeSetUserNotification(HANDLE hNotification,
                                                TCHAR* pwszAppName,
                                                SYSTEMTIME* lpTime,
                                                PCE_USER_NOTIFICATION lpUserNotification);
其參數含義是:

控制代碼hNotification配置為0表示建立一個新的通知,而要更改登入的通知則配置hNotification為希望更改的使用者通知的控制代碼(這個控制代碼是由註冊使用者通知的程式在調用CeSetUserNotification後的傳回值);

pwszAppName是該應用程式的名稱,當通知發生時,該應用程式的小表徵圖將在工作列上顯示;lpTime是個指向SYSTEMTIME結構指標,該結構指定了通知發生的時間;lpUserNotification也是個結構指標,他指向PCE_USER_NOTIFICATION結構, Windows CE用該結構描述使用者怎樣被通知,這個結構的定義是:
typedef struct UserNotificationType {
  DWORD ActionFlags;
  TCHAR* pwszDialogTitle;
  TCHAR* pwszDialogText;
  TCHAR* pwszSound;
  DWORD nMaxSound;
  DWORD dwReserved;
} CE_USER_NOTIFICATION, *PCE_USER_NOTIFICATION;

其中變數ActionFlags是一組定義了在到達指定的時間時以何種形式提示使用者的標誌:

PUN_LED(閃動螢幕),

PUN_VIBRATE(震動裝置),

PUN_DIALOG(顯示對話方塊),

PUN_SOUND(播放聲音文檔)

PUN_REPEAT(重複聲音文檔10到15秒),

他能夠是上述標誌的任意組合。從程式調用CeSetUserNotification開始到使用者得到通知的這一時間段中,通知一直處於活動狀態。如要在他逾時之前修改此通知,程式可通過再次調用CeSetUserNotification來實現

(2)調用CeGetUserNotificationPreferences,函數原型為:
BOOL CeGetUserNotificationPreferences(HWND hWndParent, PCE_USER_NOTIFICATION lpNotification);
這個函數可配置使用者通知,以便讓使用者能有修改提示方式的機會,其中hWndParent是提示框父視窗的視窗控制代碼。

(3)調用CeClearUserNotification能夠實現在使用者通知到達之前清除他。

(4)調用CeHandleAppNotifications 函數以確認使用者通知。使用者通知到達後需要確認。對於顯示提示框的通知,確認的方式是點擊提示框的確定按鈕或按下裝置外殼上的通知按鈕(此時使用者通知僅起到提示的作用,不啟動應用程式);對於不顯示提示框的通知,系統將在工作列上顯示註冊該通知的程式的表徵圖,當使用者點擊此表徵圖時系統將啟動相應的應用程式的一個執行個體(系統還傳遞一個命令列參數lpCmdLine以表明為什麼應用程式會運行,該參數是串 APP_RUN_TO_HANDLE_NOTIFICATION加空格加通知的控制代碼)。對於不顯示提示框的使用者通知,在應用程式中要調用 CeHandleAppNotifications 函數來確認通知,該函數將任何用於應用程式的活動通知都標記為已處理,並刪除工作列上的表徵圖。在實際編碼時還要考慮是否有該應用程式的另一個執行個體在運行,如有,則應向他發送一個自訂訊息由該執行個體處理此通知並終止自身以節省資源。

(5)調用CeRunAppAtTime產生“定時器事件通知”,函數原型為:
BOOL CeRunAppAtTime(TCHAR* pwszAppName, SYSTEMTIME* lpTime );

其參數含義是:

lpTime是個結構指標,該結構指定了運行應用程式的時間;

pwszAppName是要啟動並執行應用程式的名稱。由於只是在給定的時間自動運行某個應用程式,因此比較簡單。要修改“定時器事件通知”,只要再次調用CeRunAppAtTime。因為後一次調用CeRunAppAtTime將替換前一次的通知。要清除“定時器事件通知”,只要在調用CeRunAppAtTime時,在參數lpTime中傳遞一個NULL指標。

(6)調用CeRunAppAtEvent產生″系統事件通知″,函數原型:
BOOL CeRunAppAtEvent(TCHAR* pwszAppName, LONG lWhichEvent);

其參數含義是:

pwszAppName是要啟動並執行應用程式的名稱;

lWhichEvent 是指出要監控哪一個事件,標誌常量如下:
NOTIFICATION_EVENT_NONE                   清除事件通知
NOTIFICATION_EVENT_SYNC_END            同步完成通知
NOTIFICATION_EVENT_DEVICE_CHANGE   添加或刪除裝置通知
NOTIFICATION_EVENT_RS232_DETECTED 檢測到RS232串連通知
NOTIFICATION_EVENT_TIME_CHANGE       系統時間更改通知
NOTIFICATION_EVENT_RESTORE_END      裝置恢複完成通知

要停止回應系統事件通知,應用程式只要再次調用CeRunAppAtEvent,並在lWhichEvent參數中傳遞其名稱和NOTIFICATION_EVENT_NONE。

3  通知API的使用代碼執行個體
#include <Notify.h>               
CE_USER_NOTIFICATION g_ceun;
(1) 對CE_USER_NOTIFICATION結構初始化的程式碼片段. 

  memset (&g_ceun, sizeof(g_ceun));
  g_ceun.ActionFlags = PUN_DIALOG;
  g_ceun.pwszDialogTitle = szDlgTitle;
  g_ceun.pwszDialogText = szDlgText;
  g_ceun.pwszSound = szSound;
  g_ceun.nMaxSound = sizeof(szSound);

(2)註冊使用者通知的程式碼片段:
  SYSTEMTIME st;   

  GetLocalTime (&st);
  GetModuleFileName (hInst, szExeName,sizeof(szExeName));
    hNotify = CeSetUserNotification (0, szExeName,&st, &g_ceun);

(3)配置使用者通知的程式碼片段:
  CeGetUserNotificationPreferences(hWnd, &g_ceun);

(4)使用CeHandleAppNotifications並只運行一個執行個體(為節省資源)的程式碼片段 :
//判斷應用程式的啟動是否源於使用者通知
If (lstrcmp(szText,APP_RUN_TO_HANDEL_NOTIFICATION==0)
      GetModuleFileName (hInst, szText, sizeof(szText));

CeHandleAppNotifications (szText);
hNotify =(HANDLE)_wtol(pPtr); //取通知的控制代碼
//檢查是否已有應用程式的執行個體在運行
hWnd = FindWindow(NULL, szAppName);
if(hWnd)//如有,向他發送一個自訂訊息,由他處理此使用者通知
     SendMessage(hWnd, MYMSG_TELLNOTIFY, 0, (LPARM)hNotify);

//終止自身, 代碼略去

(5)使用“定時器事件通知”的程式碼片段:
SYSTEMTIME st;   

GetLocalTime (&st);
GetModuleFileName (hInst, szExeName, sizeof(szExeName));
CeRunAppAtTime (szExeName, &st);

(6)使用“系統事件通知”的程式碼片段:
  LONG lEvent;
if (IsDlgButtonChecked(hWnd, IDC_SYNC_END) ==1)
     lEvent != NOTIFICATION_EVENT_SYNC_END;
if (IsDlgButtonChecked(hWnd, IDC_SERIAL_DETECT)==1) 
     lEvent !=NOTIFICATION_EVENT_RS232_DETECTED;
if (IsDlgButtonChecked(hWnd, IDC_DEVICE_CHANGE)== 1)
     lEvent != NOTIFICATION_EVENT_DEVICE_CHANGE;
if (IsDlgButtonChecked(hWnd, IDC_TIME_CHANGE)==1)
     lEvent != NOTIFACTION_EVENT_TIME_CHANGE;
if (IsDlgButtionChecked(hWnd, IDC_RESTORE_END) ==1)
     lEvent != NOTIFICATION_EVENT_RESTORE_END;

GetModuleFileName (hInst, szExeName, sizeof(szExeName);
CeRunAPpAtEvent(szExeName, lEvent);
    以上我們介紹了Windows CE Notification API的使用方法,關於Windows CE應用程式研發環境的使用。

 

  • 如何去掉工作列上的Notification

分為兩種情況:

一、自己用SHNotificationAdd 建立出來的Notification,當然是用SHNotificationRemove來去掉了。

二、系統的Notification(比方說未接電話、新簡訊之類的),可以用以下的方法:

通過修改註冊表[HKEY_CURRENT_USER\System\State]下一些相關的索引值。e.g.

要去掉未接電話Notificatio,修改如下:

[HKEY_CURRENT_USER\System\State\Phone]

"Missed Call Count"=0

去掉新短訊息Notification,修改如下:

[HKEY_CURRENT_USER\System\State\Messages\sms\Unread]

"Count"=0

上次說修改索引值來達到刪除Notification的目的,但可能會產生副作用,比方說Today Screen裡面的計數可能會因為這個註冊表的改動而顯示了錯誤的值。

[HKEY_CURRENT_USER\System\State\Messages\sms\Unread]

"Count"=0

後來在網上搜了一下,codeproject上有個人是通過SHNotificationRemove實現的,我修改了一下,sample code如下:

void RemoveNewMessageNotification() 

    SHNOTIFICATIONDATA shnd; 
    CLSID clsid; 
    LRESULT result; 
    DWORD dwID = 0;

    if (0 == CLSIDFromString(TEXT("{A877D65B-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 < 20000)); 
    }
}

 

  • 系統功能表擴充

系統功能表的擴充是通過COM來實現的,主要工作有兩個:代碼實現和建立註冊表索引值。

1. 代碼實現:

實現介面為IObjectWithSite和IContextMenu。當然,還包括IClassFactory,它協助產生指定CLSID的對象,它的代碼其實都是千篇一律,把sample中的代碼稍微修改一下就可以用了。

具體的實現請參考<SDK安裝路徑>\Samples\Common\CPP\Win32\InboxMenuExtensibility下的一個例子,它擴充了tmail.exe(Messaging) message list下的menu。

關鍵的實現主要還是在QueryContextMenu和InvokeCommand,QueryContextMenu一般用來添加菜單的操作,InvokeCommand是用於點擊你剛添加的功能表項目時的響應。值得一提的是QueryContextMenu的傳回值,應設為你添加的功能表項目個數,一般實現為return MAKE_HRESULT(SEVERITY_SUCCESS, 0, nMenuAdded); 這樣系統就知道你到底添加了多少菜單,別人調用QueryContextMenu的時候idCmdFirst才是正確的。比方說其它應用程式恰好也在這個菜單裡加了功能表項目,就不會引起衝突(衝突就是說比方說點了你的功能表項目,結果響應的卻是其它軟體加的功能表項目的命令)。而且Smart Phone也比較特殊,每進到一個popup menu就會響應一下QueryContextMenu,所以一般都是計算當前快顯功能表的功能表項目個數來避免每次進去一個popup menu都添加功能表項目。

 

2. 註冊表索引值的建立:

[HKEY_CLASSES_ROOT\CLSID]下建立一個key,name為你所用的CLSID,再在這個key下面建立一個key,name為InProcServer32,預設值設為你的DLL。

[HKEY_LOCAL_MACHINE\Software\Microsoft\Shell\Extensions\ContextMenus]下建立的key需要根據你擴充菜單的位置來決定的,具體的值請看SDK document中的Menu Overview。

 State and Notifications Broker

 State and Notifications Broker提供了一個在註冊表中儲存系統和應用程式資訊的機制和一個儲存資訊改變的通知系統。它可以用於監控系統中的任何註冊表索引值。通知種類包括以下幾種:

System state information, such as features present (camera, keyboard), active application, cradled state, battery state.
Message information, such as count of unread, last received, account info.
Tasks and appointments information, such as upcoming, overdue, location.
Windows Media Player information, such as currently playing album, artist.
Phone information, such as signal information, operator information, call information, multiline information.
Connections information, related to bluetooth, cellular, network, modem, etc.
snapi.h中包含了需要監控的註冊表Key、Path、Value Name和Mask,比方說你想知道現在的phone處在一個什麼狀態,可以看到snapi.h中有這麼一段:

////////////////////////////////////////////////////////////////////////////////
// PhoneRoaming
// Gets a value indicating whether the phone is currently in roaming mode.
#define SN_PHONEROAMING_ROOT HKEY_LOCAL_MACHINE
#define SN_PHONEROAMING_PATH TEXT("System\\State\\Phone")
#define SN_PHONEROAMING_VALUE TEXT("Status")
#define SN_PHONEROAMING_BITMASK 0x200

        當索引值[HKLM\System\State\Phone] "Status"值的0x200這一位上為1時,說明phone處在漫遊狀態。

        那麼,如何監控註冊表索引值呢?可以用RegistryNotifyApp、RegistryNotifyWindow、RegistryNotifyCallback等API。以下是Sample Code:

#include <snapi.h>
#include <regext.h>

#define UM_REGNOTIFY    WM_USER+1000

// Global Variables:
HREGNOTIFY          g_hRegNotify;

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message) 
    {
        case WM_CREATE:
            NOTIFICATIONCONDITION nc;
            ZeroMemory(&nc, sizeof(NOTIFICATIONCONDITION));
            nc.ctComparisonType = REG_CT_EQUAL;
            nc.dwMask = 0x200;
            nc.TargetValue.dw = 0x200;
            RegistryNotifyWindow(SN_PHONEROAMING_ROOT, SN_PHONEROAMING_PATH, SN_PHONEROAMING_VALUE, hWnd, UM_REGNOTIFY, 0, &nc, &g_hRegNotify);
            break;
        case UM_REGNOTIFY:
            MessageBox(hWnd, _T("Phone is roaming!"), _T("Notification Broker"), MB_OK);
            break;
        case WM_DESTROY:
            RegistryCloseNotification(g_hRegNotify);
            PostQuitMessage(0);
            break;

        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

 

本文來自CSDN部落格,轉載請標明出處:http://www.cnblogs.com/Kane_zzt/admin/file:///C:/Documents%20and%20Settings/Kane/案頭/WINCE/Windows%20CE%20Notification%20API的使用方法.mht

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.