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 3

Structure d’un VxD

1 Introduction

Maintenant que vous connaissez les bases concernant le VMM et les VxD, vous êtes capable d’apprendre à écrire du code pour créer un VxD. Vous avez besoin du Windows 95/98 Device Driver Development Kit. Cette acquisition est indispensable. Le DDK de Windows 95 est fourni uniquement aux souscripteurs du MSDN. Toutefois le DDK de Windows 98 DDK est disponible gratuitement grâce au net sur le site de Microsoft. Vous pouvez utiliser le DDK de Windows 98 pour développer des VxD même si ce DDK est plutôt orienté vers les WDM. Vous pouvez télécharger le DDK Windows 98 sur :

http://www.microsoft.com/hwdev/ddk/install98ddk.php

Vous pouvez télécharger le package complet, environ 30 Mo ou sélectionner seulement les parties qui vous intéressent.

Si vous ne téléchargez pas le package complet, n’oubliez pas de télécharger la documentation du DDK Windows 95 DDK documentation incluse dans other.exe.

Le DDK Windows 98 contient MASM version 6.11d. Vous pouvez l’upgrader dans sa dernière version en consultant comment faire sur le site de Iczelion's Win32 Assembly Homepage sur :

http://members.xoom.com/Iczel/

Le DDK Windows 9x DDK contient plusieurs fichiers d’inclusions indispensables qui ne sont pas inclus dans le package MASM32. Vous pouvez également y télécharger la version originale en anglais de ce document, ainsi que les exemples associés.

2 Le format de fichier LE

2.1 Description

Un VxD utilise le format exécutable linéaire LE. C’est le format conçu pour OS/2 version 2.0.Il peut contenir à la fois du code 16-bit et 32-bit, ce qui est une exigence des VxD.

Souvenez-vous que les VxD datent de l’époque de Windows 3.x. En ce temps, Windows se lançait à partir du DOS, aussi les VxD devaient procéder à certaines initialisations en mode réel avant que la machine ne bascule en mode protégé. Le code 16-bit en mode réel devant être dans le même exécutable que le code 32-bit en mode protégé, le format LE est un choix logique.

2.2 Drivers de NT

Les drivers de Windows NT n’ayant pas d’initialisation en mode réel utilisent le format PE et non LE.

3 Classes de segments

3.1 Généralités

Le code et les données dans un fichier LE sont stockés dans différents segments dont les différentes classes sont expliquées ci après.

3.2 LCODE code et données verrouillés

Ce segment est verrouillé en mémoire, ce qui signifie que ce segment ne peut être paginé sur disque. Le code et les données qui doivent être présents à tout moment, tout particulièrement le gestionnaire d’interruption, doivent être dans ce segment.

3.3 PCODE code paginable

Ce segment peut être paginé par le VMM. Le code et les données ne sont pas nécessairement présents en mémoire à tout moment. Le VMM peut paginer ce segment sur disque si le manque de mémoire vive physique se fait sentir.

3.4 PDATA données paginables

3.5 ICODE code d’initialisation

Le code de ce segment est utilisé durant l’initialisation du VxD seulement. Après initialisation ce segment sera détruit par le VMM pour récupérer de la mémoire physique.

3.6 DBOCODE code et données de déboguage

Le code et les données de ce segment sont utilisés quand vous lancez le VxD sous débogueur. Il contient par exemple le gestionnaire du message Debug_Query.

3.7 SCODE code et données statiques

Ce segment sera toujours présent en mémoire, même si le VxD est déchargé. Ce segment est tout particulièrement utilisé pour les VxD dynamiques devant être chargés et déchargés de nombreuse fois durant une session Windows et dont vous souhaitez en garder la configuration.

3.8 RCODE initialisation du code et des données en mode réel

Code 16-bit en mode réel pour l’initialisation.

3.9 16ICODE données d’initialisation en mode protégé USE16

Ce segment est en mode 16-bit et contient le code que le VxD copie du mode protégé au mode V86. Par exemple si vous voulez coller du code V86 dans une VM, le code à transférer doit être dans ce segment. Si vous ne mettez pas ce code dans ce segment, l’assembleur générera un code faux, à savoir 32-bit au lieu de 16-bit.

