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
:
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.IStorage
for the IShellItem
and invoke IStorage::Stat()
.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).
Have you tried getting hold of the IShellItem2 interface, and then querying for the value of the PKEY_Size property?
Even with the accepted answer, it took some doing.
The first thing you need is the Windows Properties reference. From there you have to know that you want to go into System.Size. From there you get the two important pieces of information:
System.Size
The system-provided file system size of the item, in bytes.
shellPKey = PKEY_Size
typeInfo
type = UInt64
Knowing that it's a UInt64
, you can then get ahold of the IShellItem2
interface, in order to use one of the many property-getting methods:
//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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With