ActiveX / OCX heute behandeln - Entscheidungstabelle: Behalten, Kapseln, Ersetzen

· · COM, ActiveX, OCX, .NET, Windows-Entwicklung, Modernisierung

Projekte, in denen die Begriffe ActiveX / OCX fallen, haben meist eine etwas schwere Atmosphäre.

  • VB6 oder alte C++ / MFC-Anwendungen sind noch im aktiven Einsatz
  • Das SDK für Industriegeräte oder Messinstrumente liefert nur eine OCX
  • Die interne Web-Anwendung setzt ActiveX voraus und kommt nicht aus dem IE-Modus heraus
  • Sie wollen von 32-Bit auf 64-Bit umstellen, aber eine einzige OCX schüttelt den Kopf

Dabei ist sowohl „es ist alt, also weg damit“ als auch „es läuft, also für immer aufbewahren“ zu grob gedacht. Wichtig ist zu unterscheiden, ob dieses ActiveX / OCX eine bloße UI-Komponente ist oder eine Grenzfläche, die Fachlogik oder Gerätespezifikationen in sich trägt.

Dieser Artikel ordnet, in einer Reihenfolge, die die Entscheidung erleichtert, welche der drei Optionen - Behalten, Kapseln, Ersetzen - Sie wählen sollten, wenn Sie ActiveX / OCX vorfinden.

Zielgruppe sind zum Beispiel Fälle wie diese.

  • Bestehende Desktop-Anwendungen aus der VB6- / MFC- / WinForms-Familie
  • Schrittweise Migration zu C# / .NET
  • Legacy-Bildschirme mit WebBrowser / IE-Modus
  • Windows-Anwendungen mit ActiveX-Steuerelementen von Drittanbietern

Inhaltsverzeichnis

  1. Zuerst das Fazit (in einem Satz)
  2. Was dieser Artikel unter ActiveX / OCX versteht
  3. Die Entscheidungstabelle, die Sie zuerst ansehen sollten
    • 3.1. Das Gesamtbild
    • 3.2. Die Entscheidung für Behalten
    • 3.3. Die Entscheidung für Kapseln
    • 3.4. Die Entscheidung für Ersetzen
    • 3.5. Browser-Abhängigkeiten separat betrachten
  4. Punkte, die die Entscheidung leicht verzerren
    • 4.1. UI-Komponente oder Komponente mit eigener Fachlogik?
    • 4.2. 32-Bit / 64-Bit und Prozessgrenzen
    • 4.3. Registrierung, Verteilung, Berechtigungen, Lizenzierung
    • 4.4. STA / Nachrichtenschleife / Callbacks
    • 4.5. Gibt es Tests? Lässt es sich beobachten?
  5. Empfehlungen nach typischem Muster
    • 5.1. Eine intern noch stabil laufende Desktop-Anwendung
    • 5.2. Eine 32-Bit-OCX zur 64-Bit-Seite mitnehmen
    • 5.3. Bildschirme mit IE- / WebBrowser-Abhängigkeit
    • 5.4. ActiveX mit Gerätesteuerung oder proprietärer Fachlogik
  6. Häufige Antimuster
  7. Checkliste für den Start einer Migration
  8. Grobe Entscheidungshilfe
  9. Zusammenfassung
  10. Für solche Anliegen sind wir ein guter Ansprechpartner
  11. Referenzen

1. Zuerst das Fazit (in einem Satz)

  • Sehen Sie ActiveX / OCX, sollten Sie zuerst nicht fragen „ist es alt“, sondern was diese Komponente eigentlich übernimmt
  • Ist es eine bloße UI-Komponente, ist Ersetzen vergleichsweise einfach
  • Trägt es Gerätesteuerung, Berichtswesen, ein proprietäres Dateiformat oder jahrelang gewachsene Betriebseigenheiten, ist Kapseln zuerst sicherer als eine sofortige Neuimplementierung
  • Läuft es stabil auf dem Desktop und ist der Änderungsumfang klein, ist Behalten eine durchaus vertretbare Entscheidung
  • Browser-seitige ActiveX-Abhängigkeiten lassen sich am Leben erhalten, haben aber eine dünne Zukunft - hier ist Ersetzen mit Priorität die bessere Sicht
  • Eine 32-Bit-OCX lässt sich nicht einfach in einen 64-Bit-Prozess laden. Das lässt sich mit keiner Willensanstrengung überwinden
  • Registrierung, abhängige DLLs, Administratorrechte, Lizenzierung, STA / MTA - Reibung außerhalb der Implementierung wird häufig zum Engpass
  • Sowohl „erst mal alles neu schreiben“ als auch „aus Angst für immer einfrieren“ haben eine hohe Unfallquote

Kurz gesagt, die Reihenfolge der Entscheidung ist diese.

  1. Was trägt diese OCX in sich?
  2. Muss sie im selben Prozess laufen?
  3. Verhaken Sie sich an 32-Bit / 64-Bit, Registrierung oder Browser-Abhängigkeiten?
  4. Sollten Sie vor dem Ersetzen erst eine testbare Grenze schaffen?

In dieser Reihenfolge betrachtet, lässt sich die Sache deutlich leichter ordnen.

2. Was dieser Artikel unter ActiveX / OCX versteht

Zunächst legen wir fest, wie die Begriffe in diesem Artikel verwendet werden.

Begriff Bedeutung in diesem Artikel
COM Windows’ binärkompatibles Komponentenmodell. Die Grundlage für öffentliche Schnittstellen, Registrierung, das Apartment-Modell und Ähnliches
ActiveX / OCX In der Praxis meist kollektiv für COM-basierte Steuerelemente und ihr Umfeld verwendet. Insbesondere häufig .ocx-UI-Steuerelemente und Komponenten, die in den IE oder einen Container eingebettet werden
WebBrowser- / IE-Abhängigkeiten Auch wenn es nicht ActiveX selbst ist, gehören eingebettete Browser und Integrationen dazu, die von der „Welt des IE“ ausgehen. Für die Entscheidung ist das ein sehr ähnliches Problem

