Вот кусок моего драйвера-фильтра: Код (Text): NTSTATUS DispatchRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PDEVICE_EXTENSION devExt; PIO_STACK_LOCATION currentIrpStack; PIO_STACK_LOCATION nextIrpStack; devExt = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension; currentIrpStack = IoGetCurrentIrpStackLocation(Irp); nextIrpStack = IoGetNextIrpStackLocation(Irp); *nextIrpStack = *currentIrpStack; IoSetCompletionRoutine(Irp, ReadComplete, DeviceObject, TRUE, TRUE, TRUE); // Запоминаем количество незавершенных IRP-пакетов. numPendingIrps++; // Копируем параметры на следующий уровень в стеке для нижележащего драйвера. return IoCallDriver(devExt->TopOfStack, Irp); } //------------------------------------------------------------------------------ NTSTATUS ReadComplete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) { PIO_STACK_LOCATION IrpSp; PKEYBOARD_INPUT_DATA KeyData; IrpSp = IoGetCurrentIrpStackLocation(Irp); if(NT_SUCCESS(Irp->IoStatus.Status)) { KeyData = Irp->AssociatedIrp.SystemBuffer; DbgPrint("ScanCode: %x ", KeyData[0].MakeCode); DbgPrint("IRPs pending: %x", numPendingIrps); } if( Irp->PendingReturned) { IoMarkIrpPending(Irp); } numPendingIrps--; return Irp->IoStatus.Status; } //------------------------------------------------------------------------------ VOID DispatchUnload(IN PDRIVER_OBJECT DriverObject) { KTIMER kTimer; LARGE_INTEGER timeout; // Получаем указатель на структуру расширения. PDEVICE_EXTENSION pKeyboardDeviceExtension = (PDEVICE_EXTENSION) DriverObject->DeviceObject->DeviceExtension; DbgPrint("Driver Unload Called..\n"); // Отсоединяемся от устройства, к которому подсоединялись. IoDetachDevice(pKeyboardDeviceExtension->TopOfStack); DbgPrint("Keyboard hook detached from device..\n"); //Пока существует хоть один необработанный IRP-пакет, функция Unload будет ожидать окончания его обработки: timeout.QuadPart = 1000000; // 0,1 секунда KeInitializeTimer(&kTimer); while(numPendingIrps > 0) { // Устанавливаем таймер. KeSetTimer(&kTimer,timeout,NULL); KeWaitForSingleObject(&kTimer, Executive, KernelMode, FALSE, NULL); } IoDeleteDevice(DriverObject->DeviceObject); return; } При ручной выгрузке требует нажатия клавиши, и тогда впринципе нормально, но если выключаешь комп - тогда BSOD. Как правильно его выгрузить?
Собрал анализ дампа. Прилагаю. И еще вопрос: в книге нашел, что для корректной выгрузке при выключении компа, нужно регистрировать DriverObject->MajorFunction[IRP_MJ_SHUTDOWN]= DispatchShutdown; предварительно сделав IoRegisterShutdownNotification(device);.
Символы подгрузи нормальные и стек правильный покажи. А вот судя по этому Код (Text): FAULTING_IP: kbfiltr!DispatchShutdown+0 [f:\drv\kb1\kbfiltr.c @ 175] ты забыл дерегистрировать обработчик IRP_MJ_SHUTDOWN вызовом IoUnregisterShutdownNotification(), ибо сказано в великом писании:
Чем дальше, тем страшней... Переписал так: Код (Text): VOID DispatchUnload(IN PDRIVER_OBJECT DriverObject) { // Получаем указатель на структуру расширения. PDEVICE_EXTENSION pKeyboardDeviceExtension = (PDEVICE_EXTENSION) DriverObject->DeviceObject->DeviceExtension; IoUnregisterShutdownNotification(DriverObject->DeviceObject); return; } //------------------------------------------------------------------------------ NTSTATUS DispatchShutdown(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { KTIMER kTimer; LARGE_INTEGER timeout; // Получаем указатель на структуру расширения. PDEVICE_EXTENSION pKeyboardDeviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; DbgPrint("Driver Unload Called..\n"); // Отсоединяемся от устройства, к которому подсоединялись. IoDetachDevice(pKeyboardDeviceExtension->TopOfStack); DbgPrint("Keyboard hook detached from device..\n"); //Пока существует хоть один необработанный IRP-пакет, функция Unload будет ожидать окончания его обработки: timeout.QuadPart = 1000000; // 0,1 секунда KeInitializeTimer(&kTimer); while(numPendingIrps > 0) { // Устанавливаем таймер. KeSetTimer(&kTimer,timeout,NULL); KeWaitForSingleObject(&kTimer, Executive, KernelMode, FALSE, NULL); } IoDeleteDevice(DeviceObject); return Irp->IoStatus.Status; } После старта драйвера, и попытки останова системы, дамп не создался, хотя был BSOD. Может отсоединяться от стека надо в другой ф-ции?
Советую почитать про Cancel-Safe IRP Queues и вобще на тему IRP cancellation, потому как код вышеприведенный есть полный ахтунг.
Походу получилось! Переписал так: Код (Text): VOID DispatchUnload(IN PDRIVER_OBJECT DriverObject) { KTIMER kTimer; LARGE_INTEGER timeout; // Получаем указатель на структуру расширения. PDEVICE_EXTENSION pKeyboardDeviceExtension = (PDEVICE_EXTENSION) DriverObject->DeviceObject->DeviceExtension; IoUnregisterShutdownNotification(DriverObject->DeviceObject); DbgPrint("Driver Unload Called..\n"); // Отсоединяемся от устройства, к которому подсоединялись. IoDetachDevice(pKeyboardDeviceExtension->TopOfStack); DbgPrint("Keyboard hook detached from device..\n"); //Пока существует хоть один необработанный IRP-пакет, функция Unload будет ожидать окончания его обработки: timeout.QuadPart = 1000000; // 0,1 секунда KeInitializeTimer(&kTimer); while(numPendingIrps > 0) { // Устанавливаем таймер. KeSetTimer(&kTimer,timeout,NULL); KeWaitForSingleObject(&kTimer, Executive, KernelMode, FALSE, NULL); } IoDeleteDevice(DriverObject->DeviceObject); return; } //------------------------------------------------------------------------------ NTSTATUS DispatchShutdown(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { // Получаем указатель на структуру расширения. PDEVICE_EXTENSION pKeyboardDeviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; IoUnregisterShutdownNotification(DeviceObject); [b] // удаляем существующие Irp Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); [/b] // Отсоединяемся от устройства, к которому подсоединялись. IoDetachDevice(pKeyboardDeviceExtension->TopOfStack); IoDeleteDevice(DeviceObject); return STATUS_SUCCESS; } и теперь работает корректное завершение работы в системе! >x64 Насколько правильно такое решение? И огромное спасибо, что наставил на путь истины!
Какое решение-то? Я у тебя в коде вообще никаких решений не вижу, одна копипаста. Если по поводу IoUnregisterShutdownNotification(), ну так это даже не решение, а единственная возможность сделать это правильно. А в остальном перепиши на WDM и многое станет проще, например, не придётся вот так трахаться с запросами в Unload-процедуре.