The Windows system is built on the event-driven mechanism, which is to put it bluntly that the entire system is implemented through message delivery. The hook is a very important system interface in Windows system, it can intercept and process the message to other applications, to complete the function that ordinary application is difficult to implement. Hooks can monitor various event messages in the system or process, intercept messages destined for the target form, and process them. In this way, we can install their own defined hooks in the system, monitor the occurrence of specific events in the system, and complete specific functions, such as intercepting the keyboard, mouse input, screen fetching words, log monitoring and so on. Can be seen, the use of hooks to achieve a number of special and practical functions. Therefore, it is very necessary for the advanced programmer to master the hook programming method.
Types of Hooks
A By event category, there are several types of frequent use such as the following
(1) Keyboard hooks and low-level keyboard hooks can monitor various keyboard messages.
(2) Mouse hooks and low-level mouse hooks can monitor various mouse messages.
(3) Shell hooks can monitor various shell event messages. For example, start and close the application.
(4) Log hooks can record various event messages taken from the system message queue.
(5) The form procedure Hooks monitor all messages sent from the system message queue to the target form.
In addition, there are some specific event hooks available for us to use, not listed.
The following description describes the types of hooks that are used frequently:
1, Wh_callwndproc and Wh_callwndprocret Hooks
Wh_callwndproc and Wh_callwndprocret hooks enable you to monitor messages sent to the form process. The system calls the Wh_callwndproc hook before the message is sent to the Receive form procedure, and calls Wh_callwndpro after the form process finishes processing the message
Cret Hook. The Wh_callwndprocret hook passes the pointer to the CWPRETSTRUCT structure, which is then passed to the hook path. The CWPRETSTRUCT structure includes the return value of the form procedure from which the message was processed, as well as the number of message parameters associated with the message.
2, WH_CBT Hook
The system calls the WH_CBT hook thread before the following events, which include:
1. Activate, build, destroy, minimize, maximize, move, resize, etc. form events;
2. Complete the system instructions;
3. Mobile mouse, keyboard events from the system message queue;
4. Set input focus events;
5. Synchronize system Message Queuing events.
The return value of the hook determines whether the system agrees or prevents one of these operations.
3, Wh_debug Hook
The system calls the Wh_debug hook before the hook thread that is associated with the other hooks in the system call system. You can use this hook to decide whether or not to agree to the system calling the hooks associated with other hooks.
4, Wh_foregroundidle Hook
When the foreground thread of an application is in the spare state, a low-priority task can be run with wh_foregroundidle hooks. When the foreground thread of the application is about to become spare state, the system calls the Wh_foregroundidle hook thread.
5, Wh_getmessage Hook
The application uses wh_getmessage hooks to monitor the messages returned from the GETMESSAGE or PeekMessage function. You can use the Wh_getmessage hook to monitor mouse and keyboard input, as well as other messages sent to the message queue.
6, Wh_journalplayback Hook
Wh_journalplayback hooks enable applications to insert messages into the system message queue. The ability to use this hook to replay successive mouse and keyboard events recorded by using the Wh_journalrecord hook. Only the Wh_journalplayback hook has been installed, the normal mouse and keyboard events are invalid. The Wh_journalplayback Hook is a global hook that cannot be used as a thread-specific hook. Wh_journalplayback Hook returns the timeout value, which tells the system how long (in milliseconds) to wait before processing the current message from the playback hook. This enables the hook to control the playback of real-time events. Wh_journalplayback are system-wide local hooks and they will not be injected into any of the travel address spaces. (The key wizard is expected to be made with this hook)
7, Wh_journalrecord Hook
Wh_journalrecord hooks are used to monitor and record input events. Typically, you can use this hook to record continuous mouse and keyboard events, and then back and forth by using the Wh_journalplayback hook. The Wh_journalrecord Hook is a global hook that cannot be used as a thread-specific hook. Wh_journalrecord are system-wide local hooks and they will not be injected into any of the travel address spaces.
8, Wh_keyboard Hook
In the application, Wh_keyboard hooks are used to monitor wm_keydown and WM_KEYUP messages, which are returned by GetMessage or PeekMessage function. The ability to use this hook to monitor keyboard messages entered into the message queue.
9, Wh_keyboard_ll Hook
The Wh_keyboard_ll hook monitors the keyboard messages entered into the thread message queue.
10, Wh_mouse Hook
Wh_mouse Hooks monitor Mouse messages returned from the GetMessage or PeekMessage functions. Use this hook to monitor mouse messages entered into the message queue.
11, Wh_mouse_ll Hook
WH_MOUSE_LL Hooks monitor Mouse messages that are entered into the thread message queue.
12, Wh_msgfilter and Wh_sysmsgfilter Hooks
Wh_msgfilter and Wh_sysmsgfilter hooks enable us to monitor menus, scroll bars, message boxes, dialog box messages and find that users use ALT + TAB or ALT+ESC key combinations to switch forms. Wh_msgfilter hooks can only monitor messages that are passed to menus, scroll bars, message boxes, and messages that are passed to a dialog box created by an application that has a hook thread installed. Wh_sysmsgfilter Hooks monitor all application messages. Wh_msgfilter and Wh_sysmsgfilter hooks enable us to filter messages during the pattern cycle, which is equivalent to filtering messages in the main message loop. The Wh_msgfilter Hook can be called directly by calling Callmsgfilter function. By using this function, the application can use the same code to filter the message during the pattern loop, as in the main message loop.
13, Wh_shell Hook
The shell application can use the Wh_shell hook to receive important notifications. When the shell application is active and the When top layer form is established or destroyed, the system calls the Wh_shell hook thread.
Wh_shell has 5 in common:
1. Only a top-level, unowned form is created, acted on, or destroyed;
2. When taskbar need to redraw a button;
3. When the system needs to display a minimal form of a program about taskbar;
4. When the current keyboard layout state changes;
5. When the user presses CTRL+ESC to run task Manager (or the same level of program).
As a rule, shell applications do not receive Wh_shell messages. Therefore, before an application can receive Wh_shell messages, the application must call the SystemParametersInfo function to register itself.
These are the 13 types of hooks that are commonly used!
Two The main thread hooks and system hooks are categorized by use range
(1) Thread hooks monitor event messages for the specified thread.
(2) System hooks Monitor event messages for all threads in the system. Because the system hooks affect all applications in the system, the hook function must be placed in a separate dynamic link library (DLL)
In This is a very big difference between the system hooks and the thread hooks.
A few points to note:
(1) Assuming that the same event (such as a mouse message) has both a thread hook installed and a system hook installed, then the system will proactively call the thread hooks, and then call the system hooks.
(2) Multiple hook processes can be installed on the same event message, and these hook processes form a chain of hooks. The hook information should be passed to the next hook function at the end of the current hook processing. And recently installed hooks are placed at the beginning of the chain, and the first installed hooks at the end, that is, after the addition of the first gain control.
(3) Hooks, especially system hooks, consume message processing time and reduce system performance. Only when necessary to install the hook, after the use of the time to uninstall.
Write a hook program
The procedure for writing hooks is divided into three steps: defining hook functions, installing hooks, and unloading hooks.
1. Defining hook functions
The hook function is a special callback function. After the specific event that the hook is monitored, the system calls the hook function for processing. The form of the hook function for different events is not the same. The following example illustrates the prototype of the hook function with the mouse hook function:
LRESULT CALLBACK HookProc (int nCode, WPARAM wparam,lparam LPARAM)
The parameters wparam and lparam include information about the hooked message, such as the mouse position, status, keyboard keys, and so on. Ncode includes information about the message itself, such as whether to move out of the message queue.
We first implement our own defined function in the hook function, and then call the function CallNextHookEx. Pass the hook information to the next hook function in the hook chain. The prototypes for CallNextHookEx are as follows:
LRESULT CallNextHookEx (hhook hhk, int nCode, WPARAM WPARAM, LPARAM LPARAM)
The parameter hhk is the hook handle. NCode, wparam, and lparam are hook functions.
It is also possible to discard the message by directly returning true to prevent the message from being passed.
2. Mounting hooks
At the time of program initialization, call function SetWindowsHookEx install hooks. Its function prototypes are:
Hhook SetWindowsHookEx (int idhook,hookproc lpfn, INSTANCE hmod,dword dwthreadid)
The parameter Idhook represents the hook type, which corresponds to the hook function type one by one. For example, Wh_keyboard indicates that a keyboard hook is installed, Wh_mouse is a mouse hook, and so on.
LPFN is the address of the hook function.
Hmod is the handle to the instance where the hook function resides. For thread hooks, the parameter is null, and for system hooks, the reference is the DLL handle where the hook function resides.
DWTHREADID Specifies the thread number of the thread that the hook is monitoring. For global hooks, the number of the parameters is null.
SetWindowsHookEx returns the installed hook handle.
3. Uninstalling Hooks
When you no longer use hooks, you must uninstall them in a timely manner. Simply call the function BOOL UnhookWindowsHookEx (hhook hhk) and you can.
It is important to note that the position of the hook function of the thread hook and the system hook is very big difference. Thread hooks are generally in the current thread or in a thread that derives from the threads, and the system hooks must be placed in a separate dynamic link library, which is a bit cumbersome to implement.
Programming examples of thread hooks:
Follow the method described above to implement a thread-level mouse hook. The hook tracks the position change information of the mouse movement of the current form. and output to the form.
(1) using MFC in vc++6.0
APPWizard (EXE) generates a single document application Mousehook that does not use the document/view structure. Open the Childview.cpp file and add the global variables:
Hhook hhook;//Mouse Hook handle
CPoint point;//Mouse location information
CChildView *pview;
The output form pointer used by the mouse hook function
The following code is added for example in Cchildview::onpaint ():
CPAINTDC DC (this);
Char str[256];
sprintf (str, "x=%d,y=%d", POINT.X,POINT.Y);
Construct a string
dc. TextOut (0,0,STR); Display string
(2) The global mouse hook function is defined in the Childview.cpp file.
LRESULT CALLBACK Mouseproc
(int nCode, WPARAM WPARAM, LPARAM LPARAM)
{//IS mouse move message
if (wparam==wm_mousemove| | WParam
==wm_ncmousemove)
{
Point= ((MouseHookStruct *) lParam)->pt;
Take Mouse information
Pview->invalidate (); Form Redraw
}
return CallNextHookEx (Hhook,ncode,wparam,lparam);
Passing Hook information
}
(3) Install hooks in the constructor of the CChildView class.
Cchildview::cchildview ()
{
pview=this;//get the Output form pointer
Hhook=setwindowshookex (Wh_mouse,mouseproc,0,getcurrentthreadid ());
}
(4) Unload hooks in the destructor of the CChildView class.
Cchildview::~cchildview ()
{
if (hhook)
UnhookWindowsHookEx (Hhook);
}
Programming examples of system hooks:
Because the system hooks to use the DLL, so first introduced the following Win32 DLL features:
The Win32 DLL differs greatly from the Win16 DLL, which is mainly determined by the operating system's design ideas. On the one hand, the program entry point function and exit point function (LibMain and WEP) are implemented separately in the Win16 DLL, whereas in the Win32 DLL it is implemented by the same function DllMain. This function is called whenever a process or line preempted and unloads a DLL, and its prototype is bool WINAPI DllMain
(HInstance Hinstdll,dword Fdwreason, LPVOID lpvreserved); in which the first parameter represents the instance handle of the DLL; The third parameter system is reserved; Here's a second parameter, which has four possible values: Dll_ Process_attach (process load), Dll_thread_attach (line preempted), Dll_thread_detach (thread offload), Dll_process_detach (process offload), In the DllMain function, it is possible to discriminate the value of the parameter passed in, and to perform the necessary initialization or cleanup of the DLL according to the different parameters. For example, when a process loads a DLL, the second parameter that the system assigns to the DLL is Dll_process_attach, in which case you can initialize the specific data based on that parameter. On the one hand, in the WIN16 environment, all applications are in the same address space, while in the WIN32 environment, all applications have their own private space, each process space is independent of each other, which reduces the interaction between applications, but also increased the difficulty of programming at the same time. As you know, in the WIN16 environment, the DLL's global data is the same for every process that loads it, and in the WIN32 environment, the situation changes, and when the process loads the DLL, the system itself proactively maps the DLL address to the private space of the process. It also replicates a copy of the DLL's global data to the process space, which means that the value of the same DLL's global data owned by each process is not necessarily the same. Therefore, in a Win32 environment, if you want to share data across multiple processes, you must make the necessary settings. That is, separating the data that needs to be shared, placing it in a separate data segment, and setting the attribute of that segment to shared.
There are three forms of MFC DLLs in VC6 (the ability to use and inherit existing MFC classes in the DLL), i.e. regular statically linked to MFC DLLs (standard statically linked MFC DLLs) and regular using the Shared MFC DLLs (Standard dynamic-link MFC DLLs) and extension MFC DLLs (extended MFC DLLs). The first DLL is characterized by the use of MFC code at compile time to add to the DLL, so in the use of the program does not require the existence of other MFC dynamic Link class library, but occupies a larger disk space; Another DLL is characterized by the dynamic link to the MFC class library at run time, thus reducing the space footprint, However, at runtime, it relies on the MFC dynamic Link class library, both of which can be used by MFC programs and can be used by WIN32 programs. The third kind of DLL features similar to another, as an extension of the MFC class Library, can only be used by MFC programs.
The following is the implementation of globally shared data in VC6
In the main file, create a new data segment with #pragma data_seg and define the shared data in the detailed format:
#pragma data_seg ("Shareddata")
HWND sharedwnd=null;//Shared data
#pragma data_seg ()
Defining only one segment of data does not achieve the purpose of sharing data, but also tells the compiler the properties of that segment, and there are two ways to do that (the effect is the same), and one way is to do so. DEF file is added such as the following statement:
Setctions shareddata READ WRITE SHARED
Another way is to add the following statement to the Project Settings link option, for example:
/section:shareddata,rws
Well, the preparation of knowledge has been learned, let's start to write a global hook program!
Because the global hook function must be included in the dynamic link library, this example is implemented by two program bodies.
1. Build Hook Mousehook.DLL
(1) Select MFC AppWizard (DLL) to create the project Mousehook;
(2) Select MFC Extension DLL (Shared MFC copy) type;
(3) Because VC5 does not have a ready-made hook class, you create a Mousehook.h file in the project folder, in which you build the hook class:
Class Afx_ext_class Cmousehook:public CObject
{
Public
Cmousehook ();
The constructor of the hook class
~cmousehook ();
A destructor for a hook class
BOOL Starthook (HWND hwnd);
Install hook function
BOOL Stophook ();
Unload hook function
};
(4) Add # include "Mousehook.h" statement at the top of the Mousehook.app file;
(5) Add global shared data variables:
#pragma data_seg ("MyData")
HWND Glhprevtarwnd=null;
The form handle that was last pointed to by the mouse
HWND Glhdisplaywnd=null;
Display the handle of the target form title edit box
Hhook Glhhook=null;
Installed mouse hook handle
HINSTANCE Glhinstance=null;
DLL instance handle
#pragma data_seg ()
(6) define the segment attribute in the DEF file:
SECTIONS
MyData READ WRITE SHARED
(7) Add the statement that holds the DLL instance handle in the DllMain function of the main file Mousehook.cpp:
DllMain (hinstance hinstance, DWORD dwreason, LPVOID lpreserved)
{
Suppose you use the lpreserved parameter to delete the following line
Unreferenced_parameter (lpreserved);
if (Dwreason = = Dll_process_attach)
{
TRACE0 ("Mousehook. DLL initializing!/n ");
Extension DLLs are initialized only once
if (! AfxInitExtensionModule (Mousehookdll, hinstance))
return 0;
New CDynLinkLibrary (Mousehookdll);
Adding DLLs to the dynamic MFC class Library
Glhinstance=hinstance;
Insert Save DLL Instance handle
}
else if (Dwreason = = Dll_process_detach)
{
TRACE0 ("Mousehook. DLL terminating!/n ");
Call it before terminating this link library
AfxTermExtensionModule (Mousehookdll);
}
return 1;
}
(8) A detailed implementation of the member functions of the class Cmousehook:
Cmousehook::cmousehook ()
Class constructors
{
}
Cmousehook::~cmousehook ()
Class destructor
{
Stophook ();
}
BOOL Cmousehook::starthook (HWND hwnd)
Install the hook and set the receive display form handle
{
BOOL Bresult=false;
Glhhook=setwindowshookex (wh_mouse,mouseproc,glhinstance,0);
if (glhhook!=null)
Bresult=true;
Glhdisplaywnd=hwnd;
Set the handle of the display target form title edit box
return bresult;
}
BOOL Cmousehook::stophook ()
Uninstalling Hooks
{
BOOL Bresult=false;
if (Glhhook)
{
bresult= UnhookWindowsHookEx (Glhhook);
if (bresult)
{
Glhprevtarwnd=null;
glhdisplaywnd=null;//Clear Variable
Glhhook=null;
}
}
return bresult;
}
(9) The implementation of the hook function:
LRESULT WINAPI mouseproc (int ncode,wparam wparam,lparam LPARAM)
{
Lpmousehookstruct pmousehook= (mousehookstruct FAR *) lparam;
if (ncode>=0)
{
HWND glhtargetwnd=pmousehook->hwnd;
Take the target form handle
HWND Parentwnd=glhtargetwnd;
while (Parentwnd!=null)
{
Glhtargetwnd=parentwnd;
Parentwnd=getparent (Glhtargetwnd);
Take the application main form handle
}
if (Glhtargetwnd!=glhprevtarwnd)
{
Char szcaption[100];
GetWindowText (glhtargetwnd,szcaption,100);
Take the target form title
if (IsWindow (Glhdisplaywnd))
SendMessage (glhdisplaywnd,wm_settext,0, (LPARAM) (LPCTSTR) szcaption);
Glhprevtarwnd=glhtargetwnd;
Save Target form
}
}
return CallNextHookEx (Glhhook,ncode,wparam,lparam);
Continue to deliver messages
}
(10) Compile the project to generate Mousehook.dll.
2. Create hooks to run programs
(1) using MFC AppWizard (EXE) to create the project mouse;
(2) Select "Based on the Dialogue application" and press "Finish" key;
(3) Edit the dialog box, delete when there are two buttons, add static text box and edit box, right-click on the static text box, in the pop-up menu, select "Properties", set its title "Mouse in the form of the title";
(4) Add the Include statement "# # # # to the Mousehook.h in Mouse.h. /mousehook/mousehook.h ";
(5) Add private data members to the Cmousedlg class definition in CMouseDlg.h:
Cmousehook m_hook;//Add a hook class as a data member
(6) Change the Cmousedlg::oninitdialog () function:
BOOL Cmousedlg::oninitdialog ()
{
CDialog::OnInitDialog ();
ASSERT ((Idm_aboutbox & 0xfff0) = = Idm_aboutbox);
ASSERT (Idm_aboutbox <0xf000);
cmenu* Psysmenu = GetSystemMenu (FALSE);
if (psysmenu! = NULL)
{
CString Straboutmenu;
Straboutmenu.loadstring (Ids_aboutbox);
if (!straboutmenu.isempty ())
{
Psysmenu->appendmenu (Mf_separator);
Psysmenu->appendmenu (mf_string, Idm_aboutbox, Straboutmenu);
}
}
SetIcon (M_hicon, TRUE);//set big icon
SetIcon (M_hicon, FALSE);//set small icon
Todo:add Extra initialization here
CWnd * Pwnd=getdlgitem (IDC_EDIT1);
Gets the class pointer of the edit box
M_hook.starthook (Pwnd->getsafehwnd ());
Get the form handle of the edit box and install the hook
return TRUE;
Return TRUE unless you set the focus to a control
}
(7) Link DLL library, that is, put the. /mousehook/debug/mousehook.lib added to the Project Settings Link tab;
(8) Compile the project to generate a running file;
(9) Copy the Mousehook.DLL to. The/mouse/debug folder;
(10) Run a few running programs first, then run the Mouse.exe program, move the mouse in different forms, and in the edit box in the Mouse.exe program form, the title of the application main form where the mouse is located appears.
The simplest example of VC6 mouse hooks