如果应用程序有多个线程同时对设备发起访问,就可以使用队列来处理这里IRP
WDF中使用队列也十分简单,提供了对应的函数.
#include <ntddk.h>
#include <wdf.h>
VOID EvtFileCreate(
_In_ WDFDEVICE Device,
_In_ WDFREQUEST Request,
_In_ WDFFILEOBJECT FileObject
)
{
KdPrint(("文件创建成功\n"));
WdfRequestComplete(Request,STATUS_SUCCESS);
}
VOID EvtFileClose(_In_ WDFFILEOBJECT FileObject)
{
KdPrint(("文件关闭成功\n"));
}
VOID EvtFileCleanup(_In_ WDFFILEOBJECT FileObject)
{
KdPrint(("文件清理成功\n"));
}
VOID EvtIoDeviceControl(
_In_
WDFQUEUE Queue,
_In_
WDFREQUEST Request,
_In_
size_t OutputBufferLength,
_In_
size_t InputBufferLength,
_In_
ULONG IoControlCode
)
{
WdfRequestComplete(Request,STATUS_SUCCESS);
KdPrint(("enter IoDeviceControl\n"));
}
VOID EvtDriverUnload(WDFDRIVER Driver)
{
KdPrint(("卸载成功\n"));
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING RegPath)
{
NTSTATUS status = STATUS_SUCCESS;
WDF_DRIVER_CONFIG Config;
WDFDEVICE Device = {0};
PWDFDEVICE_INIT pDeviceInit;
WDFDRIVER WdfDriver;
UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\HelloWdf");
UNICODE_STRING SymlicLinkName = RTL_CONSTANT_STRING(L"\\??\\HelloWdf");
WDF_FILEOBJECT_CONFIG FileConfig;
WDF_IO_QUEUE_CONFIG IoQueueConfig;
WDFQUEUE WdfQueue;
//对结构体清0 第二个参数为AddDevice
WDF_DRIVER_CONFIG_INIT(&Config,NULL);
//非Pnp驱动
Config.DriverInitFlags = WdfDriverInitNonPnpDriver;
//配置卸载函数
Config.EvtDriverUnload = EvtDriverUnload;
//为驱动创建WDF框架 最后一个参数为out_opt 指向新创建的WDF驱动框架指针
status = WdfDriverCreate(pDriverObject, RegPath, WDF_NO_OBJECT_ATTRIBUTES, &Config, &WdfDriver);
if (!NT_SUCCESS(status))
{
KdPrint(("WDF驱动框架创建失败\n"));
return status;
}
//返回值为框架分配的WDFDEVICE_INIT结构的指针
pDeviceInit = WdfControlDeviceInitAllocate(WdfDriver, &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX);
if (!pDeviceInit)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
//为设备分配名字 在NT驱动中是在创建设备时指定的 而在WDF驱动中,把设备名放在了WDFDEVICE_INIT结构体中
status = WdfDeviceInitAssignName(pDeviceInit, &DeviceName);
if (!NT_SUCCESS(status))
{
KdPrint(("分配设备名失败\n"));
return status;
}
//初始化WDF_FILEOBJECT_CONFIG结构,设置了几个回调函数 在什么时候触发?
WDF_FILEOBJECT_CONFIG_INIT(&FileConfig, EvtFileCreate, EvtFileClose, EvtFileCleanup);
//注册事件回调函数,并为驱动程序的框架文件对象设置配置信息。
WdfDeviceInitSetFileObjectConfig(pDeviceInit,&FileConfig,WDF_NO_OBJECT_ATTRIBUTES);
//创建设备对象 第三个参数就是返回的设备对象
status = WdfDeviceCreate(&pDeviceInit, WDF_NO_OBJECT_ATTRIBUTES,&Device);
if (!NT_SUCCESS(status))
{
KdPrint(("设备创建失败\n"));
return status;
}
/*I/O队列操作*/
//初始化I/O队列 WdfIoQueueDispatchSequential表示IO队列自动串行化
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&IoQueueConfig, WdfIoQueueDispatchSequential);
//设置处理IRP IRP_MJ_CONTROL的函数
IoQueueConfig.EvtIoDeviceControl = EvtIoDeviceControl; //也可以在这里配置ReadFile 和WriteFile函数的队列
//创建I/O队列
status = WdfIoQueueCreate(Device, &IoQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &WdfQueue);
if (!NT_SUCCESS(status))
{
KdPrint(("WDF驱动I/O队列创建失败\n"));
return status;
}
//为设备创建符号链接
status = WdfDeviceCreateSymbolicLink(Device,&SymlicLinkName);
if (!NT_SUCCESS(status))
{
KdPrint(("符号链接创建失败\n"));
//这里要删除设备吗?
return status;
}
//通知框架驱动程序已完成对指定的控制设备对象的初始化 在调用该函数之前,系统不会给驱动发送I/O请求
WdfControlFinishInitializing(Device);
KdPrint(("WDF驱动框架创建成功\n"));
return status;
}
应用层通过DeviceIoControl发起访问
// WdfApp.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <winioctl.h>
#define IO_TEST CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hDevice=CreateFile(TEXT("\\\\.\\HelloWdf"),
GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hDevice == INVALID_HANDLE_VALUE)
{
printf("打开设备失败\n");
getchar();
return -1;
}
DWORD dwRet = 0;
DeviceIoControl(hDevice, IO_TEST,NULL,0,0,0,&dwRet,NULL);
CloseHandle(hDevice);
}