DeviceIoControl
The DeviceIoControl function sends a control code directly to a specified device driver to retrieve information or modify device state.
Syntax
BOOL DeviceIoControl(
HANDLE hDevice,
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped
);
Parameters
| Parameter | Description |
|---|---|
hDevice |
A handle to the device. This handle is obtained by calling the CreateFile function. |
dwIoControlCode |
The control code for the operation. This parameter value specifies the actual device-dependent operation to perform. |
lpInBuffer |
A pointer to a buffer that contains data required for the operation specified by the dwIoControlCode parameter. This parameter can be NULL if the dwIoControlCode parameter specifies an operation that does not require input data. |
nInBufferSize |
The size, in bytes, of the buffer pointed to by lpInBuffer. |
lpOutBuffer |
A pointer to a buffer that receives data from the specified device. This parameter can be NULL if the dwIoControlCode parameter specifies an operation that does not return data. |
nOutBufferSize |
The size, in bytes, of the buffer pointed to by lpOutBuffer. |
lpBytesReturned |
A pointer to a DWORD value that receives the size, in bytes, of the data returned by the device driver, located in the buffer pointed to by lpOutBuffer. If this parameter is NULL, the information is not returned. |
lpOverlapped |
A pointer to an OVERLAPPED structure that is required for asynchronous operations. See the Remarks section for more information. This parameter can be NULL if the hDevice handle is not opened with FILE_FLAG_OVERLAPPED. |
Return Value
If the operation succeeds, the function returns a nonzero value. If the operation fails, the return value is zero. To get extended error information, call GetLastError.
Remarks
The DeviceIoControl function is the primary mechanism for device-specific operations that are not covered by the standard file I/O functions. It allows applications to communicate directly with device drivers.
The dwIoControlCode parameter is a crucial part of this function. It is a 32-bit value that encodes information about the operation, including:
- The type of device the operation is for.
- The specific function within the device driver to call.
- Whether the operation reads from or writes to the device.
- Whether the operation is buffered or direct I/O.
Device drivers define their own set of IOCTL codes. These codes are typically defined in header files specific to the device or driver.
Important
The exact set of IOCTL codes available and their behavior is entirely dependent on the specific device driver being targeted. Always consult the documentation for the device or driver to understand the valid IOCTL codes and their associated input and output buffer structures.
Commonly Used IOCTLs
While specific codes vary, here are some general categories and examples of IOCTLs you might encounter:
- Disk Management: Getting disk geometry, partitioning information, or performing raw disk access.
- Network Adapters: Querying adapter statistics, setting adapter properties.
- Input Devices: Controlling LED states, reading raw input data.
Example: Getting Disk Geometry
The following example demonstrates how to use DeviceIoControl to get disk geometry information. Note that the exact IOCTL code (e.g., IOCTL_DISK_GET_DRIVE_GEOMETRY) and the structure used for output (DISKDRIVE_GEOMETRY) are standard but specific to disk devices.
#include <windows.h>
#include <fileapi.h>
#include <ioapiset.h>
#include <iostream>
int main() {
HANDLE hDevice = CreateFile(
L"\\\\.\\PhysicalDrive0", // Target the first physical drive
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL
);
if (hDevice == INVALID_HANDLE_VALUE) {
std::cerr << "Failed to open device. Error: " << GetLastError() << std::endl;
return 1;
}
DISKDRIVE_GEOMETRY geometry;
DWORD bytesReturned;
if (DeviceIoControl(
hDevice,
IOCTL_DISK_GET_DRIVE_GEOMETRY,
NULL,
0,
&geometry,
sizeof(geometry),
&bytesReturned,
NULL
)) {
std::cout << "Disk Geometry Information:" << std::endl;
std::cout << " Cylinders: " << geometry.Cylinders.QuadPart << std::endl;
std::cout << " TracksPerCylinder: " << geometry.TracksPerCylinder << std::endl;
std::cout << " SectorsPerTrack: " << geometry.SectorsPerTrack << std::endl;
std::cout << " BytesPerSector: " << geometry.BytesPerSector << std::endl;
std::cout << " TotalSectors: " << geometry.TotalSectors.QuadPart << std::endl;
} else {
std::cerr << "DeviceIoControl failed. Error: " << GetLastError() << std::endl;
}
CloseHandle(hDevice);
return 0;
}
Security Considerations
Using DeviceIoControl directly with arbitrary IOCTL codes can pose security risks if not done carefully. Malicious or malformed IOCTL codes could lead to unintended system behavior, data corruption, or security vulnerabilities. Always validate input and ensure you are using well-documented and trusted IOCTL codes.