The Windows Message Manager provides the ability for applications to access controlled message flows.
'c4's so-called hook (HOOK) mechanism. There are many kinds of hooks, each used to capture a specific type or range of messages. Such as: keyboard messages, mouse messages, etc. We only take the use of keyboard hooks as an example here to discuss how to write DLL programs under DELPHI and how to install and use keyboard hook functions in your own programs. We also discuss how to share data when different programs use the same DLL file.
1. Instructions for writing hook filter functions
Since the hook filter function must be in an independent module, that means we must first generate a DLL framework, and then add the hook function code and other related function codes to it. Here we take the writing of keyboard hook filter function as an example to illustrate. The specific steps are as follows:
1. First generate a DLL basket 2
2. Write your own keyboard hook filter function
The hook filter function must be a callback function, and its function has the following shape:
functionKeyHookPRoc(
iCode:Integer;
wParam:WPARAM;
lParam:LPARAM ): LRESULT; stdcall ;export;
Add your own keyboard hook processing function to the generated DLL framework to handle keyboard messages.
The code is as follows:…
if(iCode>=0) then begin
Result:=0; //Initialization return value
//Add your own code here
end else
begin
Result:=CallNextHook(hOldKeyHook,iCode,wParam,lParam);
//hOldKeyHook is the saved original keyboard filter function?
end;
3. Install keyboard hook filter function
To install a hook, the _fd filter function should call the SetWindowsHookEx function (the SetWindowsHook hook installation function for Windows 3.0 is now obsolete). The prototype of this function is as follows:
HHOOK SetWindowsHookEx(
int idHook, // Installed?_b3 subtype
HOOKPROC lpfn, //Hook filter??f number address
HINSTANCE hMod, //Task handle
DWord dwThreadId // The purpose of the hook
);
It should be noted that: ?_a8 often should call the MakeProcInstance function to obtain the entry address of the preamble of an output function, and then use this address as the second parameter lpfn of SetWindowsHookEx. However, since Delphi provides "smart callback", MakeProcInstance can be omitted and the hook filter function name can be directly used as the entry address.
In this way, when the application's _c3GetMessage or PeekMessage function reads messages from the message queue or has key messages (WM_KEYDOWN or WM_KEYUP) to be processed, the system will call the hook filter function KeyHookProc to process the keyboard messages.
4. Uninstall the hook filter function.
When the hook function is no longer needed, UnHookWindowsHookProc should be called to uninstall the installed hook to release system resources.
The complete program list is as follows?_ba
Library KEYHOOK;
uses Windows;
const BUFFER_SIZE=16*1024;
const HOOK_MEM_FILENAME='SAMPLE KEY_HOOK_MEM_FILE';
const HOOK_MUTEX_NAME ='SAMPLE KEY_HOOK_MUTEX_NAME';
type
TShared=record
Keys: array[0..BUFFER_SIZE] of Char;
KeyCount : Integer;
end;
PShared=^TShared;
var
MemFile,HookMutex: THandle;
hOldKeyHook: HHook;
ProcSaveExit: Pointer;
Shared: PShared;
//Keyboard hook filter function
function KeyHookProc(iCode: Integer; wParam: WPARAM ; lParam: LPARAM):LRESULT
; stdcall; export;
const KeyPressMask = $80000000;
begin
if iCode < 0 then
Result := CallNextHookEx(hOldKeyHook, iCode, wParam, lParam)
else begin
if ((lParam and KeyPressMask)= 0) then // key pressed
begin
Shared^.Keys[Shared^.KeyCount]:=Char(wParam and $00ff);
Inc(Shared^.KeyCount);
if Shared^.KeyCount>=BUFFER_SIZE-1 then Shared^.KeyCount:=0;
end;
iCode:=-1;
Result := CallNextHookEx(hOldKeyHook, iCode, wParam, lParam);
end;
end;
//Set the hook filter function
function EnableKeyHook: BOOL; export;
begin
Shared^.KeyCount:=0; //Initialize keyboard pointer
if hOldKeyHook=0 then begin
hOldKeyHook := SetWindowsHookEx(WH_KEYBOARD,
KeyHookProc,
HInstance,
0);
end;
Result := (hOldKeyHook <> 0);
end;
//Undo hook filter function
function DisableKeyHook: BOOL; export;
begin
if hOldKeyHook<> 0 then
begin
UnHookWindowsHookEx(hOldKeyHook); // Unhook Keyboard Hook
hOldKeyHook:= 0;
Shared^.KeyCount:=0;
end;
Result := (hOldKeyHook = 0);
end;
//Get the number of keystrokes in the keyboard buffer
function GetKeyCount :Integer; export;
begin
Result:=Shared^.KeyCount;
end;
//Get the keys of the keyboard buffer
function GetKey(index:Integer) : Char ; export;
begin
Result:=Shared^.Keys[index];
end;
//Clear the keyboard buffer
procedure ClearKeyString; export;
begin
Shared^.KeyCount:=0;
end;
//DLL exit processing process
procedure KeyHookExit; far;
begin
if hOldKeyHook <> 0 then DisableKeyHook;
UnMapViewOfFile(Shared); // Release the memory image file
CloseHandle(MemFile); // Close the image file
ExitProc := ProcSaveExit;
end;
exports // define output function
EnableKeyHook,
DisableKeyHook,
GetKeyCount,
ClearKeyString,
GetKey;
begin
//DLL initialization part
HookMutex:=CreateMutex(nil,True,HOOK_MUTEX_NAME);
// Share memory by creating a memory image file
MemFile:=OpenFileMapping(FILE_MAP_WRITE,False,
HOOK_MEM_FILENAME);
if MemFile=0 then
MemFile:=CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,
SizeOf(TShared) ,HOOK_MEM_FILENAME);
Shared:=MapViewOfFile(MemFile,File_MAP_WRITE,0,0,0);
ReleaseMutex(HookMutex);
CloseHandle(HookMutex);
ProcSaveExit := ExitProc; // Save the ExitProc of the DLL
ExitProc := @KeyHookExit; // Set the new ExitProc of the DLL
end.
//End of source code
2. Use the prepared keyboard hook filter function in your own program.
After the hook function is compiled, it is actually very simple to use: first call SetWindowsHookEx to install your own hook filter function, and at the same time save the original hook filter function address. At this time, the hook function comes into play, and it will handle keyboard messages according to your requirements. When the program is finished running or it is no longer necessary to monitor keyboard messages, call the UnHookWindowsHookProc function to uninstall the installed hook function and restore the original hook filter function address.
The following is an example of using the hook function compiled above:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Panel1: TPanel;
bSetHook: TButton;
bCancelHook: TButton;
bReadKeys: TButton;
bClearKeys: TButton;
Panel2: TPanel;
procedure bSetHookClick(Sender: TObject);
procedure bCancelHookClick(Sender: TObject);
procedure bReadKeysClick(Sender: TObject);
procedure bClearKeysClick(Sender: TObject);
end;
var Form1: TForm1;
implementation
{$R *.DFM}
function EnableKeyHook : BOOL ; external 'KEYHOOK.DLL';
function DisableKeyHook : BOOL ; external 'KEYHOOK.DLL';
function GetKeyCount : Integer ; external 'KEYHOOK.DLL';
function GetKey(idx:Integer) : Char ; external 'KEYHOOK.DLL';
procedure ClearKeyString; external 'KEYHOOK.DLL';
procedure TForm1.bSetHookClick(Sender: TObject); // Set keyboard hook 7ó
begin
EnableKeyHook;
bSetHook.Enabled :=False;
bCancelHook.Enabled:=True;
bReadKeys.Enabled :=True;
bClearKeys.Enabled :=True;
Panel2.Caption:='Keyboard hook has been set';
end;
procedure TForm1.bCancelHookClick(Sender: TObject); // Uninstall keyboard hook
begin
DisableKeyHook;
bSetHook.Enabled :=True;
bCancelHook.Enabled:=False;
bReadKeys.Enabled :=False;
bClearKeys.Enabled :=False;
Panel2.Caption:='Keyboard hook is not set';
end;
procedure TForm1.bReadKeysClick(Sender: TObject); // Get keystroke history
var i:Integer;
begin
Memo1.Lines.Clear; // Display keystroke history in Memo1
for i:=0 to GetKeyCount-1 do
Memo1.Text:=Memo1.Text+GetKey(i);
end;
procedure TForm1.bClearKeysClick(Sender: TObject); // Clear keystroke history
begin
Memo1.Clear;
ClearKeyString;
end;
end.
//End of source code
3. Implementing shared memory in DLL under Windows95
In the DLL file where the above hook function is located, shared memory needs to be used, that is, all keystroke records are stored in the same data segment. Why do we do this? This is because the DLL calling method of Windows95 is different from that of Windows3.X. When each thread logs in to a dynamic link library, it will pass a new instance handle (that is, the handle of the DLL data segment) to the dynamic link library. This allows the various instances of the DLL to not interfere with each other, but it brings some difficulties when all DLL instances share a set of variables. In order to solve this problem, we solve it here by creating a memory mapped file. That is, using Windows' OpenFileMapping, CreateFileMapping and
MapViewOfFile three functions to achieve. How to use it:
…
MemFile is a THandle type, Shared is a pointer type, and HOOK_MEM_FILENAME is a constant string.
…
MemFile:=OpenFileMapping(FILE_MAP_WRITE,False,
HOOK_MEM_FILENAME); //Open memory mapped file
if MemFile=0 then //If the opening fails?_c2 Create a memory mapped file
MemFile:=CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,
SizeOf(TShared) ,HOOK_MEM_FILENAME);
//Map files to variables
Shared:=MapViewOfFile(MemFile,File_MAP_WRITE,0,0,0);
So far, you already know how easy it is to compile hook functions in Delphi. Finally, I have to remind everyone: Although the hook function is relatively powerful, if used improperly, it will seriously affect the efficiency of the system, so try to avoid using system hooks. Extra care should be taken when it must be used, so that it will affect the operation of the system as little as possible.
[End of full text]