Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Как подключиться к драйверу клавиатуры ?  (Прочитано 25243 раз)
0 Пользователей и 1 Гость смотрят эту тему.
falcon
Гость
« : 09-10-2003 09:15 » 

Подскажите, а еще лучше, толком объясните, как сделать простейший фильтр клавиатуры для 2k/xp? Даже не фильтр, а триггер - клава работает/не работает.
  А то блин, документации - нифига не поймешь. Смотрел пример в DDK - kbfiltr - так нифига и не понял - как именно подключиться к драйверу, что-то там делается с OCTL_INTERNAL_KEYBOARD_CONNECT и IOCTL_INTERNAL_I8042_HOOK_KEYBOARD, но я так не понял, ЧТО именно и КАК нужно делать. Тем более, что kbfiltr - сложнее, чем мне нужно - он еще подключается на инициализацию клавы, а мне это не нужно...
  В общем, в голове полная каша. У меня есть свой драйвер, хочу добавить в него функцию блокировки клавиатуры, но я так и не понял, как правильно подключиться к драйверу клавы.
  Объясните, пожалуйста, по-человечески, как это делать Круто!

  PS: Артем, ау! Ты еще не сделал обещанный фильтр lpt порта ?  :?:
Записан
grozny
Гость
« Ответ #1 : 09-10-2003 16:12 » 

сходи на sysinternals, там есть готовый, рабочий пример фильтра для KBDCLASS. А то клавы-то не только PS/2 бывают, если чо.

http://sysinternals.com/ntw2k/source/ctrl2cap.shtml
Записан
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #2 : 10-10-2003 05:42 » 

Подтверждаю- лучше отклонить запрос(то есть заблокировать клаву) на уровне драйвера класса KBDCLASS, так как если отклонять запросы ниже, то есть на драйвере устройства, то будут всякие чудеса- типа намертво залипшего символа, который выводится постоянно и т.д. И правильно- уже куча USB клав(дроайвер HIDUSB), bluetooth есть(HIDBTH), а на KBDCLASS все эти клавы гарантированно блокируются.
Записан
falcon
Гость
« Ответ #3 : 10-10-2003 16:42 » 

Спасибо за подсказку насчет KBDCLASS.
Однако все равно мое писательство далеко не ушло.

В моем драйвере (он загружается/выгружается динамически, и это важно) в DriverEntry есть IoCreateDevice, а в ctrl2cap - нет, зато есть DriverObject->DriverExtension->AddDevice=функция, где ужЕ и есть IoCreateDevice.
Будет ли это играть роль, если я создаю свой драйвер в DriverEntry, и еще укажу только что созданному своему драйверу DriverExtension->AddDevice ? Или это - не проблема?

Еще мне непонятно, почему AddDevice будет вызвана именно с драйвером клавиатуры, к которому мы должны создать FDO, ведь в том же ctrl2cap в DriverEntry нигде не упоминается, что он собирается цепляться именно на клавиатуру...

Кроме того, в ctrl2cap не упоминается, как поотключать FDO созданные через AddDevice. Я пытался тупо добавить функции ctrl2cap к своему детищу - в результате Капс-лок не перехватывался, хотя мой драйвер работал, но при попытке выгрузить его, винда посинела. По-идее, мои куцые познания говорят мне, что при выгрузке драйвера нужно detach-нуть FDO из девайс-стэка и затем удалить их, но мне непонятно, где их взять во время выполнения функции DriverUnload ?   Вот такой я вот
Записан
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #4 : 13-10-2003 09:35 » 

Цитата

