在列表视图中显示文件夹图标

2024-04-15

我已经设法使用 shell32 提取在列表视图中显示文件的图标,但是当对文件夹执行此操作时,图标似乎不显示。怎么会这样?

这是我的 Shell 提取代码:

' declare the Win32 API function SHGetFileInfo'
Public Declare Auto Function SHGetFileInfo Lib "shell32.dll" (ByVal pszPath As String, ByVal dwFileAttributes As Integer, ByRef psfi As SHFILEINFO, ByVal cbFileInfo As Integer, ByVal uFlags As Integer) As IntPtr
' declare some constants that SHGetFileInfo requires'
Public Const SHGFI_ICON As Integer = &H100
Public Const SHGFI_SMALLICON As Integer = &H1
' define the SHFILEINFO structure'
Structure SHFILEINFO
    Public hIcon As IntPtr
    Public iIcon As Integer
    Public dwAttributes As Integer
    <Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst:=260)> _
    Public szDisplayName As String
    <Runtime.InteropServices.MarshalAs(Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst:=80)> _
    Public szTypeName As String
End Structure

Function RetrieveShellIcon(ByVal argPath As String) As Image
    Dim mShellFileInfo As SHFILEINFO
    Dim mSmallImage As IntPtr
    Dim mIcon As System.Drawing.Icon
    Dim mCompositeImage As Image
    mShellFileInfo = New SHFILEINFO
    mShellFileInfo.szDisplayName = New String(Chr(0), 260)
    mShellFileInfo.szTypeName = New String(Chr(0), 80)
    mSmallImage = SHGetFileInfo(argPath, 0, mShellFileInfo, System.Runtime.InteropServices.Marshal.SizeOf(mShellFileInfo), SHGFI_ICON Or SHGFI_SMALLICON)
    ' create the icon from the icon handle'
    Try
        mIcon = System.Drawing.Icon.FromHandle(mShellFileInfo.hIcon)
        mCompositeImage = mIcon.ToBitmap
    Catch ex As Exception
        ' create a blank black bitmap to return'
        mCompositeImage = New Bitmap(16, 16)
    End Try
    ' return the composited image'
    Return mCompositeImage
End Function

Function GetIcon(ByVal argFilePath As String) As Image
    Dim mFileExtension As String = System.IO.Path.GetExtension(argFilePath)
    ' add the image if it doesn't exist''
    If cIcons.ContainsKey(mFileExtension) = False Then
        cIcons.Add(mFileExtension, RetrieveShellIcon(argFilePath))
    End If
    ' return the image'
    Return cIcons(mFileExtension)
End Function

这就是我显示文件图标的方式。

    Dim lvi As ListViewItem
    Dim di As New DirectoryInfo(Form2.TextBox1.Text)
    Dim exts As New List(Of String)
    ImageList1.Images.Clear()
    If di.Exists = False Then
        MessageBox.Show("Source path is not found", "Directory Not Found", MessageBoxButtons.OK, MessageBoxIcon.Error)
    Else
        For Each fi As FileInfo In di.EnumerateFiles("*.*")

            lvi = New ListViewItem
            lvi.Text = fi.Name

            lvi.SubItems.Add(((fi.Length / 1024)).ToString("0.00"))
            lvi.SubItems.Add(fi.CreationTime)

            If exts.Contains(fi.Extension) = False Then
                Dim mShellIconManager As New Form1
                For Each mFilePath As String In My.Computer.FileSystem.GetFiles(Form2.TextBox1.Text)
                    ImageList1.Images.Add(fi.Extension, GetIcon(mFilePath))
                    exts.Add(fi.Extension)
                Next

            End If
            lvi.ImageKey = fi.Extension
            ListView1.Items.Add(lvi)
        Next

这就是我显示文件夹图标的方式,但似乎不起作用

For Each fldr As String In Directory.GetDirectories(Form2.TextBox1.Text)
            Dim mShellIconManager As New Form1

            lvi = New ListViewItem
            lvi.Text = Path.GetFileName(fldr)

            lvi.SubItems.Add(((fldr.Length / 1024)).ToString("0.00"))
            lvi.SubItems.Add(Directory.GetCreationTime(fldr))


            ImageList1.Images.Add(GetIcon(fldr))
            ListView1.Items.Add(lvi)            
Next

您的代码中有几件事。其中一些看起来像是之前尝试的残留物。无论如何,这是有效的:

