Win10下SHCNE_CREATE事件触发后IShellItem2无法获取文件时间如何解决
问题原因
SHCNE_CREATE是Shell发出的文件系统对象创建完成的早期通知,触发时Shell的命名空间属性缓存尚未完成同步更新,你通过PIDL创建的IShellItem2实例默认读取的是未完成初始化的缓存数据,文件创建时间、修改时间这类扩展属性还未被写入缓存,因此会返回ERROR_NOT_FOUND错误。
你调试时能看到文件完整属性、GetDisplayName()调用正常,是因为:调试中断的时间差足够让Shell完成属性缓存同步,资源管理器访问属性时会主动触发磁盘读取而非只读过期缓存;而文件名属于PIDL自带的基础属性,不依赖额外的属性缓存就能读取。
可行解决方案
- 方案1:异步延迟读取
收到SHCNE_CREATE通知后,不要在回调函数内立刻读取时间属性,投递一个延迟100~500ms的异步任务后再执行属性读取操作,给Shell属性缓存留出同步时间,注意不要在通知回调线程内做同步等待,避免阻塞Shell消息队列。 - 方案2:强制刷新
IShellItem2属性缓存
拿到IShellItem2实例后先调用Update()方法强制从磁盘同步最新属性,刷新完成后即可正常读取时间属性,该方案可靠性高于固定延迟,不受系统负载影响。
参考代码:IShellItem2* pShellItem = nullptr; HRESULT hr = SHCreateItemFromIDList(pidlReceived, IID_PPV_ARGS(&pShellItem)); if (SUCCEEDED(hr)) { // 强制同步磁盘最新属性 hr = pShellItem->Update(NULL); if (SUCCEEDED(hr)) { FILETIME ftCreate; hr = pShellItem->GetFileTime(PKEY_DateCreated, &ftCreate); // 此处hr为S_OK即可正常获取创建时间 } pShellItem->Release(); } - 方案3:绕过Shell缓存直接读取
先调用IShellItem2::GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath)获取文件的本地完整路径,再通过Win32原生APIGetFileAttributesExW()或者CreateFileW+GetFileTime直接读取文件时间属性,该方案完全不依赖Shell缓存状态,稳定性最高。
内容的提问来源于stack exchange,提问作者user3161924
相关产品推荐
相关产品推荐

