以下是一个驱动层 + 用户态的交互示例,覆盖"超时设置+设备状态查询+数据读写"全流程,包含驱动代码、用户态头文件、用户态调用代码。
一、整体架构说明
| 层级 | 核心文件/功能 |
|---|---|
| 驱动层 | 实现 IRP_MJ_DEVICE_CONTROL 处理逻辑,响应自定义IOCTL(设置超时、查状态、读写数据) |
| 接口层 | ioapist.h:封装IOCTL、结构体、用户态API声明 |
| 用户态层 | 调用 ioapist.h 封装的API,完成设备打开、参数下发、数据交互、设备关闭 |
二、步骤1:定义公共接口头文件 ioapist.h
ioapist.h 并非 Windows 系统原生公开的头文件(不属于 MSDN/Windows SDK 标准头文件),而是行业 / 厂商自定义的接口头文件,核心用于封装设备 I/O 操作的 API 集合(尤其是通过DeviceIoControl实现的设备控制、数据交互逻辑),常见于硬件驱动开发、工业控制、嵌入式 Windows 设备通信等场景。
该文件是驱动和用户态的"协议约定",需保证两端结构体、IOCTL完全一致。
c
#ifndef IOAPIST_H
#define IOAPIST_H
#ifdef __cplusplus
extern "C" {
#endif
/************************ 1. 基础常量定义 ************************/
// 自定义设备类型(避开Windows系统预留值,范围0x8000-0xFFFF)
#define FILE_DEVICE_CUSTOM_DEV 0x8000
// 缓冲区方式(驱动与用户态数据交互方式,这里用缓冲式,最通用)
#define METHOD_CUSTOM METHOD_BUFFERED
// 访问权限
#define FILE_CUSTOM_ACCESS FILE_ANY_ACCESS
// 封装CTL_CODE宏,生成唯一IOCTL控制码
#define CUSTOM_CTL_CODE(code) \
CTL_CODE(FILE_DEVICE_CUSTOM_DEV, code, METHOD_CUSTOM, FILE_CUSTOM_ACCESS)
/************************ 2. IOCTL控制码定义 ************************/
#define IOCTL_SET_TIMEOUT CUSTOM_CTL_CODE(0x0001) // 设置超时
#define IOCTL_GET_DEVICE_STATUS CUSTOM_CTL_CODE(0x0002) // 获取设备状态
#define IOCTL_WRITE_DATA CUSTOM_CTL_CODE(0x0003) // 写数据到设备
#define IOCTL_READ_DATA CUSTOM_CTL_CODE(0x0004) // 从设备读数据
/************************ 3. 数据交互结构体(驱动/用户态一致) ************************/
// 超时设置结构体(对应IOCTL_SET_TIMEOUT)
typedef struct _DEV_TIMEOUT {
DWORD dwReadTimeout; // 读超时(毫秒)
DWORD dwWriteTimeout; // 写超时(毫秒)
DWORD dwCtrlTimeout; // 控制指令超时(毫秒)
} DEV_TIMEOUT, *PDEV_TIMEOUT;
// 设备状态结构体(对应IOCTL_GET_DEVICE_STATUS)
typedef struct _DEV_STATUS {
BOOL bOnline; // 设备是否在线(TRUE/FALSE)
DWORD dwErrorCount; // 累计错误数
DWORD dwBufferSize; // 设备缓存区大小
DWORD dwReserved; // 预留字段(保证结构体对齐)
} DEV_STATUS, *PDEV_STATUS;
// 数据读写结构体(对应IOCTL_READ/WRITE_DATA)
typedef struct _DEV_DATA {
BYTE szBuffer[1024]; // 数据缓冲区
DWORD dwDataLen; // 有效数据长度(输入/输出)
DWORD dwErrorCode; // 操作错误码(输出)
} DEV_DATA, *PDEV_DATA;
/************************ 4. 辅助常量/枚举 ************************/
// 默认设备路径(用户态打开设备用)
#define DEFAULT_DEVICE_PATH L"\\\\.\\CustomDevice"
// 超时默认值
#define DEFAULT_READ_TIMEOUT 5000 // 5秒
#define DEFAULT_WRITE_TIMEOUT 3000 // 3秒
#define DEFAULT_CTRL_TIMEOUT 2000 // 2秒
// 设备状态枚举(辅助用户态判断)
typedef enum {
DEV_STATUS_OFFLINE = 0,
DEV_STATUS_ONLINE = 1,
DEV_STATUS_ERROR = 2
} DEV_STATUS_ENUM;
/************************ 5. 用户态封装API声明 ************************/
// 打开设备(封装CreateFileW)
HANDLE __stdcall DevOpen(
LPCWSTR lpDevicePath, // 设备路径(如DEFAULT_DEVICE_PATH)
DWORD dwDesiredAccess // 访问权限(GENERIC_READ | GENERIC_WRITE)
);
// 关闭设备(封装CloseHandle)
VOID __stdcall DevClose(HANDLE hDevice);
// 设置设备超时(封装DeviceIoControl + IOCTL_SET_TIMEOUT)
BOOL __stdcall DevSetTimeout(
HANDLE hDevice,
PDEV_TIMEOUT pTimeout
);
// 获取设备状态(封装DeviceIoControl + IOCTL_GET_DEVICE_STATUS)
BOOL __stdcall DevGetStatus(
HANDLE hDevice,
PDEV_STATUS pStatus
);
// 写数据到设备(封装DeviceIoControl + IOCTL_WRITE_DATA)
BOOL __stdcall DevWriteData(
HANDLE hDevice,
PDEV_DATA pData
);
// 从设备读数据(封装DeviceIoControl + IOCTL_READ_DATA)
BOOL __stdcall DevReadData(
HANDLE hDevice,
PDEV_DATA pData
);
#ifdef __cplusplus
}
#endif
#endif // IOAPIST_H
三、步骤2:驱动层实现(内核态,C语言)
驱动基于WDM框架开发,核心实现 IRP_MJ_DEVICE_CONTROL 回调,处理用户态下发的IOCTL指令。
1. 驱动头文件(CustomDev.h)
c
#ifndef CUSTOM_DEV_H
#define CUSTOM_DEV_H
#include <wdm.h>
#include "ioapist.h" // 引入公共接口头文件
// 设备扩展结构体(保存设备状态、超时配置等)
typedef struct _DEVICE_EXTENSION {
PDEVICE_OBJECT pDeviceObj; // 设备对象指针
UNICODE_STRING ustrDeviceName; // 设备名
UNICODE_STRING ustrSymLinkName; // 符号链接名
// 设备运行状态
DEV_TIMEOUT stTimeout; // 超时配置(用户态下发)
DEV_STATUS stStatus; // 设备状态
BYTE szDevBuffer[1024]; // 设备内部缓存区
DWORD dwDevBufferLen; // 缓存区有效数据长度
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
// 函数声明
NTSTATUS DriverUnload(PDRIVER_OBJECT pDriverObj);
NTSTATUS DispatchCreateClose(PDEVICE_OBJECT pDeviceObj, PIRP pIrp);
NTSTATUS DispatchDeviceControl(PDEVICE_OBJECT pDeviceObj, PIRP pIrp);
#endif // CUSTOM_DEV_H
2. 驱动实现文件(CustomDev.c)
c
#include "CustomDev.h"
/************************ 1. 驱动入口函数 ************************/
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegistryPath) {
NTSTATUS status;
PDEVICE_OBJECT pDeviceObj = NULL;
PDEVICE_EXTENSION pDevExt = NULL;
UNICODE_STRING ustrDeviceName;
UNICODE_STRING ustrSymLinkName;
// 1. 设置驱动卸载例程
pDriverObj->DriverUnload = DriverUnload;
// 2. 设置分发例程(处理Create/Close/DeviceControl)
pDriverObj->MajorFunction[IRP_MJ_CREATE] = DispatchCreateClose;
pDriverObj->MajorFunction[IRP_MJ_CLOSE] = DispatchCreateClose;
pDriverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDeviceControl;
// 3. 创建设备对象
RtlInitUnicodeString(&ustrDeviceName, L"\\Device\\CustomDevice");
status = IoCreateDevice(
pDriverObj, // 驱动对象
sizeof(DEVICE_EXTENSION), // 设备扩展大小
&ustrDeviceName, // 设备名
FILE_DEVICE_CUSTOM_DEV, // 设备类型(与ioapist.h一致)
0, // 设备特性
FALSE, // 非独占
&pDeviceObj // 输出设备对象
);
if (!NT_SUCCESS(status)) {
DbgPrint("IoCreateDevice failed, status: 0x%X\n", status);
return status;
}
// 4. 初始化设备扩展
pDevExt = (PDEVICE_EXTENSION)pDeviceObj->DeviceExtension;
pDevExt->pDeviceObj = pDeviceObj;
pDevExt->ustrDeviceName = ustrDeviceName;
// 初始化默认超时
pDevExt->stTimeout.dwReadTimeout = DEFAULT_READ_TIMEOUT;
pDevExt->stTimeout.dwWriteTimeout = DEFAULT_WRITE_TIMEOUT;
pDevExt->stTimeout.dwCtrlTimeout = DEFAULT_CTRL_TIMEOUT;
// 初始化设备状态
pDevExt->stStatus.bOnline = TRUE; // 默认在线
pDevExt->stStatus.dwErrorCount = 0; // 无错误
pDevExt->stStatus.dwBufferSize = 1024; // 缓存区大小1024
pDevExt->dwDevBufferLen = 0; // 初始无数据
// 5. 创建符号链接(用户态可通过\\.\CustomDevice访问)
RtlInitUnicodeString(&ustrSymLinkName, L"\\DosDevices\\CustomDevice");
pDevExt->ustrSymLinkName = ustrSymLinkName;
status = IoCreateSymbolicLink(&ustrSymLinkName, &ustrDeviceName);
if (!NT_SUCCESS(status)) {
DbgPrint("IoCreateSymbolicLink failed, status: 0x%X\n", status);
IoDeleteDevice(pDeviceObj);
return status;
}
DbgPrint("CustomDev Driver Load Success!\n");
return STATUS_SUCCESS;
}
/************************ 2. 驱动卸载例程 ************************/
NTSTATUS DriverUnload(PDRIVER_OBJECT pDriverObj) {
PDEVICE_OBJECT pDeviceObj = pDriverObj->DeviceObject;
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDeviceObj->DeviceExtension;
// 删除符号链接
IoDeleteSymbolicLink(&pDevExt->ustrSymLinkName);
// 删除设备对象
IoDeleteDevice(pDeviceObj);
DbgPrint("CustomDev Driver Unload Success!\n");
return STATUS_SUCCESS;
}
/************************ 3. Create/Close分发例程 ************************/
NTSTATUS DispatchCreateClose(PDEVICE_OBJECT pDeviceObj, PIRP pIrp) {
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDeviceObj->DeviceExtension;
NTSTATUS status = STATUS_SUCCESS;
// 模拟:打开设备时标记在线状态
if (pIrp->CurrentLocation == 1 && pIrp->MajorFunction == IRP_MJ_CREATE) {
pDevExt->stStatus.bOnline = TRUE;
DbgPrint("Device Opened!\n");
}
// 关闭设备时标记离线
else if (pIrp->CurrentLocation == 1 && pIrp->MajorFunction == IRP_MJ_CLOSE) {
pDevExt->stStatus.bOnline = FALSE;
DbgPrint("Device Closed!\n");
}
// 完成IRP
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return status;
}
/************************ 4. DeviceControl分发例程(核心) ************************/
NTSTATUS DispatchDeviceControl(PDEVICE_OBJECT pDeviceObj, PIRP pIrp) {
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION pIoStack = IoGetCurrentIrpStackLocation(pIrp);
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDeviceObj->DeviceExtension;
ULONG ulIoControlCode = pIoStack->Parameters.DeviceIoControl.IoControlCode;
ULONG ulInputLen = pIoStack->Parameters.DeviceIoControl.InputBufferLength;
ULONG ulOutputLen = pIoStack->Parameters.DeviceIoControl.OutputBufferLength;
DbgPrint("DispatchDeviceControl: IOCTL=0x%X\n", ulIoControlCode);
/************************ 处理IOCTL_SET_TIMEOUT ************************/
if (ulIoControlCode == IOCTL_SET_TIMEOUT) {
// 校验输入缓冲区大小
if (ulInputLen != sizeof(DEV_TIMEOUT)) {
status = STATUS_INVALID_PARAMETER;
DbgPrint("IOCTL_SET_TIMEOUT: Input buffer size error!\n");
goto End;
}
// 读取用户态下发的超时参数
PDEV_TIMEOUT pTimeout = (PDEV_TIMEOUT)pIrp->AssociatedIrp.SystemBuffer;
// 保存到设备扩展
pDevExt->stTimeout = *pTimeout;
DbgPrint("Set Timeout: Read=%dms, Write=%dms, Ctrl=%dms\n",
pTimeout->dwReadTimeout, pTimeout->dwWriteTimeout, pTimeout->dwCtrlTimeout);
}
/************************ 处理IOCTL_GET_DEVICE_STATUS ************************/
else if (ulIoControlCode == IOCTL_GET_DEVICE_STATUS) {
// 校验输出缓冲区大小
if (ulOutputLen != sizeof(DEV_STATUS)) {
status = STATUS_INVALID_PARAMETER;
DbgPrint("IOCTL_GET_DEVICE_STATUS: Output buffer size error!\n");
goto End;
}
// 将设备状态写入输出缓冲区(返回给用户态)
PDEV_STATUS pStatus = (PDEV_STATUS)pIrp->AssociatedIrp.SystemBuffer;
*pStatus = pDevExt->stStatus;
// 设置返回数据长度
pIrp->IoStatus.Information = sizeof(DEV_STATUS);
DbgPrint("Get Status: Online=%d, ErrorCount=%d\n",
pStatus->bOnline, pStatus->dwErrorCount);
}
/************************ 处理IOCTL_WRITE_DATA ************************/
else if (ulIoControlCode == IOCTL_WRITE_DATA) {
// 校验输入缓冲区大小
if (ulInputLen != sizeof(DEV_DATA)) {
status = STATUS_INVALID_PARAMETER;
DbgPrint("IOCTL_WRITE_DATA: Input buffer size error!\n");
goto End;
}
// 读取用户态下发的数据
PDEV_DATA pData = (PDEV_DATA)pIrp->AssociatedIrp.SystemBuffer;
if (pData->dwDataLen > 1024) { // 校验数据长度
status = STATUS_BUFFER_OVERFLOW;
pData->dwErrorCode = STATUS_BUFFER_OVERFLOW;
DbgPrint("IOCTL_WRITE_DATA: Data too long!\n");
goto End;
}
// 将数据拷贝到设备内部缓存
RtlCopyMemory(pDevExt->szDevBuffer, pData->szBuffer, pData->dwDataLen);
pDevExt->dwDevBufferLen = pData->dwDataLen;
pData->dwErrorCode = STATUS_SUCCESS; // 写入成功
pIrp->IoStatus.Information = sizeof(DEV_DATA);
DbgPrint("Write Data: Len=%d, Data=%s\n", pData->dwDataLen, pData->szBuffer);
}
/************************ 处理IOCTL_READ_DATA ************************/
else if (ulIoControlCode == IOCTL_READ_DATA) {
// 校验输出缓冲区大小
if (ulOutputLen != sizeof(DEV_DATA)) {
status = STATUS_INVALID_PARAMETER;
DbgPrint("IOCTL_READ_DATA: Output buffer size error!\n");
goto End;
}
// 读取设备内部缓存数据,返回给用户态
PDEV_DATA pData = (PDEV_DATA)pIrp->AssociatedIrp.SystemBuffer;
RtlCopyMemory(pData->szBuffer, pDevExt->szDevBuffer, pDevExt->dwDevBufferLen);
pData->dwDataLen = pDevExt->dwDevBufferLen;
pData->dwErrorCode = STATUS_SUCCESS;
pIrp->IoStatus.Information = sizeof(DEV_DATA);
DbgPrint("Read Data: Len=%d, Data=%s\n", pData->dwDataLen, pData->szBuffer);
}
/************************ 未知IOCTL ************************/
else {
status = STATUS_NOT_SUPPORTED;
DbgPrint("Unsupported IOCTL: 0x%X\n", ulIoControlCode);
goto End;
}
End:
// 完成IRP
pIrp->IoStatus.Status = status;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return status;
}
四、步骤3:用户态实现(ioapist.c + 测试程序)
1. 封装API实现(ioapist.c)
c
#include <windows.h>
#include <stdio.h>
#include "ioapist.h"
/************************ 1. 打开设备 ************************/
HANDLE __stdcall DevOpen(LPCWSTR lpDevicePath, DWORD dwDesiredAccess) {
if (lpDevicePath == NULL) {
lpDevicePath = DEFAULT_DEVICE_PATH;
}
// 打开设备(需管理员权限)
HANDLE hDevice = CreateFileW(
lpDevicePath,
dwDesiredAccess,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hDevice == INVALID_HANDLE_VALUE) {
DWORD dwErr = GetLastError();
printf("DevOpen failed! ErrCode=0x%X\n", dwErr);
return NULL;
}
return hDevice;
}
/************************ 2. 关闭设备 ************************/
VOID __stdcall DevClose(HANDLE hDevice) {
if (hDevice != NULL && hDevice != INVALID_HANDLE_VALUE) {
CloseHandle(hDevice);
printf("DevClose success!\n");
}
}
/************************ 3. 设置超时 ************************/
BOOL __stdcall DevSetTimeout(HANDLE hDevice, PDEV_TIMEOUT pTimeout) {
if (hDevice == NULL || pTimeout == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
DWORD dwBytesReturned = 0;
BOOL bResult = DeviceIoControl(
hDevice,
IOCTL_SET_TIMEOUT,
pTimeout,
sizeof(DEV_TIMEOUT),
NULL,
0,
&dwBytesReturned,
NULL
);
if (!bResult) {
DWORD dwErr = GetLastError();
printf("DevSetTimeout failed! ErrCode=0x%X\n", dwErr);
} else {
printf("DevSetTimeout success! Read=%dms, Write=%dms, Ctrl=%dms\n",
pTimeout->dwReadTimeout, pTimeout->dwWriteTimeout, pTimeout->dwCtrlTimeout);
}
return bResult;
}
/************************ 4. 获取设备状态 ************************/
BOOL __stdcall DevGetStatus(HANDLE hDevice, PDEV_STATUS pStatus) {
if (hDevice == NULL || pStatus == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
DWORD dwBytesReturned = 0;
BOOL bResult = DeviceIoControl(
hDevice,
IOCTL_GET_DEVICE_STATUS,
NULL,
0,
pStatus,
sizeof(DEV_STATUS),
&dwBytesReturned,
NULL
);
if (!bResult) {
DWORD dwErr = GetLastError();
printf("DevGetStatus failed! ErrCode=0x%X\n", dwErr);
} else {
printf("DevGetStatus success! Online=%d, ErrorCount=%d, BufferSize=%d\n",
pStatus->bOnline, pStatus->dwErrorCount, pStatus->dwBufferSize);
}
return bResult;
}
/************************ 5. 写数据 ************************/
BOOL __stdcall DevWriteData(HANDLE hDevice, PDEV_DATA pData) {
if (hDevice == NULL || pData == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
DWORD dwBytesReturned = 0;
BOOL bResult = DeviceIoControl(
hDevice,
IOCTL_WRITE_DATA,
pData,
sizeof(DEV_DATA),
pData, // 输出错误码到同一个结构体
sizeof(DEV_DATA),
&dwBytesReturned,
NULL
);
if (!bResult) {
DWORD dwErr = GetLastError();
printf("DevWriteData failed! ErrCode=0x%X\n", dwErr);
} else {
printf("DevWriteData success! Len=%d, Data=%s, ErrCode=0x%X\n",
pData->dwDataLen, pData->szBuffer, pData->dwErrorCode);
}
return bResult;
}
/************************ 6. 读数据 ************************/
BOOL __stdcall DevReadData(HANDLE hDevice, PDEV_DATA pData) {
if (hDevice == NULL || pData == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
DWORD dwBytesReturned = 0;
BOOL bResult = DeviceIoControl(
hDevice,
IOCTL_READ_DATA,
NULL,
0,
pData,
sizeof(DEV_DATA),
&dwBytesReturned,
NULL
);
if (!bResult) {
DWORD dwErr = GetLastError();
printf("DevReadData failed! ErrCode=0x%X\n", dwErr);
} else {
printf("DevReadData success! Len=%d, Data=%s, ErrCode=0x%X\n",
pData->dwDataLen, pData->szBuffer, pData->dwErrorCode);
}
return bResult;
}
2. 用户态测试程序(TestApp.c)
c
#include <windows.h>
#include <stdio.h>
#include "ioapist.h"
int main() {
HANDLE hDevice = NULL;
DEV_TIMEOUT stTimeout = {0};
DEV_STATUS stStatus = {0};
DEV_DATA stWriteData = {0};
DEV_DATA stReadData = {0};
/************************ 1. 打开设备 ************************/
hDevice = DevOpen(DEFAULT_DEVICE_PATH, GENERIC_READ | GENERIC_WRITE);
if (hDevice == NULL) {
printf("Open Device Failed!\n");
return -1;
}
printf("Open Device Success!\n");
/************************ 2. 设置超时 ************************/
stTimeout.dwReadTimeout = 6000; // 6秒
stTimeout.dwWriteTimeout = 4000; // 4秒
stTimeout.dwCtrlTimeout = 3000; // 3秒
if (!DevSetTimeout(hDevice, &stTimeout)) {
goto Cleanup;
}
/************************ 3. 获取设备状态 ************************/
if (!DevGetStatus(hDevice, &stStatus)) {
goto Cleanup;
}
/************************ 4. 写数据到设备 ************************/
char szWriteBuf[] = "Hello Custom Device!";
RtlCopyMemory(stWriteData.szBuffer, szWriteBuf, strlen(szWriteBuf));
stWriteData.dwDataLen = strlen(szWriteBuf);
if (!DevWriteData(hDevice, &stWriteData)) {
goto Cleanup;
}
/************************ 5. 从设备读数据 ************************/
RtlZeroMemory(&stReadData, sizeof(DEV_DATA));
if (!DevReadData(hDevice, &stReadData)) {
goto Cleanup;
}
/************************ 6. 清理资源 ************************/
Cleanup:
DevClose(hDevice);
printf("Test App Exit!\n");
return 0;
}
五、编译与运行说明
1. 驱动编译(WDK环境)
- 依赖:Windows Driver Kit(WDK 10+);
- 配置:驱动项目属性中,选择"Kernel Mode Driver",平台选择x64/x86;
- 输出:生成
CustomDev.sys驱动文件。
2. 用户态编译(VS环境)
- 依赖:Visual Studio 2019+,Windows SDK;
- 配置:控制台项目,将
ioapist.h、ioapist.c、TestApp.c加入项目; - 编译选项:启用
Unicode,平台选择与驱动一致(x64/x86); - 输出:生成
TestApp.exe可执行文件。
3. 运行步骤
- 安装驱动:通过
sc create CustomDev type= kernel binPath= "C:\CustomDev.sys"创建服务,sc start CustomDev启动驱动; - 以管理员权限运行
TestApp.exe; - 查看输出:控制台会打印各步骤结果,驱动侧可通过
DebugView查看DbgPrint日志; - 卸载驱动:
sc stop CustomDev+sc delete CustomDev。
六、关键细节与注意事项
- 权限要求 :用户态程序需管理员权限(否则
CreateFile打开设备失败); - 结构体对齐:驱动和用户态的结构体必须保证内存对齐(避免数据解析错误);
- 错误处理 :
- 驱动侧:通过
DbgPrint打印调试信息,用NT_SUCCESS判断状态; - 用户态:通过
GetLastError获取错误码,常见错误:ERROR_INVALID_HANDLE:设备句柄无效;ERROR_NOT_SUPPORTED:驱动不支持该IOCTL;ERROR_ACCESS_DENIED:无管理员权限;
- 驱动侧:通过
- 缓冲区方式 :示例中用
METHOD_BUFFERED(最通用),驱动侧通过pIrp->AssociatedIrp.SystemBuffer访问数据; - 符号链接 :驱动创建的符号链接
\\DosDevices\\CustomDevice对应用户态的\\\\.\\CustomDevice,需保证名称一致。
七、运行预期输出(用户态控制台)
Open Device Success!
DevSetTimeout success! Read=6000ms, Write=4000ms, Ctrl=3000ms
DevGetStatus success! Online=1, ErrorCount=0, BufferSize=1024
DevWriteData success! Len=19, Data=Hello Custom Device!, ErrCode=0x0
DevReadData success! Len=19, Data=Hello Custom Device!, ErrCode=0x0
DevClose success!
Test App Exit!
该示例完整覆盖了"驱动初始化→用户态打开设备→下发参数→数据交互→关闭设备→驱动卸载"全流程,可直接基于此扩展更多功能(如设备错误处理、超时触发逻辑等)。