You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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位整数,回收站对象总数)
  • 当前使用的结构体定义没有补上这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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.23 12:45:03