The simplest example of a vc6 mouse hook

Source: Internet
Author: User

The Windows system is based on the event-driven mechanism. To put it bluntly, the entire system is implemented through message transmission. Hooks are very important system interfaces in Windows systems. They can be used to intercept and process messages sent to other applications to implement functions that are hard to implement in common applications. Hooks can monitor various event messages in the system or process, intercept and process messages sent to the target window. In this way, we can install custom hooks in the system to monitor the occurrence of specific events in the system and complete specific functions, such as intercepting keyboard and mouse input, and retrieving words on the screen, log monitoring. As you can see, hooks can be used to implement many special and useful functions. Therefore, it is necessary for senior programmers to master hook programming methods.

Hook type
1. There are several common types by event
(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 an application.
(4) log hooks can record various event messages taken from the system message queue.
(5) The window hook monitors all messages sent from the system message queue to the target window.
In addition, there are some hooks for specific events for us to use, not to list them one by one.
The following describes common hook types:
1. wh_callwndproc and wh_callwndprocret hooks
Wh_callwndproc and wh_callwndprocret hooks allow you to monitor messages sent to the window process. The system calls the wh_callwndproc hook sub-process before the message is sent to the receiving window, and CALLS wh_callwndpro after the message is processed in the window process.
Cret hook sub-process. The wh_callwndprocret hook transmits the pointer to the cwpretstruct structure, and then passes the pointer to the hook sub-program. The cwpretstruct structure contains the returned values from the window process for processing the message, and also contains the message parameters associated with the message.
2. wh_cbt hook
Before the following events, the system calls the wh_cbt hook sub-process. These events include:
1. Window events such as activation, creation, destruction, minimization, maximization, movement, and size change;
2. Complete system commands;
3. Move the mouse and keyboard events from the system message queue;
4. Set the input focus event;
5. Synchronize system message queue events.
The Return Value of the hook sub-program determines whether the system allows or prevents one of these operations.
3. wh_debug hook
Before the system calls the hook child program associated with other hooks, the system calls the wh_debug hook Child Program. You can use this hook to determine whether to allow the system to call the hook child program associated with other hooks.
4. wh_foregroundidle hook
When the foreground thread of the application is idle, you can use the wh_foregroundidle hook to execute low-priority tasks. When the foreground thread of an application changes to idle, the system calls the wh_foregroundidle hook sub-thread.
5. wh_getmessage hook
The application uses the wh_getmessage hook to monitor messages returned from the getmessage or peekmessage function. You can use the wh_getmessage hook to monitor mouse and keyboard input and other messages sent to the message queue.
6. wh_journalplayback hook
Wh_journalplayback hook enables applications to insert messages to system message queues. You can use this hook to play back consecutive mouse and keyboard events recorded by using the wh_journalrecord hook. As long as the wh_journalplayback Hook has been installed, normal mouse and keyboard events are invalid. The wh_journalplayback hook is a global hook and cannot be used as a thread-specific hook. Wh_journalplayback hook returns a timeout value, which indicates how long (in milliseconds) the system will wait before processing the current message from the playback hook ). This allows the hook to control the playback of real-time events. Wh_journalplayback is system-wide local hooks, which will not be injected into any blank travel address. (It is estimated that the key-pushing wizard uses this hook)
7. wh_journalrecord hook
The wh_journalrecord hook is used to monitor and record input events. Typically, you can use this hook to record consecutive mouse and keyboard events, and then play back the events by using the wh_journalplayback hook. The wh_journalrecord hook is a global hook and cannot be used as a thread-specific hook. Wh_journalrecord is system-wide local hooks, and it will not be injected into any blank travel address.
8. wh_keyboard hook
In the application, wh_keyboard hook is used to monitor wm_keydown and wm_keyup messages, which are returned through getmessage or peekmessage function. You can use this hook to monitor keyboard messages that are input to the message queue.
9. wh_keyboard_ll hook
Wh_keyboard_ll hook monitors keyboard messages that are input to the thread message queue.
10. wh_mouse hook
Wh_mouse hook monitors the mouse messages returned from the getmessage or peekmessage function. Use this hook to monitor the mouse messages that are input to the message queue.
11. wh_mouse_ll hook
Wh_mouse_ll hook monitors the mouse messages that are input to the thread message queue.
12. wh_msgfilter and wh_sysmsgfilter hooks
Wh_msgfilter and wh_sysmsgfilter hooks allow us to monitor menus, scroll bars, message boxes, and dialog box messages. We also find that users use Alt + TAB or Alt + ESC to switch the window. Wh_msgfilter Hook can only monitor messages transmitted to menus, scroll bars, message boxes, and messages transmitted to the dialog box created by the application that has installed the hook sub-program. Wh_sysmsgfilter hook monitors all application messages. Wh_msgfilter and wh_sysmsgfilter hooks allow us to filter messages during the pattern loop, which is equivalent to filtering messages in the primary message loop. Call the callmsgfilter function to directly call the wh_msgfilter hook. By using this function, the application can use the same code during the pattern loop to filter messages, as in the main message loop.
13. wh_shell hook
Shell applications can use the wh_shell hook to receive important notifications. When the shell application is activated and the top-level window is created or destroyed, the system calls the wh_shell hook sub-program.
Wh_shell has 5 favorites:
1. As long as a top-level and unowned window is generated, acted, or destroyed;
2. When taskbar needs to re-draw a button;
3. When the system needs to display the minimal form of a program about taskbar;
4. When the current keyboard layout status changes;
5. When the user presses Ctrl + ESC to execute Task Manager (or programs of the same level ).
By convention, shell applications do not receive wh_shell messages. Therefore, before the application can receive the wh_shell message, the application must call systemparametersinfo function to register itself.
The above are 13 common hook types!
Ii. Classification by scope of use, mainly including thread hooks and system hooks
(1) The thread hook monitors the event messages of the specified thread.
(2) system hooks monitor the event messages of all threads in the system. Because system hooks affect all applications in the system, hook functions must be placed in an independent dynamic link library (DLL)
. This is a big difference between system hooks and thread hooks.
Notes:
(1) If a thread hook and a system hook are installed for the same event (such as a mouse message), the system automatically calls the thread hook and then calls the system hook.
(2) You can install multiple hooks for the same event message. These hooks form a hook chain. After processing the current Hook, you should pass the hook information to the next hook function. In addition, the recently installed hooks are placed at the beginning of the chain, and the earliest installed hooks are placed at the end, that is, the later hooks are added to obtain control.
(3) hooks, especially system hooks, consume message processing time and reduce system performance. Install the hook only when necessary. Uninstall the hook immediately after use.
Compile a hook Program
You can write a hook program in three steps: Define the hook function, install the hook, and uninstall the hook.
1. Define Hook Functions
A hook function is a special callback function. After a specific event under hook monitoring occurs, the system calls the hook function for processing. Different events have different hook functions. The following uses the mouse hook function as an example to describe the prototype of the hook function:
Lresult callback hookproc (INT ncode, wparam, lparam)
The wparam and lparam parameters contain the information of the hook message, such as the mouse position, status, and keyboard buttons. Ncode contains information about the message itself, such as whether to remove the message from the message queue.
We first implement the custom function in the hook function, and then call the callnexthookex function to pass the hook information to the next hook function of the hook chain. The callnexthookex. prototype is as follows:
Lresult callnexthookex (hhook HHK, int ncode, wparam, lparam)
The HHK parameter is the hook handle. Ncode, wparam, and lparam are hook functions.
Of course, you can also discard the message by directly returning true, thus blocking the transmission of the message.
2. Install hooks
When the program is initialized, call the setwindowshookex function to install the hook. Its function prototype is:
Hhook setwindowshookex (INT idhook, hookproc lpfn, instance hmod, DWORD dwthreadid)
The idhook parameter indicates the hook type, which corresponds to the hook function type one by one. For example, wh_keyboard indicates that the keyboard hook is installed, and wh_mouse indicates that the mouse hook is installed.
Lpfn is the address of the hook function.
Hmod is the handle of the instance where the hook function is located. For a thread hook, this parameter is null. For a system hook, this parameter is the DLL handle of the hook function.
Dwthreadid specifies the thread number monitored by the hook. For global hooks, this parameter is null.
Setwindowshookex returns the mounted hook handle.
3. Uninstall the hook
When you no longer use hooks, you must uninstall them in time. Simply call the bool unhookwindowshookex (hhook HHK) function.
  
