Windows 10下C++Builder6调用SHQueryRecycleBin获取回收站返回值异常
问题核心根因
结构体内存布局不匹配导致的内存错位
- C++Builder 6自带的Windows SDK版本停留在2002年的Windows 2000/早期XP阶段,既没有内置
SHQUERYRBINFO结构体的正确声明,默认编译器对齐规则和微软系统API要求的结构体对齐规则存在差异。 - 微软系统要求的
SHQUERYRBINFO内存布局是严格按照8字节边界对齐设计的:- 0偏移:
DWORD cbSize(占4字节) - 4偏移:4字节保留填充位(为了让后续64位整数的地址落在8字节对齐边界上)
- 8偏移:
i64Size(8字节64位整数,回收站总占用空间) - 16偏移:
i64NumItems(8字节64位整数,回收站对象总数)
- 0偏移:
- 当前使用的结构体定义没有补上这4字节的填充位,两个64位字段的读取位置比系统实际写入的位置整体靠前4个字节,所有读到的数值全是错位的内存垃圾,自然会出现空间值超过磁盘总大小、对象计数为天文数字的异常。
- 排查阶段看到的“i64NumItems返回0、i64Size数值明显偏离真实值”就是典型的错位表现:系统实际写入的正确对象计数被错位读入了i64Size的高位字节,原本i64NumItems的读取位置拿到的是相邻内存的0值。
字符串转换的隐性错误
- C++Builder 6内置的
AnsiString没有内置64位无符号整数的转换重载,当直接把64位整数传给AnsiString构造函数时,编译器会隐式把整数转成指针地址再转成字符串,这就是最初看到计数返回43628621390151600这种离谱数值的次要原因。
查询路径的匹配偏差
- 原代码传入
"C:\\"作为查询路径时,API只会返回C盘分区下的回收站统计值,不会汇总所有磁盘的回收站内容。如果其他分区也存储了回收站对象,返回值自然会比资源管理器、CCleaner显示的全局回收站数值小。
修正后的实现方式
- 不要依赖自带头文件的旧定义,手动按照系统要求的内存布局定义结构体,补上缺失的4字节填充位,保证内存布局和系统API的要求完全一致:
// 兼容Win10系统的结构体定义 typedef struct _SHQUERYRBINFO_COMPAT { DWORD cbSize; DWORD dwPadding; // 补上对齐需要的4字节填充 ULONGLONG i64Size; ULONGLONG i64NumItems; } SHQUERYRBINFO_COMPAT; // 手动导入正确的API原型,避免头文件的旧声明干扰 HRESULT WINAPI SHQueryRecycleBinA(LPCSTR pszRootPath, SHQUERYRBINFO_COMPAT *pInfo);
- 调用时如果需要查询全系统回收站的总统计值,路径参数传
NULL;如果只需要查询单个分区的回收站,传入对应分区根路径即可。 - 64位整数转字符串时不要依赖隐式类型转换,用专门的64位转字符串函数处理,避免错误的隐式转换:
void __fastcall TForm6::Button10Click(TObject *Sender) { SHQUERYRBINFO_COMPAT rbinfo; memset(&rbinfo, 0, sizeof(rbinfo)); rbinfo.cbSize = sizeof(rbinfo); HRESULT rc = SHQueryRecycleBinA(NULL, &rbinfo); if (rc != S_OK) { Application->MessageBox("Fehler bei SHQueryRecycleBin", "Fehler", MB_OK | MB_ICONERROR); return; } AnsiString sSize, sCount; char buf[32]; // 用C runtime自带的64位整数转字符串函数 _i64toa(rbinfo.i64Size, buf, 10); sSize = AnsiString(buf); _i64toa(rbinfo.i64NumItems, buf, 10); sCount = AnsiString(buf); Application->MessageBox(sSize.c_str(), "Speicherplatz", MB_OK | MB_ICONINFORMATION); Application->MessageBox(sCount.c_str(), "Anzahl Objekte", MB_OK | MB_ICONINFORMATION); }
注意事项
- Secure Eraser显示的20多万个文件、190多G的占用值,是包含了软件自身残留的擦除临时文件的统计结果,和系统回收站的真实统计值不具备可比性,正确的对比基准应该是Windows资源管理器、CCleaner显示的系统原生回收站数值。
内容的提问来源于stack exchange,提问作者Egon
相关产品推荐
相关产品推荐