Public Partial Class NativeMethods
    Private Const MAX_PATH As Integer = 256
    Private Const NAMESIZE As Integer = 80
    Private Const SHGFI_ICON As Int32 = &H100

    <StructLayout(LayoutKind.Sequential)> 
    Private Structure SHFILEINFO
        Public hIcon As IntPtr
        Public iIcon As Integer
        Public dwAttributes As Integer
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=MAX_PATH)>
        Public szDisplayName As String
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=NAMESIZE)>
        Public szTypeName As String
    End Structure

    <DllImport("Shell32.dll")> 
    Private Shared Function SHGetFileInfo(pszPath As String,
                                          dwFileAttributes As Integer,
                                          ByRef psfi As SHFILEINFO,
                                          cbFileInfo As Integer,
                                          uFlags As Integer) As IntPtr
    End Function

    <DllImport("user32.dll", SetLastError:=True)>
    Private Shared Function DestroyIcon(hIcon As IntPtr) As Boolean
    End Function

    Public Shared Function GetShellIcon(path As String) As Bitmap
        Dim shfi As SHFILEINFO = New SHFILEINFO()

        Dim ret As IntPtr = SHGetFileInfo(path, 0, shfi, Marshal.SizeOf(shfi), SHGFI_ICON)
        If ret <> IntPtr.Zero Then
            Dim bmp As Bitmap = System.Drawing.Icon.FromHandle(shfi.hIcon).ToBitmap
            DestroyIcon(shfi.hIcon)
            Return bmp
        Else
            Return Nothing
        End If
    End Function
End Class

将 PInvoke 代码放入其自己的类中有几个好处。首先,它有助于将代码与所有这些幻数、结构和常量隔离开来。 PInvoke 可以是私有的并通过方法公开(GetShellIcon) 它完成所有 scut 工作并调用 API 方法。此外,当从 VS CodeAnalysis 工具中使用它时,它不会抱怨它。NativeMethods班级。

您的代码没有做的事情之一是销毁检索到的图标并释放该资源;还有你的SHGetFileInfo看起来不对,这可能会导致不好的事情。当它无法获取图标时,我不会在 PInvoke 代码中创建空白/空位图,而是返回Nothing供代码处理。

最后封装了PInvoke代码,使用起来更方便,也更短:

Dim fPath As String = "C:\Temp"
Dim di = New DirectoryInfo(fPath)
' store imagelist index for known/found file types
Dim exts As New Dictionary(Of String, Int32)

Dim img As Image
Dim lvi As ListViewItem
For Each d In di.EnumerateDirectories("*.*", SearchOption.TopDirectoryOnly)
    lvi = New ListViewItem(d.Name)
    lvi.SubItems.Add("")        ' no file name
    lvi.SubItems.Add(Directory.GetFiles(d.FullName).Count().ToString)

    myLV.Items.Add(lvi)

    img = NativeMethods.GetShellIcon(d.FullName)
    imgLst.Images.Add(img)
    lvi.ImageIndex = imgLst.Images.Count - 1
Next

For Each f In di.EnumerateFiles("*.*")
    lvi = New ListViewItem(f.DirectoryName)
    lvi.SubItems.Add(f.Name)        ' no file name
    lvi.SubItems.Add("n/a")

    myLV.Items.Add(lvi)
    If exts.ContainsKey(f.Extension) = False Then
        ' try simplest method
        img = Drawing.Icon.ExtractAssociatedIcon(f.FullName).ToBitmap
        If img Is Nothing Then
            img = NativeMethods.GetShellIcon(f.FullName)
        End If
        If img IsNot Nothing Then
            imgLst.Images.Add(img)
            exts.Add(f.Extension, imgLst.Images.Count - 1)
        Else
            ' ?? use some default or custom '?' one?
        End If

    End If

    lvi.ImageIndex = exts(f.Extension)
Next

对于文件,它首先尝试使用 NET 获取图标Icon.ExtractAssociatedIcon方法并求助于因某种原因失败的 PInvoke。

