亲手解剖WDF驱动

article/2025/10/10 18:47:34

亲手解剖WDF驱动

创建一个WDF驱动(non-pnp)

WDF驱动其实是微软公司提供的一套驱动开发的框架。

有了这个框架之后,开发驱动会简单一些。WDF本身是从WDM基础上封装而成的。WDF里面封装了很多对象,如WDFDRIVER等。如果要学习使用WDF来开发驱动,个人感觉还是需要WDM的一些基础,不然很多东西挺难理解的。

写了一个简单的WDF驱动(非pnp),基本步骤如下:

创建framework 驱动对象

总结:

1.创建WDF驱动对象:WDFDRIVER

2.创建WDF设备对象:WDFDEVICE

原始驱动对象:Nt/wdm: DRIVER_OBJECT

WDF驱动对象:WDFDRIVER

几乎任何一个WDF驱动一开始就要创建一个framework的驱动对象,这个对象是所有其他对象的parent对象。 

        //初始化WDF_DRIVER_CONFIG

WDF_DRIVER_CONFIG_INIT(

   &cfg,

   NULL //不提供adddevice函数//不支持pnp );

cfg.DriverInitFlags = WdfDriverInitNonPnpDriver;  //非pnp驱动

cfg.DriverPoolTag   = (ULONG)'PEPU';  

cfg.EvtDriverUnload = EvtDriverUnload;  //卸载函数

//

//创建一个framework的驱动对象。

status = WdfDriverCreate(DriverObject,RegistryPath,WDF_NO_OBJECT_ATTRIBUTES,&cfg,&drv);

if(!NT_SUCCESS(status))

{

goto DriverEntry_Complete;

}

KdPrint(("Create wdf driver object successfully\n"));

这样,一个framework的驱动对象就创建好了。

创建一个设备(control device)

1. 要创建一个control device,首先得先分配一块内存

//分配一块内存

device_init = WdfControlDeviceInitAllocate(drv,&SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R);  

if( device_init == NULL )  

{    

status = STATUS_INSUFFICIENT_RESOURCES;    

goto DriverEntry_Complete;  

}

WdfControlDeviceInitAllocate函数分配了一块内存给结构WDFDEVICE_INIT,这个结构在创建control device的时候会被用到。

更多细节看

MSDN:http://msdn.microsoft.com/en-us/library/windows/hardware/ff545841(v=vs.85).aspx

2. 然后给这个设备绑定一个设备名字,注意这个设备名字只能被内核模式下的代码所看到,比如其他的内核驱动,用户模式代码是看不到的。

就好象是WDM里面的IoCreateDevice函数的第三个参数。

//设备名字,如: L"\\Device\\MyWDF_Device",只能被其他的内核驱动看到。

RtlInitUnicodeString(&ustring, MYWDF_KDEVICE);  

//将这个设备名字存入DEVICE_INIT结构中

status = WdfDeviceInitAssignName(device_init,&ustring);

if(!NT_SUCCESS(status))

{

goto DriverEntry_Complete;

}

KdPrint(("Device name Unicode string: %wZ (this name can only be used by other kernel mode code, like other drivers)\n", &ustring));

3. 给设备绑定2个回调。

//设置2个回调,FileCreate和FileClose

WDF_FILEOBJECT_CONFIG_INIT(&f_cfg,EvtDeviceFileCreate,EvtFileClose,NULL);

//存入DEVICE_INIT结构中

WdfDeviceInitSetFileObjectConfig(device_init,&f_cfg,WDF_NO_OBJECT_ATTRIBUTES);

这样当用户模式的代码调用CreateFile和CloseHandle的时候,这2个回调会被调用。

4. 初始化设备属性并且创建设备

这里创建一个control device

WDF_OBJECT_ATTRIBUTES_INIT(&object_attribs);

//创建一个设备. (control device)

status = WdfDeviceCreate(&device_init,&object_attribs,&control_device);

if(!NT_SUCCESS(status))

{

KdPrint(("create device failed\n"));

goto DriverEntry_Complete;

}

5. 创建一个符号连接

有了这个符号连接,用户模式代码才能找到这个设备。

就好像WDM里面IoCreateSymbolicLink()做的事情。

//创建一个符号连接

RtlInitUnicodeString(&ustring,MYWDF_LINKNAME);

status = WdfDeviceCreateSymbolicLink(control_device,&ustring);

if( !NT_SUCCESS(status) )  

{

KdPrint(("Failed to create Link\n"));  

goto DriverEntry_Complete;  

}

KdPrint(("Create symbolic link successfully, %wZ (user mode code should use this name, like in CreateFile())\n", &ustring));

6. 完成设备的创建

WdfControlFinishInitializing(control_device);

到这里,一个设备就创建成功了。这是一个control device,有关control device可以查看

http://msdn.microsoft.com/en-us/library/windows/hardware/ff545424(v=vs.85).aspx

framework驱动对象的创建和设备对象的创建都发生在DriverEntry()里面。

回调函数的实现

接下来就是回调函数的实现,这里就写了几行简单的代码。

static VOID EvtDriverUnload( WDFDRIVER Driver )
{  
KdPrint(("unload driver\n"));
KdPrint(("Doesn't need to clean up the devices, since we only have control device here\n"));
}/* EvtDriverUnload */VOID EvtDeviceFileCreate( __in WDFDEVICE Device, __in WDFREQUEST Request, __in WDFFILEOBJECT FileObject )
{
KdPrint(("EvtDeviceFileCreate"));WdfRequestComplete(Request, STATUS_SUCCESS);
}VOID EvtFileClose( __in  WDFFILEOBJECT FileObject )
{
KdPrint(("EvtFileClose"));
}

只有在FileCreate里面写了一行代码直接将irp请求完成。

这样一个最最简单的WDF驱动就写完了。

完整代码
#include <fltKernel.h>
#include <wdf.h>
#include <wdfdriver.h>
#include <wdfrequest.h>#define MYWDF_KDEVICE L"\\Device\\MyWDF_Device"//设备名称,其他内核模式下的驱动可以使用
#define MYWDF_LINKNAME L"\\??\\MyWDF_LINK"//符号连接,这样用户模式下的程序可以使用这个驱动设备。//声明回调
EVT_WDF_DRIVER_UNLOAD EvtDriverUnload;
EVT_WDF_DEVICE_FILE_CREATE EvtDeviceFileCreate;
EVT_WDF_FILE_CLOSE EvtFileClose;NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject , IN PUNICODE_STRING RegistryPath )
{  
NTSTATUS status;
WDF_OBJECT_ATTRIBUTES object_attribs;//驱动对象相关
WDF_DRIVER_CONFIG cfg;//驱动的配置
WDFDRIVER drv = NULL;//wdf framework 驱动对象,根节点//设备对象相关
PWDFDEVICE_INIT device_init = NULL;
UNICODE_STRING ustring;
WDF_FILEOBJECT_CONFIG f_cfg;
WDFDEVICE control_device;
PDEVICE_OBJECT dev = NULL;KdPrint(("DriverEntry [start]\n"));//初始化WDF_DRIVER_CONFIG
WDF_DRIVER_CONFIG_INIT(&cfg,NULL //不提供AddDevice函数
);cfg.DriverInitFlags = WdfDriverInitNonPnpDriver;  //指定非pnp驱动
cfg.DriverPoolTag   = (ULONG)'PEPU';  
cfg.EvtDriverUnload = EvtDriverUnload;  //指定卸载函数//创建一个framework驱动对象,在WDF程序里面,WdfDriverCreate是必须要调用的。
//framework驱动对象是其他所有wdf对象的父对象,换句话说framework驱动对象是wdf对象树的顶点,它没有父对象了。
status = WdfDriverCreate(DriverObject,RegistryPath,WDF_NO_OBJECT_ATTRIBUTES,&cfg,&drv);
if(!NT_SUCCESS(status))
{
goto DriverEntry_Complete;
}KdPrint(("Create wdf driver object successfully\n"));/创建一个设备...begin/........................
//先要分配一块内存WDFDEVICE_INIT,这块内存在创建设备的时候会用到。
device_init = WdfControlDeviceInitAllocate(drv,&SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R);  
if( device_init == NULL )  
{    
status = STATUS_INSUFFICIENT_RESOURCES;    
goto DriverEntry_Complete;  
}//创建设备的名字,内核模式下,名字类似: L"\\Device\\MyWDF_Device"
RtlInitUnicodeString(&ustring, MYWDF_KDEVICE);  
///系列一: 设备名称:设备扩展//将设备名字存入device_init中
status = WdfDeviceInitAssignName(device_init,&ustring);if(!NT_SUCCESS(status))
{
goto DriverEntry_Complete;
}KdPrint(("Device name Unicode string: %wZ (this name can only be used by other kernel mode code, like other drivers)\n", &ustring));//配置FILEOBJECT配置文件,设置FILECREATE,FILECLOSE回调。
/// IRJ_MJ_CREATE, IRJ_MJ_CLOSE: 对应的派遣函数
WDF_FILEOBJECT_CONFIG_INIT(&f_cfg,EvtDeviceFileCreate,EvtFileClose,NULL);//将FILEOBJECT的设置存入device_init中
/// 把 文件对象绑定到 设备属性中
WdfDeviceInitSetFileObjectConfig(device_init,&f_cfg,WDF_NO_OBJECT_ATTRIBUTES);//初始化设备属性
WDF_OBJECT_ATTRIBUTES_INIT(&object_attribs);
//根据前面创建的device_init来创建一个设备. (control device)
status = WdfDeviceCreate(&device_init,&object_attribs,&control_device);
if(!NT_SUCCESS(status))
{
KdPrint(("create device failed\n"));
goto DriverEntry_Complete;
}//创建符号连接,这样用户模式下的程序可以使用这个驱动。这个是必须的,不然用户模式下的程序不能访问这个设备。
/// IoCreateSysbolicLink(sysbolic_link_name, dev_name);
RtlInitUnicodeString(&ustring,MYWDF_LINKNAME);
status = WdfDeviceCreateSymbolicLink(control_device,&ustring);
if( !NT_SUCCESS(status) )  
{
KdPrint(("Failed to create Link\n")); 
goto DriverEntry_Complete;  
}KdPrint(("Create symbolic link successfully, %wZ (user mode code should use this name, like in CreateFile())\n", &ustring));WdfControlFinishInitializing(control_device);//创建设备完成。/创建一个设备...begin
/*******************************************
到这里,我们就成功创建了一个control device。
control device 是不支持png和power的,而且我们也不需要手工是删除。
因为framework会帮我们删除,看MSDN
If your driver creates control device objects but does not create framework device objects that support PnP and power management, 
the driver does not have to delete the control device objects. 
In this case, the framework deletes the control device objects after the driver's EvtDriverUnload callback function returns. 更多细节看MSDN,如
http://msdn.microsoft.com/en-us/library/windows/hardware/ff545424(v=vs.85).aspx
*******************************************/KdPrint(("Create device object successfully\n"));KdPrint(("DriverEntry succeeds [end]\n"));
DriverEntry_Complete:return status;
}static VOID EvtDriverUnload( WDFDRIVER Driver )
{  
KdPrint(("unload driver\n"));
KdPrint(("Doesn't need to clean up the devices, since we only have control device here\n"));
}/* EvtDriverUnload */VOID EvtDeviceFileCreate( __in WDFDEVICE Device, __in WDFREQUEST Request, __in WDFFILEOBJECT FileObject )
{
KdPrint(("EvtDeviceFileCreate"));/// IoCompleteRequest(pIrp);完成irp
WdfRequestComplete(Request, STATUS_SUCCESS);
}VOID EvtFileClose( __in  WDFFILEOBJECT FileObject )
{
KdPrint(("EvtFileClose"));
}

