MFC 播放器播放统计:从崩溃修复到图表重构
给一个开源的 MFC 音乐播放器做二次开发我想加个播放统计功能——看看自己每天听什么歌、哪个时段听得最多。第一版功能跑通了Release 编译 0 error我还挺得意。结果一开 Debug 版点开统计对话框直接崩在ucrtbased.dll菜单项上赫然显示一串 error。这一崩把我后面三天都搭进去了。起因想给播放器装个听歌账本我用的这个播放器是 MusicPlayer2一个用 MFC 写成的开源 Windows 音乐播放器本身没有播放统计。我这种人连自己上周循环了哪首歌都记不住就想加个本地统计把每次播放都记下来。思路其实不复杂在播放器几个关键节点埋点把每次播放写成一行 JSON 存到本地文件再做一个对话框把数据画出来看。存储我选了JSONL按月分文件statistics/playlog_YYYY-MM.jsonl。当时也考虑过 SQLite但放弃了一来这个项目本来就往song_data.dat写二进制我不想动它的存储格式二来 JSONL 追加写入、写完立刻 flush程序崩了也不丢数据崩溃安全性更好。这个决定后来帮了我——起码我的 bug 从没弄丢过已记录的数据。埋点我只动了四个地方尽量最小侵入歌曲开始播放、每秒 tick 计时、切歌、程序退出时 flush。每条记录带上标题、艺术家、专辑、流派、播放时长、播放结果完整收听 / 跳过 / 停止 / 出错、是否随机播放这些字段。第一版界面三个 Tab 和手绘图表统计界面我做成一个对话框三个 Tab总览、详细记录、图表。详细记录能按时间倒序看每一次播放还能导出 CSV带 BOMExcel 直接打开和 JSON。图表是用GDI 手绘的没引第三方库30 天播放趋势的折线 柱状组合、24 小时听歌时段的着色柱状图、艺术家播放时长占比的饼图。左键点图表区域循环切换三种图。第一版做完Release 编译干干净净我觉得这下稳了。然后我习惯性地开了 Debug 版点了一下——直接崩。Debug 崩溃死在 ucrtbased.dll 的越界访问崩溃点在CPlayStatisticsDlg::LoadRecords()里解析 JSONL 的那段。我写了个extract_bool的 lambda从was_shuffled:后面取字符判断真假out (line[pos] t); // pos 可能等于 line.size()越界访问问题就藏在这儿。当某一行was_shuffled:后面紧跟换行、或者这条记录字段被截断时pos会等于line.size()。而std::string::operator[]在Debug 模式下会做越界检查直接触发 assertion failure一路往上炸到_invalid_parameter最后死在ucrtbased.dll。Release 版不做这个检查所以看起来一切正常——这才是这件事最坑的地方Release 能跑不代表没 bug。修起来倒简单加一行边界判断auto extract_bool [](size_t pos, bool out) { if (pos line.size()) return; // 越界就跳过别去读那一位 out (line[pos] t); };但找到它花了我两小时。崩溃栈只告诉我死在ucrtbased.dll没有任何业务代码线索典型的报错信息和真正病因八竿子打不着。最后是把那一行 JSON 逐字段对了一遍才发现有的记录was_shuffled后面根本没值。顺手还收拾了两个小尾巴。一个是新增的菜单项文字显示 error根因是英文语言包English.ini的[menu.MAIN_TOOL]节里我没给ID_PLAY_STATISTICS写翻译函数找不到就返回了常量error。补一行翻译即可。另一个是ToJson()里snprintf(buf, sizeof(buf), \\u%04x, c)的c是char有符号而%x期望unsigned int类型不严谨我改成static_castunsigned char(c)收尾。图表扩展加上时间筛选却踩了第二个坑崩的问题解决后这个统计我越用越觉得不够看。我想看最近 30 天而不是全部时间的分布于是加了时间范围下拉框全部 / 7 天 / 30 天 / 90 天又补了 Top10 专辑、Top10 歌曲、流派分布环形图点击切换的视图从 3 个扩到 5 个。下拉框切换时调用GetFilteredRecords()过滤记录再Invalidate重绘逻辑看着没问题。可实测发现切到 30 天后趋势图和时段图完全没变还是全部时间的数据。排查下来DrawTrendChart和DrawHourChart这两个画图函数的开头直接遍历的是m_records压根没用我过滤出来的records// 修复前画的是全部记录时间筛选形同虚设 for (const auto r : m_records) { ... } // 修复后开头先拿过滤结果 auto records GetFilteredRecords(); for (const auto r : records) { ... }就这一行的事。但如果不看实现、只信我明明调了过滤函数的直觉根本想不到画图函数内部绕过了数据源。两个函数各补一行筛选终于生效。重构3 页视图扩到 5 页视图扩到 5 个后原来的m_chart_type % 3切换逻辑得改成% 5右上角的视图名提示数组也补到 5 个。这一版我把概览、排行榜、流派分布、30 天趋势、时段分布做成分页切换排行榜每个显示前 5 名布局压缩在一页里。编译 0 error功能全通。经验总结回过头看这三天踩的坑都是低级但隐蔽那一类的Debug 和 Release 行为不一致要警惕。越界访问在 Release 静默通过在 Debug 直接崩。这类 bug 不开 Debug 版根本发现不了所以功能写完我都会专门开 Debug 跑一遍。画图函数别绕过数据源。我本以为GetFilteredRecords()是全局生效的结果两个画图函数内部各自持有一份m_records。过滤类 bug 最容易被接口看起来对的骗过去改完一定得实测筛选结果。多语言资源漏一项就显示 error。MFC 的字符串表、菜单翻译每加一个新控件或菜单记得把所有语言包都补齐。这套统计模块我用了快两个月每天听歌习惯一目了然也没再崩过。如果你也在维护老 MFC 项目、想加类似的本地统计JSONL GDI 手绘这条路是走得通的就是调试时记得开 Debug 版。

