10.2. Verwaltung der Module

10.2.1. Aufbau der Modulketten

Die einzelnen residenten Module werden über zwei Ketten miteinander verbunden. Eine Kette ist iterativ, d.h. vorwärts gerichtet, die andere rekursiv, also rückwärts gerichtet. Was dies genau bedeutet, kann am besten an einem kleinen Beispiel aus der Praxis veranschaulicht werden :

Die Applikation DASM32 benötigt zwei DLLs, um korrekt ausgeführt zu werden : CRTD.DLL und SYS4G.DLL. Beide DLLs befinden sich im BIN-Verzeichnis nach der Installation, also dort, wo sich auch alle anderen DiceRTE-Anwendungen befinden. Das DASM32-Modul in der Programmdatei besteht aus insgesamt 4 Objektimages: '.text' (=Codesegment), '.data' (=initialisierte Daten), '.reloc' (=Relokationstabelle) und '.idata'. Nachdem alle Images eingeladen wurden, wird das Modul 'DASM32' an die iterative Modulkette gehängt (in diesem Fall ist es noch das einzige Modul). Nachdem die Relokation anhand des '.reloc'-Objekts durchgeführt wurde, wird das '.idata'-Objekt analysiert. Hier sind nun die beiden DLLs und die aus ihnen benötigten Symbole aufgelistet. Der Programmlader beginnt nun seine Suche nach der ersten DLL (CRTD.DLL) in der iterativen Liste. Da sie noch nicht vorhanden ist, wird sie aus dem BIN-Verzeichnis eingeladen. Nun spielt sich dasselbe wie oben ab: die Objektimages von CRTD.DLL werden geladen, das Modul wird an die iterative Kette gehängt, die Relokation wird durchgeführt und das Importimage wird analysiert. Hier sind nun Referenzen auf Symbole aus SYS4G.DLL aufgelistet. Das Spiel beginnt nun wieder von vorne :

Da SYS4G.DLL kein Importimage besitzt, also nicht auf andere Module angewiesen ist, ist das Einladen dieses Moduls beendet und es wird an die rekursive Kette gehängt (ist hier erstes Modul). Nun erfolgt der Rücksprung zur Verarbeitung des Importimages von CRTD.DLL. Da die SYS4G.DLL erfolgreich geladen wurde, können nun die Referenzen darauf aufgelöst werden. Danach wird CRTD.DLL an die rekursive Kette gehängt (hinter SYS4G.DLL) und es erfolgt der Rücksprung zur Verarbeitung des Importimages von DASM32. Da jetzt die CRTD.DLL auch erfolgreich geladen wurde, können die Referenzen von DASM32 auf deren Symbole aufgelöst werden. Als zweite DLL wird noch SYS4G.DLL benötigt, die aber schon geladen wurde. Daher können nun direkt die Referenzen auf SYS4G.DLL hergestellt werden. Zum Schluß wird DASM32 an die rekursive Kette gehängt.

Am Ende dieses (ziemlich komplexen) Vorgangs stehen also zwei Modulketten, die die Abhängigkeiten zwischen den einzelnen Modulen widerspiegeln. Aufgrund des obigen Algorithmus wird ein Modul also immer vor der Auflösung seines Importimages an die iterative und danach an die rekursive Modulkette gehängt.

10.2.2. DllInits und -Exits

Die rekursive Kette dient dazu, Abhängigkeiten zwischen einzelnen Modulen zu berücksichtigen, was bei der folgenden Ausführung der DllInit-Funktionen äußerst wichtig ist. So ist es in diesem Beispiel wichtig, daß zuerst das Modul SYS4G.DLL initialisiert wird, da es selbst keine Abhängigkeiten vorzuweisen hat. Danach kommt CRTD.DLL, da es auf SYS4G.DLL-Symbolen basiert und schließlich DASM32, das von beiden vorherigen Modulen abhängig ist. Die Module werden also bei der nun folgenden Initialisierung in der Reihenfolge der rekursiven Kette durchgearbeitet.

Die iterative Kette dient dazu, bei der Auflösung externer Referenzen bereits eingeladene Module zu finden. Die fertige Verarbeitung des Importimages dieser gesuchten Module ist dabei irrelevant. Ferner dient die iterative Kette zur Ausführung der DllExit-Funktionen, da hier die Module in umgekehrter Reihenfolge entfernt werden müssen.

Die DllInit-Funktion dient dazu, Variablen einer DLL zu initialisieren, bevor deren Funktionen verwendet werden. Hier können z.B. Dateien geöffnet, Speicherbereiche reserviert und Datenstrukturen gefüllt werden. Die Funktion bekommt keine Parameter übergeben, muß aber einen Integer-Rückgabewert liefern, der anzeigt, ob die Initialisierung erfolgreich war ( <>3 ) oder nicht ( =3 ). Liefert eine der DllInit-Funktionen den Wert 3 zurück, wird die Ausführung sofort abgebrochen und die DllExit-Funktion der bereits aktivierten Module in umgekehrter Reihenfolge ausgeführt. Dadurch kann verhindert werden, daß die Applikation ausgeführt wird, obwohl die Initialisierung einer oder mehrerer DLLs fehlgeschlug (z.B. Datei konnte nicht angelegt werden, kein Speicher mehr frei etc.).
Die DllExit-Funktionen bekommen den Rückgabewert der jeweiligen DllInit-Funktion als Integer-Parameter übergeben. Einen Rückgabewert gibt es hier nicht, da das Scheitern einer Aktion hier keine Konsequenzen für die Ausführung der folgenden DllExits hat, denn diese sind in umgekehrter Reihenfolge voneinander abhängig. Die DllInit und -Exit-Funktionen können (wie in C üblich) auch mit exit oder abort beendet werden.

10.2.3. Struktur residenter Module

Die Struktur eines geladenen und im Speicher resident installierten Moduls ist identisch mit der Struktur innerhalb der Programmdatei. Am Anfang befindet sich also wieder der Kopfsatz (256 Bytes), gefolgt von der Objekttabelle und den Objektimages. Die ersten 204 Bytes im Kopfsatz entsprechen den Daten aus der Programmdatei, dahinter sind nun die folgenden Felder :

Offset Typ Bedeutung
204 Dword Applikations-ID
208 Byte[16] Modulname (terminiert mit '\0')
224 Dword nächstes Modul (iterative Kette)
228 Dword nächstes Modul (rekursive Kette)
232 Dword Rückgabewert von DllInit
236 Dword[5] momentan unbenutzt
256- ??? Objekttabelle