编译错误

使用VS2015+WDK10 在学习windows WDF驱动时候,使用下面链接文章提供的代码编译后,得到错误:

LNK2001无法解析的外部符号 SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R

http://blog.csdn.net/zj510/article/details/16983863

https://blog.csdn.net/wuoo98/article/details/54970782

解决方法:链接属性设置中增加

$(DDK_LIB_PATH)\wdmsec.lib

应用层程序

#include "stdafx.h"
#include <Windows.h>#define MYDEVICE L"\\\\.\\MyWDF_LINK"//符号链接int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hDevice = CreateFile(MYDEVICE,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);if (hDevice == INVALID_HANDLE_VALUE)
{
wprintf(L"Failed to open device %s, err: %x\n", MYDEVICE, GetLastError());
}
else
{
wprintf(L"Open device %s successfully\n", MYDEVICE);
CloseHandle(hDevice);wprintf(L"Closed handle\n");
}return 0;
}

这是个用户模式代码,运行一下,就会发现

image.png

image.png

用debugview看一下驱动的输出,看到了驱动里面的log,这就说明用户模式的代码CreateFile和CloseHandle成功的引起驱动调用2个回调。

image.png

安装调试

设备管理器-->添加过时硬件-->安装我手动从列表选择的硬件-->从磁盘安装