It is worth noting that the location of the hook function varies greatly between the thread hook and the system hook. Thread hooks are generally in the current thread or the thread derived from the current thread, and the system hooks must be placed in an independent dynamic link library, which is troublesome to implement.

Programming example of thread HOOK:
Follow the methods described above to implement a line-level mouse hook. The hook tracks the changes of the cursor position in the current window. And output to the window.
(1) use 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 variable:
Hhook; // the handle of the mouse hook.
Cpoint point; // The cursor position.
Cchildview * pview;
// Output Window pointer used by the mouse Hook Function

Add the following code 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) define the global mouse hook function in the childview. cpp file.
Lresult callback mouseproc
(INT ncode, wparam, lparam)
{// Indicates moving the message with the mouse
If (wparam = wm_mousemove | wparam
= Wm_ncmousemove)
{
Point = (mousehookstruct *) lparam)-> pt;
// Obtain the mouse information
Pview-> invalidate (); // redraw the window
}
Return callnexthookex (hhook, ncode, wparam, lparam );
// Transfer the hook Information
}
(3) install the hook in the constructor of the cchildview class.
Cchildview: cchildview ()
{
Pview = This; // get the output window pointer
Hhook = setwindowshookex (wh_mouse, mouseproc, 0, getcurrentthreadid ());
}
(4) unmount the hook in the destructor of the cchildview class.
Cchildview ::~ Cchildview ()
{
If (hhook)
Unhookwindowshookex (hhook );
}

