编写操作前回调例程
微筛选器驱动程序使用一个或多个 操作前回调例程 来筛选 I/O 操作。 操作前回调例程 类似于 旧筛选器模型中使用的调度例程。
微筛选器通过将回调例程的入口点存储在 FLT_REGISTRATION 结构的 OperationRegistration 成员中,为特定类型的 I/O 操作注册操作前回调例程。 微筛选器将此成员作为参数传递给 FltMgr,并将其作为其 DriverEntry 例程中的 FltRegisterFilter。
微筛选器仅接收已为其注册了操作前或操作后回调例程的 I/O 操作类型。 微筛选器可以为给定类型的 I/O 操作注册操作前回调例程,而无需注册 操作后回调例程,反之亦然。
每个操作前回调例程的定义如下:
typedef FLT_PREOP_CALLBACK_STATUS
(*PFLT_PRE_OPERATION_CALLBACK) (
IN OUT PFLT_CALLBACK_DATA Data,
IN PCFLT_RELATED_OBJECTS FltObjects,
OUT PVOID *CompletionContext
);
当 FltMgr 为给定的 I/O 操作调用微筛选器的预操作回调例程时,微筛选器会暂时控制 I/O 操作。 微筛选器会保留此控件,直到它:
从其操作前回调例程返回除FLT_PREOP_PENDING以外的状态值。
从已处理之前在其操作前回调例程中插入的操作的工作例程调用 FltCompletePendedPreOperation 。
下表列出了微筛选器操作前回调例程的一些可能的使用方案,并提供了每个方案的实现详细信息和返回值。
使用方案 | 实现 | 返回的值 |
---|---|---|
例程与操作无关,不需要操作的最终状态,或者没有操作后回调。 | 传递 I/O 操作,并告知 FltMgr 在完成后不要调用微筛选器的操作后回调。 | FLT_PREOP_SUCCESS_NO_CALLBACK |
例程需要操作的最终状态。 | 传递操作并告知 FltMgr 调用微筛选器的操作后回调例程。 | FLT_PREOP_SUCCESS_WITH_CALLBACK |
微筛选器必须在将来完成或继续处理此操作。 | 将操作置于挂起状态。 稍后使用 FltCompletePendedPreOperation 完成操作。 返回FLT_PREOP_PENDING的预操作例程与调用 的 FltCompletePendingOperation 之间可能存在可接受的争用。 FltMgr 无需驱动程序输入即可处理此方案。 | FLT_PREOP_PENDING |
操作后处理必须在调用调度例程的同一线程的上下文中进行。 此条件可确保 IRQL 一致,并维护局部变量状态。 | 将操作与操作后同步。 | FLT_PREOP_SYNCHRONIZE |
操作前回调例程需要完成操作。 | 停止处理操作并分配最终 NTSTATUS 值。 | FLT_PREOP_COMPLETE |
IRQL 和操作前回调例程
FltMgr 无法知道微筛选器在其操作前回调 (或任何回调) 中可能执行的操作。 因此,FltMgr 无法知道调用微型端口的操作前回调是否可能导致问题。 (在提升的 IRQL 中可以安全地执行某些操作,以及无法) 的操作。 因此,微筛选器需要知道 IRQL 并对其进行适当处理。 对于需要知道调用它的 IRQL 的情况,微筛选器可以安全且廉价地调用 KeGetCurrentIRQL 。
有关微筛选器的预操作回调例程 IRQL 的以下信息非常有用:
可以在 IRQL = PASSIVE_LEVEL 或 IRQL = APC_LEVEL 调用操作前回调。 大多数操作前回调在发起 I/O 请求的线程上下文中,在 IRQL = PASSIVE_LEVEL 调用。 在 IRQL = APC_LEVEL 只能调用少量操作前回调。
对于基于 IRP 的操作,如果更高的筛选器或微筛选器驱动程序将操作置于工作线程进行处理,则可以在系统工作线程的上下文中调用微筛选器的预操作回调。 操作前回调相当于旧筛选器的调度例程,因此了解 旧筛选器调度例程的 IRQL 和线程上下文 可能很有用。
无法在 IRQL > APC_LEVEL的操作后例程中检索上下文对象。 相反,在操作前例程期间获取上下文对象并将其传递给操作后例程,或在 IRQL <= APC_LEVEL执行操作后处理。 有关上下文的详细信息,请参阅 管理上下文。