While we don’t have a table of properties and filetypes that are writable, there is a programmatic method to determine if a given property can be written to a given property handler. Here’s how it works:
First, properties can be designated innate. This means they are supposed to be read-only system-wide regardless of filetype. To check this, call IPropertyDescription::GetTypeFlags and look for PDTF_ISINNATE. Examples are System.Size and System.Image.Dimensions. These are things that the user should not be able to set.
Next, a property handler can reject the call to IShellItem2::GetPropertyStore(GPS_READWRITE). The GPS flag is passed to the property handler via IInitializeWithStream::Initialize. If a property handler is read-only, it will return STG_E_ACCESSDENIED. If the store is writable, it returns S_OK.
Finally, the property handler can indicate if a particular property is writable or not. Clients of the property system absolutely must call IPropertyStoreCapabilities::IsPropertyWritable if the handler supports this interface. This method returns S_OK for writable properties and S_FALSE if the property is readonly.
That’s it! Here I’ve put this into code:
BOOL _IsPropertyValueWritable(__in IPropertyStore *pps, __in REFPROPERTYKEY key, __in REFPROPVARIANT propvar)
BOOL fWritable = TRUE;
// 1. The caller already got the property store, so we know it likes GPS_READWRITE
// 2. Check if the property itself is innate
// Ignore errors just in case we want to write a property the system doesn’t recognize
if (SUCCEEDED(PSGetPropertyDescription(key, IID_PPV_ARGS(&ppropdesc))))
if (SUCCEEDED(ppropdesc->GetTypeFlags(PDTF_ISINNATE, &flags)))
fWritable = !(flags & PDTF_ISINNATE); // 2006/11/2 Edit: Add a ! that was missing here
// 3. Check if the property store likes the property
// Ignore errors since this interface is optional
fWritable = (S_OK == ppsc->IsPropertyWritable(key));
If you’re following along at home, feel free make propset call this function and print an appropriate diagnostic.