Spezialfälle in Windows 95

Aus API Sicht waren Windows 95, 98 und ME für mich so ziemlich das gleiche, nämlich ein reduziertes Set von NT4. Die Frage war damals also:

Ist etwas kompatibel mit “NT4” oder “nur 9x”.

Doch … Windows 95 war stets “weniger”, der Support wurde schnell fallen gelassen als 98 auf den Markt kam … und heute verstehe ich erst, warum das so war.


Das schöne an Visual Basic 6 Code war: Er lief überall, da er nur Windows 95 als Minimum voraussetzte und selbst dort nur Teile der Windows API nutzte.

In C/C++ musst man sich über diverse Makros entscheiden, ob man bei NT4 startete, oder nur:

  • das 95er Subset
  • 95 + IE4
  • 98
  • 98 + IE5

usw. einsetzen wollte. Je nach Wahl wurden mehr APIs freigeschaltet, bzw. neue Flags und structs für diese APIs.

Windows 95 (auch als v4.0 bekannt) war das erste 32-bit OS mit “neuem” Design und man mag denken, es wäre der kleine Bruder von NT4 (auch v4.0), doch es liegt in Wahrheit irgendwo zwischen NT 3.5 und NT 4.0.

Fehlende Komponenten

Meine neulichen Compiler-Experimente mit Visual Studio 2003 deckten auf, dass GATE Code zwar auf Windows 98 liefen, unter 95 jedoch mit fehlenden Einsprungpunkten abbrachen.

Interlocked Compare Exchange

InterlockedIncrement(), ...Decrement und ...Exchange gab es bereits, doch InterlockedAdd() und InterlockedCompareExchange() fehlten. Das bedeutet: Reference-Counting-Support ist da, State-Machine-Support nicht.

Ich nutze CompareExchange häufig zum sicheren Umschalten zwischen Zuständen und das tun auch andere Bibliotheken.

Winsock 1

Es gibt de facto keine Software, die nicht gegen ws2_32.dll, also Winsock-2 linkt, wenn sie TCP/IP braucht, doch eben diese DLL fehlte im originalen Win95. Sie wurde zwar mit dem Internet Explorer nachgeliefert … doch der war damals eben noch kein Standard.
Während NT4 und 98 somit “jede” Netzwerk Software ausführen konnte, wurde 95 meist ausgeschlossen.

UTF-8

WideCharToMultiByte() und MultiByteToWideChar() sind die beiden wichtigsten Funktionen, um zwischen NT’s Unicode Strings und alten Win9x ANSI Strings hin und her zu konvertieren. Mit dem Flag CP_UTF8 war auch UTF-8 als char-Output möglich … doch erst ab 98.

Mir flog das als “unerklärbarer” Fehler um die Ohren, denn im GATE Projekt sind alle Strings UTF-8 und müssen entweder nach UTF-16 oder ANSI konvertiert werden, wenn Windows-APIs aufgerufen werden.

Fibers

Die Fiber-APIs kommen ebenso erst mit Windows 98, obwohl sie schon in NT 3.51 implementiert waren.
Zwar sind Fibers im GATE Projekt optional, doch nun weiß ich: OpenSSL und andere Hilfsbibliotheken nutzen ebenso Fibers oder fragen zumindest ab, ob die Ausführung auf einem Thread oder einem Fiber läuft.

Fazit

Meine Lösung zur Umgehung dieser Probleme ist: im ANSI-Modus werden die fehlenden APIs durch Fallbacks ersetzt. Unicode Varianten laufen daher ab NT4 mit Standard APIs, ANSI Varianten implementieren Fallbacks für Windows 95.

Mein größtes Problem sind Fremdbibliotheken, für die habe ich aktuell keine richtige Lösung. Zwar wäre es möglich per Makros die Aufrufe von Fiber- und Interlocked-Code auf selbst implementierte Hilfsfunktionen umzuleiten … aber wer weiß, ob das Ergebnis dann korrekt ist.

Vorerst muss ich leider Tools mit SSL und SQLite von Windows 95 ausschließen. Und das ist deshalb ärgerlich, weil es nur 2 oder 3 Aufrufe innerhalb dieser Bibliotheken gibt.

Doch ich habe nun (20 Jahre zu spät) endlich gelernt, warum einige Projekte damals einfach nicht Win95-kompatibel waren.
Ich dachte damals, dass UI-Spezialitäten daran Schuld wären, doch die Ursache lag teilweise viel tiefer.

Relevanz hat diese Erkenntnis heute keine mehr. Doch sie zeigt die historische Entwicklung und Integration von Funktionen bzw. deren Prioritäten recht gut auf.