0

I am trying to set the icon of a shortcut pointing to a folder, but cannot find any resources on how to set a shortcut icon to a native icon from shell32.dll. I found This answer on msdn by Rykler, but the answer is outdated. Any help would be appreciated.

Code

SHFILEINFO shinfo = new SHFILEINFO();
Win32.SHGetFileInfo(filename, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), (int)0x1000);
// icon index # and path
int IconIndex = shinfo.iIcon
string IconPath = shinfo.szDisplayName
shortcut.IconLocation = ???

SHFILEINFO struct: (Taken from This question)

[StructLayout(LayoutKind.Sequential)]
public struct SHFILEINFO
{
    public IntPtr hIcon;
    public int iIcon;
    public uint dwAttributes;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
    public string szDisplayName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
    public string szTypeName;
};

class Win32
{
    [DllImport("shell32.dll")]
    public static extern IntPtr SHGetFileInfo(string pszPath, uint 
dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);
}
Jack Sullivan
  • 199
  • 1
  • 1
  • 10

1 Answers1

0

So, after a little research, it seems not too complicate. At first, take the interface declarations from this question. Include the declarations in your project.

After that, you can use this code:

public class Q47602417
{
    public static void MakeShortcut(string targetPath)
    {
        var shellLink = new ShellLink();
        ((IShellLinkW)shellLink).SetDescription("Sample Shortcut");
        ((IShellLinkW)shellLink).SetPath(targetPath);
        ((IShellLinkW)shellLink).SetIconLocation(Environment.SystemDirectory + "\\Shell32.dll", 12);
        ((IPersistFile)shellLink).Save(@"C:\temp\shortcut.lnk", false);
    }
}

One thing to add: this sample contains no error checking! You don't know if the shortcut was created or not. So, change the called interface methods to return integers and add exception checking:

//...

int SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
int SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
int SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);

//.. omitted other details ...

int Save([In, MarshalAs(UnmanagedType.LPWStr)] string pszFileName, [In, MarshalAs(UnmanagedType.Bool)] bool fRemember);

Now you can check if creating the shortcut acutally works.

public class Q47602417
{

    public static void MakeShortcut(string targetPath)
    {
        ShellLink shellLink = new ShellLink();
        int hr;
        hr = ((IShellLinkW)shellLink).SetDescription("Sample Shortcut");
        Marshal.ThrowExceptionForHR(hr);

        hr = ((IShellLinkW)shellLink).SetPath(targetPath);
        Marshal.ThrowExceptionForHR(hr);

        hr = ((IShellLinkW)shellLink).SetIconLocation(Environment.SystemDirectory + "\\Shell32.dll", 12);
        Marshal.ThrowExceptionForHR(hr);

        hr = ((IPersistFile)shellLink).Save(@"C:\temp\shortcut.lnk", false);
        Marshal.ThrowExceptionForHR(hr);
    }

}

Example result:

enter image description here

ventiseis
  • 3,029
  • 11
  • 32
  • 49
  • Looks quite awful, consider the post I linked. No need for explicit error checking either, any COM error code is automatically turned into a CLR exception. – Hans Passant Dec 04 '17 at 11:04
  • I know it looks awful, but I tried the above code without error checking and a write protected folder and there wasn't a CLR exception on the call to `Save`. I've read about the automation objects but I simply took the other way round via direct calls. As I've not enough real-world experience with that topic, I can't judge which method is better or more future-proof. But I agree that this kind of error checking is awful. – ventiseis Dec 04 '17 at 13:54
  • Another thing is that the original question is a little unclear: why is he using `SHGetFileInfo`. In [this question](https://stackoverflow.com/questions/1599235/how-do-i-fetch-the-folder-icon-on-windows-7-using-shell32-shgetfileinfo) their getting the folder icon from an handle. So, if the questioner wants the icon of a specific folder, he'll has to use that code part, store it in an `.ico` and use that as an icon for the shortcut? Or am I missing something? – ventiseis Dec 04 '17 at 14:00