Partilhar via


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

Comments

  • Anonymous
    October 30, 2006
    i'm glad i found these posts of yours, now i know why file comments don't work in vista as they did in xp!clearly m$ have had a complete rethink but surely they could maintain backward compatibility... in the past things were done through IPropertySetStorage. I'm interested to see if they're going to change anything till vista makes it public

  • Anonymous
    November 02, 2006
    Many thanks to Clark who noticed that I was missing a ! in this statement: fWritable = !(flags & PDTF_ISINNATE); That'll teach me to write entries in a rush. The reasoning behind the change from XP behavior is a complicated topic.  I'd like to research it more and discuss it later.  In short, there were compelling reasons why we made the change, but you could have guessed I'd say that much :)

  • Anonymous
    November 14, 2006
    Have you ever felt this before? It's the day after you send your product to manufacturing . You step