Будет ли это играть роль, если я создаю свой драйвер в DriverEntry, и еще укажу только что созданному своему драйверу DriverExtension->AddDevice ? Или это - не проблема?


  Только создавать не DRIVER_OBJECT а DEVICE_OBJECT.
  Где создавать- это зависит от того, как ты собираешьмся отлавливать обращение к клавиатуре. Если ты хочешь как фильтр над KBDCLASS сесть, то тебе лучше в AddDevice создавать DEVICE_OBJECT, а потом присоединять его к стеку, так как тебе необходимо для каждого DEVICE_OBJECT, созданного KBDCLASS, создать свой DEVICE_OBJECT и посадить его над этим DEVICE_OBJECT. Система будет вызывать твой AddDevice для каждого созданного DEVICE_OBJECT KBDCLASS. В DriverEntry ты еще не знаешь сколько DEVICE_OBJECT создал KBDCLASS, к тому же их число может меняться динамически.
 DEVICE_OBJECT в стек добавляются ф-цией IoAttachDeviceToDeviceStack, нижний PDO тебе передается как параметр. Cмотри примеры в DDK, там есть тонкости с флагами, наследуемыми от PDO.
А FDO можно запомнить в связанном списке.
Записан
falcon
Гость
« Ответ #5 : 13-10-2003 13:10 » 

Пока остался только один вопрос. Сделал, даже работает. НО!
  Проверяю драйвер тестовой консольной прогой. Прога управляется клавиатурой, что неудивительно Ага , и команда выгрузить драйвер, в конечном итоге дается тоже с клавиатуры.
  Так вот, если я ВВОЖУ С КЛАВИАТУРЫ команду выгрузить драйвер, то успеваю разглядеть свое сообщение о успешной выгрузке драйвера, после чего ХР падает в синий экран.
  А если я копирую команду в буфер и затем мышкой клацаю вставить ее из буфера, все успешно завершается и ничего не падает.

  То есть нажатие на клавиши в момент выгрузки драйвера приводит к трапу.

  Подскажите, пожалуйста, что я не доделал?

  Вот куски моего кода, ответственные за init-term драйвера:

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
                                              IN PUNICODE_STRING RegistryPath) {
  PDEVICE_OBJECT    deviceObject;
  PDEVICE_EXTENSION ext;
  UNICODE_STRING    USStr;
  NTSTATUS          ntStatus;
  LONG              i;

  for(i=0; i<IRP_MJ_MAXIMUM_FUNCTION; i++) {
    DriverObject->MajorFunction=PassThrough;
  }
  DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=DriverDeviceControl;
  DriverObject->DriverUnload=DriverUnload;
  DriverObject->MajorFunction[IRP_MJ_CREATE]=DriverOpen;
  DriverObject->MajorFunction[IRP_MJ_CLOSE]=DriverClose;
  DriverObject->MajorFunction[IRP_MJ_READ]=ReadDispatch;
  RtlInitUnicodeString(&USName, NT_DEVICE_NAME);
  ntStatus=IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION),
                          &USName, FILE_DEVICE_KEYBOARD, 0,
                          FALSE, &deviceObject);
  if (!NT_SUCCESS(ntStatus)) {
    RtlFreeUnicodeString(&USName);
    return ntStatus;
  }
  PDO_k=deviceObject;
  ext=(PDEVICE_EXTENSION) deviceObject->DeviceExtension;
  RtlZeroMemory(ext, sizeof(DEVICE_EXTENSION));
  ext->DriverObject=DriverObject; ext->Dev=deviceObject;
  IoInitializeRemoveLock(&ext->RemoveLock, 0, 0, 0);
  RtlInitUnicodeString(&USLink, DOS_DEVICE_NAME);
  ntStatus=IoCreateSymbolicLink(&USLink, &USName);
  if (ntStatus!=STATUS_SUCCESS) {
    RtlFreeUnicodeString(&USLink); RtlFreeUnicodeString(&USName);
    IoDeleteDevice(deviceObject);
    return ntStatus;
  }
  deviceObject->Flags|=DO_BUFFERED_IO;
  deviceObject->Flags&=~DO_DEVICE_INITIALIZING;
  RtlInitUnicodeString(&USStr, K_CLASS0);
  ntStatus=IoAttachDevice(deviceObject, &USStr, &ext->TopOfStack);
  if (ntStatus!=STATUS_SUCCESS) {
    IoDeleteSymbolicLink(&USLink); IoDeleteDevice(deviceObject);
    return ntStatus;
  }
  return STATUS_SUCCESS;
}