Streng genommen sind ActiveX und COM nicht dasselbe. In der Praxis liegen die Schmerzpunkte aber ziemlich nah beieinander.

  • Passen 32-Bit / 64-Bit zusammen?
  • Wie verteilt man Registrierung und abhängige DLLs?
  • In welchem Host / Container läuft es?
  • Verhaken Sie sich an STA, Nachrichtenschleife oder Callbacks?
  • Bleibt eine Browser-Abhängigkeit bestehen?

Dieser Artikel behandelt diese praktischen Entscheidungspunkte gemeinsam.

Da im weiteren Verlauf einige Abkürzungen wie selbstverständlich vorkommen, fassen wir sie vorab zusammen. Steht in der Checkliste in Kapitel 7 „ProgID und CLSID ermitteln“, kommen Sie ohne diese Grundlage nicht weiter.

Begriff Aussprache / vollständiger Name Bedeutung
CLSID Class ID Eine GUID, die die Implementierung (Klasse) einer COM-Komponente eindeutig bezeichnet. Auch die Registry-Registrierung hängt an diesem Wert
ProgID Programmatic Identifier Ein menschenlesbarer Name, der einer CLSID zugeordnet ist. Eine Zeichenkette wie Excel.Application
IID Interface ID Eine GUID, die eine COM-Schnittstelle eindeutig bezeichnet. Etwas anderes als die CLSID
TLB Type Library Eine Datei, die Typinformationen wie Schnittstellen, Methoden und Parametertypen binär enthält. Nur dank ihr lässt sich „typisiert“ aus VB6 oder .NET aufrufen
RegAsm Assembly Registration Tool Ein zum .NET Framework gehörendes Werkzeug. Registriert eine .NET-Assembly in der Registry, damit sie von COM aus nutzbar ist
AxHost Die Basisklasse zum Hosten eines ActiveX-Steuerelements in Windows Forms
AxImp ActiveX Control Importer Ein Werkzeug, das aus einer OCX eine Wrapper-Assembly für Windows Forms erzeugt
in-proc / out-of-proc Prozessintern / prozessextern Läuft im selben Prozess wie der Aufrufer (DLL oder OCX) oder in einem separaten Prozess (EXE als Server)
LocalServer Eine Form, bei der ein COM-Server als EXE in einem separaten Prozess läuft. Damit lässt sich die Bitness-Grenze überwinden oder ein Absturz isolieren
Reg-Free COM / side-by-side Registrierungsfreies COM Ein Mechanismus, der COM ohne Registry-Registrierung anhand von Informationen in der Anwendungsmanifest-Datei auflöst
design-time / runtime-Lizenz Entwicklungszeit / Laufzeit Bei Steuerelementen von Drittanbietern ist die Lizenzbehandlung beim Platzieren auf dem Entwicklungsrechner manchmal von der Behandlung beim Ausführen beim Kunden getrennt
adapter / facade Entwurfsmuster, die eine feingranulare bestehende API durch eine für die eigenen Zwecke günstigere, grobkörnige API ersetzen
STA / MTA Single / Multi Threaded Apartment Das Threading-Modell von COM. Es legt fest, von welchem Thread aus ein Aufruf erlaubt ist

3. Die Entscheidungstabelle, die Sie zuerst ansehen sollten

3.1. Das Gesamtbild

Werfen Sie zuerst einen Blick auf diese Tabelle - damit steht die grobe Richtung meist schon fest.

Situation Erste Wahl Grund
Abhängigkeit von browser-basiertem ActiveX Eher ersetzen Edge selbst unterstützt kein ActiveX, und der IE-Modus ist als Übergangslösung positioniert
OCX läuft stabil in einer Desktop-Anwendung, Änderungsumfang klein Eher behalten Die Kosten, es jetzt aufzubrechen, sind meist höher
Nur das Umfeld soll auf .NET modernisiert werden, aber das Verhalten des Steuerelements ist unklar Eher kapseln Erst die Grenze zu ordnen ist sicherer
Eine 32-Bit-OCX soll direkt in einen 64-Bit-Prozess Kapseln / Konfiguration ändern Eine Grenze, die in-proc nicht überwunden werden kann
Nur als UI-Komponente genutzt, Alternative vorhanden Eher ersetzen Ein oberflächlicher Austausch reicht oft aus
Hersteller nicht mehr aktiv; Signierung, Registrierung oder abhängige DLLs sorgen ständig für Ärger Eher ersetzen Die Betriebskosten sind bereits als technische Schuld sichtbar
Enthält Gerätesteuerung, Berichtswesen oder proprietäre Protokolle Eher kapseln Erst wenn das Verhalten fixiert ist, lassen sich die Ersetzungskosten abschätzen
JaNeinJaJaNeinNeinJaNeinJaNeinActiveX / OCX vorhandenBrowser-Abhängigkeit?Ersetzen priorisierenIE-Modus ist ÜbergangslösungHauptsächlich UI-Komponente?Gleichwertige Alternative vorhanden?Ersetzen prüfenZuerst kapseln und die Grenze ordnenTrägt Gerätesteuerung / proprietäre Fachlogik / Berichtslogik?Zuerst kapselnTests aufbauen, dann schrittweise ersetzenRegistrierung / Bitness / Verteilung schmerzhaft?Konfiguration überdenkenOut-of-Process / Prozessbrücke / Reg-Free COM prüfenBehalten ist auch realistisch

Im Folgenden betrachten wir jedes Muster der Reihe nach.

3.2. Die Entscheidung für Behalten

Nur weil etwas ActiveX / OCX ist, wird es nicht automatisch zum Ersetzungskandidaten. Kommen Bedingungen wie diese zusammen, ist Behalten oft schlicht die günstigste Option.

  • Der Nutzungsbereich ist geschlossen, das Betriebsumfeld ist fixiert - interne Verteilung, Mitlieferung mit Geräten und Ähnliches
  • Das Steuerelement läuft nach wie vor stabil, die Änderungsanforderungen sind nicht groß
  • Der Hersteller ist noch aktiv, oder das eigene Team kann die Mindestpflege leisten
  • Es besteht keine Browser-Abhängigkeit, alles spielt sich innerhalb eines bestehenden Desktop-Hosts ab
  • Die 32-Bit- / 64-Bit-Voraussetzung muss vorerst nicht geändert werden