image.png

image.png

知识点总结

//声明回调

EVT_WDF_DRIVER_UNLOAD EvtDriverUnload;

EVT_WDF_DEVICE_FILE_CREATE EvtDeviceFileCreate;

EVT_WDF_FILE_CLOSE EvtFileClose;

NTSTATUS status;

WDF_OBJECT_ATTRIBUTES object_attribs;

//驱动对象相关

WDF_DRIVER_CONFIG cfg;//驱动的配置

WDFDRIVER drv = NULL;//wdf framework 驱动对象

//设备对象相关

PWDFDEVICE_INIT device_init = NULL;

UNICODE_STRING ustring;

WDF_FILEOBJECT_CONFIG f_cfg;

WDFDEVICE control_device;

PDEVICE_OBJECT dev = NULL;

//初始化WDF_DRIVER_CONFIG

WDF_DRIVER_CONFIG_INIT(...)

WdfDriverCreate(...)

WdfControlDeviceInitAllocate(...)

RtlInitUnicodeString(...)

WdfDeviceInitAssignName(...)

WDF_FILEOBJECT_CONFIG_INIT(...)

WdfDeviceInitSetFileObjectConfig(...)

WDF_OBJECT_ATTRIBUTES_INIT(...)

WdfDeviceCreate(...)

WdfDeviceCreateSymbolicLink(...)

WdfControlFinishInitializing(...)

WdfRequestComplete(...)

WDF驱动简介及几个驱动对象介绍

1.1 WDF简述

WDF是微软提出的全新驱动程序模型,它提供了面向对象、事件驱动的驱动程序开发框架,对它的研究是设计高效稳定设备驱动程序的基础。注意理解WDF模型的特点,对象模型,以及基本结构.

设备驱动程序是硬件设备连接到计算机系统的软件接口,任何设备都必须有相应的驱动程序才能在计算机系统上正常工作。设备驱动程序的优劣直接关系到整个系统的性能和稳定性,因此,设计和开发稳定高效的驱动程序具有重要意义。

WDF(Windows Driver Foundation)是微软提出的下一代全新的驱动程序模型,它是在WDM(Windows Driver Model)的基础上发展而来的,支持面向对象、事件驱动的驱动程序开发,提供了比WDM更高层次抽象的高度灵活、可扩展、可诊断的驱动程序框架。WDF框架管理了大多数与操作系统相关的交互,实现了公共的驱动程序功能(如电源管理、PNP支持),隔离了设备驱动程序与操作系统内核,降低了驱动程序对内核的影响。

