【问题标题】:Use Icon from shell32.dll as shortcut icon使用 shell32.dll 中的图标作为快捷方式图标
【发布时间】:2017-12-01 22:30:33
【问题描述】:

我正在尝试设置指向文件夹的快捷方式图标,但找不到任何有关如何从 shell32.dll 将快捷方式图标设置为本机图标的资源。我在 Rykler 的 msdn 上找到了This 答案,但答案已经过时了。任何帮助将不胜感激。

代码

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 结构:(取自This问题)

[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);
}

【问题讨论】:

  • "但 Visual Studio 抛出错误" 任何时候出现错误消息时,最好将其作为问题的一部分进行分享。
  • “ExpandEnvironmentStrings”方法没有重载需要 2 个参数。我认为我正在查看的答案已经过时了。
  • ExpandEnvironmentStrings 没有出现在您的代码中,那怎么会出现在错误中?
  • msdn 上列出的答案使用ExpandEnvironmentStrings
  • 也许这个库会对你有所帮助:github.com/securifybv/ShellLink

标签: c# windows icons


【解决方案1】:

所以,经过一番研究,它似乎并不太复杂。首先,从this question 获取接口声明。在您的项目中包含声明。

之后,您可以使用此代码:

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);
    }
}

要补充一点:此示例不包含错误检查!您不知道快捷方式是否已创建。因此,将调用的接口方法更改为返回整数并添加异常检查:

//...

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);

现在您可以检查创建快捷方式是否有效。

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);
    }

}

示例结果:

【讨论】:

  • 看起来很糟糕,考虑一下我链接的帖子。也不需要显式错误检查,任何 COM 错误代码都会自动转换为 CLR 异常。
  • 我知道它看起来很糟糕,但我尝试了上面的代码,没有错误检查和写保护文件夹,并且在调用 Save 时没有 CLR 异常。我已经阅读了有关自动化对象的信息,但我只是通过直接调用采取了相反的方式。由于我对该主题没有足够的实际经验,因此我无法判断哪种方法更好或更面向未来。但我同意这种错误检查很糟糕。
  • 还有一点,原来的问题有点不清楚:他为什么用SHGetFileInfo。在this question 他们从句柄获取文件夹图标。因此,如果提问者想要特定文件夹的图标,他将不得不使用该代码部分,将其存储在 .ico 中并将其用作快捷方式的图标?还是我错过了什么?
猜你喜欢
  • 2012-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多