使用 WDM 驱动程序的函数角色类型来声明函数
注意
从 Windows 10 版本 2004 开始,静态驱动程序验证程序 ( SDV) 不再需要注释来标识 WDM 驱动程序的调度例程的角色类型。 请按照本页的"基本" 和"高级初始化"部分中 的指导执行。
若要在分析 WDM 驱动程序时通知 SDV 驱动程序的入口点,必须使用函数角色类型声明声明函数。 函数角色类型在 Wdm.h 中定义。 WDM 驱动程序 中 DriverEntry 例程的每个入口点都必须通过指定相应的角色类型进行声明。 角色类型是预定义的 typedef,对应于 WDM 驱动程序中识别的入口点。
例如,若要为名为 CsampUnload 的驱动程序的 Unload 例程创建函数角色类型声明,请使用预定义的 typedef DRIVER_UNLOAD角色类型声明。 函数角色类型声明必须出现在函数定义之前。
DRIVER_UNLOAD CsampUnload;
CsampUnload 函数的定义保持不变:
VOID
CsampUnload(
IN PDRIVER_OBJECT DriverObject
)
{
...
}
SDV 可识别下表中所示的入口点类型。
WDM 函数角色类型 | WDM 例程 |
---|---|
DRIVER_INITIALIZE |
|
DRIVER_STARTIO |
|
DRIVER_UNLOAD |
|
DRIVER_ADD_DEVICE |
|
Dispatch_type (类型) DRIVER_DISPATCH | 调度例程 () 驱动程序使用。 请参阅 编写调度例程。 |
IO_COMPLETION_ROUTINE |
通过调用IoSetCompletionRoutine 或 IoSetCompletionRoutineEx,将函数指针作为第二个参数传递给 IoCompletion 例程,来设置 IoCompletion 例程。 |
DRIVER_CANCEL |
通过 调用IoSetCancelRoutine ,将函数指针传递给 IRP 的取消例程作为函数的第二个参数来设置 Cancel 例程。 |
IO_DPC_ROUTINE |
通过 调用IoInitializeDpcRequest ,将函数指针作为第二个参数传递给 DpcForIsr 例程来注册 DpcForIsr 例程。 若要将 DPC 排队,请使用相同的 DPC 对象从 ISR 例程调用 IoQueueDpc 。 |
KDEFERRED_ROUTINE |
通过调用 KeInitializeDpc,将函数指针作为第二个参数传递给 CustomDpc 来设置 CustomDpc 例程。 若要将 驱动程序的 CustomDpc 排队,请使用相同的 DPC 对象从 ISR 例程调用 KeInsertQueueDpc 。 |
KSERVICE_ROUTINE |
INTERRUPTService 例程 (ISR) 服务设备中断,并计划接收数据的中断后处理(如有必要)。 |
REQUEST_POWER_COMPLETE |
PowerCompletion 回调例程完成电源 IRP 的处理。 如果驱动程序需要在所有其他驱动程序完成 IRP 后执行其他任务,则驱动程序将在调用分配 IRP 的 PoRequestPowerIrp 例程期间注册 PowerCompletion 回调例程。 |
WORKER_THREAD_ROUTINE |
例程所返回的值 例程 是在 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、分片和 PVOID (请参阅 IoCompletion 例程,了解语法) 。
NTSTATUS
myCompletionRoutine(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
)
{
}
运行Code Analysis驱动程序以验证函数声明
为了帮助你确定是否已准备好源代码,请为驱动程序Code Analysis代码。 Code Analysis驱动程序检查函数角色类型声明,并有助于识别可能错过的函数声明,或在函数定义的参数与函数角色类型中的参数不匹配时发出警告。