Wichtig ist hier: Behalten bedeutet nicht Vernachlässigen. Wenn Sie es behalten, sollten Sie zumindest dies erledigen.

  • Unterstütztes Betriebssystem, Bitness, benötigte abhängige DLLs und Registrierungsschritte schriftlich festhalten
  • Installation, Registrierung und Deinstallation in Skripte oder einen Installer überführen, nicht in handschriftliche Notizen
  • Einen Smoke-Test für eine saubere Umgebung bereithalten
  • Aufrufe des Steuerelements möglichst an einer Stelle bündeln, statt sie über die ganze Anwendung zu verstreuen

Am schlimmsten ist es, „es läuft, also nicht anfassen“ zehn Jahre lang fortzusetzen, bis niemand mehr die Voraussetzungen erklären kann. Je mehr Sie sich für Behalten entscheiden, desto wichtiger wird es, die Voraussetzungen sichtbar zu machen.

3.3. Die Entscheidung für Kapseln

In der Praxis steckt in dieser Entscheidung die meiste Arbeit.

„Kapseln“ bedeutet hier, ActiveX / OCX innerhalb einer engen Grenze einzuschließen und es der Umgebung gegenüber als neue API oder neues Bildschirmelement erscheinen zu lassen.

Das ist ziemlich wirksam. Der Grund: Steigt man in eine vollständige Neuimplementierung ein, solange das Verhalten der alten Komponente noch nicht durchschaut ist, wird daraus leicht eine doppelte Last aus Spezifikationsarchäologie und Fehlerreproduktion. Es ist sicherer, zuerst die alte Komponente zu isolieren und nur die Grenze zu ordnen.

Für das Kapseln gibt es mehrere etablierte Formen.

Kapselungsform Geeignet für Worauf zu achten ist
WinForms-Host + AxHost / Aximp In bestehende Desktop-Bildschirme einbetten, nur wenige Bildschirme belassen STA, Ereignisse, Design-Time-Abhängigkeiten, Lizenzierung
32-Bit-Helper-EXE / COM-LocalServer / Prozessbrücke Umstellung auf 64-Bit, Abstürze isolieren Interprozesskommunikation, Startreihenfolge, Überwachung, Deployment
COM-kompatible Fassade auf der .NET-Seite Interna aktualisieren, während bestehende COM-Aufrufer erhalten bleiben IID / CLSID / TLB / Registrierungsart / Bitness

Steht die Richtung fest, hier auch noch, was der erste Schritt jeweils ist.

Kapselungsform Erster Schritt Ausführliche Anleitung
WinForms-Host + AxHost In Visual Studio mit der rechten Maustaste in die Toolbox klicken → „ToolBox-Elemente auswählen“ → auf der Registerkarte „COM-Komponenten“ das Ziel auswählen. Über die Kommandozeile: aximp Fallstricke bei Registrierung und Bitness in der COM-/OCX-/ActiveX-Entwicklung
32-Bit-Helper-EXE / LocalServer Die 32-Bit-EXE als COM-Server registrieren, von der 64-Bit-Seite out-of-proc aufrufen Ein COM-Fallbeispiel - Wenn Sie aus einer 32-Bit-Anwendung eine 64-Bit-DLL aufrufen möchten
Reg-Free COM In der Anwendungsmanifest-Datei file und comClass eintragen, Auflösung ohne Registry-Registrierung Was ist Reg-Free COM - COM ohne Registrierung nutzen
COM-kompatible Fassade auf der .NET-Seite Die .NET-Seite als COM veröffentlichen, bei Bedarf mit dscom eine TLB erzeugen .NET-8-DLL typisiert aus VBA nutzen - COM-Veröffentlichung und dscom TLB

aximp führen Sie über die Developer Command Prompt von Visual Studio aus.

aximp C:\path\to\MyControl.ocx

Dabei entstehen zwei Dateien: der COM-typisierte Runtime Callable Wrapper und ein von AxHost abgeleiteter Wrapper für Windows Forms. Der Dateiname wird dabei nicht aus dem ursprünglichen Dateinamen, sondern aus der ProgID bestimmt - das ist der einzige Punkt, auf den Sie achten müssen. Im Beispiel der Microsoft-Dokumentation entstehen aus msdxm.ocx die Dateien MediaPlayer.dll und AxMediaPlayer.dll. Sie fügen Letztere als Referenz hinzu und platzieren AxMediaPlayer auf dem Formular.

Bei Reg-Free COM sieht die Anwendungsmanifest-Datei in ihrer minimalen Form so aus.

<?xml version="1.0" encoding="utf-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity type="win32" name="MyApp" version="1.0.0.0" />
  <file name="MyControl.ocx">
    <comClass
      clsid="{01234567-89AB-CDEF-0123-456789ABCDEF}"
      threadingModel="Apartment"
      progid="MyCompany.MyControl.1" />
  </file>
</assembly>

Beim LocalServer-Ansatz steht in der Registry unter HKEY_CLASSES_ROOT\CLSID\{CLSID}\LocalServer32 der Pfad zur EXE. Bei einem mit ATL oder MFC gebauten EXE-Server ist es üblich, dass sich MyServer.exe /regserver und /unregserver konventionsgemäß selbst registrieren und deregistrieren lassen. Da sich die Registry-Ansicht jedoch je nach Bitness unterscheidet, gilt unbedingt zu beachten: Eine 32-Bit-EXE wird in der 32-Bit-Registry registriert.

Besonders wichtig ist es, beim Kapseln nicht einfach 200 alte APIs in Masse zu kopieren. Tut man das, importiert man lediglich die alten Eigenheiten unverändert in den neuen Code.

Beim Kapseln hilft es erheblich, Folgendes zu beachten.

  • Grobkörnige Methoden bilden
  • Den Bildschirmcode nicht direkt auf die OCX zugreifen lassen
  • Bei Fehlern die nötigen Logs an der Grenze erfassen
  • Verantwortlichkeiten für Timeouts, Wiederholungsversuche und Ausnahmeumsetzung an der Grenze festlegen
  • Auch einen künftigen Ersatz über dieselbe Schnittstelle austauschbar machen

