Section courante

A propos

Section administrative du site

Utilisation de recouvrement

Les recouvrements font partie d'un programme partageant une zone de mémoire commune. Seules les parties du programme étant nécessaires pour une fonction donnée résident en même temps en mémoire; ils peuvent se remplacer pendant l'exécution. Les recouvrements peuvent réduire considérablement les besoins totaux de mémoire d'exécution d'un programme. En fait, avec les recouvrements, vous pouvez exécuter des programmes beaucoup plus volumineux que la mémoire totale disponible, car seules des parties du programme résident en mémoire à un moment donné. Le Turbo Pascal gère les recouvrements au niveau de l'unité; c'est la plus petite partie d'un programme pouvant être transformée en recouvrement. Lorsqu'un programme de recouvrement est compilé, le Turbo Pascal génère un fichier de recouvrement (extension .OVR) en plus du fichier exécutable (extension .EXE). Le fichier .EXE contient les parties statiques (sans le recouvrement) du programme et le fichier .OVR contient toutes les unités de recouvrement étant permutées dans et hors de la mémoire pendant l'exécution du programme. À l'exception de quelques règles de programmation, une unité de recouvrement est identique à une unité sans recouvrement. En fait, tant que vous respectez ces règles, vous n'avez même pas besoin de recompiler une unité pour en faire un recouvrement. La décision d'appliquer un recouvrement ou non à une unité est prise par le programme utilisant l'unité. Lorsqu'un recouvrement est chargée en mémoire, elle est placée dans le tampon de recouvrement, résidant en mémoire entre le segment de pile et le tas. Par défaut, la taille du tampon de recouvrement est aussi petite que possible, mais il peut être facilement augmenté au moment de l'exécution en allouant de l'espace supplémentaire à partir du tas. Comme le segment de données et la taille minimale du tas, la taille de tampon de recouvrement par défaut est allouée lorsque le .EXE est chargé. Si suffisamment de mémoire n'est pas disponible, un message d'erreur sera affiché par DOS :

Program too big to fit in memory

ou par le IDE :

Not enough memory to run program

Une option très importante du gestionnaire de recouvrement est la possibilité de charger le fichier de recouvrement dans la mémoire paginée lorsqu'un espace suffisant est disponible. Le Turbo Pascal prend en charge la version 3.2 ou ultérieure de la spécification de mémoire étendue (EMS) Lotus/Intel/Microsoft à cet effet. Une fois placé dans EMS, le fichier de recouvrement est fermé et les charges de recouvrement suivantes sont réduites à des transferts rapides en mémoire.

Le gestionnaire de recouvrement

