Search code examples
c++windowswindows-shell

Get a file's size through `IShellItem`


I've implemented a directory walking algorithm for the Windows Shell using IShellItem, IShellFolder, IStorage, IStream, etc. All is well and good. I can even walk inside shell namespace extensions (e.g. .zip) files.

However, I have problems extracting (regular) file sizes when files are being used by some other program with exclusive access.

AFAIK, there is nothing but the STATSTG structure that gives more information than the file's name. There are essentially 3 ways to get a hold of a STATSTG for a IShellItem:

  1. Iterate using IEnumSTATSTG instead of IEnumIDList. Instead of invoking IShellFolder::EnumObjects(), get the IStorage for the folder and invoke IStorage::EnumElements(). You now get STATSTG structures directly.
  2. Get the IStorage for the IShellItem and invoke IStorage::Stat().
  3. Get the IStream for the IShellItem and invoke IStream::Stat().

I would really like to use #1 because it would give me all the information I need. However, I cannot get it to enumerate folder contents. I successfully extract the IStorage for the folder: it's own Stat() gives me the proper folder name. I successfully extract the IEnumSTATSTG, but the first call to Next(1, &item, NULL) returns S_FALSE and terminates the enumeration.

I would fallback to use #2 as it is still not so bad, but extracting the IStorage for regular disk files produces an error using both of IShellItem::BindToHandler(0, BHID_Storage, ...) and IShellFolder::BindToStorage(child, ...).

I finally tried #3 although it just plains seems wrong and it succeeds as long as files are not being used with exclusive access by another program.

I've googled around a bit and found several code snippets that use approach #3.

Question: Can anyone explain how I'm supposed to get the file's STATSTG without using approach #3?

Should approach #1 work, or does the IStorage implementation for regular folders simply not produce listings? Should approach #2 work or is the IStorage implementation simply not implemented for regular files?

Environment: Windows Vista Ultimate 32-bit, Visual Studio 2008 Express. Using C++, no ATL, all custom COM wrappers (in-house, may be suitably modified assuming somwthing is wrong there).


Solution

  • Have you tried getting hold of the IShellItem2 interface, and then querying for the value of the PKEY_Size property?