本插件 (IPRegionMon) 专为 TrafficMonitor 设计,主要功能如下:
- IP 归属地与网络类型检测:
- 支持通过第三方 API 接口获取当前的公网 IP 地址。
- 解析并显示 IP 对应的地理位置(国家、省份、城市)及运营商(ISP)。
- 对 IP 进行风险或威胁类型检测(如:移动网络、数据中心、宽带、是否为代理/VPN/Tor 节点、是否存在滥用黑名单记录)。
- 多链路(直连与代理)并行检测:
- 插件支持双轨并行查询。一条链路直连(绕过系统代理)以获取本地真实外网 IP;另一条链路走代理(如果配置了代理),以获取代理节点的出口 IP。
- 在任务栏主界面同时显示两者的概况(如:
直:中国福建 | 代:日本Tokyo)。
- 节点延迟测速:
- 支持配置多个测速目标 URL(如百度、Google、Github 等)。
- 使用 WinHTTP 对这些目标进行 HTTP 延迟测量(记录建立连接及首字节响应时间),并分别测量直连延迟和代理延迟。
- 悬浮提示 (Tooltip):
- 鼠标悬停在任务栏文本时,提供详细的报告,包含直连和代理的具体 IP、完整位置、ISP、网络纯净度(类型、状态、风险分数)以及所有测速目标的延迟详情和最后更新时间。
- 无 UI 纯后台运行:
- (当前版本调整)插件移除了所有 MFC 弹窗配置界面,以换取极高的运行稳定性和零前台打扰。所有配置项(包括更新间隔、API 接口、测速目标等)均通过读取
IPRegionMon.ini配置文件实现。用户需要手动修改 ini 并重启 TrafficMonitor 或重载插件来使配置生效。
- (当前版本调整)插件移除了所有 MFC 弹窗配置界面,以换取极高的运行稳定性和零前台打扰。所有配置项(包括更新间隔、API 接口、测速目标等)均通过读取
在项目早期的 UI 界面开发过程中,遇到了多次致命卡死和死锁问题,特此记录以避免未来重蹈覆辙:
- 现象:在设置界面包含
SysListView32列表控件时,如果用户尝试拖拽表头(Column Header)调整列宽,整个 TrafficMonitor 主程序瞬间卡死,且永远无法恢复,窗口标题变为(未响应)。 - 原因:TrafficMonitor 作为悬浮窗软件,在底层安装了全局的鼠标钩子(Mouse Hook)来实现“按住任意位置拖动窗口”的功能。当用户在列表表头上按下鼠标并拖动时,原生的表头控件会进入一个内部的
GetMessage死循环,等待WM_LBUTTONUP消息来结束拖拽。但 TrafficMonitor 的全局钩子误将该松开动作识别为主窗口的拖拽结束事件,从而拦截并吞噬了WM_LBUTTONUP消息。这导致表头控件永远等不到释放信号,主线程彻底死锁在内部循环中。 - 临时解决方案:曾在底层拦截表头控件的
HDN_BEGINTRACK通知消息,并返回TRUE强制禁止改变列宽。
- 现象:当改变列表列宽时,即便没有全局钩子的死锁,有时也会引发界面的无限重绘风暴,导致 CPU 满载并卡死。
- 原因:
CDialogEx拥有复杂的背景重绘和主题(Theme)管理逻辑。当嵌套包含LVS_EX_FULLROWSELECT和LVS_REPORT样式的 ListCtrl 时,控件的调整会触发父窗口背景重绘,而父窗口的重绘又再次触发子控件的刷新,形成WM_PAINT和WM_NCPAINT的死循环。 - 临时解决方案:必须将对话框基类降级为
CDialog,并为所有的对话框模板(Dialog Template)强行加上WS_CLIPCHILDREN窗口样式,以切断父子窗口间的无效重绘链。
- 现象:在点击“立即刷新”按钮或定时后台刷新触发时,整个界面偶尔或极易出现瞬间卡死
(未响应),且无法恢复。 - 原因:
- TrafficMonitor 官方的插件架构采用了主线程和刷新线程分离的模型。其中
DataRequired()(数据准备)由独立工作线程调用,而GetItemText()/GetTooltipInfo()由主线程(UI线程)调用读取字符串的c_str()。 - 早期代码在弹窗定时器中或后台测速线程中,强行使用了
SwapBuffers()来赋值和重新分配双缓冲的std::wstring变量。 - 结果造成了经典的数据竞争:UI 线程正在读取
std::wstring::c_str()指针进行绘制,而另一个线程同时对该字符串重新赋值,导致旧内存被释放。Windows 堆分配器在处理这种并发野指针访问时发生崩溃,进而引发了RtlAllocateHeap内部关键节死锁,导致程序硬卡死。
- TrafficMonitor 官方的插件架构采用了主线程和刷新线程分离的模型。其中
- 最终解决方案:
- 彻底理清并遵守 TrafficMonitor 的线程模型。后台测速线程在长达数秒的网络请求期间,必须绝对只使用函数局部变量。
- 只有在所有网络请求结束的最后一刻,才加锁并一次性安全地赋予全局背景变量(_bg)。
- 取消了在 UI 层面的所有强制同步操作。
- 考虑到 MFC UI 在 TrafficMonitor 插件生态下存在过多未知冲突和同步风险,最终决定整体切除 UI 层,将程序架构简化为纯后台执行引擎,以获得极致的稳定性。