Диспетчер сообщений Windows предоставляет приложениям возможность доступа к контролируемым потокам сообщений.
Так называемый механизм крючка (HOOK) 'c4. Существует множество видов перехватчиков, каждый из которых используется для захвата определенного типа или диапазона сообщений. Например: сообщения клавиатуры, сообщения мыши и т. д. Здесь мы используем использование перехватов клавиатуры только в качестве примера, чтобы обсудить, как писать программы DLL в DELPHI, а также как устанавливать и использовать функции перехвата клавиатуры в ваших собственных программах. Мы также обсуждаем, как обмениваться данными, когда разные программы используют один и тот же файл DLL. .
1. Инструкция по написанию функций-фильтров
Поскольку функция фильтра перехвата должна находиться в независимом модуле, это означает, что мы должны сначала сгенерировать структуру DLL, а затем добавить в нее код функции перехвата и другие связанные коды функций. Здесь в качестве примера мы возьмем написание функции фильтра перехвата клавиатуры. Конкретные шаги заключаются в следующем:
1. Сначала создайте корзину DLL 2.
2. Напишите свою собственную функцию фильтра перехвата клавиатуры.
Функция фильтра перехвата должна быть функцией обратного вызова, и ее функция имеет следующую форму:
functionKeyHookPROc(
iкод: целое число;
вПарам: WPARAM;
lParam: LPARAM): LRESULT; stdcall; экспорт;
Добавьте собственную функцию обработки перехвата клавиатуры в созданную структуру DLL для обработки сообщений клавиатуры.
Код следующий:…
если(iCode>=0), то начнем
Результат:=0 // Возвращаемое значение инициализации
//Добавьте сюда свой собственный код
закончить еще
начинать
Результат:=CallNextHook(hOldKeyHook,iCode,wParam,lParam);
//hOldKeyHook — это сохраненная исходная функция фильтра клавиатуры?
конец;
3. Установите функцию фильтра крючка клавиатуры.
Чтобы установить перехват, функция фильтра _fd должна вызвать функцию SetWindowsHookEx (функция установки перехвата SetWindowsHook для Windows 3.0 теперь устарела). Прототип этой функции следующий:
HHOOK SetWindowsHookEx(
int idHook, // Установлен?_b3 подтип
HOOKPROC lpfn, //Фильтр перехвата??f номер адреса
HINSTANCE hMod, //Дескриптор задачи
DWord dwThreadId // Назначение хука
);
Следует отметить, что: ?_a8 часто должен вызывать функцию MakeProcInstance для получения адреса входа преамбулы выходной функции, а затем использовать этот адрес в качестве второго параметра lpfn SetWindowsHookEx. Однако, поскольку Delphi обеспечивает «умный обратный вызов», MakeProcInstance можно опустить, а имя функции фильтра перехвата можно напрямую использовать в качестве адреса входа.
Таким образом, когда функция _c3GetMessage или PeekMessage приложения считывает сообщения из очереди сообщений или имеет ключевые сообщения (WM_KEYDOWN или WM_KEYUP), подлежащие обработке, система вызовет функцию фильтра перехвата KeyHookProc для обработки сообщений клавиатуры.
4. Удалите функцию фильтра крючков.
Когда функция перехвата больше не нужна, следует вызвать UnHookWindowsHookProc, чтобы удалить установленный перехватчик и освободить системные ресурсы.
Полный список программ выглядит следующим образом?_ba
Библиотека KEYHOOK;
использует Windows;
константный BUFFER_SIZE=16*1024;
const HOOK_MEM_FILENAME='SAMPLE KEY_HOOK_MEM_FILE';
const HOOK_MUTEX_NAME = 'SAMPLE KEY_HOOK_MUTEX_NAME';
тип
TShared=запись
Ключи: массив [0..BUFFER_SIZE] символов;
KeyCount: целое число;
конец;
PShared=^TShared;
вар
MemFile,HookMutex: THandle;
HoldKeyHook: HHook;
ProcSaveExit: Указатель;
Общий доступ: PShared;
//Функция фильтра перехвата клавиатуры
функция KeyHookProc (iCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT
; стандартный вызов;
const KeyPressMask = $80000000;
начинать
если iCode < 0, то
Результат: = CallNextHookEx(hOldKeyHook, iCode, wParam, lParam)
еще начать
if ((lParam и KeyPressMask)= 0), то // клавиша нажата
начинать
Shared^.Keys[Shared^.KeyCount]:=Char(wParam и $00ff);
Inc(Shared^.KeyCount);
если Shared^.KeyCount>=BUFFER_SIZE-1, то Shared^.KeyCount:=0;
конец;
iкод:=-1;
Результат: = CallNextHookEx(hOldKeyHook, iCode, wParam, lParam);
конец;
конец;
//Устанавливаем функцию фильтра перехвата
функция EnableKeyHook: экспорт BOOL;
начинать
Shared^.KeyCount:=0 //Инициализируем указатель клавиатуры;
если hOldKeyHook=0, то начнем
hOldKeyHook := SetWindowsHookEx(WH_KEYBOARD,
КейХукПрок,
HИнстанс,
0);
конец;
Результат:= (hOldKeyHook <> 0);
конец;
//Отменить функцию фильтра перехвата
функция DisableKeyHook: экспорт BOOL;
начинать
если hOldKeyHook<> 0, то
начинать
UnHookWindowsHookEx(hOldKeyHook); // Отсоединить крючок клавиатуры;
холдкэйхук:= 0;
Общий^.KeyCount:=0;
конец;
Результат:= (hOldKeyHook = 0);
конец;
//Получаем количество нажатий клавиш в буфере клавиатуры
функция GetKeyCount: Целочисленный экспорт;
начинать
Результат:=Shared^.KeyCount;
конец;
//Получаем клавиши буфера клавиатуры
функция GetKey(index:Integer) : Char экспорт;
начинать
Результат:=Общие^.Ключи[индекс];
конец;
//Очищаем буфер клавиатуры
экспорт процедуры ClearKeyString;
начинать
Общий^.KeyCount:=0;
конец;
//DLL завершаем процесс обработки
процедура KeyHookExit;
начинать
если hOldKeyHook <> 0, то DisableKeyHook;
UnMapViewOfFile(Shared); // Освободите файл изображения в памяти;
CloseHandle(MemFile); // Закрываем файл изображения.
ExitProc := ProcSaveExit;
конец;
экспорт // определение функции вывода
ВключитьКейХук,
ОтключитьKeyHook,
GetKeyCount,
ОчиститьКейСтрока,
ПолучитьКлюч;
начинать
//часть инициализации DLL
HookMutex:=CreateMutex(nil,True,HOOK_MUTEX_NAME);
// Делимся памятью, создавая файл образа памяти
MemFile:=OpenFileMapping(FILE_MAP_WRITE,False,
HOOK_MEM_FILENAME);
если MemFile=0, то
MemFile: = CreateFileMapping ($ FFFFFFFF, ноль, PAGE_READWRITE, 0,
SizeOf(TShared),HOOK_MEM_FILENAME);
Общий: = MapViewOfFile (MemFile, File_MAP_WRITE, 0,0,0);
ReleaseMutex(HookMutex);
CloseHandle(HookMutex);
ProcSaveExit := ExitProc; // Сохраняем ExitProc библиотеки DLL.
ExitProc := @KeyHookExit // Устанавливаем новый ExitProc DLL;
конец.
//Конец исходного кода
2. Используйте подготовленную функцию фильтра перехвата клавиатуры в своей собственной программе.
После того, как функция-перехват скомпилирована, ее на самом деле очень просто использовать: сначала вызовите SetWindowsHookEx, чтобы установить собственную функцию фильтра-перехвата, и в то же время сохраните исходный адрес функции фильтра-перехватчика. В это время в игру вступает функция перехвата, которая будет обрабатывать сообщения клавиатуры в соответствии с вашими требованиями. Когда программа завершит работу или больше не будет необходимости отслеживать сообщения клавиатуры, вызовите функцию UnHookWindowsHookProc, чтобы удалить установленную функцию перехвата и восстановить исходный адрес функции фильтра перехватчиков.
Ниже приведен пример использования функции перехвата, скомпилированной выше:
блок Unit1;
интерфейс
использует
Windows, сообщения, SysUtils, классы, графика, элементы управления, формы, диалоги,
StdCtrls, ExtCtrls;
тип
ТФорм1 = класс (ТФорма)
Памятка1: TMemo;
Панель1: ТПанель;
бSetHook: TButton;
бCancelHook: TButton;
bReadKeys: TButton;
bClearKeys: TButton;
Панель2: ТПанель;
процедура bSetHookClick (Отправитель: TObject);
процедура bCancelHookClick (Отправитель: TObject);
процедура bReadKeysClick (Отправитель: TObject);
процедура bClearKeysClick (Отправитель: TObject);
конец;
вар Form1: TForm1;
выполнение
{$R *.DFM}
функция EnableKeyHook: BOOL внешний 'KEYHOOK.DLL';
функция DisableKeyHook: BOOL внешний 'KEYHOOK.DLL';
функция GetKeyCount: Integer внешний 'KEYHOOK.DLL';
функция GetKey(idx:Integer) : Char внешний 'KEYHOOK.DLL';
процедура ClearKeyString внешний «KEYHOOK.DLL»;
процедура TForm1.bSetHookClick(Sender: TObject // Установка хука клавиатуры 7ó);
начинать
ВключитьКейХук;
bSetHook.Enabled :=False;
bCancelHook.Enabled:=True;
bReadKeys.Enabled :=True;
bClearKeys.Enabled :=True;
Panel2.Caption:='Привязка клавиатуры установлена';
конец;
процедура TForm1.bCancelHookClick(Sender: TObject); // Удаление хука клавиатуры;
начинать
ОтключитьKeyHook;
bSetHook.Enabled :=True;
bCancelHook.Enabled:=False;
bReadKeys.Enabled :=False;
bClearKeys.Enabled :=False;
Panel2.Caption:='Привязка клавиатуры не установлена';
конец;
процедура TForm1.bReadKeysClick(Sender: TObject); // Получаем историю нажатий клавиш;
вар я: целое число;
начинать
Memo1.Lines.Clear // Отображение истории нажатий клавиш в Memo1;
для i:=0 для GetKeyCount-1 сделать
Memo1.Text:=Memo1.Text+GetKey(i);
конец;
процедура TForm1.bClearKeysClick(Sender: TObject); // Очистить историю нажатий клавиш;
начинать
Памятка1.Очистить;
ОчиститьКейСтрока;
конец;
конец.
//Конец исходного кода
3. Реализация общей памяти в DLL под Windows95.
В файле DLL, где находится указанная выше функция перехвата, необходимо использовать общую память, то есть все записи нажатий клавиш хранятся в одном и том же сегменте данных. Почему мы это делаем? Это связано с тем, что метод вызова DLL в Windows95 отличается от метода вызова в Windows3.X. Когда каждый поток входит в динамическую библиотеку, он передает новый дескриптор экземпляра (то есть дескриптор сегмента данных DLL) в динамическую библиотеку. Это позволяет различным экземплярам DLL не мешать друг другу, но создает некоторые трудности, когда все экземпляры DLL используют общий набор переменных. Чтобы решить эту проблему, мы решаем ее здесь, создавая файл с отображением в памяти. То есть, используя Windows OpenFileMapping, CreateFileMapping и
MapViewOfFile три функции для достижения. Как его использовать:
…
MemFile — это тип THandle, Shared — это тип указателя, а HOOK_MEM_FILENAME — это константная строка.
…
MemFile:=OpenFileMapping(FILE_MAP_WRITE,False,
HOOK_MEM_FILENAME); //Открыть файл, отображенный в памяти
if MemFile=0 then //Если открытие не удалось?_c2 Создать файл с отображением в памяти
MemFile: = CreateFileMapping ($ FFFFFFFF, ноль, PAGE_READWRITE, 0,
SizeOf(TShared),HOOK_MEM_FILENAME);
//Сопоставляем файлы с переменными
Общий: = MapViewOfFile (MemFile, File_MAP_WRITE, 0,0,0);
На данный момент вы уже знаете, как легко скомпилировать функции-перехватчики в Delphi. Наконец, я должен напомнить всем: хотя функция перехвата является относительно мощной, при неправильном использовании она серьезно повлияет на эффективность системы, поэтому старайтесь избегать использования системных перехватчиков. При его использовании следует проявлять особую осторожность, чтобы это как можно меньше влияло на работу системы.
[Конец полного текста]