Реферат: Переопределение назначений клавиш на клавиатуре в операционной системе Windows

--PAGE_BREAK--Функции, адреса которых записаны в массиве MajorFunctions, вызываются диспетчером ввода / вывода для обработки соответствующих запросов от клиентского драйвера (пользовательских приложений или модулей уровня ядра). Эти запросы оформляются в виде специальных структур – IRP пакетов.
При любом запросе Диспетчер формирует IRP. память для структуры IRP выделяется в нестраничной памяти. В IRP записывается код операции ввода вывода. Пакет IRP состоит из заголовка, который имеет постоянный размер и стека IRP. Стек имеет переменную длину.
Заголовок IRPпакета:
§     Поле IoStatus типа IO_STATUS_BLOCKсодержит два подполя
§  Status содержит значение, которое устанавливает драйвер после обработки пакета.
§  В Information чаще всего помещается число переданных или полученных байт.
§     Поле AssociatedIrp. SystemBuffer типа void* содержит указатель на системный буфер для случая если устройство поддерживает буферизованный ввод / вывод.
§     Поле MdlAddress типа PMDL содержит указатель на MDL список, если устройство поддерживает прямой ввод вывод.
§     Поле UserBuffer типа void* содержит адрес пользовательского буфера для ввода / вывода.
§     Типа Cancel типа BOOLEAN – это индикатор того, что пакет IRP должен быть аннулирован.
<imagedata src=«88689.files/image006.png» o:><img width=«385» height=«257» src=«dopb304991.zip» v:shapes="_x0000_i1028">
Стек IRPпакета
Основное значение ячеек стека IRP пакета состоит в том, чтобы хранить функциональный код и параметры запроса на ввод / вывод. Для запроса, который адресован драйверу самого нижнего уровня, соответствующий IRP пакет имеет только одну ячейку стека. Для запроса, который послан драйверу верхнего уровня, Диспетчер ввода / вывода создает пакет IRP с несколькими стековыми ячейками – по одной для каждого FDO.
Каждая ячейка стека IRP содержит:
§  MajorFunction типа UCHAR – это код, описывающий назначение операции
§  MinorFunction типа UCHAR – это код, описывающий суб-код операции
§  DeviceObject типа PDEVICE_OBJECT – это указатель на объект устройства, которому был адресован данный запрос IRP
§  FileObject типа PFILE_OBJECT – файловый объект для данного запроса
Диспетчер ввода / вывода использует поле MajorFunction для того, чтобы извлечь из массива MajorFunction нужную для обработки запроса процедуру.
Каждая процедура обработки IRP пакетов должна в качестве параметров иметь:
§  Указатель на объект устройства, для которого предназначен IRP запрос
§  Указатель на пакет IRP, описывающий этот запрос
Возвращает такая функция значение типа NTSTATUS, содержащее результат обработки.
<imagedata src=«88689.files/image008.png» o:><img width=«408» height=«334» src=«dopb304992.zip» v:shapes="_x0000_i1029">
Функция обработки пакетов IRP_MJ_DEVICE_CONTROL
Эти функции позволяют обрабатывать расширенные запросы от клиентов пользовательского режима. Такой запрос может быть сформирован посредством вызова функции DeviceIoControl. Каждый IOCTL запрос имеет свой код. Этот код передается как параметр функции DeviceIoControl. Код IOCTL – это 32‑битное число.
Запросы IOCTL служат чаще всего для обмена данными между драйвером и приложением. Для передачи данных в Windows предусмотрены 4 способа
§  METHOD_BUFFERED
Входной пользовательский буфер копируется в системный, а по окончании обработки системный копируется в в выходной пользовательский буфер.
§  METHOD_IN_DIRECT и METHOD_OUT_DIRECT
Необходимые страницы пользовательского буфера загружаются с диска в оперативную память и блокируются. И с помощью DMA осуществляется передача данных между устройством и пользователем.
§  METHOD_NEITHER
При данном методе передачи не производится проверка доступности памяти, не выделяются промежуточные буфера и не создаются MDL. В пакете IRP передаются виртуальные адреса буферов в пространстве памяти инициатора запроса ввода / вывода.
Функция обработки пакетов IRPMJREAD
Данная функция должна обрабатывать запросы на чтение информации из устройства.
Функция обработки пакетов IRPMJPNP
Данная функция должна обрабатывать запросы от менеджера PnP.
ISR
Данная точка входа вызовется при, когда произойдет прерывание, на которое зарегистрирована эта ISR функция. Вызов может произойти в любом контексте: как ядра, так и пользовательского процесса. Здесь драйвер может либо дожидаться следующего прерывания (с какой-либо целью), либо запросить отложенный вызов процедуры (Deferred Procedure Call), DPC

