Introduction
A good white box testing is essential for the success of software. Testing is usually done with human interaction, which is both slow and expensive. Testing is a long process which needs a lot patience and keen observation. If it is a white box testing, then we need to follow some steps and run a lot of scenarios whenever we make a small change in our software’s code. Usually, the same steps are done by testers repeatedly. To overcome this problem, a lot of Test Automation tools are available in the market. Some of the famous GUI testing tools are IBM Rational Functional Tester from IBM and Phantom Automation Language from Microsoft.
This article is concentrated mainly on creating a miniature of a Test Automation tool, with the help of mouse and keyboard hooking. Keyboard and mouse hooking is no longer an undocumented activity. It is available in plenty on the internet. As we know, whenever a good technology is introduced, it has pros and cons. If we record the mouse and keyboard events without the knowledge of a user, then it is Trojan horse, key logger or a virus. But if it is done purposefully, then it is automation. The next few sections mentioned below will be fully concentrated on creating a Test Automation miniature with the help of global mouse and keyboard hooking. So hooking is a simple activity by which, we will be able to get the keyboard and mouse events in our application. Let us go in detail.
Background
Hooking of keyboard and mouse can be usually done in two ways:
- Thread wise Hooking
As the name reveals, it is only limited to a thread in a process. This can be useful in our software. So hook procedure can be placed either on an EXE or a DLL.
- Global Hooking
Global Hooking is a system wide hooking. The entire keyboard or mouse event is diverted to our hook procedure. The hooking function must be placed on a separate DLL in this case.
We achieve the mouse and keyboard hooking with he help of the Windows provided SetWindowHookEx WINAPI
(Hooks many types of events ). To unhook the event, we need to give UnhookWindowsHookEx WINAPI
.
To demonstrate the usage of hooking, I came up with an application RecordPlayer.exe. So let me introduce the application to you. It mainly consists of three components.
- RecordPlayer.exe
- The application that manages the keyboard and mouse hook events from the corresponding DLL.The playback operation of the recorded steps.
- KeyBoardHook.dll
- Hooking the keyboard events
- HookDll.dll
Our application consists of two operations, recording and playback. Recording is done with the help of DLLs and playback is done with the help of two APIs mainly - keybd_event
and mouse_event
. Now let us go under the hood. I will demonstrate the hooking activity with the help of keyboard hooking.
Using the Code
To start the keyboard hooking, firstly make a WIN32 DLL. Let us start with the header file of DLL.
Then Export the functions from the DLL, so that it can be accessible from our native application that is going to get the data from the hook procedure.
The code inside KeyBoardHookLib.h:
#ifdef __cplusplus
extern "C" {
#endif #define LIBSPEC __declspec(dllexport)
LIBSPEC BOOL InstallKeyBoardHook(HWND hWndParent);
LIBSPEC BOOL UnInstallKeyBoardHook(HWND hWndParent);
#undef LIBSPEC
The named events that registers to send the window message to RecordPlayer.exe.
#define UWM_KEYBOARD_MSG ("UWM_KEYBOARD_USER_MSG")
Let us become familiar with KeyBoardHookLib.cpp.
The below steps are done to share the HANDLE mentioned inside that #pragma
to be shared among DLL or to the native application from this DLL.
#pragma data_seg(".SHARE")
UINT UWN_KEYSTROKE;
HWND hWndServer = NULL;
#pragma data_seg()
#pragma comment(linker,
"/section:.SHARE,rws")
The below mentioned step is done to register the window message so that we can send the keyboard events received inside the Hook
function to the native executable.
UWN_KEYSTROKE= ::RegisterWindowMessage(UWM_KEYBOARD_MSG);
The below mentioned static
function is a keyboard procedure which receives the global keyboard events.
static LRESULT CALLBACK KeyBoardMsgProc( int nCode, WPARAM wParam, LPARAM lParam)
We start the hooking of the keyboard events once InstallKeyBoardHook is called from the parent executable.
In the SetWindowHookEx
, we have specified the first parameter as WH_KEYBOARD
to hook the keyboard event.
hook= SetWindowsHookEx( WH_KEYBOARD, (HOOKPROC)KeyBoardMsgProc, hInst, 0);
The CallNextHookEx
is a optional procedure but it is highly recommented by Microsoft. If it is not called, there is a chance that other processes that have installed hook may not get the events correctly.
CallNextHookEx(hook, nCode, wParam,lParam);
To uninstall the hook procedure, we need to call the UnhookWindowsHookEx
specifying the Handle of returned by SetWindowHookEx
.
BOOL unhooked = UnhookWindowsHookEx(hook);
Points of Interest
This tool is a miniature implementation to the test automation software. But I am sure, it will give you an idea about mouse and keyboard hooking. SetWindowsHookEx
can be used to inject a DLL into another process. In this article, we are dealing with WH_KEYBOARD
which monitors keystroke message. The keyboard input can come from the local keyboard driver or from calls to the keybd_event
function. If the input comes from a call to keybd_event
, the input is "injected". WH_KEYBOARD_LL
hook is not injected into another process, so it’s better. WH_SHELL
can be used to get notification of the shell events. SetWindowHookEx
is a very useful API, but for a good work we have to pay, so let's do so. Hooks tend to slow down the system because they increase the amount of processing the system must perform for each message. So use judiciously. If my Allah allows me, I will write more articles.
History