Programmation d'un VxD : élémentaire
(VxD Programming: Primer)

Nous savons comment construire un VxD qui ne fait rien. Dans ce tutorial, nous allons le rendre plus productif en lui ajoutant des 'control message handlers' ou des traiteurs de message de contrôle.

Initialisation et Terminaison du VxD

Il y a deux types de VxDs : statiques et dynamiques. Chaque type présente une méthode de chargement différente. Ils reçoivent également une initialisation et des messages de terminaison différents.

VxD statics:

Le VMM (le Manager de Machines Virtuelles) charge un VxD static lorsque: Pendant la phase de d'apprentissage, je suggère que vous chargiez le VxD grâce à system.ini parce que si quelque chose tourne mal avec votre VxD avant même que Windows n'ait été lancé, vous pourrez toujours éditer system.ini sous DOS. Vous ne pouvez pas faire ça si vous optez pour la méthode de la base des registres.
Quand le VMM charge votre VxD statique, votre VxD reçoit trois messages de contrôle de système dans l'ordre suivant : Votre VxD doit purifier le Flag CARRY si l'initialisation s'est déroulée avec succès sinon vous devez mettre le Flag CARRY à 1 en cas d'erreur avant retourner. Si votre VxD n'a pas besoin d'initialisation, vous n'avez besoin de traiter aucun des trois messages d'initialisation.
Quand il est temps pour terminer le VxD statique, le VMM envoie les messages de contrôle suivants : La plupart des VxDs n'ont pas besoin de traiter ces messages, sauf quand vous voulez préparer le système pour passer au mode réel. Vous devez savoir que lorsque Windows 95 se referme, il revient en mode réel. Ainsi si votre VxD a fait quelque chose au mode réel, ça le rendra instable, il doit rétablir le changement pendant ce temps.
Vous pouvez vous demander pourquoi ces deux messages de fin ont tous les deux un "2" de rajouté. Rappelez-vous que lorsque le VMM charge les VxDs statiques, pendant l'initialisation il charge les VxDs d'ordre inférieur les premiers, ainsi les VxDs suivants peuvent compter sur les services des VxDs qui ont déjà été chargés avant eux. Par exemple, si VxD2 compte sur les services de VxD1, on doit spécifier que son ordre d'initialisation doit être plus grand que celui de VxD1. L'ordre de chargement serait :
..... VxD1 ===>  VxD2 ===> VxD3 .....
Maintenant pendant le déchargement, il est raisonnable que ce soient les VxDs qui ont été initialisés les plus tard qui doivent être détruit les premiers. Ainsi les VxDs les derniers initialisés ont toujours la possibilité d'appeler les services des premiers VxDs, ce qui n'aurait pas été vrai si ont avait fait l'inverse. Donc dans l'exemple ci-dessus, l'ordre de déchargement doit être :
.... VxD3 ===> VxD2 ===> VxD1.....
Dans le susdit exemple, si VxD2 a appelé certains des services de VxD1 pendant l'initialisation, il peut de nouveau avoir besoin de compter sur les services de VxD1 pendant le déchargement. System_Exit2 et Sys_Critical_Exit2 sont envoyé dans l'ordre inverse d'initialisation . Ça signifie que, lorsque VxD2 reçoit ces messages, VxD1 n'a pas encore été désinitialiser et on peut toujours appeler les services de VxD1. Les messages System_Exit et Sys_Critical_Exit ne sont pas envoyés dans l'ordre inverse de l'initialisation. Ça signifie que lorsque vous traitez ces deux messages, vous ne pouvez pas être sûrs que vous pouvez encore appeler les services des VxDs qui ont été chargés avant ça. Ces messages ne doivent pas être employés pour les VxDs les plus nouveau.
Il y a encore deux messages de sortie : Maintenant, vous être capables de comprendre qu'il y existe les messages Device_Reboot_Notify et Crit_Reboot_Notify mais qu'ils ne sont pas envoyés dans l'ordre inverse de l'initialisation comme dans la version "2".

Les VxDs Dynamics:

Les VxDs Dynamiques peuvent être chargés et déchargés dynamiquement pendant les sessions de Windows 9x. Cette particularité n'est pas disponible sous Windows 3.x. Le but principal des VxDs dynamiques c'est de permettre une reconfiguration dynamique du matériel comme les devices Plug and Play. Cependant, vous pouvez également les charger/décharger de vos applications win32, faisant d'eux (ces VxDs Dyn) des extensions idéales pour vous applications Ring-0.
L'exemple du Tutorial précédent est un VXD statique. Vous pouvez convertir cet exemple en un VXD dynamique en ajoutant le mot-clé DYNAMIC à la déclaration VXD dans le fichier .DEF.
VXD   FIRSTVXD   DYNAMIC
C'est tout que ce vous devez faire pour convertir un VxD statique en un VxD dynamique.
Un VxD Dynamique peut être chargé soit : Le flag FILE_FLAG_DELETE_ON_CLOSE indique que le VxD est déchargé dès que son handle est renvoyé par CreateFile.
Si vous employez CreateFile pour charger un VxD dynamique, ce VxD must traiter le message w32_DeviceIoControl. VWIN32 envoie ce message de contrôle à votre VxD dynamique lorsqu'il est chargé par la méthode CreateFile. Votre VxD doit retourner la valeur 0 dans eax en réponse à ce message. Plusieurs messages w32_DeviceIoControl sont également envoyés quand l'application appelle l'API DeviceIoControl pour communiquer avec le VxD. Nous examinerons DeviceIoControl dans les futurs tutorials.
Un VxD dynamique reçoit un message pendant son initialisation : Et un message de contrôle pour sa terminaison : Un VxD dynamique ne recevra pas les messages de contrôle Sys_Critical_Init, Device_Init ni Init_Complete parce que ces messages sont envoyés pendant que le système VM procède à son initialisation. Il y en a autres, tous les VxDs dynamiques reçoivent d'autres messages de contrôle une fois qu'ils sont en mémoire. Ils peuvent faire tout ce que font les VxDs statiques. Bref, les VxDs dynamiques sont chargés par des mécanismes différents et reçoivent également des messages de contrôle d'initialisation/terminaison différents, mais ils peuvent faire tout ce que font les VxDs statiques.

D'autres Systèmes de messages de Contrôle :

Pendant le temps où un VxD reste en mémoire, il recevra beaucoup de messages de contrôle, autres que ceux liés à l'initialisation et la terminaison. Quelques-uns d'entre eux sont conçus pour la gestion des machines virtuelles et quelques-uns pour divers événements. Voici par exemple quelques messages de contrôle VM-liés : C'est à vous de répondre ou non aux messages de contrôle pour lesquels vous êtes intéressé.

Création des procédures à l'intérieur d'un VxD

Dans un VxD vous devez déclarez une procédure à l'intérieur d'un segment. Vous devez d'abord définir un segment et ensuite mettre votre procédure à l'intérieur. Par exemple, si vous voulez que votre fonction soit dans un segment pageable (un segment où on peut modifier du code ou des données), vous devez d'abord définir un pageable segment, comme cela :
VxD_PAGEABLE_CODE_SEG

[VOTRE PROÉCDURE ICI]

VxD_PAGEABLE_CODE_ENDS

Vous pouvez placer plusieurs procédures à l'intérieur d'un segment. Vous comme êtes l'auteur du VxD, c'est à vous de décider dans quel segment vous devez mettre vos procédures. Si vos procédures doivent être présent en mémoire tout le temps comme les manipulateurs d'interruption matériel (hardware interrupt handlers), il faut les mettre dans un segment fermé (Page-locked contraire de Pageable). Autrement vous devez les mettre dans le segment pageable.
Vous définissez votre procédure avec les macros BeginProc et EndProc.
BeginProc name

EndProc name

name est le nom de la procédure. La macro BeginProc peut prendre encore plusieurs paramètres, vous devez consulter la documentation Win95 DDK pour plus de détails. Mais la plupart du temps, vous pouvez vous contenter du nom de la procédure.
Vous devez employer les macros BeginProc-EndProc au lieu des habituelles directives proc-endp parce que les macros BeginProc-EndProc fournissent plus de fonctionnalités que proc-endp.