相关新闻

AI沙箱逃逸真相:从报错到权限边界防护

AI沙箱逃逸真相:从报错到权限边界防护

“AI Escaped Its Sandbox”——AI逃出了沙箱,这类说法在网上隔一段时间就会出现一次,听起来很吓人,仿佛模型突然有了自我意识,自己推开门跑了。实际不是这么回事。沙箱是计算机安全里常用的隔离运行环境;逃逸的意思是…

2026/8/29 19:59:21 阅读更多 →
AI沙箱逃逸真相:从沙箱创建失败到权限边界实战排查

AI沙箱逃逸真相:从沙箱创建失败到权限边界实战排查

一个开发者朋友突然发来一条消息:“AI Escaped Its Sandbox,这是什么意思?”字面翻译是“AI 逃出了它的沙箱”,听起来像是科幻电影里“AI 觉醒”的第一步。但他真正遇到的场景其实很普通:Codex 在 Windows 上创建沙箱失…

2026/8/29 19:59:21 阅读更多 →
AI沙箱逃逸解析:从提示词注入到Agent防护实践

AI沙箱逃逸解析:从提示词注入到Agent防护实践

“AI Escaped Its Sandbox”——这句话最近在国外技术社区和标题党新闻里反复出现。单看这个说法,很容易脑补出一幅“大模型冲破机房、自我觉醒”的画面;实际拆开看,它指向的是一个更具体的安全工程问题:大模型助手、Agent 应用、…

2026/8/29 19:59:21 阅读更多 →

最新新闻

HoRain云--Node.js 模块导入

HoRain云--Node.js 模块导入

