在WM5以上系統使用Notification Broker機制實現擷取全部電話狀態

來源:互聯網
上載者:User

 查了很多資料涉及到Notification Broker的都只有觸發一種狀態的代碼,但是為了一個功能改進,我需要一種能擷取多種電話狀態(呼出、呼入、通話中……)的方法,同時由於程式是需要主動觸發的,所以用RegistryNotifyApp做主動Broker,查了MSDN卻發現沒有對RegistryNotifyApp如何在多種事件中啟動做出過多說明,就繼續翻其他MSDN,終於看到在NOTIFICATIONCONDITION的解釋裡有這含義模糊的兩行文字:
dwMask
Applies only to DWORD values. This mask is applied to the changed registry value before comparison. By specifying a bit mask, the Notifications Broker notifies the clients only when specific bits in the registry value changes.
This mask is not applied to TargetValue. If dwMask is 0, TargetValue is treated as a string (type REG_SZ), otherwise it is treated as type REG_DWORD.

TargetValue
If the changed value is type REG_SZ, then comparison is done between psz and the changed value. If the changed value is type REG_DWORD, then dwMask is applied to the changed value and then the result is compared to dw. If the changed value is neither REG_SZ nor REG_DWORD, then notification is sent without any comparison. You must set dwMask to -1 to test against the whole doubleword.

可以看出,dwMask=-1好像會有什麼好玩的事情發生,立即寫代碼測試:

代碼:
#define SN_PHONECALLTALKING_ROOT HKEY_LOCAL_MACHINE#define SN_PHONECALLTALKING_PATH TEXT("System//State//Phone")#define SN_PHONECALLTALKING_VALUE TEXT("Status")#define SN_PHONECALLTALKING_BITMASK 536870912#define SN_PHONECALLCALLING_BITMASK 131072#define SN_PHONEINCOMINGCALL_BITMASK 65536#define MY_NOTIFICATION_NAME TEXT("testnotification")DWORD GetCurrentNotificationStatus(){    DWORD lpPhoneTalking = 0;    HRESULT hr;    hr = RegistryGetDWORD(SN_PHONECALLTALKING_ROOT,       SN_PHONECALLTALKING_PATH,       SN_PHONECALLTALKING_VALUE,       &lpPhoneTalking);    if(SUCCEEDED(hr))    {      if(lpPhoneTalking & SN_PHONECALLTALKING_BITMASK){        return SN_PHONECALLTALKING_BITMASK;      }else if(lpPhoneTalking & SN_PHONECALLCALLING_BITMASK){        return SN_PHONECALLCALLING_BITMASK;      }else if(lpPhoneTalking & SN_PHONEINCOMINGCALL_BITMASK){        return SN_PHONEINCOMINGCALL_BITMASK;      }else{        return lpPhoneTalking;      }    }else{      return 0;    }}HRESULT RegisterNotification(){    HRESULT hr = NULL;    NOTIFICATIONCONDITION nc;    nc.dwMask = -1;    nc.ctComparisonType = REG_CT_ANYCHANGE;    nc.TargetValue.dw = 0x01;    hr = RegistryNotifyApp(SN_PHONECALLTALKING_ROOT, SN_PHONECALLTALKING_PATH,      SN_PHONECALLTALKING_VALUE, MY_NOTIFICATION_NAME, szExeFile,      NULL, NULL, 0x00, RNAF_NONAMEONCMDLINE, &nc);    return hr;}int _tmain(int argc, _TCHAR* argv[]){    GetModuleFileName(NULL,szExeFile,256);    HRESULT hr = RegisterNotification();    LPCTSTR currStatus;    DWORD dStatus;    dStatus=GetCurrentNotificationStatus();    switch(dStatus){      case SN_PHONECALLCALLING_BITMASK:        currStatus=L"Calling";        break;      case SN_PHONECALLTALKING_BITMASK:        currStatus=L"Talking";        break;      case SN_PHONEINCOMINGCALL_BITMASK:        currStatus=L"Incoming";        break;      default:        currStatus=(LPCTSTR)dStatus;    }    MessageBox(GetActiveWindow(),currStatus,TEXT("test"),MB_SETFOREGROUND | MB_ICONINFORMATION | MB_OK);    return 0;}

執行程式,尋找註冊表果然註冊了一個新的Broker“testnotification”,然後測試呼叫電話和打出電話和接聽,成功擷取了三種狀態。

因此,如果你想在自己的Notification Broker程式裡實現監控某種事件的整個狀態,用dwMask = -1配合ctComparisonType = REG_CT_ANYCHANGE使用即可。

 

  在WM6下實現對電話進程通話狀態視窗的截獲以及Subclass Hook
首先感謝看雪論壇嵌入開發版塊的加百力和宇宙青年Yonsm對我提問文章的解答,沒有他倆我現在大概還沒思緒呢。

以及感謝今天下午MobileSide開發群裡的山夕兄的協助。

解決的關鍵如所示,這是微軟搞的一個小陷阱,偷懶一點不抓完控制項都不知道你該找那個視窗的Handle……

分別對應關係:
1.撥號

2.通話中(本文主角)

3.通話結束

這3個視窗裡的類名控制項名全都一樣,唯一不同的就是那些按鈕的文本名,還有通話狀態視窗和通話結束視窗是動態切換的,也就是平時狀態下你只能看到通話結束視窗,而通話的時候通話結束視窗是被幹掉了一堆MS_PHONE_BUTTON按鈕控制項的。

“開啟擴音器”按鈕的標識是IDC_SPEAKER(分析CProg就知道),用GetDlgCtrlID可以獲得其ID為23016

#define IDC_SPEAKER 23016

然後我們要獲得發往這個視窗和指定按鈕的訊息,所以要對其Subclass子類化,WINCE沒有SetWindowsHook等相關函數,只能用SetWindowLong來實現。

