------------------------------------------------------------------
大家好,我是平夏雨,微软拼音的测试工程师。今天向大家介绍一个跟测试相关的具体的编程技术——如何使用钩子机制动态监控输入法。
------------------------------------------------------------------
为了自动化测试输入法,我们经常需要动态的得到各种输入法程序的候选项。得到它们的方法有很多,例如可以使用内部的API,当然前提是可以得到这些API;使用UI Automation的机制,将来有机会可以有其他篇幅来介绍;另外就是今天我们今天要介绍的钩子机制。
钩子机制是Windows系统的一种标准机制。钩子程序能够截获Windows程序的各种消息并对其进行处理,有点像是一个后门程序。
钩子程序有很多种类型,例如:
· 键盘钩子可以监控各种键盘消息 (WH_KEYBOARD, WH_ KEYBOARD_LL)
· 鼠标钩子可以监控各种鼠标消息 (WH_MOUSE, WH_MOUSE_LL)
· 外壳钩子可以监控各种外壳事件消息 (WM_SHELL)
· 日志钩子可以监控从系统消息队列中取出的各种事件消息 (WH_JOURNALPLAYBACK, WH_JOURNALRECORD)
· 窗口过程钩子可以监控所有目标窗口的消息 (WH_CALLWNDPROC, WH_CALLWNDPROCRET)
以动态得到输入法的候选项为例,要用到的钩子是WH_GETMESSAGE类型的线程钩子,这个类型的钩子用来监控从GetMessage或者PeekMessage函数返回的消息。可以使用WH_GETMESSAGE钩子来监控鼠标和键盘输入,以及其他发送到消息队列中的消息。
使用SetWindowsHookEx来设置钩子。
hhook = SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)HookProcess,hModule,threadid)
其中HookProcess是我们需要准备的钩子程序,hModule是所在dll的句柄,threadid是被监控线程的Id号。hhook是返回的对应钩子函数的句柄,之后撤销钩子的时候要用到。
LRESULT CALLBACK HookProcess(int nCode,WPARAM wParam,LPARAM lParam)
钩子函数是一种回调函数,函数体可以这样写:
PMSG pmsg = (PMSG)lParam;
// 只关心WM_IME_NOTIFY这个消息,对应输入法程序的变化
if (pmsg->message == WM_IME_NOTIFY)
{
// 这里只关心IMN_CHANGECANDIDATE这个消息,输入法选项的变化
if (pmsg->wParam & IMN_CHANGECANDIDATE)
{
// 获取当前正在输入的窗口的输入法句柄
hIMC = ImmGetContext(hWnd);
// 通过句柄得到IMC结构 (input method context)
lpImc = ImmLockIMC(hIMC);
// 得到候选项信息
lpCandInfo = (LPCANDIDATEINFO)ImmLockIMCC(lpImc->hCandInfo);
// 得到输入法的候选项列表
lpCandList = (LPCANDIDATELIST)(((LPBYTE)lpCandInfo) + lpCandInfo->dwOffset[0]);
// 成功:)之后就可以做进一步的处理
}
}
UnhookWindowsHookEx(hhook)
这里用到了之前设置钩子的时候用到的句柄。由于钩子程序消耗较多的系统资源,所以我们在用完了之后要及时地撤销钩子。
总而言之,钩子机制是一种很强大的机制,在监听消息方面可以说是无所不能。使用这种机制得到输入法的候选项由于是基于消息的,所以和具体的输入法无关。
参考文献:
MSDN 钩子机制 http://msdn.microsoft.com/en-us/library/ms644959(VS.85).aspx