当你开始写 Node.js 项目时,最先遇到的问题之一就是——如何导入模块(module)。在 Node.js 里,模块就是可以重复使用的 JavaScript 文件,它们之间通过导入(import)和导出(export&…

2026/8/29 20:39:01 阅读更多 →
HoRain云--CSS 分组 和 嵌套 选择器

HoRain云--CSS 分组 和 嵌套 选择器

分组选择器在样式表中有很多具有相同样式的元素。h1 { color:green; } h2 { color:green; } p { color:green; }为了尽量减少代码,你可以使用分组选择器。每个选择器用逗号分隔。在下面的例子中,我们对以上代码使用分组选择器:实例h1,h2,p { …

2026/8/29 20:39:01 阅读更多 →
HoRain云--CSS padding(填充)

HoRain云--CSS padding(填充)

CSS padding(填充)是一个简写属性,定义元素边框与元素内容之间的空间,即上下左右的内边距。 padding(填充) 当元素的 padding(填充)内边距被清除时,所释放的区域将会受到…

2026/8/29 20:39:01 阅读更多 →
学习FastAPI,定义模型时使用Pydantic

学习FastAPI,定义模型时使用Pydantic

在其他的web框架中,Django或Flask,都有相应的表单类用来校验前端数据的合法行,在FaskAPI中则用Pydantic来实现。Pydantic 是 FastAPI 的"数据守门员":你只用声明"我想要什么类型的数据、有什么规则"&#xff…

2026/8/29 20:39:01 阅读更多 →
解构 K8s 弹性管道:Metrics‑Server 指标采集与 HPA 自动扩缩容深度剖析

解构 K8s 弹性管道:Metrics‑Server 指标采集与 HPA 自动扩缩容深度剖析

Kubernetes Metric Server 学习参考:Metric Server 环境准备 rootmaster30:~# kubectl create ns metric rootmaster30:~# kubectl config set-context --current --namespace metricMetrics-Server 概述 我们在使用 Kubernetes 中过程中面临的问题: 如…

2026/8/29 20:39:01 阅读更多 →
IDA*算法精解:从暴力搜索到启发式剪枝,解决“排书”难题

IDA*算法精解:从暴力搜索到启发式剪枝,解决“排书”难题

1. 从一道“排书”题说起:当暴力搜索遇上剪枝艺术 最近在算法社区里,一道编号为180的“排书”问题讨论热度不低。乍一看标题,你可能会觉得这不过是又一道普通的深度优先搜索(DFS)练习题,但真正上手后&#…

2026/8/29 20:38:00 阅读更多 →

日新闻

etc目录下的profile.d文件目录设置环境变量和全局脚本shell

etc目录下的profile.d文件目录设置环境变量和全局脚本shell

一、设置环境变量etc目录下的profile.d文件目录 /etc/profile.d1、编写 vi test.sh文件内容# jdk变量 export ZHK_HOME/root export PATH$PATH:$ZHK_HOME/test # 可以取出来ZHK_HOME变量给ZZZ_HOME赋值 export ZZZ_HOME${ZHK_HOME}/test2、刷新 执行source /etc/profile 命令使…

2026/8/29 0:00:24 阅读更多 →
【JavaScript】内存管理-垃圾回收机制-内存泄露

【JavaScript】内存管理-垃圾回收机制-内存泄露

内存管理 C 语言这样的底层语言一般都有底层的内存管理接口,比如 malloc()和free()。 而 JavaScript 是在创建变量(对象,字符串等)时自动进行了分配内存,并且在不使用它们时“自动”释放。释放的过程称为垃圾回收。 整…

2026/8/29 0:00:24 阅读更多 →
Labgrid-MCP:为嵌入式硬件实验室接入AI Agent操控能力

Labgrid-MCP:为嵌入式硬件实验室接入AI Agent操控能力

Labgrid-MCP 的目标是把 MCP(Model Context Protocol)能力延伸到真实嵌入式硬件实验室:AI Agent 通过一个标准化的 MCP Server,就能查看目标板状态、控制上电断电、复位开发板、读取串口日志,甚至执行镜像刷写。对于经…

2026/8/29 0:00:24 阅读更多 →

周新闻

[光学原理与应用-521]:对光的错误理解与纠偏

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/29 18:08:35 阅读更多 →
SIP通话转接原理与REFER方法实战解析

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/28 23:05:07 阅读更多 →
Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/28 19:47:53 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/29 4:34:53 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/28 17:43:04 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/29 2:05:18 阅读更多 →