Manchmal möchten Sie auf der neuen .NET-Seite nur den COM-Zugang erhalten. In diesem Fall ist eine Konstruktion realistisch, bei der „die Interna aktualisiert werden, während nur der COM-Vertrag erhalten bleibt“. Allerdings reicht es nicht unbedingt, mit der Instinktreaktion aus der Zeit des .NET Framework „einfach mal RegAsm“ zu sagen. Wie der moderne .NET-COM-Host, TLBs, Bitness und Registration-Free COM behandelt werden, sollte vorab entworfen werden - das erspart später viel Arbeit. Dazu gibt es ausführliche Schritt-für-Schritt-Anleitungen in .NET-8-DLL typisiert aus VBA nutzen - COM-Veröffentlichung und dscom TLB und Was ist Reg-Free COM - COM ohne Registrierung nutzen.

3.4. Die Entscheidung für Ersetzen

Für Ersetzen geeignet sind vor allem Fälle, in denen hauptsächlich oberflächliches Alter das Problem ist.

In Situationen wie diesen ist Ersetzen mit Priorität die richtige Sicht.

  • Das ActiveX wird ausschließlich als UI-Komponente genutzt
  • Der Hersteller bietet einen Nachfolger für .NET / WPF / WebView2 an
  • Browser-Abhängigkeit oder IE-Voraussetzung bremst
  • Registrierung, Signierung, Administratorrechte oder Sicherheitseinstellungen sorgen ständig für Stolpersteine
  • Es gibt Tests oder Geschäftsszenarien, mit denen sich eine alternative Implementierung verifizieren lässt

Umgekehrt endet es meist im Chaos, wenn man eine Komponente mit Gerätesteuerung oder Berichtslogik allein deshalb radikal verwirft, weil sie alt aussieht.

Wenn Sie ersetzen, beginnen Sie zuerst bei der UI.

  • Grids
  • Kalender
  • Bäume
  • Browser-Anzeigebereiche
  • Einfache Eingabehilfen

Diese lassen sich vergleichsweise leicht ersetzen. Manches sieht dagegen wie UI aus, ist aber innen dicht.

  • Vom Hersteller gelieferte ActiveX-Steuerelemente zur Gerätesteuerung
  • Steuerelemente, die mit Druck- oder Berichtserstellung verschmolzen sind
  • Steuerelemente, die das Lesen/Schreiben proprietärer Dateiformate einbetten
  • Steuerelemente mit COM-Callbacks oder Threading-Voraussetzungen

Verschätzt man sich hier, bricht die Aufwandsschätzung schlagartig zusammen.

3.5. Browser-Abhängigkeiten separat betrachten

Dieser Bereich ist wirklich eine eigene Kategorie.

Browser-basiertes ActiveX hat, anders als eine Desktop-OCX, eine ziemlich schwache Berechtigung für weitere Investitionen.

Der Grund ist einfach: Moderne Browser-Plattformen machen dies nicht mehr zu ihrem Schlachtfeld. Microsoft Edge selbst unterstützt kein ActiveX. Der IE-Modus dagegen verwendet für konfigurierte Sites die IE-Engine und lässt sich als Kompatibilitätsschicht nutzen, um einen Teil der IE-Funktionen, einschließlich ActiveX, weiterlaufen zu lassen.

Mit anderen Worten:

  • Übergangsweise am Laufen halten ist möglich
  • Aber als langfristiger Entwurf ist die Zukunft nicht breit

Dasselbe gilt für das in Windows-Anwendungen eingebettete WebBrowser-Steuerelement. WebBrowser schleppt die Denkweise der IE-Welt mit, weshalb es naheliegender ist, für neue Arbeiten von heute an WebView2 als ersten Kandidaten anzusetzen, wenn nur HTML angezeigt werden soll.

Zu beachten ist hier allerdings, dass WebView2 kein vollständiger Ersatz für WebBrowser ist.

  • Skripte, die vom IE-DOM ausgehen
  • ActiveX-Abhängigkeiten
  • Annahmen rund um window.external
  • Verhalten, das von Sicherheitszonen oder Intranet-Voraussetzungen ausgeht

Diese lassen sich nicht unverändert übernehmen. Wenn Sie ersetzen, müssen Sie nicht nur die Rendering-Engine, sondern auch die Verbindungsfläche zwischen Browser und nativer Anwendung neu entwerfen.

4. Punkte, die die Entscheidung leicht verzerren

4.1. UI-Komponente oder Komponente mit eigener Fachlogik?

Das ist der wichtigste Punkt.

Bei einem alten Grid oder Kalender kommt man mit der Prüfung von Optik- und Ereigniskompatibilität schon ziemlich weit. ActiveX mit Gerätesteuerung, Berichtswesen oder proprietärem Format hat dagegen hinter seiner Optik eine ganze Masse an Fachlogik.

Auch wenn es gleichermaßen wie „ein Steuerelement auf dem Bildschirm“ aussieht, reicht die Bandbreite tatsächlich so weit.

  • Eine reine Listendarstellungskomponente
  • Eine Komponente, die über ein proprietäres Protokoll Befehle an ein Gerät sendet
  • Eine Komponente, die intern sogar Timeouts, Wiederverbindung, erneutes Senden und Ausnahmebehandlung erledigt
  • Eine Komponente, die die Kompatibilität von Druck- oder Exportformaten trägt

Die zweite Gruppe unvermittelt neu zu implementieren, wird meist zu einem Spezifikationsarchäologie-Projekt. Hier ist Kapseln zuerst sicherer.

4.2. 32-Bit / 64-Bit und Prozessgrenzen

Dieser Punkt wird oft übersehen, ist aber ziemlich grundlegend.

Eine in-proc-OCX muss in derselben Bitness laufen wie der ladende Prozess. Das heißt, eine 32-Bit-OCX lässt sich nicht direkt in eine 64-Bit-Anwendung laden.

