See the question and my original answer on StackOverflow

They are just serialized Windows properties. You can write and read these files (as streams) using builtin Windows implementation of IPropertyStore, for example using the PSCreateMemoryPropertyStore function

Here is a small sample console app that creates a test.props file with one property of string type:

#include <windows.h>
#include <atlbase.h>
#include <atlcom.h>
#include <propsys.h>
#include <propkey.h>
#include <propvarutil.h>

// some COM error handling useful macros
#define WIDEN2(x) L ## x
#define WIDEN(x) WIDEN2(x)
#define __WFILE__ WIDEN(__FILE__)
#define SBTRACE wprintf
#define CHECKHR(expr) {hr=(expr);if(FAILED(hr)){ SBTRACE(L"HR FAILED line:%u file:%s\n", __LINE__, __WFILE__); goto cleanup; } }  
#define HR HRESULT hr=S_OK;

int main()
{
  HR;
  PROPVARIANT pv;
  PropVariantInit(&pv);
  CoInitialize(NULL);
  {
    CComPtr<IPropertyStore> ps;
    CComPtr<IPersistStream> pstream;
    CComPtr<IStream> stream;

    // create the in-memory store
    CHECKHR(PSCreateMemoryPropertyStore(IID_PPV_ARGS(&ps)));

    // define some PROPVARIANT value (here it's a string)
    CHECKHR(InitPropVariantFromString(L"hello world", &pv));

    // any property key would work
    CHECKHR(ps->SetValue(PKEY_ItemNameDisplay, pv));

    // get IPersistStream to be able to load or write
    CHECKHR(ps->QueryInterface(&pstream));

    // create a file stream
    CHECKHR(SHCreateStreamOnFileEx(L"test.props", STGM_WRITE | STGM_CREATE, 0, TRUE, nullptr, &stream));

    // this sample only saves, but you can load from an existing stream
    CHECKHR(pstream->Save(stream, TRUE));
  }

cleanup:
  PropVariantClear(&pv);
  CoUninitialize();
  return 0;
}

Here is the result:

enter image description here