为啥我在使用 SHFileInfo 时得到错误的 SpecialFolder 图标?

Posted

技术标签:

【中文标题】为啥我在使用 SHFileInfo 时得到错误的 SpecialFolder 图标?【英文标题】:Why do I get the wrong SpecialFolder icon when using SHFileInfo?为什么我在使用 SHFileInfo 时得到错误的 SpecialFolder 图标? 【发布时间】:2013-09-11 16:16:19 【问题描述】:

我正在使用SHFileInfo 来检索文件和文件夹的系统图标,但是我发现特殊文件夹没有返回正确的文件夹图标。

例如,Desktop 文件夹将返回与常规文件夹相同的文件夹图标而不是 Desktop 图标,MyComputer 图标看起来像旧的 Windows 98 图标,而不是我预期的 Windows 7 MyComputer 图标。

为什么我得到了错误的特殊文件夹图标,以及如何使用SHFileInfo 检索特殊文件夹的正确系统图标?

我的原始代码来自this codeproject article,但经过了一些修改。不过,实际执行的代码仍然非常相似,如下所示:

public static System.Drawing.Icon GetFolderIcon(string folderPath, IconSize size, FolderType folderType)

    try
    
        // Need to add size check, although errors generated at present!
        Int64 flags = WinApi.SHGFI_ICON | WinApi.SHGFI_USEFILEATTRIBUTES;

        if (FolderType.Open == folderType)
            flags |= WinApi.SHGFI_OPENICON;

        if (IconSize.Small == size)
            flags |= WinApi.SHGFI_SMALLICON;
        else
            flags |= WinApi.SHGFI_LARGEICON;

        // Get the folder icon
        WinApi.SHFILEINFO shfi = new WinApi.SHFILEINFO();
        WinApi.SHGetFileInfo(folderPath,
            WinApi.FILE_ATTRIBUTE_DIRECTORY,
            ref shfi,
            (Int32)System.Runtime.InteropServices.Marshal.SizeOf(shfi),
            flags);

        if (shfi.hIcon == IntPtr.Zero)
            return null;

        // Now clone the icon, so that it can be successfully stored in an ImageList
        System.Drawing.Icon icon = (System.Drawing.Icon)System.Drawing.Icon.FromHandle(shfi.hIcon).Clone();

        WinApi.DestroyIcon(shfi.hIcon);     // Cleanup
        return icon;
    
    catch (Exception ex)
    
        // Log Error
    

    return null;

对它的调用如下所示:

var icon = IconUtil.GetFolderIcon(
    Environment.GetFolderPath(Environment.SpecialFolder.Desktop), 
    IconUtil.IconSize.Large, IconUtil.FolderType.Closed);

我得到的图标看起来像这样

而不是这个

【问题讨论】:

您可能需要使用 PIDL 而不是文件名。 最重要的是,您传递了SHGFI_USEFILEATTRIBUTES,这意味着“忽略文件的实际内容,并假装它是我告诉你的。”而你的伪装文件属性是FILE_ATTRIBUTE_DIRECTORY,这意味着“只是一个普通的无聊目录”。 @RaymondChen 谢谢,这似乎是我的问题。如果你把它写成答案,我会接受。 @EricBrown 谢谢,如果我想维护FILE_ATTRIBUTE_DIRECTORY 标志,这是一个很好的替代方法。如果其他人有兴趣,我发现了一个使用 PIDL here 的不错的代码示例。 【参考方案1】:

根据MSDN,SHGFI_USEFILEATTRIBUTES 标志:

表示函数不应尝试访问文件 由 pszPath 指定。相反,它应该像指定的文件一样 通过 pszPath 与 dwFileAttributes 中传递的文件属性存在。

我认为Raymond Chen's comment 提供了一个更容易理解的解释:

你传递了SHGFI_USEFILEATTRIBUTES 这意味着“忽略文件 实际上是,只是假装这是我告诉你的。”而你的 假装文件属性是FILE_ATTRIBUTE_DIRECTORY,这意味着“只是 一个普通无聊的目录。”

所以要解决我的问题,我只需要在想要获取文件夹特定图标时删除 SHGFI_USEFILEATTRIBUTES 标志。

Eric Brown's comment 还提供了一种有用的替代方法来使用 PIDL 执行此操作。可以在here 找到一个代码示例。

【讨论】:

您能分享一下您是如何使用这种方式获取 MyComputer 的图标的吗?我使用相同的方法来提取图标,但我似乎找不到如何提取 MyComputer 的图标,因为它没有实际路径。 @MaorB 如果我没记错的话,我是使用 Environment.SpecialFolder 枚举找到的。尝试使用Environment.GetFolderPath(Environment.SpecialFolder.MyComputer) 我已经尝试过了,但是Environment.GetFolderPath 方法为Environment.SpecialFolder.MyComputer 枚举返回了一个空路径,因为我的电脑没有实际路径。 @MaorB 我不确定我当时做了什么。我认为“我的电脑”问题中显示的第一个图标是在修复之前从空字符串返回的图标,或者我只是用“C:\”图标替换了“我的电脑”。

以上是关于为啥我在使用 SHFileInfo 时得到错误的 SpecialFolder 图标?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我在运行简单的 Spring Boot 应用程序时总是得到状态为“404”的 Whitelabel 错误页面

为啥我在 POST 到 Django REST 框架时得到“CSRF cookie not set”?

为啥我在尝试创建新的 qml 文件时得到 QmlCachedGenerateCode?

为啥我在这个 SASS 文件中得到一个未定义的 Foundation 变量错误?

为啥我在页面刷新时收到网络错误? (获取请求)

为啥我在使用 location.href 时总是被 CORS 阻止