WDF提供了两个框架:KMDF(内核模式驱动程序框架)和UMDF(用户模式驱动程序框架)。

1.2 WDF对象模型

KMDF框架支持面向对象、事件驱动的驱动程序模型

它定义了一系列的对象用来表示驱动、设备、中断等,每个对象有对应的属性、方法和事件。驱动程序利用这些方法创建对象、设置属性和响应事件。

框架定义的主要对象有:

1.2.1 WDFDRIVER对象

对应于WDM中的DRIVER-OBJECT,描述驱动在内存中的实例,包括加载的位置、有关的属性和所管理的设备。

1.2.2 WDFDEVICE对象

对应于WDM中的DEVICE-OBJECT,描述由驱动程序管理的单个设备实例。

设备可以是命名的也可以是未命名的,用户模式程序可以通过设备接口或符号链接访问设备。WDFDEVICE对象具有丰富的属性,如PNP和电源管理相关的事件处理回调函数(callbacks)。

1.2.3 WDFREQUEST对象

对应于WDM中的IRP,表示一个I/O请求。

1.2.4 WDFQUEUE对象

每个WDFQUEUE对象和一个WDFDEVICE对象关联,描述一个特殊的I/O请求队列。它具有一系列的事件处理回调函数,当I/O请求进入队列时,wdf框架将自动调用驱动程序中对应的callback。

1.2.5 WDFINTERRUPT对象

表示设备中断。驱动程序可以通过WDFINTERRUPT对象的中断使能enable和禁止disable事件处理callbacks使能或禁止设备中断;通过ISR和DPC for ISR例程处理设备中断。

1.3 WDF的对象模型是层次化的模型。

WDFDRIVER对象是根对象,其他对象都是它的子对象。对于大多数对象,驱动程序在创建它们的时候可以指定父对象,如果没有指定,则框架默认其父对象为WDF DRIVER对象。

WDF大大简化了WDM中的PNP和电源管理的开发。

WDM---> IRP_MJ_PNP,IRP_MN_START_DEVICE/STOP_DEVICE/REMOVE_DEVICE/...

MJ: major,,  MN: minor

WDF框架为设备停止、设备删除、电源状态切换等PNP和电源管理事件提供了适合的缺省行为,驱动程序本身不再纠缠于复杂的PNP和电源管理事件处理。

1.4 WDF请求队列

一个设备可以有多个请求队列,每个请求队列可以有一种模式。

1.4.1  WdfIoQueueDispatchSerial模式

请求队列将请求串行化后再处理

1.4.2  WdfIoQueueDispatchParallel模式

自动在每个请求到来时调用相应的回调函数;

1.4.3  WdfIoQueueDispatchManual模式

允许驱动程序手工分发请求,类似于WDM的工作方式。

IoSetCancelRoutine(...), interrupt, irql,

在WDM驱动程序中,I/O请求的取消是一个复杂难以理解的过程,开发人员必须有对内核深刻的理解才能正确处理I/O请求的取消。

WDF框架支持内建的I/O请求取消处理,使得驱动程序处理取消I/O请求的工作大大简化。

1.5 I/O请求包(IRP, WDFRequest) 

1.5.1  IRP简介

IRP是I/O系统用来存储处理I/O请求所需信息的地方, I/O管理器在IRP中保存一个指向调用者文件对象(FILE_OBJECT,设备:内联一个文件对象)的指针。

:所有设备都被当做  文件 来统一处理

CreateFile,CloseHandle,ReadFile, WriteFile,DeviceIoControl,CancelIo

ReadFile(handle,buf, len, &bytes, flags,....),

从编程的角度看, IRP是I/O管理器在响应一个I/O请求时从非分页系统内存中分配的一块可变大小的数据结构内存, I/O管理器每收到一个来自用户的请求就创建一个该结构,并将其作为参数传给驱动程序的DispatchXxx、StartIo等例程。该结构中存放有请求的类型、用户缓冲区的首地址、用户请求数据的长度等信息。驱动程序处理完这个请求后, 也在该结构中添加处理结果的有关信息, 然后调用IoCompleteRequest将其返回给I/O管理器, 用户程序的请求随即返回。     

每个IRP可以被看成由两部分组成:

固定部分和一个I/O堆栈。IRP的固定部分包含关于请求的信息, I/O堆栈则包含一系列I/O堆栈单元(I/O Stack location), 单元的数目应与驱动程序堆栈中处理这一请求的驱动程序数目相同, 每个单元对应一个将处理该IRP的驱动程序。     

1.5.2  IRP固定部分的域

 MdlAddress(Memory Descriptor List, MDL): 指向一个内存描述表。当驱动程序使用直接I/O时, MDL用来描述一个与该请求相关联的用户模式缓冲区       