и

VOID DriverUnload(IN PDRIVER_OBJECT DriverObject) {
  PDEVICE_EXTENSION ext;

  ext=(PDEVICE_EXTENSION) PDO_k->DeviceExtension;
  IoAcquireRemoveLock(&ext->RemoveLock, DriverUnload);

  IoDeleteSymbolicLink(&USLink);

  IoReleaseRemoveLockAndWait(&ext->RemoveLock, DriverUnload);

  IoDetachDevice(ext->TopOfStack);

  IoDeleteDevice(DriverObject->DeviceObject);
}

И еще.

Это ^^^ я сделал по подобию term2cap ДЛЯ НТ4, без всяких PnP, но мне по крайней мере понятно, КАК оно работает: Я создаю девайс-обжект, затем аттачу его к устройству "\Device\KeyboardClass0", благодаря чему оно и работает ИМЕННО С КЛАВИАТУРОЙ.
  А через PnP AddDevice - я понимаю В ПРИНЦИПЕ, как оно работает - мне говорят о появлении/исчезновении устройства, и я на это должен реагировать - все понятно, ничего сложного. Непонятно КАК В ЧАСТНОСТИ такую конструкцию посадить именно на KBDCLASS ?!!
Записан
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #6 : 13-10-2003 13:52 » 

Почему падает понятно- ты лупишь по клавишам, там всякие IRP cоздаются у них стек с учетом твоего драйвера и тут вдруг- хрясь и нет драйвера,  IRP в дауне. Попробуй после того как  вызовешь IoDetachDevice(ext->TopOfStack) сделать задержку на 2-5 секунд перед вызовом IoDeleteDevice(DriverObject->DeviceObject) это даст возможность проскочить IRP, созданным с учетом твоего драйвера.

Вот такой ф-цией можно сделать задержку

VOID FASTCALL Sleep(IN ULONG ulMilSecs)
{
   KEVENT      kEvent;
   LARGE_INTEGER   qTimeout;

   qTimeout.QuadPart = 10000L;
   qTimeout.QuadPart *= ulMilSecs;
   qTimeout.QuadPart = -(qTimeout.QuadPart);

   KeInitializeEvent(&kEvent,SynchronizationEvent,FALSE);

   KeWaitForSingleObject((PVOID)&kEvent,Executive,KernelMode,FALSE,&qTimeout);
}

вызови  Sleep(3000);
Цитата

 Непонятно КАК В ЧАСТНОСТИ такую конструкцию посадить именно на KBDCLASS ?!!


Надо его зарегистрировать как драйвер фильтр.
Записан
grozny
Гость
« Ответ #7 : 13-10-2003 18:04 » 

Всё достаточно примитивно. РNP Manager управляется в основном через реестр, оттуда же и "узнаёт" про фильтры и иерархию дивайсов. Тупым перебором по ГУИДам.

В ctrl2cap инсталляторе всё написано, что тебе надо сделать. А надо для ключа, соответствующего GUID KBDCLASS в реестре  записать в значение UpperFilters (у него тип MULTI_SZ) имя твоего дивайса. Не помню, но кажется там затирается старое значение. А надо добавлять через 0. Например, было UpperFilters="nmfilter\0" , а надо сделать
UpperFilters="nmfilter\0mykbdfilter\0" . Nmfilter.sys - это фильтр клавы, вставляемый софт-айсом. Так что если просто затереть UpperFilters, то софтайсу станет нехорошо. Разные мультимудийные клавы и тачпады тоже любят сюда вешаться.

вот тебе ключик KBDCLASS, чтоб не искать:

System\\CurrentControlSet\\Control\\Class\\{4D36E96B-E325-11CE-BFC1-08002BE10318}
Записан
Anonymous
Гость
« Ответ #8 : 14-10-2003 14:27 » 

