Search code examples
windowswinapifilesystemsmsdnfile-attributes

How to get extended file-attributes in Windows in Python/Go/C/Batch?


I have searched a lot and have got some findings on how to get extended FA, but they are in C# using the language's own built-in APIs. I am trying to find the author name for a file in Windows, but my requirement is in Go/Python/C/Batch (order of priority).

In python, the third party packages (exifread and hachoir_metadata) are not working (not giving any result for a sample doc/xlsx file. Maybe the package I am installing via pip-install is erroneous).

Is there any other way or any user-level MSDN API available?

Please let me know if any experience on this. Thanks.


Solution

  • In C, C++ or other language, you get file properties with IPropertyStore interface

    For example, for a .jpg file (test on Windows 10, VS 2015) =>

    I get for Author : System.Author(Auteurs) = Test Auteur

    PIDLIST_ABSOLUTE pidl = ILCreateFromPath(L"E:\\icon_rose.jpg");
    if (pidl != NULL)
    {
        IPropertyStore *pps;
        HRESULT hr = SHGetPropertyStoreFromIDList(pidl, GPS_DEFAULT, IID_PPV_ARGS(&pps));
        if (SUCCEEDED(hr))
        {
            DWORD dwCount;
            hr = pps->GetCount(&dwCount);
            PROPERTYKEY propKey;
            for (DWORD i = 0; i < dwCount; ++i)
            {
                hr = pps->GetAt(i, &propKey);
                if (SUCCEEDED(hr))
                {
                    PWSTR pszCanonicalName = NULL;
                    hr = PSGetNameFromPropertyKey(propKey, &pszCanonicalName);                      
                    PWSTR pszDescriptionName = NULL;
                    IPropertyDescription *ppd;
                    hr = PSGetPropertyDescription(propKey, IID_PPV_ARGS(&ppd));
                    if (SUCCEEDED(hr))
                    {
                        hr = ppd->GetDisplayName(&pszDescriptionName);
                        ppd->Release();
                    }
                    PROPVARIANT propvarValue = { 0 };
                    HRESULT hr = pps->GetValue(propKey, &propvarValue);
                    if (SUCCEEDED(hr))
                    {
                        PWSTR pszDisplayValue = NULL;
                        hr = PSFormatForDisplayAlloc(propKey, propvarValue, PDFF_DEFAULT, &pszDisplayValue);
                        if (SUCCEEDED(hr))
                        {
                            WCHAR wsBuffer[255];
                            wsprintf(wsBuffer, L"%s(%s) = %s\n", pszCanonicalName, (pszDescriptionName==NULL?L"Unknown":pszDescriptionName), pszDisplayValue);
                            OutputDebugString(wsBuffer);
                            CoTaskMemFree(pszDisplayValue);
                        }
                        PropVariantClear(&propvarValue);
                    }
                    if (pszCanonicalName != NULL)
                        CoTaskMemFree(pszCanonicalName);
                    if (pszDescriptionName != NULL)
                        CoTaskMemFree(pszDescriptionName);;                         
                }
            }                   
            pps->Release();
        }
        ILFree(pidl);
    }