In parts one and two, I started writing a program to print out the properties on an item.  But I saved the best for last -- printing a value.   Discussion follows the code.

HRESULT _PrintPropertyValue(__in REFPROPERTYKEY key, __in REFPROPVARIANT propvar)
{
    IPropertyDescription *ppropdesc;
    HRESULT hr = PSGetPropertyDescription(key, IID_PPV_ARGS(&ppropdesc));
    if (SUCCEEDED(hr))
    {
        PWSTR pszLabel;
        hr = ppropdesc->GetDisplayName(&pszLabel);
        if (SUCCEEDED(hr))
        {
            PWSTR pszValue;
            hr = ppropdesc->FormatForDisplay(propvar, PDFF_DEFAULT, &pszValue);
            if (SUCCEEDED(hr))
            {
                wprintf(L"%s: %s\n", pszLabel, pszValue);
                CoTaskMemFree(pszValue);
            }
            CoTaskMemFree(pszLabel);
        }
        ppropdesc->Release();
    }

    return S_OK;  // For now, I'm going to ignore properties we couldn't view.
}

We got some meat to the program now!  There are a lot of details to notice here.

First, the the property system knows something about that property key we got from IPropertyStore::GetAt.  We can tap that knowledge by asking for the IPropertyDescription interface.  For instance, we can ask for the label of the property, such as L"Rating" or L"Tags". 

Another facility IPropertyDescription provides is to format a data value into a printable string.  If formatting is necessary (such as to convert a number to a string), the result will be in the user's current locale.  String values do not require formatting and are assumed to have been typed by the user in his or her preferred language.

Finally, notice how I'm ignoring the final HRESULT?  That's for a reason.  It turns out some property stores can return properties the system doesn't know about.  Try this program on a .doc file.  Other properties were not meant to be displayed and lack labels or formatting routines.  So pretty much any of the above functions can fail, but since this toy example just wants to print everything it can, I have it ignore errors here.

I'll talk about the output of this program tomorrow.