Die realistischen Optionen dabei sind im Wesentlichen diese drei.

  • Die Host-Anwendung vorerst ebenfalls bei 32-Bit belassen
  • Sie in einem separaten 32-Bit-Prozess einschließen und mit der 64-Bit-Seite über IPC oder Out-of-Process-COM verbinden
  • Die OCX-Abhängigkeit dort zuerst ersetzen, wo sie sich entfernen lässt

„Es ist ja Any CPU, das wird schon irgendwie gehen“ funktioniert hier meist nicht. Auch wenn Sie auf der neuen .NET-Seite eine COM-kompatible Fassade bauen, sind die Erscheinung des Managed Code und die tatsächliche Bitness des COM-Hosts zwei verschiedene Dinge. Fangen Sie das nachlässig an, bekommen Sie den unangenehmen Fall, dass der Build durchläuft, die Anwendung beim Kunden aber nicht startet.

4.3. Registrierung, Verteilung, Berechtigungen, Lizenzierung

Technisch aufrufbar, aber bei der Verteilung stirbt es. Das kommt bei ActiveX / OCX ziemlich häufig vor.

Die typischen Stolperstellen sind diese.

  • Die Voraussetzungen für regsvr32 stecken nur im Kopf einer Person
  • Die Platzierung abhängiger DLLs ist implizit
  • Administratorrechte sind erforderlich, wurden aber nie in die Betriebsanleitung übernommen
  • Design-Time- und Runtime-Lizenz eines Drittanbieter-Steuerelements sind getrennt
  • Es läuft auf dem Entwicklungsrechner, aber nicht in einer sauberen Umgebung

Diese Punkte können ein Projekt zum Stillstand bringen, ohne dass auch nur eine Codezeile angefasst wird.

Registrierungsfreie Konfigurationen oder Side-by-Side-Platzierung können die Sache in manchen Fällen erleichtern, sind aber kein Zaubermittel. Die Kompatibilität mit der Container-Seite und der Verteilungsmethode muss geprüft werden.

Kurz gesagt: Eine ActiveX-/OCX-Migration ist nicht nur Implementierung, sondern auch Verteilungsdesign. Wird dieser Teil aufgeschoben, stürzt man am Ende spektakulär.

4.4. STA / Nachrichtenschleife / Callbacks

ActiveX / OCX ist kein bloßer DLL-Aufruf. Es kann Voraussetzungen zum Threading-Modell von COM und zur Nachrichtenschleife mit sich tragen.

Besonders zu beachten sind Fälle wie diese.

  • Nur stabil, wenn vom UI-Thread aus vorausgesetzt
  • Geht von STA aus, wird aber unbedacht von der MTA-Seite aufgerufen
  • Ein Callback kommt mitten in einem synchronen Aufruf zurück
  • Die Thread-Voraussetzung zum Empfang von Ereignissen ist unklar

Diese Fälle treten anfangs im Gewand einer Geistergeschichte auf: „hängt manchmal“, „das Ereignis kommt manchmal nicht an“. Aber im Kern ist es meist ein Verstoß gegen eine Voraussetzung.

Deshalb sollte, ob beim Kapseln oder beim Ersetzen, vorab festgelegt werden: Auf welchem Thread wird erzeugt, von welchem Thread aus aufgerufen, und wo werden Ereignisse empfangen.

4.5. Gibt es Tests? Lässt es sich beobachten?

Ersetzen ist nicht nur deshalb schwierig, weil der Code alt ist. Es fehlt die Grundlage, um zu sagen, „es hat sich gleich verhalten“.

Schon das Vorhandensein solcher Dinge macht einen erheblichen Unterschied.

  • Smoke-Tests je Bedienszenario
  • Ein-/Ausgabebeispiele
  • Bildschirmaufnahmen oder Berichtsbeispiele
  • Fehlermuster und erwartetes Verhalten
  • Logs für Timeout- oder Nichtverbindungsfälle des Geräts

Besonders wenn Geräte oder Berichte im Spiel sind, tritt das eigenartige Phänomen auf, dass das tatsächliche Verhalten wahrer ist als das Pflichtenheft. Ohne Beobachtungsmittel wird Ersetzen zu einer Ausgrabung.

5. Empfehlungen nach typischem Muster

5.1. Eine intern noch stabil laufende Desktop-Anwendung

Empfehlung: eher behalten.

Unter Bedingungen wie diesen ist es oft besser, sie nicht gewaltsam herauszureißen.

  • Nur intern genutzt
  • Zielgeräte und Betriebssystem sind einigermaßen fixiert
  • Die OCX wird nur auf wenigen Bildschirmen verwendet
  • Die Änderungsanforderungen sind klein, und die Lebensdauer ist absehbar

Statt es aber einfach nackt liegen zu lassen, zahlt es sich später aus, zumindest die Aufrufstellen zu bündeln.

Als Richtung ergibt sich also dies.

  • Jetzt behalten
  • Aber nur die Grenze ordnen
  • Es so gestalten, dass Sie dort ansetzen können, sobald ein Ersatz nötig wird

Dieser dreistufige Aufbau ist die naheliegende Wahl.

5.2. Eine 32-Bit-OCX zur 64-Bit-Seite mitnehmen

Empfehlung: kapseln / Konfiguration ändern.

Geht man das frontal an, ist es aussichtslos. Eine 32-Bit-OCX lässt sich nicht in-proc in einen 64-Bit-Prozess laden.

Realistisch ist eine Konstruktion, bei der Sie sie in einem 32-Bit-Helper-Prozess oder LocalServer einschließen und über eine grobe API mit der 64-Bit-Anwendung kommunizieren.

32-Bit-OCX32-Bit-Helper / LocalServer64-Bit-.NET-Anwendung32-Bit-OCX32-Bit-Helper / LocalServer64-Bit-.NET-AnwendungAnfrage über grobe APIIn-proc-AufrufErgebnis / EreignisUmgewandeltes Ergebnis

Der entscheidende Punkt ist, nicht jede feingranulare Methode einzeln durchzureichen. Eine Prozessgrenze wird schnell schmerzhaft, wenn Sie große Mengen feingranularer Aufrufe hindurchschicken.

  • Auf eine Granularität von etwa 1 Operation = 1 Anfrage hinarbeiten
  • Rückgabewerte und Fehler zu sinnvollen Einheiten zusammenfassen
  • Logs an der Grenze erfassen

