GDI-Handle-Lecks? Nicht mit mir: Ein natives Kontextmenü-Control für VB6, von Grund auf neu gebaut

Tags: VB6 · Win32 API · COM/ActiveX · Legacy-Modernisierung · Performance

MenuEx ist ein eigenes Entwicklungsprojekt von HPApps.

VB6 Kontextmenü GDI-Probleme kennen viele Entwickler: Owner-Draw-Controls, veraltete ActiveX-Menüs und vor allem GDI-Handle-Lecks. MenuEx löst das als natives VB6 Kontextmenü GDI-sicheres Control über die Windows-API.

VB6 Kontextmenü GDI: Das Problem

In vielen gewachsenen VB6-Anwendungen hängen Kontextmenüs und Menüleisten noch an kommerziellen Drittanbieter-Controls. Oft sind das betagte ActiveX-Komponenten ohne Updates seit Jahren.

Zunächst das Offensichtliche: Solche Controls zeichnen ihre Menüs selbst (Owner-Draw). Dadurch passen sie selten zum aktuellen Windows-Theme. Zudem kennen Entwickler ein altes Problem: GDI-Handle-Lecks.

Darüber hinaus gilt: Jedes Öffnen eines Menüs kostet Windows-Ressourcen, die nicht sauber freigegeben werden. Läuft die Anwendung im Dauerbetrieb, führt das irgendwann zu Rucklern — im schlimmsten Fall zum Absturz.

Die Frage war deshalb nicht: „Welches andere Control nehmen wir?“ Sondern: Warum bauen wir das nicht einfach selbst — richtig?

VB6 Kontextmenü GDI: Die Idee

MenuEx ist deshalb die Antwort: ein neu geschriebenes VB6-ActiveX-Control. Es arbeitet direkt über die Windows-API — zum Beispiel TrackPopupMenuEx und InsertMenuItemW — statt Menüs selbst zu zeichnen.

Daraus folgt ein großer Vorteil: Windows rendert das Menü. Es sieht deshalb immer wie ein natives Windows-Menü aus — inklusive Theme und alpha-transparenter Icons.

Zudem liegt der eigentliche Clou im Ressourcen-Management. In unseren Tests werden Menü-Handles und Icon-Bitmaps typischerweise direkt freigegeben, sobald das Menü schließt — nicht erst beim nächsten Öffnen, nicht erst beim Beenden.

Nach zehntausend Öffnungen in Langzeittests hielt die Komponente in der Regel null zusätzliche GDI-Handles. Das war von Anfang an das wichtigste Entwurfsziel.

VB6 Kontextmenü GDI: Funktionen

Zwei Einsatzarten, eine DLL

Zum Beispiel unterstützt MenuEx klassische Rechtsklick-PopUp-Menüs und angedockte Menüleisten im Datei/Bearbeiten-Stil. Beide Varianten teilen sich dasselbe Datenmodell und lassen sich unabhängig auf einem Formular einsetzen.

Native Darstellung

Außerdem gibt es kein Owner-Draw und keinen eigenen Zeichencode. Windows rendert das Menü zu 100 %. Dadurch folgt es automatisch dem System-Theme. Icons werden bei Bedarf mit echtem Alpha-Kanal eingebunden.

Checked-Zustand, Separatoren, Untermenüs

Pro Eintrag gibt es eigene Checked/Unchecked-Icons — mit nativem Haken als Fallback. Außerdem unterstützt MenuEx Separatoren, tief verschachtelte Untermenüs sowie Enabled/Disabled- und Visible/Hidden-Zustände.

Lazy-Aufbau für große Menüs

Insbesondere bei sehr großen Menübäumen werden nur die Äste aufgebaut, die der Anwender wirklich öffnet. Ein Ast, der nie geöffnet wird, verursacht typischerweise keine merkbare Rechenzeit.

Live-Hover-Events

Das ItemPopup-Event feuert kurz bevor ein Untermenü sichtbar wird. So lassen sich Einträge situativ ein- oder ausblenden — zum Beispiel je nach Markierung im Formular.

Multi-Monitor-Positionierung

Eine Kollisionserkennung hält das Menü auf jedem Monitor vollständig sichtbar. Das gilt auch bei vertikalen Taskleisten oder ungewöhnlichen Multi-Monitor-Setups.

Migration ohne Nervenzusammenbruch

Das Objektmodell orientiert sich an gängigen Menü-Controls aus der VB6-Welt. Bestehender Code lässt sich deshalb mit überschaubarem Aufwand umstellen.

Unter der Haube

Die Komponente ist reines VB6 — ohne externe Laufzeit-Abhängigkeiten. Sie nutzt User32, GDI32 und OLE32 für Menüs, Icon-Konvertierung und GUID-Schlüssel pro Eintrag.

Für Klick-Erkennung und Live-Hover sorgen eigene Window-Subclassing-Hooks. Sie fangen gezielt WM_COMMAND und WM_INITMENUPOPUP ab.

Fazit

Schließlich steht ein Kontextmenü-Control, das sich wie natives Windows anfühlt — und das in unseren Langzeittests auch nach vielen tausend Klicks stabil lief.

Weitere VB6-Projekte im Blog: MSChart mit WebView2, VB6 Profiler, MenuEx-Kontextmenü und VB6 Time Picker.