- Die API von Windows ermöglicht Ihnen, HICON zu erhalten und Pixel mit GetDIBits (BGRA) zu lesen.
- En Python, ctypes deckt ExtractIconExW und die Konvertierung in Bilder mit Pillow ab.
- .NET erleichtert die Anzeige des mit einer Datei verknüpften Symbols mit ImageList + ListView.
- Verwaltet GDI-Handles und Kanalreihenfolge, um Lecks und Fehler zu vermeiden.
Wenn Sie unter Windows arbeiten, möchten Sie früher oder später ein Symbol aus einer ausführbaren Datei oder einer ICO-Datei extrahieren, um es in einer anderen App, in einer Liste oder für Ihre Tests wiederzuverwenden. Im Windows-Ökosystem gibt es hierfür mehrere Möglichkeiten: die native API (ExtractIconExW, GetDIBits…), Python mit ctypes, .NET mit Icon.ExtractAssociatedIcon und sogar altbewährte Lösungen im klassischen Visual Basic. Jeder hat seine Nuancen und Vorteile. Sie können eine Leitfaden zu NirSoft-Dienstprogrammen.
In diesem Handbuch haben wir alle Teile an einem Ort zusammengetragen. Sie erfahren alles, von der Frage, wie Sie Windows nach dem HICON „klein“ und „groß“ das eine .exe oder .ico verfügbar macht, wie man die Bitmap im BGRA-Format liest, sie in RGBA konvertiert, wenn man sie für PyGame oder Pillow braucht, und wie man das mit einer Datei verknüpfte Symbol in einem Windows Forms ListView mit einer ImageListWir überprüfen auch einen klassischen VB-Ansatz zum Auflisten und Speichern von Symbolen und diskutieren praktische Überlegungen.
Was ist in einer .ico- und .exe-Datei enthalten: Größen und wo sie erscheinen
Ein einzelnes Symbol kann mehrere interne Bilder unterschiedlicher Größe enthalten (16x16, 32x32, 48x48 usw.). In Windows ist es üblich, dass sogenannte Symbole „klein“ (16×16) werden in Windows und im Explorer verwendet, wo Caches wie Windows thumbs.db können Miniaturansichten gespeichert werden, während die „groß“ (32×32) Sie werden in der Taskleiste angezeigt und wenn Sie mit Alt+Tab umschalten. Ausführbare Dateien (.exe) und Bibliotheken (.dll) speichern Symbole als Mittel, und .ico-Dateien selbst sind Container für mehrere Auflösungen und Farbtiefen.
Die Windows-API erleichtert dieses Lesen: mit ExtractIconExW (At shell32.dll) können Sie das kleine oder große Icon einer Datei (.exe oder .ico) anfordern. Diese Funktion gibt HICON-Handles zurück, die zum Zeichnen bereit sind oder, wenn Sie noch weiter gehen möchten, Lesen Sie die zugrunde liegende Bitmap und manipulieren Sie die Pixel.
Wenn Sie das Rohmaterial benötigen (z. B. Bitmap-Bytes zur Verarbeitung mit Ihren eigenen Bibliotheken), enthält der Pfad Symbolinfo abrufen von HICON zu Ihrem HBITMAP zu gelangen und GetDIBits um den Inhalt in einen von Ihnen kontrollierten Puffer zu schreiben. Dies gibt Ihnen die vollständige Kontrolle: genaue Größe, Byte-Reihenfolge, Transparenz und Formatierung.
Wir müssen das interne Format berücksichtigen, das Windows in diesen Fällen zurückgibt: Normalerweise haben wir es mit 32 Bit pro Pixel in BGRA (Blau, Grün, Rot und Alpha). Dieser Unterschied zum herkömmlichen RGBA ist wichtig, wenn Sie das Bild an Engines oder Bibliotheken weitergeben möchten, die eine andere Kanalreihenfolge erwarten.
Der Schlüssel liegt darin, zu verstehen, dass die API Daten in der Lesereihenfolge von GDI zurückgibt. Mit dem richtigen Header und negativer Höhe können Sie das Bild in Top-down- (von oben nach unten) und ermöglichen so die direkte Verwendung in anderen Bibliotheken, ohne den Puffer umdrehen zu müssen.

