首页
社区
课程
招聘
[原创]在WM6下实现对电话进程通话状态窗口的截获以及Subclass Hook
2009-4-5 23:23 12166

[原创]在WM6下实现对电话进程通话状态窗口的截获以及Subclass Hook

2009-4-5 23:23
12166
首先感谢加百力和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 23016

unsigned 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;
}


阿里云助力开发者!2核2G 3M带宽不限流量!6.18限时价,开 发者可享99元/年,续费同价!

上传的附件:
  • 1.jpg (102.11kb,98次下载)
  • 2.jpg (178.57kb,99次下载)
  • 3.jpg (167.81kb,97次下载)
  • 4.jpg (169.72kb,97次下载)
收藏
点赞7
打赏
分享
最新回复 (7)
雪    币: 2604
活跃值: (64)
能力值: (RANK:510 )
在线值:
发帖
回帖
粉丝
加百力 12 2009-4-6 09:10
2
0
NETTF小金 总结的很好,图文并茂,分析详细!一大早来就看到好帖真是心情愉快!
把遇到的问题和大家一起讨论,并将成果发布出来,这种精神很值得提倡!

也欢迎在各个嵌入式平台的学习研究的朋友发布自己的成果、资料和大家一起分享!
雪    币: 2604
活跃值: (64)
能力值: (RANK:510 )
在线值:
发帖
回帖
粉丝
加百力 12 2009-4-6 09:29
3
0
我记得:Windows CE下有SetWindowsHookEx()函数,但功能很有限。
雪    币: 164
活跃值: (10)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
NETTF小金 2 2009-4-6 10:18
4
0
据说那个SetWindowsHookEx经常返回失败~~~~我觉得奇怪的是为啥不需要DLL Inject也能做Subclass,在Win32下应该不可能哇,看过许多教程也是说要注入其他进程才能子类化,难道这一点上WM6又神奇了一把?
雪    币: 2604
活跃值: (64)
能力值: (RANK:510 )
在线值:
发帖
回帖
粉丝
加百力 12 2009-4-6 10:24
5
0
WM的内核同桌面Windows内核有很大差异。虽然表面上看,界面相似,API,MFC,.NET都非常接近,但是毕竟是资源受限的嵌入式平台上的OS所以核心部分还是做了很多剪裁。越研究到底层越会发现有很多不同之处。
雪    币: 104
活跃值: (68)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
刘国华 2009-5-17 20:59
6
0
TECHED2008上听微软的Windows CE工程师讲,WindowsCE 6之前的版本,所有的进程是共享同一个进程空间的,所以不需要注入…… 不过,Windows CE6之后就改掉了,所以还是不要依赖这个特性比较好。
雪    币: 237
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
蓝色神话 2009-11-18 20:21
7
0
同意楼上的。
雪    币: 9
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ubugmenot 2009-12-6 00:25
8
0
同意楼上的。
游客
登录 | 注册 方可回帖
返回