不說廢話了,還是貼代碼省事,今天忙一天又搞Dll Injection又搞回來又搞回去最後發現還是搞回來就行,累死我了……

代碼示範了對“開啟擴音器”按鈕和“開啟擴音器”菜單進行控制,代碼裡的一些ID來自實際分析,非官方標準聲明。

代碼:
#define IDM_SPEAKER 21426#define IDC_SPEAKER 23016unsigned int timerID;static WNDPROC s_OldWndProc = NULL;static WNDPROC s_OldSpkBtnProc = NULL;HANDLE s_hExit = NULL;HWND lpSpeakerPhoneBtn=NULL;LRESULT CALLBACK NewSpkBtnProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){    if(timerID!=0){      KillTimer(NULL,timerID);      timerID=0;    }    switch (uMsg)    {    case WM_LBUTTONDOWN:      {        SetSpeakerPhone();        break;      }    }    return CallWindowProc(s_OldSpkBtnProc, hwnd, uMsg, wParam, lParam);}LRESULT CALLBACK NewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){    if(timerID!=0){      KillTimer(NULL,timerID);      timerID=0;    }    switch (uMsg)    {    case WM_COMMAND:      {        //SetWindowText(lpCallStatWin,TEXT("WM_COMMAND"));        if(LOWORD(wParam)==IDM_SPEAKER) SetSpeakerPhone();        break;      }    case WM_SIZE:      {        if(wParam==SIZE_MINIMIZED) _debug(L"SIZE_MINIMIZED");        _debug(L"WM_SIZE:wParam:%08x,lParam:%08x",wParam,lParam);        break;      }    case WM_SYSCOMMAND:      {        _debug(L"SYSCOMMAND");        break;      }    case WM_ACTIVATE:      {        _debug(L"WM_ACTIVATE:wParam:%08x,lParam:%08x",wParam,lParam);        break;      }    case WM_KILLFOCUS:      {        _debug(L"WM_KILLFOCUS:wParam:%08x,lParam:%08x",wParam,lParam);        break;      }    case WM_DESTROY:      {        if (s_hExit)        {          //_debug(L"Posting exit msg...");          SetEvent(s_hExit);        }        break;      }    }    return CallWindowProc(s_OldWndProc, hwnd, uMsg, wParam, lParam);}int SetHook(HWND lpHookHwnd){    s_hExit = CreateEvent(NULL, FALSE, FALSE, NULL);    if (lpHookHwnd!=NULL)    {      lpCallStatWin=lpHookHwnd;      s_OldWndProc = (WNDPROC)GetWindowLong(lpHookHwnd, GWL_WNDPROC);      SetWindowLong(lpHookHwnd, GWL_WNDPROC, (DWORD)NewWndProc);      s_OldSpkBtnProc = (WNDPROC)GetWindowLong(lpSpeakerPhoneBtn, GWL_WNDPROC);      SetWindowLong(lpSpeakerPhoneBtn, GWL_WNDPROC, (DWORD)NewSpkBtnProc);      WaitForSingleObject(s_hExit, INFINITE);      SetWindowLong(lpHookHwnd, GWL_WNDPROC, (DWORD)s_OldWndProc);      SetWindowLong(lpSpeakerPhoneBtn, GWL_WNDPROC, (DWORD)s_OldSpkBtnProc);    }    return 0;}HWND FindPhoneHandle(){    HWND lpNextWindow = NULL;    HWND lpForeground = NULL;    TCHAR lpClassName[64];    int lpControlID;    //LPWSTR lpControlText;    //LPSTR test;    lpForeground =GetForegroundWindow();    if(lpForeground==NULL) return 0;    lpNextWindow = GetWindow(lpForeground, GW_CHILD);    lpNextWindow = GetWindow(lpNextWindow, GW_HWNDFIRST);    while(lpNextWindow!=0){      GetClassName( lpNextWindow,lpClassName,64);      //_debug(L"Main Handle:%d,ClassName:%s",lpForeground,lpClassName);      if(!_tcscmp(lpClassName,TEXT("MS_PHONE_BUTTON"))){        //確認是電話介面裡的按鈕,開始判斷IDC_SPEAKER        lpControlID=GetDlgCtrlID(lpNextWindow);        if(lpControlID==IDC_SPEAKER){          //_debug(L" Speaker found");          lpSpeakerPhoneBtn=lpNextWindow;          HWND lpRealHandle=GetParent(lpNextWindow);          //_debug(L" ParentHandle:%d,lpForeground:%d",lpRealHandle,lpForeground);          if(lpRealHandle!=NULL){            return lpRealHandle;          }          return lpForeground;        }      }      lpNextWindow = GetWindow(lpNextWindow, GW_HWNDNEXT);    }    return 0;}void CALLBACK TimeProc(HWND hwnd,                        UINT message,                      UINT idTimer,                      DWORD dwTime)     {    HWND lpCallStatusWindow;    lpCallStatusWindow=FindPhoneHandle();    if(lpCallStatusWindow!=0){      SetHook(lpCallStatusWindow);    }}int WINAPI WinMain(HINSTANCE hInstance,             HINSTANCE hPrevInstance,             LPTSTR      lpCmdLine,             int         nCmdShow){    //NOTIFICATIONCONDITION condition;    timerID = SetTimer(NULL,1,1000,TimeProc);               MSG msg;               while(GetMessage(&msg,0,0,0))               {                 //收到wm_timer訊息,處理它       //_debug(L"msg.message:%d",msg.message);      if(msg.message==WM_TIMER){        DispatchMessage(&msg);      }    }    return 0;}

http://hi.baidu.com/net%5Flk007/blog/item/8874f635a8c7921990ef395d.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.