
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;
