Accueil
Qui suis-je ?
 
Mes livres
Les pompes rotodynamiques
Commander un livre
 
Mes programmes
Nopopup
Aide française
Télécharger
English help
Download
 
Optipump
English help
Download
 
SaveRes
Aide française
Télécharger
English help
Download
 
TTFName
Aide française
Télécharger
 
Mes articles
Composant ASP en C/C++
VxD W9x en ASM
 
Mes photos
Afrique australe
Autres photos
 
 visiteurs.
 pages vues.
 connecté(s).
Accueil-->VxD W9x en ASM - Chapitre 4

Programmation d’un VxD

1 Initialisation et terminaison d’un VxD

1.1 Les VxD statiques

1.1.1 Généralités

La VMM charge un VxD statique quand :

  • Un programme résidant en mode réel utilise int 2Fh, 1605h pour le charger.

  • Le VxD est spécifié dans le registre sous la clef HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\key\StaticVxD=pathname

  • Le VxD est spécifié dans system.ini dans la section [386enh]: device=pathname
  • Pendant la phase de mise au point , je suggère que vous chargiez le VxD via system.ini parce que si quelque chose mal tourne avec votre VxD, Windows ne pouvant démarrer, vous pouvez éditer system.ini à partir du DOS. Vous ne pouvez pas le faire avec le registre.

    Quand le VMM charge votre VxD statique, votre VxD recevra trois messages de contrôle de système dans l'ordre suivant :

    1.1.2 Sys_Critical_Init

    VMM envoie ce message de contrôle après la commutation dans le mode protégé, mais avant d'activer les interruptions. La plupart des VxD ne doivent pas manipuler ce message sauf quand :

  • Votre VxD intercepte certaines interruptions qui seront appelées plus tard par d'autres VxD ou des programmes en mode protégés. Comme les interruptions sont désactivées quand vous traitez ce message de contrôle, vous pouvez être sûrs que votre hook d'interruption ne sera pas effectif.
  • Votre VxD fournit des services VxD qui seront appelés pendant l'initialisation par d'autre VxD. Par exemple, un VxD qui est chargé après votre VxD peut devoir appeler un des services de votre VxD pendant le traitement du message de contrôle de Device_Init. Comme le message Sys_Critical_Init est envoyé avant Device_Init , vous devez initialiser vos services pendant le message Sys_Critical_Init. Si vous traitez ce message, vous devez faire votre initialisation aussi rapidement que possible sous peine de perte d'interruption hardware. (Souvenez-vous : les interruptions sont mises hors de service).
  • 1.1.3 Message de contrôle Device_Init

    VMM envoie ce message de contrôle après l'activation des interruptions. La plupart des VxD exécutent l'initialisation en réponse à ce message. Parce que les interruptions sont désactivées, des opérations consommatrices de temps peuvent être faites sans la crainte de perdre une interruption hardware. Vous devez faire votre initialisation ici.

    1.1.4 Message de contrôle Init_Complete

    Après que le VxD ai traité le message Device_Init, mais avant que le VMM ne libère tous les segments d'initialisation (Ies classes de segment RCODE et ICODE), le VMM envoie ce message de contrôle. Peu de VxD doivent traiter ce message. Si l'initialisation est réussie, votre VxD doit désarmer le carry flag si vous devez positionner ce flag sur erreur avant retour. Vous ne devez traiter aucun de ces trois messages d'initialisation si votre VxD n'a pas besoin d'initialisation. Quand il est temps de terminer le VxD statique, le VMM envoie les messages de contrôle suivants

    1.1.5 Message de contrôle System_Exit2

    Quand votre VxD reçoit ce message, Windows 9x est sur le point de se fermer. Toutes les VM sauf la VM système sont déjà détruites. Cependant l'UC est toujours dans le mode protégé et il est plus sûr d'exécuter le code de mode réel dans le système VM. Kernel32.dll été déjà déchargé à ce moment.

    1.1.6 Message de contrôle Sys_Critical_Exit2

    Votre VxD reçoit ce message quand tout les VxD ont traité System_Exit2 et les interruptions sont mises hors service. La plupart des VxD ne doivent pas traiter ces deux messages, sauf quand vous voulez préparer le système à en mode réel. Vous devez savoir que quand Windows 9x se ferme, il retourne en mode réel. Ainsi si votre VxD fait quelque chose en mode réel qui le rend instable, il doit rétablir les changements à ce moment.

    1.1.7 Message de contrôle Device_Reboot_Notify2

    Notifie le VxD que la VMM va redémarrer le système. Les interruptions sont toujours désactivées à ce moment.

    1.1.8 Message de contrôle Crit_Reboot_Notify2

    Notifie le VxD que la VMM va redémarrer de manière critique le système. Les interruptions sont toujours désactivées à ce moment.

    1.1.9 Message de contrôle Device_Reboot_Notify

    Idem Device_Reboot_Notify2 à l’exception de l’ordre d’initialisation non inversé

    1.1.10 Message de contrôle Crit_Reboot_Notify

    Idem Crit_Reboot_Notify2 à l’exception de l’ordre d’initialisation non inversé.

    1.1.11 Explication sur les messages avec suffixe 2

    Vous pouvez vous demander pourquoi ces deux messages de sortie on un suffixe "2". Rappelez-vous que quand la VMM charge un VxD statique, il charge le VxD avec l'initialisation d'ordre inférieur d'abord pour que les VxD puissent compter sur les services des VxD qui se chargent avant eux. Par exemple, si VxD2 compte sur les services de VxD1, il doit spécifier que son ordre d'initialisation sera plus élevé que celui de VxD1. L'ordre de chargement serait :

    ..... VxD1 ===> VxD2 ===> VxD3 ....

    Maintenant pendant le déchargement, il est logique de que les VxD qui sont initialisé le plus tard doivent initialiser d'abord ceux dont ils font un appel de service VxD. Dans le cas, l'ordre doit être :

    .... VxD3 ===> VxD2 ===> VxD1....

    Dans cet exemple, si le VxD2 appelle des services de VxD1 pendant l'initialisation, il doit pouvoir compter sur les services de VxD1 de nouveau pendant le déchargement. System_Exit2 et Sys_Critical_Exit2 sont donc envoyés en ordre inverse de l'ordre de chargement. Cela signifie que, quand le VxD2 reçoit ces messages, VxD1 n'a pas encore été dés initialisé et que VxD2 peut toujours appeler des services de VxD1. Avec System_Exit et Sys_Critical_Exit les messages ne sont pas envoyés en ordre inverse.

    Cela signifie que quand vous traitez ces deux messages, vous ne pouvez pas être sûrs de pouvoir appeler les services d'un VxD qui a été chargé avant votre VxD.

    Ces messages ne doivent pas être employés pour les VxD récents.

    1.2 Les VxD dynamiques

    1.2.1 Généralités

    Les VxD dynamiques peuvent être dynamiquement chargés et déchargés pendant une session de Windows 9x. Cette particularité n'est pas disponible sous Windows 3.x. Le but primaire des VxD dynamiques est de soutenir la reconfiguration dynamique hardware comme les périphériques dispositifs Plugs and Play. Cependant, vous pouvez très bien les charger ou les décharger à partir d'une application win32 ce qui les rend idéals pour donner des extensions ring-0 à vos applications.

    L'exemple dans le tutorial précédent est un VXD statique. Vous pouvez convertir cet exemple en VXD dynamique en ajoutant le mot-clé DYNAMIC à la déclaration VXD dans le fichier .DEF.

    VXD FIRSTVXD     DYNAMIC

    C'est tout que vous devez faire pour convertir un VxD de statique à en dynamique.

    Un VxD Dynamique peut être chargé de différentes façons:

  • En le mettant dans le sous répertoire \SYSTEM\IOSUBSYS de votre répertoire Windows.
    Les VxD dans ce dossier seront chargés par le Input Output Supervisor (IOS). Les VxD dans ce répertoire doivent être des layer device drivers donc, est possible que ce ne soit pas la meilleure manière de charger un VxD.
  • Par un service VxD Loader.
    VxDLDR est un VxD statique qui peut charger dynamiquement un VxD dynamique. Vous pouvez appeler ce service à partir d'autre VxD ou de code 16 bits.
  • En utilisant l’API Win32 CreateFile à partir d’une application.
    Vous spécifiez le VxD dynamique VxD à charger avec CreateFile dans le format \\.\pathname
  • Par exemple, si vous voulez charger le VxD nommé FirstVxD dans le répertoire courrant, vous devez faire comme suit :

    .data
    VxDName db "\\.\FirstVxD.VXD",0
    ......
    .data?
    hDevice dd ?
    .....
    .code
    .....
    invoke CreateFile, addr VxDName,0,0,0,0, FILE_FLAG_DELETE_ON_CLOSE,0
    mov hDevice, eax
    ......
    invoke CloseHandle, hDevice
    ......

    Le flag FILE_FLAG_DELETE_ON_CLOSE spécifie que le VxD est déchargé quand le handle retourné par CreateFile est refermé.

    Si vous employez CreateFile pour charger un VxD dynamique, le VxD doit traiter le message w32_DeviceIoControl. VWIN32 envoie ce message de contrôle à votre VxD dynamique quand il est chargé par la fonction CreateFile. Votre VxD doit retourner 0 dans eax en réponse à ce message.

    Les messages W32_DeviceIoControl sont aussi envoyés quand l'application appelle l'API DeviceIoControl pour communiquer avec le VxD. Nous examinerons DeviceIoControl plus tard.

    1.2.2 Messages d’initialisation et de clôture

    Un VxD dynamique reçoit un message :

  • Sys_Dynamic_Device_Init pendant l'initialisation.
  • Sys_Dynamic_Device_Exit pendant la terminaison.
  • Un VxD dynamique ne recevra ni Sys_Critical_Init, ni Device_Init, ni Init_Complete parce que ces messages sont envoyés pendant l'initialisation de la VM système. De plus un VxD dynamique reçoit tous les autres messages de contrôle quand il est en mémoire. Il peut faire tout ce que un VxD statique peut faire.

    2 Messages de Contrôle du Système

    2.1 Généralités

    Pendant le temps ou un VxD réside en mémoire , il recevra beaucoup de messages de contrôle autres que ceux liés à l'initialisation et la terminaison. Certains d'entre eux se rapportent à la gestion de la machine virtuelle, d’autres à des événements divers.

    2.2 Messages de contrôle relatifs à la VM

  • Create_VM
  • VM_Critical_Ini
  • VM_Suspend
  • VM_Resume
  • Close_VM_Notify
  • Destroy_VM
  • C'est de votre responsabilité de répondre aux messages de contrôle auxquels vous portez intérêt.

    3 Création de procédures à l'intérieur du VxD

    Vous déclarez une procédure dans un VxD à l'intérieur d'un segment. Vous devez définir un segment d'abord et mettre ensuite votre procédure à l'intérieur de ce segment. Par exemple, si vous voulez que votre fonction soit dans un segment paginable, vous devez définir ce segment comme cela :

    VxD_PAGEABLE_CODE_SEG
    [Votre procédure ici]
    VxD_PAGEABLE_CODE_ENDS

    Vous pouvez mettre beaucoup de procédures à l'intérieur d'un segment. Comme auteur de VxD vous devez décider quel segment recevra vos procédures. Si vos procédures doivent être toujours en mémoire, comme par exemple un traitement d'interruptions, mettez les dans un segment verrouillé. Autrement vous devez les mettre dans un segment paginable.

    Vous définissez votre procédure avec les macros BeginProc et EndProc

    BeginProcname
    EndProcname

    Name est le nom de votre procédure. La macro BeginProc peut prendre plusieurs autres paramètres supplémentaires, consultez le DDK pour de plus amples renseignements.

    Mais la plupart du temps, vous n'avez besoin que du nom de la procédure. Vous devez employer les macros BeginProc et EndProc au lieu des directives normales proc et endp parce que ces macros fournissent plus de fonctionnalités que proc et endp.

    4 Convention de codage d’un VxD

    4.1 Usage des registres

    Votre VxD peut employer n'importe quel registre général, FS et GS. Mais vous devez prendre garde de la modification des registres de segment.

    Particulièrement, vous ne devez certainement pas changer CS et SS à moins que vous ne soyez tout à fait sur de ce que vous faites.

    Vous pouvez employer DS et ES tant que vous n'oubliez pas de rétablir leurs valeurs au retour de fonction. Deux flags sont particulièrement importants : Le flag de direction et le flag d’interruption. Vous ne devez désactiver les interruptions pendant une période prolongée et si vous modifiez le flag, n'oubliez pas de rétablir son état précédent au retour de fonction.

    4.2 Passage des paramètres

    4.2.1 Services basés sur les registres

    Avec la technique registre, vous passez des paramètres aux services via des registres divers et vous pouvez vérifier le carry flag après l'appel du service pour voir si l'opération à réussie. Les valeurs des registres généraux ne sont pas automatiquement préservées après l'appel du service.

    4.2.2 Services basés sur la pile

    Avec des services basés sur la pile, vous poussez les paramètres sur la pile et vous obtenez la valeur de retour dans eax. Les services basés sur la pile préservent ebx, esi, edi et ebp.

    4.2.3 Astuce

    La plupart la des services basés sur les registres datent de Windows 3.x. pour la plupart, vous pouvez différencier ces services par leurs noms. Si le nom du service commence par un underscore comme _HeapAllocate, c'est un service basé la pile (convention C), à la part quelques services exportés par VWIN32. VXD.

    Si le nom ne commence pas par un underscore, c'est un service basé sur registre.

    5 Appel des services VxD

    Vous appelez les services VMM et VxD en employant les macros VMMCall et VxDCall. Ces deux macros ont exactement la même syntaxe. Vous employez VMMCall quand vous voulez appeler des services VxD exportés par VMM et vous employez VxDCall quand vous appelez des services exportés par un VxD autre que la VMM.

    VMMCall service                      ;pour les service base registre
    VMMCall _service, <argument list>    ;pour les services base pile

    Les macros VMMCall et VxDCall se décomposent en int 20h suivi par un dword que j'ai décrit dans le chapitre précédant mais elles sont beaucoup plus commodes à employer. Dans le cas de services basés sur la pile, vous devez inclure la liste d'arguments avec une paire de parenthèses angulaires.

    VMMCall _HeapAllocate, <<size mybuffer>, HeapLockedIfDP>

    _HeapAllocate est un service basé sur la pile. Il accepte deux paramètres. Nous devons les inclure dans des parenthèses angulaires. Cependant, le premier paramètre est une expression qui la macro peut interpréter inexactement, nous la mettons également à l'intérieur de parenthèses angulaires.

    6 Adresses Linéaires

    Avec les outils anciens, l'assembleur et le linker produisait des adresses incorrectes quand vous employiez l'opérateur offset. Ainsi les programmeurs de VxD emploient les adresses linéaires au lieu des offset classiques.

    vmm.inc contient une macro pour faciliter cela : OFFSET32. Ainsi au lieu d’employer l'opérateur offset, employez OFFSET32.

    Note : j'ai expérimenté avec l'opérateur d'offset quand j'ai écrit ce document. Il a produit des adresses correctes. Je pense que le bogue a été enlevé dans MASM 6.14. Mais par sécurité vous utilisez OFFSET32.

    Page:  1  2  3  5  6  7  8  9 

    Précédent       Suivant

    Copyright © Jean-Pierre Fayeulle