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 请求模型,核心流程可概括为 “四步走”:
- 打开驱动设备:应用程序通过CreateFile函数,指定 WDF 驱动注册的 “设备接口 GUID” 或 “设备路径”,获取驱动设备的句柄(HANDLE)—— 这是后续交互的 “入口凭证”;
- 发起 I/O 请求:通过ReadFile(读取驱动数据)、WriteFile(向驱动写入数据)、DeviceIoControl(发送控制指令)等 API,将请求发送到 WDF 驱动的 I/O 队列;
- 驱动处理请求:WDF 驱动的 I/O 队列回调函数(如EvtIoRead/EvtIoDeviceControl)接收请求,执行硬件操作或数据处理后,通过WdfRequestCompleteWithInformation完成请求并返回结果;
- 应用接收结果:应用程序通过 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