Writing properties #1 - Simple beginnings

I'm going to be talking about writable properties over the next few days. I know that some of you are itching to try this out yourselves, so here is an overly simplistic program that will write a single property to a file. I have omitted a lot of diagnostic code, so this will not work for all files, all strings, or all properties. I plan to go through those details another day.

 int wmain(__in int argc, __in_ecount(argc+1) WCHAR **argv)
{
    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
    if (SUCCEEDED(hr))
    {
        if (argc < 3)
        {
            wprintf(L"Usage: %s <filename> <property> <value>\n", argv[0]);
        }
        else
        {
            PCWSTR pszFile = argv[1];
            PCWSTR pszProperty = argv[2];
            PCWSTR pszValue = argv[3];

            PROPERTYKEY key;
            hr = PSGetPropertyKeyFromName(pszProperty, &key);
            if (SUCCEEDED(hr))
            {
                IShellItem2 *psi;
                hr = _GetShellItemFromRelativePath(pszFile, IID_PPV_ARGS(&psi));
                if (SUCCEEDED(hr))
                {
                    IPropertyStore *pps;
                    hr = psi->GetPropertyStore(GPS_READWRITE, IID_PPV_ARGS(&pps));
                    if (SUCCEEDED(hr))
                    {
                        PROPVARIANT propvar = {0};
                        hr = _GetValueFromString(key, pszValue, &propvar);
                        if (SUCCEEDED(hr))
                        {
                            hr = pps->SetValue(key, propvar);
                            if (SUCCEEDED(hr))
                            {
                                hr = pps->Commit();
                            }
                            PropVariantClear(&propvar);
                        }
                        pps->Release();
                    }
                    psi->Release();
                }
            }
            wprintf(L"Wrote %s:%s to %s; hr = 0x%08x\n", pszProperty, pszValue, pszFile, hr);
        }

        CoUninitialize();
    }
}

This code figures out which property to set, opens the store for writing, figures out the value to set, sets it, and commits the changes. Here are the helper functions I'm using:

 HRESULT _GetValueFromString(__in REFPROPERTYKEY key, __in PCWSTR pszValue, __out PROPVARIANT *ppropvar)
{
    return InitPropVariantFromString(pszValue, ppropvar); 
}

HRESULT _GetShellItemFromRelativePath(
    __in PCWSTR pszRelative, 
    __in REFIID riid, 
    __deref_out void **ppv)
{
    WCHAR szFile[MAX_PATH];
    HRESULT hr = StringCchCopyW(szFile, ARRAYSIZE(szFile), pszRelative);
    if (SUCCEEDED(hr))
    {
        PathUnquoteSpacesW(szFile);

        WCHAR szDir[MAX_PATH];
        hr = GetCurrentDirectory(ARRAYSIZE(szDir), szDir) ? S_OK : E_FAIL;
        if (SUCCEEDED(hr))
        {
            WCHAR szPath[MAX_PATH];
            hr = PathCombineW(szPath, szDir, szFile) ? S_OK : E_FAIL;
            if (SUCCEEDED(hr))
            {
                hr = SHCreateItemFromParsingName(szPath, NULL, riid, ppv);
            }
        }
    }
    return hr;
}
 And here's my output:
 C:\> propset.exe scan0010.jpg System.Keywords abc
Wrote System.Keywords:abc to scan0010.jpg; hr = 0x00000000 
 -Ben Karas
 see also: Reading properties

Comments

  • Anonymous
    November 02, 2006
    While we don't have a table of properties and filetypes that are writable, there is a programmatic method
  • Anonymous
    January 09, 2007
    Someone asked if I had a copy of the code I've been using in my blog so far. Well, I didn't as of 5pm