Mit dieser Struktur ist es später auch einfacher, die Interna tatsächlich zu ersetzen.

5.3. Bildschirme mit IE- / WebBrowser-Abhängigkeit

Empfehlung: Ersetzen priorisieren.

Das ist ein Bereich, in dem „funktioniert jetzt“ und „lässt sich auch künftig leicht pflegen“ selten zusammenfallen. Der IE-Modus hilft für die Kompatibilität sehr, dennoch bleibt die Voraussetzung die IE-Welt.

Als Denkweise ist es daher übersichtlich, so zu trennen.

  • Mit dem IE-Modus übergangsweise am Laufen halten, damit der interne Betrieb nicht stillsteht
  • Aber Übergangslösung und dauerhaften Entwurf nicht verwechseln
  • Das Ersatzziel aus WebView2, reinem Web oder einer Hybridlösung aus nativer UI und Web auswählen

Auch zur konkreten Übergangsmaßnahme sei Folgendes gesagt: Der IE-Modus wirkt nicht einfach „automatisch, sobald Edge installiert ist“. Er öffnet die betreffende Site erst mit der IE-Engine, wenn die Ziel-Site per Richtlinie angegeben wird. Es gibt dafür drei Zugänge.

Vorgehen Einstellung Anmerkung
Sites einzeln auflisten In der Gruppenrichtlinie „Configure the Enterprise Mode Site List“ (Microsoft Edge ab Version 78) den Speicherort der XML-Datei der Enterprise-Mode-Site-Liste angeben Die grundlegendste Form
Die alte IE-Liste weiterverwenden Die Richtlinie „Use the Enterprise Mode IE website list“ des Internet Explorer Ist die Edge-seitige Richtlinie gesetzt, hat sie Vorrang
Das gesamte Intranet umleiten Die Gruppenrichtlinie „Send all intranet sites to Internet Explorer“ (Microsoft Edge ab Version 77) aktivieren Der Geltungsbereich wird breiter - das ersetzt keine Bestandsaufnahme

Voraussetzung ist, dass Windows und Edge auf dem neuesten Stand sind, die administrativen Vorlagen von Microsoft Edge eingerichtet sind und die Windows-Funktion Internet Explorer 11 aktiviert ist. Fehlt eines davon, schlägt der IE-Modus fehl.

Im IE-Modus laufen im Übrigen ActiveX-Steuerelemente und Browser Helper Objects. Das heißt, die Übergangslösung funktioniert wirklich. Gerade deshalb kommt man ohne festgelegte Ausstiegsbedingung nicht wieder heraus, wenn man ihn einmal dauerhaft nutzt. Wie man sich davon löst, ist im Leitfaden zum Ausstieg aus IE-Modus-abhängigen Systemen zusammengefasst.

Wird das WebBrowser-Steuerelement lediglich als HTML-Betrachter genutzt, ist die Ersetzungspriorität besonders hoch.

Trägt das ActiveX im Browser dagegen Rollen wie lokale Dateien, Geräte, Signierung oder proprietäre Add-ons, ist das kein Austausch der Rendering-Engine mehr, sondern eine Neugestaltung der nativen Integration. Das wird dann etwas schwergewichtiger.

5.4. ActiveX mit Gerätesteuerung oder proprietärer Fachlogik

Empfehlung: zuerst kapseln.

Dieser Typ ist innen dichter, als er aussieht. Selbst wenn die SDK-Dokumentation dünn ist, können sich durch jahrelangen Betrieb vor Ort implizit Verhaltensweisen wie diese angesammelt haben.

  • Wie bei einem Verbindungsfehler gewartet wird
  • Wiederholungsversuche nach einem Timeout
  • Die Reihenfolge der Ereignisse
  • Workarounds, die Eigenheiten der realen Hardware abfangen
  • Die Interpretation von Ausnahmen und Fehlercodes

Baut man diese Art von Komponente mit der Begründung „ist ja sowieso alt“ neu, brennen die Feldtests mit hoher Wahrscheinlichkeit lichterloh.

Deshalb ist es am sichersten, hier zu beginnen.

  1. Die bestehende Komponente innerhalb einer Grenze einschließen
  2. Logging hinzufügen, damit sichtbar wird, was geschieht
  3. Testszenarien und Muster von der realen Hardware sammeln
  4. Danach die ersetzbaren Bereiche herausschälen

Es wirkt unspektakulär, ist aber in der Praxis das Wirksamste.

6. Häufige Antimuster

Antimuster Warum es schmerzt Erste Abhilfe
Wegen ActiveX gleich alles neu schreiben Spezifikationslücken und Aufwandsexplosion sind wahrscheinlich Erst Bestandsaufnahme, dann Grenzen herausschälen
Eine 32-Bit-OCX unverändert in eine 64-Bit-Anwendung laden wollen Prinzipiell unmöglich Auf der 32-Bit-Seite isolieren oder die Konfiguration ändern
Die API des Steuerelements direkt aus dem gesamten Bildschirmcode aufrufen Wird leicht unersetzbar Auf Adapter / Facade bündeln
regsvr32-Schritte manuell betreiben Umgebungsunterschiede führen jedes Mal zu Zwischenfällen Installer, Skripte oder Manifest-Ansatz prüfen
Sich beruhigen, weil es den IE-Modus gibt Übergangslösung und Dauerlösung werden leicht verwechselt Ersatzplan und Ausstiegsbedingung festlegen
Vor dem Ersetzen das Verhalten nicht aufgezeichnet haben Fertigstellung lässt sich nicht beurteilen Smoke-Tests, Beispieldaten und Logs zusammenstellen

Von diesen sind besonders drei in der Praxis häufig anzutreffen.

  1. Ein vollständiges Neuschreiben zu forcieren
  2. Die Bitness-Grenze zu unterschätzen
  3. Die API über die ganze Anwendung zu verstreuen

Schon das Vermeiden dieser drei Punkte senkt die Unfallquote erheblich.

7. Checkliste für den Start einer Migration

