这篇博客详细介绍了UMDF驱动的基本概念、生命周期、代码实现和应用交互,适合初学者入门
驱动的生命周期从加载到运行驱动像“服务”一样工作。安装后它不直接运行而是等系统调用。• 入口点在哪里• 全局入口DriverEntry 函数在Driver.c。这是驱动的“起点”系统加载DLL时第一个调用它。• 它初始化WDF框架、注册回调如设备添加事件、设置跟踪日志。• 如果失败驱动不加载。• 设备入口UMDFTestEvtDeviceAdd也在Driver.cPnP即插即用系统添加设备时调用。它调用UMDFTestCreateDevice在Device.c创建设备对象。• 安装后驱动作为UMDF服务运行在WUDFHost.exe进程中用户模式主机。系统启动它时调用DriverEntry然后创建设备。• 安装过程手动做的• 用pnputil /add-driver UMDFExample.inf /install安装INF文件。 //安装后出现在system devices下面名字叫做UMDFExampledevices• 系统注册设备硬件ID Root\UMDFExample加载DLL到WUDFHost。• 设备出现在设备管理器“UMDFExample Device”状态“正常”。 //没找到其他程序怎么用这个驱动入口点在哪里驱动不是“程序”它是系统服务。其他程序应用通过设备接口与之交互像打开文件一样。• 入口点main应用侧• 设备接口GUIDGUID_DEVINTERFACE_UMDFExample在Public.h定义值是{8d385c4d-4fa8-413c-9307-a8fa3e768390}。这是“门牌号”应用用它找到设备。• 打开设备用CreateFile APIWindows函数路径是\.\GUID字符串如\.{8d385c4d-4fa8-413c-9307-a8fa3e768390}。成功返回句柄handle像文件句柄。• 发送消息: 使用DeviceIoControl APIwindows函数成功的话会返回DeviceIoControl succeeded 返回的实际内容如下bytesReturnedBOOL result DeviceIoControl(hDevice, // 1. 设备句柄IOCTL_UMDFTEST_HELLO, // 2. 控制码(LPVOID)inputBuffer, // 3. 输入缓冲区指针inputSize, // 4. 输入缓冲区大小outputBuffer, // 5. 输出缓冲区指针outputSize, // 6. 输出缓冲区大小bytesReturned, // 7. 接收实际返回字节数的变量指针nullptr); // 8. 用于异步操作此处为同步3.驱动层先不细讲在驱动里面UMDFTestEvtIoDeviceControl是一个回调函数用于处理来自用户模式应用程序的 设备控制请求IOCTL。当你的应用调用 DeviceIoControl 时UMDF 框架会自动调用这个函数来处理请求。再博客的最后会写个例子讲解这个函数详细的代码内容VOID UMDFTestEvtIoDeviceControl( _In_ WDFQUEUE Queue, // 队列句柄框架管理的 I/O 队列 _In_ WDFREQUEST Request, // 请求句柄包含输入/输出缓冲区和请求详情 _In_ size_t OutputBufferLength, // 输出缓冲区大小字节 _In_ size_t InputBufferLength, // 输入缓冲区大小字节 _In_ ULONG IoControlCode // IOCTL 控制码唯一标识请求类型如 IOCTL_UMDFTEST_HELLO )• 返回类型VOID无返回值因为处理结果通过 Request 对象传递。• 参数• Queue指向队列对象的句柄你不需要直接操作它。• Request核心对象封装了请求的所有数据输入缓冲区、输出缓冲区等。这是你处理数据的入口。• OutputBufferLength / InputBufferLength缓冲区大小用于安全检查防止缓冲区溢出。• IoControlCode一个数字标识具体的 IOCTL 类型例如你的代码中定义的 IOCTL_UMDFTEST_HELLO。• In 注解SAL (Source Annotation Language) 注解表示这些参数是输入的只读。检查是否还有 pnputil /enum-drivers | findstr /i UMDFTest我们讲解一下exe要加载驱动的时候传入的参数和驱动的inf的对应关系SW_DEVICE_CREATE_INFO createInfo { 0 }; createInfo.cbSize sizeof(SW_DEVICE_CREATE_INFO); createInfo.pszInstanceId Lumdftest; // 实例ID createInfo.pszzHardwareIds LRoot\\UMDFTest\0\0; // 硬件ID与INF文件匹配 createInfo.pszzCompatibleIds nullptr; // 兼容ID无需设置 createInfo.pContainerId nullptr; // 容器ID createInfo.CapabilityFlags SWDeviceCapabilitiesDriverRequired; // 能力标志需要驱动程序 createInfo.pszDeviceDescription LUMDF Test Device; // 设备描述 createInfo.pszDeviceLocation nullptr; // 设备位置 createInfo.pSecurityDescriptor nullptr; // 安全描述符 HRESULT hr SwDeviceCreate(Lumdftest, LHTREE\\ROOT\\0, createInfo, 0, nullptr, SwDeviceCreatedCallback, nullptr, g_SwDevice);• createInfo.pszInstanceId实例ID如Lumdfexample这不是直接对应INF中的某个字段而是软件设备的唯一标识符用于区分多个实例。它与INF中的硬件IDRoot\UMDFExample配合使用但INF本身不定义实例ID。你可以自定义只要在代码中保持一致即可。• SwDeviceCreate的第一个参数pszEnumeratorName如Lumdfexample这是枚举器名称通常设置为与pszInstanceId相同的值用于标识创建设备的枚举器。它也不直接对应INF中的特定字段而是系统内部使用的标识符。每次编译并修改代码后重复安装INF时系统会将每个INF作为独立的驱动包添加导致多个oemXX.inf文件例如oem40.inf和oem54.inf。即使硬件ID相同pnputil也会创建新包而不是覆盖旧的。这是因为驱动包是基于INF内容的哈希值管理的如果内容不同即使硬件ID相同会被视为新包。对于软件设备如SWD\umdfexample\umdfexample可能会出现多个设备实例或冲突。正常更新驱动的处理步骤停止相关应用程序和服务确保没有进程使用驱动。删除旧驱动包• 运行 pnputil /enum-drivers 查看所有驱动包。• 删除旧的pnputil /delete-driver oem40.inf替换为实际名称。卸载设备实例如果存在• 使用设备管理器找到设备例如“UMDF Test Device”右键卸载。• 或使用命令pnputil /remove-device SWD\umdfexample\umdfexample替换为实际设备ID。安装新驱动• 复制新编译的INF和DLL到目录。• 运行 pnputil /add-driver UMDFExample.inf /install。重启系统如果需要有时软件设备需要重启才能生效。测试运行应用程序验证新代码。如果只想强制更新而不删除可以尝试 pnputil /add-driver UMDFExample.inf /install /force但这可能不总是可靠。建议始终删除旧包以避免冲突。驱动层代码详细分析1.INF安装阶段驱动注册我们从编译完成之后的安装开始• 首先命令执行pnputil /add-driver UMDFExample.inf /install 将INF文件添加到系统驱动存储中生成一个oemXX.inf文件例如oem54.inf。• 驱动代码经历此时驱动代码UMDFExample.dll尚未加载。INF只是注册了驱动包包括硬件IDRoot\UMDFExample、服务名UMDFExample和DLL路径。系统知道“如果有匹配的硬件ID就加载这个驱动”。• 结果驱动包已安装但没有设备实例。驱动代码静止。2.设备枚举与发现阶段PnP触发• 触发条件当应用程序运行 SwDeviceCreate在UMDFConsole.cpp中时系统创建软件设备实例SWD\umdfexample\umdfexample硬件ID为Root\UMDFExample。• PnP管理器动作PnP检测到新设备匹配INF中的硬件ID决定加载对应的驱动。• 驱动代码经历WUDFHost进程启动如果未运行。系统启动WUDFHost.exe用户模式主机进程并加载UMDFExample.dll到该进程中。• DriverEntry调用这是驱动的入口点在Driver.c中。DriverEntry 初始化WDF框架注册设备创建回调UMDFExampleCreateDevice。