[Résolu] Extraction de donné dans un AppleEvent

tabliertablier Membre
juin 2008 modifié dans API AppKit #1
Je ne suis pas sur que ce message soit au bon endroit!! je n'expose ici qu'une petite partie du problème.

Je souhaite commander toast en direct par des AppleEvents. Toast étant ouvert par ailleur et son PSN étant connu, l'équivalent du script:
global ToastBase
tell application "Toast Titanium"
set ToastBase to make new ISO 9660 disc
end tell

s'écrit comme ci-dessous. Il s'agit donc d'envoyer un apple Event, et de récupérer l'apple event de retour. cela marche très bien:
OSErr err;
AppleEvent diskEvent;
AppleEvent reponse ;

err = AEBuildAppleEvent( kAECoreSuite, kAECreateElement,
                                  typeProcessSerialNumber, &Toastpsn, sizeof(Toastpsn),
                                  kAutoGenerateReturnID, kAnyTransactionID, &diskEvent, NULL,
                                  "'kocl':type('dI96')") ;
if (err == noErr)
{
err = AESend(&diskEvent, &reponse, kAEWaitReply | kAECanInteract,
                                            kAENormalPriority, kNoTimeOut, NULL, NULL) ;
(void) AEDisposeDesc(&diskEvent);

A ce point du fonctionnement, Toast est correctement réglé et j'ai dans "reponse" l'AppleEvent de retour dont la représentation dans la console est:
{ 1 } 'aevt':  aevt/ansr (ppc ){
          return id: 64815107 (0x3dd0003)
    transaction id: 0 (0x0)
  interaction level: 112 (0x70)
    reply required: 0 (0x0)
            remote: 0 (0x0)
  target:
    { 1 } 'psn ':  8 bytes {
      { 0x0, 0x5e0001 } (Toast Titanium)
    }
  optional attributes:
    < empty record >
  event data:
    { 1 } 'aevt':  - 1 items {
      key '----' -
        { 1 } 'obj ':  - 4 items {
          key 'want' -
            { 1 } 'type':  4 bytes {
              'Disc'
            }
          key 'from' -
            { -1 } 'null':  null descriptor
          key 'form' -
            { 1 } 'enum':  4 bytes {
              'indx'
            }
          key 'seld' -
            { 1 } 'long':  4 bytes {
              1 (0x1)
            }
        }
    }
}
Cet AppleEvent contient l'index du disque à  remplir (ici: 1). Et je n'arrive pas à  extraire cet index. J'ai beau lire, relire et faire différents essais, je ne m'en sort pas  >:(
Comment fait-on cela? Eventuellement qui aurait un exemple plus complexe que ce qu'il y a dans la doc?

Réponses

  • NoNo Membre
    14:43 modifié #2
    La réponse de ton apple-event (ici dans la variable reponse) est aussi un apple-event.
    Donc tu dois utiliser la function AEGetParamDesc pour extraire le contenu de la donnée de key 'seld' (je pense que c'est cette clé qui contient l'index que tu veux).
  • tabliertablier Membre
    14:43 modifié #3
    Oui, c'est bien la valeur de 'seld' que je souhaite récupérer et j'ai bien compris que la réponse est elle même un AppleEvent. Dans les cas simples de réponse comme:
    { 1 } 'aevt':  aevt/ansr (ppc ){
              return id: 32833539 (0x1f50003)
        transaction id: 0 (0x0)
      interaction level: 112 (0x70)
        reply required: 0 (0x0)
                remote: 0 (0x0)
      target:
        { 1 } 'psn ':  8 bytes {
          { 0x0, 0x460001 } (CDFinder)
        }
      optional attributes:
        < empty record >
      event data:
        { 1 } 'aevt':  - 1 items {
          key '----' -
            { 1 } 'long':  4 bytes {
              65 (0x41)
            }
        }
    }
    qui est une réponse de CDFinder, AEGetParamDesc ou AEGetParamPtr permettent d'arriver directement au "65" qui est la valeur recherchée. Dans le cas exposé au debut, le paramètre doit être un objet spécifié car:
    err = AESizeOfParam(&reponse, keyDirectObject, &letyp, &taille) ;
    renvoie 'obj ' comme type (et 84 comme taille).  'seld' n'est pas un paramètre de 'reponse' car
    err = AESizeOfParam(&reponse, 'seld', &letyp, &taille) ;
    renvoie une erreur. Donc 'seld' doit être une spécification du l'objet qui est le paramètre de 'reponse'.
    Logiquement, je pense qu'il faut extraire le paramètre (le descripteur de l'objet??) puis aller chercher sa spécification 'seld'. Et là , il me reste beaucoup de questions et je n'arrive pas à  écrire le code!

  • NoNo Membre
    14:43 modifié #4
    Quand on lit le dump de la réponse que tu as posté, il ne s'agit pas d'un type "simple", mais d'une liste.
    Il faut donc extraire l'argument sous forme de liste, puis parcourir chaque index de cette liste jusqu'à  trouver l'index de clé 'seld' pour en extraire sa valeur.
    Voici un code non testé, mais qui doit en gros t'indiquer la marche à  suivre :
    <br />AEDescList liste;<br />long nbcle, ix, tmplong, seld;<br />AEKeyword cle;<br /><br />// récupération du paramètre sous forme de liste<br />AEGetParamDesc(&amp;reponse, keyDirectObject, typeAEList, &amp;liste);<br /><br />// récupération du nombre d&#39;index dans la liste<br />AECountItems(&amp;liste, &amp;nbcle);<br /><br />// par défaut, valeur &#39;seld&#39; non trouvée<br />seld=-1;<br /><br />// parcours de chaque index de la liste jusqu&#39;à  trouver &#39;seld&#39;<br />for (ix=1; ix&lt;=nbcle; ix++)<br />{<br />    // lecture de l&#39;index n°ix<br />    AEGetNthPtr(&amp;liste, ix, typeWildCard, &amp;cle, NULL, &amp;tmplong, sizeof(long), NULL);<br /><br />    // l&#39;index a pour clé la valeur &#39;seld&#39; : on mémorise sa valeur et on quitte la boucle<br />    if (cle==&#39;seld&#39;)<br />    {<br />        seld=tmplong;<br />        break;<br />    }<br />}<br /><br />if (seld&gt;=0)<br />{<br />    // seld trouvé !<br />}<br />
    

    C'est minimaliste. Chaque fonction AE retourne un code erreur qui doit être testé.
    J'ai aussi des doutes sur la récupération du type long de la clé 'seld'. J'ai choisi de ne pas faire de conversion (type typeWildCard) en espérant que ça retourne effectivement une valeur de type long. Sinon, il faudra approfondir la doc pour passer le juste type.

  • tabliertablier Membre
    14:43 modifié #5
    J'ai déja essayé cela et ça n'a pas marché!. Mais comme monsieur No a insisté (dois-je dire docteur?), j'ai été relire la "tn2045" et j'ai compris que comme un AERecord est une liste, on peut le traité comme une liste a condition de le déclarer AERecord et non pas AEDescList. Donc ça marche si l'on code:
    AERecord dico;
    long nbcle, ix, seld;
    AEKeyword cle;

    // récupération du paramètre sous forme de dictionnaire
    AEGetParamDesc(&reponse, keyDirectObject, typeAERecord, &dico);

    // récupération du nombre d'index dans le dico
    AECountItems(&dico, &nbcle);

    // parcours de chaque index du dico jusqu'à  trouver la clef 'seld'
    for (ix=1 ; ix<=nbcle; ix++)
    {
        // lecture de l'index n°ix
        AEGetNthPtr(&dico, ix, typeWildCard, &cle, NULL, &seld, sizeof(long), NULL);

        // l'index a pour clé la valeur 'seld' : on quitte la boucle
        if (cle=='seld'break;
    }

    if (cle=='seld')
    {
        // seld trouvé !
    }
    Et voilà ! Merci à  No pour son aide.  :P
    Il me reste une intérogation: porquoi l'index va de 1 à  4 et non pas de 0 à  3 comme en C standard?
  • NoNo Membre
    juin 2008 modifié #6
    dans 1213868246:

    Il me reste une intérogation: porquoi l'index va de 1 à  4 et non pas de 0 à  3 comme en C standard?


    L'Apple Event Manager date de Système 7.
    La toolbox du Mac à  cette époque été très imprégnée du Pascal.
    Les premières versions de la toolbox (celles datant du Lisa) étaient écrites en Pascal.
    Même si à  l'avènement du Mac, la toolbox a été ré-écrite en C (pour gagner en taille de code et de rapidité), la philosophie est restée la même (que ce soit pour les formats de chaines de caractère, les appels aux fonctions, ou la gestion des tableaux - en Pascal, le premier indice est toujours 1- ).

    PS : je trouve ton code pas très propre.
    En effet, si la liste ne contient aucune donnée, on ne passe pas dans la boucle. Or tu testes ensuite la variable seld qui se trouve non initialisée...
  • AliGatorAliGator Membre, Modérateur
    14:43 modifié #7
    Heu j'ai pas tout suivi ni tout lu, mais... [tt]if (cle=='seld')[/tt] ça marche ça ??
    les guillemets simples c'est en général pour des caractères uniques, pas des chaà®nes, et le "==" pour comparer des chaà®nes, ben heu, bof quoi...
    J'ai dû louper un épisode :P
  • orfaitorfait Membre
    14:43 modifié #8
    C'est vrai que la comparaison parait louche... mais regarde ça (doc apple) :
    <br />typedef FourCharCode AEKeyword;<br />typedef unsigned long FourCharCode;<br />
    

    Donc aucun problème à  priori.
  • NoNo Membre
    14:43 modifié #9
    dans 1213875731:

    J'ai dû louper un épisode :P


    Réapprendre le C ?

    'x' = 1 char ou 1 octet ou 8 bits,
    'xy' = 2 char ou 1 mot ou 16 bits,
    'xyzt' = 4 char ou 1 int ou 32 bits,
    etc...
  • Philippe49Philippe49 Membre
    juin 2008 modifié #10
    #include <stdio.h>

    int main (int argc, const char * argv[]) {
    unsigned short t=(unsigned short) 'xy';
    unsigned int u='a'*256*256*256+'b'*256*256+'c'*256+'d';
    if(t=='xy' && u=='abcd'){
    puts("equality");
    } else {
    puts("non equality");
    }
    return 0;
    }



    % gcc pgm.c -o pgm -Wno-multichar
    % pgm
    equality
    %
  • tabliertablier Membre
    juin 2008 modifié #11
    PS : je trouve ton code pas très propre.
    En effet, si la liste ne contient aucune donnée, on ne passe pas dans la boucle. Or tu testes ensuite la variable seld qui se trouve non initialisée...
    Exact!!!, mais c'est cle que je teste et non pas seld.  j'ai modifié le for comme ça:
    for (ix=1, cle='?-?-' ; ix<=nbcle; ix++)
    Merci  :P
  • AliGatorAliGator Membre, Modérateur
    juin 2008 modifié #12
    Waaah j'ai beau avoir pratiqué le C pendant un sacré paquet d'années (je fais plus que de l'objet maintenant, C++ dans mon taf essentiellement), je crois que j'ai jamais eu connaissance de cette subtilité.

    Bien sûr je connaissais le 'A' représentation alternative du char de valeur 65, code ascii de A.
    Mais 'AB' pour la représentation alternative d'un short = 65*256+66 je connaissais pas, et pareil pour 'ABCD' et les long ;)

    A quel point c'est sensible à  l'endianness, ce truc, d'ailleurs ? 'AB' représente le short 65*256+66 sur toutes les architectures (et donc ainsi représenté en mémoire par 0x41 suivi de 0x42 sur les archis bigendian, l'inverse sur les little endian) ? ou 0x4142 dans tous les cas (et j'imagine que c'est plutôt ça) ?


    Enfin bon, comme quoi on en apprend tous les jours (et toutes les nuits aussi ;D)
  • Philippe49Philippe49 Membre
    juin 2008 modifié #13

    #include <stdio.h>

    int main (int argc, const char * argv[]) {
    unsigned short t= 'xy';
    char c=*((char*) &t );
    putchar(c);     // affiche 'y' en little endian
    return 0;
    }


    dans 1213926738:

    (et donc ainsi représenté en mémoire par 0x41 suivi de 0x42 sur les archis bigendian, l'inverse sur les little endian) ? ou 0x4142 dans tous les cas (et j'imagine que c'est plutôt ça) ?


    Je n'ai pas trouvé de confirmation mais j'imagine aussi que little endian et big endian c'est de la "cuisine arrière" et que dans le code c'est la "lecture humaine" qui est privilégiée.

    [EDIT] la norme ISO/IEC 9899 (6-4-4-4) déclare l'évaluation de ces multibytes "implementation-dependant" 
Connectez-vous ou Inscrivez-vous pour répondre.