Некоторые девайсы позволяют дожидаться своей готовности таким способом Код (Text): hDevice= CreateFile("\\\\?\\... WaitForSingleObject(hDevice, INFINITE); Когда у драйвера появляются данные, которые можно прочитать, WaitForSingleObject возвращается вопрос: как сделать такое самому?
DDK\src\general\cancel Основные моменты: Открыть девайс с флагом FILE_FLAG_OVERLAPPED. Кинуть в него несколько запросов через ReadFile или DeviceIoControl. Драйвер возвращает STATUS_PENDING, не завершая IRP, а IRP пихает в очередь. В ДДК описано несколько способов организации такой очереди. В примере используется Cancel Safe Queue. ReadFile/DeviceIoControl возвратят FALSE, а GetLastError даст ERROR_IO_PENDING, т.е. можно ждать. В примере вместо WaitForSingleObject используется ReadFileEx, но это по сути одно и тоже. Разумеется и WaitForSingleObject можно прикрутить. Когда настанет момент такой, драйвер достает IRP из очереди и завершает его. На юзерной стороне ожидание успешно завершается. Тут главный гемор - это необходимость отмены IRP, поставленных в очередь. Без возможности отмены никак нельзя, ибо юзер может, например, умереть в любой момент и нужно как-то доставать все его IRP из ядра. Если никогда с отменой не разбирался, то используй Cancel Safe Queue, как в примере. Она сама внутри себя с этим справляется. Все другие очереди требуют явно это делать.
А я, кстати, так и пытался только вместо очереди запоминал адрес IRP в глобальной переменной )) а завершал пакет в DispatchRoutine, по запросу DeviceIoControl. Так вот, все работает замечательно, если дожидаться на event'е, переданном в структуре OVERLAPED. Что же касается ожидания самого устройства, то WaitForSingleObject выходит же сразу, если ReadFile еще не вызывался, и вообще не выходит после того, как чтение было запущено. Она продолжает висеть даже после того, как IRP завершается. Похоже, для перевода устройства в сигнальное состояние (если это понятие тут вообще применимо) используются какие-то другие механизмы. Что касается отмены... до завершения IRP юзера убить просто невозможно. Если попытаться замочить его, он останется висеть, и закроется сразу же, как только IRP будет завершен. Canceling нужен именно для того, чтобы не блокировать процесс?
Да.. маленькое дополнение Ожидание устройства действительно, судя по всему, связанно с наличием незавершенных IRP, только простое их завершение почему-то не помогает. В чем же может быть дело?
Ну для экспериментов можно и так. Девайс не является объектом ожидания: http://msdn2.microsoft.com/en-us/library/ms686364(d=printer).aspx Да, т.к. поставленный в очередь IRP может находиться там сколь угодно долго. Если не будет отмены, то будут плодиться процессы-зомби. Ну и просто нужно иметь механизм отмены для отзыва IRP.
да я то в курсе, вот только одна загвоздочка: Код (Text): RtlInitUnicodeString(ObjectAttributes.ObjectName, L"\\Device\\KeyboardClass0"); ntStatus= NtOpenFile(&hKeyboard, GENERIC_READ, &ObjectAttributes, &IoStatusBlock... .. for(;;) { ntStatus= NtReadFile(hKeyboard, NULL, NULL, NULL, &IoStatusBlock, &stInputData, sizeof(stInputData), &r, NULL); if(ntStatus!=0 && ntStatus!=STATUS_PENDING) { ... } if(ntStatus==STATUS_PENDING) { ntStatus= NtWaitForSingleObject(hKeyboard, FALSE, NULL); if(ntStatus!=0) { ... } } printf("UnitId=%04X, MakeCode=%04X, Flags=%04X, Res=%04X, Extra=%08X\n", stInputData.UnitId, stInputData.MakeCode, stInputData.Flags, stInputData.Reserved, stInputData.ExtraInformation); } и вот представь, NtWaitForSingleObject дожидается готовности безо всяких так event'ов и APC! Причем, если поменять их местами, wait выйдет сразу же. Если в конце цикла вставить еще один wait, он тоже сразу завершится. Ожидание выполняется только пока в драйере обрабатывается направленный на этот девайс пакет.. Ну так вот, самому этого сделать не удается. Есть предположение, что kbdclass все таки добавляет в конце kernel apc, которая вроде сработает независимо от параметра alertable и тоже прервет ожидание (если честно, я слабо в этом разбираюсь) Конечно, особой разницы - дожидаться на событии или на устройстве, теперь все равно нет, поскольку в любом случае требуется, чтобы в устройстве был irp. А я было подумал, что можно дождаться на устройстве, и только после этого пытаться его читать, что убавило бы проблем с отменой запросов )) Но все равно интересно, к тому же, так можно будет не создавать лишних объектов вроде собыий для ожидания операции.
То, что оно как-то работает в данном конкретном случае, ничего не означает. Нет. Просто достает IRP из очереди, копирует KEYBOARD_INPUT_DATA и IoCompleteRequest. И кстати, csrss открывает этот девайс и постоянно читает клавиатурный ввод. Так что ты ему мешаешь.
да, но ведь работает как-то.. Странно, что он вообще дает мне его открыть а вот KeyboardClass2, например, не открывается Вообще предполагалось все это использовать на стади загрузки(HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\BootExecute) Кстати, интересный момент, Sleep проходит через kbdclass, но обрабатыватся где-то ниже. Даже если поставить на него фильтр и залочить всю клавиатуру, реакция на Sleep все равно сохраняется
Конкретно насчет sleep не знаю, но kbdclass - это upper-level class filter. Клавой же рулит драйвер i8042prt. Полные исходники тоже есть в ддк DDK\src\input\pnpi8042.