【问题标题】:Using system icons for TreeView in C#在 C# 中使用 TreeView 的系统图标
【发布时间】:2017-07-04 10:27:21
【问题描述】:

我正在制作一个文件传输应用程序,我需要使用系统图标,以便图标可以匹配不同版本的 Windows。它们是远程文件,所以我不能只使用 SHFILEINFO。

【问题讨论】:

  • 呃,这是 C# 还是 C?您可能想要更改标题或 C# 标记。你所说的“远处”是指在另一台机器上?
  • 对不起,错字:(是的,它在另一台计算机上(这是我自己的协议,不是标准的 TCP 或 SMB)
  • 好的,只需要一点信息:您的应用程序是基于 WPF 还是 WindowsForms?并且图标将显示在您的应用程序的树视图中?
  • 它是 WindowsForms,是的,我需要在应用程序的树视图中显示图标。谢谢
  • 在这种情况下 shfileinfo 应该可以工作。您只是不传递整个文件名,而只传递扩展名。检查stackoverflow.com/q/2701263/937093

标签: c# winforms treeview icons system


【解决方案1】:

所以,我通过使用 CodeProject 中的这个非常好的示例来实现它:

public class IconReader
{
    /// <summary>
    /// Options to specify the size of icons to return.
    /// </summary>
    public enum IconSize
    {
        /// <summary>
        /// Specify large icon - 32 pixels by 32 pixels.
        /// </summary>
        Large = 0,
        /// <summary>
        /// Specify small icon - 16 pixels by 16 pixels.
        /// </summary>
        Small = 1
    }

    /// <summary>
    /// Options to specify whether folders should be in the open or closed state.
    /// </summary>
    public enum FolderType
    {
        /// <summary>
        /// Specify open folder.
        /// </summary>
        Open = 0,
        /// <summary>
        /// Specify closed folder.
        /// </summary>
        Closed = 1
    }

    /// <summary>
    /// Returns an icon for a given file - indicated by the name parameter.
    /// </summary>
    /// <param name="name">Pathname for file.</param>
    /// <param name="size">Large or small</param>
    /// <param name="linkOverlay">Whether to include the link icon</param>
    /// <returns>System.Drawing.Icon</returns>
    public static System.Drawing.Icon GetFileIcon(string name, IconSize size, bool linkOverlay)
    {
        Shell32.SHFILEINFO shfi = new Shell32.SHFILEINFO();
        uint flags = Shell32.SHGFI_ICON | Shell32.SHGFI_USEFILEATTRIBUTES;

        if (true == linkOverlay) flags += Shell32.SHGFI_LINKOVERLAY;

        /* Check the size specified for return. */
        if (IconSize.Small == size)
        {
            flags += Shell32.SHGFI_SMALLICON;
        }
        else
        {
            flags += Shell32.SHGFI_LARGEICON;
        }

        Shell32.SHGetFileInfo(name,
            Shell32.FILE_ATTRIBUTE_NORMAL,
            ref shfi,
            (uint)System.Runtime.InteropServices.Marshal.SizeOf(shfi),
            flags);

        // Copy (clone) the returned icon to a new object, thus allowing us to clean-up properly
        System.Drawing.Icon icon = (System.Drawing.Icon)System.Drawing.Icon.FromHandle(shfi.hIcon).Clone();
        User32.DestroyIcon(shfi.hIcon);     // Cleanup
        return icon;
    }

    /// <summary>
    /// Used to access system folder icons.
    /// </summary>
    /// <param name="size">Specify large or small icons.</param>
    /// <param name="folderType">Specify open or closed FolderType.</param>
    /// <returns>System.Drawing.Icon</returns>
    public static System.Drawing.Icon GetFolderIcon(IconSize size, FolderType folderType)
    {
        // Need to add size check, although errors generated at present!
        uint flags = Shell32.SHGFI_ICON | Shell32.SHGFI_USEFILEATTRIBUTES;

        if (FolderType.Open == folderType)
        {
            flags += Shell32.SHGFI_OPENICON;
        }

        if (IconSize.Small == size)
        {
            flags += Shell32.SHGFI_SMALLICON;
        }
        else
        {
            flags += Shell32.SHGFI_LARGEICON;
        }

        // Get the folder icon
        Shell32.SHFILEINFO shfi = new Shell32.SHFILEINFO();
        Shell32.SHGetFileInfo(@"Folder",
            Shell32.FILE_ATTRIBUTE_DIRECTORY,
            ref shfi,
            (uint)System.Runtime.InteropServices.Marshal.SizeOf(shfi),
            flags);

        System.Drawing.Icon.FromHandle(shfi.hIcon); // Load the icon from an HICON handle

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

        User32.DestroyIcon(shfi.hIcon);     // Cleanup
        return icon;
    }

    public static System.Drawing.Icon GetDriveIcon(IconSize size, FolderType folderType)
    {
        // Need to add size check, although errors generated at present!
        uint flags = Shell32.SHGFI_ICON | Shell32.SHGFI_USEFILEATTRIBUTES;

        if (FolderType.Open == folderType)
        {
            flags += Shell32.SHGFI_OPENICON;
        }

        if (IconSize.Small == size)
        {
            flags += Shell32.SHGFI_SMALLICON;
        }
        else
        {
            flags += Shell32.SHGFI_LARGEICON;
        }

        // Get the folder icon
        Shell32.SHFILEINFO shfi = new Shell32.SHFILEINFO();
        Shell32.SHGetFileInfo(null,
            Shell32.FILE_ATTRIBUTE_DIRECTORY,
            ref shfi,
            (uint)System.Runtime.InteropServices.Marshal.SizeOf(shfi),
            flags);

        System.Drawing.Icon.FromHandle(shfi.hIcon); // Load the icon from an HICON handle

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

        User32.DestroyIcon(shfi.hIcon);     // Cleanup
        return icon;
    }
}

/// <summary>
/// Wraps necessary Shell32.dll structures and functions required to retrieve Icon Handles using SHGetFileInfo. Code
/// courtesy of MSDN Cold Rooster Consulting case study.
/// </summary>
/// 

// This code has been left largely untouched from that in the CRC example. The main changes have been moving
// the icon reading code over to the IconReader type.
public class Shell32
{

    public const int MAX_PATH = 256;
    [StructLayout(LayoutKind.Sequential)]
    public struct SHITEMID
    {
        public ushort cb;
        [MarshalAs(UnmanagedType.LPArray)]
        public byte[] abID;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct ITEMIDLIST
    {
        public SHITEMID mkid;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct BROWSEINFO
    {
        public IntPtr hwndOwner;
        public IntPtr pidlRoot;
        public IntPtr pszDisplayName;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string lpszTitle;
        public uint ulFlags;
        public IntPtr lpfn;
        public int lParam;
        public IntPtr iImage;
    }

    // Browsing for directory.
    public const uint BIF_RETURNONLYFSDIRS = 0x0001;
    public const uint BIF_DONTGOBELOWDOMAIN = 0x0002;
    public const uint BIF_STATUSTEXT = 0x0004;
    public const uint BIF_RETURNFSANCESTORS = 0x0008;
    public const uint BIF_EDITBOX = 0x0010;
    public const uint BIF_VALIDATE = 0x0020;
    public const uint BIF_NEWDIALOGSTYLE = 0x0040;
    public const uint BIF_USENEWUI = (BIF_NEWDIALOGSTYLE | BIF_EDITBOX);
    public const uint BIF_BROWSEINCLUDEURLS = 0x0080;
    public const uint BIF_BROWSEFORCOMPUTER = 0x1000;
    public const uint BIF_BROWSEFORPRINTER = 0x2000;
    public const uint BIF_BROWSEINCLUDEFILES = 0x4000;
    public const uint BIF_SHAREABLE = 0x8000;

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

    public const uint SHGFI_ICON = 0x000000100;     // get icon
    public const uint SHGFI_DISPLAYNAME = 0x000000200;     // get display name
    public const uint SHGFI_TYPENAME = 0x000000400;     // get type name
    public const uint SHGFI_ATTRIBUTES = 0x000000800;     // get attributes
    public const uint SHGFI_ICONLOCATION = 0x000001000;     // get icon location
    public const uint SHGFI_EXETYPE = 0x000002000;     // return exe type
    public const uint SHGFI_SYSICONINDEX = 0x000004000;     // get system icon index
    public const uint SHGFI_LINKOVERLAY = 0x000008000;     // put a link overlay on icon
    public const uint SHGFI_SELECTED = 0x000010000;     // show icon in selected state
    public const uint SHGFI_ATTR_SPECIFIED = 0x000020000;     // get only specified attributes
    public const uint SHGFI_LARGEICON = 0x000000000;     // get large icon
    public const uint SHGFI_SMALLICON = 0x000000001;     // get small icon
    public const uint SHGFI_OPENICON = 0x000000002;     // get open icon
    public const uint SHGFI_SHELLICONSIZE = 0x000000004;     // get shell size icon
    public const uint SHGFI_PIDL = 0x000000008;     // pszPath is a pidl
    public const uint SHGFI_USEFILEATTRIBUTES = 0x000000010;     // use passed dwFileAttribute
    public const uint SHGFI_ADDOVERLAYS = 0x000000020;     // apply the appropriate overlays
    public const uint SHGFI_OVERLAYINDEX = 0x000000040;     // Get the index of the overlay

    public const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
    public const uint FILE_ATTRIBUTE_NORMAL = 0x00000080;

    [DllImport("Shell32.dll")]
    public static extern IntPtr SHGetFileInfo(
        string pszPath,
        uint dwFileAttributes,
        ref SHFILEINFO psfi,
        uint cbFileInfo,
        uint uFlags
        );
}

/// <summary>
/// Wraps necessary functions imported from User32.dll. Code courtesy of MSDN Cold Rooster Consulting example.
/// </summary>
public class User32
{
    /// <summary>
    /// Provides access to function required to delete handle. This method is used internally
    /// and is not required to be called separately.
    /// </summary>
    /// <param name="hIcon">Pointer to icon handle.</param>
    /// <returns>N/A</returns>
    [DllImport("User32.dll")]
    public static extern int DestroyIcon(IntPtr hIcon);
}

但是,还有一个问题:图标看起来很糟糕!这是一个屏幕截图:

有人知道我该如何解决这个问题吗?

【讨论】:

  • 对我来说也一样 :( Blech!那些图标太恶心了!对不起..
  • @Momoro 老实说,已经3年了,我还没弄明白?
  • 也许使用您自己的自定义图标可以替代? docs.microsoft.com/en-us/dotnet/framework/winforms/controls/… 是一个非常好的 - 需要一些额外的工作,但:D
  • 从你 3 年前的截图来看,图片看起来有点失真。我使用了这个答案中的代码,驱动器图像的背景是黑色的,而不是透明的。我建议保存驱动器图像并使背景透明,而不是尝试通过代码使其透明。您可以使用GetDriveIcon()bmp.Save() 方法将驱动器映像保存为BMP。谷歌“在 C# 中保存 BMP”,它应该会出现。
  • 另外,您能否链接您找到此代码的 CodeProject 页面?谢谢;)
猜你喜欢
  • 2012-02-14
  • 1970-01-01
  • 2011-06-25
  • 2016-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-23
相关资源
最近更新 更多