Obligement - L'Amiga au maximum

Dimanche 20 août 2017 - 21:03  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

 · Accueil
 · A Propos
 · Articles
 · Galeries
 · Glossaire
 · Hit Parade
 · Liens
 · Liste jeux Amiga
 · Quizz
 · Téléchargements
 · Trucs et astuces


Articles

 · Actualité (récente)
 · Actualité (archive)
 · Comparatifs
 · Dossiers
 · Entrevues
 · Matériel (tests)
 · Matériel (bidouilles)
 · Points de vue
 · En pratique
 · Programmation
 · Reportages
 · Tests de jeux
 · Tests de logiciels
 · Tests de compilations
 · Articles divers

 · Articles in english
 · Articles in other languages


Twitter

Suivez-nous sur Twitter




Liens

 · Sites de téléchargements
 · Associations
 · Pages Personnelles
 · Moteurs de recherche
 · Pages de liens
 · Constructeurs matériels
 · Matériel
 · Autres sites de matériel
 · Réparateurs
 · Revendeurs
 · Presse et médias
 · Programmation
 · Développeurs logiciels
 · Logiciels
 · Développeurs de jeux
 · Jeux
 · Autres sites de jeux
 · Scène démo
 · Divers
 · Informatique générale


Jeux Amiga

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Trucs et astuces

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Glossaire

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Partenaires

Annuaire Amiga

Amedia Computer

Relec

Hit Parade


Contact

David Brunet

Courriel

 


