Accueil
Rechercher:
sur developpez.com sur les forums
Forums | Tutoriels | F.A.Q's | Participez | Hébergement | Contacts
Club Emploi Blogs   TV   Dév. Web PHP XML Python Autres 2D-3D-Jeux Sécurité Windows Linux PC Mac
Accueil Conception Java DotNET Visual Basic  C  C++ Delphi MS-Office SQL & SGBD Oracle  4D  Business Intelligence
ACCUEIL PASCAL FORUM PASCAL F.A.Q PASCAL TUTORIELS PASCAL SOURCES COMPILATEURS OUTILS LIVRES

La mémoire XMS
eXtended Memory System

par Haypo - 24 juin 2001

Sommaire :

Introduction :

La mémoire XMS est gérée par le pilote HIMEM.SYS chargé automatiquement par Windows (et très souvent par DOS). Ce pilote permet d'accéder à toute la mémoire RAM disponible sur l'ordinateur (contrairement à Turbo Pascal, programme 16 bits, qui est limité aux 640 Ko).

 

Côté technique :

Toutes les fonctions XMS passent par l'interruption 2Fh (interruption qui regroupe plusieurs extensions comme le pilote de CD-Rom MSCDEX par exemple) et la fonction 43h, oui, faut faire de l'assembleur. Si une erreur se produit (AX=0), BL contient le code d'erreur. Sinon AX est différent de 0. Je ne vais pas détailler toutes les fonctions car premièrement je ne les connais pas, et deuxièmement j'ai une unité qui fait ça très bien. J'ai menti (j'avoue), l'unité n'est pas entièrement de moi, je me suis beaucoup basé sur une autre unité (dont la source n'était pas indiquée), ce qui veut dire que je ne suis pas un expert en mémoire XMS. L'unité s'appelle "XMS.PAS" (elle est dans le pack de toutes mes unités, disponnible sur ce site).

 

Vérifier la présence du pilote XMS :

Le pilote pour la mémoire XMS n'est pas toujours disponnible (il arrive que HIMEM.SYS ne soit pas chargé). Il est donc OBLIGATOIRE (sous peine de plantage ou d'erreurs inexpliquées) d'appeler : " VerifiePresenceXms" au démarrage de votre programme. Celui-ci afficher un message d'erreur standart si le pilote n'est pas présent. Dans la version 0.4 de l'unité, ça donne :


Le driver XMS n'est pas installé !

[ Sous DOS ]
-> Vérifiez que vous avez bien la ligne 'DEVICE=C:\WINDOWS\HIMEM.SYS' dans le fichier Config.sys

[ Sous Windows 95/98 ]
-> 'Cliquez avec le bouton droit sur le programme, choisissez 'Propriétés'. Dans l'onglet 'Mémoire'', sous ''Mémoire XMS'', choisissez 'Auto'.


Allouer de la mémoire :