Le gestionnaire de recouvrement de Turbo Pascal est mise en oeuvre par l'unité standard Overlay. Les techniques de gestion du tampon utilisées par l'unité Overlay sont très avancées et garantissent toujours des performances optimales dans la mémoire disponible. Par exemple, le gestionnaire de recouvrement conserve toujours autant de recouvrements que possible dans la mémoire tampon de recouvrement pour réduire le risque d'avoir à lire un recouvrement à partir du disque. Une fois qu'un recouvrement est chargée, un appel à l'une de ses routines s'exécute aussi vite qu'un appel à une routine sans recouvrement. De plus, lorsque le gestionnaire de recouvrement a besoin de supprimer un recouvrement pour faire de la place pour une autre, il tente d'abord de supprimer les recouvrements inactives (celles n'ayant pas de routines actives à ce moment-là).

Pour mettre à jour ses techniques avancées de gestion des recouvrements, le Turbo Pascal nécessite que vous respectiez deux règles importantes lors de l'écriture de programmes de recouvrements :

Notez simplement que vous pouvez facilement satisfaire ces exigences en plaçant une directive de compilateur {$O+,F+} au début de toutes les unités de recouvrements, et une directive de compilateur {$F+} au début de toutes les autres unités et du programme principal. Ne pas observer l'exigence d'appel à distance dans un programme de recouvrement provoque des résultats imprévisibles et éventuellement catastrophiques lorsque le programme est exécuté. La directive du compilateur {$O unitname} est utilisée dans un programme pour indiquer les unités en recouvrement. Cette directive doit être placée après la clause USES du programme, et la clause USES doit nommer l'unité standard Overlay avant l'une des unités de recouvrement. Voici un exemple :

Program Editeur;
{$F+} { Force les appels en FAR pour tous les procédures et fonctions }
Uses Overlay,Crt,Dos,EdtInOut, EdtForm, EdtPrint, EdtFind, EdtMain;
{SO EdtInOut}
{SO EdtForm}
{SO EdtPrint}
{SO EdtFind}
{SO EdtMain}

BEGIN
{ ... }
END.

Le compilateur signale une erreur si vous essayez un recouvrement sur une unité n'ayant pas été compilée dans l'état {$O+}. Parmi les unités standard, la seule pouvant être en recouvrement est DOS; les autres unités standard, ne peuvent pas être en recouvrement. De plus, les programmes contenant des unités en recouvrement doivent être compilés sur disque; le compilateur signale une erreur si vous essayez de compiler ces programmes en mémoire.

Gestion du tampon de recouvrement

Le tampon de recouvrement de Turbo Pascal est mieux décrit comme un tampon en anneau ayant un pointeur de tête et un pointeur de queue. Les recouvrements sont toujours chargées à la tête du tampon, poussant les plus anciennes vers la queue. Lorsque le tampon devient plein (c'est-à-dire lorsqu'il n'y a pas assez d'espace libre entre la tête et la queue), les recouvrements sont éliminées à la queue pour faire de la place pour de nouvelles. Étant donné que la mémoire ordinaire n'est pas de nature circulaire, la mise en oeuvre réelle du tampon de recouvrement implique quelques étapes supplémentaires pour que le tampon ressemble à un anneau. L'image suivante montre une progression de recouvrements en cours de chargement dans un tampon de recouvrement initialement vide. Le recouvrement A est chargée en premier, suivie de B, puis C et enfin D. Les zones en gris indiquent un espace tampon libre.

Comme vous pouvez le voir, quelques choses d'intéressants se produisent lors de la transition de l'étape 3 à l'étape 4. Tout d'abord, le pointeur de tête s'enroule vers le bas du tampon de recouvrement, ce qui oblige le gestionnaire de recouvrement à faire glisser toutes les recouvrements chargées (et le pointeur de queue) vers le haut. Ce glissement est nécessaire pour garder la zone entre le pointeur de tête et le pointeur de queue libre. Deuxièmement, pour charger le recouvrement D, le gestionnaire de recouvrement doit disposer du recouvrement A dans la queue du tampon. Le recouvrement A dans ce cas est le recouvrement la moins récemment chargée et, par conséquent, le meilleur choix pour l'élimination lorsque quelque chose doit disparaître. Le gestionnaire de recouvrement continue de disposer des recouvrements à la queue pour faire de la place pour de nouvelles à la tête, et chaque fois que le pointeur de tête s'enroule, l'opération de glissement se répète.

Bien qu'il s'agisse du mode de fonctionnement par défaut du gestionnaire de recouvrement de Turbo Pascal, vous pouvez utiliser une optimisation facultative de l'algorithme de gestion de recouvrement. Imaginez que le recouvrement A contienne un certain nombre de routines fréquemment utilisées. Même si ces routines sont utilisées tout le temps, A est toujours éjecté de la mémoire tampon de recouvrement de temps en temps, pour être rechargé à nouveau peu de temps après. Le gestionnaire de recouvrement ne sait rien de la fréquence des appels aux routines en A - seulement qu'un appel est fait à une routine en A et A n'est pas en mémoire, il doit donc charger A. Une solution à ce problème pourrait être de piéger chaque appel à des routines dans A, puis, à chaque appel, de déplacer A vers la tête du tampon de recouvrement pour refléter son nouvel état de recouvrement la plus récemment utilisée. Intercepter les appels de cette manière est très coûteux en termes de vitesse d'exécution et, dans certains cas, il peut ralentir l'application encore plus que les opérations de chargement de recouvrement supplémentaires.

Le Turbo Pascal offre une solution n'entraînant presque aucune surcharge de performances et identifiant avec succès les recouvrements fréquemment utilisées ne devant pas être déchargées: lorsqu'un recouvrement se rapproche de la queue du tampon de recouvrement, elle est mise en «probation». Si, pendant cette période probatoire, un appel est fait à une routine dans le recouvrement, il est récupéré et n'est pas éliminé lorsqu'il atteint la queue du tampon de recouvrement. Au lieu de cela, il est déplacé vers la tête du tampon et obtient un autre tour gratuit autour de l'anneau de tampon de recouvrement. D'autre part, si aucun appel n'est fait à un recouvrement pendant sa période d'essai, indiquant ainsi une utilisation peu fréquente, le recouvrement est éliminée lorsqu'elle atteint la queue du tampon de recouvrement. L'effet net du système de probation/récupération est que les recouvrements fréquemment utilisées sont conservées dans le tampon de recouvrement au prix d'intercepter un seul appel chaque fois que le recouvrement se rapproche de la queue du tampon de recouvrement. Deux routines de gestionnaire de recouvrement, OvrSetRetry et OvrGetRetry, contrôlent le mécanisme de probation / répression. La procédure OvrSetRetry définit la taille de la zone dans la mémoire tampon de recouvrement pour conserver la probation et OvrGetRetry renvoie le paramètre actuel. Si un recouvrement se trouve dans les derniers octets OvrGetRetry avant la fin du tampon de recouvrement, elle est automatiquement mise en probation. Tout espace libre dans la mémoire tampon de recouvrement est considéré comme faisant partie de la zone de probation.

Procédures et fonctions de recouvrement

L'unité Overlay définit quelques procédures et fonctions pour les recouvrements :

Nom Description
OVRCLEARBUF Cette procédure permet de vider le tampon de la mémoire destiné aux recouvrements.
OVRGETBUF Cette fonction renvoie la taille en octets du tampon de recouvrements.
OVRGETRETRY Cette fonction renvoie la taille en octets de la zone d'observation du tampon de recouvrements.
OVRINIT Cette procédure permet d'ouvrir le fichier de recouvrement devant être utilisé.
OVRINITEMS Cette procédure permet d'utiliser la mémoire EMS pour charger la partie du programme en recouvrement.
OVRSETBUF Cette procédure permet de fixer la taille du tampon de recouvrement.
OVRSETRETRY Cette procédure permet de fixer la taille de la zone d'observation du tampon de recouvrement.

Variables et constantes

L'unité Overlay définit cinq variables :

Nom Description
OvrFileMode Cette variable permet de déterminer le code d'accès à transmettre au DOS lorsque le fichier de recouvrement est ouvert.
OvrLoadCount Cette variable s'incrémente à chaque fois qu'un recouvrement est chargée.
OvrReadBuf Cette variable de procédure permet d'intercepter les opérations de chargement de recouvrement.
OvrResult Cette variable contient le code de résultat lors de l'exécution d'une procédure Overlay.
OvrTrapCount Cette variable permet d'incrémenter à chaque fois qu'une routine de recouvrement est interceptée par le gestionnaire de recouvrement.

Codes de résultat

Les erreurs dans l'unité Overlay sont signalées via la variable OvrResult.

Génération de code de recouvrement

Le Turbo Pascal autorise le recouvrement d'une unité uniquement si elle a été compilée avec {$O+}. Dans cet état, le générateur de code prend des précautions particulières lors du passage de la chaîne de caractères et de la définition des paramètres constants d'une procédure ou d'une fonction de recouvrement à une autre. Par exemple, si UniteA contient une procédure avec l'entête suivant :

Procedure EcrireChaine(S:String);

et si UniteB contient l'instruction :

EcrireChaine('Bonjour Gladir.com!...');

puis Turbo Pascal place la constante de chaîne de caractères 'Bonjour Gladir.com! ... ' dans le segment de code d'UniteB, et lui transmet un pointeur vers la procédure EcrireChaine. Si les deux unités sont des recouvrements, cela ne fonctionne pas car, lors de l'appel à EcrireChaine, le segment de code d'UniteB peut être écrasé par UniteA et le pointeur de chaîne de caractères devient invalide. La directive {$O+} est utilisée pour éviter de tels problèmes; chaque fois que Turbo Pascal détecte un appel depuis une unité compilée avec {$O+} vers une autre unité compilée avec {$O+}, le compilateur copie toutes les constantes basées sur des segments de code dans les temporaires de la pile avant de leur passer des pointeurs. L'utilisation de {$O+} dans une unité ne vous oblige pas au recouvrement de cette unité. Il demande simplement à Turbo Pascal de s'assurer que l'unité peut être en recouvrement, si vous le souhaitez. Si vous développez des unités que vous prévoyez d'utiliser dans des applications de recouvrement et sans recouvrement, les compiler avec {$O+} garantit que vous pouvez faire les deux avec une seule version de l'unité.

Appel FAR requis

À tout appel à une procédure ou une fonction de recouvrement dans un autre module, vous devez garantir que toutes les procédures ou fonctions actuellement actives utilisent le modèle d'appel à distance. Prenons l'exemple suivant : Supposons que OvrA est une procédure dans une unité de recouvrement, et que MainB et Maine sont des procédures dans le programme principal. Si le programme principal appelle Maine, appelant MainB, appelant ensuite OvrA, alors à l'appel d'OvrA, MainB et Maine sont actifs (ils ne sont pas encore revenus) et ils doivent utiliser le modèle d'appel à distance. Étant déclarés dans le programme principal, MainB et Maine utiliseraient normalement le modèle d'appel proche. Dans ce cas, une directive de compilateur {$F+} doit être utilisée pour forcer le modèle d'appel à distance à entrer en vigueur. Le moyen le plus simple de satisfaire l'exigence de l'appel à distance est de placer une directive {$F+} au début du programme principal et de chaque unité. Vous pouvez également modifier le paramètre $F par défaut en {$F+} en utilisant une directive de ligne de commande /$F+ ou la case à cocher Force Far Calls dans Options | Compiler de la boîte de dialogue. Comparé au coût du mélange des appels proches et à distances, l'utilisation des appels à distances coûte exclusivement un mot supplémentaire d'espace de pile par procédure active et un octet supplémentaire par appel.

Initialisation du gestionnaire de recouvrement

Ici, nous allons jeter un oeil à quelques exemples de la façon d'initialiser le gestionnaire de recouvrement. Placez le code d'initialisation avant le premier appel à une routine de recouvrement. En règle générale, vous le feriez au début de la partie instruction du programme. Le code suivant montre à quel point vous avez peu besoin d'initialiser le gestionnaire de recouvrement :

Program Gladir;
{ ... }
BEGIN
OvrInit('GLADIR.OVR');
{ ... }
END.

Aucun contrôle d'erreur n'est effectué. S'il n'y a pas assez de mémoire pour le tampon de recouvrement ou si le fichier de recouvrement n'a pas été trouvé, l'erreur d'exécution 208 suivante se produit lorsque vous essayez d'appeler une routine de recouvrement :

Overlay manager not installed

Voici un autre exemple simple étendant le précédent :

Program Gladir;
{ ... }
BEGIN
OvrInit('GLADIR.OVR');
OvrlnitEMS;
{ ... }
END.

Dans ce cas, à condition qu'il y ait suffisamment de mémoire pour le tampon de recouvrement et que le fichier de recouvrement puisse être localisé, le gestionnaire de recouvrement vérifie si la mémoire EMS est disponible. Si tel est le cas, il charge le fichier de recouvrement dans l'EMS.

La taille de la mémoire tampon de recouvrement initiale est aussi petite que possible, ou en d'autres termes, juste assez grande pour contenir le plus grand recouvrement. Cette situation peut convenir pour certaines applications, mais imaginez une situation dans laquelle une fonction particulière d'un programme est mise en oeuvre à travers deux unités ou plus, chacune étant en recouvrement. Si la taille totale de ces unités est supérieure au recouvrement le plus grand, une quantité substantielle de permutation se produit si les unités s'appellent fréquemment. La solution consiste à augmenter la taille de la mémoire tampon de recouvrement afin que suffisamment de mémoire soit disponible à tout moment pour contenir toutes les recouvrement s'appelant fréquemment. Le code suivant montre l'utilisation d'OvrSetBuf pour augmenter la taille du tampon de recouvrement :

Program Gladir;
Const OvrMaxSize = 80000;
{ ... }
BEGIN
OvrInit('GLADIR.OVR');
OvrlnitEMS;
OvrSetBuf(OvrMaxSize); { ... }
END.

Il n'existe pas de formule générale pour déterminer la taille idéale du tampon de recouvrement. Seule une connaissance intime de l'application et un peu d'expérimentation aboutit à une valeur appropriée. L'utilisation d'OvrInitEMS pour placer le fichier de recouvrement dans EMS n'élimine pas le besoin d'un tampon de recouvrement. Les recouvrements doivent toujours être copiées depuis l'EMS dans la mémoire conventionnelle dans le tampon de recouvrement avant de pouvoir être exécutées, mais comme ces transferts en mémoire sont nettement plus rapides que les lectures de disque, il est moins nécessaire d'augmenter la taille du tampon de recouvrement. N'oubliez pas qu'OvrSetBuf étend le tampon de recouvrement en réduisant le tas. Par conséquent, le tas doit être vide ou OvrSetBuf n'a aucun effet. Si vous utilisez l'unité Graph, assurez-vous d'appeler OvrSetBuf avant d'appeler InitGraph, allouant de la mémoire sur le tas. Voici un exemple assez élaboré d'initialisation du gestionnaire de recouvrement avec vérification complète des erreurs :

  1. Program Gladir;
  2.  
  3. Uses Overlay;
  4.  
  5. Const
  6.  OvrMaxSize = 80000;
  7. Var
  8.  OvrName:String[79];
  9.  Size:LongInt;
  10. BEGIN
  11.  OvrName := 'GLADIR.OVR';
  12.  Repeat
  13.   OvrInit(OvrName);
  14.   If OvrResult = OvrNotFound Then Begin
  15.    WriteLn('Fichier de recouvrement introuvable: ', OvrName,'.');
  16.    Write('Entrez le nom de fichier de recouvrement correcte : ');
  17.    ReadLn(OvrName);
  18.   End;
  19.  Until OvrResult <> OvrNotFound;
  20.  If OvrResult <> OvrOk Then Begin
  21.   Writeln('Erreur dans le gestionnaire Overlay.');
  22.   Halt(1);
  23.  End;
  24.  OvrInitEMS;
  25.  If OvrResult<>OvrOk Then Begin
  26.   Case OvrResult of
  27.    ovrIOError: Write('Erreur d''entree/sortie de fichier de recouvrement');
  28.    ovrNoEMSDriver: Write('Pilote EMS n''est pas installe');
  29.    ovrNoEMSMemory: Write('Il n''y a pas assez de memoire EMS');
  30.  End;
  31.  Write('. Presse Enter ... ');
  32.  ReadLn;
  33.  End;
  34.  OvrSetBuf(OvrMaxSize);
  35. END.

Premièrement, si le nom du fichier de recouvrement par défaut n'est pas correct, l'utilisateur est invité à plusieurs reprises à indiquer un nom de fichier correct. Ensuite, une vérification est effectuée pour d'autres erreurs ayant pu se produire lors de l'initialisation. Si une erreur est détectée, le programme s'arrête car les erreurs dans OvrInit sont fatales. (S'ils sont ignorés, une erreur d'exécution se produit lors du premier appel à une routine de recouvrement.) En supposant une initialisation réussie, un appel à OvrInitEMS est effectué pour charger le fichier de recouvrement dans EMS si possible. En cas d'erreur, un message de diagnostic s'affiche, mais le programme n'est pas arrêté. Au lieu de cela, il continue à lire les recouvrements du disque. Enfin, OvrSetBuf est appelé pour définir la taille du tampon de recouvrement sur une valeur appropriée, déterminée par l'analyse et l'expérimentation avec l'application particulière. Les erreurs d'OvrSetBuf sont ignorées, bien qu'OvrResult puisse renvoyer un code d'erreur de -3 (OvrNoMemory). S'il n'y a pas assez de mémoire, le gestionnaire de recouvrement continue d'utiliser le tampon minimum ayant été alloué au démarrage du programme.

Initialisation de sections

Comme les unités statiques, les unités recouvrement peuvent avoir une section d'initialisation. Bien que le code d'initialisation de recouvrement ne diffère pas du code de recouvrement normal, le gestionnaire de recouvrement doit d'abord être initialisé afin qu'il puisse charger et exécuter des unités de recouvrements. En vous référant à l'ancien programme Editeur, supposez que les unités EdtInOut et EdtMain ont un code d'initialisation. Elle nécessite que OvrInit soit appelé avant le code d'initialisation d'EdtInOut. Le seul moyen de le faire est de créer une unité sans recouvrement supplémentaire précédant EdtInOut et d'appeler OvrInit dans sa section d'initialisation :

Unit EdtInit;
Interface
Implementation
Uses Overlay;
Const
OvrMaxSize = 80000;
BEGIN
OvrInit('EDITEUR.OVR');
OvrInitEMS;
OvrSetBuf(OvrMaxSize);
END.

L'unité EdtInit doit être répertoriée dans la clause USES du programme avant l'une des unités de recouvrements :

Program Editeur;
{$F+}
Uses Overlay,Crt,Dos,EdtInit,EdtInOut, EdtForm, EdtPrint, EdtFind, EdtMain;
{SO EdtInOut}
{SO EdtForm}
{SO EdtPrint}
{SO EdtFind}
{SO EdtMain}
BEGIN
END.

En général, bien que le code d'initialisation en unités de recouvrements soit effectivement possible, vous devez l'éviter pour un certain nombre de raisons. Premièrement, le code d'initialisation, même s'il n'est exécuté qu'une seule fois, fait partie du recouvrement et occupe l'espace du tampon de recouvrement chaque fois que le recouvrement est chargée. Deuxièmement, si un certain nombre d'unités de recouvrements ont un code d'initialisation, chacune d'elles doit être lue en mémoire lorsque le programme démarre. Une bien meilleure approche consiste à rassembler tout le code d'initialisation dans une unité d'initialisation de recouvrement, étant appelée une fois au début du programme, puis jamais référencée à nouveau.

Ce qu'il ne faut pas mettre en recouvrement

Certaines unités ne peuvent pas être mit en recouvrement. En particulier, n'essayez pas de mettre en recouvrement les éléments suivants :

L'appel de routines de recouvrements via des pointeurs de procédure est entièrement pris en charge par le gestionnaire de recouvrement de Turbo Pascal. Des exemples d'utilisation de pointeurs de procédure incluent les procédures de sortie et les pilotes de périphérique de fichier texte. Le gestionnaire de recouvrement prend également en charge la transmission de procédures et de fonctions de recouvrements en tant que paramètres de procédure et l'affectation de procédures et de fonctions de recouvrements à des variables de type procédural.

Débogage des recouvrements

La plupart des débogueurs ont des capacités de débogage de recouvrements très limitées, voire aucune. Ce n'est pas le cas avec Turbo Pascal et Turbo Debugger. Le débogueur intégré prend entièrement en charge les étapes simples et les points d'arrêt dans les recouvrements d'une manière totalement transparente pour vous. En utilisant des recouvrements, vous pouvez facilement concevoir et déboguer d'énormes applications, le tout à partir de l'EDI ou en utilisant Turbo Debugger.

Routines externes dans les recouvrements

Comme les procédures et fonctions Pascal normales, les routines du langage assembleur externe doivent respecter certaines règles de programmation pour fonctionner correctement avec le gestionnaire de recouvrement. Si une routine de langage assembleur appelle des procédures ou des fonctions de recouvrements, la routine de langage assembleur doit utiliser le modèle FAR et elle doit configurer un cadre de pile à l'aide du registre BP. Par exemple, en supposant que OtherProc est une procédure de recouvrement dans une autre unité et que la routine de langage d'assemblage ExternProc l'appelle, alors ExternProc doit utiliser le modèle FAR et configurer un cadre de pile. Par exemple :

  1. ExternProc PROC FAR
  2.    PUSH BP          ; Sauvegarde BP
  3.    MOV BP,SP        ; Fixe le cadre de la pile
  4.    SUB SP,LocalSize ; Allocation des variables local
  5.    CALL OtherProc   ; Appeler un autre unité de recouvrement
  6.    MOV SP,BP        ; Dispose des variables local
  7.    POP BP           ; Restauration BP
  8.    RET ParamSize    ; Retourne
  9. ExternProc ENDP 

Le paramètre LocalSize est la taille des variables locales et ParamSize est la taille des paramètres. Si LocalSize vaut zéro, vous pouvez omettre les deux lignes pour allouer et supprimer les variables locales. Ces exigences sont les mêmes si ExternProc fait des références indirectes à des procédures ou des fonctions de recouvrements. Par exemple, si OtherProc fait des appels à des procédures ou des fonctions de recouvrements, mais n'est pas lui-même en recouvrement, ExternProc doit toujours utiliser le modèle FAR et doit toujours configurer un cadre de pile. Lorsqu'une routine en langage assembleur ne fait aucune référence directe ou indirecte aux procédures ou fonctions de recouvrements, il n'y a pas d'exigences particulières; la routine de langage d'assemblage est libre d'utiliser le modèle proche et il n'est pas nécessaire de configurer un cadre de pile. Les routines de langage d'assemblage de recouvrements ne doivent pas créer de variables dans le segment de code, car toutes les modifications apportées à un segment de code de recouvrement sont perdues lorsque le recouvrement est supprimée. De même, on ne peut pas s'attendre à ce que les pointeurs vers des objets basés dans un segment de code de recouvrement restent valides dans les appels à d'autres recouvrements, car le gestionnaire de recouvrement se déplace librement et supprime les segments de code de recouvrements.

Installation d'une fonction de lecture de recouvrement

La variable de procédure OvrReadBuf vous permet d'intercepter les opérations de chargement de recouvrement. Par exemple, vous pouvez mettre en oeuvre la gestion des erreurs ou vérifier qu'un disque amovible est présent. Chaque fois que le gestionnaire de recouvrement a besoin de lire un recouvrement, il appelle la fonction dont l'adresse est entreposée dans OvrReadBuf. Si la fonction renvoie zéro, le gestionnaire de recouvrement suppose que l'opération a réussi; si le résultat de la fonction est différent de zéro, le compilateur génère l'erreur d'exécution 209. Le paramètre OvrSeg indique que le recouvrement à charger. Pour installer votre propre fonction de lecture de recouvrement, vous devez d'abord enregistrer la valeur précédente d'OvrReadBuf dans une variable de type OvrReadFunc, puis affecter votre fonction de lecture de recouvrement à OvrReadBuf Dans votre fonction de lecture, vous devez appeler la fonction de lecture enregistrée pour effectuer la opération de chargement. Toutes les validations que vous souhaitez effectuer, telles que la vérification de la présence d'un disque amovible, doivent être effectuées avant l'appel à la fonction de lecture enregistrée, et toute vérification d'erreur doit avoir lieu après l'appel. Le code pour installer une fonction de lecture de recouvrement doit aller juste après l'appel à OvrInit; à ce stade, OvrReadBuf contient l'adresse de la fonction de lecture de disque par défaut. Si vous appelez également OvrInitEMS, il utilise votre fonction de lecture pour lire les recouvrements du disque dans la mémoire EMS, et si aucune erreur ne se produit, il entrepose l'adresse de la fonction de lecture EMS par défaut dans OvrReadBuf si vous souhaitez également remplacer la fonction de lecture EMS, répétez simplement le processus d'installation après l'appel à OvrInitEMS. La fonction de lecture de disque par défaut renvoie zéro si elle réussit, ou un code d'erreur DOS si elle échoue. De même, la fonction de lecture EMS par défaut renvoie 0 si elle réussit, ou un code d'erreur EMS (allant de $80 à $FF) si elle échoue. Le fragment de code suivant montre comment écrire et installer une fonction de lecture de recouvrement. La nouvelle fonction de lecture de recouvrement appelle à plusieurs reprises la fonction de lecture de recouvrement enregistrée jusqu'à ce qu'aucune erreur ne se produise. Toutes les erreurs sont transmises aux procédures _DOSError ou _EMSError afin qu'elles puissent présenter l'erreur à l'utilisateur. Remarquez comment le paramètre OvrSeg est simplement passé à la fonction de lecture de recouvrement enregistrée et n'est jamais directement géré par la nouvelle fonction de lecture de recouvrement.

  1. Program Gladir;
  2. Uses DOS,Overlay;
  3. Var
  4.  SaveOvrRead:OvrReadFunc;
  5.  UsingEMS:Boolean;
  6.  
  7. Procedure _EMSError(E:Integer);Begin
  8.  WriteLn('Une erreur EMS');
  9. End;
  10.  
  11. Procedure _DOSError(E:Integer);Begin
  12.  WriteLn('Une erreur DOS');
  13. End;
  14.  
  15. Function MyOvrRead(OvrSeg:Word):Integer;Far;
  16. Var
  17.  E:Integer;
  18. Begin
  19.  Repeat
  20.   E:=SaveOvrRead(OvrSeg);
  21.   If E <> 0 Then If UsingEMS Then _EMSError(E) Else _DOSError(E);
  22.  Until E = 0;
  23.  MyOvrRead := 0;
  24. End;
  25.  
  26. BEGIN
  27.  OvrInit('GLADIR.OVR');
  28.  SaveOvrRead := OvrReadBuf;
  29.  OvrReadBuf := MyOvrRead;
  30.  UsingEMS := False;
  31.  OvrInitEMS;
  32.  If OvrResult = OvrOK Then Begin
  33.    SaveOvrRead := OvrReadBuf;
  34.    OvrReadBuf := MyOvrRead;
  35.    UsingEMS := True;
  36.  End;
  37. END. 

Recouvrements en fichiers .EXE

Le Turbo Pascal permet d'entreposer vos recouvrements à la fin du fichier .EXE de votre application plutôt que dans un fichier .OVR séparé. Pour attacher un fichier .OVR à la fin d'un fichier .EXE, utilisez la commande COPY de DOS avec un paramètre de ligne de commande  :

COPY /B GLADIR.EXE + GLADIR.OVR

Vous devez vous assurer que le fichier .EXE a été compilé sans informations de débogage Turbo Debugger. Dans l'EDI, assurez-vous que l'option Standalone n'est pas cochée dans Options | Debugger. Avec la version de ligne de commande du compilateur, ne spécifiez pas de paramètre /V. Pour lire les recouvrements à partir de la fin d'un fichier .EXE au lieu d'un fichier .OVR séparé, spécifiez simplement le nom de fichier .EXE dans l'appel à OvrInit. Si vous exécutez sous DOS 3.x ou supérieur, vous pouvez utiliser la fonction standard ParamStr pour obtenir le nom du fichier .EXE; par exemple :

OvrInit(PararnStr(0));

Dernière mise à jour : Dimanche, le 15 novembre 2020