WDF里面,大多数对象都支持自定义的数据,比如给设备对象创建一个context。
对象上下文
先自定义一个结构,比如
typedef struct
{
WDFQUEUE _DefaultQueue;
}DEVICE_CONTEXT;
里面放了一个对象WDFQUEUE. 然后给设备对象创建一个上下文内存块。在使用之前先要声明一下这个结构,相当于告诉框架,我们需要使用一个context。
WDF_DECLARE_CONTEXT_TYPE(DEVICE_CONTEXT);
如果不需要context,那么可以这么初始化一个设备属性,WDF_OBJECT_ATTRIBUTES_INIT(&object_attribs);
如果需要context,那么要换个函数,WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&object_attribs, DEVICE_CONTEXT); 这样就会分配一个DEVICE_CONTEXT的内存块,并且将内存块的指针保存到WDF_OBJECT_ATTRIBUTES里面。看一下WDF_OBJECT_ATTRIBUTES的定义:
typedef struct _WDF_OBJECT_ATTRIBUTES {
ULONG Size;
PFN_WDF_OBJECT_CONTEXT_CLEANUP EvtCleanupCallback;
PFN_WDF_OBJECT_CONTEXT_DESTROY EvtDestroyCallback;
WDF_EXECUTION_LEVEL ExecutionLevel;
WDF_SYNCHRONIZATION_SCOPE SynchronizationScope;
WDFOBJECT ParentObject;
size_t ContextSizeOverride;
PCWDF_OBJECT_CONTEXT_TYPE_INFO ContextTypeInfo;
} WDF_OBJECT_ATTRIBUTES, *PWDF_OBJECT_ATTRIBUTES;
最后一个成员ContextTypeInfo就指向分配出来的context内存块。
可以根据对象来得到这个context:
dev_ctx = WdfObjectGetTypedContext(control_device, DEVICE_CONTEXT);
RtlZeroMemory(dev_ctx, sizeof(DEVICE_CONTEXT));
上面2行代码的意思就是获取设备对象control_device的上下文内存块,并且清零。
IO QUEUE,存放WDFREQUEST的队列
WDF提供了一个对象WDFREQUEST, WDFREQUEST其实是对WDM里面IRP的一个封装。WDF还提供了另外一个对象也就是WDFQUEUE,这个队列会存放IRP请求。
我们可以给设备对象control_device创建一个IOQUEUE,比如:(WDFQUEUE存放在了设备对象的上下文里面)
默认队列不能使用WdfIoQueueDispatchManual,不然创建queue会失败。这个我试过。
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&qcfg, WdfIoQueueDispatchParallel);
qcfg.PowerManaged = WdfFalse; //非pnp驱动,也就无需电源管理了.
qcfg.EvtIoDefault = EvtIoPDPControlDevice;
//创建一个queue
status = WdfIoQueueCreate(control_device,&qcfg,WDF_NO_OBJECT_ATTRIBUTES,&dev_ctx->_DefaultQueue);
if( !NT_SUCCESS(status) )
{
KdPrint(("Create IoQueue failed, %x\n", status));
goto DriverEntry_Complete;
}
注意, 需要在WdfControlFinishInitializing(contr