Overview
The I/O Manager is a core component of the Windows kernel responsible for handling all I/O requests from user mode and managing communication between drivers and the operating system. It provides services such as device object creation, IRP life‑cycle management, and dispatch routine handling.
This documentation covers the primary concepts, key functions, structures, and best‑practice patterns for kernel‑mode drivers that interact with the I/O Manager.
Key Functions
DriverEntry
Entry point for a driver. Registers device objects and sets dispatch routines.
NTSTATUS
DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath
);
IoCreateDevice
Creates a device object to represent a functional device.
NTSTATUS
IoCreateDevice(
_In_ PDRIVER_OBJECT DriverObject,
_In_ ULONG DeviceExtensionSize,
_In_opt_ PUNICODE_STRING DeviceName,
_In_ DEVICE_TYPE DeviceType,
_In_ ULONG DeviceCharacteristics,
_In_ BOOLEAN Exclusive,
_Out_ PDEVICE_OBJECT *DeviceObject
);
IoDeleteDevice
Deletes a previously created device object.
VOID
IoDeleteDevice(
_In_ PDEVICE_OBJECT DeviceObject
);
IoCreateSymbolicLink / IoDeleteSymbolicLink
Creates and removes a user‑mode symbolic link to the device.
NTSTATUS
IoCreateSymbolicLink(
_In_ PUNICODE_STRING SymbolicLinkName,
_In_ PUNICODE_STRING DeviceName
);
NTSTATUS
IoDeleteSymbolicLink(
_In_ PUNICODE_STRING SymbolicLinkName
);
Important Structures
DEVICE_OBJECT
typedef struct _DEVICE_OBJECT {
CSHORT Type;
USHORT Size;
LONG ReferenceCount;
struct _DRIVER_OBJECT *DriverObject;
struct _DEVICE_OBJECT *NextDevice;
DEVICE_TYPE DeviceType;
ULONG Characteristics;
PVOID DeviceExtension;
// …
} DEVICE_OBJECT, *PDEVICE_OBJECT;
IO_STACK_LOCATION
typedef struct _IO_STACK_LOCATION {
UCHAR MajorFunction;
UCHAR MinorFunction;
UCHAR Flags;
UCHAR Control;
union {
PIO_SECURITY_CONTEXT SecurityContext;
// …
} Parameters;
// …
} IO_STACK_LOCATION, *PIO_STACK_LOCATION;
IRP (I/O Request Packet)
typedef struct _IRP {
CSHORT Type;
USHORT Size;
PMDL MdlAddress;
ULONG Flags;
union {
struct _IRP *MasterIrp;
PDEVICE_OBJECT DeviceObject;
} AssociatedIrp;
// …
PIO_STACK_LOCATION CurrentIrpStackLocation;
// …
} IRP, *PIRP;
IRP Model & Dispatch Routine
When an I/O request reaches a driver, the I/O Manager creates an IRP and calls the driver’s dispatch routine based on the request’s major function code.
NTSTATUS
DispatchRead(
_In_ PDEVICE_OBJECT DeviceObject,
_Inout_ PIRP Irp
){
// Retrieve parameters from IRP stack
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
// Process read request...
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = bytesRead;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
Sample Minimal Driver
This example demonstrates a simple driver that creates a device, handles create/close and read requests, and cleans up on unload.
#include <ntddk.h>
#define DRIVER_TAG 'tseD'
void DriverUnload(_In_ PDRIVER_OBJECT DriverObject);
NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath);
NTSTATUS DispatchCreateClose(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp);
NTSTATUS DispatchRead(_In_ PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp);
NTSTATUS
DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
UNREFERENCED_PARAMETER(RegistryPath);
PDEVICE_OBJECT deviceObject = NULL;
UNICODE_STRING devName = RTL_CONSTANT_STRING(L"\\Device\\SampleIoMgr");
UNICODE_STRING symLink = RTL_CONSTANT_STRING(L"\\DosDevices\\SampleIoMgr");
NTSTATUS status = IoCreateDevice(
DriverObject,
0,
&devName,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&deviceObject);
if (!NT_SUCCESS(status)) return status;
status = IoCreateSymbolicLink(&symLink, &devName);
if (!NT_SUCCESS(status)) {
IoDeleteDevice(deviceObject);
return status;
}
for (int i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
DriverObject->MajorFunction[i] = DispatchCreateClose;
DriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead;
DriverObject->DriverUnload = DriverUnload;
deviceObject->Flags |= DO_DIRECT_IO;
return STATUS_SUCCESS;
}
void
DriverUnload(PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING symLink = RTL_CONSTANT_STRING(L"\\DosDevices\\SampleIoMgr");
IoDeleteSymbolicLink(&symLink);
IoDeleteDevice(DriverObject->DeviceObject);
}
NTSTATUS
DispatchCreateClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
UNREFERENCED_PARAMETER(DeviceObject);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS
DispatchRead(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
UNREFERENCED_PARAMETER(DeviceObject);
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
ULONG length = irpSp->Parameters.Read.Length;
// Fill buffer with dummy data
RtlZeroMemory(Irp->AssociatedIrp.SystemBuffer, length);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = length;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}