Windows驱动程序开发:WDF应用程序编写

90 阅读3分钟

2b98908500f7a960250ee4891473c62d9777.jpeg

Windows驱动程序开发:WDF应用程序编写---itazs.fun/16957/

一、WDF 应用程序的核心定位与交互逻辑

1. 核心定位:驱动与用户层的 “通信桥梁”

WDF 应用程序并非传统意义上的 “桌面软件”,而是专注于与 WDF 驱动进行交互的 “专用客户端”,其核心作用包括:

  • 发起 I/O 请求:通过 Windows API(如CreateFile打开驱动设备、ReadFile/WriteFile发起读写请求)与 WDF 驱动的 I/O 队列交互;
  • 参数传递与数据交换:向驱动传递配置参数(如硬件控制指令),接收驱动返回的处理结果(如传感器采集数据、设备状态信息);
  • 驱动状态监控:通过DeviceIoControl发送控制码,查询驱动或硬件的实时状态(如设备温度、运行模式),实现对驱动的动态管控。

2. 与 WDF 驱动的交互逻辑:基于 I/O 请求模型

WDF 应用程序与驱动的交互遵循 Windows I/O 请求模型,核心流程可概括为 “四步走”:

  1. 打开驱动设备:应用程序通过CreateFile函数,指定 WDF 驱动注册的 “设备接口 GUID” 或 “设备路径”,获取驱动设备的句柄(HANDLE)—— 这是后续交互的 “入口凭证”;
  1. 发起 I/O 请求:通过ReadFile(读取驱动数据)、WriteFile(向驱动写入数据)、DeviceIoControl(发送控制指令)等 API,将请求发送到 WDF 驱动的 I/O 队列;
  1. 驱动处理请求:WDF 驱动的 I/O 队列回调函数(如EvtIoRead/EvtIoDeviceControl)接收请求,执行硬件操作或数据处理后,通过WdfRequestCompleteWithInformation完成请求并返回结果;
  1. 应用接收结果:应用程序通过 API 的返回值(如ReadFile的lpNumberOfBytesRead)或输出缓冲区,获取驱动处理结果,完成一次交互闭环。

关键区别:WDF 应用程序与普通桌面应用的核心差异在于 “交互对象不同”—— 普通应用调用系统 API 或第三方库,而 WDF 应用直接与底层驱动通信,需严格遵循驱动定义的 “请求格式” 与 “数据协议”。

二、WDF 应用程序编写的核心技术

1. 前置准备:驱动设备的 “识别与访问”

编写 WDF 应用程序前,需先明确驱动的 “访问标识”,确保应用能精准定位并打开目标驱动,核心技术点包括:

(1)获取驱动的设备路径或接口 GUID

WDF 驱动通常通过两种方式向用户层暴露访问入口:

  • 设备路径:驱动安装时通过.inf文件注册固定路径(如\.\HelloWdfDevice),应用程序可直接通过该路径打开设备;
  • 设备接口 GUID:驱动通过WdfDeviceCreateDeviceInterface注册唯一 GUID(如{12345678-1234-5678-1234-567890ABCDEF}),应用程序通过SetupDiGetClassDevs等 API 枚举设备,动态获取设备路径。

实战代码:通过设备接口 GUID 枚举驱动设备

#include <windows.h>
#include <setupapi.h>
#include <initguid.h>
#include <devguid.h>
// 定义WDF驱动注册的设备接口GUID(需与驱动代码一致)
DEFINE_GUID(GUID_DEVINTERFACE_HELLO_WDF, 
    0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF);
// 枚举设备并获取设备路径
BOOL GetWdfDevicePath(LPTSTR lpDevicePath, DWORD dwPathSize) {
    HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
    SP_DEVICE_INTERFACE_DATA deviceInterfaceData = {0};
    PSP_DEVICE_INTERFACE_DETAIL_DATA pDeviceDetailData = NULL;
    DWORD dwRequiredSize = 0;
    BOOL bResult = FALSE;
    // 1. 初始化设备信息集
    hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_HELLO_WDF, 
        NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    if (hDevInfo == INVALID_HANDLE_VALUE) {
        printf("SetupDiGetClassDevs failed, Error: %d\n", GetLastError());
        goto Cleanup;
    }
    // 2. 枚举设备接口
    deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
    if (!SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVINTERFACE_HELLO_WDF, 0, &deviceInterfaceData)) {
        printf("SetupDiEnumDeviceInterfaces failed, Error: %d\n", GetLastError());
        g