AssociatedIrp: 该域是一个三指针联合, 其中与WDM驱动程序相关的指针是AssociatedIrp.SystemBuffer。如果设备执行缓冲I/O, 则SystemBuffer指针指向系统空间缓冲区, 否则为NULL。 

      RequestorMode: 取值为一个枚举常量UserMode或KernelMode, 指定请求初始化的模式为用户模式还是核心模式。驱动程序有时需要查看这个值来决定是否需要信任某些参数 

      Cancel: 该域为BOOLEAN类型。如果为TRUE, 则表明IoCancelIrp已被调用, 该函数用于取消这个请求。如果为FALSE, 则表明没有调用IoCancelIrp函数 

      CancelIrql: 一个IRQL(I/O Request Query Level)值, 表明那个专用的取消自旋锁是在这个IRQL上获取的。当驱动程序在取消例程中释放自旋锁时应该参考这个域 

      CancelRoutine: 指向驱动程序取消例程的地址。应该使用IoSetCancelRoutine函数设置CancelRoutine域而不是直接修改该域  

1.5.3      IRP堆栈单元中的域 

      任何内核模式程序在创建一个IRP时, 同时还创建了一个与之关联的I/O堆栈。堆栈中的I/O堆栈单元由IO_STACK_LOCATION结构定义, 每个堆栈单元都对应一个将处理的IRP的驱动程序。为了在一个给定的IRP中确定当前的IRP I/O堆栈单元, 驱动程序可以调用IoGetCurrentIrpStackLocation函数, 该函数返回当前I/O堆栈单元的指针。 

      MajorFunction: 该IRP的主要功能代码, 它指出所要执行的I/O操作类型。例如: 主功能代码IRP_MJ_READ表示通过Win32 API函数CreateFile发送的请求。主功能代码与驱动程序对像的MajorFunction表中的某个分发函数指针相对应。 

      MinorFunction: 该IRP的副功能代码, 它进一步指出该IRP属于哪个主功能类。例如: IRP_MJ_PNP请求有十几个副功能代码, 包括IRP_MN_START_DEVICE、IRP_MN_REMOVE_DEVICE等。 

      DeviceObject: 指向该堆栈单元对应的设备对象地址, 该域由IoCallDriver函数负责填写。 

      FileObject: 指向与一个I/O请求有关的文件对象地址。  

1.5.4  I/O功能代码 

      IRP_MJ_CREATE: 打开设备  CreateFile 

IRP_MJ_CLEANUP: 在关闭设备时, 取消挂起的I/O请求  CloseHandle       

IRP_MJ_CLOSE: 关闭设备  CloseHandle

 IRP_MJ_READ: 从设备获得数据  ReadFile       

IRP_MJ_WRITE: 向设备发送数据  WriteFile 

       IRP_MJ_DEVICE_CONTROL: 对用户模式或内核模式客户可用的控制操作  DeviceControl 

       IRP_MJ_INTERNAL_DEVICE_CONTROL: 只对内核模式客户程序可用的控制操作  没有对应的Win32 API 

IRP_MJ_QUERY_INFORMATION: 得到文件的长度  GetFileLength       

IRP_MJ_SET_INFORMATION: 设置文件的长度  SetFileLength 

      IRP_MJ_FLUSH_BUFFERS: 写输出缓冲区或丢弃输入缓冲区  FlushFileBuffers  FlushConsoleInputBuffer  PureComm 

      IRP_MJ_SHUTDOWN: 系统关闭  InitialSystemShutdown   

WDF模型驱动程序开发

WDF驱动程序开发

1. 引言

设备驱动程序是硬件设备连接到计算机系统的软件接口,任何设备都必须有相应的驱动程序才能在计算机系统上正常工作。设备驱动程序的优劣直接关系到整个系统的性能和稳定性,因此,设计和开发稳定高效的驱动程序具有重要意义。

WDF(Windows Driver Foundation)是微软提出的下一代全新的驱动程序模型,它是在WDM(windows Driver Model)的基础上发展而来的,支持面向对象、事件驱动的驱动程序开发,提供了比WDM更高层次抽象的高度灵活、可扩展、可诊断的驱动程序框架。

WDF框架管理了大多数与操作系统相关的交互,实现了公共的驱动程序功能(如电源管理、PnP支持),隔离了设备驱动程序与操作系统内核,降低了驱动程序对内核的影响。

WDF提供了两个框架:KMDF(内核模式驱动程序框架)和UMDF(用户模式驱动程序框架)。本文只介绍KMDF的设计与实现。

2. WDF对象模型

KMDF框架支持面向对象、事件驱动的驱动程序模型。它定义了一系列的对象用来表示设备、驱动、中断等,每个对象有对应的属性、方法和事件。驱动程序利用这些方法创建对象、设置属性和响应事件。

框架定义的主要对象有:

WDFDRIVER对象,对应于WDM中的DRIVER_OBJECT。描述驱动在内存中的实例,包括加载的位置、有关的属性和所管理的设备。

WDFDEVICE对象,对应于WDM中的DEVICE_OBJECT。描述由驱动程序管理的单个设备实例,设备可以是命名的也可以是未命名的。用户模式程序可以通过设备接口或设备名称访问设备。WDFDEVICE对象具有丰富的属性,如pnp和电源管理相关的事件处理回调函数(callbacks)。

