Icon aus Datei Extrahieren -> FTP

  • VB.NET

Es gibt 62 Antworten in diesem Thema. Der letzte Beitrag () ist von ~blaze~.

    Um das jetzt noch mal klar zu stellen:
    Die Icons werden von den Programmen, die sie öffnen können, bereitgestellt, nicht von den Dateien selbst. Wenn man Dateien auf einen FTP-Server rauflädt, sind die Icons nicht dabei. Es gibt da allerdings Unterschiede. Beispielsweise werden bei .txt-Dateien die Icons von einem Programm bereitgestellt bzw. als Icon auf der Festplatte gespeichert. Ausführbare Dateien können Icons in ihren Resourcen zur Verfügung stellen. Ich denke jetzt nicht, dass standardmäßig andere Wege zur Icon-Gewinnung unterstützt werden. Für Iconresourcen verwendet man halt ExtractAssociatedIcon(Ex) und erstellt die Instanz der Icon-Klasse vom Handle. Bei Icondateien verwendet man den von der Icon-Klasse gebotenen Konstruktor und ggf. Environment.ExpandEnvironmentVariables. Problematisch ist halt nur, wenn der Eintrag wie z.B. bei .exe-Dateien aussieht, die ja ein dynamisches Icon haben. Den kann man nicht auswerten, ohne dass die Dateien heruntergeladen werden. Dumm ist auch, dass ich nicht die Argumentwerte der Format-Funktion weiß, die benötigt werden. %1 dürfte wohl der Dateiname sein, aber gibt es da noch andere Argumente und wo findet man sie? Wenn ihr mir die Informationen besorgt, versuch' ich, einen kurzen Code zusammenzuschreiben, der die Icons anhand der Extensions aus der Registry ermittelt. Da unterscheiden sich halt dann die Icons auf den verschiedenen Systemen. Das ist aber auch die vom Explorer verwendete Methode.

    Gruß
    ~blaze~
    Danke ~balze~,
    das habe ich nicht so schön erklärt.
    Ich versuche mal raus zu bekommen wie diese Argumente sind und wo man sie findet.

    ~blaze~ schrieb:

    Da unterscheiden sich halt dann die Icons auf den verschiedenen Systemen.

    und das währe sogar Perfekt. Dann währe die Methode automatisch immer up to date.

    ich melde mich sobal ich etwas habe.

    danke dir

    Bernd

    Edit:
    ich habe die frage mal bei msdn abgesetzt, dauert halt ein wenig bei denen.
    Icons stecken doch bekanntlich in der selben Stelle in den Dateien, sonst wüsste Windows auch nicht wo/was das Icon vom jeweiligen Programm ist.

    Du kannst also folgendes machen (erfordert vermutlich eine große Menge an Kenntnissen):

    Anstatt das du dir die Datei komplett auf den Rechner siehst holst du dir die Bytes, die das Icon beinhalten auf den Rechner und liest nur diese aus.
    So hast du die notwendige Downloadgröße auf 0,1% reduziert.

    Nachteil:

    - Du müsstest wissen an welcher Stelle im Code das Icon liegt und ich weiß auch nicht ob man mit dem Filereader nur bestimmte Bytes auslesen kann.
    Antwort von MSDN ist da.
    Hallo Bernd,

    die Werte die Du suchst stehen in HKEY_CLASSES_ROOT und zwar als Schlüssel DefaultIcon. In der Regel findest Du den Schlüssel in der ausgeschriebenen Version eines jeden Dateityps (z.B. dllfile statt dll).

    Die Werte des Schlüssels DefaultIcon sind aber nur Verweise auf Ressourcendateien oder eingebettete Ressourcen. Um diese Bilder zu nutzen, musst Du jeweillige Datei laden und die Ressource auslesen.

    Schöne Grüße

    Oliver


    Ich schaue nochmals mit regedit da rein.

    Edit:
    ~blaze~ , meinst du die ?
    Ja genau. Das war das was ich gemeint habe. Die Extension ist ja genau der Sub-Key des HKEY_CLASSES_ROOT und der Default-Eintrag verweist auf den Key, der das DefaultIcon definiert.
    Per Microsoft.Win32.RegistryKey kannst du auf die Schlüssel zugreifen (Microsoft.Win32.Registry enthält statische Felder, die auch den Classes-Root-Schlüssel enthalten).
    Spoiler anzeigen

    VB.NET-Quellcode

    1. <System.Runtime.InteropServices.DllImport("shell32.dll")> _
    2. Private Shared Function ExtractIcon(ByVal hInst As IntPtr, ByVal lpIconPath As String, ByVal lpiIcon As Integer) As IntPtr
    3. End Function
    4. Public Shared Function GetIcon(ByVal extension As String) As Icon
    5. 'Key der Extension finden (extension muss mit . anfangen)
    6. Dim extensionKey As Microsoft.Win32.RegistryKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(extension)
    7. If extensionKey IsNot Nothing Then 'Wenn der Key gefunden werden konnte, wird der Default-Wert ermittelt
    8. Dim extensionInfo As Microsoft.Win32.RegistryKey
    9. Dim extensionInfoObject As Object = extensionKey.GetValue(Nothing, Nothing)
    10. If extensionInfoObject IsNot Nothing Then 'wenn ein Default-Wert existiert, ...
    11. Select Case extensionKey.GetValueKind(Nothing) 'wird der Typ des jeweiligen untersucht
    12. Case Microsoft.Win32.RegistryValueKind.String 'bei Strings wird einfach der referenzierte Knoten geoeffnet
    13. extensionInfo = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(DirectCast(extensionInfoObject, String))
    14. Exit Select
    15. Case Microsoft.Win32.RegistryValueKind.ExpandString
    16. 'Wenn der String erweiterbare Umgebungsvariablen enthalet werden diese erweitert und der Knoten anschliessend geoeffnet
    17. extensionInfo = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(Environment.ExpandEnvironmentVariables(DirectCast(extensionInfoObject, String)))
    18. Exit Select
    19. Case Else
    20. extensionKey.Close() 'Falls der Typ nicht unterstuetzt wird, wird einfach Null (Nothing) zurueckgegeben
    21. Return Nothing
    22. End Select
    23. 'Wenn der Schluessel mit weiteren Informationen zum Typen verfuegbar ist
    24. If extensionInfo IsNot Nothing Then
    25. 'Wird der DefaultIcon-Schluessel geoeffnet
    26. Dim defaultIcon As Microsoft.Win32.RegistryKey = extensionInfo.OpenSubKey("DefaultIcon")
    27. If defaultIcon IsNot Nothing Then 'existiert dieser, ...
    28. 'wird dessen Standardwert ermittelt
    29. Dim defaultIconValue As Object = defaultIcon.GetValue(Nothing, Nothing)
    30. If defaultIconValue IsNot Nothing Then 'existiert dieser, ...
    31. Dim kind As Microsoft.Win32.RegistryValueKind = defaultIcon.GetValueKind(Nothing)
    32. 'werden alle jetzt nicht mehr benoetigten Schluessel geschlossen
    33. defaultIcon.Close()
    34. extensionKey.Close()
    35. extensionInfo.Close()
    36. 'der Typ des Knotens wird untersucht
    37. If kind = Microsoft.Win32.RegistryValueKind.ExpandString Then
    38. 'Erweiterbare Umgebungsvariablen werden wieder erweitert
    39. defaultIconValue = Environment.ExpandEnvironmentVariables(DirectCast(defaultIconValue, String))
    40. ElseIf Not kind = Microsoft.Win32.RegistryValueKind.String Then
    41. 'Nicht unterstuetzte Typen resultieren in einem Rueckgabewert Null (Nothing)
    42. Return Nothing
    43. End If
    44. 'Existiert ein Verweis auf eine Icon-Datei...
    45. If Not String.IsNullOrEmpty(DirectCast(defaultIconValue, String)) Then
    46. 'wird der String formattiert (siehe Format-Funktion unten)
    47. Dim formatted() As String = Format(DirectCast(defaultIconValue, String), New String() {})
    48. If formatted Is Nothing Then 'schlaegt das formattieren fehl, wird null zurueckgegeben
    49. Return Nothing
    50. ElseIf formatted.Length = 1 Then 'enthaelt das formattierte Array nur einen Wert
    51. 'wird untersucht, ob eine Datei mit dem Pfad existiert
    52. If IO.File.Exists(formatted(0)) Then
    53. 'und das Icon der Datei extrahiert
    54. Return Icon.ExtractAssociatedIcon(formatted(0))
    55. Else
    56. 'andernfalls wird nichts zurueckgegeben
    57. Return Nothing
    58. End If
    59. ElseIf formatted.Length = 2 Then 'sind zwei Werte vorhanden
    60. 'wird wieder ueberprueft, ob eine Datei mit dem Dateinamen existiert
    61. If IO.File.Exists(formatted(0)) Then
    62. Dim arg As Integer
    63. 'es wird ueberprueft, ob der zweite Parameter eine Ganzzahl ist
    64. If Integer.TryParse(formatted(1), arg) Then
    65. If arg = -1 Then 'ist arg = -1, wird es einfach mit 0 ersetzt (-1 gibt die Anzahl der Icons zurueck)
    66. arg = 0
    67. End If
    68. 'Findet das Icon-Handle
    69. Dim hicon As IntPtr = ExtractIcon(Process.GetCurrentProcess().Handle, formatted(0), arg)
    70. If hicon = IntPtr.Zero Then 'wenn die Funktion fehlschlaegt, wird Null (Nothing) zurueckgegeben
    71. Return Nothing
    72. Else
    73. 'andernfalls wird ein Icon vom Handle erzeugt
    74. Return Icon.FromHandle(hicon)
    75. End If
    76. Else 'schlaegt die Integer-Konversion des 2. Arguments fehl, wird Null (Nothing) zurueckgegeben
    77. Return Nothing
    78. End If
    79. Else 'ist eine ungueltige Anzahl an Argumenten vorhanden, wird Null (Nothing) zurueckgegeben
    80. Return Nothing
    81. End If
    82. Else 'schlaegt die Integer-Konversion des Arguments fehl, wird Null (Nothing) zurueckgegeben
    83. Return Nothing
    84. End If
    85. Else 'existiert kein Verweis auf eine Datei, die ein Icon bereitstellt, wird Null (Nothing) zurueckgegeben
    86. Return Nothing
    87. End If
    88. Else 'existiert kein Standardwert fuer den DefaultIcon-Schluessel, wird Null (Nothing) zurueckgegeben
    89. defaultIcon.Close()
    90. extensionKey.Close()
    91. extensionInfo.Close()
    92. Return Nothing
    93. End If
    94. Else 'existiert der DefaultIcon-Schluessel nicht, wird Null (Nothing) zurueckgegeben
    95. extensionKey.Close()
    96. extensionInfo.Close()
    97. Return Nothing
    98. End If
    99. Else 'existiert der Schluessel nicht, auf den der Schluessel der Dateierweiterung verweist, wird Null (Nothing) zurueckgegeben
    100. extensionKey.Close()
    101. Return Nothing
    102. End If
    103. Else 'ist kein Standardwert fuer den Erweiterungsschluessel verfuegbar, wird Null (Nothing) zurueckgegeben
    104. extensionKey.Close()
    105. Return Nothing
    106. End If
    107. Else 'Existiert kein Schluessel fuer die Erweiterung, wird Null (Nothing) zurueckgegeben
    108. Return Nothing
    109. End If
    110. End Function
    111. Public Shared Function Format(ByVal input As String, ByVal arguments() As String) As String()
    112. 'Zwischenpuffer
    113. Dim outputBuffer As New System.Text.StringBuilder(input.Length)
    114. Dim numberBuffer As New System.Text.StringBuilder(256)
    115. Dim temporaryInt As Integer
    116. Dim chars As IEnumerator(Of Char) = input.GetEnumerator()
    117. Dim output As New List(Of String)(2) 'Sinnvolle Kapazitaet der Liste angeben (eigentlich genuegen 2)
    118. While chars.MoveNext()
    119. If chars.Current = ","c Then 'einzelne Segmente trennen
    120. output.Add(outputBuffer.ToString()) 'zuletzt eingelesenes und ausgewertetes Segment hinzufuegen
    121. outputBuffer.Remove(0, outputBuffer.Length) 'Puffer leeren
    122. ElseIf chars.Current = """"c Then 'Gaensefuesschen erreicht (liest bis zum naechsten Gaensefuesschen)
    123. Do
    124. If chars.MoveNext() Then
    125. 'Wenn der Buchstabe ein % ist, wird eine Zahl eingelesen, die ein Argument (arguments)
    126. 'anspricht
    127. If chars.Current = "%"c Then
    128. If chars.MoveNext() Then
    129. If chars.Current = "%"c Then
    130. outputBuffer.Append("%"c) '%% als % auswerten
    131. ElseIf Char.IsLetterOrDigit(chars.Current) Then
    132. 'solange Buchstaben einlesen, bis ein nicht alphanumerischer Buchstabe erreicht wird.
    133. Do
    134. numberBuffer.Append(chars.Current)
    135. Loop While Char.IsLetterOrDigit(chars.Current) AndAlso chars.MoveNext()
    136. 'ist die Eingabe ueberhaupt eine Zahl...
    137. If Integer.TryParse(numberBuffer.ToString(), temporaryInt) Then
    138. '... wird ueberprueft, ob sie ein gueltiges Argument ist
    139. If temporaryInt >= arguments.GetLowerBound(0) AndAlso temporaryInt <= arguments.GetUpperBound(0) Then
    140. outputBuffer.Append(arguments(temporaryInt)) 'das Argument wird dem Puffer hinzugefuegt
    141. Else
    142. Return Nothing 'nicht genuegend Argumente
    143. End If
    144. Else
    145. Return Nothing 'ungueltige Zahl
    146. End If
    147. End If
    148. End If
    149. ElseIf Not chars.Current = """" Then 'wenn der Buchstabe kein Gaensefuesschen ist, ...
    150. outputBuffer.Append(chars.Current) '... wird es dem Puffer hinzugefuegt
    151. Else
    152. 'sonst wird der Puffer verlassen (mit Exit Do prinzipiell guenstiger, als per Variable)
    153. Exit Do
    154. End If
    155. Else
    156. Return Nothing 'ungueltige Syntax
    157. End If
    158. Loop
    159. Else
    160. outputBuffer.Append(chars.Current) '"normale" Zeichen werden unveraendert dem Puffer hinzugefuegt
    161. End If
    162. End While
    163. output.Add(outputBuffer.ToString()) 'letztes Segment der Liste hinzufuegen
    164. Return output.ToArray() 'Array der Liste ausgeben
    165. End Function

    Und hier ein kleines Anwendungsbeispiel:

    VB.NET-Quellcode

    1. Public Sub EnumerateExtensionIcons()
    2. Dim images As New ImageList 'Liste der Bilder erstellen
    3. Dim icon As Icon'Momentanes Icon
    4. images.ColorDepth = ColorDepth.Depth32Bit 'Farbtiefe auf 32-Bit ARGB einstellen
    5. images.Images.Add(Me.Icon) 'Standardicon 'Irgendein Icon als Standardicon hinzufuegen (steht fuer nicht ermittelbare Icons)
    6. tvExtensions.BeginUpdate()'Update des Ziel-Treeviews einleiten
    7. For Each rkn As String In Microsoft.Win32.Registry.ClassesRoot.GetSubKeyNames() 'Alle Schluessel in ClassesRoot durchlaufen
    8. If rkn.Length > 0 AndAlso rkn.Chars(0) = "."c Then'ueberpruefen, ob der Schluessel eine Dateierweiterung ist/sein koennte
    9. icon = GetIcon(rkn)'Icon ermitteln
    10. If icon Is Nothing Then'Wenn kein Icon verfuegbar ist, wird das Standardicon (Index = 0) eingesetzt
    11. tvExtensions.Nodes.Add(rkn, rkn, 0, 0)
    12. Else
    13. images.Images.Add(icon)'ansonsten wird das Icon zur Liste hinzugefuegt
    14. tvExtensions.Nodes.Add(rkn, rkn, images.Images.Count - 1, images.Images.Count - 1) 'und ein Item mit den Bild-Indices erzeugt
    15. End If
    16. End If
    17. Next
    18. tvExtensions.ImageList = images 'die Bilderliste der TreeView auf die Liste setzen
    19. tvExtensions.EndUpdate() 'Update abschliessen
    20. End Sub


    Gruß
    ~blaze~
    Hallo ~blaze~,
    coole Nr. die du abziehst. Vielen dank dafür.

    Aber gleich noch ne Frage hinterher geschoben.
    Damit später das Icon einer Extension zugeordnet werden kann, habe ich mir gedacht
    - in der ImageListe das Icon und das Extension zu speichern.
    - das Extension könnte ja im Tag platz nehmen.

    Das mache ich dann wie folgt

    VB.NET-Quellcode

    1. ImageList1.Images.Add(icon) 'ansonsten wird das Icon zur Liste hinzugefuegt
    2. ' Den Namen und die lfd. Nr. anzeigen lassen
    3. ListBox1.Items.Add(rkn & " -> " & (ImageList1.Images.Count - 1).ToString)
    4. ' Den Namen in der Tag mitschreiben
    5. ImageList1.Images.Item(ImageList1.Images.Count - 1).Tag = rkn.ToString

    Er bringt mir keinen Fehler, nun gehe ich davon aus er macht es auch.
    Leider bringt er mir nichts mehr zurück.

    VB.NET-Quellcode

    1. Dim Count As Integer = ImageList1.Images.Count - 1
    2. For i = 0 To Count
    3. If Not ImageList1.Images.Item(i).Tag Is Nothing Then
    4. ListBox2.Items.Add(ImageList1.Images.Item(i).Tag.ToString)
    5. End If
    6. Next


    Griefe ich denn nicht auf das Richtige Item zurück. beim einschreiben ins TAG ?

    Oder soll ich lieber Paralell eine Dictonary laufen lassen ?

    danke

    Bernd

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Bernd“ ()

    ImageList kann bereits Keys Bilder zuordnen.

    VB.NET-Quellcode

    1. ImageListInstance.Images.Add(".BlA".ToLower(), icon)
    2. ImageListInstance.Images.ContainsKey(".bla")
    3. Dim image As Image = ImageListInstance.Images(".bla")


    Generell würde ich selbst Tags vermeiden, da sie einfach viel zu allgemein nutzbar sind und man schnell den Überblick verliert. Die würde ich wenn dann nur in kleinen Programmen verwenden.

    Gruß
    ~blaze~
    Ok ~balze~
    ich glaube ein danke reicht hier bald nicht mehr.
    wenn du mal Hilfe brauchst, scheu dich nicht mich zu fragen.

    DANKE

    Ich hatte bisher noch nicht das Vergnügen mit TreeView und ImageListe.
    Meine anderen Projekte habe eigentlich immer mit einem DGV realisiert. Was eigentlich auch schöner ist.

    Nuja und die Beispiele in meinen Büchern und bei MSDN sind nciht immer die ausgibigsten.

    naja, nu weis ich ja bescheid.


    vielen dank
    Bernd
    Diese kleine Function von mir holt einfach das Icon, das bei einem Dateityp angezeigt wird.


    VB.NET-Quellcode

    1. Public Function GetIcon(ByVal extension As String) As Icon
    2. extension = extension.ToLower()
    3. Dim tmpFile As String = Application.LocalUserAppDataPath & "\tmp." & extension
    4. System.IO.File.Create(tmpFile).Close()
    5. Dim icon As Icon = icon.ExtractAssociatedIcon(tmpFile)
    6. System.IO.File.Delete(tmpFile)
    7. Return icon
    8. End Function


    So wird eine vordefinierte ImageList völlig überflüssig.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Quadsoft“ ()

    Imagelists sind eigentlich schon relativ weit verbreitet. Ich finde DataGridViews generell nicht schlecht, aber wenn man sich Programme so ansieht, stellt man fest, dass sie sehr selten benutzt werden. Für ListViews, DataGridViews usw. läuft das ganze übrigens analog. Die ImageList wird nur zum zwischenspeichern der Icons verwendet.
    @Quadsoft:
    Ich glaube du hast den Sinn einer ImageList nicht ganz verstanden... TreeViews und ListViews können zum Anzeigen der Icons ImageList-Instanzen verwenden. Das mache ich mir hier zunutze. Deine Funktion ist im Übrigen total unsauber und es läuft abgesehen von der verwendeten Datei auf das gleiche hinaus.

    Gruß
    ~blaze~

    ~blaze~ schrieb:

    Ich glaube du hast den Sinn einer ImageList nicht ganz verstanden... TreeViews und ListViews können zum Anzeigen der Icons ImageList-Instanzen verwenden.

    Das ist mir klar. Aber warum sollte man eine ImageList mit 1000 Icons von den verschiedensten Dateitypen mitschleppen? Unterstelle mir nicht, es nicht verstanden zu haben. Man muss auch bei Verwendung meiner Funktion eine ImageList erstellen, aber nur mit denjenigen Icons, die man auch wirklich benutzen will (dynamisch)

    Und btw: Die Funktion gibt das Icon eines Dateityps zurück. Wenn du mir sagst, wie es einfacher geht, dann bitte.

    Quadsoft schrieb:

    So wird eine vordefinierte ImageList völlig überflüssig.

    Extrahiert aber wieder nur das Icon aus einer vorhanden Datei.
    Und was ist wenn die Datei kein Icon hat ?

    Nach ~blaze~ seiner Methode findet er aber alle die sich bei Windows registriert haben.
    Da ist die Trefferquote um einiges höher.

    @ ~blaze~
    bin noch beim Experimentieren.
    Wie gesagt, ich habe mir ein Aufgabe als Ziel gesetzt. Nun greifen dort Themen die ich bisher nie gebraucht habe.
    - TreeView
    - ImageListe
    - FTP auslesen

    Wenn meine Test also etwas länger dauern ,bzw. die Antworten, liegt es daran das ich mich nicht mit C&P zufrieden gebe.
    Wenn dann hacke ich solange drauf rum, bis ich das auch in der Birne habe.

    Danke euch Beiden

    Bernd
    ImageList ist einfach eine Collection, auf die man mit Schlüssel und/oder per Index zugreifen kann. Wenn Bilder ohne Index übergeben werden geht das mit dem Schlüssel halt nicht so einfach. ImageLists können außerdem noch verschiedene Farbtiefen für die Bilder unterstützten, wie 32-Bit Argbs.
    TreeView und ListView enthalten beide Auflistungen. Das TreeView stellt mit der Nodes-Eigenschaft eine Auflistung von Knoten zur Verfügung. Knoten können wieder eigene Knoten enthalten. Das wird über die Nodes-Eigenschaft der jeweiligen Knoten geregelt. Außerdem können Knoten einen ImageKey und einen ImageIndex angeben, der ihnen ein Bild aus einer ImageList lädt. Die ImageList wird der ImageList-Eigenschaft des TreeViews zugewiesen, damit die Knoten darauf zugreifen können. ListViews enthalten normalerweise nur "oberste Items", also Items, die keine eigenen Unter-Items enthalten.
    Wenn ich es noch richtig in Erinnerung habe, geht man beim Zugriff auf den Ftp-Server so vor:
    - Webclient auf die URI erstellen
    - Method (siehe System.Net.WebRequestMethods.Ftp z.B. System.Net.WebRequestMethods.Ftp.ListDirectory), Credentials usw. zuweisen
    - Response abfragen
    - Response-Stream auswerten

    Bei System.Net.WebRequestMethods.Ftp.ListDirectory sind die Dateien durch Zeilen getrennt, wenn ich mich nicht täusche.

    Gruß
    ~blaze~