Рабочая процедура обработки IOCTL запросов
Процедура DeviceControlRoutine предназначена для обработки запросов Диспетчера ввода/вывода, которые он формирует в виде IRP пакетов с кодом IRP_MJ_DEVICE_CONTROL по результатам обращения к драйверу из пользовательских приложений с вызовами DeviceIoControl.
В нашем примере это самая важная функция. Она реализует обработку пяти IOCTL запросов:
Эти IOCTL коды являются пользовательскими — они определены с помощью макроса CTL_CODE в файле Driver.h, который является частью данного проекта, и речь о котором пойдет ниже.
![]() | Определения используемых ниже непривычных для программистов Win32 типов данных (например, UCHAR или PUCHAR) можно найти в DDK в файле Windef.h . |
// (Файл init.cpp) // DeviceControlRoutine: обработчик IRP_MJ_DEVICE_CONTROL запросов // Аргументы: // Указатель на объект нашего FDO // Указатель на структуру IRP, поступившего от Диспетчера ВВ // Возвращает: STATUS_XXX // #define SMALL_VERSION // В том случае, если не закомментировать верхнюю строчку v будет // выполнена компиляция версии, в которой будет обрабатываться только // один тип IOCTL запросов -- IOCTL_MAKE_SYSTEM_CRASH
NTSTATUS DeviceControlRoutine( IN PDEVICE_OBJECT fdo, IN PIRP Irp ) { NTSTATUS status = STATUS_SUCCESS; ULONG BytesTxd =0; // Число переданных/полученных байт (пока 0) PIO_STACK_LOCATION IrpStack=IoGetCurrentIrpStackLocation(Irp);
// Получаем указатель на расширение устройства PEXAMPLE_DEVICE_EXTENSION dx = (PEXAMPLE_DEVICE_EXTENSION)fdo->DeviceExtension; //------------------------------- // Выделяем из IRP собственно значение IOCTL кода, по поводу // которого случился вызов: ULONG ControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode; ULONG method = ControlCode & 0x03;
errDetected=1; }; #if DBG DbgPrint("-Example- Value of x is %X.",x); if(errDetected) DbgPrint("-Example- Except detected in Example driver."); #endif break; }
#ifndef SMALL_VERSION case IOCTL_TOUCH_PORT_378H: { unsigned short ECRegister = 0x378+0x402; #if DBG DbgPrint("-Example- IOCTL_TOUCH_PORT_378H."); #endif // Пробуем программно перевести параллельный порт 378, // сконфигурированный средствами BIOS как ECP+EPP, в // режим EPP. _asm { mov dx,ECRegister ; xor al,al ; out dx,al ; Установить EPP mode 000 mov al,095h ; Биты 7:5 = 100 out dx,al ; Установить EPP mode 100 } // Подобные действия в приложении пользовательского // режима под NT обязательно привело бы к аварийной // выгрузке приложения с сообщением об ошибке! // Практически эти пять строк демонстрируют, что можно // работать с LPT портом под Windows NT ! break; }
case IOCTL_SEND_BYTE_TO_USER: { // Размер данных, поступивших от пользователя: ULONG InputLength = //только лишь для примера IrpStack->Parameters.DeviceIoControl.InputBufferLength; // Размер буфера для данных, ожидаемых пользователем ULONG OutputLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength; #if DBG DbgPrint("-Example- Buffer outlength %d",OutputLength); #endif
if( OutputLengthAssociatedIrp.SystemBuffer; #if DBG DbgPrint("-Example- Method : BUFFERED."); #endif } else if (method==METHOD_NEITHER) { buff=(unsigned char*)Irp->UserBuffer; #if DBG DbgPrint("-Example- Method : NEITHER."); #endif } else { #if DBG DbgPrint("-Example- Method : unsupported."); #endif status = STATUS_INVALID_DEVICE_REQUEST; break; } #if DBG DbgPrint("-Example- Buffer address is %08X",buff); #endif *buff=33; // Любимое число Штирлица BytesTxd = 1; // Передали 1 байт break; } #endif // SMALL_VERSION // Ошибочный запрос (код IOCTL, который не обрабатывается): default: status = STATUS_INVALID_DEVICE_REQUEST; } // Освобождение спин-блокировки KeReleaseSpinLock(&MySpinLock,irql);
#if DBG DbgPrint("-Example- DeviceIoControl: %d bytes written.", (int)BytesTxd); #endif
return CompleteIrp(Irp,status,BytesTxd); // Завершение IRP }
![]() |
Корректность фрагмента кода, посвященного обработке IOCTL запроса IOCTL_TOUCH_PORT_378H, может вызвать споры, поскольку действует "напролом", не обращая внимания на то, что в системе могут быть устройства и драйвера, работающие с этим портом, существование которых следует учитывать. Однако цель данного примера — показать, что само по себе обращение к аппаратным ресурсам в режиме ядра является делом тривиальным, не имеющим ограничений со стороны операционной системы. |