| 首先感謝看雪論壇嵌入開發版塊的加百力和宇宙青年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;} |