Declaring Functions Using Function Role Types for WDM Drivers

Note

Starting in Windows 10 Version 2004, Static Driver Verifier (SDV) no longer requires annotations to identify role types of dispatch routines for WDM drivers. Please follow the guidance in the Basic and Advanced Initializations section of this page.

To inform SDV about the driver's entry points when you analyze a WDM driver, you must declare functions using function role type declarations. The function role types are defined in Wdm.h. Each entry point in the DriverEntry routine in your WDM driver must be declared by specifying the corresponding role type. The role types are predefined typedefs that correspond to the recognized entry points in a WDM driver.

For example, to create a function role type declaration for a driver's Unload routine called CsampUnload, use the predefined typedef DRIVER_UNLOAD role type declaration. The function role type declaration must appear before the function definition.

DRIVER_UNLOAD CsampUnload;

The definition of the CsampUnload function remains unchanged:

VOID
CsampUnload(
    IN PDRIVER_OBJECT DriverObject
    )
{
    ...
}

SDV recognizes the types of entry points shown in the following table.

WDM function role type WDM routine

DRIVER_INITIALIZE

DriverEntry

DRIVER_STARTIO

StartIO

DRIVER_UNLOAD

Unload

DRIVER_ADD_DEVICE

AddDevice

Dispatch_type( type ) DRIVER_DISPATCH

The dispatch routine(s) used by the driver. See Writing Dispatch Routines.

IO_COMPLETION_ROUTINE

IoCompletion

The IoCompletion routine is set by calling IoSetCompletionRoutine or IoSetCompletionRoutineEx and passing the function pointer to the IoCompletion routine as the second parameter.

DRIVER_CANCEL

Cancel

The Cancel routine is set by calling IoSetCancelRoutine and passing the function pointer to the cancellation routine for the IRP as the second parameter to the function.

IO_DPC_ROUTINE

DpcForIsr

The DpcForIsr routine is registered by calling IoInitializeDpcRequest and passing the function pointer to the DpcForIsr routine as the second parameter. To queue the DPC, call IoQueueDpc from the ISR routine by using the same DPC object.

KDEFERRED_ROUTINE

CustomDpc

The CustomDpc routine is set by calling KeInitializeDpc and passing the function pointer to the CustomDpc as the second parameter. To queue the CustomDpc for the driver, call KeInsertQueueDpc from the ISR routine by using the same DPC object.

KSERVICE_ROUTINE

InterruptService

The InterruptService routine (ISR) services a device interrupt and schedules post-interrupt processing of received data, if necessary.

REQUEST_POWER_COMPLETE

The PowerCompletion callback routine completes the processing of a power IRP. If the driver needs to perform additional tasks after all other drivers have completed the IRP, the driver registers a PowerCompletion callback routine during the call to the PoRequestPowerIrp routine that allocates the IRP.

WORKER_THREAD_ROUTINE

Routine

Routine is the callback routine that is specified in the second parameter to the ExInitializeWorkItem function.

The Routine should only be declared this way if the driver calls ExQueueWorkItem to add the work item to a system queue.

Declaring Driver Dispatch Routines

Starting in Windows 10 Version 2004, the function role type declarations for dispatch routines are refined with their IRP category automatically based on the initialization of the DriverObject->MajorFunction table in the DriverEntry routine of a WDM driver.

A driver Foo must accomplish role declarations by using either the basic or advanced style of declaration in order to be compliant with SDV.

Basic and Advanced Initializations

The basic style can be seen in the example below (note the dispatch routine names FooCreate and FooCleanup are just examples, any appropriate name can be used):

DriverObject->MajorFunction[IRP_MJ_CREATE] = FooCreate; //Basic style
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = FooCleanup;

A more advanced approach can be taken to shorten the list required. While the same dispatch routine is used for more than one IRP category, a driver may encode two initializations this way:

DriverObject->MajorFunction[IRP_MJ_CREATE] = 
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = FooCreateCleanup; // Advanced style for a multi-role dispatch routine 

In order for a driver to be able to run SDV properly, the driver must only use either the basic or advanced style shown above. SDV verification on the driver will not work as expected if one of these two methods is not used.

Function Parameters and Function Role Types

As required in the C programming language, the parameter types that you use in the function definition must match the parameter types of the function prototype, or in this case, the function role type. SDV depends upon the function signatures for analysis and ignores functions whose signatures do not match.

For example, you should declare an IoCompletion routine using the IO_COMPLETION_ROUTINE function role type:

IO_COMPLETION_ROUTINE myCompletionRoutine;

When you implement myCompletionRoutine, the parameter types must match those used by IO_COMPLETION_ROUTINE, namely, PDEVICE_OBJECT, PIRP, and PVOID (see IoCompletion routine for syntax).

NTSTATUS
myCompletionRoutine(
 PDEVICE_OBJECT  DeviceObject,
 PIRP  Irp,
 PVOID  Context
 )
{
}

Running Code Analysis for Drivers to verify the function declarations

To help you determine whether the source code is prepared, run Code Analysis for Drivers. Code Analysis for Drivers checks for function role type declarations and can help identify function declarations that might have been missed or warn you when the parameters of the function definition do not match those in the function role type.