Gogs преди 2 седмици
родител
ревизия
a7bdfefd74
променени са 7 файла, в които са добавени 373 реда и са изтрити 105 реда
  1. 104 27
      driver/ClientConnection.cpp
  2. 7 4
      driver/ClientConnection.h
  3. 9 0
      driver/DeviceContext.h
  4. 93 23
      driver/DriverEntry.cpp
  5. 25 7
      driver/QueueCallback.cpp
  6. 130 31
      driver/SerialFilter.cpp
  7. 5 13
      driver/SerialFilter.h

+ 104 - 27
driver/ClientConnection.cpp

@@ -12,7 +12,6 @@ volatile LONG g_diag_evt_device_add_count = 0;
 volatile LONG g_diag_prepare_hardware_count = 0;
 volatile LONG g_diag_register_filter_count = 0;
 volatile LONG g_diag_irp_preprocess_ok = 0;
-volatile LONG g_diag_sddl_ok = 0;
 volatile LONG g_diag_device_create_ok = 0;
 volatile LONG g_diag_last_failure_status = 0;
 
@@ -134,8 +133,8 @@ NTSTATUS ClientConnection::HandleAttachPort(ULONG com_number) {
     if (!ctx) {
         DbgPrint("[CommModifyKit] HandleAttachPort: COM%u NOT in ports_table (count=%u)\n",
                  com_number, ports_count_);
-        DbgPrint("[CommModifyKit] DIAG: EvtDeviceAdd=%ld, IRPpreproc=%ld, SDDL=%ld, DevCreate=%ld, Register=%ld, PrepHW=%ld, LastFail=0x%lX\n",
-                 g_diag_evt_device_add_count, g_diag_irp_preprocess_ok, g_diag_sddl_ok,
+        DbgPrint("[CommModifyKit] DIAG: EvtDeviceAdd=%ld, IRPpreproc=%ld, DevCreate=%ld, Register=%ld, PrepHW=%ld, LastFail=0x%lX\n",
+                 g_diag_evt_device_add_count, g_diag_irp_preprocess_ok,
                  g_diag_device_create_ok, g_diag_register_filter_count, g_diag_prepare_hardware_count,
                  g_diag_last_failure_status);
         // 打印 ports_table_ 里所有已注册的 COM 编号,便于诊断
@@ -196,13 +195,39 @@ NTSTATUS ClientConnection::HandleDetachPort(ULONG com_number) {
     return STATUS_SUCCESS;
 }
 
-NTSTATUS ClientConnection::HandleWritePort(ULONG com_number, PVOID data, ULONG len) {
+NTSTATUS ClientConnection::HandleWritePort(ULONG com_number, PVOID data, ULONG len,
+                                             PULONG bytes_written) {
+    *bytes_written = 0;
+
     PDEVICE_CONTEXT ctx = FindPortContext(com_number);
     if (!ctx || !ctx->LowerDevice) {
         return STATUS_DEVICE_DOES_NOT_EXIST;
     }
 
+    // 获取保存的 FileObject(由 DispatchCreate 捕获)。
+    // 串口驱动(尤其是虚拟串口如 ELTIMA)需要有效的 FileObject 才能正确处理
+    // 写请求——没有 FileObject 时,写 IRP 可能返回 STATUS_SUCCESS 但数据不会
+    // 路由到配对端口的读缓冲,导致其他工具收不到客户端写的数据。
+    PFILE_OBJECT fo = nullptr;
+    KIRQL old_irql;
+    KeAcquireSpinLock(&ctx->FileObjectLock, &old_irql);
+    fo = ctx->SavedFileObject;
+    if (fo) {
+        ObReferenceObject(fo);  // 额外引用,防止 DispatchClose 期间被释放
+    }
+    KeReleaseSpinLock(&ctx->FileObjectLock, old_irql);
+
+    DbgPrint("[CommModifyKit] HandleWritePort COM%u len=%u FileObject=%p\n",
+             com_number, len, fo);
+    if (!fo) {
+        DbgPrint("[CommModifyKit] HandleWritePort WARNING: no SavedFileObject for COM%u "
+                 "(no user-mode app has the port open). Write may not be routed correctly.\n",
+                 com_number);
+    }
+
     // 构造同步写 IRP 发送给下层串口设备
+    // IoBuildSynchronousFsdRequest 内部用 MmProbeAndLockPages(KernelMode)
+    // 创建 MDL,对 NonPaged pool 缓冲(METHOD_BUFFERED SystemBuffer)可正常工作
     KEVENT event;
     KeInitializeEvent(&event, NotificationEvent, FALSE);
 
@@ -210,38 +235,75 @@ NTSTATUS ClientConnection::HandleWritePort(ULONG com_number, PVOID data, ULONG l
     PIRP irp = IoBuildSynchronousFsdRequest(
         IRP_MJ_WRITE, ctx->LowerDevice, data, len, nullptr, &event, &io_status);
     if (!irp) {
+        if (fo) ObDereferenceObject(fo);
         return STATUS_INSUFFICIENT_RESOURCES;
     }
 
+    // 关键:将 RequestorMode 改为 UserMode
+    // IoBuildSynchronousFsdRequest 默认设 KernelMode,但 ELTIMA 等虚拟串口驱动
+    // 会检查 RequestorMode——对 KernelMode 写 IRP 只接受写入(返回 SUCCESS)
+    // 但不路由数据到配对端口。改为 UserMode 让虚拟串口驱动正常路由数据。
+    // 缓冲已由 IoBuildSynchronousFsdRequest 用 KernelMode 探测锁定,
+    // MDL 有效,下层驱动通过 MmGetSystemAddressForMdlSafe 访问,不受影响。
+    irp->RequestorMode = UserMode;
+
+    // IoBuildSynchronousFsdRequest 不设置 FileObject,需手动设置
+    if (fo) {
+        PIO_STACK_LOCATION sl = IoGetNextIrpStackLocation(irp);
+        sl->FileObject = fo;
+    }
+
     NTSTATUS status = IoCallDriver(ctx->LowerDevice, irp);
     if (status == STATUS_PENDING) {
         KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, nullptr);
         status = io_status.Status;
     }
 
+    *bytes_written = (ULONG)io_status.Information;
+
+    DbgPrint("[CommModifyKit] HandleWritePort COM%u status=0x%08X written=%u\n",
+             com_number, status, *bytes_written);
+
+    // 释放 FileObject 额外引用
+    if (fo) {
+        ObDereferenceObject(fo);
+    }
+
     // 注:此 IRP 直接发给 LowerDevice,绕过 SerialFilter::DispatchWrite,
-    // 不会触发 OnWriteComplete 捕获。需手动将写入数据 Push 为 OP_WRITE 事件,
-    // 否则监控端看不到注入的写流量(监控数据不完整)
-    if (NT_SUCCESS(status) && ctx->MonitoringEnabled && ctx->RingBuffer) {
-        ULONG written = (ULONG)io_status.Information;
-        if (written > 0 && data) {
-            LONG seq = InterlockedIncrement(&g_sequence_counter);
-            UINT64 timestamp = KeQueryInterruptTime();
-            EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
-            ring->Push((ULONG)seq, timestamp, com_number, COMMKIT_OP_WRITE,
-                        written, data);
-        }
+    // 不会触发 OnWriteComplete 捕获。需手动将写入数据 Push 为 OP_WRITE 事件
+    if (NT_SUCCESS(status) && *bytes_written > 0 && ctx->MonitoringEnabled && ctx->RingBuffer) {
+        LONG seq = InterlockedIncrement(&g_sequence_counter);
+        UINT64 timestamp = KeQueryInterruptTime();
+        EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
+        ring->Push((ULONG)seq, timestamp, com_number, COMMKIT_OP_WRITE,
+                    *bytes_written, data);
     }
 
     return status;
 }
 
-NTSTATUS ClientConnection::HandleReadPort(ULONG com_number, PVOID data, ULONG len) {
+NTSTATUS ClientConnection::HandleReadPort(ULONG com_number, PVOID data, ULONG len,
+                                            PULONG bytes_read) {
+    *bytes_read = 0;
+
     PDEVICE_CONTEXT ctx = FindPortContext(com_number);
     if (!ctx || !ctx->LowerDevice) {
         return STATUS_DEVICE_DOES_NOT_EXIST;
     }
 
+    // 获取保存的 FileObject(与 HandleWritePort 同理)
+    PFILE_OBJECT fo = nullptr;
+    KIRQL old_irql;
+    KeAcquireSpinLock(&ctx->FileObjectLock, &old_irql);
+    fo = ctx->SavedFileObject;
+    if (fo) {
+        ObReferenceObject(fo);
+    }
+    KeReleaseSpinLock(&ctx->FileObjectLock, old_irql);
+
+    DbgPrint("[CommModifyKit] HandleReadPort COM%u len=%u FileObject=%p\n",
+             com_number, len, fo);
+
     // 构造同步读 IRP 发送给下层串口设备
     KEVENT event;
     KeInitializeEvent(&event, NotificationEvent, FALSE);
@@ -250,27 +312,42 @@ NTSTATUS ClientConnection::HandleReadPort(ULONG com_number, PVOID data, ULONG le
     PIRP irp = IoBuildSynchronousFsdRequest(
         IRP_MJ_READ, ctx->LowerDevice, data, len, nullptr, &event, &io_status);
     if (!irp) {
+        if (fo) ObDereferenceObject(fo);
         return STATUS_INSUFFICIENT_RESOURCES;
     }
 
+    // 同 HandleWritePort:改为 UserMode 让虚拟串口驱动正常处理
+    irp->RequestorMode = UserMode;
+
+    // 设置 FileObject(同 HandleWritePort)
+    if (fo) {
+        PIO_STACK_LOCATION sl = IoGetNextIrpStackLocation(irp);
+        sl->FileObject = fo;
+    }
+
     NTSTATUS status = IoCallDriver(ctx->LowerDevice, irp);
     if (status == STATUS_PENDING) {
         KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, nullptr);
         status = io_status.Status;
     }
 
+    *bytes_read = (ULONG)io_status.Information;
+
+    DbgPrint("[CommModifyKit] HandleReadPort COM%u status=0x%08X read=%u\n",
+             com_number, status, *bytes_read);
+
+    if (fo) {
+        ObDereferenceObject(fo);
+    }
+
     // 注:此 IRP 直接发给 LowerDevice,绕过 SerialFilter::DispatchRead,
-    // 不会触发 OnReadComplete 捕获。需手动将读取数据 Push 为 OP_READ 事件,
-    // 否则读取的数据既不返回调用者(METHOD_BUFFERED + info=0)也不进 RingBuffer,完全丢失
-    if (NT_SUCCESS(status) && ctx->MonitoringEnabled && ctx->RingBuffer) {
-        ULONG read_bytes = (ULONG)io_status.Information;
-        if (read_bytes > 0 && data) {
-            LONG seq = InterlockedIncrement(&g_sequence_counter);
-            UINT64 timestamp = KeQueryInterruptTime();
-            EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
-            ring->Push((ULONG)seq, timestamp, com_number, COMMKIT_OP_READ,
-                        read_bytes, data);
-        }
+    // 不会触发 OnReadComplete 捕获。需手动将读取数据 Push 为 OP_READ 事件
+    if (NT_SUCCESS(status) && *bytes_read > 0 && ctx->MonitoringEnabled && ctx->RingBuffer) {
+        LONG seq = InterlockedIncrement(&g_sequence_counter);
+        UINT64 timestamp = KeQueryInterruptTime();
+        EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
+        ring->Push((ULONG)seq, timestamp, com_number, COMMKIT_OP_READ,
+                    *bytes_read, data);
     }
 
     return status;

+ 7 - 4
driver/ClientConnection.h

@@ -31,10 +31,14 @@ public:
     NTSTATUS HandleDetachPort(ULONG com_number);
 
     // WRITE_PORT:向指定串口发数据
-    NTSTATUS HandleWritePort(ULONG com_number, PVOID data, ULONG len);
+    // bytes_written 输出实际写入字节数
+    NTSTATUS HandleWritePort(ULONG com_number, PVOID data, ULONG len,
+                              PULONG bytes_written);
 
-    // READ_PORT:从指定串口读数据(异步,结果通过回调上抛)
-    NTSTATUS HandleReadPort(ULONG com_number, PVOID data, ULONG len);
+    // READ_PORT:从指定串口读数据
+    // bytes_read 输出实际读取字节数
+    NTSTATUS HandleReadPort(ULONG com_number, PVOID data, ULONG len,
+                             PULONG bytes_read);
 
     // READ_EVENTS:批量读取所有启用端口的事件
     // out_buf:用户缓冲;out_size:缓冲字节大小
@@ -91,6 +95,5 @@ extern volatile LONG g_diag_evt_device_add_count;
 extern volatile LONG g_diag_prepare_hardware_count;
 extern volatile LONG g_diag_register_filter_count;
 extern volatile LONG g_diag_irp_preprocess_ok;    // 所有 IRP preprocess 注册成功次数
-extern volatile LONG g_diag_sddl_ok;               // SDDL 赋值成功次数
 extern volatile LONG g_diag_device_create_ok;       // WdfDeviceCreate 成功次数
 extern volatile LONG g_diag_last_failure_status;   // 最后一次失败的 NTSTATUS

+ 9 - 0
driver/DeviceContext.h

@@ -31,6 +31,15 @@ typedef struct _DEVICE_CONTEXT {
     // WDF 设备句柄(包装下层)
     WDFDEVICE            WdfDevice;
 
+    // ====== 注入 I/O 用的 FileObject ======
+    // 串口驱动(尤其是虚拟串口如 ELTIMA)需要有效的 FileObject 才能正确处理
+    // HandleWritePort/HandleReadPort 构造的 IRP。没有 FileObject 时,写 IRP
+    // 可能返回 STATUS_SUCCESS 但数据不会路由到配对端口的读缓冲。
+    // 这里保存最近一次用户态打开该串口时的 WDM FILE_OBJECT(已 ObReference),
+    // 在 EvtDeviceFileCreate 中捕获,EvtFileClose 中释放。
+    PFILE_OBJECT        SavedFileObject;
+    KSPIN_LOCK          FileObjectLock;
+
 } DEVICE_CONTEXT, *PDEVICE_CONTEXT;
 
 // WDF_DECLARE_CONTEXT_TYPE_WITH_NAME 必须在全局作用域

+ 93 - 23
driver/DriverEntry.cpp

@@ -10,7 +10,9 @@
 #include "DeviceContext.h"
 #include "QueueCallback.h"
 #include "ClientConnection.h"
-#include "SerialFilter.h"
+#include "SerialFilter.h"   // g_sequence_counter
+#include "EventRingBuffer.h" // EventRingBuffer
+#include "../common/CommKitEvents.h"  // COMMKIT_OP_OPEN / OP_CLOSE
 
 extern "C" {
 
@@ -67,56 +69,68 @@ extern "C" NTSTATUS EvtDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT init) {
     UNREFERENCED_PARAMETER(driver);
 
     InterlockedIncrement(&g_diag_evt_device_add_count);
+    DbgPrint("[CommModifyKit] >>> EvtDeviceAdd ENTER (count=%ld)\n", g_diag_evt_device_add_count);
 
     NTSTATUS status;
 
     // 1. 标记为过滤设备
     WdfFdoInitSetFilter(init);
+    DbgPrint("[CommModifyKit] EvtDeviceAdd: WdfFdoInitSetFilter OK\n");
 
     // 2. 注册 PnP 电源回调
     WDF_PNPPOWER_EVENT_CALLBACKS pnp_callbacks;
     WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_callbacks);
     pnp_callbacks.EvtDevicePrepareHardware = EvtDevicePrepareHardware;
     WdfDeviceInitSetPnpPowerEventCallbacks(init, &pnp_callbacks);
+    DbgPrint("[CommModifyKit] EvtDeviceAdd: PnpPower callbacks registered\n");
+
+    // 2.5 不使用 WdfDeviceInitSetFileObjectConfig
+    // -----------------------------------------------
+    // 原因:WdfDeviceInitSetFileObjectConfig 会让 WDF 为每个 CREATE 创建
+    // WDFFILEOBJECT,并在 WdfDeviceWdmDispatchPreprocessedIrp 中强制查找它。
+    // 当 WDFFILEOBJECT 查找失败时(异步 SEND_AND_FORGET 转发时序问题、
+    // 或 FileObject 不匹配),WDF 返回 STATUS_FILE_FORCED_CLOSED (0xC0000182),
+    // 导致其他工具的 READ/WRITE IRP 全部失败。
+    //
+    // 改用 IRP_MJ_CREATE/CLOSE 预处理回调手动追踪文件打开/关闭和捕获 FileObject。
+    // 没有 WdfDeviceInitSetFileObjectConfig,WdfDeviceWdmDispatchPreprocessedIrp
+    // 不再查找 WDFFILEOBJECT,直接转发 IRP 到下层设备。
 
     // 3. 注册 WDM IRP 预处理回调
-    status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
-        init, commkit_driver::SerialFilter::DispatchRead,
-        IRP_MJ_READ, nullptr, 0);
-    if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
-
-    status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
-        init, commkit_driver::SerialFilter::DispatchWrite,
-        IRP_MJ_WRITE, nullptr, 0);
-    if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
-
-    status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
-        init, commkit_driver::SerialFilter::DispatchDeviceControl,
-        IRP_MJ_DEVICE_CONTROL, nullptr, 0);
-    if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
-
     status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
         init, commkit_driver::SerialFilter::DispatchCreate,
         IRP_MJ_CREATE, nullptr, 0);
     if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
+    DbgPrint("[CommModifyKit] EvtDeviceAdd: IRP_MJ_CREATE preprocess registered\n");
 
     status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
         init, commkit_driver::SerialFilter::DispatchClose,
         IRP_MJ_CLOSE, nullptr, 0);
     if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
+    DbgPrint("[CommModifyKit] EvtDeviceAdd: IRP_MJ_CLOSE preprocess registered\n");
 
     status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
-        init, commkit_driver::SerialFilter::DispatchCleanup,
-        IRP_MJ_CLEANUP, nullptr, 0);
+        init, commkit_driver::SerialFilter::DispatchRead,
+        IRP_MJ_READ, nullptr, 0);
     if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
+    DbgPrint("[CommModifyKit] EvtDeviceAdd: IRP_MJ_READ preprocess registered\n");
 
+    status = WdfDeviceInitAssignWdmIrpPreprocessCallback(
+        init, commkit_driver::SerialFilter::DispatchWrite,
+        IRP_MJ_WRITE, nullptr, 0);
+    if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
+    DbgPrint("[CommModifyKit] EvtDeviceAdd: IRP_MJ_WRITE preprocess registered\n");
+
+    // IRP_MJ_CLEANUP / IRP_MJ_DEVICE_CONTROL 不注册预处理回调。
+    // CLEANUP 由 WDF 自动转发(过滤驱动模式)。
+    // DEVICE_CONTROL 由 WDF 自动转发给下层设备,串口 IOCTL(波特率/DCB 等)
+    // 由虚拟串口驱动直接处理。
     InterlockedIncrement(&g_diag_irp_preprocess_ok);
 
     // 4. SDDL: WDF filter device 不支持 WdfDeviceInitAssignSDDLString
     //    它会返回 STATUS_INVALID_SECURITY_DESCR (0xC0000079)
     //    Filter device 会继承下层设备 (serial.sys) 的安全描述符
     //    不需要显式设置 SDDL
-    InterlockedIncrement(&g_diag_sddl_ok);
 
     // 5. 创建 WDF 设备
     WDFDEVICE device;
@@ -124,8 +138,14 @@ extern "C" NTSTATUS EvtDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT init) {
     WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attrs, DEVICE_CONTEXT);
     attrs.EvtCleanupCallback = EvtDeviceContextCleanup;
 
+    DbgPrint("[CommModifyKit] EvtDeviceAdd: calling WdfDeviceCreate...\n");
     status = WdfDeviceCreate(&init, &attrs, &device);
-    if (!NT_SUCCESS(status)) { InterlockedExchange(&g_diag_last_failure_status, status); return status; }
+    if (!NT_SUCCESS(status)) {
+        DbgPrint("[CommModifyKit] EvtDeviceAdd: WdfDeviceCreate FAILED 0x%08X\n", status);
+        InterlockedExchange(&g_diag_last_failure_status, status);
+        return status;
+    }
+    DbgPrint("[CommModifyKit] EvtDeviceAdd: WdfDeviceCreate OK device=%p\n", device);
 
     InterlockedIncrement(&g_diag_device_create_ok);
 
@@ -136,9 +156,25 @@ extern "C" NTSTATUS EvtDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT init) {
     ctx->RingBuffer = nullptr;
     ctx->WdfDevice = device;
     ctx->LowerDevice = WdfDeviceWdmGetAttachedDevice(device);
+    ctx->SavedFileObject = nullptr;
+    KeInitializeSpinLock(&ctx->FileObjectLock);
+
+    DbgPrint("[CommModifyKit] EvtDeviceAdd: ctx initialized, LowerDevice=%p\n", ctx->LowerDevice);
+
+    // 注意:不再设置过滤设备 / 下层设备的 SecurityDescriptor。
+    // 之前直接覆盖 ctx->LowerDevice->SecurityDescriptor 是严重错误:
+    //   1. 下层设备不归本驱动管理(由虚拟串口驱动创建)
+    //   2. 原始 SD 内存被泄漏
+    //   3. 时机错误:EvtDeviceAdd 中下层设备可能未完成初始化
+    //   4. 破坏下层驱动的内部状态,导致 CreateFile 异常失败
+    // 过滤设备是未命名的,其 SD 不参与 CreateFile 的安全检查
+    // (I/O Manager 查的是命名设备即下层 FDO 的 SD)。
+    // 若需放宽非 elevated 进程的访问权限,应通过 INF 文件在设备类
+    // 注册表项 HKLM\...\Control\Class\{Ports GUID}\Security 中设置。
 
     // 7. 注册到全局端口表
     commkit_driver::GetClientConnection().RegisterFilterDevice(device);
+    DbgPrint("[CommModifyKit] EvtDeviceAdd: RegisterFilterDevice done, EvtDeviceAdd COMPLETE\n");
 
     return STATUS_SUCCESS;
 }
@@ -153,6 +189,7 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
     PDEVICE_CONTEXT ctx = DeviceGetContext(device);
 
     InterlockedIncrement(&g_diag_prepare_hardware_count);
+    DbgPrint("[CommModifyKit] EvtDevicePrepareHardware ENTER\n");
 
     // 从 PnP 属性解析 COM 编号
     // 方式:获取 DevicePropertyFriendlyName 或 DevicePropertyDeviceDescription,
@@ -161,6 +198,7 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
     status = WdfDeviceAllocAndQueryProperty(
         device, DevicePropertyFriendlyName, NonPagedPoolNx, 0, &memory);
     if (!NT_SUCCESS(status)) {
+        DbgPrint("[CommModifyKit] PrepareHardware: FriendlyName query failed 0x%08X, trying DeviceDescription\n", status);
         // 尝试 DeviceDescription 作为后备
         status = WdfDeviceAllocAndQueryProperty(
             device, DevicePropertyDeviceDescription, NonPagedPoolNx, 0, &memory);
@@ -170,7 +208,7 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
         PWCHAR name = (PWCHAR)WdfMemoryGetBuffer(memory, nullptr);
         if (name) {
             // 打印 FriendlyName/DeviceDescription 前 40 字符用于诊断
-            DbgPrint("[CommModifyKit] FriendlyName='%ws'\n", name);
+            DbgPrint("[CommModifyKit] PrepareHardware: name='%ws'\n", name);
             // 解析 "COMx" 模式(可能出现在 "COMx (port)" 或 "通信端口 (COMx)" 等格式中)
             ULONG name_len = (ULONG)wcslen(name);
             for (ULONG i = 0; i + 3 <= name_len; i++) {
@@ -186,6 +224,7 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
                         }
                         if (num > 0 && num <= 256) {
                             ctx->ComNumber = num;
+                            DbgPrint("[CommModifyKit] PrepareHardware: parsed COM%u from name\n", num);
                             break;
                         }
                     }
@@ -198,6 +237,7 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
     // 后备方案:FriendlyName/DeviceDescription 均未解析出 COM 编号时,
     // 从 PDO 名称查询 HKLM\HARDWARE\DEVICEMAP\SERIALCOMM 获取 "COMx" 映射
     if (ctx->ComNumber == 0) {
+        DbgPrint("[CommModifyKit] PrepareHardware: trying SERIALCOMM registry fallback\n");
         WDFMEMORY pdo_memory;
         status = WdfDeviceAllocAndQueryProperty(
             device, DevicePropertyPhysicalDeviceObjectName,
@@ -205,6 +245,7 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
         if (NT_SUCCESS(status)) {
             PWCHAR pdo_name = (PWCHAR)WdfMemoryGetBuffer(pdo_memory, nullptr);
             if (pdo_name && pdo_name[0] != L'\0') {
+                DbgPrint("[CommModifyKit] PrepareHardware: PDO name='%ws'\n", pdo_name);
                 UNICODE_STRING key_path;
                 RtlInitUnicodeString(&key_path,
                     L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\SERIALCOMM");
@@ -229,6 +270,7 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
                         if (kv_info->Type == REG_SZ && kv_info->DataLength >= sizeof(WCHAR)) {
                             PWCHAR com_name = (PWCHAR)kv_info->Data;
                             ULONG com_len = kv_info->DataLength / sizeof(WCHAR);
+                            DbgPrint("[CommModifyKit] PrepareHardware: SERIALCOMM value='%ws'\n", com_name);
                             // 解析 "COMx"
                             if (com_len >= 4 &&
                                 (com_name[0] == L'C' || com_name[0] == L'c') &&
@@ -244,11 +286,16 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
                                 }
                                 if (num > 0 && num <= 256) {
                                     ctx->ComNumber = num;
+                                    DbgPrint("[CommModifyKit] PrepareHardware: parsed COM%u from SERIALCOMM\n", num);
                                 }
                             }
                         }
+                    } else {
+                        DbgPrint("[CommModifyKit] PrepareHardware: SERIALCOMM query failed 0x%08X\n", status);
                     }
                     ZwClose(hkey);
+                } else {
+                    DbgPrint("[CommModifyKit] PrepareHardware: ZwOpenKey(SERIALCOMM) failed 0x%08X\n", status);
                 }
             }
             WdfObjectDelete(pdo_memory);
@@ -260,6 +307,7 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
     // 注意:必须传入本设备 PDO,不能传 nullptr 枚举所有设备后用 IoGetDeviceObjectPointer 打开,
     //       因为那会发送 IRP_MJ_CREATE 到正在初始化的设备栈,导致死锁
     if (ctx->ComNumber == 0) {
+        DbgPrint("[CommModifyKit] PrepareHardware: trying GUID_DEVINTERFACE_COMPORT fallback\n");
         PDEVICE_OBJECT currentPdo = WdfDeviceWdmGetPhysicalDevice(device);
         if (currentPdo) {
             PWSTR interfaceList = nullptr;
@@ -272,6 +320,7 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
                 PWCHAR p = interfaceList;
                 while (*p && ctx->ComNumber == 0) {
                     ULONG len = (ULONG)wcslen(p);
+                    DbgPrint("[CommModifyKit] PrepareHardware: interface='%ws'\n", p);
                     // 从符号链接路径解析 COM 编号(如 "\\?\COM12")
                     for (ULONG i = 0; i + 3 <= len; i++) {
                         if ((p[i] == L'C' || p[i] == L'c') &&
@@ -286,6 +335,7 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
                             }
                             if (num > 0 && num <= 256) {
                                 ctx->ComNumber = num;
+                                DbgPrint("[CommModifyKit] PrepareHardware: parsed COM%u from interface\n", num);
                                 break;
                             }
                         }
@@ -293,6 +343,8 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
                     p += len + 1;
                 }
                 ExFreePool(interfaceList);
+            } else {
+                DbgPrint("[CommModifyKit] PrepareHardware: IoGetDeviceInterfaces failed 0x%08X or empty\n", status);
             }
         }
     }
@@ -300,7 +352,7 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
     // 更新端口表中的 COM 编号
     commkit_driver::GetClientConnection().UpdatePortComNumber(device, ctx->ComNumber);
 
-    DbgPrint("[CommModifyKit] EvtDevicePrepareHardware OK, ComNumber=%u\n", ctx->ComNumber);
+    DbgPrint("[CommModifyKit] EvtDevicePrepareHardware COMPLETE, ComNumber=%u\n", ctx->ComNumber);
     return STATUS_SUCCESS;
 }
 
@@ -308,11 +360,29 @@ NTSTATUS EvtDevicePrepareHardware(WDFDEVICE device,
 VOID EvtDeviceContextCleanup(WDFOBJECT object) {
     WDFDEVICE device = (WDFDEVICE)object;
     PDEVICE_CONTEXT ctx = DeviceGetContext(device);
-    if (ctx && ctx->ComNumber != 0) {
+    if (!ctx) return;
+
+    // 释放保存的 FileObject
+    KIRQL old_irql;
+    KeAcquireSpinLock(&ctx->FileObjectLock, &old_irql);
+    PFILE_OBJECT saved = ctx->SavedFileObject;
+    ctx->SavedFileObject = nullptr;
+    KeReleaseSpinLock(&ctx->FileObjectLock, old_irql);
+    if (saved) {
+        ObDereferenceObject(saved);
+    }
+
+    if (ctx->ComNumber != 0) {
         commkit_driver::GetClientConnection().UnregisterFilterDevice(ctx->ComNumber);
     }
 }
 
+// 文件打开/关闭/数据捕获现在通过 IRP_MJ_CREATE/CLOSE/READ/WRITE 预处理回调处理
+// (见 SerialFilter.cpp 中的 DispatchCreate/DispatchClose/DispatchRead/DispatchWrite)。
+// 不再使用 WdfDeviceInitSetFileObjectConfig + EvtDeviceFileCreate/EvtFileClose/EvtFileCleanup,
+// 因为 WdfDeviceInitSetFileObjectConfig 会导致 WdfDeviceWdmDispatchPreprocessedIrp
+// 强制查找 WDFFILEOBJECT,查找失败时返回 STATUS_FILE_FORCED_CLOSED (0xC0000182)。
+
 extern "C" VOID EvtDriverUnload(WDFDRIVER driver) {
     UNREFERENCED_PARAMETER(driver);
     commkit_driver::GetClientConnection().Cleanup();

+ 25 - 7
driver/QueueCallback.cpp

@@ -10,9 +10,10 @@
 
 namespace commkit_driver {
 
-// SDDL: System and Administrators have full access
+// SDDL: System+Admins full access, Authenticated Users+Everyone read/write
+// 控制设备 \\.\CommModifyKit 需要允许非 elevated 进程也能打开
 static const UNICODE_STRING SddlSysAdminFullAccess =
-    RTL_CONSTANT_STRING(L"D:P(A;;GA;;;SY)(A;;GA;;;BA)");
+    RTL_CONSTANT_STRING(L"D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GRGW;;;AU)(A;;GRGW;;;WD)");
 
 // 专用 Parallel 队列句柄:用于 READ_EVENTS 转发
 // WdfDeviceConfigureRequestDispatching 只能按请求类型路由(如 WdfRequestTypeDeviceControl),
@@ -136,13 +137,21 @@ VOID EvtIoDeviceControl(WDFQUEUE queue, WDFREQUEST request,
                                                   (PVOID*)&req, &buf_len);
         if (NT_SUCCESS(status) && req) {
             // 校验 DataLen 不超过实际缓冲区容量,防止越界读取
-            // Data 字段起始偏移 = sizeof(UINT32) * 2 = 8
-            ULONG data_capacity = (buf_len > 8) ? (ULONG)(buf_len - 8) : 0;
+            ULONG header_size = FIELD_OFFSET(COMMKIT_DATA_REQUEST, Data);
+            ULONG data_capacity = (buf_len > header_size)
+                                     ? (ULONG)(buf_len - header_size) : 0;
             if (req->DataLen > data_capacity) {
                 status = STATUS_INVALID_PARAMETER;
             } else {
                 PVOID data = req->Data;
-                status = conn.HandleWritePort(req->ComNumber, data, req->DataLen);
+                ULONG bytes_written = 0;
+                status = conn.HandleWritePort(req->ComNumber, data, req->DataLen,
+                                                &bytes_written);
+                // 更新 DataLen 为实际写入字节数,用户态 DLL 可直接读取
+                req->DataLen = bytes_written;
+                // METHOD_BUFFERED: info = 从 SystemBuffer 拷贝回用户缓冲的字节数
+                // = 头部(ComNumber+DataLen) + 实际数据
+                info = header_size + bytes_written;
             }
         }
         break;
@@ -154,12 +163,21 @@ VOID EvtIoDeviceControl(WDFQUEUE queue, WDFREQUEST request,
         status = WdfRequestRetrieveInputBuffer(request, sizeof(*req),
                                                   (PVOID*)&req, &buf_len);
         if (NT_SUCCESS(status) && req) {
-            ULONG data_capacity = (buf_len > 8) ? (ULONG)(buf_len - 8) : 0;
+            ULONG header_size = FIELD_OFFSET(COMMKIT_DATA_REQUEST, Data);
+            ULONG data_capacity = (buf_len > header_size)
+                                     ? (ULONG)(buf_len - header_size) : 0;
             if (req->DataLen > data_capacity) {
                 status = STATUS_INVALID_PARAMETER;
             } else {
                 PVOID data = req->Data;
-                status = conn.HandleReadPort(req->ComNumber, data, req->DataLen);
+                ULONG bytes_read = 0;
+                status = conn.HandleReadPort(req->ComNumber, data, req->DataLen,
+                                               &bytes_read);
+                // 更新 DataLen 为实际读取字节数,用户态 DLL 可直接读取
+                req->DataLen = bytes_read;
+                // METHOD_BUFFERED: info = 从 SystemBuffer 拷贝回用户缓冲的字节数
+                // = 头部(ComNumber+DataLen) + 实际数据
+                info = header_size + bytes_read;
             }
         }
         break;

+ 130 - 31
driver/SerialFilter.cpp

@@ -96,57 +96,156 @@ NTSTATUS SerialFilter::OnWriteComplete(PDEVICE_OBJECT dev, PIRP irp, PVOID ctx)
     return STATUS_SUCCESS;
 }
 
-NTSTATUS SerialFilter::DispatchRead(WDFDEVICE dev, PIRP irp) {
+NTSTATUS SerialFilter::DispatchCreate(WDFDEVICE dev, PIRP irp) {
     PDEVICE_CONTEXT ctx = DeviceGetContext(dev);
+    ULONG com = ctx ? ctx->ComNumber : 0;
+
+    // 从 IRP 栈位置获取 WDM FileObject,用于 HandleWritePort/HandleReadPort
+    PIO_STACK_LOCATION sl = IoGetCurrentIrpStackLocation(irp);
+    if (ctx && sl && sl->FileObject) {
+        PFILE_OBJECT wdm_fo = sl->FileObject;
+        ObReferenceObject(wdm_fo);
+        KIRQL old_irql;
+        KeAcquireSpinLock(&ctx->FileObjectLock, &old_irql);
+        PFILE_OBJECT old_fo = ctx->SavedFileObject;
+        ctx->SavedFileObject = wdm_fo;
+        KeReleaseSpinLock(&ctx->FileObjectLock, old_irql);
+        if (old_fo) {
+            ObDereferenceObject(old_fo);
+        }
+        DbgPrint("[CommModifyKit] DispatchCreate COM%u: SavedFileObject=%p\n", com, wdm_fo);
+    } else {
+        DbgPrint("[CommModifyKit] DispatchCreate COM%u: no FileObject in IRP\n", com);
+    }
 
+    // OP_OPEN 事件
     if (ctx && ctx->MonitoringEnabled && ctx->RingBuffer) {
-        IoSetCompletionRoutine(irp, OnReadComplete, ctx, TRUE, TRUE, TRUE);
+        EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
+        LONG seq = InterlockedIncrement(&g_sequence_counter);
+        UINT64 timestamp = KeQueryInterruptTime();
+        ring->Push((ULONG)seq, timestamp, com, COMMKIT_OP_OPEN, 0, nullptr);
     }
 
-    return WdfDeviceWdmDispatchPreprocessedIrp(dev, irp);
+    // 转发到下层设备(无 WdfDeviceInitSetFileObjectConfig,WDF 不查找 WDFFILEOBJECT)
+    NTSTATUS fwd_status = WdfDeviceWdmDispatchPreprocessedIrp(dev, irp);
+    DbgPrint("[CommModifyKit] DispatchCreate COM%u: forward status=0x%08X LowerDev=%p\n",
+             com, fwd_status, ctx ? ctx->LowerDevice : nullptr);
+    return fwd_status;
 }
 
-NTSTATUS SerialFilter::DispatchWrite(WDFDEVICE dev, PIRP irp) {
+NTSTATUS SerialFilter::DispatchClose(WDFDEVICE dev, PIRP irp) {
     PDEVICE_CONTEXT ctx = DeviceGetContext(dev);
+    ULONG com = ctx ? ctx->ComNumber : 0;
 
+    // 释放捕获的 FileObject
+    PIO_STACK_LOCATION sl = IoGetCurrentIrpStackLocation(irp);
+    if (ctx && sl && sl->FileObject) {
+        PFILE_OBJECT wdm_fo = sl->FileObject;
+        KIRQL old_irql;
+        KeAcquireSpinLock(&ctx->FileObjectLock, &old_irql);
+        PFILE_OBJECT saved = ctx->SavedFileObject;
+        if (saved == wdm_fo) {
+            ctx->SavedFileObject = nullptr;
+        } else {
+            saved = nullptr;
+        }
+        KeReleaseSpinLock(&ctx->FileObjectLock, old_irql);
+        if (saved) {
+            ObDereferenceObject(saved);
+            DbgPrint("[CommModifyKit] DispatchClose COM%u: SavedFileObject released\n", com);
+        }
+    }
+
+    // OP_CLOSE 事件
     if (ctx && ctx->MonitoringEnabled && ctx->RingBuffer) {
-        IoSetCompletionRoutine(irp, OnWriteComplete, ctx, TRUE, TRUE, TRUE);
+        EventRingBuffer* ring = (EventRingBuffer*)ctx->RingBuffer;
+        LONG seq = InterlockedIncrement(&g_sequence_counter);
+        UINT64 timestamp = KeQueryInterruptTime();
+        ring->Push((ULONG)seq, timestamp, com, COMMKIT_OP_CLOSE, 0, nullptr);
     }
 
-    return WdfDeviceWdmDispatchPreprocessedIrp(dev, irp);
+    NTSTATUS fwd_status = WdfDeviceWdmDispatchPreprocessedIrp(dev, irp);
+    DbgPrint("[CommModifyKit] DispatchClose COM%u: forward status=0x%08X LowerDev=%p\n",
+             com, fwd_status, ctx ? ctx->LowerDevice : nullptr);
+    return fwd_status;
 }
 
-NTSTATUS SerialFilter::DispatchDeviceControl(WDFDEVICE dev, PIRP irp) {
-    // DeviceControl 透传,不拦截(串口 IOCTL 由应用层处理)
-    return WdfDeviceWdmDispatchPreprocessedIrp(dev, irp);
-}
+NTSTATUS SerialFilter::DispatchRead(WDFDEVICE dev, PIRP irp) {
+    PDEVICE_CONTEXT ctx = DeviceGetContext(dev);
+    ULONG com = ctx ? ctx->ComNumber : 0;
 
-NTSTATUS SerialFilter::DispatchCreate(WDFDEVICE dev, PIRP irp) {
-    // CREATE/CLOSE/CLEANUP 直接转发,不做任何处理
-    DbgPrint("[CommModifyKit] DispatchCreate entered, IRP=%p\n", irp);
-    NTSTATUS status = WdfDeviceWdmDispatchPreprocessedIrp(dev, irp);
-    DbgPrint("[CommModifyKit] DispatchCreate returned 0x%08X\n", status);
+    // 在转发前读取栈位置(转发后可能失效)
+    PIO_STACK_LOCATION sl_before = IoGetCurrentIrpStackLocation(irp);
+    ULONG req_len = sl_before ? sl_before->Parameters.Read.Length : 0;
+    PFILE_OBJECT irp_fo = sl_before ? sl_before->FileObject : nullptr;
+    PDEVICE_OBJECT lower_dev = ctx ? ctx->LowerDevice : nullptr;
+    BOOLEAN monitored = (ctx && ctx->MonitoringEnabled && ctx->RingBuffer);
+
+    NTSTATUS status;
+    const char* fwd_method = "";
+
+    if (monitored) {
+        // 监控端口:设置完成例程后手动转发(捕获数据需要完成例程)
+        IoSetCompletionRoutine(irp, OnReadComplete, ctx, TRUE, TRUE, TRUE);
+        IoSkipCurrentIrpStackLocation(irp);
+        status = IoCallDriver(lower_dev, irp);
+        fwd_method = "IoCallDriver";
+    } else {
+        // 非监控端口:使用 WdfDeviceWdmDispatchPreprocessedIrp 转发
+        // 原因:CREATE/CLOSE 使用 WdfDeviceWdmDispatchPreprocessedIrp,
+        // READ/WRITE 若用 IoCallDriver 会绕过 WDF 内部 IRP 跟踪,
+        // 导致 WDF 状态不一致,可能引发后续 IRP 异常。
+        // 统一使用 WdfDeviceWdmDispatchPreprocessedIrp 确保 WDF 一致性。
+        status = WdfDeviceWdmDispatchPreprocessedIrp(dev, irp);
+        fwd_method = "WdfDispatch";
+    }
+
+    // 诊断:每个端口前 5 次 IRP 记录详细信息
+    if (com > 0 && com <= 256) {
+        static volatile LONG g_read_log_count[257] = {0};
+        LONG count = InterlockedIncrement(&g_read_log_count[com]);
+        if (count <= 5) {
+            DbgPrint("[CommModifyKit] IRP_MJ_READ COM%u status=0x%08X reqLen=%u mon=%d FO=%p Low=%p [%s] (#%ld)\n",
+                     com, status, req_len, (int)monitored, irp_fo, lower_dev, fwd_method, count);
+        }
+    }
     return status;
 }
 
-NTSTATUS SerialFilter::DispatchClose(WDFDEVICE dev, PIRP irp) {
-    return WdfDeviceWdmDispatchPreprocessedIrp(dev, irp);
-}
+NTSTATUS SerialFilter::DispatchWrite(WDFDEVICE dev, PIRP irp) {
+    PDEVICE_CONTEXT ctx = DeviceGetContext(dev);
+    ULONG com = ctx ? ctx->ComNumber : 0;
 
-NTSTATUS SerialFilter::DispatchCleanup(WDFDEVICE dev, PIRP irp) {
-    return WdfDeviceWdmDispatchPreprocessedIrp(dev, irp);
-}
+    PIO_STACK_LOCATION sl_before = IoGetCurrentIrpStackLocation(irp);
+    ULONG req_len = sl_before ? sl_before->Parameters.Write.Length : 0;
+    PFILE_OBJECT irp_fo = sl_before ? sl_before->FileObject : nullptr;
+    PDEVICE_OBJECT lower_dev = ctx ? ctx->LowerDevice : nullptr;
+    BOOLEAN monitored = (ctx && ctx->MonitoringEnabled && ctx->RingBuffer);
+
+    NTSTATUS status;
+    const char* fwd_method = "";
 
-NTSTATUS SerialFilter::CreateAndAttach(WDFDRIVER driver,
-                                         PDEVICE_OBJECT serial_pdo,
-                                         ULONG com_number,
-                                         WDFDEVICE* out_filter_device) {
-    // 不再使用:过滤设备由 EvtDeviceAdd 自动创建
-    UNREFERENCED_PARAMETER(driver);
-    UNREFERENCED_PARAMETER(serial_pdo);
-    UNREFERENCED_PARAMETER(com_number);
-    *out_filter_device = nullptr;
-    return STATUS_NOT_IMPLEMENTED;
+    if (monitored) {
+        // 监控端口:设置完成例程后手动转发
+        IoSetCompletionRoutine(irp, OnWriteComplete, ctx, TRUE, TRUE, TRUE);
+        IoSkipCurrentIrpStackLocation(irp);
+        status = IoCallDriver(lower_dev, irp);
+        fwd_method = "IoCallDriver";
+    } else {
+        // 非监控端口:使用 WdfDeviceWdmDispatchPreprocessedIrp 转发(同 DispatchRead)
+        status = WdfDeviceWdmDispatchPreprocessedIrp(dev, irp);
+        fwd_method = "WdfDispatch";
+    }
+
+    if (com > 0 && com <= 256) {
+        static volatile LONG g_write_log_count[257] = {0};
+        LONG count = InterlockedIncrement(&g_write_log_count[com]);
+        if (count <= 5) {
+            DbgPrint("[CommModifyKit] IRP_MJ_WRITE COM%u status=0x%08X reqLen=%u mon=%d FO=%p Low=%p [%s] (#%ld)\n",
+                     com, status, req_len, (int)monitored, irp_fo, lower_dev, fwd_method, count);
+        }
+    }
+    return status;
 }
 
 } // namespace commkit_driver

+ 5 - 13
driver/SerialFilter.h

@@ -1,6 +1,6 @@
 // SerialFilter.h - 串口 IRP 拦截
 // 职责:作为上层过滤驱动 attach 到串口设备栈
-//      拦截 IRP_MJ_READ / IRP_MJ_WRITE / IRP_MJ_DEVICE_CONTROL
+//      拦截 IRP_MJ_CREATE / CLOSE / READ / WRITE
 //      将捕获的数据推入对应端口的环形缓冲
 #pragma once
 
@@ -15,14 +15,6 @@ extern LONG g_sequence_counter;
 
 class SerialFilter {
 public:
-    // 创建过滤设备并 attach 到串口设备栈
-    // parent_serial_pdo:下层串口的 PDO
-    // 返回 STATUS_SUCCESS + 设置 *filter_device
-    static NTSTATUS CreateAndAttach(WDFDRIVER driver,
-                                      PDEVICE_OBJECT serial_pdo,
-                                      ULONG com_number,
-                                      WDFDEVICE* out_filter_device);
-
     // 拦截 IRP_MJ_READ 完成:捕获数据并推入环形缓冲
     static NTSTATUS OnReadComplete(PDEVICE_OBJECT dev, PIRP irp, PVOID ctx);
 
@@ -30,12 +22,12 @@ public:
     static NTSTATUS OnWriteComplete(PDEVICE_OBJECT dev, PIRP irp, PVOID ctx);
 
     // WDM IRP 预处理回调(KMDF 签名:WDFDEVICE, PIRP)
-    static NTSTATUS DispatchRead(WDFDEVICE dev, PIRP irp);
-    static NTSTATUS DispatchWrite(WDFDEVICE dev, PIRP irp);
-    static NTSTATUS DispatchDeviceControl(WDFDEVICE dev, PIRP irp);
+    // CREATE/CLOSE: 捕获/释放 FileObject + OP_OPEN/OP_CLOSE 事件
+    // READ/WRITE: 数据捕获(设置完成例程)
     static NTSTATUS DispatchCreate(WDFDEVICE dev, PIRP irp);
     static NTSTATUS DispatchClose(WDFDEVICE dev, PIRP irp);
-    static NTSTATUS DispatchCleanup(WDFDEVICE dev, PIRP irp);
+    static NTSTATUS DispatchRead(WDFDEVICE dev, PIRP irp);
+    static NTSTATUS DispatchWrite(WDFDEVICE dev, PIRP irp);
 
 private:
     // 从 IRP 中提取数据并推入环形缓冲