Bei ActiveX-/OCX-Projekten läuft es besser, wenn Sie zuerst eine Bestandsaufnahme machen, statt direkt in die Implementierung einzusteigen. Die Reihenfolge sieht ungefähr so aus.

  1. Die verwendeten OCX / DLLs ermitteln
    • Dateiname, Version, ProgID, CLSID, Hersteller, Vorhandensein einer Lizenz
  2. Ermitteln, wo sie eingesetzt werden
    • Bildschirme, Funktionen, Berichte, Geräte, Stapelverarbeitung, Office-Integration und Ähnliches
  3. Bitness und Host-Bedingungen prüfen
    • 32-Bit / 64-Bit, in-proc / out-of-proc, STA-Voraussetzung, Browser-Abhängigkeit
  4. Verteilungsbedingungen prüfen
    • Registrierungsmethode, abhängige DLLs, Administratorrechte, stille Installation, Reproduzierbarkeit in sauberer Umgebung
  5. Smoke-Tests erstellen
    • Nicht nur den Normalfall, sondern auch Fehler-, Nichtverbindungs- und Timeout-Fälle einbeziehen
  6. Eine Grenze schaffen
    • Adapter, Service, Facade, Prozessbrücke und Ähnliches
  7. In kleinen Einheiten testen - ein Bildschirm, eine Funktion, ein Gerät
  8. Ausgehend von den erfolgreichen Grenzen Behalten / Kapseln / Ersetzen schrittweise ausweiten

Überspringen Sie diese Schritte, lässt sich später nicht einmal mehr erklären, „was eigentlich schwierig war“.

8. Grobe Entscheidungshilfe

Situation Erste Wahl
Nur intern, stabil, kleine Änderungen Behalten
Nur das Umfeld soll auf .NET modernisiert werden Kapseln
32-Bit / 64-Bit kollidieren Kapseln / Konfiguration ändern
IE / WebBrowser / Browser-ActiveX-Abhängigkeit Ersetzen
Reine UI-Komponente mit vorhandener Alternative Ersetzen
Trägt Gerätesteuerung, Berichtswesen, proprietäre Fachlogik Kapseln
Registrierung oder Verteilung sorgt jedes Mal für Ärger Kapseln oder ersetzen

Im Zweifel hilft es sehr, zunächst zu unterscheiden, ob es sich um eine UI-Komponente oder eine Grenzfläche mit eigener Fachlogik handelt - damit liegen Sie deutlich seltener daneben.

9. Zusammenfassung

Wie man mit ActiveX / OCX umgeht, ist keine Frage, die man mit „das ist Legacy, also unbeliebt“ entscheidet.

Zuerst sollten Sie vier Punkte betrachten.

  1. Ist die Komponente reine UI, oder eine Grenzfläche mit eigener Fachlogik?
  2. Muss sie im selben Prozess laufen?
  3. Verhaken Sie sich an 32-Bit / 64-Bit, Registrierung, Browser-Abhängigkeit oder Lizenzierung?
  4. Lässt sich das Verhalten vor dem Ersetzen beobachten?

Sind diese vier Punkte geklärt, lässt sich die Sache im Wesentlichen so ordnen.

  • Läuft es stabil und ist die Lebensdauer absehbar: behalten
  • Soll nur das Umfeld modernisiert werden: kapseln
  • UI-Komponente oder browser-abhängig: ersetzen
  • Eine Komponente mit einer Masse an Fachlogik: zuerst kapseln, dann schrittweise ersetzen

Legacy-Technik ist kein Anlass zum Lachen, sondern ein reales Artefakt, das Geschichte und Verträge in sich trägt. Der Umgang mit diesem Artefakt erfordert allerdings ein durchdachtes Grenzdesign.

Sobald Sie in einer Mischung aus „Behalten, Kapseln, Ersetzen“ denken können, verwandeln sich ActiveX-/OCX-Projekte plötzlich in beherrschbare Probleme.

10. Für solche Anliegen sind wir ein guter Ansprechpartner

Bei diesem Thema entsteht oft schon durch die reine Ausrichtungsklärung, bevor die Entwicklung beginnt, ein spürbarer Nutzen.

Anliegen wie diese passen zum Beispiel ziemlich gut.

  • Sie möchten eine Bestandsaufnahme machen, welche OCX wirklich ersetzt werden sollte
  • Sie möchten nur die Engpässe bei 32-Bit / 64-Bit vorab klären
  • Sie wollen auf .NET umstellen, aber nur den COM-Zugang erhalten
  • Sie möchten Übergangsmaßnahmen und Ausstiegsstrategie für ein ActiveX vergleichen, dessen Hersteller nicht mehr aktiv ist
  • Sie möchten sehen, wo sich IE-/WebBrowser-Abhängigkeiten zuerst lösen lassen
  • Sie möchten zunächst nur einen Bildschirm oder eine Funktion sicher isolieren

Bei ActiveX-/OCX-Projekten entscheidet oft wie die Grenzen gezogen werden mehr über den Ausgang als die Implementierung selbst. Schon der Einstieg über Bestandsaufnahme, Konfigurationsvergleich und Entwurf der Migrationsreihenfolge als Vorstufe zu einer umfassenden Überarbeitung ist durchaus wertvoll.

