minispy 示例是一个用于监视和记录系统中发生的任何 I/O 和事务活动的工具。 此示例与 FileSpy 旧版过滤器类似; 然而,与 FileSpy 不同的是,minispy 是作为微型过滤器实现的。
minispy 由用户模式和内核模式组件组成。 内核模式组件向过滤器管理器注册与各种 I/O 和事务操作相对应的回调函数。 这些回调函数帮助 minispy 记录系统中发生的任何 I/O 和事务活动。 当用户可以请求记录的信息时,记录的信息被传递到用户模式组件,该组件可以将其输出在屏幕上或将其记录到磁盘上的文件中。
要观察设备上的 I/O 活动,您必须使用 minispy 用户模式组件显式地将 minispy 连接到该设备。 同样,您可以请求 minispy 停止记录特定设备的数据。
如果您正在开发微型过滤器,则应该使用此示例。
如果构建成功,驱动程序 minispy.sys 将被放置在源文件中指定的 %TargetPath% 目录的特定于平台的子目录中。
最终用户
minispy minifilter 附带了一个用于安装 minifilter 的 INF 文件。 要安装微型过滤器,请执行以下操作:
此安装将进行必要的注册表更新以注册元数据服务并将 minispy.sys 放置在 %SystemRoot%\system32\drivers 目录中。
此安装将进行必要的注册表更新以注册元数据服务并将 minispy.sys 放置在 %SystemRoot%\system32\drivers 目录中。
为 Minifilter 驱动程序编写 DriverEntry 例程
每个文件系统微筛选器驱动程序都必须有一个 DriverEntry 例程。 DriverEntry 例程在微过滤器驱动程序加载时被调用。
DriverEntry 例程执行全局初始化、注册微筛选器驱动程序并启动筛选。 该例程在 IRQL PASSIVE_LEVEL 的系统线程上下文中运行。
DriverEntry例程定义如下:
NTSTATUS
(*PDRIVER_INITIALIZE) (
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
DriverEntry 有两个输入参数。 第一个是 DriverObject,是加载微过滤器驱动程序时创建的驱动程序对象。 第二个是RegistryPath,它是一个指向计数Unicode 字符串的指针,该字符串包含微过滤器驱动程序注册表项的路径。
微过滤器驱动程序的 DriverEntry 例程必须按顺序执行以下步骤:
每个微筛选器驱动程序都必须从其 DriverEntry 例程调用 FltRegisterFilter,以将自身添加到已注册微筛选器驱动程序的全局列表中,并向筛选器管理器提供回调例程列表和有关驱动程序的其他信息。
在 MiniSpy 示例中,微过滤器驱动程序已注册,如以下代码示例所示:
NTSTATUS 状态;
status = FltRegisterFilter(
DriverObject, //Driver
&FilterRegistration, //Registration
&MiniSpyData.FilterHandle); //RetFilter
FltRegisterFilter 有两个输入参数。 第一个 Driver 是驱动程序对象指针,微筛选器驱动程序将其作为 DriverEntry 例程的 DriverObject 输入参数接收。 第二个是 Registration,是指向 FLT_REGISTRATION 结构的指针,该结构包含微过滤器驱动程序回调例程的入口点。
此外,FltRegisterFilter 有一个输出参数 RetFilter,它接收微过滤器驱动程序的不透明过滤器指针。 该过滤器指针是许多 FltXxx 支持例程(包括 FltStartFiltering 和 FltUnregisterFilter)所需的输入参数。
调用 FltRegisterFilter 后,微筛选器驱动程序的 DriverEntry 例程通常调用 FltStartFiltering 来开始筛选 I/O 操作。
每个微筛选器驱动程序都必须从其 DriverEntry 例程调用 FltStartFiltering 来通知筛选器管理器微筛选器驱动程序已准备好开始附加到卷并筛选 I/O 请求。 微筛选器驱动程序调用 FltStartFiltering 后,筛选器管理器将微筛选器驱动程序视为完全活动的微筛选器驱动程序,向其提供 I/O 请求和要附加到的卷的通知。 即使在 FltStartFiltering 返回之前,微筛选器驱动程序也必须准备好开始接收这些 I/O 请求和通知。
在 MiniSpy 示例驱动程序中,调用 FltStartFiltering,如以下代码示例所示:
status = FltStartFiltering( MiniSpyData.FilterHandle );
if( !NT_SUCCESS( status )) {
FltUnregisterFilter( MiniSpyData.FilterHandle );
}
如果对 FltStartFiltering 的调用未返回 STATUS_SUCCESS,则微筛选器驱动程序必须调用 FltUnregisterFilter 来注销自身。
微筛选器驱动程序的 DriverEntry 例程通常返回 STATUS_SUCCESS。 但如果微过滤器初始化失败,DriverEntry 例程应返回适当的错误 NTSTATUS 值。
如果 DriverEntry 例程返回的状态值不是成功的 NTSTATUS 值,系统将通过卸载微筛选器驱动程序进行响应。 不调用微筛选器驱动程序的 FilterUnloadCallback 例程。 因此,DriverEntry 例程必须在返回非成功 NTSTATUS 值的状态值之前释放为系统资源分配的所有内存。
文件系统微筛选器驱动程序可以选择将 PFLT_FILTER_UNLOAD_CALLBACK 类型的例程注册为微筛选器驱动程序的 FilterUnloadCallback 例程。 此回调例程也称为微筛选器驱动程序的卸载例程。
微过滤器驱动程序不需要注册 FilterUnloadCallback 例程。 但是,我们强烈建议微筛选器驱动程序注册此回调例程,因为如果微筛选器驱动程序不注册 FilterUnloadCallback 例程,则无法卸载该驱动程序。
为了注册此回调例程,微筛选器驱动程序将 PFLT_FILTER_UNLOAD_CALLBACK 类型例程的地址存储在 FLT_REGISTRATION 结构的 FilterUnloadCallback 成员中,微筛选器驱动程序将其作为参数传递给其 DriverEntry 例程中的 FltRegisterFilter。
FilterUnloadCallback 例程定义如下:
typedef NTSTATUS
(*PFLT_FILTER_UNLOAD_CALLBACK) (
FLT_FILTER_UNLOAD_FLAGS Flags
);
FilterUnloadCallback 例程有一个输入参数 Flags,该参数可以为 NULL 或 FLTFL_FILTER_UNLOAD_MANDATORY。 过滤器管理器将此参数设置为 FLTFL_FILTER_UNLOAD_MANDATORY 以指示卸载操作是强制的。 有关此参数的更多信息,请参阅 PFLT_FILTER_UNLOAD_CALLBACK 。
微过滤器驱动程序的 FilterUnloadCallback 例程必须执行以下步骤:
如果微筛选器驱动程序先前通过调用 FltCreateCommunicationPort 打开了内核模式通信服务器端口,则它必须通过调用 FltCloseCommunicationPort 关闭该端口。 为了防止系统在卸载过程中挂起,微过滤器驱动程序的 FilterUnloadCallback 例程必须在调用 FltUnregisterFilter 之前关闭此端口。
如果用户模式应用程序与通信服务器端口有打开的连接,则该连接的任何客户端端口在 FltCloseCommunicationPort 返回后将保持打开状态。 但是,当卸载微过滤器驱动程序时,过滤器管理器将关闭所有客户端端口。
微筛选器驱动程序的 FilterUnloadCallback 例程必须调用 FltUnregisterFilter 来取消注册微筛选器驱动程序。 调用 FltUnregisterFilter 会导致发生以下情况:
如果微筛选器驱动程序的不透明筛选器指针上存在未完成的 rundown 引用,则 FltUnregisterFilter 会进入等待状态,直到它们被删除。 未完成的循环引用通常会发生,因为微筛选器驱动程序已调用 FltQueueGenericWorkItem 将工作项插入系统工作队列,并且该工作项尚未出队和处理。 (当微型筛选器驱动程序调用 FltQueueGenericWorkItem 时,筛选器管理器会添加纲要引用,并在微型筛选器驱动程序的工作例程返回时删除它。)
如果微筛选器驱动程序调用了向微筛选器驱动程序的不透明筛选器指针添加缩减引用的任何例程(例如 FltObjectReference 或 FltGetFilterFromInstance ),但随后没有调用 FltObjectDereference ,则也可能会发生未完成的缩减引用。
微筛选器驱动程序的 FilterUnloadCallback 例程必须执行任何所需的全局清理。 以下列表包括微筛选器驱动程序可能执行的全局清理任务的示例:
微筛选器驱动程序的 FilterUnloadCallback 例程通常返回 STATUS_SUCCESS。
要拒绝非强制的卸载操作,微筛选器驱动程序应返回适当的警告或错误 NTSTATUS 值,例如 STATUS_FLT_DO_NOT_DETACH。 有关强制卸载操作的更多信息,请参阅编写 FilterUnloadCallback 例程和 PFLT_FILTER_UNLOAD_CALLBACK 。
如果 FilterUnloadCallback 例程返回警告或错误 NTSTATUS 值,并且卸载操作不是强制的,则不会卸载微筛选器驱动程序。
在其 DriverEntry 例程中,微筛选器驱动程序可以为其需要筛选的每种类型的 I/O 操作注册最多一个预操作回调例程和最多一个后操作回调例程。
与旧版文件系统筛选器驱动程序不同,微筛选器驱动程序可以选择要筛选的 I/O 操作类型。 微筛选器驱动程序可以为给定类型的 I/O 操作注册预操作回调例程,而无需注册后操作回调,反之亦然。 微筛选器驱动程序仅接收那些已为其注册了预操作或后操作回调例程的 I/O 操作。
. 预操作回调例程类似于遗留过滤器驱动程序模型中的调度例程。 当筛选器管理器处理 I/O 操作时,它会调用微筛选器驱动程序实例堆栈中已为此类 I/O 操作注册的每个微筛选器驱动程序的预操作回调例程。 堆栈中最顶层的微过滤器驱动程序(即实例具有最高高度的驱动程序)首先接收操作。 当该微筛选器驱动程序完成对操作的处理时,它会将操作返回给筛选器管理器,然后筛选器管理器将操作传递给下一个最高的微筛选器驱动程序,依此类推。 当微筛选器驱动程序实例堆栈中的所有微筛选器驱动程序都已处理 I/O 操作时(除非微筛选器驱动程序已完成 I/O 操作),筛选器管理器会将操作发送到旧筛选器和文件系统。
操作后回调例程类似于旧过滤器驱动程序模型中的完成例程。 当 I/O 管理器将操作传递给文件系统和已注册该操作的完成例程的遗留过滤器时,I/O 操作的完成处理开始。 在这些完成例程完成之后,过滤管理器执行该操作的完成处理。 然后,筛选器管理器调用微筛选器驱动程序实例堆栈中已为此类 I/O 操作注册了一个微筛选器驱动程序的每个微筛选器驱动程序的 postoper 回调例程。 堆栈中底部的微型过滤器驱动程序(即实例具有最低高度的驱动程序)首先接收操作。 当该微筛选器驱动程序完成对操作的处理时,它将其返回到筛选器管理器,然后筛选器管理器将操作传递给下一个最低的微筛选器驱动程序,依此类推。
为了注册操作前回调例程和操作后回调例程,微筛选器驱动程序在其 DriverEntry 例程中对 FltRegisterFilter 进行一次调用。 对于 FltRegisterFilter 中的注册参数,微筛选器驱动程序将指针传递给 FLT_REGISTRATION 结构。 该结构的OperationRegistration成员包含一个指向FLT_OPERATION_REGISTRATION结构数组的指针,该结构对应于微过滤器驱动程序必须过滤的每种类型的I/O操作。
数组中的每个 FLT_OPERATION_REGISTRATION 结构(最后一个除外)都包含以下信息:
数组中的最后一个元素必须是 {IRP_MJ_OPERATION_END}。
以下代码示例取自 Scanner 示例微型过滤器驱动程序,显示了 FLT_OPERATION_REGISTRATION 结构的数组。 Scanner 示例微型过滤器驱动程序为 IRP_MJ_CREATE 注册预操作和后操作回调例程,并为 IRP_MJ_CLEANUP 和 IRP_MJ_WRITE 操作注册预操作回调例程。
const FLT_OPERATION_REGISTRATION Callbacks[] = {
{IRP_MJ_CREATE,
0,
ScannerPreCreate,
ScannerPostCreate},
{IRP_MJ_CLEANUP,
0,
ScannerPreCleanup,
NULL},
{IRP_MJ_WRITE,
0,
ScannerPreWrite,
NULL},
{IRP_MJ_OPERATION_END}
};
以下列表描述了在文件系统微筛选器驱动程序中筛选特定类型 I/O 操作的几个准则:
文件系统微筛选器驱动程序使用一个或多个预操作回调例程来筛选 I/O 操作。 预操作回调例程类似于旧文件系统过滤器驱动程序中使用的调度例程。
微筛选器驱动程序通过将回调例程的入口点存储在 FLT_REGISTRATION 结构的 OperationRegistration 成员中,为特定类型的 I/O 操作注册预操作回调例程,微筛选器驱动程序将微筛选器驱动程序作为参数传递给其 DriverEntry 例程中的 FltRegisterFilter。
微筛选器驱动程序仅接收它们已为其注册了预操作或后操作回调例程的那些类型的 I/O 操作。 微筛选器驱动程序可以为给定类型的 I/O 操作注册 preoper 回调例程,而无需注册 postoper 回调例程,反之亦然。
每个预操作回调例程定义如下:
typedef FLT_PREOP_CALLBACK_STATUS
(*PFLT_PRE_OPERATION_CALLBACK) (
IN OUT PFLT_CALLBACK_DATA Data,
IN PCFLT_RELATED_OBJECTS FltObjects,
OUT PVOID *CompletionContext
);
与调度例程一样,预操作回调例程可以在 IRQL = PASSIVE_LEVEL 或 IRQL = APC_LEVEL 处调用。 通常,它在发起 I/O 请求的线程上下文中以 IRQL = PASSIVE_LEVEL 调用。 对于快速 I/O 和文件系统过滤器 (FsFilter) 操作,始终在 IRQL = PASSIVE_LEVEL 处调用预操作回调例程。 但是,对于基于 IRP 的操作,如果高级筛选器或微筛选器驱动程序挂起该操作以供工作线程处理,则可以在系统工作线程的上下文中调用微筛选器驱动程序的预操作回调例程。
当筛选器管理器为给定的 I/O 操作调用微筛选器驱动程序的预操作回调例程时,微筛选器驱动程序会临时控制 I/O 操作。 微过滤器驱动程序保留此控制权,直到执行以下操作之一:
当微筛选器驱动程序的预操作回调例程或工作例程将 I/O 操作返回到筛选器管理器时,筛选器管理器会将该操作发送到微筛选器驱动程序实例堆栈中当前微筛选器驱动程序下方的微筛选器驱动程序以及旧版筛选器和文件系统 进一步处理。
微筛选器驱动程序的预操作回调例程通过返回以下状态值之一将 I/O 操作返回到筛选器管理器以进行进一步处理:
注意 虽然 FLT_PREOP_SYNCHRONIZE 应该仅针对基于 IRP 的 I/O 操作返回,但您可以为其他操作类型返回此状态值。 如果返回的 I/O 操作不是基于 IRP 的 I/O 操作,则过滤器管理器会将此返回值视为 FLT_PREOP_SUCCESS_WITH_CALLBACK。
或者,在操作前回调例程中被暂停的操作的工作例程,在调用 FltCompletePendedPreOperation 恢复暂停的 I/O 操作的处理时,通过在 CallbackStatus 参数中传递前面的一个状态值,将 I/O 操作返回给过滤器管理器。
如果微型过滤器驱动程序的操作前回调例程返回 FLT_PREOP_SUCCESS_WITH_CALLBACK,则过滤器管理器会在 I/O 完成期间调用微型过滤器驱动程序的操作后回调例程。
注意 如果微型滤波器驱动程序的操作前回调例程返回 FLT_PREOP_SUCCESS_WITH_CALLBACK,但微型滤波器驱动程序没有为该操作注册操作后回调例程,则系统会在 "检查构建 "时断言。
如果微型过滤器驱动程序的操作前回调例程返回 FLT_PREOP_SUCCESS_WITH_CALLBACK,则可在其 CompletionContext 输出参数中返回一个非空值。该参数是一个可选的上下文指针,将传递给相应的操作后回调例程。操作后回调例程在其 CompletionContext 输入参数中接收该指针。
所有类型的 I/O 操作都可以返回 FLT_PREOP_SUCCESS_WITH_CALLBACK 状态值。
如果微型过滤器驱动程序的操作前回调例程返回 FLT_PREOP_SUCCESS_NO_CALLBACK,则过滤器管理器不会在 I/O 完成期间调用微型过滤器驱动程序的操作后回调例程(如果存在)。
如果微型过滤器驱动程序的操作前回调例程返回 FLT_PREOP_SUCCESS_NO_CALLBACK,则其 CompletionContext 输出参数必须返回 NULL。
所有类型的 I/O 操作都可以返回 FLT_PREOP_SUCCESS_NO_CALLBACK 状态值。
如果微型过滤器驱动程序的操作前回调例程通过返回 FLT_PREOP_SYNCHRONIZE 来同步 I/O 操作,则过滤器管理器会在 I/O 完成期间调用微型过滤器驱动程序的操作后回调例程。
过滤器管理器会在与操作前回调相同的线程上下文中调用微型过滤器驱动程序的操作后回调例程,IRQL 为 <= APC_LEVEL. (Note that this thread context is not necessarily the context of the originating thread.)
注意 如果微型过滤器驱动程序的操作前回调例程返回 FLT_PREOP_SYNCHRONIZE,但微型过滤器驱动程序没有为该操作注册操作后回调例程,则系统在检查构建时断言。
如果微型过滤器驱动程序的预操作回调例程返回 FLT_PREOP_SYNCHRONIZE,则可在其 CompletionContext 输出参数中返回一个非空值。该参数是一个可选的上下文指针,将传递给相应的操作后回调例程。操作后回调例程在其 CompletionContext 输入参数中接收该指针。
微型过滤器驱动程序的操作前回调例程应仅为基于 IRP 的 I/O 操作返回 FLT_PREOP_SYNCHRONIZE。不过,其他操作类型也可以返回该状态值。如果返回的 I/O 操作不是基于 IRP 的 I/O 操作,则过滤器管理器会将该返回值视为 FLT_PREOP_SUCCESS_WITH_CALLBACK。要确定一个操作是否是基于 IRP 的 I/O 操作,请使用 FLT_IS_IRP_OPERATION 宏。
对于创建操作,微型过滤器驱动程序不应返回 FLT_PREOP_SYNCHRONIZE,因为这些操作已由过滤器管理器同步。如果 Minifilter 驱动程序已为 IRP_MJ_CREATE 操作注册了操作前和操作后回调例程,则会在 IRQL = PASSIVE_LEVEL 处调用创建后回调例程,其线程上下文与创建前回调例程相同。
对于创建操作,微型过滤器驱动程序不应返回 FLT_PREOP_SYNCHRONIZE,因为这些操作已由过滤器管理器同步。如果 Minifilter 驱动程序已为 IRP_MJ_CREATE 操作注册了操作前和操作后回调例程,则会在 IRQL = PASSIVE_LEVEL 处调用创建后回调例程,其线程上下文与创建前回调例程相同。
以下类型的 I/O 操作无法同步:
对于任何这些操作都无法返回 FLT_PREOP_SYNCHRONIZE。
完成 I/O 操作意味着停止该操作的处理,为其分配最终的 NTSTATUS 值,并将其返回到过滤器管理器。
当微过滤器驱动程序完成 I/O 操作时,过滤器管理器将执行以下操作:
微过滤器驱动程序的预操作回调例程通过执行以下步骤完成 I/O 操作:
完成 I/O 操作的预操作回调例程无法设置非 NULL 完成上下文(在 CompletionContext 输出参数中)。
微过滤器驱动程序还可以通过执行以下步骤来完成工作例程中先前挂起的 I/O 操作的操作:
完成 I/O 操作时,微筛选器驱动程序必须将回调数据结构的 IoStatus.Status 字段设置为该操作的最终 NTSTATUS 值,但此 NTSTATUS 值不能是 STATUS_PENDING 或 STATUS_FLT_DISALLOW_FAST_IO。 对于清理或关闭操作,该字段必须为 STATUS_SUCCESS。 这些操作无法使用任何其他 NTSTATUS 值来完成。
完成 I/O 操作通常称为操作成功或失败,具体取决于 NTSTATUS 值:
NTSTATUS 值在 ntstatus.h 中定义。 这些值分为四类:成功、信息、警告和错误。
在某些情况下,微筛选器驱动程序可能会选择禁止快速 I/O 操作而不是完成它。 禁止快速 I/O 操作会阻止快速 I/O 路径用于该操作。
与完成 I/O 操作一样,不允许快速 I/O 操作意味着停止对其进行处理并将其返回到过滤器管理器。 然而,禁止快速 I/O 操作与完成它是不同的。 如果微过滤器驱动程序不允许 I/O 管理器发出的快速 I/O 操作,则 I/O 管理器可能会重新发出相同的操作作为等效的基于 IRP 的操作。
当微筛选器驱动程序的预操作回调例程不允许快速 I/O 操作时,筛选器管理器将执行以下操作:
微筛选器驱动程序通过从操作的预操作回调例程返回 FLT_PREOP_DISALLOW_FASTIO 来禁止快速 I/O 操作。
预操作回调例程不应设置回调数据结构的 IoStatus.Status 字段,因为过滤器管理器会自动将此字段设置为 STATUS_FLT_DISALLOW_FAST_IO。
FLT_PREOP_DISALLOW_FASTIO 只能针对快速 I/O 操作返回。 要确定操作是否是快速 I/O 操作,请参阅 FLT_IS_FASTIO_OPERATION 。
对于 IRP_MJ_SHUTDOWN、IRP_MJ_VOLUME_MOUNT 或 IRP_MJ_VOLUME_DISMOUNT 操作,微筛选器驱动程序无法返回 FLT_PREOP_DISALLOW_FASTIO。
微筛选器驱动程序的预操作回调例程可以通过将操作发布到系统工作队列并返回 FLT_PREOP_PENDING 来挂起 I/O 操作。 返回此状态值指示微筛选器驱动程序保留对 I/O 操作的控制,直到它调用 FltCompletePendingPreOperation 来恢复 I/O 操作的处理。
微筛选器驱动程序的预操作回调例程通过执行以下步骤来挂起 I/O 操作:
必须挂起所有(或大多数)传入 I/O 操作的微筛选器驱动程序不应使用 FltQueueDeferredIoWorkItem 等例程来挂起操作,因为调用此例程可能会导致系统工作队列被淹没。 相反,这样的微过滤器驱动程序应该使用取消安全队列。 有关使用取消安全队列的更多信息,请参阅 FltCbdqInitialize 。
请注意,如果满足以下任一条件,对 FltQueueDeferredIoWorkItem 的调用将会失败:
如果微筛选器驱动程序的预操作回调例程返回 FLT_PREOP_PENDING,则它必须在 CompletionContext 输出参数中返回 NULL。
微筛选器驱动程序只能针对基于 IRP 的 I/O 操作返回 FLT_PREOP_PENDING。 要确定操作是否是基于 IRP 的 I/O 操作,请使用 FLT_IS_IRP_OPERATION 宏。
使 I/O 操作出列并处理的工作例程必须调用 FltCompletePishedPreOperation 来恢复操作的处理。
文件系统微筛选器驱动程序使用一个或多个操作后回调例程来筛选 I/O 操作。
操作后回调例程类似于旧文件系统过滤器驱动程序中使用的完成例程。
微筛选器驱动程序为特定类型的 I/O 操作注册后操作回调例程,其方式与注册预操作回调例程相同,即通过将回调例程的入口点存储在微筛选器驱动程序的 FLT_REGISTRATION 结构的 OperationRegistration 成员中。 作为参数传递给其 DriverEntry 例程中的 FltRegisterFilter。
微筛选器驱动程序仅接收它们已为其注册了预操作或后操作回调例程的那些类型的 I/O 操作。 微筛选器驱动程序可以为给定类型的 I/O 操作注册预操作回调例程,而无需注册后操作回调,反之亦然。
每个操作后回调例程定义如下:
typedef FLT_POSTOP_CALLBACK_STATUS
(*PFLT_POST_OPERATION_CALLBACK) (
IN OUT PFLT_CALLBACK_DATA Data,
IN PCFLT_RELATED_OBJECTS FltObjects,
IN PVOID CompletionContext,
IN FLT_POST_OPERATION_FLAGS Flags
);
与完成例程一样,操作后回调例程在 IRQL 处调用 <= DISPATCH_LEVEL, in an arbitrary thread context.
由于可以在 IRQL = DISPATCH_LEVEL 上调用它,因此操作后回调例程无法调用必须在较低 IRQL 上调用的内核模式例程,例如 FltLockUserBuffer 或 RtlCompareUnicodeString 。 出于同样的原因,操作后回调例程中使用的任何数据结构都必须从非分页池中分配。
以下情况是上述规则的几种例外情况:
当筛选器管理器针对给定 I/O 操作调用微筛选器驱动程序的 postoper 回调例程时,微筛选器驱动程序会临时控制 I/O 操作。 微过滤器驱动程序保留此控制权,直到执行以下操作之一:
当底层文件系统、旧筛选器或微筛选器驱动程序实例堆栈中处于较低高度的另一个微筛选器驱动程序完成 I/O 操作时,将调用微筛选器驱动程序的操作后回调例程。
此外,当微筛选器驱动程序实例被拆除时,筛选器管理器会“排出”该实例已收到 preoper 回调并正在等待 postoperated 回调的所有 I/O 操作。 在这种情况下,即使 I/O 操作尚未完成,筛选器管理器也会调用微筛选器驱动程序的 post操作回调例程,并在 Flags 输入参数中设置 FLTFL_POST_OPERATION_DRAINING 标志。
当设置 FLTFL_POST_OPERATION_DRAINING 标志时,微过滤器驱动程序不得执行正常的完成处理。 相反,它应该只执行必要的清理,例如释放微筛选器驱动程序在其预操作回调例程中为其 CompletionContext 参数分配的内存,并返回 FLT_POSTOP_FINISHED_PROCESSING。
如编写操作后回调例程中所述,基于 IRP 的 I/O 操作的操作后回调例程可以在 IRQL = DISPATCH_LEVEL 处调用,除非微筛选器驱动程序的操作前回调例程通过返回 FLT_PREOP_SYNCHRONIZE 来同步该操作,或者该操作是创建操作, 这本质上是同步的。 (有关此返回值的更多信息,请参阅返回 FLT_PREOP_SYNCHRONIZE。)
但是,对于尚未同步的基于 IRP 的 I/O 操作,微筛选器驱动程序可以使用两种技术来确保在 IRQL 上执行完成处理 <= APC_LEVEL.
第一种技术是让操作后回调例程挂起 I/O 操作,直到可以在 IRQL 执行完成处理为止 <= APC_LEVEL. This technique is described in Pending an I/O Operation in a Postoperation Callback Routine.
第二种技术是微筛选器驱动程序的 postoper 回调例程调用 FltDoCompletionProcessingWhenSafe 。 仅当当前 IRQL >= DISPATCH_LEVEL 时,FltDoCompletionProcessingWhenSafe 才会挂起 I/O 操作。 否则,此例程立即执行微筛选器驱动程序的 SafePostCallback 例程。 FltDoCompletionProcessingWhenSafe 中描述了此技术。
微过滤器驱动程序的操作后回调例程可以通过执行以下步骤来挂起 I/O 操作:
请注意,如果满足以下任一条件,对 FltQueueDeferredIoWorkItem 的调用将会失败:
微过滤器驱动程序必须准备好处理此故障。 如果您的微筛选器驱动程序无法处理此类故障,则应考虑使用返回 FLT_PREOP_SYNCHRONIZE 中描述的技术,而不是挂起 I/O 操作。
在微筛选器驱动程序的 postoper 回调例程返回 FLT_POSTOP_MORE_PROCESSING_REQUIRED 后,筛选器管理器将不会对 I/O 操作执行任何进一步的完成处理,直到微筛选器驱动程序的工作例程调用 FltCompletePendingPostOperation 将操作的控制权返回给筛选器管理器。 在这种情况下,即使工作例程在操作的回调数据结构的 IoStatus.Status 字段中设置失败 NTSTATUS 值,过滤器管理器也不会执行任何进一步的处理。
使 I/O 操作出列并执行完成处理的工作例程必须调用 FltCompletePishedPostOperation 将操作的控制权返回给过滤器管理器。
微筛选器驱动程序的操作后回调例程可能会使成功的 I/O 操作失败,但仅仅使 I/O 操作失败并不会撤消操作的效果。 微过滤器驱动程序负责执行撤消操作所需的任何处理。
例如,微筛选器驱动程序的创建后回调例程可能会通过执行以下步骤使成功的 IRP_MJ_CREATE 操作失败:
将回调数据结构的 IoStatus.Status 字段设置为操作的最终 NTSTATUS 值时,微筛选器驱动程序必须指定有效的错误 NTSTATUS 值。 请注意,微过滤器驱动程序无法指定 STATUS_FLT_DISALLOW_FAST_IO; 只有过滤器管理器可以使用此 NTSTATUS 值。
FltCancelFileOpen 的调用者必须在 IRQL 下运行 <= APC_LEVEL. However, a minifilter driver can safely call this routine from a post-create callback routine, because, for IRP_MJ_CREATE operations, the postoperation callback routine is called at IRQL = PASSIVE_LEVEL, in the context of the thread that originated the create operation.
微过滤器驱动程序可以修改 I/O 操作的参数。 例如,微过滤器驱动程序的预操作回调例程可以通过更改操作的目标实例将 I/O 操作重定向到不同的卷。 新的目标实例必须是另一个卷上同一海拔高度的同一微筛选器驱动程序的实例。
I/O 操作的参数可在操作的回调数据 ( FLT_CALLBACK_DATA ) 结构和 I/O 参数块 ( FLT_IO_PARAMETER_BLOCK ) 结构中找到。 微筛选器驱动程序的 preoper 回调例程和 postoper 回调例程在 Data 输入参数中接收指向操作的回调数据结构的指针。 回调数据结构的 Iopb 成员是指向包含操作参数的 I/O 参数块结构的指针。
如果微筛选器驱动程序的预操作回调例程修改了 I/O 操作的参数,则微筛选器驱动程序实例堆栈中该微筛选器驱动程序下方的所有微筛选器驱动程序都将在其预操作和后操作回调例程中接收修改后的参数。
当前微筛选器驱动程序的操作后回调例程或微筛选器驱动程序实例堆栈中该微筛选器驱动程序之上的任何微筛选器驱动程序都不会接收修改后的参数。 在所有情况下,微筛选器驱动程序的预操作和后操作回调例程都会接收给定 I/O 操作的相同输入参数值。
修改 I/O 操作的参数后,预操作或后操作回调例程必须通过调用 FltSetCallbackDataDirty 来指示它已完成此操作,除非它更改了回调数据结构的 IoStatus 字段的内容。 否则,过滤器管理器将忽略对参数值的任何更改。 FltSetCallbackDataDirty 在 I/O 操作的回调数据结构中设置 FLTFL_CALLBACK_DATA_DIRTY 标志。 Minifilter 驱动程序可以通过调用 FltIsCallbackDataDirty 来测试此标志,或通过调用 FltClearCallbackDataDirty 来清除它。
如果微筛选器驱动程序的预操作回调例程修改了 I/O 操作的参数,则微筛选器驱动程序实例堆栈中该微筛选器驱动程序下方的所有微筛选器驱动程序都将在其预操作和后操作回调例程的 Data 和 FltObjects 输入参数中接收修改后的参数。 (微筛选器驱动程序无法直接修改 FltObjects 参数指向的 FLT_RELATED_OBJECTS 结构的内容。但是,如果微筛选器驱动程序修改 I/O 操作的目标实例或目标文件对象,则筛选器管理器会修改 传递给较低微过滤器驱动程序的 FLT_RELATED_OBJECTS 结构的相应 Instance 或 FileObject 成员。)
尽管微筛选器驱动程序的预操作回调例程所做的任何参数更改都不会被微筛选器驱动程序自己的后操作回调例程接收,但预操作回调例程能够将有关已更改参数的信息传递给微筛选器驱动程序自己的后操作回调例程。 如果预操作回调例程通过返回 FLT_PREOP_SUCCESS_WITH_CALLBACK 或 FLT_PREOP_SYNCHRONIZE 将 I/O 操作传递到堆栈中,它可以将有关更改的参数值的信息存储到 CompletionContext 输出参数指向的微过滤器驱动程序定义的结构中。 过滤器管理器将 CompletionContext 输入参数中的结构指针传递给操作后回调例程。