See the question and my original answer on StackOverflow

The Windows Shell Link class implements a property store, so you can get access to this with code like this (with ATL smart pointers):

int main()
{
    // note: error checking omitted!
    CoInitialize(NULL);
    {
        CComPtr<IShellLink> link;
        link.CoCreateInstance(CLSID_ShellLink);

        CComPtr<IPersistFile> file;
        link->QueryInterface(&file);

        file->Load(L"shortcut", STGM_READ);

        // get the property store
        CComPtr<IPropertyStore> ps;
        link->QueryInterface(&ps);

        // dump all properties
        DWORD count = 0;
        ps->GetCount(&count);
        for (DWORD i = 0; i < count; i++)
        {
            PROPERTYKEY pk;
            ps->GetAt(i, &pk);

            // get property's canonical name from pk
            CComHeapPtr<wchar_t> name;
            PSGetNameFromPropertyKey(pk, &name);

            PROPVARIANT pv;
            PropVariantInit(&pv);
            ps->GetValue(pk, &pv);

            // convert PropVariants to a string to be able to display
            CComHeapPtr<wchar_t> valueAsString;
            PropVariantToStringAlloc(pv, &valueAsString); // propvarutil.h

            wprintf(L"%s: %s\n", name, valueAsString);
            PropVariantClear(&pv);
        }
    }
    CoUninitialize();
    return 0;
}

It will output this:

System.ItemNameDisplay: New Text Document.txt
System.DateCreated: 2021/06/03:14:45:30.000
System.Size: 0
System.ItemTypeText: Text Document
System.DateModified: 2021/06/03:14:45:29.777
System.ParsingPath: C:\Users\b\Desktop\New Text Document.txt
System.VolumeId: {E506CEB2-0000-0000-0000-300300000000}
System.ItemFolderPathDisplay: C:\Users\b\Desktop

So, you're looking for System.ParsingPath, which you can get directly like this:

...   
ps->GetValue(PKEY_ParsingPath, &pv); // propkey.h
...