System hook programming example:
Because the system hook uses DLL, first introduce the characteristics of Win32 dll:
Win32 DLL differs greatly from Win16 DLL, which is mainly determined by the operating system design philosophy. On the one hand, in Win16 DLL, the program entry point function and exit point function (libmain and WEP) are implemented respectively, but in Win32 DLL, the same function is implemented by dllmain. This function is called whenever a process or thread loads and uninstalls a DLL. Its prototype is bool winapi dllmain.
(Hinstance hinstdll, DWORD fdwreason, lpvoid lpvreserved). The first parameter indicates the DLL instance handle, and the third parameter is retained. The second parameter is introduced here, it has four possible values: dll_process_attach (process loading), dll_thread_attach (thread loading), dll_thread_detach (thread uninstallation), dll_process_detach (process uninstallation ), in the dllmain function, you can identify the value of the passed parameter, and perform necessary initialization or cleanup for the DLL based on different parameter values. For example, when a process loads a DLL, the second parameter assigned to the DLL by the system is dll_process_attach. In this case, you can initialize specific data based on this parameter. In Win16, all applications are in the same address space. In Win32, all applications have their own private space, the space of each process is independent of each other, which reduces the interaction between applications, but also increases the programming difficulty. As you know, in the Win16 environment, the global data of DLL is the same for every process that loads it. In the Win32 environment, the situation has changed, when a process loads a DLL, the system automatically maps the DLL address to the private space of the process and copies the global data of the DLL to the process space, that is to say, the global data values of the same DLL owned by each process are not necessarily the same. Therefore, to share data among multiple processes in a Win32 environment, you must make necessary settings. That is, the data to be shared is separated and placed in an independent data segment, and the attribute of this segment is set to share.
There are three forms of mfc dll in vc6 (which can be used and inherit from existing MFC classes in this DLL) to choose from, that is, regular statically linked to mfc dll (Standard static link mfc dll) and regular using the shared mfc dll (Standard Dynamic Link mfc dll) and extension mfc dll (Extended mfc dll ). The first type of DLL is that the MFC code used is added to the DLL during compilation. Therefore, when using this program, no other MFC dynamic link library is required, however, the occupied disk space is relatively large. The second DLL is characterized by dynamic link to the MFC class library during runtime, which reduces the occupied space, however, the runtime depends on the Dynamic Link class library of MFC. These two DLL types can be used by both the MFC program and Win32 program. The third type of DLL is similar to the second type. As an extension of the MFC class library, it can only be used by the MFC program.
The following describes how to implement global data sharing in vc6.
In the main file, use # pragma data_seg to create a new data segment and define shared data. The specific format is:
# Pragma data_seg ("shareddata ")
Hwnd sharedwnd = NULL; // share data
# Pragma data_seg ()
Defining only one data segment can not achieve the purpose of sharing data, but also tell the compiler the attributes of this segment, there are two ways to achieve this (the effect is the same ), one way is in. add the following statement to the def file:
Setctions shareddata read write shared
Another method is to add the following statement to the project setting link option:
/Section: shareddata, RWS
Now that you have finished the preparation, let's start writing 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. Create hook mousehook. dll
(1) Select MFC Appwizard (DLL) to create the project mousehook;
(2) Select the MFC extension DLL (shared MFC copy) type;
(3) because there is no ready-made hook class in vc5, create a mousehook. h file in the project directory and create a hook class in it:
Class afx_ext_class cmousehook: Public cobject
{
Public:
Cmousehook ();
// Constructor of the hook class
~ Cmousehook ();
// Hook class destructor
Bool starthook (hwnd );
// Install the hook function
Bool stophook ();
Uninstall Hook Function
};
(4) Add the # include "mousehook. H" Statement to the top of the mousehook. app file;
(5) Add the global shared data variable:
# Pragma data_seg ("mydata ")
Hwnd glhprevtarwnd = NULL;
// The Window handle pointed by the last mouse
Hwnd glhdisplaywnd = NULL;
// Display the handle of the title edit box of the target window
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 for saving the DLL instance handle to the dllmain function of the main file mousehook. cpp:
Dllmain (hinstance, DWORD dwreason, lpvoid lpreserved)
{
// If the lpreserved parameter is used, delete the following line.
Unreferenced_parameter (lpreserved );
If (dwreason = dll_process_attach)
{
Trace0 ("mousehook. dll initializing! /N ");
// The extension DLL is initialized only once.
If (! Afxinitextensionmodule (mousehookdll, hinstance ))
Return 0;
New cdynlinklibrary (mousehookdll );
// Add the DLL to the dynamic MFC class library
Glhinstance = hinstance;
// Insert and save the DLL instance handle
}
Else if (dwreason = dll_process_detach)
{
Trace0 ("mousehook. dll terminating! /N ");
// Call this library before terminating it
Afxtermextensionmodule (mousehookdll );
}
Return 1;
}
(8) Implementation of member functions of class cmousehook:
Cmousehook: cmousehook ()
// Class Constructor
{
}
Cmousehook ::~ Cmousehook ()
// Class destructor
{
Stophook ();
}
Bool cmousehook: starthook (hwnd)
// Install the hook and set the handle for receiving the display window
{
Bool bresult = false;
Glhhook = setwindowshookex (wh_mouse, mouseproc, glhinstance, 0 );
If (glhhook! = NULL)
Bresult = true;
Glhdisplaywnd = hwnd;
// Set the handle to display the title edit box of the target window
Return bresult;
}
Bool cmousehook: stophook ()
// Uninstall the hook
{
Bool bresult = false;
If (glhhook)
{
Bresult = unhookwindowshookex (glhhook );
If (bresult)
{
Glhprevtarwnd = NULL;
Glhdisplaywnd = NULL; // clear the variable
Glhhook = NULL;
}
}
Return bresult;
}
(9) Implementation of hook functions:
Lresult winapi mouseproc (INT ncode, wparam, lparam)
{
Lpmousehookstruct pmousehook = (mousehookstruct far *) lparam;
If (ncode> = 0)
{
Hwnd glhtargetwnd = pmousehook-> hwnd;
// Retrieve the target window handle
Hwnd parentwnd = glhtargetwnd;
While (parentwnd! = NULL)
{
Glhtargetwnd = parentwnd;
Parentwnd = getparent (glhtargetwnd );
// Obtain the handle of the main application window
}
If (glhtargetwnd! = Glhprevtarwnd)
{
Char szcaption [100];
Getwindowtext (glhtargetwnd, szcaption, 100 );
// Obtain the title of the target window
If (iswindow (glhdisplaywnd ))
Sendmessage (glhdisplaywnd, wm_settext, 0, (lparam) (lpctstr) szcaption );
Glhprevtarwnd = glhtargetwnd;
// Save the target window
}
}
Return callnexthookex (glhhook, ncode, wparam, lparam );
// Continue message transmission
}
(10) compile the project to generate mousehook. dll.
2. Create a hook executable program
(1) Use the Appwizard (exe) of MFC to create the project mouse;
(2) Select "Application Based on dialog" and press "finish;
(3) In the edit dialog box, delete the original two buttons, add the static text box and edit box, right-click the static text box, and select "attribute" in the pop-up menu ", set the title to "the title of the window where the mouse is located ";

(4) Add the include statement # include "../mousehook. H" to the mouse. h ";
(5) add private data members to the cmousedlg class definition of cmousedlg. h:
Cmousehook m_hook; // Add the hook class as a data member
(6) modify 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 );
// Get the class pointer of the edit box
M_hook.starthook (pwnd-> getsafehwnd ());
// Obtain the window handle in the editing box and install the hook
Return true;
// Return true unless you set the focus to a control
}
(7) link the dll library to add ../mousehook/debug/mousehook. lib to the project setting link tag;
(8) compile the project to generate executable files;
(9) Copy mousehook. dll to the./mouse/DEBUG directory;
(10)run several executable programs first, then run the mouse.exeprogram to move the mouse in different windows. The edit box in the mouse.exe program window displays the title of the application main window where the mouse is located.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.