3.10 MCODE chaînes de caractères verrouillées

Ce segment contient les chaînes de caractères qui sont compilées avec l’aide de macros de message du VMM. C’est utile pour créer des versions internationales de driver.

4 Choix des segments

4.1 Limitations

Cela ne signifie pas que votre VxD doit contenir tous ces segments.

Vous pouvez choisir parmi ceux ci les segments qui vous intéressent. Par exemple, si votre VxD n’a pas besoin d’être initialisé en mode réel, il n’y aura pas de segment RCODE.

La plupart du temps il y aura les segments LCODE, PCODE et PDATA. C’est aux programmeur de VxD de juger de l’opportunité de tel ou tel segment pour le code et les données.

4.2 Conseils

En général, vous devriez utiliser le plus souvent possible les segments PCODE et PDATA car la VMM peut déplacer en mémoire les segments si nécessaire. Il faut utiliser LCODE pour stocker les gestionnaires d’interruption hardware. On n’utilise pas les classes directement, mais vous devez utiliser des segments basés sur ces classes. Les déclarations de ces segments sont stockés dans un fichier de définition de module (.def) comme dans l’exemple complet ci après.

5 Exemple

5.1 Code

VXD FIRSTVXD
SEGMENTS
_LPTEXT          CLASS 'LCODE' PRELOAD NONDISCARDABLE
_LTEXT           CLASS 'LCODE' PRELOAD NONDISCARDABLE
_LDATA           CLASS 'LCODE' PRELOAD NONDISCARDABLE
_TEXT            CLASS 'LCODE' PRELOAD NONDISCARDABLE
_DATA            CLASS 'LCODE' PRELOAD NONDISCARDABLE
CONST            CLASS 'LCODE' PRELOAD NONDISCARDABLE
_TLS             CLASS 'LCODE' PRELOAD NONDISCARDABLE
_BSS             CLASS 'LCODE' PRELOAD NONDISCARDABLE
_LMGTABLE        CLASS 'MCODE' PRELOAD NONDISCARDABLE IOPL
_LMSGDATA        CLASS 'MCODE' PRELOAD NONDISCARDABLE IOPL
_IMSGTABLE       CLASS 'MCODE' PRELOAD DISCARDABLE IOPL
_IMSGDATA        CLASS 'MCODE' PRELOAD DISCARDABLE IOPL
_ITEXT           CLASS 'ICODE' DISCARDABLE
_IDATA           CLASS 'ICODE' DISCARDABLE
_PTEXT           CLASS 'PCODE' NONDISCARDABLE
_PMSGTABLE       CLASS 'MCODE' NONDISCARDABLE IOPL
_PMSGDATA        CLASS 'MCODE' NONDISCARDABLE IOPL
_PDATA           CLASS 'PDATA' NONDISCARDABLE SHARED
_STEXT           CLASS 'SCODE' RESIDENT
_SDATA           CLASS 'SCODE' RESIDENT
_DBOSTART        CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
_DBOCODE         CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
_DBODATA         CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING
_16ICODE         CLASS '16ICODE'     PRELOAD DISCARDABLE
_RCODE           CLASS 'RCODE'

EXPORTS
        FIRSTVXD_DDB  @1

5.2 Explications

La première instruction est la déclaration du nom du VxD, en majuscules.

Après vous trouvez la déclaration des segments, constituée de trois parties : le nom du segment, sa classe, et ses propriétés de fonctionnement. Vous constatez que de nombreux segments partagent la même classe. Par exemple,les segments _LPTEXT, _LTEXT, _LDATA sont tous basés sur la classe LCODE et les mêmes propriétés. Ces segments sont déclarés pour rendre le code plus facile à lire et comprendre.

Par exemple, LCODE peut contenir du code et des données mais il est plus structuré de stocker les données dans le segment _LDATA et le code dans le segment _LTEXT.

Eventuellement les segments partageant la même classe seront combinés dans un seul segment, après mise au point, dans la version finale du VxD.

