自拖管IO
2026-06-17
3
0
自拖管IO主要是一些电源的回调
typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS {
//
// Size of this structure in bytes
//
ULONG Size;
PFN_WDF_DEVICE_D0_ENTRY EvtDeviceD0Entry;
PFN_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED EvtDeviceD0EntryPostInterruptsEnabled;
PFN_WDF_DEVICE_D0_EXIT EvtDeviceD0Exit;
PFN_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED EvtDeviceD0ExitPreInterruptsDisabled;
PFN_WDF_DEVICE_PREPARE_HARDWARE EvtDevicePrepareHardware;
PFN_WDF_DEVICE_RELEASE_HARDWARE EvtDeviceReleaseHardware;
//自拖管IO的回调
PFN_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP EvtDeviceSelfManagedIoCleanup;
PFN_WDF_DEVICE_SELF_MANAGED_IO_FLUSH EvtDeviceSelfManagedIoFlush;
PFN_WDF_DEVICE_SELF_MANAGED_IO_INIT EvtDeviceSelfManagedIoInit;
PFN_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND EvtDeviceSelfManagedIoSuspend;
PFN_WDF_DEVICE_SELF_MANAGED_IO_RESTART EvtDeviceSelfManagedIoRestart;
PFN_WDF_DEVICE_SURPRISE_REMOVAL EvtDeviceSurpriseRemoval;
PFN_WDF_DEVICE_QUERY_REMOVE EvtDeviceQueryRemove;
PFN_WDF_DEVICE_QUERY_STOP EvtDeviceQueryStop;
PFN_WDF_DEVICE_USAGE_NOTIFICATION EvtDeviceUsageNotification;
PFN_WDF_DEVICE_RELATIONS_QUERY EvtDeviceRelationsQuery;
PFN_WDF_DEVICE_USAGE_NOTIFICATION_EX EvtDeviceUsageNotificationEx;
} WDF_PNPPOWER_EVENT_CALLBACKS, *PWDF_PNPPOWER_EVENT_CALLBACKS;
自拖管IO是对电源状态管理变化时相对应的调用,这组回调函数正是 WDF 框架为了让你能优雅地管理“自托管 I/O”与电源状态之间的同步而专门设计的。它们精确地映射到了设备电源状态(D状态)变化的关键节点上。
可以把它们理解为 “自托管 I/O 的电源状态机”。框架会在设备电源状态转换时,自动调用对应的回调,让你有机会暂停、重启或清理这些后台活动。
调用时机
设备插入 / 系统启动
↓
[ 第一阶段:设备启动 ]
↓
EvtDevicePrepareHardware (分配硬件资源)
↓
EvtDeviceD0Entry (设备进入 D0 工作状态)
↓
EvtDeviceSelfManagedIoInit ★ 启动你的后台活动 (定时器/线程)
↓
设备正常运行 (自托管 I/O 活动进行中)
↓
[ 第二阶段:设备进入睡眠 (S3) ]
↓
EvtDeviceSelfManagedIoSuspend ★ 暂停你的后台活动
↓
EvtDeviceD0Exit (设备离开 D0,进入低功耗状态)
↓
[ 系统进入睡眠... ]
↓
[ 第三阶段:设备从睡眠唤醒 ]
↓
EvtDeviceD0Entry (设备回到 D0 工作状态)
↓
EvtDeviceSelfManagedIoRestart ★ 重启你的后台活动
↓
设备正常运行
↓
[ 第四阶段:设备被移除 (物理拔出 / 禁用) ]
↓
EvtDeviceSelfManagedIoSuspend ★ 暂停活动 (为移除做准备)
↓
EvtDeviceSelfManagedIoFlush ★ 清空所有待处理的操作
↓
EvtDeviceD0Exit (设备进入 D0 冷移除或低功耗状态)
↓
EvtDeviceReleaseHardware (释放硬件资源)
↓
EvtDeviceSelfManagedIoCleanup ★ 释放所有自托管 I/O 资源 (最后的清理)
| 回调函数 | 调用时机 (电源状态变化) | 对应的 PnP/电源事件 | 你通常在这里做什么? |
|---|---|---|---|
EvtDeviceSelfManagedIoInit |
设备首次从 D0(工作状态)启动时。 (只调用一次) | 在 EvtDeviceD0Entry 之后调用。 |
启动所有后台活动。例如:创建并启动定时器、启动后台线程、初始化自托管的 I/O 队列。 |
EvtDeviceSelfManagedIoSuspend |
设备将要离开 D0 状态,进入低功耗状态(D1/D2/D3)之前。 | 在 EvtDeviceD0Exit 之前调用。 |
暂停所有后台活动。例如:停止定时器、挂起后台线程、等待正在进行的 I/O 完成。目的是让设备能安全地进入低功耗状态。 |
EvtDeviceSelfManagedIoRestart |
设备从低功耗状态(D1/D2/D3)回到 D0 状态之后。 | 在 EvtDeviceD0Entry 之后调用。 |
重启被暂停的后台活动。例如:重新启动定时器、恢复后台线程。它恢复的是 Suspend 时暂停的工作。 |
EvtDeviceSelfManagedIoFlush |
设备即将被移除或被重新配置(如 PnP 重新平衡资源)时。 | 在 EvtDeviceSelfManagedIoSuspend 之后,设备移除前调用。 |
清空所有待处理的自托管 I/O。例如:取消所有未完成的内部请求、清空队列。确保设备移除时没有“悬空”的 I/O 操作。 |
EvtDeviceSelfManagedIoCleanup |
设备对象正在被删除时。这是自托管 I/O 生命周期的最后一步。 | 在设备移除流程的最末尾调用。 | 释放所有自托管 I/O 使用的资源。例如:删除定时器对象、等待线程结束。这是最后的“打扫卫生”工作。 |
虚拟驱动或者过滤驱动的使用示例
WDF_PNPPOWER_EVENT_CALLBACKS wdfPnpPowerCallbacks;
WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&wdfPnpPowerCallbacks);
wdfPnpPowerCallbacks.EvtDeviceSelfManagedIoInit = HIDINJECTOR_EvtDeviceSelfManagedIoInit;
wdfPnpPowerCallbacks.EvtDeviceSelfManagedIoCleanup = HIDINJECTOR_EvtDeviceSelfManagedIoCleanup;
WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &wdfPnpPowerCallbacks);
对应函籹
NTSTATUS
HIDINJECTOR_EvtDeviceSelfManagedIoInit(
WDFDEVICE WdfDevice
)
{
PHID_DEVICE_CONTEXT deviceContext;
NTSTATUS status;
PAGED_CODE();
deviceContext = GetHidDeviceContext(WdfDevice);
status = VhfStart(deviceContext->VhfHandle);
if (!NT_SUCCESS(status))
{
// TODO; seach all KDPrint Calls to make sure parameters match format specifiers
KdPrint(("VhfStart failed %d\n", status));
}
return status;
}
VOID
HIDINJECTOR_EvtDeviceSelfManagedIoCleanup(
WDFDEVICE WdfDevice
)
{
PHID_DEVICE_CONTEXT deviceContext;
PAGED_CODE();
deviceContext = GetHidDeviceContext(WdfDevice);
VhfDelete(deviceContext->VhfHandle, TRUE);
return;
}
WDF