WDFREQUEST对象,对应于WDM中的IRP,表示一个I/O请求。

WDFQUEUE对象:每个WDFQUEUE对象和一个WDFDEVICE对象关联,描述一个特殊的I/O请求队列。它具有一系列的事件处理回调函数,当I/O请求进入队列时,框架将自动调用驱动程序中对应的callback。

WDFINTERRUPT对象:表示设备中断。驱动程序可以通过WDFINTERRUPT对象的中断使能和禁止事件处理callbacks使能或禁止设备中断;通过ISR和DPCforISR例程处理设备中断。

WDF的对象模型是层次化的模型。WDFDRIVER对象是根对象,其他对象都是它的子对象。对于大多数对象,驱动程序在创建他们的时候可以指定父对象,如果没有指定,则框架默认其父对象为WDFDRIVER对象。

WDF大大简化了WDM中的pnp和电源管理的开发。WDF框架为设备停止、设备删除、电源状态切换等pnp和电源管理事件提供了适合的缺省行为,驱动程序本身不再纠缠于复杂的pnp和电源管理事件处理。

此外,WDF还集成了请求队列的支持,一个设备可以有多个请求队列,每个请求队列可以有一种模式。最简单的是 WdfIoQueueDispatchSerial模式,在这种模式下,请求队列将请求串行化后再处理;而WdfIoQueueDispatchParallel模式则自动在每个请求到来时调用相应的回调函数;最后WdfIoQueueDispatchManual模式允许驱动程序手工分发请求,类似于WDM的工作方式。

在WDM驱动程序中,I/O请求的取消是一个复杂难以理解的过程,开发人员必须有对内核深刻的理解才能正确处理I/O请求的取消。WDF框架支持内建的I/O请求取消处理,使得驱动程序处理取消I/O请求的工作大大简化。

3. WDF设备驱动程序的结构

与WDM驱动程序一样,WDF驱动程序得标准入口函数是DriverEntry。与WDM不同,WDF的DriverEntry只负责创建和初始化WDFDRIVER对象,告诉WDF框架处理增加新设备连接的回调函数。

NTSTATUS  DriverEntry(PDRIVER_OBJECT DriverObj, PUNICODE_STRING RegistryPath)
{NTSTATUS code;WDF_DRIVER_CONFIG config;WDFDRIVER hDriver;// 初始化驱动配置结构,指定设备添加事件callback
WDF_DRIVER_CONFIG_INIT_NO_CONSTRAINTS(&config, MyEvtDeviceAdd);// 创建WDFDRIVER对象code = WdfDriverCreate(DriverObj,RegistryPath,WDF_NO_OBJECT_ATTRIBUTES,&config,   // 指向config结构的指针NULL);     return(code);
}

    每当有新设备连接到系统时,WDF框架自动调用EvtDeviceAdd设备添加callback。该回调函数初始化pnp和电源管理相关结构,设置相应的事件处理callbacks,然后创建WDFDEVICE对象和符号连接,初始化请求队列、中断处理等相关结构,设置相应的回调函数。

WDFSTATUS  MyEvtDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit)
{WDFSTATUS status = STATUS_SUCCESS;WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;WDF_OBJECT_ATTRIBUTES objAttributes;WDFDEVICE device;PMY_DEVICE_CONTEXT devContext;WDF_IO_QUEUE_CONFIG ioCallbacks;
WDF_INTERRUPT_CONFIG interruptConfig;
///1. 设备对象
///2. IO请求队列
///3. 中断对象// 初始化pnpPowerCallbacks ,设置与PnP和电源管理相关的事件回调函数WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);pnpPowerCallbacks.EvtDevicePrepareHardware = MyEvtPrepareHardware;pnpPowerCallbacks.EvtDeviceReleaseHardware = MyEvtReleaseHardware;pnpPowerCallbacks.EvtDeviceD0Entry= MyEvtDeviceD0Entry;pnpPowerCallbacks.EvtDeviceD0Exit = MyEvtDeviceD0Exit;WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, pnpPowerCallbacks);// 创建设备对象,初始化相关的属性WDF_OBJECT_ATTRIBUTES_INIT(&objAttributes);WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&objAttributes,MY_DEVICE_CONTEXT);// 命名设备status = WdfDeviceInitUpdateName(DeviceInit, L"\\device\\WDFDEMO");if (!NT_SUCCESS(status))     return(status);status = WdfDeviceCreate(&DeviceInit, &objAttributes, &device);    if ( !NT_SUCCESS(status))     return(status);devContext = MyGetContextFromDevice(device);devContext->WdfDevice = device;// 创建符号连接status = WdfDeviceCreateSymbolicLink(device, L"\\DosDevices\\WDFDEMO");
if (!NT_SUCCESS(status))     return(status);// 创建和初始化请求队列WDF_IO_QUEUE_CONFIG_INIT(&ioCallbacks, WdfIoQueueDispatchSerial,WDF_NO_EVENT_CALLBACK,  WDF_NO_EVENT_CALLBACK);ioCallbacks.EvtIoDeviceControl = MyEvtDeviceControlIoctl;status = WdfDeviceCreateDefaultQueue(device,&ioCallbacks,WDF_NO_OBJECT_ATTRIBUTES,NULL); 
if (!NT_SUCCESS(status))    return(status);// 创建和初始化中断对象,MyIsr和MyDpc分别是isr中断服务例程和DPC例程WDF_INTERRUPT_CONFIG_INIT(&interruptConfig, FALSE,  MyIsr, MyDpc);interruptConfig.EvtInterruptEnable  = MyEvtInterruptEnable;//中断使能interruptConfig.EvtInterruptDisable = MyEvtInterruptDisable;//中断禁止status = WdfInterruptCreate(device, &interruptConfig,&objAttributes,&devContext->WdfInterrupt);return(status);
}