1.6 Анализ методов решения задачи
В соответствии с заданием на курсовую работу, необходимо разработать программное обеспечение, позволяющее переопределять назначение клавиш на клавиатуре. Из анализа архитектуры Windows XP следует, что для доступа к информации, содержащей скэнкоды нажатых или отпущенных клавишей необходимо написать драйвер. Драйвер может получить доступ к скэнкодам нажатых или отпущенных клавиш двумя способами. Либо перехватывая IRP пакеты от других драйверов, либо самостоятельно обрабатывая прерывания от клавиатуры. Оптимальным является написание драйвера, который перехватывал бы IRP пакеты от драйвера клавиатуры, то есть написание драйвера-фильтра. В этом случае нет необходимости переписывать уже сделанный драйвер клавиатуры, нужно написать драйвер, изменяющий информацию в приходящих IRP пакетах.
Существует два типа драйверов фильтров: драйвер-фильтр верхнего и нижнего уровня. В рамкой данной задачи не имеет значения на каком этапе будет производится переопределение. Но предпочтительнее выбрать драйвер-фильтр верхнего уровня, поскольку информация возвращаемая драйвером клавиатуры хорошо документирована и описана в литературе.
Ввиду того, что все современные драйверы, рекомендуется писать согласно стандарту PnP, поскольку они обладают большей функциональностью, то разрабатываемый драйвер должен быть драйвером PnP.
Формализация постановки задачи:
§     Необходимо написать драйвер-фильтр верхнего уровня для драйвера клавиатуры.
§     Драйвер-фильтр должен перехватывать IRP пакеты, содержащие скэнкоды нажатых и отпущенных клавиш, переопределять, если необходимо, скэнкоды на скэнкоды других клавиш. Он должен удалять записи, соответствующие отключенным клавишам.
§     Решение о том, какие клавиши должны быть переопределены или отключены, принимается в соответствии со списком замен, который хранится в памяти ядра.
§     Для установки списка замен используется пользовательское приложение, которое пересылает в драйвер список замен.
§     Драйвер должен быть драйвером PnP.
§     Драйвер-фильтр не должен тормозить ввод с клавиатуры и работу всей системы в целом. Драйвер-фильтр должен обеспечить надежную работу системы.

