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

我怕爱的太早我们不能终老 提交于 2020-01-22 15:05:10

问题


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.")


回答1:


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;



回答2:


As user "pointoforder" points out in this issue report on GitHub, another fix is to unset the SLDF_HAS_EXP_ICON_SZ flag and remove the EXP_SZ_ICON_SIG data block from the IShellLinkDataList object. This comment has the according Delphi code snippet.




回答3:


When I was looking for a solution to create shortcuts in C# I found this post on StackOverflow.

Now I came across the problem described in this thread. I'm unsure where to post my solution but I guess this is the right place.

I added IShellLinkDataList and changed the Save() method as below:

#region IShellLinkDataList Interface
[ComImportAttribute()]
[GuidAttribute("45e2b4ae-b1c3-11d0-b92f-00a0c90312e1")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
private interface IShellLinkDataList
{
    void AddDataBlock(IntPtr pDataBlock);
    void CopyDataBlock(uint dwSig, out IntPtr ppDataBlock);
    void RemoveDataBlock(uint dwSig);
    void GetFlags(out uint pdwFlags);
    void SetFlags(uint dwFlags);
}
#endregion

private const uint SLDF_HAS_EXP_ICON_SZ = 0x00004000;
private const uint EXP_SZ_ICON_SIG = 0xA0000007;

public void Save(string linkFile)
{   
    // Save the object to disk
    uint flags;
    if (linkA == null)
    {
        ((IShellLinkDataList)linkW).GetFlags(out flags);
        flags = flags & ~SLDF_HAS_EXP_ICON_SZ;
        ((IShellLinkDataList)linkW).SetFlags(flags);
        ((IShellLinkDataList)linkW).RemoveDataBlock(EXP_SZ_ICON_SIG);
        ((IPersistFile)linkW).Save(linkFile, true);
        shortcutFile = linkFile;
    }
    else
    {
        ((IShellLinkDataList)linkA).GetFlags(out flags);
        flags = flags & ~SLDF_HAS_EXP_ICON_SZ;
        ((IShellLinkDataList)linkA).SetFlags(flags);
        ((IShellLinkDataList)linkA).RemoveDataBlock(EXP_SZ_ICON_SIG);
        ((IPersistFile)linkA).Save(linkFile, true);
        shortcutFile = linkFile;
    }
}


来源:https://stackoverflow.com/questions/2976489/ishelllinkseticonlocation-translates-my-icon-path-into-program-files-which-i

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!