windows用户态到内核态

以下是一个驱动层 + 用户态的交互示例,覆盖"超时设置+设备状态查询+数据读写"全流程,包含驱动代码、用户态头文件、用户态调用代码。

一、整体架构说明

层级 核心文件/功能
驱动层 实现 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.hioapist.cTestApp.c加入项目;
  • 编译选项:启用Unicode,平台选择与驱动一致(x64/x86);
  • 输出:生成TestApp.exe可执行文件。
3. 运行步骤
  1. 安装驱动:通过sc create CustomDev type= kernel binPath= "C:\CustomDev.sys"创建服务,sc start CustomDev启动驱动;
  2. 以管理员权限运行TestApp.exe
  3. 查看输出:控制台会打印各步骤结果,驱动侧可通过DebugView查看DbgPrint日志;
  4. 卸载驱动:sc stop CustomDev + sc delete CustomDev

六、关键细节与注意事项

  1. 权限要求 :用户态程序需管理员权限(否则CreateFile打开设备失败);
  2. 结构体对齐:驱动和用户态的结构体必须保证内存对齐(避免数据解析错误);
  3. 错误处理
    • 驱动侧:通过DbgPrint打印调试信息,用NT_SUCCESS判断状态;
    • 用户态:通过GetLastError获取错误码,常见错误:
      • ERROR_INVALID_HANDLE:设备句柄无效;
      • ERROR_NOT_SUPPORTED:驱动不支持该IOCTL;
      • ERROR_ACCESS_DENIED:无管理员权限;
  4. 缓冲区方式 :示例中用METHOD_BUFFERED(最通用),驱动侧通过pIrp->AssociatedIrp.SystemBuffer访问数据;
  5. 符号链接 :驱动创建的符号链接\\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!

该示例完整覆盖了"驱动初始化→用户态打开设备→下发参数→数据交互→关闭设备→驱动卸载"全流程,可直接基于此扩展更多功能(如设备错误处理、超时触发逻辑等)。

相关推荐
硬汉嵌入式2 小时前
将STM32H7的SPI MISO和MOSI短接回环测试配置问题也是非常方便的
stm32·miso·h7-tool·spi回环·mosi
Hy行者勇哥2 小时前
从零搭建小智 AI 音箱 MCP 开发环境:自定义智能家居控制技能实战指南
人工智能·嵌入式硬件·硬件工程·智能家居
richxu202510014 小时前
嵌入式学习之路>单片机核心原理篇>(11) 存储器(Flash & SRam)
单片机·嵌入式硬件·学习
@good_good_study4 小时前
STM32 TIM编码器模式配置函数及实验
stm32·单片机
云山工作室6 小时前
基于单片机的客车载客状况自动检测系统设计(论文+源码)
stm32·单片机·嵌入式硬件·毕业设计
Rorsion6 小时前
第二章(2.5):微控制器8051的硬件结构---时钟、复位和MCU工作方式
单片机·嵌入式硬件·备考ing
Qingniu016 小时前
SP40P65NJ:一款高性能40V P沟道MOSFET深度解析
单片机·嵌入式硬件·电机驱动·dc-dc降压/升压转换器·电源管理模块
brave and determined7 小时前
传感器学习(day10):MEMS传感器:揭秘智能时代的核心技术
嵌入式硬件·汽车电子·传感器·mems·消费电子·嵌入式设计·传感器应用
信奥洪老师8 小时前
2025年12 电子学会 机器人三级等级考试真题
单片机·嵌入式硬件·机器人