Pour allouer de la mémoire, utilisez la fonction " AlloueMemXms" (j'ai essayé de donner des noms parlant !). La taille du "bloc" demandé est donné en Kilo-octets. Malgré l'appellation "Kilo", 1 Kilo octet = 1024 octets. Pour convertir les octets en kilo-octets, il faut diviser par 1024 et arrondir par défaut (car écrire hors du bloc XMS provoque une erreur!), pour celà tapez : " Taille := Taille div 1024 +1;" ou plus rapidement " Taille := Taille shr 10 +1;". "shr d" est un décalage binaire de d bits vers la droite, R = Right = Droite en anglais. Donc shr n = div (2^n) et 2^10 = 1024 ! Il faut taper {$G+} au début de votre programme pour pouvoir utiliser cette instruction (= utilise les instructions du 80286, dire qu'on en est au 686 !). Chaque "bloc" de mémoire alloué est désigné par un "handle", c'est un nombre de type Word (valeur entre 0 et 65535), mais sa valeur ne peut pas être 0 (on verra plus tard). Fonction AlloueMemXms : " Function AlloueMemXms (Taille: word) : word;".

 

Rendre la mémoire :

C'est tout simple : "RendMemXms". Il faut juste donner comme paramètre le handle renvoyé par AlloueMemXms. "Procedure RendMemXms (Handle: word);". Exemple :


uses Xms;
var MaMem: Word; Taille: LongInt;
begin
  { Vérifie la présence du driver XMS }
  VerifiePresenceXms;

  Taille := 81530; { 81 530 octets }
  MaMem := AlloueMemXms (Taille shr 10 +1);
  Writeln ("Ma mémoire est allouée");
  RendMemXms (MaMem);
end.

 


 

Créer un tampon de transfert :

Voilà, on a de la mémoire disponnible, voyons comment y accéder maintenant. La solution la plus pratique est de "vérouiller" un bloc mémoire pour qu'il soit accessible via un pointeur : " Function VerrouilleBlocXms (Handle : word) : pointer;". Le problème est que ça ne fonctionne pas toujours ... Je n'ai donc jamais utilisé cette méthode. Peut-être que je m'y prends mal, à vous de tester. Personellement je crée un tampon de 64 Ko (taille maximale avec Turbo Pascal, car c'est un programme 16 bits : 2^16 = 65536 octets !) avec GetMem :


{ Rêglage de la mémoire requise : 4 Ko de pile (ça suffit, voir 8 Ko), }
{ et 65 Ko de mémoire allouable dynamiquement, c'est à dire avec GetMem. }
{ Remarque : XMS n'entre pas du tout en compte }
{$M 4096,0,65536}

uses StopProg;
type
 TamponMax = Array[0..$FFFE] of Byte; { Accessible octet/octet }
 PtrTampon = ^TamponMax;
var
 Tampon: PtrTampon;
 txt: String;
begin
 { Assez de mémoire libre ? }
 if MemAvail<$FFFF then begin
  Str ($FFFF-MemAvail,txt);
  StopProgramInfo ('allocation du tampon de transfert','Mémoire libre insuffisante','manque '+txt+'octets');
 end;

 GetMem (Tampon,$FFFF); { $FFFF = 65535 octets }
 Tampon^[0] := 0; { On accède au tampon avec ^[i] où i est l'index de l'octet à modifier }
 fillchar (Tampon^,65535,23); { Rempli le tampon avec la valeur Byte 23 }
 FreeMem (Tampon,$FFFF);
end.


 

Copier de la mémoire :

Maintenant que nous avons de la mémoire XMS et un tampon de transfert, voyons comment passer de l'un à l'autre. Le coeur de l'accès à la mémoire XMS est "CopieXms", c'est une variable de l'unité XMS du type "StructCopieXms". Voyons ce type :

La structure
Commentaire
StructCopieXms = record
Taille : LongInt;

Taille des données à copier. Ce qui est embêtant, c'est qu'il faut que c'est la taille soit paire. On peut arrondir par excès avec "Taille := Taille or 1; ", mais il faut faire attention à ne pas sortir de notre bloc de mémoire XMS, ni du tampon de transfert.
Remarque: Windows permet des tailles impaires, mais pas DOS, alors utilisez toujours des tailles paires.

SrcHdl : word; Handle de la source. Si un Handle est égal à zéro, alors SrcOfs est une adresse dans la mémoire 16 bits (les 640 Ko).
SrcOfs : LongInt;
  • Si SrcHdl<>0 : Offset dans le bloc XMS dont le handle est SrcHdl (Attention à ce que SrcOfs+Taille soit inférieur ou égal à la taille du bloc désigné, sous peine d'erreur)
  • Si SrcHdl=0,
    • Vous pouvez taper directement une adresse. Pour la mémoire vidéo en mode texte couleur (mode 03h), l'adresse est B800:0000h, tapez "$B8000000".
    • Dans le cas de notre tampon de transfert : utilisez la fonction "Ptr2Long" qui convertit un pointeur en LongInt. Exemple :
      CopieXms.SrcOfs := Ptr2Long (Tampon);
    • Sinon pour n'importe quelle variable, utilisez "Ptr2Long". Le pointeur sera l'adresse de vos données. Exemple :
      {var txt: String;}
      CopieXms.SrcOfs := Ptr2Long (Ptr(Seg(txt),Ofs(txt)));
      ou (beaucoup) plus simplement :
      CopieXms.SrcOfs := Ptr2Long (@txt);
      car "@var" renvoie l'adresse de la variable var.
DstHdl : word; Même remarque que pour SrcHdl, sauf qu'ici c'est la destination.
DstOfs : LongInt; Même remarque que pour SrcOfs, sauf qu'ici c'est la destination.
End;

Après avoir initiliser la structure CopieXms, il faut appeler la procédure "CopieMemXms" avec comme paramètre CopieXms (ou un autre StructCopieXms de votre choix). "Procedure CopieMemXms (var StructCopie: StructCopieXms);".

Retour au sommaire

 

Gestion des erreurs :

Il faut vérifier après chaque appel de fonction ou procédure qu'aucune erreur ne se soit produit. Pour celà, pas de procédure standart, je vous ai laisssé programmer la votre. Cela vous permettra de choisir d'afficher les erreurs en mode texte, ou en mode graphique, et d'afficher ce que vous voulez. Je vous offre quand même ma procédure standart que j'intègre dans tous mes programmes :


(fonctionne en mode texte couleur uniquement)
(nécessite les unités EcranTxt, Clavier et Convert)

procedure TestErreurXms (Quand: String); begin
 { Aucune erreur, rien à signaler }
 if ErreurXms=0 then exit;

 {=== En cas d'erreur : efface l'écran, affiche l'erreur, puis stoppe le programme ===}
 EffaceEcranTxt;
 EcriTcr ('Erreur lors de '+Quand+' (n°'+Hex8z(ErreurXms)+') :',12);
 Ecrit ('=> '); EcriTcr (TxtErreurXms+' !',15);
 SauteLigne;
 EcriTcr ('[ Info pour le débogage ]',15+3*16);
 with CopieXms do begin
  Ecrit ('Taille = '); EcriTncr (Taille,10);
  Ecrit ('SrcHdl = '); EcriTncr (SrcHdl,10);
  Ecrit ('SrcOfs = '); EcriTnc (SrcOfs,10);
  Ecrit (' ('); EcriTc (Hex16z(SrcOfs shr 16)+':'+Hex16z(SrcOfs and $FFFF),10); EcriTr (')');
  Ecrit ('DstOfs = '); EcriTnc (DstOfs,10);
  Ecrit (' ('); EcriTc (Hex16z(DstOfs shr 16)+':'+Hex16z(DstOfs and $FFFF),10); EcriTr (')');
  Ecrit ('Mémoire XMS libre = '); EcriTnc (MemXmsLibre,10); EcriTr (' Ko');
 end;
 SauteLigne;

 { Attend la pression d'une touche }
 Ecrit ('Pressez une touche pour finir :'); LitTouche; EffaceLigneTxt;

 { Libère la mémoire XMS allouée }
 RendMemXms (TamponTexte);

 { Stoppe le programme }
 Halt (8);
end;


Cette procédure doit être appelée après chaque appel à une fonction de l'unite XMS avec comme paramètre un texte expliquant l'opération que l'on voulait exécuter (qui sera précédé de "Erreur lors de "). Exemple : pour allouer de la mémoire, on tapera : " TestErreurXms ('l''allocation d''un tampon mémoire');".

Autre point : rendre la mémoire allouée en cas d'erreur. La solution la plus simple est de créer une procédure (nommée "LibereMemAllouee" par exemple) qui sera exécutée en cas d'erreur avant d'arrêter l'exécution du programme (appel de "Halt"). Si vous utilisez mon unité StopProg, vous pouvez mettre cette procédure en appel far (par la commande "far;" écrite juste avant begin ou var), puis la rentrer dans la variable "ProcAppeleeStop" (procédure appelée lorsque le programme stoppe son exécution :-). Exemple :


(uses StopProg;)

procedure LibereMemAllouee; { Aucun paramètre }
far; { Adressage long}
var ...
begin
  { Libère la mémoire allouée dynamiquement }
  Dispose (Tampon);

  { Libère la mémoire XMS }
  RendMemXms (MonHandle);
end;

begin
  ...
  { En cas d'erreur : libère la mémoire allouée }
  ProcAppeleeStop := LibereMemAllouee;
  ...
  { Libère la mémoire allouée en fin de programme }
  LibereMemAllouee;
end.


Retour au sommaire - Retour aux tutoriels

Par Haypo

Responsable bénévole de la rubrique Pascal : wormful_sickfoot - Contacter par EMail :
Vos questions techniques : forum d'entraide Pascal - Publiez vos articles, tutoriels et cours
et rejoignez-nous dans l'équipe de rédaction du club d'entraide des développeurs francophones
Nous contacter - Copyright © 2000-2008 www.developpez.com - Legal informations.