Есть такая задачка из ядра послать IRP другому устройству. Если конкретно, то SMART_GET_VERSION для "\\??\\PhysicalDrive0". И что-то пока не особо получается. Делаю так: Код (Text): ... NTSTATUS status; IO_STATUS_BLOCK iosb; HANDLE hDevice; PIRP pIRP = NULL; PIO_STACK_LOCATION pNextStack; GETVERSIONINPARAMS VersionParams; PVOID pObject; KEVENT event; LARGE_INTEGER timeout; ... status = ObReferenceObjectByHandle(hDevice, GENERIC_READ, 0, KernelMode, &pObject, NULL); ZwClose(hDevice); if(status != STATUS_SUCCESS) { DbgPrint("kdiskid: ObReferenceObjectByHandle fail\n"); return STATUS_INSUFFICIENT_RESOURCES; } KeInitializeEvent(&event, NotificationEvent, FALSE); pIRP = IoAllocateIrp(((PDEVICE_OBJECT)pObject)->StackSize + 1, FALSE); if(pIRP == NULL) { DbgPrint("kdiskid: IoAllocateIrp fail\n"); ObDereferenceObject(pObject); return STATUS_INSUFFICIENT_RESOURCES; } // заполняем IRP pNextStack = IoGetNextIrpStackLocation(pIRP); pNextStack->MajorFunction = IRP_MJ_DEVICE_CONTROL; pNextStack->MinorFunction = 0; pNextStack->Parameters.DeviceIoControl.IoControlCode = SMART_GET_VERSION; pNextStack->Parameters.DeviceIoControl.InputBufferLength = 0; pNextStack->Parameters.DeviceIoControl.OutputBufferLength = sizeof(VersionParams); pNextStack->Parameters.DeviceIoControl.Type3InputBuffer = &VersionParams; pIRP->AssociatedIrp.SystemBuffer = &VersionParams; pIRP->RequestorMode = KernelMode; IoSetCompletionRoutine(pIRP, CompletionRoutine, &event, TRUE, TRUE, TRUE); IoCallDriver(pObject, pIRP); // и писеееец... timeout.QuadPart = -100000000; status = KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, &timeout); if(status == STATUS_SUCCESS) DbgPrint("kdiskid: KeWaitForSingleObject - success\n"); if(status == STATUS_TIMEOUT) DbgPrint("kdiskid: KeWaitForSingleObject - SATUS_TIMEOUT \n"); IoFreeIrp(pIRP); ObDereferenceObject(pObject); в sice ловлю page fault я так понимаю, что что-то с буферами делаю не то код выполняется в PASSIVE_LEVEL помогите чем можете
Смотри в сторону функций IoBuildDeviceIoControlRequest и IoBuildSynchronousFsdRequest. И проверяй результат IoCallDriver. Ждать надо только при возврате STATUS_PENDING.
Пробовал IoBuildDeviceIoControlRequest. Там нет такого нужного параметра как StackSize... В итоге, как и следовало ожидать, BSOD. А если возврат будет не STATUS_PENDING, а, скажем, STATUS_SUCCESS, то CompletionRoutine не вызовется ?
Конечно нет, так как он равен DeviceObject->StackSize. Вызоветься, но в точки зрения производительности лучше в этом случае не ждать.
Я уже говорил, что пробовал IoBuildDeviceIoControlRequest. И, кстати, BSOD вылетал как раз по поводу StackSize. Такой же BSOD вылетает и при IoAllocateIrp если ставлю StackSize = DeviceObject->StackSize. может есть смысл перед IoBuildDeviceIoControlRequest увеличить DeviceObject->StackSize ?
А использовать NtDeviceIoControlFile не годиться? И и почему поле pNextStack->FileObject не заполняешь?
Короче в общем случае посылка IOCTL будет выглядеть так: Код (Text): Status = ObReferenceObjectByHandle(DeviceHandle, (IoControlCode >> 14) & 0x3, IoFileObjectType, KernelMode, &FileObject, NULL); if (!NT_SUCCESS(Status)) return Status; DeviceObject = IoGetRelatedDeviceObject(FileObject); Irp = IoBuildDeviceIoControlRequest(IoControlCode, DeviceObject, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, FALSE, Event, IoStatusBlock); Irp->Tail.Overlay.OriginalFileObject = FileObject; Irp->RequestorMode = KernelMode; StackPtr = IoGetNextIrpStackLocation(Irp); StackPtr->FileObject = FileObject; StackPtr->MajorFunction = IRP_MJ_DEVICE_CONTROL; Status = IoCallDriver(DeviceObject, Irp); if (Status == STATUS_PENDING) { KeWaitForSingleObject(&Event, Executive, PreviousMode, FALSE, NULL ); Status = FileObject->FinalStatus; }
Я меленько опоздал, но тем не менее... <font color="gray][ Maveric</font><!--color--><font color="gray]: я так понимаю, что что-то с буферами делаю не то ]</font><!--color--> Код (Text): pNextStack->Parameters.DeviceIoControl.Type3InputBuffer = &VersionParams; Это неверно. Должно быть: irp->UserBuffer = pOutputBuffer; + должно быть: pIrp->UserIosb = IoStatusBlock; pIrp->UserEvent = Event; + ещё флаги, наверное: pIrp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION; <font color="gray][ Maveric</font><!--color--><font color="gray]: Там нет такого нужного параметра как StackSize ]</font><!--color--> Он тебе вообще не нужен. pDeviceObject->StackSize + 1 нужно только если нужен один доп. блок стека, для использования не по прямому назначению, а просто как буфер пристёгнутый к IRP. В этом случае IoGetNextIrpStackLocation делается 2 раза и инициализируется второй IO_STACK_LOCATION, а в первый (буферный) пихается что-то. <font color="gray][ Maveric</font><!--color--><font color="gray]: А если возврат будет не STATUS_PENDING, а, скажем, STATUS_SUCCESS, то CompletionRoutine не вызовется ? ]</font><!--color--> Последние три параметра в IoSetCompletionRoutine определяют, при каком исходе звать CompletionRoutine. Если все три = TRUE, то CompletionRoutine будет вызвана в любом случае. <font color="gray][ Maveric</font><!--color--><font color="gray]: может есть смысл перед IoBuildDeviceIoControlRequest увеличить DeviceObject->StackSize ? ]</font><!--color--> Нет. Зря паришься с ручным созданием IRP. Этот код должен работать: Код (Text): GETVERSIONINPARAMS VersionParams; KEVENT event; NTSTATUS status; IO_STATUS_BLOCK IoStatus; PIRP pIrp; PDEVICE_OBJECT pDeviceObject; PAGED_CODE(); KeInitializeEvent( &event, NotificationEvent, FALSE ); pIrp = IoBuildDeviceIoControlRequest(SMART_GET_VERSION, pDeviceObject, (PVOID) NULL, 0, &VersionParams, sizeof(VersionParams), FALSE, &event, &IoStatus); if ( pIrp ) { status = IoCallDriver( pDeviceObject, pIrp ); if ( STATUS_PENDING == status ) { KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL ); status = IoStatus.Status; } Если име девайса или символьной ссылки не него заранее известны, то можно не парится с хендлами. Код (Text): PDEVICE_OBJECT pDeviceObject; UNICODE_STRING us; PFILE_OBJECT pFileObject; RtlInitUnicodeString( &us, L"\\??\\PhysicalDrive0" ); status = IoGetDeviceObjectPointer( &us, FILE_READ_ATTRIBUTES, &pFileObject, &pDeviceObject ); // build IRP and call driver ObDereferenceObject( pFileObject );
Four-F, огромное спасибо за внимание. Сейчас всё работает, хотя не мешало бы кое-что прояснить. Код, который ты привёл, очень похож на то что у меня было в самом начале. IRP создавался с помощью IoBuildDeviceIoControlRequest. Но на IoCallDriver вылет BSOD по поводу этих самых StackSize. Я открывал "\\??\\PhysicalDrive0" и уже по хэндлу получал объект (уже понятно, что это лишние телодвижения), и дальше эото самый объект я и подставлял в IoBuildDeviceIoControlRequest. Я так понимаю, что в этом и была ошибка, потому что сделав так, как написал Ms Rem "(DeviceObject = IoGetRelatedDeviceObject(FileObject);" всё стало нормально работать. Честно говоря, хотелось бы услышать комментарии по этому поводу.
Наконец-то я понял. У тебя hDevice соответствует FILE_OBJECT. Ты его, наверное, через (Zw)CreateFile получил. Поэтому твой pObject указывал на FILE_OBJECT, а не на DEVICE_OBJECT. Когда ты звал IoBuildDeviceIoControlRequest, то она делала так: irp = IoAllocateIrp( DeviceObject->StackSize, FALSE ); но DeviceObject был указателем на FILE_OBJECT. Соответственно DeviceObject->StackSize было равно тому, что по этому смещению лежит в FILE_OBJECT. Вот и всё. IoCallDriver по любому кирдыкнулась бы. IoGetDeviceObjectPointer же делает так (псевдо-код): Код (Text): NTSTATUS IoGetDeviceObjectPointer( IN PUNICODE_STRING pusObjectName, IN ACCESS_MASK DesiredAccess, OUT PFILE_OBJECT *out_pFileObject, OUT PDEVICE_OBJECT *out_pDeviceObject ) { PFILE_OBJECT pFileObject OBJECT_ATTRIBUTES oa HANDLE hFile InitializeObjectAttributes( &oa, pusObjectName, ... ) ZwOpenFile( &hFile, DesiredAccess, &oa, ... ) ObReferenceObjectByHandle( hFile, 0, IoFileObjectType, KernelMode, &pFileObject, NULL ) *out_pFileObject = pFileObject *out_pDeviceObject = IoGetRelatedDeviceObject( pFileObject ) ZwClose( hFile ) return STATUS_XXX } Как видишь, тоже ZwOpenFile, но потом IoGetRelatedDeviceObject, чтобы извлечь из файлового объекта указатель на соответствующий ему девайс.
Тут все давным давно решилось. Но... Вообще про разруливание IRP могу посоветовать классную статью Toby Opferman`a. На англицком. http://www.codeproject.com/system/driverdev5asp.asp Там на примире посылки пакетов IRP \driver\tcpip Есть возможность скачать исходник драйвера.