WDF驱动程序下一步的工作就是编写各事件处理回调函数,当相应事件发生时,WDF框架会自动调用指定的回调函数进行处理。

其中EvtDevicePrepareHardware回调函数在分配资源的时候被调用,框架将分配给设备的资源传递给回调函数,回调函数保存需要的资源,将共享内存映射到内核虚拟地址空间。与此对应的是EvtDeviceReleaseHardware回调函数,每当设备释放所占用的资源时,框架都将调用它。

EvtDeviceD0Entry 和 EvtDeviceD0Exit事件callbacks则分别在设备即将进入和离开D0电源状态时调用。EvtIoDeviceControl、EvtIoRead、EvtIoWrite等回调函数分别用来处理DeviceControl、Read、Write I/O请求。

当WDF框架获得一个I/O请求时,它首先确定该请求应该放入哪个请求队列。如果驱动程序没有提供指定的队列,WDF框架默认将请求放入缺省请求队列会自动调用对应的回调函数。然后,框架寻找处理该请求的回调函数,如果驱动程序提供了相应的callback,则调用它处理请求。对于没有指定回调函数的I/O请求,WDF调用EvtIoStart回调函数处理。如果EvtIoStart callback也不存在,框架将返回STATUS_NOT_SUPPORTED。

设备中断的管理由EvtInterruptEnable callback、EvtInterruptDisable callback、中断服务例程(ISR)和DpcForISr例程实现。WDF框架在调用EvtDeviceD0Entry callback和注册ISR后,通过调用EvtInterruptEnable回调函数使能设备中断;而EvtInterruptDisable回调函数则在设备离开D0状态,EvtDeviceD0Exit callback调用前获得调用,完成禁止设备中断的工作。此外,中断服务例程和DpcForIsr例程具体完成中断服务的功能,与WDM驱动程序相似。


http://chatgpt.dhexx.cn/article/y8ZDJm3f.shtml

相关文章

windows驱动开发4:WDM、WDF等驱动基本概念

一、WDM 1、WDM WDM是英文Windows Driver Model(WDM)的缩写&#xff0c;是Windows98和Windows2000使用的新的驱动程序设计规范。使用WDM使得硬件驱动程序更加稳定&#xff0c;让操作系统对硬件更加有效地控制硬件。 除了定义一个驱动程序与操作系统连接的标准接口以外&#…

WDF开发详解

原文地址&#xff1a;https://blog.csdn.net/lang_eva/article/details/109676808 WDF开发详解 添加设备&#xff1a;hdwwiz KMDF驱动程序框架 KMDF 驱动程序框架由对象和事件回调例程构成。KMDF 框架中所有的事物都由对象表示&#xff0c;各种事件处理都由事件回调例程来完…

windows驱动开发-WDF编程

文章目录 前言WDF编程前的准备工作WDF编程创建驱动对象创建设备对象设备对象的回调函数链表操作驱动的测试代码 其他 前言 注&#xff1a;本文的完整代码见仓库 18-WDF-reflect 代码参考自&#xff1a;junjiexing/libredirect 我不是从事驱动开发的专业人员&#xff0c;打酱…

javaWeb图书管理系统

javaWeb图书管理系统 1.项目简单介绍 a.项目用到的技术 IDE: Intellij IDEA语言&#xff1a;java&#xff0c;html ajax&#xff0c;js数据库&#xff1a;Mysql数据库可视化&#xff1a; navicatweb服务器&#xff1a;Tomcat框架&#xff1a;&#xff08;mybatis&#xff0…

基于Java基础的图书管理系统

文章目录 前言一、前期准备二、需求分析三、核心代码开发1、 model 层1.1、 Book 类1.2、 User 类1.3、 NormalUser 类1.4、 Admin 类 2、 service 层2.1、 IOOperation 接口2.1、 AddBook 类2.2、 DeleteBook 类2.3、 ReplaceBook 类2.4、 ListAllBook 类2.5、 BorrowBook 类2…

图书馆管理系统 Java

目录 要求&#xff1a; 代码 Operate接口 Book类 Reader类 BookList类 ReadList 类 Infor类 InforList类 main 功能实现 改进 错误 总结 要求&#xff1a; 为图书管理人员编写一个图书管理系统&#xff0c;图书管理系统的设计主要是实现对图书的管理和相关操作&a…

图书管理系统【Java实现】

目录 一、项目简介二、项目演示1.登录界面2.图书借阅信息管理界面3.新增图书借阅信息界面4.修改图书借阅信息界面5.删除图书借阅信息界面 三、项目流程1.准备开发环境&#xff08;1&#xff09;下载所需文件&#xff08;2&#xff09;在IDEA中配置Maven&#xff08;3&#xff0…

