the parameter list for KeInsertQueueDpc is shorter than for IoRequestDpc – it takes a pointer to the DPC object initialized with KeInitializeDpc and two additional arguments that are simply passed through to the DPC routine. The DPC function receives a pointer to the DPC object, the context parameter that was passed to KeInitializeDpc, and the two system variables from KeInsertQueueDpc.

The I/O Manager's IoInitializeDpcRequest is actually nothing more than a wrapper around KeInitializeDpc.

#define IoInitializeDpcRequest( DeviceObject, DpcRoutine ) (\

 KeInitializeDpc( &(DeviceObject)->Dpc, \

 (PKDEFERRED_ROUTINE) (DpcRoutine), \

 (DeviceObject) ) )

A device object has both a field for an IRP, which would be used for serially-oriented I/O devices, and a field for a DPC, which is the DPC object used in I/O Manager-DPC functions. Similarly, IoRequestDpc is a macro that calls KeInsertQueueDpc.

#define IoRequestDpc( DeviceObject, Irp, Context ) ( \

 KeInsertQueueDpc( &(DeviceObject)->Dpc, (Irp), (Context) ) )

It obtains the DPC object pointer for the call from the device object.

The DPC Object

typedef struct {SHORT

 SHORT Type;

 UCHAR Number;

 UCHAR Importance;

 LIST_ENTRY DpcListEntry;

 PKDEFERRED_ROUTINE DeferredRoutine;

 PVOID DeferredContext;

 PVOID SystemArgument1;

 PVOID SystemArgument2;

 PULONG Lock;



3 из 9