Цитата: SlavaI
Почему падает понятно- ты лупишь по клавишам, там всякие IRP cоздаются у них стек с учетом твоего драйвера и тут вдруг- хрясь и нет драйвера,  IRP в дауне. Попробуй после того как  вызовешь IoDetachDevice(ext->TopOfStack) сделать задержку на 2-5 секунд перед вызовом IoDeleteDevice(DriverObject->DeviceObject) это даст возможность проскочить IRP, созданным с учетом твоего драйвера.


Хм. А это - кузяво ?
Я в своих программах стараюсь решать такие вещи eventam-и.
Неужели в драйвере нет механизма для гарантированного отключения PDO из девайс-стэка? Так чтобы как-то подготовить систему к детачу, затем детачнуть драйвер, потОм дождаться пока система скажет, что "ужЕ можно" удалять PDO, и затем удалить его...
Мне, думается, что-то такое должно быть, не может быть, чтобы такие вещи решалить через паузу - пронесет-непронесет...  :?
Записан
falcon
Гость
« Ответ #9 : 14-10-2003 14:36 » 

Блин, забыл залогиниться - предыдущий гость был я.

Цитата: grozny

В ctrl2cap инсталляторе всё написано, что тебе надо сделать. А надо для ключа, соответствующего GUID KBDCLASS в реестре  записать в значение UpperFilters (у него тип MULTI_SZ) имя твоего дивайса. Не помню, но кажется там затирается старое значение. А надо добавлять через 0. Например, было UpperFilters="nmfilter\0" , а надо сделать
UpperFilters="nmfilter\0mykbdfilter\0" . Nmfilter.sys - это фильтр клавы, вставляемый софт-айсом. Так что если просто затереть UpperFilters, то софтайсу станет нехорошо. Разные мультимудийные клавы и тачпады тоже любят сюда вешаться.


То есть, если я сделаю эту запись в реестре, а затем своим приложением загружу драйвер, то он"усядется" на KBDCLASS ?

Кстати, а порядок драйверов, записанных в UpperFilters играет роль ? Если я свой фильтр запишу туда первым, это будет означать, что он станет первым фильтром в цепочке этого класса ? Или, учитывая, что драйвер грузится динамически, значит все остальные фильтры ужЕ загружены и мой в любом случае будет последним ?
Записан
falcon
Гость
« Ответ #10 : 14-10-2003 16:19 » 

Цитата: SlavaI
Почему падает понятно- ты лупишь по клавишам
...
вызови  Sleep(3000);


Хех Улыбаюсь , с паузой все еще интереснее  8)
Выгружаю мышкой - пауза, все ок.
Выгружаю с клавы - пауза, все ок, кроме клавиатуры - до перезагрузки клавиатура отваливается напрочь, даже CAD не действует.  Жаль
Записан
grozny
Гость
« Ответ #11 : 14-10-2003 20:39 » 

Цитата: falcon


То есть, если я сделаю эту запись в реестре, а затем своим приложением загружу драйвер, то он"усядется" на KBDCLASS ?

Кстати, а порядок драйверов, записанных в UpperFilters играет роль ? Если я свой фильтр запишу туда первым, это будет означать, что он станет первым фильтром в цепочке этого класса ? Или, учитывая, что драйвер грузится динамически, значит все остальные фильтры ужЕ загружены и мой в любом случае будет последним ?


Его попытается "усадить" PNP Manager - он вызовет твой AddDevice().

Порядок играет роль - это порядок вызова AddDevice и порядок прокачки IRP по цепочке фильтров.

Только вот забыл, в какую сторону - то ли FIFO, то ли LIFO, кажись, последний в списке - первый на прицепление и первый на перехват (значит, может встать последним на IoCompletion, что есть для тебя хорошо, никто мимо не пробежит).

Я свой фильтр добавляю в конец, пока всё работает Улыбаюсь.
Записан
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #12 : 15-10-2003 05:04 » 

Цитата

Я в своих программах стараюсь решать такие вещи eventam-и.
Неужели в драйвере нет механизма для гарантированного отключения PDO из девайс-стэка? Так чтобы как-то подготовить систему к детачу, затем детачнуть драйвер, потОм дождаться пока система скажет, что "ужЕ можно" удалять PDO, и затем удалить его...
Мне, думается, что-то такое должно быть, не может быть, чтобы такие вещи решалить через паузу - пронесет-непронесет...


