3. KMDF驱动程序入口:DriverEntry函数详解、WDF_DRIVER_CONFIG初始化、EvtDriverDeviceAdd回调注册

在KMDF框架中,DriverEntry是所有驱动程序的入口点,类似于应用程序的main函数。当操作系统加载驱动时,首先调用此函数。本章将深入解析DriverEntry的结构、WDF_DRIVER_CONFIG的初始化流程,以及如何正确注册EvtDriverDeviceAdd回调函数。

3.1 DriverEntry函数签名与职责

DriverEntry函数由WDK(Windows Driver Kit)定义,其标准原型如下:

NTSTATUS
DriverEntry(
    _In_ PDRIVER_OBJECT  DriverObject,
    _In_ PUNICODE_STRING RegistryPath
);
参数 类型 说明
DriverObject PDRIVER_OBJECT 指向驱动对象的指针,由I/O管理器创建。驱动需在此对象上注册分发例程。
RegistryPath PUNICODE_STRING 指向注册表中驱动服务项的路径,通常用于读取配置信息。

DriverEntry的核心职责包括:

  • 初始化WDF_DRIVER_CONFIG结构体。
  • 调用WdfDriverCreate创建WDF驱动对象。
  • 注册EvtDriverDeviceAdd回调(必须)。
  • 可选:注册其他事件回调(如EvtDriverUnload)。
关键提示: 在KMDF中,DriverEntry通常不直接处理硬件或创建设备。这些工作被推迟到EvtDriverDeviceAdd回调中执行,以确保PnP管理器在合适的时机调用。

3.2 WDF_DRIVER_CONFIG初始化

WDF_DRIVER_CONFIG是KMDF驱动配置的核心结构体,它告诉框架驱动的基本属性。初始化此结构体有两种方式:

3.2.1 使用初始化宏

推荐使用WDF_DRIVER_CONFIG_INIT宏进行初始化,它会自动设置结构体大小和默认值:

WDF_DRIVER_CONFIG config;
WDF_DRIVER_CONFIG_INIT(
    &config,
    MyEvtDeviceAdd   // 指定EvtDriverDeviceAdd回调
);

3.2.2 手动初始化

如果需要自定义更多字段,可以手动赋值:

WDF_DRIVER_CONFIG config;
RtlZeroMemory(&config, sizeof(WDF_DRIVER_CONFIG));
config.Size = sizeof(WDF_DRIVER_CONFIG);
config.EvtDriverDeviceAdd = MyEvtDeviceAdd;
config.DriverInitFlags = WDF_DRIVER_INIT_FLAGS::WdfDriverInitNonPnpDriver; // 非PnP驱动标志
config.EvtDriverUnload = MyEvtDriverUnload;
字段 默认值 说明
Size sizeof(WDF_DRIVER_CONFIG) 结构体大小,用于版本兼容。
EvtDriverDeviceAdd NULL 必须设置,否则驱动加载失败。
EvtDriverUnload NULL 可选,驱动卸载时的清理回调。
DriverInitFlags WdfDriverInitPnpDriver 默认为PnP驱动,可改为非PnP。
DriverPoolTag 'DfWx' 用于内存池标记,便于调试。

3.3 EvtDriverDeviceAdd回调注册

EvtDriverDeviceAdd是KMDF驱动中最重要的回调之一。当PnP管理器检测到驱动支持的设备时,会调用此回调。驱动在此回调中创建设备对象、初始化硬件、设置I/O队列等。

3.3.1 回调函数原型

NTSTATUS
MyEvtDeviceAdd(
    _In_    WDFDRIVER       Driver,
    _Inout_ PWDFDEVICE_INIT DeviceInit
);
参数 说明
Driver 由WdfDriverCreate返回的WDF驱动对象句柄。
DeviceInit 指向WDFDEVICE_INIT结构的指针,用于配置设备属性(如设备名称、同步模式、文件对象等)。