Un VxD exporte un et seulement un symbole, le device descriptor block (DDB).Le DDB est actuellement une structure contenant tout ce que le VMM a besoin de savoir sur le VxD. Vous devez exporter le DDB dans le fichier de définition de module.

La plupart du temps, vous pouvez utiliser comme modèle ce fichier .def. Changez seulement le nom du VxD en première et dernière ligne.

Les déclarations de segments sont écrasées pour un projet assembleur de VxD. Ils sont prévus pour un projet C , mais il est possible de faire de même en assembleur.

Vous obtiendrez beaucoup de warnings mais cela assemble. Vous pouvez vous débarrasser de ces warnings en effaçant les déclarations de segments inutiles au projet.

“vmm.inc” contient de nombreuses macros pour déclarer vos segments dans le fichier source.

_LTEXT           VxD_LOCKED_CODE_SEG
_PTEXT           VxD_PAGEABLE_COD_SEG
_DBOCODE         VxD_DEBUG_ONLY_CODE_SEG
_ITEXT           VxD_INIT_CODE_SEG
_LDATA           VxD_LOCKED_DATA_SEG
_IDATA           VxD_IDATA_SEG
_PDATA           VxD_PAGEABLE_DATA_SEG
_STEXT           VxD_STATIC_CODE_SEG
_SDATA           VxD_STATIC_DATA_SEG
_DBODATA         VxD_DEBUG_ONLY_DATA_SEG
_16ICODE         VxD_16BIT_INIT_SEG
_RCODE           VxD_REAL_INIT_SEG

Chaque macro a son pendant de terminaison. Par exemple si vous voulez déclarer un segment _LTEXT dans votre source, procédez ainsi :

VxD_LOCKED_CODE_SEG
<le code ici >
VxD_LOCKED_CODE_ENDS

6 Squelette d’un VxD

6.1 Généralités

Maintenant que vous connaissez les segments dans un fichier LE, nous pouvons aller au fichier source. Une chose que vous pouvez observer de la programmation de VxD est l'utilisation importante de macros. Vous trouverez des macros partout dans la programmation de VxD. Ces macros sont fournies pour masquer les détails insidieux aux yeux du programmeur et d'une certaine façon rendre le code plus portable. Si vous êtes curieux, vous pouvez voir la définition de ces macros dans divers fichiers include comme "vmm.inc".

Voici le squelette du code source :

.386p
include vmm.inc
DECLARE_VIRTUAL_DEVICE FIRSTVXD, 1, 0, FIRSTVXD_Control, UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDER
Begin_control_dispatch FIRSTVXD
End_control_dispatch FIRSTVXD
End

À première vue, le code source ne ressemble pas à un code source asm. C'est du à l'utilisation de macros.

Analysons ce code source et vous le comprendrez bientôt.

6.2 .386

Dites à l'assembleur que nous voulons employer le jeu d'instruction 80386 en mode protégé. Vous pouvez aussi employer .486p ou .586p.

6.3 include vmm.inc

Vous devez inclure vmm.inc dans chaque code source VxD parce qu'il contient les définitions de macros que vous employez dans le fichier source. Vous pouvez inclure d'autre include si nécessaire.

6.4 DECLARE_VIRTUAL_DEVICE

