使用钩子记录鼠标点击处网页元素
来源:互联网 发布:毕向东java教学视频 编辑:程序博客网 时间:2024/06/17 17:35
1、目的
研究自动化测试中的录制、回放实现方法。通过钩子录制鼠标、键盘的记录,然后再进行回放。
2、方法
windows下的钩子有很多类型,这里采用WH_JOURNALRECORD和WH_JOURNALPLAYBACK这一对钩子实现录制和回放。
2.1 钩子的安装
在所有钩子中,WH_JOURNALRECORD和WH_JOURNALPLAYBACK是特殊的一对,可以不通过DLL就能够实现全局效果。因此只需要在主程序中通过调用windows api 安装即可。
SetWindowsHookEx(WH_JOURNALRECORD,JournalRecordProc,hinstance,0);
2.2 钩子处理函数
根据WH_JOURNALRECORD钩子的标准定义,钩子处理函数定义为:
LRESULT CALLBACK JournalRecordProc(int code,WPARAM wparam,LPARAM lparam)
其中参数lparam为传进的消息。
如果只需要将消息记录,那么通过下面的代码就可以实现:
switch (code)
{
case HC_ACTION:
mesg=(EVENTMSG *)lparam;
if (mesg->hwnd!=thiswindow_hwnd){
mesg->time=mesg->time-start_time;
output->write((const char *)mesg,sizeof(EVENTMSG)); //output为输出文件流
output->flush();
}
break;
default:
return CallNextHookEx(hook_handle,code,wparam,lparam);
}
但是如果只记录消息,不利于录制之后的二次编辑,不利于实现关键字驱动的自动化测试。因此,需要在记录时对消息进行提取,简单的讲就是当鼠标点击网页时,钩子只能记录一个鼠标点击消息。但是我们还需要得到点击的网页元素是什么,id是什么之类的信息。
根据鼠标点击时的坐标,我们可以得到HTML信息。
2.3 根据坐标获得网页元素
我们可以根据IHTMLDocument2接口提供的方法获得所在坐标的html element。
HRESULT elementFromPoint(long x,
long y,
IHTMLElement **elementHit );
现在的问题是我们只有通过钩子记录的鼠标点击发送的消息。没关系,我们对消息进行分析。当钩子记录的消息类型为WM_LBUTTONDOWN时,消息的参数paramL表示横坐标,paramH表示纵坐标。这下坐标有了,就差获得当前网页窗口的IHTMLDocument2对象了。
2.4 根据句柄获得IHTMLDocument2对象
我们现在能够得到当前浏览器窗口的句柄,因为当鼠标点击网页元素时,WM_LBUTTONDOWN消息的hwnd参数记录的正是该消息发送的目标窗口句柄,即当前操作的浏览器窗口句柄。通过调用"OLEACC.DLL"库来实现。以下代码来自MSDN的开源代码,可以直接使用。
IHTMLDocument2* GetDocInterface(HWND hWnd)
{
CoInitialize( NULL );
// 我们需要显示地装载OLEACC.DLL,这样我们才知道有没有安装MSAA
HINSTANCE hInst = ::LoadLibrary( _T("OLEACC.DLL") );
IHTMLDocument2* pDoc2=NULL;
if ( hInst != NULL ){
if ( hWnd != NULL ){
CComPtr< IHTMLDocument2 > spDoc=NULL;
LRESULT lRes;
// 由于WM_HTML_GETOBJECT非Windows标准消息,所以需要RegisterWindowMessage
UINT nMsg = ::RegisterWindowMessage( _T("WM_HTML_GETOBJECT") );
::SendMessageTimeout( hWnd,
nMsg,
0L,
0L,
SMTO_ABORTIFHUNG,
1000,
(DWORD*)&lRes );
//取得ObjectFromLresult函数的地址
LPFNOBJECTFROMLRESULT pfObjectFromLresult =(LPFNOBJECTFROMLRESULT)::GetProcAddress( hInst, _T("ObjectFromLresult") );
if ( pfObjectFromLresult != NULL ){
HRESULT hr;
hr = (*pfObjectFromLresult)(lRes,IID_IHTMLDocument, 0,(void**)&spDoc);
if ( SUCCEEDED(hr) ){
CComPtr< IDispatch > spDisp;
CComQIPtr< IHTMLWindow2 > spWin;
spDoc->get_Script( &spDisp );
spWin = spDisp;
spWin->get_document( &pDoc2 );
}
}
}
::FreeLibrary(hInst);
}
else{//如果没有安装MSAA
AfxMessageBox(_T("请您安装Microsoft Active Accessibility"));
}
return pDoc2;
}
2.5 困扰很长时间的问题
一切看起来都是那么完美,好像问题迎刃而解?
但是运行时发现,钩子一开始记录网页,就卡死。但是单步调试没有问题。仔细分析,发现了问题的所在。
当钩子被启动以后,原来程序是在钩子中调用GetDocInterface方法,目的是获得坐标处的HTML,但是仔细看看GetDocInterface方法。其中,SendMessageTimeout函数的含义是,如果是在跨线程中调用,则必须等到接收消息的窗口处理完原信息之后再响应该消息。此时,发送消息的是钩子线程,而接收消息的是浏览器。那么意味着钩子线程必须等待直至浏览器处理完消息,但是浏览器此时还需等待钩子程序对钩子消息进行处理。这样就形成了死锁。
解决的办法是,在钩子处理函数中,创建一个线程,该线程用来处理GetDocInterface函数原本处理的工作。这样钩子处理程序就不需要等待SendMessageTimeout消息的处理,这样就不会形成死锁。
这样处理之后,实验证明问题解决。
2.6其它小问题
包括用户区坐标和屏幕坐标的转换等小问题,也要注意。
- 使用钩子记录鼠标点击处网页元素
- VB 用全局钩子,记录鼠标点击次数
- C# 鼠标钩子使用
- C#使用鼠标钩子
- 关于鼠标钩子使用入门
- 关于鼠标钩子使用入门
- 如何在网页中禁止使用鼠标右键?如何禁止鼠标点击?
- 鼠标钩子 键盘钩子
- 鼠标钩子
- 使用钩子函数屏蔽键盘或鼠标
- 使用C#钩子监视全局鼠标位置
- 如何使用Win32Api创建鼠标钩子
- c#使用钩子拦截鼠标键盘事件
- 钩子函数-建立键盘鼠标动作记录与回放
- Javascript判断鼠标在元素外点击
- Javascript判断鼠标在元素外点击
- javascript 获取鼠标点击的元素
- 网页效果获取鼠标点击的位置
- 【网摘整理】30而立
- ue技巧,替换空行
- char 转为 CString
- Maven的基本原理和Maven2的新特性
- Xdebug Errors: xdebug(32) : error C2365: 'operator new' : redefinition; previous definition was 'function'
- 使用钩子记录鼠标点击处网页元素
- 视线语音鼠标 2 C#视频捕获
- 游戏开放平台开发历程
- FT5406电容屏驱动移植总结
- vs2010+windows phone7 sdk tool初体验
- Oracle忘记用户密码解决方案
- 创建一个自定义的 Halo Accordion header skin
- php调试环境搭建--zendstudio+xdebug
- Cypress 和 FT5406 电容屏调试记录