Разрабатываемый драйвер-фильтр осуществляет обработку следующих пакетов IRP:
IRP_MJ_DEVICE_CONTROL
IRP_MJ_READ
IRP_MJ_PNP
IRP_MJ_POWER
Остальные IRP пакеты пропускаются ниже по стеку драйверов.
Функция обработки пакетов IRP _ MJ _ DEVICE _ CONTROL
В данной работе пользовательское приложение должно иметь возможность посылать IOCTL-запросы драйверу. Приложение должно иметь возможность отправить драйверу объект открытого музыкального пина и музыкальные параметры клавиши.
Для этого в теле драйвера определены две 32-битные константы:
#define IOCTL_SHARE_PIN \
CTL_CODE(FILE_DEVICE_KEYBOARD, 0x810, METHOD_BUFFERED, FILE_ANY_ACCESS)
По этому коду в драйвер передаётся 4 байта, которые являются HANDLE объекта пина, открытого в пользовательской программе.
#define IOCTL_MIDI_NOTE \
CTL_CODE(FILE_DEVICE_KEYBOARD, 0x811, METHOD_BUFFERED, FILE_ANY_ACCESS)
По этому коду в драйвер передаётся 7 байт, которые можно описать структурой:
typedef struct _KEY_MIDI_INFO
{UCHAR ScanCode; // Скан-код клавиши, генерируемый клавиатурой
UCHAR Flag; // Флаг клавиши, генерируемый клавиатурой
UCHAR Position; // Позиция на клавиатуре (всего 104 клавиши)
UCHAR Channel; // Музыкальный канал
UCHAR Instrument; // Музыкальный инструмент
UCHAR Note; // Музыкальная нота
UCHAR Used; // Для клавиши используется нота или нет
} KEY_MIDI_INFO, * PKEY_MIDI_INFO;
Это коды IOCTL-запросов, которые не используются драйверами стека клавиатуры. Поэтому в данном проекте они могут быть использованы безо всяких опасений.
Применяется способ передачи данных METHOD_BUFFERED. Т.к. передаётся буфер в 4 или 7 байт, то его размер не повредит системному пулу, и копироваться пользовательский буфер в системный будет очень быстро. Нет необходимости применять более сложные методы METHOD_IN_DIRECT или METHOD_NEITHER, которые используются при передаче больших объемов данных.
Функция обработки пакетов IRP _ MJ _ READ
Данная функция осуществляет обработку пакетов на чтение. IRP-пакет сначала попадает в разрабатываемый драйвер. Вызовется зарегистрированная в DriverEntry функция __MyFilterDispatchRead. К моменту вызова __MyFilterDispatchRead, буфер не содержит кодов считанных клавиш. Для того чтобы получить доступ к ним __MyFilterDispatchRead должна установить CallBack процедуру __MyFilterReadComplete. Она получит управление, когда буфер IRP-пакета будет содержать информацию о нажатых клавишах. Пакет будет подниматься вверх по стеку драйверов и вызывать CallBack функции на каждом уровне стека. CallBack процедура устанавливается с помощью функции IoSetCompletionRoutine.
MyFilterReadComplete получает буфер нажатых клавиш, как массив структур KEYBOARD_INPUT_DATA, функция выполняется на IRQL <= DISPATCH_LEVEL.
Далее в MyFilterDispatchRead происходит копирование текущей ячейки IRP-пакета в следующую ячейку. Таким образом происходит передача неизмененных параметров в Kbdclass.
Функция обработки пакетов IRP _ MJ _ PNP
Драйвер-фильтр должен обрабатывать только запросы IRP_MN_REMOVE_DEVICE и IRP_MN_SURPRISE_REMOVAL. При этом функция посылает данный пакет менеджера PnP нижестоящему в стеке устройству. В обработчиках этих запросов происходит освобождение памяти, которая выделялась для модуля работы с пином, для таблицы музыкальных нот, происходит завершение работы музыкального потока, освобождение очередей и объектов синхронизации, используемых в драйвере.
В обработчике IRP_MN_REMOVE_DEVICE дополнительно происходит:
отключение устройства от стека драйверов вызовом функции IoDetachDevice,
удаление устройства FDO вызовом функции IoDeleteDevice,
удаление символьной ссылки вызовом IoDeleteSymbolicLink.
Остальные пакеты пропускаются ниже по стеку.
Функция обработки пакетов IRP _ MJ _ POWER
Т.к. разрабатываемый драйвер является фильтром, задача которого – получить информацию о нажатых клавишах, то в нём не производится никаких действий, связанных с изменением питания. Поэтому эти IRP-пакеты пропускаются ниже по стеку.
Дата: 2019-12-22, просмотров: 260.