11. Referenzen

  • Microsoft Learn: AxHost Class (System.Windows.Forms)
    • https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.axhost
  • Microsoft Learn: Aximp.exe (ActiveX-Steuerelement-Importer für Windows Forms)
    • https://learn.microsoft.com/en-us/dotnet/framework/tools/aximp-exe-windows-forms-activex-control-importer
  • Microsoft Learn: How to: Add ActiveX Controls to Windows Forms
    • https://learn.microsoft.com/en-us/dotnet/desktop/winforms/controls/how-to-add-activex-controls-to-windows-forms
  • Microsoft Learn: Expose .NET Core components to COM
    • https://learn.microsoft.com/en-us/dotnet/core/native-interop/expose-components-to-com
  • Microsoft Learn: Registration-Free COM Interop
    • https://learn.microsoft.com/en-us/dotnet/framework/interop/registration-free-com-interop
  • Microsoft Learn: Häufig gestellte Fragen zu Microsoft Edge
    • https://learn.microsoft.com/en-us/deployedge/microsoft-edge-frequently-asked-questions
  • Microsoft Learn: What is Internet Explorer (IE) mode?
    • https://learn.microsoft.com/en-us/deployedge/edge-ie-mode
  • Microsoft Learn: WebBrowser Class (System.Windows.Forms)
    • https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.webbrowser
  • Microsoft Learn: Introduction to Microsoft Edge WebView2
    • https://learn.microsoft.com/en-us/microsoft-edge/webview2/
  • KomuraSoft Blog: Grundlagen zur Vermeidung von Hängern bei COM STA/MTA
    • https://comcomponent.com/de/blog/sta-mta-com-relationship/
  • KomuraSoft Blog: Warum Sie beim Aufruf nativer C++-DLLs aus C# einen C++/CLI-Wrapper bauen sollten
    • https://comcomponent.com/de/blog/cpp-cli-wrapper-for-native-dlls/
  • KomuraSoft Blog: Ein COM-Fallbeispiel - Wenn Sie aus einer 32-Bit-Anwendung eine 64-Bit-DLL aufrufen möchten
    • https://comcomponent.com/de/blog/com-case-study-32bit-to-64bit/
  • KomuraSoft Blog: Was sind COM / ActiveX / OCX - Unterschiede und Zusammenhänge erklärt
    • https://comcomponent.com/de/blog/what-is-com-activex-ocx/
  • KomuraSoft Blog: .NET-8-DLL typisiert aus VBA nutzen - COM-Veröffentlichung und dscom TLB
    • https://comcomponent.com/de/blog/dotnet8-dll-typed-vba-com-dscom-tlb/
  • KomuraSoft Blog: Was ist Reg-Free COM - COM ohne Registrierung nutzen
    • https://comcomponent.com/de/blog/what-is-reg-free-com/
  • KomuraSoft Blog: Fallstricke bei Registrierung und Bitness in der COM-/OCX-/ActiveX-Entwicklung
    • https://comcomponent.com/de/blog/com-ocx-activex-pitfalls-visual-studio-bitness-admin-rights/
  • KomuraSoft Blog: Leitfaden zum Ausstieg aus IE-Modus-abhängigen Systemen
    • https://comcomponent.com/de/blog/ie-mode-internal-web-system-life-extension-and-exit/
  • KomuraSoft Blog: Ist nach dem IE-Modus WebView2 die richtige Wahl? - Die Einschränkung, dass ActiveX nicht läuft, und ein realistischer Migrationsentwurf
    • https://comcomponent.com/de/blog/webview2-embed-web-ui-in-windows-apps/

Aktuelle Artikel mit denselben Schlagwörtern führen zu verwandten Themen weiter.

Diese Seiten ordnen den Artikel in einen größeren Leistungs- und Entscheidungskontext ein.

Dieser Artikel ist direkt mit den folgenden Leistungen verbunden.

Häufige Fragen

Fragen, die in Beratungen zu diesem Artikelthema häufig gestellt werden.

Sollte man ActiveX / OCX ersetzen?
Die Entscheidung richtet sich nicht danach, ob die Komponente alt ist, sondern danach, was sie eigentlich übernimmt. Ist es nur eine UI-Komponente mit vorhandener Alternative, ist Ersetzen sinnvoll; trägt sie Gerätesteuerung, Berichtswesen oder ein proprietäres Dateiformat, ist es sicherer, sie zunächst zu kapseln und die Grenze zu ordnen; läuft sie stabil und ist der Änderungsumfang klein, ist auch Behalten eine realistische Entscheidung. Sowohl „einfach alles neu schreiben“ als auch „aus Angst für immer einfrieren“ sind Entscheidungen mit hoher Unfallquote.
Kann ich eine 32-Bit-OCX aus einer 64-Bit-Anwendung heraus verwenden?
In-proc geht das nicht. Eine OCX muss in derselben Bitness wie der ladende Prozess laufen - das ist eine grundsätzliche Einschränkung. Realistische Optionen sind: die Host-Anwendung vorerst ebenfalls bei 32-Bit belassen; die OCX in einem separaten 32-Bit-Prozess (Helper-EXE oder COM-LocalServer) einschließen und mit der 64-Bit-Seite über IPC oder Out-of-Process-COM verbinden; oder die OCX-Abhängigkeit dort zuerst ersetzen, wo sie sich am leichtesten entfernen lässt.
Wie soll man mit ActiveX-Abhängigkeiten im Browser umgehen?
Am besten mit Ersetzen als Priorität. Microsoft Edge selbst unterstützt ActiveX nicht, und der IE-Modus ist als Übergangslösung gedacht. Auch das WebBrowser-Steuerelement schleppt die Denkweise der IE-Welt mit, weshalb WebView2 der erste Kandidat ist, wenn nur HTML angezeigt werden soll. WebView2 ist aber kein vollständiger Ersatz: Skripte, die vom IE-DOM ausgehen, sowie Annahmen rund um window.external lassen sich nicht unverändert übernehmen.
Was bedeutet es konkret, ActiveX / OCX zu „kapseln“?
Es bedeutet, ActiveX / OCX innerhalb einer engen Grenze einzuschließen und der Umgebung gegenüber als neue API oder neues Bildschirmelement erscheinen zu lassen. Übliche Formen sind ein WinForms-Host mit AxHost, eine Prozessbrücke über eine 32-Bit-Helper-EXE oder einen LocalServer sowie eine COM-kompatible Fassade auf der .NET-Seite. Beim Kapseln sollte man die alte API nicht einfach in Masse kopieren, sondern grobkörnige Methoden bilden, an der Grenze Verantwortlichkeiten für Logging, Timeouts und Ausnahmeumsetzung festlegen und dafür sorgen, dass ein künftiger Ersatz über dieselbe Schnittstelle austauschbar bleibt.

Autorenprofil

Profilseite des Artikelautors.

Go Komura

Geschäftsführer von KomuraSoft LLC

Spezialisiert auf Windows-Softwareentwicklung, technische Beratung und Fehleranalyse, insbesondere bei bestehenden Systemen und schwer reproduzierbaren Störungen.

Zurück zum Blog