Драйвер №2
Создание объекта-устройство, определение точек входа создания и закрытия объекта-файл и точки входа выгрузки драйвера
Имя проекта – simple2
Описание файла simple2.C
1) Функция DriverEntry
Создает объект-устройство с помощью вызова функции IoCreateDevice:
NTSTATUS IoCreateDevice( IN PDRIVER_OBJECT DriverObject,
IN ULONG DeviceExtensionSize,
IN PUNICODE_STRING DeviceName,
IN DEVICE_TYPE DeviceType,
IN ULONG DeviceCharacteristics,
IN BOOLEAN Exclusive,
OUT PDEVICE_OBJECT *DeviceObject);
Описание см. в DDK Help.
Параметр DriverObject был передан в качестве первого параметра в DriverEntry
Размер структуры DeviceExtension – DeviceExtensionSize – принимаем равным 0.
В качестве имени устройства должна быть указана строка “\Device\Simple2”. Для инициализации переменной типа UNICODE_STRING необходимо воспользоваться функцией RtlInitUnicodeString():
VOID RtlInitUnicodeString(IN OUT PUNICODE_STRING DestinationString,
IN PCWSTR SourceString);
Строка типа PCWSTR может быть задана с помощью макроса L в виде L“\\Device\\Simple2”.
В качестве типа устройства указываем любое значение в интервале 32768…65535.
Характеристик устройства нет (DeviceCharacteristics=0)
Устройство неэксклюзивное (Exclusive = FALSE)
Обязательно проверяется возвращаемого значения. Если оно не равно STATUS_SUCCESS, вызываем return с этим значением.
В противном случае продолжаем инициализацию.
Для объекта – драйвер указываются адреса функций - точек входа
DriverObject->MajorFunction[IRP_MJ_CREATE] = OnCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = OnClose;
DriverObject->DriverUnload = OnDrvUnload;
Возвращаемым значением функции DriverEntry должен быть статус работы функции IoCreateDevice (или любой другой функции, возвращающей значение типа NTSTATUS, вызывавшейся перед выходом из DriverEntry).
2) Функции – обработчики открытия и закрытия объекта-файл.
Прототип функций одинаков. Для данного драйвера их содержимое также одинаково и состоит в успешном завершении запроса в/в.
NTSTATUS OnCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp);
NTSTATUS OnClose(PDEVICE_OBJECT DeviceObject, PIRP Irp);
Завершение запроса в/в.
Запрос в/в описывается структурой IRP, указатель на которую получают наши функции в качестве второго параметра.
В структуре IRP имеется структура, возвращающая статус завершения обработки запроса в/в – IoStatus. В этой структуре нас интересуют 2 поля: поле Status и поле Information.
NTSTATUS Status – статус завершения в/в. При успешной обработке запроса в/в этому полю должно быть присвоено значение STATUS_SUCCESS.
Information – четырехбайтовое поле с дополнительной информацией. Мы будем устанавливать его равным 0.
После установления статуса обработки запроса в/в диспетчеру в/в необходимо указать завершить наш запрос. Для этого служит функция IoCompleteRequest():
VOID IoCompleteRequest(IN PIRP Irp, IN CCHAR PriorityBoost);
С первым параметром все ясно – это указатель на структуру IRP. Второй параметр указывает значение, на которое должно увеличиться значение приоритета потока – инициатора запроса в/в (базовый приоритет такого потока должен быть в диапазоне динамических приоритетов). Если мы не хотим увеличить приоритет потока, мы должны указать значение IO_NO_INCREMENT, определенное в ntddk.h равным 0.
Возвращаемым значением наших функций должно быть STATUS_SUCCESS.
3) Функция – обработчик выгрузки драйвера
Прототип функции
VOID OnDrvUnload(PDRIVER_OBJECT DriverObject);
Функция должна освободить все ресурсы, выделенные в функции DriverEntry. В нашем случае это только объект-устройство. Он освобождается с помощью функции IoDeleteDevice():
VOID IoDeleteDevice(IN PDEVICE_OBJECT DeviceObject);
Как, зная указатель на объект-драйвер, получить список соответствующих ему объектов-устройств, смотри лекцию №5. Напомню, что объект-драйвер поддерживает однонаправленный список устройств через поле DriverObject->DeviceObject и поля DeviceObject->NextDevice.