Convention de codage pour les VxDs

Utilisation des Registres

Votre VxD peut utiliser n'importe quels registres généraux, FS et GS. Mais vous devez prendre garde à la modification des registres de segment. Particulièrement, vous ne devez sûrement pas changer CS où SS à moins que vous ne soyez tout à fait certain que vous savez ce que vous faites. Vous pouvez employer DS et ES tant que vous n'oubliez pas de rétablir leurs valeurs avant de retourner. Deux Flags sont particulièrement importants : les Flags de direction et d'interruption. Vous ne devez pas désactiver les interruptions pendant une longue période de temps, quant au flag de direction si vous le modifiez n'oubliez pas de rétablir son état précédent avant le retour.

Convention sur les paramètres de passage

Il y a deux types de conventions d'appel pour les services des VxD : les registres de base ou la pile. Avec les services utilisants les registres de base, vous passez des paramètres aux services grâce à divers registres et vous pouvez vérifier le flag CARRY après l'appel du service pour voir si l'opération s'est correctement déroulée. Vous ne pouvez pas admettre que les valeurs des registres généraux seront préservés après l'appel des services. Avec des services utilisant la pile, vous poussez les paramètres sur la pile et vous obtenez la valeur de retour dans eax. Des services utilisant la pile préservent ebx, esi, edi et ebp. La plupart des services qui utilisent les registres sont des produits des vieux jours de Windows 3.x. La plupart du temps, vous pouvez différencier ces deux sortes de services en regardant les noms. Si le nom du service commence par un souligné comme _HeapAllocate, alors c'est qui utilise la pile (C) (à part quelques services exportés par VWIN32.VxD). Si le nom du service ne commence pas par un souligné, c'est un service qui utilise les registres de base.

Appeler les services d'un VxD

Vous appelez les services du VMM (du Manager de Machine Virtuelle) et des VxDs (des Virtual Device Driver) en employant les macros VMMCall et VxDCall. Ces deux macros ont exactement la même syntaxe. Vous employez VMMCall quand vous voulez appeler les services d'un VxD exportés par le VMM et vous employez VxDCall quand vous appelez les services exportés par autres VxDs que le VMM.
VMMCall service                ; Pour appeler des services basés sur les regitres
VMMCall  _service, <argument list>    ; Pour appeler les services basés sur la pile
VMMCall et VxDCall sont en réalité la composition d'une int 20h suivie d'un dword que j'ai décrit dans le tutorial précédent mais ils sont beaucoup plus commodes à employer. Dans le cas de services basés sur pile, vous devez inclure la liste d'argument avec une paire de parenthèse angulaire [].
VMMCall  _HeapAllocate, <<size mybuffer>, HeapLockedIfDP>
_HeapAllocate est un service basé sur la pile. Il accepte deux paramètres. Nous devons les inclure à l'intérieur d'une parenthèse angulaire. Cependant, le premier paramètre est une expression que la macro peut mal interpréter, donc nous le mettons à l'intérieur d'une autre parenthèse angulaire.

Adresses Flats (Plates)

Dans des outils plus vieux, l'assembleur et le linker produisent des adresses incorrectes quand vous employez l'operateur offset. Ainsi les programmeurs de VxD utilisent offset flat: au lieu d' offset. vmm.inc contient une macro pour rendre ça plus simple. OFFSET32 développer offset flat:. Ainsi si vous voulez employer cet opérateur de compensation, vous devez employer OFFSET32 au lieu de offset flat: .

Note: j'ai expérimenté la compensation Offset32 quand j'ai écris ce Tutorial. Ça a produit des adresses correctes donc je pense que le bogue a été enlevé dans MASM 6.14. Mais pour que ça reste correcte, vous devez employer la macro OFFSET32 au lieu de l'habituel offset.


[Iczelion's Win32 Assembly Homepage]


Traduit par Morgatte