Comme exposé précédemment, le VMM apprend tout ce qu'il doit savoir d'un VxD via le VxD_Desc_Block (DDB). Un bloc de descripteur de VxD est une structure qui contient l'information essentielle sur le VxD comme le nom de VxD, son deviceID, les points d'entrée des services VxD (s'ils existent) etc. Vous pouvez chercher cette structure dans VMM.inc. Elle est déclarée comme VxD_Desc_Block. Vous exporterez cette structure dans le fichier .DEF.

Il y a 22 membres dans cette structure, mais vous devrez d'habitude de remplir seulement certains d'entre eux. Ainsi VMM.inc contient une macro qui initialisera et remplira les membres de structure pour vous.

Cette macro est DECLARE_VIRTUAL_DEVICE. Elle a le format suivant :

Declare_Virtual_Device_Name, MajorVer, MinorVer, CtrlProc, DeviceID, InitOrder, V86Proc, PMProc, RefData

Une chose que vous pouvez observer est que, les étiquettes dans le code source VxD sont insensibles à la casse. Vous pouvez employer des majuscules ou des minuscules ou les combiner.

6.5 Paramètres de Declare_Virtual_Device

6.5.1 NAME

Le nom du VxD. La longueur maximale est de 8 caractères. Cela DOIT ÊTRE en majuscule. Le nom doit être unique parmi les VxD dans le système. La macro emploie aussi le nom pour créer le nom du DDB en ajoutant _DDB au nom du device. Ainsi si vous employez FIRSTVXD comme nom du VxD, la macro Declare_Virtual_Device déclarera le nom du DDB comme FIRSTVXD_DDB. Rappelez-vous que, vous devrez aussi exporter le DDB dans le fichier .DEF. Vous devez faire correspondre l'étiquette dans le fichier source avec celui dans le fichier DEF.

6.5.2 MajorVer et MinorVer

Les versions principale et secondaire de votre VxD CtrlProc. Le nom de la procédure de contrôle pour votre VxD. Une procédure de contrôle est une fonction qui reçoit et traite les messages du VxD. Penser qu'une procédure de contrôle est l'équivalent d' une classique procédure de fenêtre.

Puisque nous emploierons la macro Begin_Control_Dispatch pour créer notre procédure de contrôle, nous devons employer le nom standard qui est dans la forme de VxDName_Control.

6.5.3 Begin_Control_Dispatch

La macro ajoute _Control au nom du VxD passé, aussi devons nous spécifier le nom de notre VxD suivi de _Control dans le paramètre CtrlProc.

6.5.4 DeviceID

L'identificateur 16 bits unique de votre VxD. Vous avez besoin de l'ID si et seulement si votre VxD doit utiliser une des situations ci-dessous :

Votre VxD exporte des services VxD pour d'autres VxD. Comme l' interruption 20h emploie l' ID pour identifier le VxD, il est impératif que votre VxD ait un identificateur unique.

Votre VxD correspond avec des applications en mode réel pendant l'initialisation avec la fonction 1607h de l'interruption 2Fh.

Les résidents en mode réel (TSR) employe la fonction 1605h de l'interruption 2Fh pour charger votre VxD.

Si votre VxD n'a pas besoin d'un ID unique ID, vous pouvez spécifier UNDEFINED_DEVICE_ID dans ce champ.

Si vous avez besoin d'ID unique, vous devez en demander un à Microsoft.

6.5.5 InitOrder

L'ordre d'initialisation, ou en bref, l'ordre de chargement. Le VMM charge les VxD dans l'ordre indiqué. Chacun VxD aura un numéro d'ordre de chargement. Par exemple :

VMM_INIT_ORDER          EQU 000000000H
DEBUG_INIT_ORDER        EQU 000000000H
DEBUGCMD_INIT_ORDER     EQU 000000000H
PERF_INIT_ORDER         EQU 000900000H
APM_INIT_ORDER          EQU 001000000H

Vous pouvez voir que VMM, DEBUG et DEBUGCMD sont les premiers VxD chargés, suivi par PERF et APM. Le VxD ayant la plus petite valeur d'ordre d'initialisation est chargé d'abord. Si votre VxD exige les services d'autre VxD pendant l'initialisation, vous devez spécifier une valeur d'ordre d'initialisation qui est plus grande que celui du VxD que vous voulez appeler de manière à ce que le VxD appelé soit déjà en mémoire. Si votre VxD ne se soucie pas de l'ordre d'initialisation, spécifiez UNDEFINED_INIT_ORDER dans ce paramètre.

6.5.6 V86Proc et PMProc

Votre VxD peut exporter l'API pour l'utilisation par des programmes en mode protégé et V86.

V86Proc et PMProc spécifient les adresses de ces API. Rappelez-vous que les VxD existent principalement pour la supervision de VM. Il est raisonnable pour les VxD de fournir le support API pour les programmes DOS et les programmes en mode protégé. Si vous n'exportez pas d' API, vous pouvez omettre ces champs.

6.5.7 RefData

Données de référence employées par l' Input Output Supervisor (IOS). La seule occasion ou vous emploierez ce champ est quand vous programmerez un layer block driver utilisant l'IOS. Vous pouvez omettre ce champ si votre VxD n'est pas un layer block driver.

6.6 La macro Begin_Control_Dispatch

Begin_control_dispatch FIRSTVXD
End_control_dispatch FIRSTVXD

Cette macro et sa contre-partie définissent la procédure de contrôle qui est la fonction que le VMM appelle quand il y a des messages de contrôle pour votre VxD. Vous devez spécifier la première moitié du nom de la procédure de contrôle de dispositif, dans notre exemple nous employons FIRSTVXD. La macro ajoutera _Control au nom que vous avez fourni.

Ce nom doit correspondre à celui que vous spécifiez dans le paramètre CtrlProc de la macro.

6.7 Declare_Virtual_Device

La procédure de contrôle est toujours dans un segment verrouillé VxD_LOCKED_CODE_SEG. Cette procédure de contrôle ne fait rien. Vous devez spécifier quels messages de contrôle sont nécessaires à votre VxD ainsi que fonctions qui les manipuleront. Vous employez la macro Control_Dispatch à cette fin.

6.8 La fonction Control_Dispatchmessage

Par exemple, si votre VxD traite seulement le message Device_Init, votre procédure de contrôle ressemblerait à cela :

Begin_Control_Dispatch FIRSTVXD
Control_Dispatch Device_Init, OnDeviceInit
End_Control_DispatchFIRSTVXD

OnDeviceInit est le nom de la fonction qui manipulera le message Device_Init. Vous pouvez nommer votre fonction comme vous le voulez. Vous finissez le code source du VxD avec la directive de fin.

6.9 Récapitulatif

Pour récapituler, un VxD doit avoir au minimum un device block control et une procédure de contrôle. Vous déclarez un bloc avec la macro Declare_Virtual_Device et une procédure de contrôle avec la macro Begin_Control_Dispatch. Vous devez exporter le bloc en spécifiant son nom sous la directive EXPORTS dans le fichier DEF.

7 Assemblage du VxD

Le processus d'assemblage est le même que celui employé dans l'assemblage d'applications normales win32. Vous exécutez ml.exe sur le code source asm et liez ensuite le fichier d'objet avec link.exe. Les différences sont dans les commutateurs de ligne de commande employés par ml.exe et link.exe

ml -coff -c -Cx -DMASM6 -DBLD_COFF -DIS_32firstvxd.asm

  • -coff Spécifie le format objet COFF
  • -c Assemble seulement. N’appelez pas le linker pour lier le fichier objet.
  • -Cx Préserve la casse des labels public et extern.
  • -D<texte> défini une macro.
    Par exemple, -DBLD_COFF défini une macro BLD_COFF utilise pour l’assemblage conditionnel. Si vous êtes intéressé cherchez BLD_COFF dans les fichiers include et voyez par vous-même l’effet sur le processus d’assemblage. Dans une ligne de commande comme celle ci dessous , 3 macros sont définies : BLD_COFF, IS_32, et MASM6. Si vous êtes familier du C, ce procédé est identique à :

    #define BLD_COFF
    #define IS_32
    #define MASM6

  • link -vxd -def:firstvxd.def firstvxd.obj
  • -vxd spécifie que vous voulez construire un VxD à partir du fichier objet
  • -def:<.DEF file> spécifie le nom du fichier de définition de module.

Je trouve plus commode d'employer un makefile mais vous pouvez créer un fichier batch pour automatiser le processus d'assemblage si vous n'aimez pas l'approche du makefile. Voici mon makefile.

NAME=firstvxd
$(NAME).vxd:$(NAME).obj
  link -vxd -def:$(NAME).def $(NAME).obj
$(NAME).obj:$(NAME).asm
  ml -coff -c -Cx -DMASM6 -DBLD_COFF -DIS_32 $(NAME).asm

Page:  1  2  4  5  6  7  8  9 

Précédent       Suivant

Copyright © Jean-Pierre Fayeulle