通过 `IShellItem` 获取文件大小

7
我已经使用IShellItemIShellFolderIStorageIStream等实现了Windows Shell的目录遍历算法。一切都很好。我甚至可以遍历Shell命名空间扩展(例如.zip)文件。
然而,当其他程序以独占访问方式使用文件时,我无法提取(常规)文件大小。
据我所知,除了文件名称外,没有什么比STATSTG结构体提供更多信息了。获取IShellItemSTATSTG有三种方法:
1. 使用IEnumSTATSTG进行迭代,而不是使用IEnumIDList。获取文件夹的IStorage并调用IStorage::EnumElements(),而不是调用IShellFolder::EnumObjects()。这样你就可以直接获得STATSTG结构体了。 2. 获取IShellItemIStorage并调用IStorage::Stat()。 3. 获取IShellItemIStream并调用IStream::Stat()
我真的很想使用第一种方法,因为它会给我所有需要的信息。但是,我无法枚举文件夹内容。我成功地提取了文件夹的IStorage:它自己的Stat()给出了正确的文件夹名称。我成功地提取了IEnumSTATSTG,但第一次调用Next(1, &item, NULL)返回S_FALSE并终止枚举。
如果无法使用方法1,我将使用方法2,虽然这仍然不太好,但是对于常规磁盘文件提取IStorage会产生错误,无论是使用IShellItem::BindToHandler(0, BHID_Storage, ...)还是IShellFolder::BindToStorage(child, ...)都不行。
最后我尝试了方法3,虽然它似乎很奇怪,但只要文件没有被其他程序以独占访问方式使用,它就可以成功。
我在网上搜寻了一些代码片段,发现了使用方法3的几个例子。
问题:有人能解释一下我应该如何在不使用方法3的情况下获取文件的STATSTG吗?
方法1是否有效?或者常规文件的IStorage实现是否不会生成列表?方法2是否有效,或者常规文件的IStorage实现是否未实现?

环境: Windows Vista Ultimate 32位, Visual Studio 2008 Express. 使用C++,没有ATL,所有自定义COM包装器(内部开发,可能需要适当修改,假设有问题)。


打开文件的文件大小相对来说并没有太大意义。即使你找到了一个返回它的函数,这个值也可能在下一条指令中发生变化。 - MSalters
2
按照这种逻辑,检查文件的存在是没有意义的。在下一个指令执行之前,文件可能会被另一个进程删除。我很清楚这些问题,但实现文件浏览功能需要显示过时的信息 :-) - André Caron
2个回答

1

你尝试获取IShellItem2接口并查询PKEY_Size属性的值了吗?


不,我还没有尝试过那个,主要是因为它在Windows XP上无法运行(如果可以的话,我会考虑与旧系统兼容)。不过看来我别无选择了。我会去查一下这个的。 - André Caron
你知道我需要哪个头文件/版本宏才能定义PKEY_Size常量吗?我一直在谷歌搜索,但得到很多与数据库相关的内容。我猜PKEY被误认为是“主键”了... - André Caron
我现在不在我的桌面电脑上。我在Windows 7.0A\Include目录中的一个文件中找到了它。你可能需要安装更新的平台SDK。 - Roger Lipscombe
2
确实,我在平台SDK的Include文件夹中使用了grep命令搜索它,但没有找到。我已经决定使用IShellFolder2 :: GetDetailsEx(),它非常好用。而且它还兼容XP! - André Caron
@AndréCaron 属性键 - xenophōn

1
即使有了被接受的答案,这也需要一些努力。
首先,您需要Windows属性参考。从那里,您必须知道要进入System.Size。从那里,您可以获得两个重要的信息:

System.Size

该项的系统提供的文件系统大小(以字节为单位)。

shellPKey = PKEY_Size
typeInfo
       type = UInt64

知道它是一个UInt64,您就可以获取IShellItem2接口,以使用其中的许多属性获取方法:
//Get the IShellItem2 interface out of the IShellItem object
IShellItem2 si2 = shellItem as IShellItem2;

//Get the file fize (in bytes)
UInt64 fileSize;
si2.GetUInt64(PKEY_Size, ref fileSize);

感谢您抽出时间发布这个答案!然而,我无法再验证它的相关性了(因为我不再在那个环境中工作)。但愿它仍能对后人有所帮助。 - André Caron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接