使用 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

DriverEntry

DRIVER_STARTIO

StartIO

DRIVER_UNLOAD

卸载

DRIVER_ADD_DEVICE

AddDevice

Dispatch_type (类型) DRIVER_DISPATCH

调度例程 () 驱动程序使用。 请参阅 编写调度例程

IO_COMPLETION_ROUTINE

IoCompletion

通过调用IoSetCompletionRoutineIoSetCompletionRoutineEx,将函数指针作为第二个参数传递给 IoCompletion 例程,来设置 IoCompletion 例程。

DRIVER_CANCEL

取消

通过 调用IoSetCancelRoutine ,将函数指针传递给 IRP 的取消例程作为函数的第二个参数来设置 Cancel 例程。

IO_DPC_ROUTINE

DpcForIsr

通过 调用IoInitializeDpcRequest ,将函数指针作为第二个参数传递给 DpcForIsr 例程来注册 DpcForIsr 例程。 若要将 DPC 排队,请使用相同的 DPC 对象从 ISR 例程调用 IoQueueDpc

KDEFERRED_ROUTINE

CustomDpc

通过调用 KeInitializeDpc,将函数指针作为第二个参数传递给 CustomDpc 来设置 CustomDpc 例程。 若要将 驱动程序的 CustomDpc 排队,请使用相同的 DPC 对象从 ISR 例程调用 KeInsertQueueDpc

KSERVICE_ROUTINE

InterruptService

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驱动程序检查函数角色类型声明,并有助于识别可能错过的函数声明,或在函数定义的参数与函数角色类型中的参数不匹配时发出警告。