API ShGetFileInfo: Icon holen

  • VB.NET
  • .NET (FX) 4.0

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von fichz.

    API ShGetFileInfo: Icon holen

    yo Leute,

    hab mal eine Frage ob hierzu eventuell wer eine bessere Lösung hat.
    Hintergrund: Ich speichere Dateipfade in eine Datenbank. Anzeigen tu ich diese in einem Grid welches eine Spalte "Icon" besitzt. Hier zeige ich dann das dementsprechende Icon der Datei an.
    Das Icon lese ich mit folgender API:
    Spoiler anzeigen

    Visual Basic-Quellcode

    1. Namespace Helpers
    2. Public Class IconExtractor
    3. ' Constants that we need in the function call
    4. Private Const SHGFI_ICON As Integer = &H100
    5. Private Const SHGFI_SMALLICON As Integer = &H1
    6. Private Const SHGFI_LARGEICON As Integer = &H0
    7. ' This structure will contain information about the file
    8. Public Structure SHFILEINFO
    9. ' Handle to the icon representing the file
    10. Public hIcon As IntPtr
    11. ' Index of the icon within the image list
    12. Public iIcon As Integer
    13. ' Various attributes of the file
    14. Public dwAttributes As UInteger
    15. ' Path to the file
    16. <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
    17. Public szDisplayName As String
    18. ' File type
    19. <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=80)> _
    20. Public szTypeName As String
    21. End Structure
    22. ' The signature of SHGetFileInfo (located in Shell32.dll)
    23. <DllImport("Shell32.dll")> _
    24. Public Shared Function SHGetFileInfo(pszPath As String, dwFileAttributes As UInteger, ByRef psfi As SHFILEINFO, cbFileInfo As Integer, uFlags As UInteger) As IntPtr
    25. End Function
    26. ''' <summary>
    27. ''' Gibt ein kleines Icon retour
    28. ''' </summary>
    29. ''' <param name="FileName">Pfad zur Datei</param>
    30. ''' <returns></returns>
    31. ''' <remarks></remarks>
    32. Public Function GetSmallIcon(ByVal FileName As String) As Icon
    33. Return GetIcon(FileName, IconSize.Small)
    34. End Function
    35. ''' <summary>
    36. ''' Gibt ein großes Icon retour
    37. ''' </summary>
    38. ''' <param name="FileName">Pfad zur Datei</param>
    39. ''' <returns></returns>
    40. ''' <remarks></remarks>
    41. Public Function GetLargeIcon(ByVal FileName As String) As Icon
    42. Return GetIcon(FileName, IconSize.Large)
    43. End Function
    44. Private Function GetIcon(ByVal FileName As String, ByVal Size As IconSize) As Icon
    45. If Not System.IO.File.Exists(FileName) Then
    46. Throw New System.IO.FileNotFoundException()
    47. End If
    48. ' Will store a handle to the small icon
    49. Dim hImg As IntPtr
    50. Dim shinfo As New SHFILEINFO()
    51. ' Sore the icon in this myIcon object
    52. Dim myIcon As System.Drawing.Icon
    53. Select Case Size
    54. Case IconSize.Small
    55. ' Get a handle to the small icon
    56. hImg = SHGetFileInfo(FileName, 0, shinfo, Marshal.SizeOf(shinfo), SHGFI_ICON Or SHGFI_SMALLICON)
    57. Case IconSize.Large
    58. ' Get a handle to the large icon
    59. hImg = SHGetFileInfo(FileName, 0, shinfo, Marshal.SizeOf(shinfo), SHGFI_ICON Or SHGFI_LARGEICON)
    60. End Select
    61. ' Get the icon from the handle
    62. myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon)
    63. Return myIcon
    64. End Function
    65. Private Enum IconSize
    66. Small
    67. Large
    68. End Enum
    69. End Class
    70. End Namespace



    Hab das so in eine Klasse gepackt. Den Code an sich hab ich irgendwo ausn Internet.

    Code funktioniert pipifein.
    Jedoch dauert es je Aufruf rund 100ms. Hab ich nun 10 so Dateien anzuzeigen bin ich gleich mal bei einer Sekunde.

    - Kann man Icon auslesen irgendwie beschleunigen bzw. gibt es eine andere Möglichkeit?
    - Ich greife persönlich nicht so gerne Win-APIs an. Können irgendwelche Probleme mit solchen APIs auftreten?

    lg
    fichz
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten
    Hey,

    VB.NET-Quellcode

    1. Icon.ExtractAssociatedIcon("Path")


    existiert bereits im FrameWork. Musst mal schauen, ob das schneller arbeitet.
    Die Unendlichkeit ist weit. Vor allem gegen Ende. ?(
    Manche Menschen sind gar nicht dumm. Sie haben nur Pech beim Denken. 8o
    Ich glaube, wenn schon die WinAPI so langsam ist, wirst du es auf anderem Wege auch nicht schneller hinbekommen. Und wenn man sich ansieht, wie der Verzeichnisinhalt im Explorer bei einem neu geöffneten Ordner aufgebaut wird, hat auch Windows selbst keine bessere Methode. Dort wird offensichtlich zunächst ein Standard-Icon verwendet, welches dann in einem separaten Thread nachträglich gegen das assoziierte Icon ausgetauscht wird.
    Weltherrschaft erlangen: 1%
    Ist dein Problem erledigt? -> Dann markiere das Thema bitte entsprechend.
    Waren Beiträge dieser Diskussion dabei hilfreich? -> Dann klick dort jeweils auf den Hilfreich-Button.
    Danke.
    Hab mir die Sache mal in IL-Spy angesehen. Da wird auch nicht viel anders gemacht, als Du es bereits tust. Die Funktion (Wrapper), der eine Angabe der Größe zulässt, ist leider Private und somit nicht zu benutzen.
    Die Unendlichkeit ist weit. Vor allem gegen Ende. ?(
    Manche Menschen sind gar nicht dumm. Sie haben nur Pech beim Denken. 8o

    ThuCommix schrieb:

    Scale dein Icon doch einfach von 32x32 auf 16x16.
    Das meinst du nicht ernst, oder? ;)
    Ein von 32x32 auf 16x16 skaliertes Bild (möglicherweise noch ohne Interpolation) sieht in vielen Fällen (vor allem bei professionellen Icons) komplett anders (und schlechter) aus als ein direkt in 16x16-Pixelformat mit eingettetes separates Icon. Meinem Anspruch würde dies jedenfalls nicht genügen.
    Weltherrschaft erlangen: 1%
    Ist dein Problem erledigt? -> Dann markiere das Thema bitte entsprechend.
    Waren Beiträge dieser Diskussion dabei hilfreich? -> Dann klick dort jeweils auf den Hilfreich-Button.
    Danke.
    @ThuCommix
    Das ist keine Option da, wie bereits Arby sagte, der Qualitätsverlust zu hoch wäre.

    Was mir eventuell noch einfällt, wäre das Icon in die Datenbank mitzuspeichern. Somit würde es nur einmal laden müssen und das wäre beim Auswählen der Datei (und da fallen 100ms nicht auf mMn.) So ein 16x16 Bitmap kann ja nicht die "mörderische" Größe aufweisen denk ich.

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten

    ThuCommix schrieb:

    Scale dein Icon
    ist ein NoGo.
    Icons werden pixelgenau designed. Was, wenn die beiden Icons inhaltlich verschieden sind (kann passieren)?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    fichz schrieb:

    Code funktioniert pipifein.
    Jedoch dauert es je Aufruf rund 100ms. Hab ich nun 10 so Dateien anzuzeigen bin ich gleich mal bei einer Sekunde.

    Nee - nicht pipifein :D !
    Ich gebe Dir mal eine Vorlage aus der Praxis als Anhanltspunkt, da ich gerade ein Control baue, das diese API und Weitere benutzt.
    Gemessen auf einem PC mit normaler, "lowcost" Festplatte:
    176.843 Dateien auf "C:" rekursiv ermittelt, alle DateiInfos und die Icons geholt und das ganze in eine DataTable abgelegt (inkl. der Icons), daraus ein DataView gemacht und alles an ein DataGridView gebunden: 4,5 Sekunden zusammen!
    Von den 4,5 Sekunden brauchte das Icon holen bestimmt nur eine Sekunde für alle Dateien - wenns hochkommt.

    Du musst den Fehler vermutlich im Rest Deines Programms suchen.
    Und Deine Icons binär in die arme DB zu stopfen, löst Dein Problem nicht wirklich - verlagert es nur.

    Zeig doch mal Dein Werk ein bisschen genauer..

    LG,
    Bruno
    Du hast recht. Der Hinweis mit LW C:\ hat mich erleuchtet.
    Das Problem liegt nicht an der Funktion selbst, sondern daran, dass ich mit Dokumente auf einem Netzlaufwerk arbeite...
    Hatte nun testweise 3 Dokumente von C:\ ausgewählt und da war dies in ~ 15 ms erledigt
    auf dem Netzlaufwerk dauert dies leider ~500 ms.

    Denke daran werde ich nichts ändern können. Liegt scheinbar an der Geschwindigkeit des NW.

    Besten Dank

    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten