Alte Software modernisieren: Delphi, VB6 und MFC schrittweise nach .NET

Laborarbeitsplatz mit Pipette, Proben und Messsoftware auf dem Laptop

Softwarearchitektur und UML

Die Software läuft seit zwanzig Jahren, die Kunden verlassen sich auf sie – und der Einzige, der den Delphi-Code wirklich kennt, geht nächstes Jahr in Rente. Alles neu schreiben? Das dauert Jahre und bringt erst am Ende Nutzen. Es gibt einen besseren Weg: Stück für Stück, ohne den Betrieb anzuhalten.

Warum jetzt – und warum nicht alles auf einmal

Bei Visual Basic 6 ist die Lage eindeutig. Microsoft unterstützt die Entwicklungsumgebung seit dem 8. April 2008 nicht mehr. Die Laufzeit funktioniert laut Microsoft auch unter Windows 11, unterstützt wird sie aber nur bei schweren Rückschritten und kritischen Sicherheitslücken. Microsoft empfiehlt ausdrücklich, VB6-Anwendungen zu ersetzen. Delphi und MFC werden dagegen weiter gepflegt. Dort kommt der Druck von anderer Seite: weniger Entwickler, die den Code verstehen, eine veraltete Oberfläche, fehlende Tests, Bibliotheken ohne Updates.

Eine Brücke, über die täglich Verkehr rollt, reißt niemand ab, um eine neue zu bauen. Man baut daneben und verlegt Spur für Spur. Martin Fowler nennt dieses Muster nach der Würgefeige, die einen Baum langsam umwächst: Neuer Code wächst um den alten herum, bis der alte sich abschalten lässt. Jeder Schritt geht in Betrieb und bringt sofort Nutzen.

Fünf Schritte

  1. Bestandsaufnahme: Module, Datenbank, Schnittstellen und Formulare erfassen. Welche Teile ändern sich oft, welche verursachen die meisten Fehler?
  2. Verhalten festhalten: Die alte Software mit echten Eingaben laufen lassen und die Ergebnisse aufzeichnen. Diese „Golden Master“ sind der Maßstab für jede neue Zeile.
  3. Brücke bauen: Alt und Neu müssen miteinander reden, solange beide leben.
  4. Modul für Modul umziehen: Mit dem Teil beginnen, der sich am häufigsten ändert oder am meisten schmerzt. Jeden Schritt ausliefern.
  5. Abschalten: Erst wenn nichts mehr den alten Teil aufruft, fliegt er raus.

Brücken zwischen Alt und Neu

  • Delphi: Der alte Rechenkern wird als DLL mit stdcall-Exporten erreichbar gemacht, .NET ruft ihn per P/Invoke auf. Alternativ spricht man über COM.
  • VB6: Neue Teile entstehen in .NET und werden als COM-Server bereitgestellt. Mit EnableComHosting erzeugt das SDK eine .comhost.dll, die mit regsvr32 registriert wird. Zwei Fallen: VB6 ist 32 Bit, die COM-Hülle ist aber standardmäßig 64 Bit. Und .NET erzeugt keine Typbibliothek mehr. Für frühe Bindung in VB6 schreiben Sie sie per IDL selbst oder binden spät über CreateObject.
  • MFC: C++/CLI verbindet nativen und .NET-Code im selben Prozess. Neue Dialoge entstehen in WPF oder WinForms und werden in die MFC-Fenster eingebettet.

So sieht die Delphi-Brücke im Kleinen aus. Der alte Kern:

library Messkern;

// Alter Rechenkern, als DLL mit stdcall nach außen gereicht
function Mittelwert(Werte: PDouble; Anzahl: Integer): Double; stdcall;
var
  I: Integer;
  Summe: Double;
begin
  Summe := 0;
  for I := 0 to Anzahl - 1 do
  begin
    Summe := Summe + Werte^;
    Inc(Werte);
  end;
  if Anzahl > 0 then
    Result := Summe / Anzahl
  else
    Result := 0;
end;

exports
  Mittelwert;

begin
end.

Und der Aufruf aus C#, gleich mit dem Vergleich gegen die neue Umsetzung:

using System;
using System.Linq;
using System.Runtime.InteropServices;

double[] messreihe = { 10.2, 10.4, 10.1, 10.3 };
double alt = Messkern.Mittelwert(messreihe, messreihe.Length);
double neu = messreihe.Average();
// Golden Master: Der neue Code muss liefern, was der alte geliefert hat
Console.WriteLine(Math.Abs(alt - neu) < 1e-9 ? "gleich" : $"Abweichung: {alt} / {neu}");

internal static class Messkern
{
    // Ist die DLL 32 Bit, muss auch der .NET-Prozess als x86 laufen
    [DllImport("Messkern.dll", CallingConvention = CallingConvention.StdCall)]
    internal static extern double Mittelwert(double[] werte, int anzahl);
}

Fallen bei Datentypen

  • Gleitkomma: Delphis Extended ist unter Win32 zehn Byte groß, ein .NET-double acht. Ergebnisse weichen deshalb in den letzten Stellen ab. Vergleichen Sie mit Toleranz.
  • Datum: Delphis TDateTime und VB6-Date zählen Tage seit dem 30.12.1899 als Gleitkommazahl. DateTime.FromOADate übersetzt sie.
  • Währung: Currency ist in beiden Sprachen eine 64-Bit-Ganzzahl mit vier festen Nachkommastellen. In .NET wird daraus decimal, nicht double.
  • Texte: Delphi-string gehört nie über eine DLL-Grenze. Nehmen Sie PWideChar oder WideString. Ältere Delphi-Versionen arbeiten mit ANSI-Texten, meist in Codepage 1252.

Aus der Praxis

Ein Messgerätehersteller setzte seit Jahrzehnten eine selbst entwickelte Delphi-Software ein. Am Anfang standen Beratung und Planung: Ziele und Möglichkeiten neuer Technologien haben wir gegenübergestellt, Prototypen zeigten, wie Lösungen aussehen könnten. Danach haben wir das ganze Team des Kunden vor Ort geschult. Ein Projektteam aus zehn Personen portiert die Software agil nach C# und WPF, mit MariaDB und Entity Framework. Die neue Software ist intern bereits im Einsatz und überzeugt Messtechniker wie Vertrieb. Bei einem Tiefbau-Aufsatz in C++, MFC und ObjectARX hat eine Wirtschaftlichkeitsrechnung vorab gezeigt, ab wann sich die Portierung bezahlt macht.

Typische Fehler

  • Alles neu, alles auf einmal: jahrelang kein Nutzen, und am Ende fehlt die Hälfte.
  • Nach Erinnerung neu schreiben statt nach gemessenem Verhalten.
  • Alte Fehler stillschweigend korrigieren, auf die sich Anwender oder Folgesysteme verlassen.
  • 32 und 64 Bit mischen. Eine 32-Bit-DLL in einem 64-Bit-Prozess endet in einer BadImageFormatException.
  • Texte ohne klare Regel über die Grenze reichen. Das Ergebnis sind Abstürze oder kaputte Umlaute.
  • Die Oberfläche Pixel für Pixel nachbauen, statt die Abläufe zu verbessern.
  • Das eigene Team nicht mitnehmen. Wer den neuen Code nicht versteht, pflegt bald wieder Altsoftware.

So helfen wir

Quellen: Microsoft, „Support Statement for Visual Basic 6.0 on Windows“; Microsoft Learn, „Exposing .NET Core components to COM“; Martin Fowler, „Strangler Fig Application“; Embarcadero DocWiki, „System.Extended“; Fallstudien „Modernisierung einer Messgerätesoftware: von Delphi nach C#“ und „Modernisierung eines AutoCAD-Aufsatzes für den Tiefbau“, Cadida-Fallstudien.

KONTAKT

Sprache auswählen

ErstgesprächvereinbarenErstgesprächvereinbaren