Java开发实现图书管理系统(超详细)

本文用Java代码实现图书代码管理系统&#xff0c;有些地方可能会有纰漏&#xff0c;希望各位大佬鉴赏&#xff01;&#xff01; 文章目录 文章目录 一、Java实现图书管理系统 1.1创建book包 二、创建图书管理系统的操作包 2.1创建Operation接口 三、创建User包 3.1创建User类 四…

Java实现图书管理系统(新手友好)

图书管理系统 一、初识工作二、具体实现三、代码book包Book类BookList类 operation包IOperation接口AddOperationBorrowOperationDelOperationDisplayOperationExitOperationFindOperationReturnOperation user包AdminUserNormalUserUser Main 一、初识工作 我们首先要清楚的是…

图书管理系统【java】

目录 &#x1f947;1.设计背景 &#x1f50e;2.设计思路 &#x1f511;3.book包 &#x1f4d7;3.1 Book类的实现 &#x1f4d5;3.2 BookList类的实现(书架) &#x1f511;4.user包 &#x1f4d9;4.1 User类的实现 &#x1f4d2;4.2 AdminUser&#xff08;管理员&#x…

图书管理系统(Java)

&#x1f4da; 一、前言1.1整体框架 二、book包2.1Book2.2BookList 三、user包3.1、User3.2、Adminuser3.3、Normaluser 四、Operation包4.1、IOperation接口4.2、AddOperattion4.3、ShowOperation4.4、FindOperation4.5、DelOperation4.6、BorrowOperation4.7、ReturnOperatio…

图书管理系统(Java简单版)(完整代码+详解)

目录 详解&#xff1a; BookList类&#xff1a; InOperation接口 User类&#xff08;父类&#xff09; 和 Main类&#xff08;这俩要一起看&#xff09; 完整代码 book包 Book类 BookList类 operation包 AddBook类 BorrowBook类 DeleteBook类 FindBook类 Pr…

用java实现图书管理系统。

在学完java基础篇的时候&#xff0c;安排做了一个综合版的java基础项目&#xff0c;可以把之前学到的知识综合运用。 图书管理系统。 一.项目设计到的知识1.MVC设计模式思想&#xff08;分包&#xff09;>项目分包>MVC简单介绍 2.GUI&#xff08;图形化界面&#xff09;3…

Java实现简易版的【图书管理系统】

目录 &#x1f30e;1.分析图书管理系统的功能 &#x1f30d; 2.在IDEA中进行功能类的创建 &#x1f984;2.1 创建一个名为book的包&#xff0c;里面存放书相关的 &#x1f984; 2.2 创建一个名为Operation的包&#xff0c;里面存放对书的所有操作 &#x1f30e; 3.进行用户…

Java图书管理系统(代码及详解)

图书管理系统在C、C、Java学习中我们都会进行练习来串联我们学习的一些知识以及使用场景&#xff0c;这里跟着我我带大家敲Java版本&#xff01; 结果展示&#xff1a; 这是我们最终实现的图书管理系统&#xff0c;下面我们慢慢来 思路&#xff1a; Java是面向对象的语言特点…

JAVA实现简易的图书管理系统(含过程)

目录 设计背景 成果展示 设计思路 详细代码 book包 Book类 BookList类 operation包 IOperation接口 AddOperation类 BorrowOperation类 DelOperation类 DisplayOperation类 ExitOperation类 ReturnOperation类 user包 User类 Admin类 NormalUser类 Test类…

图书管理系统(Java实现)[附完整代码]

作者&#xff1a;爱塔居的博客_CSDN博客-JavaSE领域博主 专栏&#xff1a;JavaSE 作者专栏&#xff1a;大三学生&#xff0c;希望跟大家一起进步&#xff01; 文章目录 目录 文章目录 一、图书管理系统菜单 二、实现基本框架 三、实现业务 3.1 打印所有图书 3.2 退出系统 3.3 查…

JAVA->实现图书管理系统

目录 一、图书管理系统展示 1.管理员 2.普通用户 ​编辑3.操作 二、图书管理系统基本实现思路 book --- 包 1.Book类 注意&#xff1a; 2.BookList类 注意&#xff1a; Opreration --- 包 Operration接口 1.AddOperation -- 增加图书 注意&#xff1a; 2. BorrowO…

Java实现简单的图书管理系统

图书管理系统 简介知识点类封装包继承接口多态 创建书&#xff08;Book&#xff09;书架&#xff08;BookList&#xff09;主函数&#xff08;Main&#xff09;用户&#xff08;User&#xff09;管理员&#xff08;Administrator&#xff09;接口&#xff08;IOperation&#x…

Java基础之图书管理系统

一&#xff1a;建立信息表 为图书管理人员编写一个图书管理系统&#xff0c;图书管理系统的设计主要是实现对图书的管理和相关操作&#xff0c;包括3个表&#xff1a; 图书信息表——存储图书的基本信息&#xff0c;包括书号、书名、作者、出版社、出版日期、存馆数量、定价等…