Extrahieren von Symbolen mit Python und der Windows-API (ctypes): von HICON zu Bildbytes
Wenn Sie Python unter Windows verwenden, ist der direkteste Weg heute, ctypes zum Aufrufen der nativen API. Wir könnten an pywin32 denken, aber es gibt ein wichtiges Detail: pywin32 stellt nicht GetDIBitsund diese Funktion ist notwendig für Holen Sie sich die echten Pixel von einem HICONDaher ist ctypes die praktische Möglichkeit, Strukturen, Prototypen und Aufrufe genau so zu definieren, wie es die Windows-API erwartet.
Der typische Ablauf ist wie folgt: Erstellen Sie eine DC-kompatibel (CreateCompatibleDC), Aufruf ExtractIconExW Um das kleine oder große Symbol zu erhalten, lösen Sie die Farb- und Maskenbitmaps mit Symbolinfo abrufen, bereiten Sie ein BITMAPINFO mit 32-Bit-Header, geben Sie eine negative Höhe für die Koordinaten von oben nach unten an und schließlich Pixel mit GetDIBits ausgeben in einem Python-Puffer (ctypes.create_string_buffer).
von ctypes importiere byref, sizeof von ctypes importiere c_int, c_void_p von ctypes importiere create_string_buffer von ctypes.wintypes importiere BOOL, BYTE, DWORD, HBITMAP, HDC, HGDIOBJ, HICON, LONG, LPCWSTR, LPVOID, UINT, WORD importiere ctypes # Gemeinsame Konstanten BI_RGB = 0 DIB_RGB_COLORS = 0 # Mindeststrukturen für GDI Klasse ICONINFO(ctypes.Structure): _fields_ = Klasse RGBQUAD(ctypes.Structure): _fields_ = Klasse BITMAPINFOHEADER(ctypes.Structure): _fields_ = Klasse BITMAPINFO(ctypes.Structure): _fields_ = # DLLs shell32 = ctypes.WinDLL('shell32', use_last_error=True) user32 = ctypes.WinDLL('user32', use_last_error=True) gdi32 = ctypes.WinDLL('gdi32', use_last_error=True) # Wichtige Prototypen shell32.ExtractIconExW.argtypes = shell32.ExtractIconExW.restype = UINT user32.GetIconInfo.argtypes = user32.GetIconInfo.restype = BOOL user32.DestroyIcon.argtypes = user32.DestroyIcon.restype = BOOL gdi32.CreateCompatibleDC.argtypes = gdi32.CreateCompatibleDC.restype = HDC gdi32.GetDIBits.argtypes = gdi32.GetDIBits.restype = c_int gdi32.DeleteObject.argtypes = gdi32.DeleteObject.restype = BOOL # Einfache Aufzählung für Größen Klasse IconSize: KLEIN = 1 GROSS = 2 @staticmethod def to_wh(size): return {IconSize.SMALL: (16, 16), IconSize.LARGE: (32, 32)} # Hochrangige Funktion (Skizze) def extract_icon(Dateiname, Größe): dc = gdi32.CreateCompatibleDC(0) wenn dc == 0: raise ctypes.WinError() hicon = HICON() # Wir sortieren das Große oder das Kleine wie angemessen out_large = byref(hicon) wenn Größe == IconSize.LARGE sonst Keine out_small = byref(hicon) wenn Größe == IconSize.SMALL sonst Keine got = shell32.ExtractIconExW(Dateiname, 0, out_large, out_small, 1) wenn got != 1: raise ctypes.WinError() info = ICONINFO() wenn nicht user32.GetIconInfo(hicon, byref(info)): user32.DestroyIcon(hicon) raise ctypes.WinError() w, h = IconSize.to_wh(Größe) bmi = BITMAPINFO() ctypes.memset(byref(bmi), 0, sizeof(bmi)) bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER) bmi.bmiHeader.biWidth = w bmi.bmiHeader.biHeight = -h # negativ für Top-Down bmi.bmiHeader.biPlanes = 1 bmi.bmiHeader.biBitCount = 32 bmi.bmiHeader.biCompression = BI_RGB bmi.bmiHeader.biSizeImage = w * h * 4 Bits = create_string_buffer(bmi.bmiHeader.biSizeImage) kopiert = gdi32.GetDIBits(dc, info.hbmColor, 0, h, Bits, byref(bmi), DIB_RGB_COLORS) wenn kopiert == 0: # Minimale Bereinigung wenn info.hbmColor: gdi32.DeleteObject(info.hbmColor) wenn info.hbmMask: gdi32.DeleteObject(info.hbmMask) user32.DestroyIcon(hicon) raise ctypes.WinError() # GDI und HICON bereinigen if info.hbmColor: gdi32.DeleteObject(info.hbmColor) if info.hbmMask: gdi32.DeleteObject(info.hbmMask) user32.DestroyIcon(hicon) return bits # bytes BGRA
Mit dem oben genannten können Sie nun das kleine oder große Symbol jeder ausführbaren Datei abrufen. Wenn Sie es beispielsweise mit dem Python-Interpreter selbst versuchen möchten (Pfad verfügbar unter sys.executable), extrahieren Sie einfach beide Größen und arbeiten Sie mit ihren Puffern.
# Verwendungsbeispiel import sys small_icon = extract_icon(sys.executable, IconSize.SMALL) large_icon = extract_icon(sys.executable, IconSize.LARGE)
Das Ergebnis ist ein Byteblock, in dem Jedes Pixel belegt 4 Bytes in BGRA. Bei 16×16 erhalten Sie 16×16×4 = 1024 Bytes und bei 32×32 4096. Die Reihenfolge ist Zeile für Zeile und Spalte für Spalte, von oben nach unten und von links nach rechts, wenn Sie in der Kopfzeile eine negative Höhe verwendet haben, wodurch es einfacher wird, den richtigen Index für jedes (x, y) zu lesen.
Wenn Sie die Größe überprüfen möchten, können Sie die Länge des 16x16-Puffers drucken und überprüfen, ob sie 1024 bytesDiese Prüfung erspart Ihnen Überraschungen bei der Arbeit mit Ressourcen, die unterschiedliche Auflösungen und Farbtiefen umfassen.
Um Pixel für Pixel zu visualisieren und die Lesereihenfolge zu verstehen, ist eine Lehrmethode die Verwendung von PyGame: Sie gehen den Puffer Zeile für Zeile durch, konvertieren jedes BGRA in RGBA und malen mit set_at. Sie können sogar eine kleine anfängliche Verzögerung einführen, um „sehen“, wie das Symbol gefüllt ist auf dem Bildschirm.
# Rendern Sie das 32x32-Symbol mit PyGame und konvertieren Sie BGRA -> RGBA von winicon import IconSize, extract_icon import pygame import sys pygame.init() screen = pygame.display.set_mode((320, 240)) icon_size = IconSize.LARGE w, h = IconSize.to_wh(icon_size) icon_large = extract_icon(sys.executable, icon_size) rendered = False offset_x, offset_y = 50, 50 while True: für Ereignis in pygame.event.get(): wenn event.type == pygame.QUIT: sys.exit() screen.fill((0, 0, 0)) für Zeile im Bereich (h): für Spalte im Bereich (w): Index = Zeile * w * 4 + Spalte * 4 b, g, r, a = icon_large Farbe = (r, g, b, a) screen.set_at((offset_x + col, offset_y + row), Farbe), falls nicht gerendert: pygame.time.wait(10) pygame.display.flip() gerendert = True
In der Praxis werden Sie nicht immer Pixel von Hand antippen wollen. Um das Symbol als Bild auf der Festplatte zu speichern, Kissen (PIL) macht das Leben viel einfacher: Sie erstellen das Bild aus den Bytes mit dem Modus 'RGBA', der angibt, dass die Eingabe 'BGRA' ist und die Speichern als BMP, PNG oder was auch immer praktisch istEin Adapter wie win32_icon_to_image(icon_bits, size) zentralisiert diese Konvertierung für Sie.
# Konvertieren des BGRA-Puffers in ein PIL-Bild und Speichern aus PIL-Importbild def win32_icon_to_image(icon_bits, size): w, h = IconSize.to_wh(size) img = Image.frombytes('RGBA', (w, h), icon_bits, 'raw', 'BGRA') return img img_small = win32_icon_to_image(small_icon, IconSize.SMALL) img_large = win32_icon_to_image(large_icon, IconSize.LARGE) img_small.save('python1.bmp') img_large.save('python2.bmp')

