使用 WDM 驱动程序的函数角色类型来声明函数
注意
从 Windows 10 2004 版本开始,静态驱动程序验证程序 (SDV) 不再需要注释来识别 WDM 驱动程序的调度例程角色类型。 请遵循本页基本和高级初始化部分的指导。
在分析 WDM 驱动程序时,为了向 SDV 提供驱动程序入口点的信息,必须使用函数角色类型声明来声明函数。 函数角色类型在 Wdm.h 中定义。 WDM 驱动程序中 DriverEntry 例程的每个入口点都必须通过指定相应的角色类型来声明。 角色类型是预定义的类型定义,与 WDM 驱动程序中的公认入口点相对应。
例如,要为驱动程序的 Unload 例程创建名为 CsampUnload的函数角色类型声明,请使用预定义的 typedef DRIVER_UNLOAD 角色类型声明。 函数角色类型声明必须出现在函数定义之前。
DRIVER_UNLOAD CsampUnload;
CsampUnload 函数的定义保持不变:
VOID
CsampUnload(
IN PDRIVER_OBJECT DriverObject
)
{
...
}
SDV 可识别下表所示的入口点类型。
波分复用功能作用类型 | 波分复用例程 |
---|---|
驱动程序初始化 |
|
DRIVER_STARTIO |
|
DRIVER_UNLOAD |
|
驱动程序添加设备 |
|
Dispatch_type(类型) DRIVER_DISPATCH | 驱动程序使用的调度例程。 请参见编写调度例程。 |
io_completion_routine |
该 IoCompletion 例程是通过调用 IoSetCompletionRoutine 或 IoSetCompletionRoutineEx 并将指向 IoCompletion 例程的函数指针作为第二个参数来设置的。 |
DRIVER_CANCEL |
该取消例程是通过调用 IoSetCancelRoutine 并将 IRP 取消例程的函数指针作为第二个参数传递给函数来设置的。 |
IO_DPC_ROUTINE |
该 DpcForIsr 例程是通过调用 IoInitializeDpcRequest 并将 DpcForIsr 例程的函数指针作为第二个参数来注册的。 要对 DPC 进行排队,请使用相同的 DPC 对象,在 ISR 例程中调用 IoQueueDpc 。 |
kdeferred_routine |
该 CustomDpc 例程是通过调用 KeInitializeDpc 并将指向 CustomDpc 的函数指针作为第二个参数来设置的。 要为驱动程序排队 CustomDpc,请使用相同的 DPC 对象在 ISR 例程中调用 KeInsertQueueDpc。 |
kservice_routine |
中断服务例程 (ISR) 为设备中断提供服务,并在必要时安排对接收到的数据进行中断后处理。 |
功率请求完成 |
该 PowerCompletion 回调例程完成对功率 IRP 的处理。 如果驱动程序需要在所有其他驱动程序完成 IRP 后执行其他任务,则会在调用分配 IRP 的 PoRequestPowerIrp 例程时注册 PowerCompletion 回调例程。 |
工作线程程序 |
例程 例程是 ExInitializeWorkItem 函数第二个参数中指定的回调例程。 例程只有在驱动程序调用 ExQueueWorkItem 将工件添加到系统队列时才应这样声明。 |
声明驱动程序调度例程
从 Windows 10 2004 版开始,调度例程的函数角色类型声明将根据 WDM 驱动程序的 DriverEntry 例程中 DriverObject->MajorFunction 表的初始化情况,自动与 IRP 类别一起完善。
Foo 驱动程序必须使用基本或高级声明方式完成角色声明,才能符合 SDV 标准。
基本和高级初始化
基本样式可以从下面的示例中看出(注意,调度例程名称 FooCreate 和 FooCleanup 只是示例,可以使用任何合适的名称):
DriverObject->MajorFunction[IRP_MJ_CREATE] = FooCreate; //Basic style
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = FooCleanup;
可以采用更先进的方法来缩短所需的清单。 虽然同一调度例程可用于多个 IRP 类别,但一个驱动程序可以用这种方式对两个初始化进行编码:
DriverObject->MajorFunction[IRP_MJ_CREATE] =
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = FooCreateCleanup; // Advanced style for a multi-role dispatch routine
为了使驱动程序能够正常运行 SDV, 驱动程序必须只使用基本或高级样式,如上图所示。 如果不使用这两种方法,驱动程序上的 SDV 验证将无法按预期运行。
函数参数和函数作用类型
按照 C 编程语言的要求,在函数定义中使用的参数类型必须与函数原型的参数类型相匹配,或者在本例中与函数角色类型相匹配。 SDV 依靠函数签名进行分析,并忽略签名不匹配的函数。
例如,应使用 IO_COMPLETION_ROUTINE 函数角色类型声明 IoCompletion 例程:
IO_COMPLETION_ROUTINE myCompletionRoutine;
当您实现 myCompletionRoutine时,参数类型必须与 IO_COMPLETION_ROUTINE 使用的类型一致,即 PDEVICE_OBJECT、PIRP 和 PVOID(语法参见 IoCompletion 例程)。
NTSTATUS
myCompletionRoutine(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
)
{
}
运行驱动程序代码分析以验证函数声明
为帮助确定源代码是否准备就绪,请运行 驱动程序代码分析。 驱动程序的代码分析可检查函数角色类型声明,帮助识别可能遗漏的函数声明,或在函数定义的参数与函数角色类型中的参数不匹配时发出警告。