C юзермод замашками в драйвера не лезь. Может способ и есть, да без исходников его трудно найти. Есть способ с подсчетом обрабатываемых IRP, я так у себя делаю в драйвере, который может ждать окончательной отработки несколько минут, но в этом случае за 3 сек IRP гарантированно проскачит, да и объяснять свой способ было лень. К тому же удаляют не PDO, а FDO.
Записан
SlavaI
Главный специалист

ru
Offline Offline

« Ответ #13 : 15-10-2003 05:06 » 

Цитата

ыгружаю с клавы - пауза, все ок, кроме клавиатуры - до перезагрузки клавиатура отваливается


Попробуй вызвать  IoInvalidateDeviceRelations  в DriverUnload после отключения девайса. Но не забудь убрать свой фильтр из списка верхних фильтров в реестре.
Записан
falcon
Гость
« Ответ #14 : 15-10-2003 11:39 » 

Цитата: SlavaI
Цитата

Попробуй вызвать  IoInvalidateDeviceRelations  в DriverUnload после отключения девайса. Но не забудь убрать свой фильтр из списка верхних фильтров в реестре.


Не помогло Жаль

Начитавшись DDK я попытался вынести аттач-детач процедуру в IRP_MJ_DEVICE_CONTROL функцию, и управлять этим через IOCTL, а в DriverUnload только удалять девайс. Получил тоже самое, вид сбоку: либо все трапается при попытке выгрузить драйвер, либо все детачится и выгружается нормально, но после этого ХР валится при первом же нажатии на любую клавишу

Блин, а перегружать винду для выгрузки драйвера меня не устраивает.   Ха-ха-ха Подскажите, пожалуйста, куда копать дальше.
Записан
grozny
Гость
« Ответ #15 : 15-10-2003 19:27 » 

Цитата

Мне, думается, что-то такое должно быть, не может быть, чтобы такие вещи решалить через паузу - пронесет-непронесет...

Цитата

после этого ХР валится при первом же нажатии на любую клавишу



А ты проверяешь, пуста ли очередь клавиатурных IRP перед отгрузкой драйвера? У меня счётчик, который инкрементируется когда IRP входит и в IoCompletionRoutine он декрементируется  только после того, как IRP обработано. Ессно, этот счётчик защищён критической секцией от клинча (новый IRP легко может прервать Completion в момент обновления счётчика).

Без этой мелочи вот что случается на выходе: IRP помечено к завершению в моём фильтре, драйвер выгружен, система честно пытается вызвать IoCompletionRoutine драйвера, адрес на которую лежит в IRP, а драйвера-то уже нету и страничка с кодом уже протухла.

На самом деле, ты по стэку вызовов можешь увидеть, где и почему сломалось. У тебя символы ядра загружены? Какой отладчик ядра? Такие штуки, как IRP Completion, WinDBG показывает луче
Записан
Deke
Гость
« Ответ #16 : 18-10-2003 10:07 » 

Цитата: falcon

Блин, а перегружать винду для выгрузки драйвера меня не устраивает.   Ха-ха-ха Подскажите, пожалуйста, куда копать дальше.


А почему тебя так сильно волнует, выгружен драйвер или нет? Ведь можно просто ограничиться отстановкой фильтрования через DeviceIoControl. А выгрузку как таковую не проводить.
Записан
falcon
Гость
« Ответ #17 : 19-10-2003 17:32 » new

Цитата: Deke

А почему тебя так сильно волнует, выгружен драйвер или нет? Ведь можно просто ограничиться отстановкой фильтрования через DeviceIoControl. А выгрузку как таковую не проводить.


Для прозрачного обновления моей программы в рабочем режиме. И драйвер обновлять тоже хочется, его тоже еще предстоит доделывать, блокировка клавы - это не единственная его обязанность.
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines