# CommModifyKit 使用说明文档 ## 1. 环境要求 | 项目 | 要求 | |------|------| | 操作系统 | Windows 10/11 x64 | | 编译器 | MSVC v142(Visual Studio 2019) | | WDK | Windows Driver Kit 10(编译内核驱动) | | 权限 | 安装驱动需要**管理员权限** | | 测试签名 | 开发阶段需启用 Windows 测试签名模式 | --- ## 2. 编译构建 ### 2.1 编译用户态 DLL 1. 用 VS2019 打开 `CommModifyKit.sln` 2. 选择配置 **Release | Win32** 3. 生成项目 **CommModifyKit** 4. 产物位于 `build\Release\Win32\CommModifyKit.dll` ### 2.2 编译内核态驱动 1. 确保已安装 WDK 10 2. 选择配置 **Release | x64** 3. 生成项目 **CommModifyKitDriver** 4. 产物位于 `build\Release\x64\CommModifyKit.sys` > 注意:驱动项目仅支持 x64 平台,Win32 配置会自动映射到 x64。 --- ## 3. 安装 ### 3.1 自动安装(推荐) 以**管理员身份**打开 PowerShell,执行: ```powershell cd CommModifyKit\installer .\install.ps1 ``` 脚本自动完成: 1. 查找构建产物(.sys、.inf、.dll) 2. 拷贝驱动文件到 `%SystemRoot%\System32\drivers\` 3. 创建并启动驱动服务 4. 拷贝 DLL 到 CommModifyService 目录(如检测到) 5. 启用测试签名(开发阶段需要,需重启生效) **安装后确认**: - 计算机已重启(启用测试签名后) - `CommModifyKit.dll` 已拷贝到 `CommModifyService.exe` 所在目录 - `config.json` 中 `comm.use_dll` 设为 `true` ### 3.2 手动安装 #### 安装驱动 ```powershell # 1. 拷贝驱动文件 copy CommModifyKit.sys %SystemRoot%\System32\drivers\ copy CommModifyKit.inf %SystemRoot%\System32\drivers\ # 2. 创建驱动服务 sc.exe create CommModifyKit binPath= "%SystemRoot%\System32\drivers\CommModifyKit.sys" type= kernel start= demand error= normal # 3. 启动驱动服务 sc.exe start CommModifyKit # 4. 启用测试签名(首次需要,重启生效) bcdedit /set testsigning on ``` #### 安装 DLL 将 `CommModifyKit.dll` 拷贝到 `CommModifyService.exe` 所在目录即可。 ### 3.3 验证安装 ```powershell # 检查驱动服务状态 sc.exe query CommModifyKit # 检查测试签名 bcdedit /enum | Select-String "testsigning" # 检查 DLL 是否在目标目录 dir CommModifyService\Release\CommModifyKit.dll ``` --- ## 4. 卸载 ### 4.1 自动卸载 以**管理员身份**打开 PowerShell,执行: ```powershell cd CommModifyKit\installer .\uninstall.ps1 ``` 脚本自动完成: 1. 停止并删除驱动服务 2. 删除 `%SystemRoot%\System32\drivers\` 下的 .sys 和 .inf 文件 3. 检查并提示通过 `pnputil` 移除驱动包 ### 4.2 手动卸载 ```powershell # 1. 停止驱动服务 sc.exe stop CommModifyKit # 2. 删除驱动服务 sc.exe delete CommModifyKit # 3. 删除驱动文件 del %SystemRoot%\System32\drivers\CommModifyKit.sys del %SystemRoot%\System32\drivers\CommModifyKit.inf # 4. 删除 DLL(手动) del CommModifyService\Release\CommModifyKit.dll # 5. 关闭测试签名(可选,重启生效) bcdedit /set testsigning off ``` --- ## 5. API 使用说明 ### 5.1 导出函数一览 CommModifyKit.dll 导出 7 个 `__stdcall` 函数: | 函数 | 用途 | |------|------| | `InitMonitor` | 初始化监控(必须最先调用) | | `Monitor` | 开始监控指定串口 | | `Stop` | 停止监控指定串口 | | `SetWrite_Data` | 向串口写数据 | | `SetRead_Data` | 发起异步读请求 | | `FreeMonitor` | 释放所有资源 | | `get_LastErrror` | 获取最近错误码 | ### 5.2 回调函数 ```cpp // 事件回调类型 typedef LONG(CALLBACK* TOnData)( int Sequence, // 递增序列号 double dTime, // OLE Automation date 时间戳 DWORD ComNumber, // 串口编号(COM n 的 n) DWORD Irp, // 事件类型 DWORD dwSize, // 数据字节数 char* lpData // 数据指针(只读!) ); ``` #### 事件类型(Irp 参数) | 值 | 常量 | 含义 | |----|------|------| | 1 | `COMMKIT_OP_OPEN` | 串口打开/开始监控 | | 2 | `COMMKIT_OP_READ` | 读取到数据(dwSize > 0, lpData 有效) | | 3 | `COMMKIT_OP_WRITE` | 写入数据(dwSize > 0, lpData 有效) | | 4 | `COMMKIT_OP_CLOSE` | 串口关闭/停止监控 | > **重要**:回调中的 `lpData` 指针指向 DLL 内部缓冲,仅在回调执行期间有效。如需保留数据,请在回调内拷贝,切勿存储指针。 ### 5.3 完整调用示例 ```cpp #include #include // 回调函数类型(与 DLL 导出一致) typedef LONG(CALLBACK* TOnData)(int, double, DWORD, DWORD, DWORD, char*); // 导出函数指针类型 typedef BOOL (__stdcall *FnInitMonitor)(wchar_t*, TOnData); typedef BOOL (__stdcall *FnMonitor)(DWORD); typedef BOOL (__stdcall *FnStop)(DWORD); typedef BOOL (__stdcall *FnSetWriteData)(DWORD, char*, int); typedef BOOL (__stdcall *FnSetReadData)(DWORD, char*, int); typedef void (__stdcall *FnFreeMonitor)(void); typedef int (__stdcall *FnGetLastError)(void); // 事件回调实现 LONG CALLBACK MyOnData(int Sequence, double dTime, DWORD ComNumber, DWORD Irp, DWORD dwSize, char* lpData) { const char* type_name = "?"; switch (Irp) { case 1: type_name = "OPEN"; break; case 2: type_name = "READ"; break; case 3: type_name = "WRITE"; break; case 4: type_name = "CLOSE"; break; } printf("[COM%d] %s seq=%d size=%u\n", ComNumber, type_name, Sequence, dwSize); // 如需保留数据,在此处拷贝: // std::vector data(lpData, lpData + dwSize); return 0; } int main() { // 1. 加载 DLL HMODULE hDll = LoadLibraryW(L"CommModifyKit.dll"); if (!hDll) { printf("LoadLibrary failed, error=%lu\n", GetLastError()); return 1; } // 2. 获取导出函数指针 auto InitMonitor = (FnInitMonitor) GetProcAddress(hDll, "InitMonitor"); auto Monitor = (FnMonitor) GetProcAddress(hDll, "Monitor"); auto Stop = (FnStop) GetProcAddress(hDll, "Stop"); auto SetWrite_Data = (FnSetWriteData) GetProcAddress(hDll, "SetWrite_Data"); auto SetRead_Data = (FnSetReadData) GetProcAddress(hDll, "SetRead_Data"); auto FreeMonitor = (FnFreeMonitor) GetProcAddress(hDll, "FreeMonitor"); auto get_LastErrror= (FnGetLastError) GetProcAddress(hDll, "get_LastErrror"); // 3. 初始化监控 wchar_t key[] = L"C09976511B62F0ADB759D87E6906D865"; if (!InitMonitor(key, MyOnData)) { int err = get_LastErrror(); printf("InitMonitor failed, error=%d\n", err); FreeLibrary(hDll); return 1; } printf("InitMonitor succeeded\n"); // 4. 开始监控 COM1 和 COM3 Monitor(1); // COM1 Monitor(3); // COM3 // 5. 向 COM1 写数据 char data[] = "AT\r\n"; SetWrite_Data(1, data, (int)strlen(data)); // 6. 从 COM1 发起异步读(结果通过回调 MyOnData 返回) char buf[256] = {0}; SetRead_Data(1, buf, sizeof(buf)); // 7. 等待事件...(实际应用中事件循环在 DLL 内部线程运行) Sleep(5000); // 8. 停止监控 COM3 Stop(3); // 9. 释放所有资源 FreeMonitor(); printf("Resources released\n"); // 10. 卸载 DLL FreeLibrary(hDll); return 0; } ``` ### 5.4 调用时序规则 ``` InitMonitor → Monitor → [SetWrite_Data / SetRead_Data] → Stop → FreeMonitor │ │ │ │ │ │ │ │ │ │ 必须最先 可多次调用 可随时调用 可多次调用 必须最后 ``` **规则**: 1. `InitMonitor` 必须在所有其他函数之前调用 2. `Monitor` / `Stop` / `SetWrite_Data` / `SetRead_Data` 要求先调用 `InitMonitor` 3. `FreeMonitor` 后不可再调用任何函数(除非重新 `InitMonitor`) 4. `Monitor` 同一端口多次调用是安全的(幂等) 5. `FreeMonitor` 不卸载驱动服务,仅释放 DLL 内部资源 --- ## 6. 错误处理 ### 6.1 错误码获取 每次导出函数调用后,通过 `get_LastErrror()` 获取最近一次操作的错误码: ```cpp if (!Monitor(1)) { int err = get_LastErrror(); // 根据 err 处理错误 } ``` > 注意:`get_LastErrror` 是**线程局部**的,与 Win32 `GetLastError()` 语义一致。 ### 6.2 错误码表 | 错误码 | 含义 | 建议处理 | |--------|------|---------| | 0 | 成功 | 无需处理 | | -1 | 未初始化 / 回调为空 | 先调用 `InitMonitor` | | 3 | 串口读取失败 | 检查端口是否已监控、驱动是否运行 | | 4 | 串口写入失败 | 检查端口状态和数据有效性 | | -241 | 安装驱动失败(SCM 错误) | 以管理员权限运行 | | -243 | 其他错误 | 查看日志获取详情 | | -244 | 驱动文件不存在或设备打开失败 | 检查 .sys 文件是否在 System32\drivers | | -252 | Key 无效 | 提供非空 Key | | -253 | 启动驱动服务失败 | 检查驱动签名、测试签名是否启用 | | -254 | 需要管理员权限 | 以管理员权限启动进程 | | -255 | 绑定串口失败 | 检查端口是否存在、驱动过滤是否正常挂载 | --- ## 7. 日志与诊断 ### 7.1 查看日志 #### DebugView(实时查看) 1. 下载 [DebugView](https://learn.microsoft.com/en-us/sysinternals/downloads/debugview) 2. 以管理员身份运行,开启 **Capture Global Win32** 3. 过滤 `CommModifyKit` 相关日志 #### 日志文件 DLL 可选输出日志到 `%TEMP%\CommModifyKit.log`,格式: ``` [2026-07-21 10:00:00][INF] DriverClient opened \\.\CommModifyKit [2026-07-21 10:00:00][INF] EventLoop started [2026-07-21 10:00:01][ERR] AttachPort failed for COM3 ``` ### 7.2 OutputDebugStringA 诊断点 MonitorManager 中关键流程节点输出 `OutputDebugStringA` 诊断信息,可通过 DebugView 实时追踪: - `[MonitorManager::EnsureDriverReady]` — 驱动就绪检查各步骤 - `[MonitorManager::InitMonitor]` — 初始化各步骤 ### 7.3 常见问题诊断 #### InitMonitor 返回 FALSE,错误码 -254 **原因**:进程未以管理员权限运行。 **解决**:右键程序 → "以管理员身份运行",或在 manifest 中请求 `requireAdministrator`。 #### InitMonitor 返回 FALSE,错误码 -244 **原因**:驱动文件不存在或驱动服务未启动。 **解决**: 1. 确认 `%SystemRoot%\System32\drivers\CommModifyKit.sys` 存在 2. 执行 `sc.exe query CommModifyKit` 检查服务状态 3. 若服务未运行:`sc.exe start CommModifyKit` #### InitMonitor 返回 FALSE,错误码 -253 **原因**:驱动服务启动失败,通常是签名问题。 **解决**: 1. 确认测试签名已启用:`bcdedit /enum | findstr testsigning` 2. 若未启用:`bcdedit /set testsigning on` 并重启 3. 生产环境需对驱动进行正式签名 #### Monitor 返回 FALSE,错误码 -255 **原因**:驱动中未找到该端口的过滤设备。 **解决**: 1. 确认该 COM 端口存在且未被占用 2. 确认驱动已作为 Upper Filter 正确挂载到串口设备栈 3. 检查设备管理器中串口属性 → "驱动程序" → "详细设置" → "上层筛选器" #### 回调不触发 **原因**:EventLoop 线程未运行或驱动未拦截到 IRP。 **解决**: 1. 确认 `InitMonitor` 返回 TRUE 2. 确认 `Monitor` 返回 TRUE 3. 用 DebugView 查看 EventLoop 日志 4. 确认驱动过滤设备已 attach 到串口栈 --- ## 8. 性能参数 | 参数 | 值 | 说明 | |------|---|------| | 单条事件最大数据 | 4096 字节 | `COMMKIT_MAX_DATA`,超出截断 | | 单次批量读取事件数 | 16 条 | `COMMKIT_EVENT_BATCH` | | 每端口环形缓冲容量 | 256 条 | `COMMKIT_RING_CAPACITY`,满了覆盖最旧 | | 最大支持端口数 | 256 | 驱动端口表大小 | | 事件循环错误重试间隔 | 50 ms | EventLoop 非致命错误后 sleep | --- ## 9. 安全说明 - **驱动访问控制**:控制设备使用 `SDDL_DEVOBJ_SYS_ONLY_ADM`,仅管理员和系统可访问 - **DLL 不直接暴露到网络**:通过 CommModifyService 封装后提供服务 - **回调数据只读**:`lpData` 指针指向内部缓冲,回调不应修改或释放 - **驱动服务常驻**:`FreeMonitor` 不卸载驱动,避免服务被恶意替换 - **测试签名**:仅用于开发,生产环境必须使用正式 WHQL 签名 --- ## 10. 版本兼容性 | 组件 | 接口版本 | 说明 | |------|---------|------| | DLL 导出函数 | 7 个 __stdcall | 与原 CommModifyKit.dll 接口完全一致 | | IOCTL 码 | 设备类型 0x8000,功能 0x800-0x806 | 用户自定义设备类型 | | 事件类型 | 0-4(OPEN/READ/WRITE/CLOSE) | 与 CommWrapperBase.h::CommEventType 数值对齐 | | 函数名拼写 | `get_LastErrror`(3 个 r) | 保留与原 DLL 一致的拼写 |