Zeigen Sie das mit einer Datei verknüpfte Symbol in .NET (WinForms) an: ListView + ImageList
Ein weiteres häufiges Bedürfnis ist die Anzeige des Namens jeder Datei, Symbol, das Windows mit seiner Erweiterung verknüpft (zum Beispiel .docx mit dem Word-Symbol). In WinForms können Sie es mit lösen Icon.ExtractAssociatedIcon und Speichern der Ergebnisse in einem Bilderliste die an eine ListView gebunden ist, die auf die SmallIcon-Ansicht eingestellt ist.
Die Idee besteht darin, die Dateien in einem Verzeichnis zu durchsuchen und für jede einzelne zu prüfen, ob Sie bereits ein Bild in der ImageList mit dem Schlüssel gleich der Erweiterung; wenn nicht, extrahieren Sie das Symbol und fügen Sie es hinzu. So Sie vermeiden Duplikate und Sie beschleunigen das Laden. Für das ListView-Element weisen Sie die ImageKey-Eigenschaft mit dieser Erweiterung zu und fügen das Element hinzu. Wenn etwas fehlschlägt, können Sie einen Fallback wie SystemIcons.WinLogo.
ListView listView1 = neue ListView(); ImageList imageList1 = neue ImageList(); listView1.SmallImageList = imageList1; listView1.View = View.SmallIcon; // Dateien durchlaufen (erfordert die Verwendung von System.IO) var dir = neues System.IO.DirectoryInfo(@"C:\\"); foreach (var Datei in dir.GetFiles()) { var item = neues ListViewItem(Datei.Name); var key = Datei.Erweiterung; if (!imageList1.Images.ContainsKey(Schlüssel)) { var icon = System.Drawing.Icon.ExtractAssociatedIcon(Datei.VollständigerName); imageList1.Images.Add(Schlüssel, Symbol); } item.ImageKey = Schlüssel; listView1.Items.Add(Element); }
Um es schnell zu kompilieren, fügen Sie den Code in eine Windows Forms, erstellen und konfigurieren Sie die ListView und ImageList im Konstruktor oder im Load-Ereignis und denken Sie daran, den Namespace zu importieren System.IO.. Sie müssen sich nicht manuell mit HICON oder Pixeln beschäftigen; hier verlassen Sie sich ganz auf Systemsymbolzuordnungen.
Klassischer Ansatz mit Visual Basic (Extraktor/Viewer und Speichern in BMP)
Vor .NET und modernen Wrappern haben viele Dienstprogramme in VB 4/5/6 diese Arbeit bereits durch Aufrufen der API erledigt: ExtractIcon von shell32, um HICON zu erhalten, DrawIcon in einer PictureBox zu malen, und Bitblt auf eine andere Oberfläche zu kopieren und einen Streifen von Miniaturansichten zu erstellen. Diese Programme zählten die Symbole einer .exe oder .dll auf, indem sie die Symbolindex bis die Funktion keine Ergebnisse mehr zurückgab.
Der typische Ablauf war: Nach der Auswahl einer Datei beginnen Sie bei Index 0 und während ExtractIcon Geben Sie einen gültigen Handle zurück, zeichnen Sie ihn in die PictureBox, aktualisieren Sie ihn und wechseln Sie zum nächsten Index. Parallel dazu mit Bitblt, wurden die 32x32 auf eine zweite Oberfläche an versetzten Positionen kopiert (z.B. auf X = 2 + Index × Zelle) um alle eingebetteten Icons auf einen Blick sehen.
Um zu sparen, bot VB zwei Routen mit Bild speichern: Speichern Sie die Picture-Eigenschaft unverändert oder die Image-Eigenschaft (letztere immer als BMP). Zusätzlich wurde in einigen Formularen ein Dateiselektor hinzugefügt mit Filter nach Erweiterung für .ico, .bmp, .exe, .dll und andere und zeigte sogar eine Vorschau an, wenn es sich bei der Datei um ein Bild handelte.
Dieser Ansatz ist weiterhin gültig, um die Interaktion mit der API aus „traditionellen“ Windows-Sprachen zu verstehen. Wenn Sie die API jedoch heute benötigen, Pixelpufferist es besser, GDI und GetDIBits zu verwenden (oder im modernen .NET Methoden, die das Bild serialisieren), anstatt sich nur auf DrawIcon über Kontrollen.
Wichtiges Detail: Größe, Bytereihenfolge und Zeilen-/Spaltenlesen
Beim Abrufen von Pixeln mit GetDIBits wird durch die Angabe von biHeight als negativ der Koordinatenursprung die obere linke Ecke, was viele Grafikbibliotheken erwarten. Wenn Sie dies nicht tun, erhalten Sie eine Bottom-up-Puffer (von unten nach oben) und Sie müssen die Blöcke reihenweise umkehren.
Bei 16×16 belegt die erste Reihe 16×4 = 64 bytes (4 pro Pixel). Daher beträgt die Verschiebung zur Zeile n n × 64 und zur Spalte m m × 4. Im 32×32-Format ist jede Zeile 128 bytes und die Summe ist 4096. Die Reihenfolge BGRA (B, G, R, A) ist das, was diese GDI-Aufrufe zurückgeben; wenn Ihre Zielbibliothek RGBA will, müssen Sie Kanäle neu anordnen wie es mit PyGame gemacht wurde, oder geben Sie es beim Erstellen des Bildes mit Pillow an.
Wenn Sie Transparenz manipulieren, ist der Alphakanal das vierte Byte des Pixels. Denken Sie daran, dass Symbole auch einen Maske (hbmMask); bei der Arbeit mit 32-Bit-BGRA ist Transparenz normalerweise bereits im Alpha des hbmColor, daher kann die Maske für allgemeine Anwendungen ignoriert werden.
Symbole in Ressourcen und Ersetzung: Kurze Überlegungen
Ausführbare Dateien und Bibliotheken speichern ihre Symbole als MittelSie können sie wie erläutert mit der API extrahieren. Wenn Sie etwas Visuelles bevorzugen, stehen Ihnen Ressourceneditoren und Dienstprogramme mit grafischen Schnittstellen zur Verfügung, die Ihnen dies ermöglichen. ersetzen oder exportieren Symbole. Wenn Sie automatisieren möchten, bietet Ihnen der programmatische Ansatz mit HICON, GetIconInfo und GetDIBits vollständige Kontrolle und Reproduzierbarkeit.
Um mit Erweiterungen verknüpfte Symbole zu lesen (ohne Ressourcen aus der .exe selbst zu extrahieren), vereinfacht .NET die Arbeit mit Icon.ExtractAssociatedIcon. Diese Methode basiert auf Registrierungszuordnungen und gibt das Symbol zurück, das das System für jede Datei anzeigen würde. Dies ist ideal für Listen, Explorer und Viewer.
Gute Praktiken und Ressourcenreinigung
Die Arbeit mit GDI umfasst die Verwaltung Griffe und Speicher explizit. Jedes Mal, wenn Sie ein HICON oder HBITMAP erhalten, müssen Sie seinen Lebenszyklus vorhersehen: Zerstören Sie das HICON mit ZerstörenSymbol und geben Sie die Bitmaps frei mit Objekt löschen. Das Vergessen kann zu Ressourcenverlusten führen, die sich bei Anwendungen mit vielen Aufrufen in Lecks und unberechenbares Verhalten.
In Python/ctypes ist es praktisch, die Bereinigung in einer kleinen Funktion oder einem Kontextmanager. Stellen Sie sicher, dass Sie immer eine Bereinigung der Fehlerzweige durchführen, insbesondere wenn GetDIBits gibt 0 oder ja zurück ExtractIconExW gibt nicht die erwartete Anzahl von Symbolen zurück. Überprüfen Sie außerdem, ob der von CreateCompatibleDC zurückgegebene DC gültig ist, bevor Sie fortfahren.
Wann ist welcher Ansatz zu wählen?
Wenn Sie nur das Symbol anzeigen müssen, das Windows für eine Datei anzeigen würde, .NET mit ExtractAssociatedIcon Es ist einfach und effektiv. Wenn Sie lesen möchten die eigentliche Bitmap von einem in einer .exe oder .ico eingebetteten Symbol, um es selbst zu bearbeiten, zu konvertieren oder zu speichern, API mit ctypes Es gibt Ihnen die volle Kontrolle, die Sie brauchen. Für Legacy- oder Rapid-Prototyping-Tools bleibt der klassische VB-Ansatz in seinem Kontext anschaulich und funktional.
Wenn das Ziel hingegen darin besteht, Symbole als Bilder mit Alpha-Ebene und ohne Verluste zu speichern, sollten Sie Formate wie PNG Verwenden Sie Pillow und stellen Sie die entsprechende Kanalreihenfolge bereit. BMP ist unkompliziert und wird weitgehend unterstützt. Wenn Sie jedoch Komprimierung und Transparenz bevorzugen, sind PNG oder ICO (bei Neuverpackung) möglicherweise besser geeignet.
Durch die Integration von Native API, Python und .NET können Sie alles abdecken, vom einfachen Anzeigen von Symbolen, die mit der Erweiterung verknüpft sind, bis zum Extrahieren der BGRA-Bytes Mit voller Kontrolle über Größe, Transparenz und Lesereihenfolge sowie der Möglichkeit, in ältere oder moderne ausführbare Dateien eingebettete Symbole aufzulisten. Diese Vielfalt an Pfaden ermöglicht Ihnen die Lösung aller Probleme, von Viewern und Auflistungen bis hin zum Symbolexport und Bearbeitungspipelines.
Leidenschaftlicher Autor über die Welt der Bytes und der Technologie im Allgemeinen. Ich liebe es, mein Wissen durch Schreiben zu teilen, und genau das werde ich in diesem Blog tun und Ihnen die interessantesten Dinge über Gadgets, Software, Hardware, technologische Trends und mehr zeigen. Mein Ziel ist es, Ihnen dabei zu helfen, sich auf einfache und unterhaltsame Weise in der digitalen Welt zurechtzufinden.