我改变了exts List(Of String to a Dictionary(Of String, Int32)。一旦代码获取扩展程序的图标,它就会将该图像的索引保存在ImageList这样就不需要再次查找扩展名/图标。这在大型文件夹上加快了相当多的速度。

如果您声明Dictionary在方法之外,然后不清除ImageList每次,您都可以让它们在运行时积累图像。这text file文件夹中的图标Foo不会与其他地方的文本文件的图像不同。

Result:
enter image description hereenter image description here

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在列表视图中显示文件夹图标 的相关文章

随机推荐

  • 在 postgresql 中查找主机名[重复]

    这个问题在这里已经有答案了 是否可以像 MS SQL Server 那样使用简单的语法 SELECT HOST NAME 在 postgresql 9 3 2 中 我读过一些文章但没有结果 不 默认版本没有这个功能 然而 使用新的本机函数扩
  • 从一个 python 脚本输出检查过期日期的代码

    我有一个预制的 Python 脚本 可以在地址服务器中调用 C 脚本 该脚本的输出是 Build Number 2381 Database Date 2015 07 15 Database Expiration Date 10 31 201
  • 如何使用键值编码判断对象是否存在键?

    我想测试iPhone SDK中的对象是否具有可写的 property 一种可能的方法是检查 valueForKey 方法 但这看起来相当不优雅 Example try id value instance valueForKey myProp
  • jQuery 选择器错误?组合选择器与简单选择器和 find()

    我的情况很尴尬 我有这样的事情 div div
  • CoreData 按属性划分的唯一对象

    我有一个图表 其中包含一种名为 消息 的对象 一条消息可以有子项 因此该图是一棵树 图上的每个对象都包含一个属性值 这是一种 UUID 全局唯一 因此存储不能包含具有相同 UUID 的多条消息 此 uuid 是从消息数据中获取的字符串 因此
  • 使用PBKDF2 java解密和加密

    有没有办法解密PBKDF2java中的密码 Java有实现PBKDF2算法为PBKDF2WithHmacSHA1 我得到了为密码创建哈希值的代码 我参考了下面的链接来了解哈希技术 http howtodoinjava com securit
  • Rails 5 - 找不到生成器“rspec:安装”

    在我的 Rails 5 0 0 应用程序中 我已将以下内容添加到我的 Gemfile 中 group development test do gem byebug platform mri gem rspec rails gt 3 5 gt
  • 使用 React 测试库提交后测试重定向

    我正在尝试测试登录组件 具体来说 它会在成功登录时重定向 手动测试时效果很好 但在我的测试中 它从不进行重定向 因此找不到 注销 链接 test successfully logs the in the user async gt cons
  • 使用 INDY 检测远程服务器上文件的 Mime 类型

    我一直在使用 Synapse 库从互联网下载文件 但我最近将我的应用程序转换为使用 INDY 并且我缺少 Synapse 库中更好的功能之一 即能够轻松获取我在将其保存到本地计算机之前从服务器下载的文件 INDY 是否具有此功能 如果有 我
  • Excel 中的数组常量

    我在单元格 A1 中定义了一个数组常量为 1 2 3 这显示为 1 数组中的第一个值 我想让公式 SUM A1 返回 6 但是 SUM 使用 A1 作为单单元数组 而不是 A1 中包含的数组常量 因此 SUM A1 返回 1 同样 我希望
  • 使用脚本更新 Google 电子表格数据透视表范围

    如何使用脚本编辑 Google 文档电子表格中数据透视表的数据范围 Or 是否可以对数据透视表范围使用命名范围 不幸的是 此时 2012 年 7 月 31 日 我相信答案是 你不能 和 不 我可以建议的唯一解决方法是 1 使用 QUERY
  • ORMLite 和惰性集合的问题

    我在我的 android 项目中使用 ormlite 我有两节课 DatabaseTable tableName usershows public class UserShow DatabaseField id true private I
  • 使用 c# 和 xaml 在 Metro 应用程序中显示 svg

    我正在使用 XAML 和 C 开发 Windows 8 Metro 应用程序 我有一个 SVG 图像的 Uri 它确实有效 但我不知道如何获取此图像并将其显示在 XAML 中 或者是否无法在 NET Core 中使用 SVG 一种方法是将
  • 尽管不再支持 TomCat,如何在 Plesk Onyx 17.8 中部署 .war 文件?

    Plesk Onyx 及之前版本 17 5 附带 Tomcat 安装 无需安装不再受支持 https support plesk com hc en us articles 115005115774从 17 8 版本开始 因此 不再可以部署
  • 如何在 Azure AD B2C 中启用电子邮件验证

    如何在 B2C 中使用自定义策略启用电子邮件验证 为了对其进行逆向工程 我尝试在内置策略中禁用它并下载该策略 我尝试将该元数据项添加到我自称的技术配置文件中 但这不起作用 逆向工程测试 内置策略
  • React-native-navigation:goBack() 不起作用

    我在 React Native 中使用 React Navigation 和 Redux 导航工作正常 但在一个屏幕上 goBack 函数不起作用 你能告诉我们为什么吗 这是标题配置 static navigationOptions hea
  • Doctrine_Core::getTable()->findAll() 如何指定顺序?

    当使用Doctrine Table对象 使用时是否可以指定返回集合的顺序findAll or findByWhatever In the doc s http www doctrine project org api orm 1 2 doc
  • 使用 Dependency Walker 分析 x86 可执行文件在 Windows 7 x64 上挂起

    在Windows 7下x64 当我尝试分析一个x86使用最新版本的 Dependency Walker 2 2 6000 可执行文件时 分析过程总是在某个点挂起 大多数时候最后加载的 DLL 是c windows syswow64 URLM
  • Apps 脚本正则表达式 - 不区分大小写

    我正在为 Google 文档编写应用程序脚本 我正在使用 findText 来查找指定字符串的实例 默认情况下 它区分大小写 我需要删除它 但我不知道如何将 i 添加到 re2 正则表达式 以便它在应用程序脚本引擎中工作 在我的示例中 我尝
  • 在列表视图中显示文件夹图标

    我已经设法使用 shell32 提取在列表视图中显示文件的图标 但是当对文件夹执行此操作时 图标似乎不显示 怎么会这样 这是我的 Shell 提取代码 declare the Win32 API function SHGetFileInfo