Курсовая работа: Переопределение назначений клавиш на клавиатуре в операционной системе Windows
В данной работе пользовательское приложение должно иметь возможность посылать IOCTLзапросы драйверу. Приложение должно иметь возможность получить список текущих замен осуществляемых драйвером и передать драйверу новый список замен.
Для этого в теле драйвера определены две 32‑битные константы.
- GetKeys
CTL_CODE (FILE_DEVICE_KEYBOARD, 0x810, METHOD_BUFFERED, FILE_ANY_ACCESS)
- SetKeys
CTL_CODE (FILE_DEVICE_KEYBOARD, 0x811, METHOD_BUFFERED, FILE_ANY_ACCESS)
Это коды IOCTL запросов не использующиеся драйверами стека клавиатуры. Поэтому в данном проекте они могут быть использованы безо всяких опасений. Запросы с первым кодом используется для получения списка текущих замен, со вторым для его установки.
Поскольку в первом случае драйверу необходимо получить буфер с данными, а во втором передать его, то необходимо использовать один из четырех способов передачи данных. В проекте применяется способ METHOD_BUFFERED. Поскольку список замен занимает всего 500 байт, то его размер не повредит системному пулу, и копироваться пользовательский буфер в системный будет очень быстро. Нет необходимости применять более сложные методы METHOD_IN_DIRECT или METHOD_NEITHER использующиеся при передаче больших объемов данных.
При обработке запроса на получение списка замен процедура копирует данные из буфера драйвера в системный буфер. После завершения обработки запроса менеджер ввода / вывода скопирует системный буфер в выходной пользовательский. Таким образом приложение сможет получить список замен. При установке списка замен менеджер скопирует пользовательский буфер в системный, а функция обработки IOCTL скопирует системный буфер в буфер драйвера. После этого драйвер начинает производить замену сканкодов, ориентируясь на новые данные.
Функция обработки пакетов IRP _ MJ _ READ
Данная функция осуществляет обработку пакетов на чтение. IRPпакет сначала будет попадать в разрабатываемый драйвер. Вызовется зарегистрированная в DriverEntry функция MyRead. К моменту вызова MyRead, буфер не содержит кодов считанных клавиш. Для того чтобы получить доступ к ним. MyRead должна установить CallBack процедуру. Она получит управление когда буфер IRP пакета будет содержать информацию о нажатых клавишах и будет подниматься вверх по стеку драйверов и будет вызывать CallBack функции на каждом уровне стека. CallBackпроцедура устанавливается с помощью функции IoSetCompletionRoutine. Далее в MyRead происходит копирование текущей ячейки IRP пакета в следующую ячейку, таким образом. Таким образом происходит передача неизмененных параметров в Kbdclass.
Функция обработки пакетов IRP _ MJ _ PNP
Драйвер-фильтр должен обрабатывать только запрос IRP_MN_REMOVE_DEVICE. При этом функция посылает данный пакет менеджера PnP нижестоящему в стеке устройству. Затем она производит необходимые завершающие действия:
- отключает устройство от стека драйверов вызовом функции IoDetachDevice
- удаляет устройство FDO вызовом функции IoDeleteDevice
- удаляет символьную ссылку вызовом IoDeleteSymbolicLink
Остальные пакеты пропускаются ниже по стеку.
Обработка остальных пактов IRP
Остальные пакета IRP, которые за ненадобностью не обрабатываются в данном фильтре, пропускаются ниже по стеку. Процедуры данного фильтра не в праве самостоятельно обрабатывать эти запросы, так как это могут запросы, адресованные нижестоящим драйверам. Примером одного из таких запросов является IOCTL запрос, адресованный драйверу i8042prt и предназначенный для перепрограммирования котроллера клавиатуры и для зажжения лампочек на клавиатуре. Такие запросы посылает Windows при обнаружении нажатия CapsLock, NumLock или ScrollLock.
В данной работе за пропускание пакетов вниз отвечает процедура MyPassNext. Она передает IRPпакет нижестоящему драйверу с помощью функции IoCallDriver. При этом нижестоящий драйвер должен считывать текущую ячейку IRP пакета. Это достигается за счет использования функции IoSkipCurrentIrpStackLocation
2.2 Взаимодействие компонентов системы
2.3 Размещение драйвера в памяти
Некоторые процедуры драйвера, те которые выполняют инициализацию, выгодно выполнить и освободить память после выполнения. Поскольку процедуры инициализации выполняются всего один раз при загрузке системы, а после этого находятся в памяти, занимая ценное место. В языке C есть специальная директива, позволяющая разместить инициализирующий код в специальной секции. Память из под этой секции будет возвращена системе после выполнения. Это директива #pragmaalloc_text («INIT», имя). Параметром директивы является имя функции.
В данном фильтре функцией, которая выполняет инициализацию, является только DriverEntry. Ее имя и является параметром директивы.
По умолчанию функции драйвера размещаются в нестраничной памяти. Эта память является очень ценной, поскольку она не может быть выгружена на жесткий диск. Экономней было бы разместить код драйвера в странично организованной памяти. Для этого в C предусмотрена директива #pragmaalloc_text («PAGE», имя). Параметром директивы является имя функции, которая должна быть размещена в странично организованной памяти. В данном драйвере-фильтре все процедуры кроме DriverEntry размещаются там.
2.4 Переопределение клавиш
Поскольку функция MyRead , которая обрабатывает пакеты IRP _ MJ _ READ , получает пакет IRP без прочитанных данных, то она устанавливает CallBack процедуру. Эта процедура вызывается, когда буфер получает данные.
Реализация процедуры MyReadBack