How does the shell get the properties of a file?
The Windows Shell exposes a rich system of properties about items (e.g. files and folders) in the shell namespace.
For example:
In order for the shell to read these properties, it obviously has to use a lot of sources:
IFilter
can retrieve Title, Author, Subject, Comments etc from Office documentsEither way, it has to read the file contents stream and do something with the contents of the file in order to get all these fancy shell properties. In other words:
IStream \
+ |--> [magic] --> IPropertyStore
.ext /
I have items that are not in the shell namespace; they are in a data store. I do expose them to the shell through IDataObject
as CF_FILEDESCRIPTOR
with an IStream
when its time to perform copy-paste or drag-drop. But outside of that they are just streamable blobs in a data store.
I'd like to be able to leverage all the existing work done by the very talented and hard-working1 shell team to read metadata from a "file", which in the end only exists as an IStream
.
Is there perhaps a binding context option that lets me get a property store based on an IDataObject
rather than a IShellItem2
?
So rather than:
IPropertyStore ps = shellItem2.GetPropertyStore();
is there a:
IPropertyStore ps = GetShellPropertiesFromFileStream(stream);
?
How does the shell get all the properties of a file?
This interface is typically obtained through IShellFolder::BindToObject or IShellItem::BindToHandler. It is useful for data source implementers who want to avoid the additional overhead of creating a property store through IShellItem2::GetPropertyStore. However, IShellItem2::GetPropertyStore is the recommended method to obtain a property store unless you are implementing a data source through a Shell folder extension.
IPropertyStore ps = CoCreateInstance(CLSID_PropertyStore);
IInitializeWithStream iws = ps.QueryInterface(IID_IInitializeWithStream);
But CLSID_PropertyStore
does not support IInitializeWithStream
.
Property handlers are a crucial part of the property system. They are invoked in-process by the indexer to read and index property values, and are also invoked by Windows Explorer in-process to read and write property values directly in the files.
(Have some experience in Property Store handlers) How I see a solution:
Get PropertyStore handler CLSID for your file extension. You should use 2 regkeys key:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\PropertySystem\PropertyHandlers\.yourext
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\PropertySystem\SystemPropertyHandlers
Create two objects with CoCreateInstance
If you have 2 object you can combine them into single object with PSCreateMultiplexPropertyStore
Query for IInitializeWithStream (also you can try to query IPersistStream).
If the PropertyStore object supports IInitializeWithStream/IPersistStream: you are lucky - just init your object and query the properties you need. If does not - you still have (dirty) variant to create temporary file and then use IPersistFile.