Writing properties #3 - Which properties are writable?
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 IPropertyDescription *ppropdesc; if (SUCCEEDED(PSGetPropertyDescription(key, IID_PPV_ARGS(&ppropdesc)))) { PROPDESC_TYPE_FLAGS flags; 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 if (fWritable) { IPropertyStoreCapabilities *ppsc; if (SUCCEEDED(pps->QueryInterface(IID_PPV_ARGS(&ppsc)))) { fWritable = (S_OK == ppsc->IsPropertyWritable(key)); ppsc->Release(); } } return fWritable; }
If you're following along at home, feel free make propset call this function and print an appropriate diagnostic.
-Ben Karas