Список контрольных кодов IOCTL и примеры использования

Переводчик Google

Dragokas

Angry & Scary Developer
Команда форума
Супер-Модератор
Разработчик
Клуб переводчиков
Сообщения
8,034
Решения
19
Реакции
6,845
DeviceIoControl — это функция в Windows API, которая используется для отправки управляющих команд (IOCTL — Input/Output Control) драйверам устройств. Она предоставляет приложениям возможность взаимодействовать с аппаратным обеспечением или виртуальными устройствами на более низком уровне, чем стандартные операции чтения/записи.

Основная цель функции — выполнять специфические операции, которые не входят в стандартный набор функций ввода/вывода. Например, с её помощью можно:
  • Управлять физическими устройствами (например, дисками, принтерами или сетевыми адаптерами).
  • Выполнять диагностику или получать подробную информацию о состоянии устройств.
  • Отправлять команды для выполнения уникальных задач, поддерживаемых конкретным драйвером устройства.
Функция является универсальным интерфейсом, который позволяет разработчикам программ обращаться к функциям, предоставляемым драйверами, используя уникальные управляющие коды (IOCTL). Она требует дескриптора устройства, который предварительно создаётся через вызов функции CreateFile.

Применение DeviceIoControl востребовано в задачах системного программирования, разработке драйверов и работе с низкоуровневым оборудованием.

Данные коды объявлены в заголовочном файле winioctl.h
Например:
Код:
#define FSCTL_FILESYSTEM_GET_STATISTICS CTL_CODE(FILE_DEVICE_FILE_SYSTEM,24,METHOD_BUFFERED,FILE_ANY_ACCESS)
Если вам нужно узнать результирующее число (например, чтобы использовать в другой среде, не C++), обратимся к объявлению CTL_CODE:
Код:
#define CTL_CODE(DeviceType,Function,Method,Access) (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
Что соответствует:
DeviceType: #define FILE_DEVICE_FILE_SYSTEM 0x00000009
Function: 24 (Passed in as constant)
Method: #define METHOD_BUFFERED 0
Access: #define FILE_ANY_ACCESS 0
Рассчет выглядеть будет так:
Код:
= (9 << 16) | (0 << 14) | (24 << 2) | (0)
= 0x00090060 (в 16-ричном виде), или 589920 (в десятичном виде)

Либо можно взять готовые константы по ссылкам:
http://www.ioctls.net/
https://github.com/wine-mirror/wine/blob/master/include/winioctl.h

Наиболее надежным способом является поиск констант и описания в официальной документации Microsoft:
https://github.com/MicrosoftDocs/sdk-api/tree/docs
либо из официального хидера, который можно получить вместе с установкой Visual Studio или пакета WDK.

Установка Visual Studio и создание проекта для общения с драйвером устройства
Чтобы создать программу на языке C/C++ и подключить winioctl.h, можно установить Visual Studio 2022.
Во время установки выбрать дополнительные отдельные компоненты, как:
- Пакет SDK для Windows 11 последней версии
- MSVC 143 библиотеки C++ для VS 2022 с устранением рисков Spectre (последняя версия)
- Windows Driver Kit

Затем Установить по этой инструкции:
- Пакет SDK
- Пакет WDK

Свой проект можно создать, запустив Visual Studio - Создание проекта - тип Driver - выбираем к примеру Empty Desktop Application for Drivers (Universal):

1736464117443.webp


Затем, допустим, пишем такой код:
C++:
#include <windows.h>
#include "winioctl.h"
#include <iostream>
#include <string>

void CheckPartitionStyle(const std::string& drive)
{
    std::string drivePath = "\\\\.\\" + drive;
    HANDLE hDevice = CreateFileA(
        drivePath.c_str(),
        GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
        nullptr, OPEN_EXISTING, 0, nullptr
    );

    if (hDevice == INVALID_HANDLE_VALUE) {
        std::cerr << "Failed to open drive " << drive << ". Error: " << GetLastError() << std::endl;
        return;
    }

    PARTITION_INFORMATION_EX partitionInfo;
    DWORD bytesReturned = 0;

    if (DeviceIoControl(
        hDevice, IOCTL_DISK_GET_PARTITION_INFO_EX,
        nullptr, 0, &partitionInfo, sizeof(partitionInfo), &bytesReturned, nullptr))
    {
        if (partitionInfo.PartitionStyle == PARTITION_STYLE_MBR) {
            std::cout << "Partition Style: MBR" << std::endl;
        }
        else if (partitionInfo.PartitionStyle == PARTITION_STYLE_GPT) {
            std::cout << "Partition Style: GPT" << std::endl;
        }
        else if (partitionInfo.PartitionStyle == PARTITION_STYLE_RAW) {
            std::cout << "Partition Style: RAW" << std::endl;
        }
        else {
            std::cout << "Partition Style: UNKNOWN" << std::endl;
        }
    }
    else {
        std::cerr << "Failed to get partition information for " << drive << ". Error: " << GetLastError() << std::endl;
    }

    CloseHandle(hDevice);
}


int main()
{
    char driveLetter = 'A';
    for (; driveLetter <= 'Z'; ++driveLetter)
    {
        std::string drive = std::string(1, driveLetter) + ":";
        UINT driveType = GetDriveTypeA(drive.c_str());

        if (driveType != DRIVE_UNKNOWN && driveType != DRIVE_NO_ROOT_DIR)
        {
            std::cout << "Drive: " << drive.c_str() << std::endl;
            CheckPartitionStyle(drive);
        }
    }
 
    system("pause");
    return 0;
}

В нём мы подключили хидеры windows.h и winioctl.h. Код перечисляет все диски, проверяет их тип и выводит стиль разметки: MBR или GPT с помощью запроса DeviceIoControl с кодом IOCTL_DISK_GET_PARTITION_INFO_EX, который возвращает результат в структуру PARTITION_INFORMATION_EX.
Здесь мы не общаемся ни с каким драйвером, однако задачей было показать простейший вызов.
Готовые проекты с примерами непосредственной комуникации с драйверами и исходники самих драйверов можно скачать из репозитория Майкрософт: Driver samples for Windows 11
 
Последнее редактирование:
503 ошибка по ссылке
 
Последнее редактирование:
У меня норм открывается.
 
Похоже был какой-то временный сбой, у меня тоже открылось нормально.
 
Добавил примеры использования в быту этих кодов.
 
Назад
Сверху Снизу