PNP管理器事件
2024-04-03
20
0
当设备管理器有动作时,使用PiInsertEventInQueue创建一个相关的事件动作,并挂入相应全局动作队列中,然后启用WorkItem来执行该动作。
事件动作定义为:
typedef struct _PNP_DEVICE_EVENT_ENTRY {
LIST_ENTRY ListEntry;
ULONG Argument;
PKEVENT CallerEvent;
PDEVICE_CHANGE_COMPLETE_CALLBACK Callback;
PVOID Context;
PPNP_VETO_TYPE VetoType;
PUNICODE_STRING VetoName;
PLUGPLAY_EVENT_BLOCK Data;
} PNP_DEVICE_EVENT_ENTRY, *PPNP_DEVICE_EVENT_ENTRY;
这些事件主要有以下几种:
- PpSetTargetDeviceRemove
- PpSetDeviceClassChange
- PpSetCustomTargetEvent
- PpSetDeviceRemovalSafe
- PpSetHwProfileChangeEvent
- PpSetBlockedDriverEvent
- PpSetPowerEvent
- PpSetPowerVetoEvent
- PpSetPlugPlayEvent
- PpSynchronizeDeviceEventQueue
PpSetDeviceRemovalSafe
其中PpSetDeviceRemovalSafe是专门用于处理设备移除的:
其初始化过程可如:
NTSTATUS
PpSetDeviceRemovalSafe(
IN PDEVICE_OBJECT DeviceObject,
IN PKEVENT SyncEvent OPTIONAL,
OUT PULONG Result OPTIONAL
)
{
if (PpPnpShuttingDown) {
return STATUS_TOO_LATE;
}
//
// Reference the device object so it can't go away until after we're
// done with notification.
//
ObReferenceObject(DeviceObject);
deviceNode = (PDEVICE_NODE)DeviceObject->DeviceObjectExtension->DeviceNode;
ASSERT(deviceNode);
//
// Calculate the size of the PLUGPLAY_EVENT_BLOCK, this is the size that
// we record in the TotalSize field later (the length doesn't count the
// terminating null but we're already counting the first index into the
// DeviceId field so it works out. Add one more for double-null term.
//
dataSize = sizeof(PLUGPLAY_EVENT_BLOCK);
dataSize += deviceNode->InstancePath.Length + sizeof(WCHAR);
totalSize = FIELD_OFFSET(PNP_DEVICE_EVENT_ENTRY, Data) + dataSize;
deviceEvent = ExAllocatePoolWithTag(PagedPool, totalSize, PNP_DEVICE_EVENT_ENTRY_TAG);
if (deviceEvent == NULL) {
ObDereferenceObject(DeviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory((PVOID)deviceEvent, totalSize);
deviceEvent->CallerEvent = SyncEvent;
deviceEvent->Argument = 0;
deviceEvent->VetoType = NULL;
deviceEvent->VetoName = NULL;
deviceEvent->Data.EventGuid = GUID_DEVICE_SAFE_REMOVAL;
deviceEvent->Data.EventCategory = TargetDeviceChangeEvent;
deviceEvent->Data.Result = Result;
deviceEvent->Data.Flags = 0;
deviceEvent->Data.TotalSize = dataSize;
deviceEvent->Data.DeviceObject = (PVOID)DeviceObject;
if (deviceNode->InstancePath.Length != 0) {
RtlCopyMemory((PVOID)deviceEvent->Data.u.TargetDevice.DeviceIds,
(PVOID)deviceNode->InstancePath.Buffer,
deviceNode->InstancePath.Length);
}
i = deviceNode->InstancePath.Length/sizeof(WCHAR);
deviceEvent->Data.u.TargetDevice.DeviceIds[i] = L'\0';
status = PiInsertEventInQueue(deviceEvent);
return status;
}
该事件主要分为以下几个层次:
- CallerEvent:表示该事件应该执行的方式。
- EventCategory:表示事件的大体分类,主要为:
- HardwareProfileChangeEvent
- TargetDeviceChangeEvent
- DeviceClassChangeEvent
- CustomDeviceEvent
- DeviceInstallEvent
- DeviceArrivalEvent
- EventGuid则为事件的具体标识:
struct { CONST GUID *Guid; PCHAR Name; } EventGuidTable[] = { { &GUID_HWPROFILE_QUERY_CHANGE, "GUID_HWPROFILE_QUERY_CHANGE" }, { &GUID_HWPROFILE_CHANGE_CANCELLED, "GUID_HWPROFILE_CHANGE_CANCELLED" }, { &GUID_HWPROFILE_CHANGE_COMPLETE, "GUID_HWPROFILE_CHANGE_COMPLETE" }, { &GUID_DEVICE_INTERFACE_ARRIVAL, "GUID_DEVICE_INTERFACE_ARRIVAL" }, { &GUID_DEVICE_INTERFACE_REMOVAL, "GUID_DEVICE_INTERFACE_REMOVAL" }, { &GUID_TARGET_DEVICE_QUERY_REMOVE, "GUID_TARGET_DEVICE_QUERY_REMOVE" }, { &GUID_TARGET_DEVICE_REMOVE_CANCELLED, "GUID_TARGET_DEVICE_REMOVE_CANCELLED" }, { &GUID_TARGET_DEVICE_REMOVE_COMPLETE, "GUID_TARGET_DEVICE_REMOVE_COMPLETE" }, { &GUID_PNP_CUSTOM_NOTIFICATION, "GUID_PNP_CUSTOM_NOTIFICATION" }, { &GUID_DEVICE_ARRIVAL, "GUID_DEVICE_ARRIVAL" }, { &GUID_DEVICE_ENUMERATED, "GUID_DEVICE_ENUMERATED" }, { &GUID_DEVICE_ENUMERATE_REQUEST, "GUID_DEVICE_ENUMERATE_REQUEST" }, { &GUID_DEVICE_START_REQUEST, "GUID_DEVICE_START_REQUEST" }, { &GUID_DEVICE_REMOVE_PENDING, "GUID_DEVICE_REMOVE_PENDING" }, { &GUID_DEVICE_QUERY_AND_REMOVE, "GUID_DEVICE_QUERY_AND_REMOVE" }, { &GUID_DEVICE_EJECT, "GUID_DEVICE_EJECT" }, { &GUID_DEVICE_NOOP, "GUID_DEVICE_NOOP" }, { &GUID_DEVICE_SURPRISE_REMOVAL, "GUID_DEVICE_SURPRISE_REMOVAL" }, { &GUID_DEVICE_SAFE_REMOVAL, "GUID_DEVICE_SAFE_REMOVAL" }, { &GUID_DEVICE_EJECT_VETOED, "GUID_DEVICE_EJECT_VETOED" }, { &GUID_DEVICE_REMOVAL_VETOED, "GUID_DEVICE_REMOVAL_VETOED" }, }; #define EVENT_GUID_TABLE_SIZE (sizeof(EventGuidTable) / sizeof(EventGuidTable[0]))