3.3.2 注册流程

在DriverEntry中,通过WdfDriverCreate函数将配置与驱动对象关联:

NTSTATUS status;
WDFDRIVER driver;
WDF_DRIVER_CONFIG config;

WDF_DRIVER_CONFIG_INIT(&config, MyEvtDeviceAdd);

status = WdfDriverCreate(
    DriverObject,           // 传入的驱动对象
    RegistryPath,           // 注册表路径
    WDF_NO_OBJECT_ATTRIBUTES, // 可选属性
    &config,                // 驱动配置
    &driver                 // 返回的WDF驱动句柄
);

if (!NT_SUCCESS(status)) {
    // 错误处理
    return status;
}
常见错误: 如果WdfDriverCreate失败,驱动将无法加载。常见原因包括:EvtDriverDeviceAdd为NULL、配置结构体大小不匹配、或驱动对象已被其他框架占用。

3.4 完整DriverEntry示例

以下是一个典型的KMDF驱动入口实现:

NTSTATUS
DriverEntry(
    _In_ PDRIVER_OBJECT  DriverObject,
    _In_ PUNICODE_STRING RegistryPath
)
{
    WDF_DRIVER_CONFIG config;
    WDFDRIVER driver;
    NTSTATUS status;

    // 1. 初始化配置结构体,注册EvtDriverDeviceAdd
    WDF_DRIVER_CONFIG_INIT(&config, MyEvtDeviceAdd);

    // 2. 可选:设置驱动卸载回调
    config.EvtDriverUnload = MyEvtDriverUnload;

    // 3. 创建WDF驱动对象
    status = WdfDriverCreate(
        DriverObject,
        RegistryPath,
        WDF_NO_OBJECT_ATTRIBUTES,
        &config,
        &driver
    );

    if (!NT_SUCCESS(status)) {
        KdPrint(("WdfDriverCreate failed with status 0x%x\n", status));
        return status;
    }

    KdPrint(("KMDF Driver loaded successfully.\n"));
    return STATUS_SUCCESS;
}

3.5 DriverEntry与WDF驱动对象关系图

下图展示了DriverEntry、WDF_DRIVER_CONFIG与WDF驱动对象之间的创建关系:

DriverEntry与WDF驱动对象创建关系 DriverEntry → WDF驱动对象创建流程 DriverEntry 入口函数 WDF_DRIVER_CONFIG 配置结构体 WdfDriverCreate 创建驱动对象 初始化 传入 WDFDRIVER 驱动对象句柄 输出 EvtDriverDeviceAdd 设备添加回调 注册 说明: 1. DriverEntry首先初始化WDF_DRIVER_CONFIG,必须设置EvtDriverDeviceAdd回调。 2. 调用WdfDriverCreate将配置与驱动对象绑定,创建WDF驱动对象。 3. 当PnP管理器检测到设备时,框架自动调用EvtDriverDeviceAdd回调。

3.6 常见问题与最佳实践

最佳实践清单:
  • 始终使用WDF_DRIVER_CONFIG_INIT宏初始化配置,避免手动设置Size字段遗漏。
  • 在EvtDriverDeviceAdd中完成所有设备初始化工作,不要在DriverEntry中操作硬件。
  • 如果驱动支持多个设备,确保EvtDriverDeviceAdd是重入的(reentrant),因为PnP可能并发调用。
  • 使用KdPrint或TraceEvents在DriverEntry中添加日志,便于调试加载失败问题。
避坑指南:
  • 不要将EvtDriverDeviceAdd设置为NULL,否则WdfDriverCreate返回STATUS_INVALID_PARAMETER。
  • 不要在DriverEntry中调用WdfDeviceCreate,设备创建必须在EvtDriverDeviceAdd中完成。
  • 如果驱动是非PnP的,需设置DriverInitFlags为WdfDriverInitNonPnpDriver,并自行管理设备生命周期。

3.7 本章小结