Programmation : Assembleur - les commodités
(Article écrit par Frédéric Delacroix et extrait d'Amiga News - juin 1995)


La commodities.library est une autre des bonnes choses que nous ont apportées les ingénieurs de Commodore lors de la sortie du Kickstart 2.0. Elle permet de regrouper tous les utilitaires système sous une interface standard et leur facilite l'accès aux "hotkeys" (raccourcis clavier).

Une "hotkey", vous le savez certainement, est une combinaison de touches qui a un certain effet sur un programme donné. Par extension, ce peut aussi être l'insertion d'une disquette ou l'action sur un bouton de la souris.

La commodities.library a ainsi simplifié la description (ce qui permet à l'utilisateur de configurer facilement ses choix) et la détection de ces raccourcis clavier, grâce à une syntaxe facile et puissante, et un système de programmation orientée objet performant. Le but de cet article n'étant pas de décrire la commodities.library, je vous renvoie à l'article d'Olivier Jeannet paru dans Amiga News n°73 à ce sujet.

Le sujet

Chaque commodité crée généralement (bien que rien ne l'y oblige) au moins un raccourcis-clavier, ne serait-ce que pour appeler sa fenêtre de configuration.

Certaines (ToolManager par exemple) peuvent en créer des centaines à la demande de l'utilisateur. Comment alors se rappeler qu'il y a trois mois, j'avais défini quelque part un raccourcis-clavier pour faire quelque chose comme ça ?

C'était "rawkey lcommand rcommand -caps control repeat a" ou bien "rawkey right_mouse lcommand rshift capslock numeric_pad enter" ? Le programme Exchange fourni avec le Workbench liste toutes les commodités déclarées (par leur "Broker"), mais pas les raccourcis-clavier créés (sous forme d'objet de type CX_FILTER) par ces commodités. La première raison est qu'il peut y en avoir énormément, et la seconde est que ces objets CX_FILTER ne sont pas conservés en mémoire sous forme de description écrite mais sous forme compilée, en utilisant une structure InputXpression.

On peut toutefois imaginer, nous y voilà, pour résoudre ce type de problème crucial, un utilitaire dans le genre de DOSTrace, IconTrace ou SnoopDOS, qui garderait la trace de la création des objets CX_FILTER en modifiant la commodities.library. C'est exactement le rôle du programme de ce mois-ci.

Le programme

Il s'agit de modifier la fonction CreateCxObj() de la commodities.library. Son rôle est de créer un nouvel objet, dont le type est fourni en D0, en utilisant deux arguments supplémentaires fournis dans les registres A0 et A1, qui dépendent entièrement du type de l'objet. Nous remplaçons donc la fonction originale de la commodities.library par la fonction qui s'appelle NewCreateCxObj() dans le code source ci-dessous. Celle-ci commence par tester si l'objet à créer est de type CX_FILTER. Si c'est le cas, A0 pointe sur la chaîne de description qui nous intéresse, et A1 est nul. On affiche donc, grâce à une fonction du DOS, le nom du programme et la description du raccourci-clavier créé. Cependant, il faut faire très attention : lorsque la fonction NewCreateCxObj() est appelée, elle l'est par une autre tâche que le programme qui l'a installée, et qui n'est pas censé appeler le DOS. Un minimum de précautions s'impose donc : il faut tester si cette tâche est en réalité un processus (les simples tâches ne peuvent pas appeler les fonctions du DOS), ce qui se fait en regardant si le champ ln_Type de la structure Node incluse dans la structure Task pointée par le champ ThisTask de la structure ExecBase (ouf) est à NT_PROCESS.

J'ai ajouté une difficulté supplémentaire : gérer plusieurs fichiers journal (logs) à la fois. Cela montre un peu l'usage de la fonction ReadArgs() et permet d'avoir à la fois le compte-rendu à l'écran et dans un fichier. La fonction ReadArgs() réserve ainsi un tableau de pointeur sur les noms de fichiers à créer. Une boucle calcule la taille de la zone mémoire à réserver pour stocker les pointeurs sur les FileHandles correspondants. On ouvre ensuite ces fichiers en écriture un à un. Une routine (la bien-nommée Print) se chargera d'écrire dans tous ces fichiers. Ensuite, la fonction CreateCxObj() est modifiée par SetFunction() et le programme attend un Ctrl-C avant de quitter.

Précautions

A chaque fois qu'on utilise SetFunction(), il faut être très prudent. En effet, rien ne garantit l'exclusivité des modifications d'une bibliothèque à votre tâche. Il se peut très bien qu'une autre tâche modifie la routine que vous avez vous-même modifiée. Si vous quittez avant cette autre tâche, vous annulez sa modification en remettant tout comme vous l'avez trouvé ! Il y a aussi des cas où une tâche se retrouve en train d'accéder à de la mémoire qui a été libérée ! Les programmes polis qui modifient les fonctions vous en avertissent avant de quitter. Je pense notamment à Magic Menu (qui vous propose de se désactiver) et CycleToMenu (qui refuse de quitter). D'autres programmes préfèrent laisser une petite routine en mémoire qui ne fait rien d'autre que sauter à l'ancienne fonction, le reste du programme étant libéré (là aussi il faut faire très attention).

D'autre part, quand on utilise SetFunction() pour modifier une bibliothèque, il faut faire attention à bien respecter l'assignation des registres de la fonction originale. Tous les registres autres que D0-D1/A0-A1/A6 doivent être sauvegardés absolument. De plus, il ne faut pas utiliser SetFunction() sur les bibliothèques non standards, c'est-à-dire celles qui ne comportent pas de table de saut à base de JMP. Je ne connais qu'une telle clownerie : la dos.library pré-2.0, écrite en BCPL (m'enfin !). L'autodoc de la fonction SetFunction() dit qu'il faut alors tout faire "à la main" (donc en s'occupant des caches du processeur et des sommes de contrôle) en préservant les six octets du vecteur. Même comme ça, ça ne risque pas de marcher puisque cette table est faite à coup d'instruction BRA (du moins si on se fie à l'excellent Amiga Guru Book), c'est-à-dire de déplacements relatifs. Il faut alors décoder les instructions et calculer l'adresse de branchement exacte. Eddy Caroll a eu beaucoup de travail pour son SnoopDOS !

Enfin, je rappelle que tout code faisant partie d'une bibliothèque partagée est susceptible d'être appelé par plusieurs tâches à la fois, et donc qu'il doit être réentrant ou comporter un système d'arbitrage à base de sémaphores.

Sur ce, je vous laisse avec le code source du programme. Je vous rappelle qu'il prend comme argument des noms de fichiers journal à créer (par exemple : HotKeyTrace CONSOLE: RAM:HKT.Log), et ne demande qu'à être amélioré : ajoutez une interface graphique, des fonctions de remplacement d'un raccourci-clavier par un autre, etc.

            include exec/exec.i
            include exec/exec_lib.i
            include libraries/commodities.i
            include libraries/commodities_lib.i

            move.l  4.w,a6
            lea     DOS.Name(pc),a1 ; ouvre le dos
            moveq   #37,d0
            jsr     _LVOOpenLibrary(a6)
            move.l  d0,DOS.Base
            beq     exit
            lea     Commodities.Name(pc),a1
            moveq   #37,d0  ; ouvre commodities
            jsr     _LVOOpenLibrary(a6)
            move.l  d0,Commodities.Base
            beq     closedos

            move.l  DOS.Base(pc),a6
            move.l  #Args.Template,d1
            move.l  #Args.Array,d2
            moveq   #0,d3   ; lit les arguments
            jsr     _LVOReadArgs(a6)
            move.l  d0,Args.RDArgs
            beq     closecommodities

            move.l  Args.Array(pc),a4
CountLogs   ; allouer de la mémoire pour
            tst.l   (a4)+   ; les handles des
            bne.s   CountLogs   ; fichiers log
            sub.l   Args.Array(pc),a4
            move.l  a4,d0
            move.l  #MEMF_PUBLIC!MEMF_CLEAR,d1
            move.l  4.w,a6
            jsr     _LVOAllocVec(a6)
            move.l  d0,Logs.Handles
            beq     freeargs
    
            move.l  Args.Array(pc),a4
            move.l  Logs.Handles(pc),a5
            move.l  DOS.Base(pc),a6
LogOpen     move.l  (a4)+,d1
            beq.s   LogEnd  ; ouvre les fichiers log
            move.l  #MODE_NEWFILE,d2
            jsr     _LVOOpen(a6)
            move.l  d0,(a5)+
            bne.s   LogOpen

LogEnd      move.l  Commodities.Base(pc),a1
            move.l  #_LVOCreateCxObj,a0
            move.l  #NewCreateCxObj,d0
            move.l  4.w,a6  ; patche CreateCxObj()
            jsr     _LVOSetFunction(a6)
            move.l  d0,OldCreateCxObj
            lea     Installed.MSG(pc),a3
            move.l  d0,-(sp)
            pea     NewCreateCxObj
            move.l  sp,a4
            bsr.s   Print
            addq.l  #8,sp

            move.l  #SIGBREAKF_CTRL_C,d0
            jsr     _LVOWait(a6)    ; attend un CTRL-C

            move.l  Commodities.Base(pc),a1
            move.l  #_LVOCreateCxObj,a0 ; remet tout
            move.l  OldCreateCxObj(pc),d0   ; en place
            jsr     _LVOSetFunction(a6)

            move.l  DOS.Base(pc),a6
            move.l  Logs.Handles(pc),a4
LogClose
            move.l  (a4)+,d1    ; ferme les logs
            beq.s   freehandles
            jsr     _LVOClose(a6)
            bra.s   LogClose
freehandles
            move.l  Logs.Handles(pc),a1
            move.l  4.w,a6
            jsr     _LVOFreeVec(a6)
freeargs
            move.l  Args.RDArgs(pc),d1
            move.l  DOS.Base(pc),a6 ; libère les arguments
            jsr     _LVOFreeArgs(a6)
closecommodities
            move.l  Commodities.Base(pc),a1
            move.l  4.w,a6  ; ferme tout et quitte
            jsr     _LVOCloseLibrary(a6)
closedos
            move.l  DOS.Base(pc),a1
            jsr     _LVOCloseLibrary(a6)
exit        moveq   #0,d0
            rts

; la routine suivante est un printf() pour tous les fichiers
; log
Print       ; Print(Format,Args)(A3,A4)
            movem.l d0-d3/a0-a1/a4-a6,-(sp)
            move.l  DOS.Base(pc),a6
            move.l  Logs.Handles(pc),a5
.Loop       move.l  (a5)+,d1
            beq.s   .End
            move.l  a3,d2
            move.l  a4,d3
            jsr     _LVOVFPrintf(a6)
            bra.s   .Loop
.End        movem.l (sp)+,d0-d3/a0-a1/a4-a6
            rts

; nouvelle fonction CreateCxObj(): elle est appelée à la
; place de celle de commodities.

NewCreateCxObj  ; Obj=NewCreateCxObj(type,arg1,arg2)(D0,A0,A1)
            cmp.l   #CX_FILTER,d0
            bne.s   .Normal
            movem.l d0/a1/a3-a4/a6,-(sp)
            move.l  4.w,a6
            move.l  ThisTask(a6),a1
            cmp.b   #NT_PROCESS,LN_TYPE(a1)
            bne.s   .Back   ; seulement les processus
            move.l  a0,-(sp)    ; touche en question
            move.l  LN_NAME(a1),d0
            bne.s   .GoodName
            move.l  #EmptyName,d0
.GoodName
            move.l  d0,-(sp)    ; nom du prog
            lea     Creating.MSG(pc),a3
            move.l  sp,a4
            bsr Print
            addq.l  #8,sp
.Back       movem.l (sp)+,d0/a1/a3-a4/a6
.Normal     move.l  OldCreateCxObj(pc),-(sp)
            rts ; saute à la routine originale

DOS.Base            dc.l    0
Commodities.Base    dc.l    0
Args.Array          dc.l    0
Args.RDArgs         dc.l    0
Logs.Handles        dc.l    0
OldCreateCxObj      dc.l    0

DOS.Name            dc.b    'dos.library',0
Commodities.Name    dc.b    'commodities.library',0
Args.Template       dc.b    'LOGS/M',0
Installed.MSG       dc.b    'Patch Installé: CreateCxObj().',10
                    dc.b    ' Nouveau: %lx',10
                    dc.b    ' Ancien:  %lx',10,0
Creating.MSG        dc.b    'Objet CX_FILTER créé par "%s":',10
                    dc.b    '%s',10,0
EmptyName           dc.b    '«Inconnu»',0


[Retour en haut] / [Retour aux articles] [Article précédent] / [Article suivant]