2. Конструкторский раздел
2.1 Точки входа разрабатываемого драйвера-фильтра
Поскольку разрабатываемый драйвер-фильтр является драйвером PnP, то должен иметь следующие точки входа:
§     DriverEntry
§     DriverUnload
§     AddDevice
§     Функции для обработки пакетов IRP
Функции для обработки прерываний в данной работе не регистрируются, поскольку драйвер не работает с прерываниями.
DiverEntry
В данной работе процедура DriverEntry выполняет следующие действия:
·                   Заполнение массива MajorFunctions. Регистрируется процедура обработки пакета на чтение, процедура обработки IOCTL запросов, процедуры обработки запросов от менеджера PnP и менеджера питания. Остальные элементы массива заполняются адресом функции MyPassNext, которая пропускает пакеты ниже по стеку.
·                   Регистрация процедуры AddDevice. В данной работе она называется MyAddDevice.
·                   Регистрация процедуры DriverUnload, называющейся MyUnload.
·                   Выделение памяти для хранения массива замен клавиш. Одна запись массива занимает 4 байта, а максимум может быть только 103 замены (клавиша Pause/Break не в счет). Значит максимальный объем массива равен 412 байт. DriverEntry сразу выделяет при загрузке эти 412 байт. Не имеет смысла экономить и выделять память динамически при каждой инициализации массива, поскольку 412 – это очень мало, и система не будет тратить время на освобождение и выделение памяти при каждой инициализации.
·                   Инициализация некоторых глобальных переменных: AltPressed, CtrlPressed, KeyPause.
DriverEntry регистрирует только необходимые процедуры. Поскольку проект представляет собой драйвер-фильтр верхнего уровня, и в нем нет необходимости обрабатывать прерывания, то не производится регистрация DriverStartIo, процедур ISR и DPC.
AddDevice
В данной работе функция MyAddDevice создает одно функциональное устройство с именем \\Device\\MyFilter. При создании устройства происходит резервирования места для хранения адреса устройства, расположенного ниже в стеке драйверов. Это сделано для того, чтобы при разрушении стека драйверов передать запрос PnP на демонтаж нижестоящему драйверу. Созданное устройство подключается к стеку драйверов клавиатуры. Это делается с помощью функции IoAttachDeviceToDeviceStack. Это стандартная функция Windows, она принимает PDO и указатель на структуру подключаемого FDO. FDO занимает место в стеке драйверов сразу после объекта, находящегося в вершине стека. Теперь подключаемый FDO становится вершиной стека. Нельзя подключится к стеку когда он уже сформирован, поэтому необходимо подключится к нему в определенный момент. Очередность загрузки драйверов описана в реестре Windows. Программа установки производит необходимую регистрацию. Структура этой программы описана ниже.
Для того чтобы пользовательское приложение смогло обратиться к драйверу (для загрузки в драйвер списка замен или для получения списка замен, которые драйвер осуществляет в данный момент) для FDO должно быть зарегистрировано DOS имя. Используя это имя приложение сможет послать драйверу IOCTL запрос. Для регистрации такого имени создается строка юникод со значением \\DosDevices\\MyFilter и применяется функция IoCreateSymbolicLink. Ее параметрами является только что созданная строка и имя FDO, которое обслуживает наш драйвер. Теперь \\DosDevices\\MyFilter – это DOS имя созданного FDO устройства.
DriverUnload
Поскольку данный фильтр является PnP драйвером, то на процедуру DriverUnload ничего не возложено.
Процедуры обработки пакетов IRP
Разрабатываемый драйвер-фильтр осуществляет обработку следующих пакетов IRP:
§  IRP_MJ_DEVICE_CONTROL
§  IRP_MJ_READ
§  IRP_MJ_PNP
Остальные IRP пакеты пропускаются ниже по стеку драйверов.
Функция обработки пакетов IRP_MJ_DEVICE_CONTROL
В данной работе пользовательское приложение должно иметь возможность посылать 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 Взаимодействие компонентов системы
<imagedata src=«88689.files/image010.png» o:><img border=«0» width=«515» height=«371» src=«dopb304993.zip» v:shapes="_x0000_i1030">
2.3 Размещение драйвера в памяти
Некоторые процедуры драйвера, те которые выполняют инициализацию, выгодно выполнить и освободить память после выполнения. Поскольку процедуры инициализации выполняются всего один раз при загрузке системы, а после этого находятся в памяти, занимая ценное место. В языке C есть специальная директива, позволяющая разместить инициализирующий код в специальной секции. Память из под этой секции будет возвращена системе после выполнения. Это директива #pragma alloc_text («INIT», имя). Параметром директивы является имя функции.
В данном фильтре функцией, которая выполняет инициализацию, является только DriverEntry. Ее имя и является параметром директивы.
По умолчанию функции драйвера размещаются в нестраничной памяти. Эта память является очень ценной, поскольку она не может быть выгружена на жесткий диск. Экономней было бы разместить код драйвера в странично организованной памяти. Для этого в C предусмотрена директива #pragma alloc_text («PAGE», имя). Параметром директивы является имя функции, которая должна быть размещена в странично организованной памяти. В данном драйвере-фильтре все процедуры кроме DriverEntry размещаются там.
2.4 Переопределение клавиш
Поскольку функция MyRead, которая обрабатывает пакеты IRP_MJ_READ, получает пакет IRP без прочитанных данных, то она устанавливает CallBack процедуру. Эта процедура вызывается, когда буфер получает данные.
    продолжение
--PAGE_BREAK--
еще рефераты
Еще работы по информатике