框架文件对象
当应用程序或驱动程序尝试访问设备(通常是通过创建或打开文件)时,操作系统会向驱动程序堆栈发送文件创建请求。 应用程序或驱动程序使用完设备后,系统会向驱动程序堆栈发送文件清理和关闭请求。 这三个 请求的请求类型 分别为 WdfRequestTypeCreate、 WdfRequestTypeCleanup 和 WdfRequestTypeClose。
通常,除非驱动程序调用 了 WdfDeviceInitSetExclusive,否则驱动程序在收到文件创建、清理和关闭请求时必须执行特定于文件或其他特定于访问的操作,因为可以同时打开多个文件,或者多个应用程序可以同时访问设备。 因此,驱动程序必须跟踪与每个文件或应用程序关联的 I/O 请求。
框架定义 框架文件对象,这些对象表示应用程序或驱动程序访问设备的方式,例如文件、目录、卷、邮件槽、命名管道或整个设备。 文件名可以与文件对象相关联,但文件名的含义是特定于驱动程序的。 有关文件名的详细信息,请参阅 控制设备命名空间访问。
如果驱动程序必须处理文件操作,则必须从其 EvtDriverDeviceAdd 回调函数中调用 WdfDeviceInitSetFileObjectConfig。 WdfDeviceInitSetFileObjectConfig 方法接收WDF_FILEOBJECT_CONFIG结构作为输入。 驱动程序使用此结构来注册其 EvtDeviceFileCreate、 EvtFileCleanup 和 EvtFileClose 回调函数,并选择性地指示每次驱动程序收到文件创建请求时框架是否应创建框架文件对象。
处理文件操作的大多数驱动程序将特定于文件的信息存储在框架文件对象的 上下文空间中。 如果驱动程序处理文件操作,但不需要将信息存储在文件对象的上下文空间中,则框架不必为驱动程序创建框架文件对象。
创建或打开文件
当框架收到函数驱动程序的文件创建请求时,它会:
创建表示该文件的框架文件对象,除非驱动程序之前指示它不需要使用框架文件对象。
如果驱动程序已注册回调函数,则调用驱动程序的 EvtDeviceFileCreate 回调函数。
EvtDeviceFileCreate 回调函数通常获取有关文件的信息,例如其名称和文件对象标志。 驱动程序通常将此信息存储在框架文件对象的上下文空间中。
驱动程序可以调用 WdfDeviceConfigureRequestDispatching 来设置 I/O 队列以接收 (WdfRequestTypeCreate 请求类型) 的所有文件创建请求,而不是提供 EvtDeviceFileCreate 回调函数。 驱动程序随后将在队列的 EvtIoDefault 请求处理程序中接收文件创建请求。 (如果队列WDF_IO_QUEUE_CONFIG结构的DefaultQueue 成员设置为 TRUE,则 I/O 队列无法接收文件创建请求。)
如果驱动程序未提供 EvtDeviceFileCreate 回调函数,并且未设置 I/O 队列来处理 WdfRequestTypeCreate 类型的 I/O 请求,则框架:
如果驱动程序是函数驱动程序,则完成状态值为 STATUS_SUCCESS 驱动程序的所有文件创建请求。
如果驱动程序是筛选器驱动程序,则将所有文件创建请求转发到下一个较低的驱动程序。
(若要查看如何更改此行为,请参阅 WDF_FILEOBJECT_CONFIG structure 的 AutoForwardCleanupClose 成员。)
注意如果函数驱动程序未提供应用程序可用于访问驱动程序设备的任何设备接口,则驱动程序必须提供 EvtDeviceFileCreate 回调函数,该函数使用状态值完成所有文件创建请求,其状态值NT_SUCCESS () FALSE。 否则,恶意应用程序可能会尝试使用设备的物理设备对象名称访问设备, (PDO) 。 (所有 PDO 都具有 名称。)
如果驱动程序将创建请求 转发 到 I/O 目标,则驱动程序以后不得使用失败状态值 完成 请求,除非驱动程序从 I/O 目标收到失败状态值。 否则,较低的驱动程序不会收到创建请求失败的通知,并且可能会尝试像打开文件一样运行。
如果驱动程序将创建请求转发到 I/O 目标,则如果框架已为创建请求创建了框架文件对象,则驱动程序无法设置 WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET 标志。 因此,驱动程序无法为创建请求设置WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET标志,除非它还设置了 WdfFileObjectNotRequired 标志,因为如果堆栈中较低的驱动程序未能通过创建请求,驱动程序将无法清理 WDFFILEOBJECT。 相反,驱动程序可以使用任何其他发送选项,例如,使用完成例程异步发送或同步发送。 在这两种情况下,驱动程序必须在重新获得控制权时调用 WdfRequestComplete 。
请注意,如果驱动程序以错误状态完成创建请求,框架将删除框架文件对象,但不调用驱动程序的 EvtFileCleanup 或 EvtFileClose 回调函数。 因此,如果驱动程序在文件对象的上下文空间之外分配额外的特定于对象的内存,则必须提供 一个 EvtCleanupCallback 或 EvtDestroyCallback 回调函数来删除分配的内存。
对于 Windows Vista 及更高版本,可以 取消文件创建请求。 早期版本的 Windows 操作系统不支持取消文件创建请求。
系统始终为来自用户应用程序的每个创建请求创建 Windows 驱动程序模型 (WDM) 文件对象。 如果驱动程序发送创建请求,它可能不会为该请求创建 WDM 文件对象。 通常,如果不存在 WDM 文件对象,框架不会创建框架文件对象。 但是,如果驱动程序已调用 WdfDeviceInitSetExclusive,并且驱动程序已在 WDF_FILEOBJECT_CONFIG 结构的 FileObjectClass 成员中设置了 WdfFileObjectWdfCannotUseFsContexts,则即使 WDM 文件对象不存在,框架也会创建框架文件对象。
获取文件信息
驱动程序的 EvtDeviceFileCreate 回调函数可以调用以下一个或多个对象方法,以获取有关应用程序或驱动程序对设备的访问权限的信息:
WdfFileObjectGetFileName
返回框架文件对象中包含的文件名。
WdfFileObjectGetFlags
返回框架文件对象中包含的标志。
WdfFileObjectWdmGetFileObject
返回与框架文件对象关联的 WDM 文件对象。
WdfRequestGetParameters
检索与框架请求对象关联的参数。 如果请求类型为 WdfRequestTypeCreate,则WDF_REQUEST_PARAMETERS结构的 Parameters.Create 成员包含有关文件创建请求的信息。
通常,驱动程序将文件信息存储在框架文件对象的上下文空间中。 当驱动程序从某个请求获取 I/O 请求(如果其 I/O 队列),驱动程序可以调用 WdfRequestGetFileObject 来获取与该请求关联的框架文件对象的句柄。 然后,驱动程序可以检索存储在框架文件对象的上下文空间中的文件信息。
驱动程序可以通过调用 WdfIoQueueRetrieveRequestByFileObject 在 I/O 队列中搜索与特定文件关联的请求。
如果驱动程序具有指向 WDM DEVICE_OBJECT 结构的指针,则驱动程序可以调用 WdfDeviceGetFileObject 以获取与 WDM 设备对象关联的框架文件对象的句柄。
关闭文件
当应用程序或其他驱动程序关闭文件时,框架会收到针对驱动程序的清理请求和关闭请求。 框架:
如果驱动程序已注册这些回调函数,则调用驱动程序的 EvtFileCleanup 和 EvtFileClose 回调函数。
删除表示文件的框架文件对象。
驱动程序的 EvtFileCleanup 和 EvtFileClose 回调函数接收框架文件对象的句柄。 驱动程序可以调用 WdfFileObjectGetDevice 来确定哪个框架设备对象与框架文件对象相关联。