falcon
Гость
|
|
« : 09-10-2003 09:15 » |
|
Подскажите, а еще лучше, толком объясните, как сделать простейший фильтр клавиатуры для 2k/xp? Даже не фильтр, а триггер - клава работает/не работает. А то блин, документации - нифига не поймешь. Смотрел пример в DDK - kbfiltr - так нифига и не понял - как именно подключиться к драйверу, что-то там делается с OCTL_INTERNAL_KEYBOARD_CONNECT и IOCTL_INTERNAL_I8042_HOOK_KEYBOARD, но я так не понял, ЧТО именно и КАК нужно делать. Тем более, что kbfiltr - сложнее, чем мне нужно - он еще подключается на инициализацию клавы, а мне это не нужно... В общем, в голове полная каша. У меня есть свой драйвер, хочу добавить в него функцию блокировки клавиатуры, но я так и не понял, как правильно подключиться к драйверу клавы. Объясните, пожалуйста, по-человечески, как это делать PS: Артем, ау! Ты еще не сделал обещанный фильтр lpt порта ? :?:
|
|
|
Записан
|
|
|
|
|
SlavaI
Главный специалист
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
Главный специалист
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
Главный специалист
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 » |
|
Почему падает понятно- ты лупишь по клавишам, там всякие IRP cоздаются у них стек с учетом твоего драйвера и тут вдруг- хрясь и нет драйвера, IRP в дауне. Попробуй после того как вызовешь IoDetachDevice(ext->TopOfStack) сделать задержку на 2-5 секунд перед вызовом IoDeleteDevice(DriverObject->DeviceObject) это даст возможность проскочить IRP, созданным с учетом твоего драйвера.
Хм. А это - кузяво ? Я в своих программах стараюсь решать такие вещи eventam-и. Неужели в драйвере нет механизма для гарантированного отключения PDO из девайс-стэка? Так чтобы как-то подготовить систему к детачу, затем детачнуть драйвер, потОм дождаться пока система скажет, что "ужЕ можно" удалять PDO, и затем удалить его... Мне, думается, что-то такое должно быть, не может быть, чтобы такие вещи решалить через паузу - пронесет-непронесет... :?
|
|
|
Записан
|
|
|
|
falcon
Гость
|
|
« Ответ #9 : 14-10-2003 14:36 » |
|
Блин, забыл залогиниться - предыдущий гость был я. В 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 » |
|
Почему падает понятно- ты лупишь по клавишам ... вызови Sleep(3000);
Хех , с паузой все еще интереснее 8) Выгружаю мышкой - пауза, все ок. Выгружаю с клавы - пауза, все ок, кроме клавиатуры - до перезагрузки клавиатура отваливается напрочь, даже CAD не действует.
|
|
|
Записан
|
|
|
|
grozny
Гость
|
|
« Ответ #11 : 14-10-2003 20:39 » |
|
То есть, если я сделаю эту запись в реестре, а затем своим приложением загружу драйвер, то он"усядется" на KBDCLASS ?
Кстати, а порядок драйверов, записанных в UpperFilters играет роль ? Если я свой фильтр запишу туда первым, это будет означать, что он станет первым фильтром в цепочке этого класса ? Или, учитывая, что драйвер грузится динамически, значит все остальные фильтры ужЕ загружены и мой в любом случае будет последним ?
Его попытается "усадить" PNP Manager - он вызовет твой AddDevice(). Порядок играет роль - это порядок вызова AddDevice и порядок прокачки IRP по цепочке фильтров. Только вот забыл, в какую сторону - то ли FIFO, то ли LIFO, кажись, последний в списке - первый на прицепление и первый на перехват (значит, может встать последним на IoCompletion, что есть для тебя хорошо, никто мимо не пробежит). Я свой фильтр добавляю в конец, пока всё работает .
|
|
|
Записан
|
|
|
|
SlavaI
Главный специалист
Offline
|
|
« Ответ #12 : 15-10-2003 05:04 » |
|
Я в своих программах стараюсь решать такие вещи eventam-и. Неужели в драйвере нет механизма для гарантированного отключения PDO из девайс-стэка? Так чтобы как-то подготовить систему к детачу, затем детачнуть драйвер, потОм дождаться пока система скажет, что "ужЕ можно" удалять PDO, и затем удалить его... Мне, думается, что-то такое должно быть, не может быть, чтобы такие вещи решалить через паузу - пронесет-непронесет...
C юзермод замашками в драйвера не лезь. Может способ и есть, да без исходников его трудно найти. Есть способ с подсчетом обрабатываемых IRP, я так у себя делаю в драйвере, который может ждать окончательной отработки несколько минут, но в этом случае за 3 сек IRP гарантированно проскачит, да и объяснять свой способ было лень. К тому же удаляют не PDO, а FDO.
|
|
|
Записан
|
|
|
|
SlavaI
Главный специалист
Offline
|
|
« Ответ #13 : 15-10-2003 05:06 » |
|
ыгружаю с клавы - пауза, все ок, кроме клавиатуры - до перезагрузки клавиатура отваливается
Попробуй вызвать IoInvalidateDeviceRelations в DriverUnload после отключения девайса. Но не забудь убрать свой фильтр из списка верхних фильтров в реестре.
|
|
|
Записан
|
|
|
|
falcon
Гость
|
|
« Ответ #14 : 15-10-2003 11:39 » |
|
Попробуй вызвать 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 » |
|
Блин, а перегружать винду для выгрузки драйвера меня не устраивает. Подскажите, пожалуйста, куда копать дальше. А почему тебя так сильно волнует, выгружен драйвер или нет? Ведь можно просто ограничиться отстановкой фильтрования через DeviceIoControl. А выгрузку как таковую не проводить.
|
|
|
Записан
|
|
|
|
falcon
Гость
|
|
« Ответ #17 : 19-10-2003 17:32 » |
|
А почему тебя так сильно волнует, выгружен драйвер или нет? Ведь можно просто ограничиться отстановкой фильтрования через DeviceIoControl. А выгрузку как таковую не проводить.
Для прозрачного обновления моей программы в рабочем режиме. И драйвер обновлять тоже хочется, его тоже еще предстоит доделывать, блокировка клавы - это не единственная его обязанность.
|
|
|
Записан
|
|
|
|
|