Mordachai Mordachai - 3 months ago 27
C++ Question

IShellLink::SetIconLocation translates my icon path into %Program Files% which is WRONG

Does anyone know how to correct for this behavior?

Currently, when our installer installs our application, it obtains an IShellLink, then loads it up with the data necessary for our shortcut icon (in the start menu & desktop), and then uses IPersistFile::Save to write out the shortcut.

The problem is that the path specified for the icon, via IShellLink::SetIconLocation, is transformed into using %ProgramFiles%... which... for x64, is WRONG.

I've noticed that lots of other 32 bit software has this failing under x64 - but then I assumed that they were using %ProgamFiles% themselves, as a literal element in their .lnk creation code. However, it appears to be that IShellLink is forcing this bug into existence, and I don't have a work-around (or perhaps that the link property editor in the shell is responsible for the problem and the underlying link is okay).

A few Google searches have turned up nothing... has anyone else encountered this or know of an article / example of how to force x64 windows to not muck this up?

Clarifying example:

hr = m_shell_link->SetIconLocation("C:\\Program Files (x86)\\Acme\\Prog.exe", 0);


Will result in a shortcut which has the correct icon, but when you press "Change icon" in the shortcut properties page, will report "Windows can't find the file %ProgramFiles%\Acme\Prog.exe.")

Answer

Convert the name into a short filename, and it will only convert the drive letter, yet keep the correct path.

        PWCHAR pIcon = L"C:\\Program Files (x86)\\Myfoo\\Bar.exe";
        DWORD dwLen = GetShortPathName(pIcon, NULL, 0);
        PWCHAR pShort = NULL; 
        if (dwLen) {
            pShort = new WCHAR[dwLen];
            dwLen = GetShortPathName(pIcon, pShort, dwLen);
            if (!dwLen) {
                delete [] pShort;
                pShort = NULL;
            }
        }

        if (NULL == pShort) {
            psl->SetIconLocation(pIcon,iTmp);
        } else {
            psl->SetIconLocation(pShort,iTmp);
        }
        delete [] pShort;