[EN] [IT]
  [INFO] [ACQUÉRIR] [PLAN] [RESSOURCES]

ACCÈS RAPIDE

OCTET Y PASSÉ?!
DIVERS EXEMPLES DE CODE & QUELQUES PIÈGES ÉVITÉS
N'ESSAYEZ PAS ÇA À LA MAISON

PALETTES
DÉCLARATIONS
ASSEMBLEUR
ANIMATION BOITEUSE

[Sommaire des FAQ]
[FAQ suivantes]
[FAQ précédentes]
Mise à jour
21 jan. 2000

FAQ #3 :: CODE & COMPLICATIONS
OCTET Y PASSÉ?!

Note technique:
Quand des variables sur un octet sont mises en registre elles deviennent des entiers longs. Pour être sûr qu'elles se comportent comme un octet (valeurs de 0 à 255), désactivez la mise en registre...
DIVERS EXEMPLES DE CODE & QUELQUES PIÈGES ÉVITÉS

[Q]:  Y-a-t'il un moyen de supprimer l'espace d'en-tête quand on utilise STR$(a$)?
[R]:  Vous pouvez utiliser la fonction suivante par exemple:
LOCAL MODE
LOCAL FN StripLdgSpaces$( A$ )
  WHILE A$[1] = _" "
    A$[1] = A$[0]-1
    A$ = PSTR$(@A$[1])
  WEND
END FN = A$

[Q]:  Pourquoi cette boucle est-elle sans fin?
FOR i = 1 to 32767
 FN doSomething
NEXT

[R]:  Vous ajoutez la valeur du pas (1 par défaut) puis vous testez si la valeur finale est dépassée. Si bien qu'un pas qui excède la limite d'un type de variable peut provoquer une boucle infinie. Quand vous arrivez à 32767 et que vous ajoutez le pas (1), la valeur devient -32768. C'est la raison pour laquelle vous êtes scotché dans la boucle.
FB^3 vous donnera maintenant ce message d'erreur:
Erreur: Valeur finale dans une boucle FOR/NEXT en dehors de l’intervalle valide pour ce type de variable!
dans le fichier Temp Project à la ligne 18 dans FBMain
*FOR i = 1 to 32767*

[Q]:  J'ai une routine qui fonctionnait parfaitement bien avec FB2, mais qui rentre dans une boucle infinie (dans une routine de tri) avec FB^3. Voici le code...
GAP%= INT( GAP% /1.3)
[R]:  2/1.3 = 1.538461 qui est arrondi à 2
En d'autres termes, votre boucle DO/UNTIL est infinie parce que vous vous attendez à ce que GAP% soit égal à 1

[Q]:  Oui, 1.5xxxx s'arrondit effectivement à 2, mais je ne fais rien pour arrondir cette valeur. Regardez encore le code...
GAP%= INT( GAP% /1.3)
FB^3 devrait retourner la partie ENTIÈRE seulement, et non pas la valeur ARRONDIE. Le problème c'est que INT(1.5xxxx) devrait être égal à 1, mais qu'il retourne 2. (À moins que vous ayiez changé la définition de la fonction INT()? Ce qui n'est pas une bonne idée.)
[R]:  On avait l'habitude de définir la valeur d'arrondi dans les préférences avec FBII. Jusque là, on manipulait nous-mêmes les nombres. Maintenant, nous utilisons les routines math PPC et nous n'avons plus le contrôle sur la façon d'arrondir un nombre.
C'est un choix parmi des millions d'autres que nous avons dû faire si l'on voulait progresser vers des calculs mathématiques rapides plutôt que de rester dans l'âge des ténèbres avec BCD. À en juger par le bond en avant fait par le nouveau G4 dans les opérations en virgule flottante, je pense que nous avons pris la bonne décision. :)

[Q]:  Le code suivant:
dim a&,aa&,b%,bb%,c#,cc#
a& = -4: b% = -4: c# = -4
aa& = a&>>1: bb% = b%>>1: cc# = c#>>1
print aa&, bb%,cc#
affiche : 2147483646 -2 -2
La valeur pour
INT b% = -4 est divisée par deux, un décalage arithmétique à droite, et naturellement le flottant est divisée par deux. L'entier long a& subit un décalage logique à droite, la valeur de aa& étant 2^31 - 2.
Je comprends que cela puisse être le meilleur compromis à ce stade, peut-être pour assurer la compatibilité avec de l'ancien code FBII. Je viens juste de consulter la documentation à ce sujet (Annexe D du manuel de Référence). Mon opinion est qu'à long terme, il est probable que cette différence de traitement entre les entiers longs et les entiers (sur deux octets) occasionne des problèmes pour ceux qui ne sont pas au courant. Y compris, pour ceux qui utilisent souvent les décalages de bit sans être attentifs à traiter séparément les entiers et les entiers longs pour tenir compte de cette différence de comportement. Quoi qu'il en soit, la différence n'est pas expliquée, ni même mentionnée dans le manuel.
[R]:  Juste une note au sujet des opérations sur les entiers...
var% est un entier sur 16 bits
var& est un entier sur 32 bits
avec FB^3, les calculs sur les entiers sont toujours traités en utilisant des entiers 32 bits, aussi, les entiers signés sur 16 bits sont étendus à des entiers signés sur 32 bits avant toute opération...
En conséquence un entier sur 16 bits valant -4 est représenté comme 0xFFFC et la même valeur sur 32 bits sera représentée par 0xFFFFFFFC
Si le résultat d'une opération sur des entiers doit être stocké dans un entier sur 16 bits, les 16 bits les plus hauts sont perdus...
Ainsi une valeur de -4 décalée d'un bit donnera 0x7FFFFFFE = 2147483646 ce qui peut représenter un nombre entier positif très grand sur 32 bits, ou a petit nombre négatif pour un entier 16 bits = 0xFFFE = -2, les premiers 0x7FFF sont perdus... finalement les calculs sur les entiers sont faits de la même façon....
Pour les flottants, comme avec FBII, il s'agit d'une multiplication ou d'une division par 2^n

[Q]:  Pour empêcher mon code de planter j'ai dû ajouter la ligne signalée par '*':
LOCAL FN Crashes (T AS POINTER)
 XREF M#(3,3) '*
 M& = T
 M#(3,3) = 3.4
END FN

[R]:  Essayez ça:
'----------------------------------
DIM test#(3,3)
LOCAL FN Crashes (localtest#(3,3))
 localtest#(1,1) = 3.4
END FN
PRINT test#(1,1)
FN Crashes(test#(0,0))
PRINT test#(1,1)
STOP
'----------------------------------
FB^3 réalise un XREF automatique sur un tableau passé en paramètre...

[Q]:  Je pense que j'ai découvert un problème avec certaines comparaisons booléennes impliquant des tests sur des entiers. Cette comparaison :

LONG IF premierCas AND secondCas
....
END IF

ne fonctionne pas tout le temps dans mes programmes. Notez que 'premierCas' et 'secondCas' sont toujours soit égaux à zéro, soit des entiers positifs. Occasionallement ce test échoue même si les deux termes sont >0 (je l'ai vérifié soigneusement). La modification suivante semble fonctionner tout le temps (même avec des données qui ne fonctionnaient pas avec le code précédent):
LONG IF premierCas>0 AND secondCas>0
....
END IF
[R]:  Les comparaisons booléennes dans FB s'opèrent sur les bits, et si vous n'y pensez pas, vous risquez d'être surpris (nous sommes tous passés par là). Si premierCas = 1 et secondCas = 2, alors l'instruction:
LONG IF premierCas AND secondCas
est évaluée comme ceci :
0000 0000 0000 0001
0000 0000 0000 0010

AND = :
0000 0000 0000 0000
Tous les bits correpondants des deux termes sont comparés deux à deux avec un AND. Vous arrivez à votre propre solution: assurez-vous que les termes évalués ne puissent être que VRAI ou FAUX, i.e. premierCas>0 AND secondCas>0, ce qui dans le scénario ci-dessus vaudrait VRAI, ou -1 (1111 1111 1111 1111), et en conséquence, le résultat retourné serait VRAI.

[Q]:  Le programme ci-dessous plante, de toute évidence à cause de l'instruction GOTO qui transfère le contrôle à l'extérieur de la structure SELECT. Le compilateur ne pourrait-il pas produire une erreur à la place?
LOCAL FN CrashGOTOInSELECT
 DIM x
 x=1
 WHILE 1
  SELECT x
   CASE 1: GOTO "Skip"
  END SELECT
 WEND
"Skip"
END FN
FN CrashGOTOInSELECT
[R]:  Nous ne pouvons vous protéger contre ça. Après un GOTO vous pourriez revenir dans la structure. (Oui. C'est ce qu'on appelle du code spaghetti.) Vous pouvez toujours utiliser EXIT CASE ou EXIT FN qui est prévu pour ce genre de situation.

[Q]:  J'aime les vrais records, mais la versatilité de l'ancienne méthode me manque. Quelqu'un a-t-il une solution pour définir un vrai record de 8 octets (BEGIN RECORD customRect...) qui permette d'accéder des trois façons différentes au rectangle et à ses composants? Oui, j'ai essayé BEGIN UNION... mais en vain.
[R]:  Ah, voici une déliceuse astuce à deux balles. En allant plus loin vers la simplicité :
DIM r1 as rect, r2 as rect, r3 as rect
r1.top =1: r1.left = 2: r1.bottom = 3: r1.right = 4
PRINT r1.top, r1.left, r1.bottom, r1.right
r2.top& = r1.top& // Copie en tant que...
r2.bottom& = r1.bottom& // ... deux points
PRINT r2.top, r2.left, r2.bottom, r2.right
r3 = r1 //Copie le RECT entier
PRINT r3.top, r3.left, r3.bottom, r3.right

Ce qui est exactement ce qui était demandé. Même si un RECT est officiellement défini comme 4 entiers courts
BEGIN RECORD rect
DIM top, left, bottom, right
END RECORD

vous pouvez grujer le compilateur et accéder aux composants du record par l'intermédiaire d'un entier long (i.e. POINT) en ajoutant le suffixe identificateur de type '&' aux champs top et bottom. Je n'aurais jamais pensé que ce fût légal.

[Andy a aussi ajouté: Ma façon préférée de faire ça, c'est...
LOCAL
 DIM @t,l,b,r
LOCAL FN myRectFunction(@theRectPtr&)
 t;8 = theRectPtr&
 theRectPtr&.left%=123
//etc...

theRectPtr&.Nil&8 = @t
END FN
DIM @t,l,b,r
DIM myRect as RECT
FN myRectFunction(t)

ou
FN myRectFunction(myRect)
Utiliser la variable locale 'l' est plus rapide et plus court que d'utiliser theRectPtr&.left% si on doit l'utiliser plusieurs fois ou bien dans une boucle...]

[Q]:  Ok, si:
DIM myRect.8
myRect.top% = 5
PRINT myRect.top%
dans FB II est différent de
DIM myRect AS RECT
myRect.top% = 5
PRINT myRect.top%
je ne vois pas pourquoi ça l'est dans FB^3. Mais avant tout, dites-moi ce que je dois utiliser dans FB^3 pour résoudre mon problème. C'est tout ce que je veux.
[R]:  Si vous déclarez "AS RECT" alors FB^3 sait ce qu'il y a dans la structure. (top, left, bottom, right). Si vous déclarez ".8" alors FB^3 n'a aucune idée sur ce que contiennent ces 8 octets. Conséquence:
DIM myRect AS RECT
myRect.top = 10
myRect.red = 10  ' ne compilera pas,red n'est pas un champ de RECT

or...
DIM myRect.8
myRect.top% = 10
myRect.red% = 10 ' FB^3 ne fait pas la différence...
                 ' il remplacera les infos dans votre rect!

[Q]:  J'ai déclaré (dans FBII) mes rectangles en tant que variables globales comme ceci :
dim gHdw1ItemRect.8
dim gHdw2ItemRect.8
...
dim gHdw10ItemRect.8

dans une autre section du code, j'accède à leur contenu en me basant sur un décalage à partir de l'adresse de
gHdw1ItemRect. Cela fonctionne (avec FBII) parce que ces 10 variables globales sont heureusement stockées dans un espace contigu en mémoire.
Cependant, je ne sais pas si je peux compter là-dessus avec FB^3. Beaucoup de choses ont changé dans le stockage des variables avec FB^3 (plus que je ne peux le comprendre pleinement); et il y a peu de situations où l'on peut s'attendre de manière certaine à trouver des variables déclarées consécutivement, stockées dans un espace mémoire contigu. Je crois qu'une référence comme "
@gHdw1ItemRect + 8" peut très bien ne pas pointer sur gHdw2ItemRect comme je pourrais m'y attendre (et comme le fait FBII). Elle peut pointer sur une zone interdite en mémoire, qui, si elle est modifiée, peut provoquer un plantage..
[R]:  Je ne suis pas sûr qu'il soit possible de régler ce problème sans reconcevoir votre programme. Vous devriez envisager de déclarer vos rectangles dans un tableau, comme ceci:
dim gHdwItemRect(9) AS RECT
Cela a deux avantages:
1. Vous utiliserez une syntaxe plus lisible quand vous accéderez aux rectangles dans une boucle: i.e. ceci:
theHdwItemRect& = @gHdwItemRect(loop)
...au lieu de cela:
theHdwItemRect& = @gHdw1ItemRect + 8 * loop
2. Vous pourrez être certain que les éléments de votre tableau seront stockés dans un espace mémoire contigu (au cas où d'autres parties de votre code supposent que les rectangles sont stockés de manière consécutive en mémoire). 

[haut de la page]

[Q]:
  J'ai essayé de convertir un projet PG/FBII vers FB^3 et j'ai rencontré un problème avec la fonction FN useAlias. Le manuel dit de l'utiliser comme ceci:

DIM fSpec;0,fVRefNum,fParID&,63 fName$
useAlias = FN useAlias(resID,fSpec)
LONG IF useAlias = _noErr
' at this point, fName$ equals the
' filename of the alias target,
' fVRefNum is its volume reference number,
'and fParID& is its parent ID.
END IF

Mais je n'obtiens pas de fName$ valide. Est-ce que le problème est dans l'instruction DIM?
[R]:  Si vous alignez automatiquement les variables (préférences) cela ne fonctionnera pas. Peut-être devrions-nous supprimer cette option. Avec ces préférences activées, vous devez utiliser...
DIM dummy%,fSpec;0,fVRefNum,fParID&,63 fName$

[Q]:  Huh? D'accord, je m'y colle.. À quoi sert la variable dummy%?
[R]:  L'option d'alignement des variables fait que toutes les variables sont alignées sur des frontières correctes.
Mémoire: |word|word|--long--|string--
Alignement activé: |vref|FFFF,0000,0000,????|-ParID&-|fName--
Alignement désactivé: |word|--long--|string--
Avec dummy: |dumy|vref|-ParID&-|fName---

[Q]:  Ceci ne veut pas fonctionner...
CLEAR LOCAL
LOCAL FN SetMouse( where&)
  CALL LOCALTOGLOBAL( where&)
  POKE LONG _RawMouse, where&
  POKE LONG _MTemp, where&
  POKE WORD _CrsrNew, &FFFF
END FN
[R]:  Le problème est le suivant: les paramètres passés sont fourrés dans des registres dès que c'est possible (si les préférences pour ça ont été activées) mais la procédure LOCALTOGLOBAL ne peut fonctionner avec un registre. Essayez ça :
CLEAR LOCAL
DIM @where&                   'place la variable en mémoire adressable
LOCAL FN SetMouse(RightHere&) 'accepte le paramètre passé,sous un autre nom
where& = RightHere&           'les rend égaux
CALL LOCALTOGLOBAL(where&)
POKE LONG _RawMouse(where&)   'etc...

[Note du Gardien des FAQ: cet exemple de code ne doit pas être utilisé pour une autre raison! Il apparaît que le programmeur ici écrit des informations directement dans une adresse mémoire de bas-niveau... Apple décourage activement ce genre de pratique. Ce code bientôt ne fonctionnera plus, si ce n'est pas déjà le cas!]

[Q]:  Errm... J'hésite à demander ça... mais quelle est la différence entre une variable et une variable en registre? Merci d'avance.
[R]:  Hmm.... j'ai besoin d'un exemple simple que je peux comprendre :
Jim a un bureau, avec une armoire de rangement à côté. Lorsqu'il trie le courrier, les factures à payer vont immédiatement dans un casier sur le bureau (REGISTRES). Les reçus et ces sortes de choses vont dans l'armoire de rangement (RAM). Ils sont tous facilement accessibles, mais il n'y a que peu de casiers sur le bureau, et ils sont petits, si bien que peu de choses peuvent y tenir; les "plus importantes". Toutes les autres choses vont dans l'armoire de rangement, ce qui prend plus de temps à ouvrir et à fouiller lorsqu'on doit y chercher quelque chose. (mais pas plus de temps que pour celles qui sont stockées dans des cartons dans le placard - DISQUE DUR.) Donc, les casiers (REGISTRES) sont vraiment rapides, et ça serait bien de pouvoir y mettre toutes les choses, mais le catalogue de la Redoute (STRINGS) ne pourrait y tenir. On ne peut glisser qu'une seule chose par casier, si bien que lorsqu'ils sont pleins, vous devez soit ranger dans l'armoire, soit retirer quelque chose d'un casier d'abord.
Nous contrôlons l'utilisation des casiers avec les préférences; si nous disons que nous voulons les utiliser, le compilateur essaie alors de "deviner" ce qui est important; et il réserve donc un registre en disant "premier arrivé, premier servi" (enfin presque). Nous pouvons aussi dire au compilateur qu'une chose peut tenir dans le casier mais qu'elle n'est pas importante pour d'autres raisons en utilisant DIM@.

[haut de la page]

[Q]:
  En ce qui concerne le gestionnaire de liste, je fais référence ici au List Manager d'Apple, et pas à un code CDEF. J'espérais que quelqu'un me prouverait que le List Manager fonctionne avec FB^3, (et pas le contraire).. [...] Quant à moi, je n'ai pas réussi à l'utiliser.
[R]:  Je soupçonne que si vous réinitialisez les préférences pour les faire correspondre à FBII, vous allez y arriver. Le fichier inclus d'interfaçage au List Manager utilise beaucoup de points qui sont déclarés comme celly,cellx. Si vous utilisez DIM celly,cellx, ces variables seront mises dans des registres et certaines parties du code ne fonctionneront plus. Vous pouvez contourner cela avec DIM@ celly,cellx qui place les variables en mémoire adressable.

[Q]:  Est-ce que quelqu'un peut me dire comment je peux utiliser l'instruction FN TOOLBOX pour lequel il n'y pas d'adresse donnée. Quand il y en a une, par exemple
toolbox Fn Gestalt(long,@long) = long
`0x245F,0x201F,0xA1AD,0x2488,0x2E80
Je n'ai pas de problème, mais il semble que beaucoup de nouvelles fonctions et procédures sont données sans de telles adresses dans les librairies d'interface de la documentation Apple, et en particulier dans les Cincludes. Comme exemple, nous avons tous vu, [...] le projet Sprockets pour FB^3 qui utilise les librairies DrawSprocket et InputSprocket. Les définitions des appels Toolbox ne comportent pas d'adresse, par exemple
toolbox fn DSpStartup () = int
et quand j'essaie d'exécuter ce projet, il plante lorsqu'il tente d'exécuter l'appel - en fait, le premier appel à la Toolbox dans le programme. Quand j'ai essayé d'ajouter des appels similaires sans adresse, aux headers et que je les ai appelés dans mon programme, j'ai obtenu le même résultat - un plantage.
J'ai ensuite pensé que l'astuce serait peut-être de placer les librairies correspondantes dans le dossier Extensions, ou éventuellement dans le même dossier que le compilateur, mais cela ne m'a été d'aucun secours.
Alors, si vous savez ce qui est requis, ou si vous savez comment faire fonctionner le programme de test de la librairie Sprockets, voudriez-vous l'expliquer, s'il vous plaît.
[R]:  Voilà le problème avec le C et MacOS. À un certain moment, tout le monde a pensé que ce serait une idée géniale d'utiliser les shared libraries pour tout, au lieu des adresses a-trap. L'avènement du PowerPC a nécessité ce changement et les divers headers sont quelque peu "panachés" maintenant.
En tout premier lieu. Si un appel n'a pas de trap (piège) c'est qu'il est propre au PowerPC uniquement. Une compilation 68K mourra d'une mort atroce. Donc, ne faites pas ça (Il y a une version 68k de cfm que l'instruction LIBRARY utilise mais je sais pas si FB l'utilise effectivement) La chose importante ensuite est que vous devez trouver dans quelle Shared Library les appels sont définis. Pour l'exemple DrawSprocket vous avez besoin des fichiers DrawSprocketLib et InsputSprocketLib, qui doivent être localisés soit a), dans le dossier de l'application, ou b) dans le dossier Extensions.
Notez bien que l'ajout d'une librairie dans votre dossier Extensions ne requiert pas un redémarrage de la machine. Spécificité :-)
Bien-sûr, je parie que vous vous demandez quel header fait référence à quelle librairie. Eh bien, c'est ainsi que les programmeurs C vivent. Les fichiers headers C qu'un programmeur C inclut résoudront ce problème avec les shared librairies qui ont été chargées jusqu'à ce point. C'est un peu comme GetResource qui passe en revue tous les fichiers de ressources ouverts; un header C trouvera éventuellement la shared library qui dispose d'un appel donné. Je ne suis pas sûr de savoir comment CodeWarrior réussit ce tour de passe-passe, mais c'est une astuce élégante. Mais un programmeur C doit toujours inclure la librairie.
Les raisons pour lesquelles votre code peut avoir planté : les librairies DrawSprocket ou InputSprocket sont manquantes ou elles sont dans un mauvais endroit, ou vous avez essayé d'utiliser ces librairies sur une machine 68K ou lors d'une compilation 68K sur une machine PPC - Seul Andy peut dire si cela a des chances de marcher. C'est possible. Essayez de glisser le fichier DrawSprocketLib dans votre dossier de projet pour vous assurer que la librairie peut être trouvée.
Les problèmes peuvent survenir lorsqu'une bibliothèque indépendante auparavant a été intégrée par la suite dans le système lui-même. Le dossier système compte néanmoins comme étant un des maillons de la chaîne des fragments de code de la même manière que des ressources dans le système sont accessibles à vos applications, ainsi certains appels dans les headers C aboutissent en fin de compte dans le système. Pour FB, le problème est que nous devons *indiquer* la bibliothèque partagée qui doit recevoir les appels que nous définissons, tandis que les programmeurs C doivent trouver d'une manière ou d'une autre la bibliothèque et la déposer dans leur gestionnaire de projet et le compilateur liera les prototypes vers les symboles correspondants.

[haut de la page]

N'ESSAYEZ PAS ÇA À LA MAISON

[Q]:  Si vous essayez l'exemple ci-dessous, il changera la police système du Finder et tout ce qui va avec! Il semble que ce soit dû à l'utilisation de la commande "TEXT" lorsqu'aucune fenêtre n'est ouverte. Notez que cela n'arrive qu'avec FB^3, puisque FBII vous protège de telle stupidité. Le deuxième exemple corrige le problème, comme ça vous pourrez vous remettre au travail.
'------- Coupez ici pour l'Exemple Un --------
OUTPUT FILE "Changer Police Système"
DIM gFontNum%
CALL GETFNUM("Chicago", gFontNum%)
TEXT gFontNum%, 10, _outlineBit%
WINDOW 1
END
'------- Coupez ici pour l'Exemple Deux --------
OUTPUT FILE "Corriger Police Système"
DIM gFontNum%
CALL GETFNUM("Chicago", gFontNum%)
TEXT gFontNum%, 12, 0,0
WINDOW 1
END
[R]:  Merci. Et je dirais même plus... n'utilisez pas la commande TEXT avant d'avoir une fenêtre ouverte!

[haut de la page]

PALETTES

[Q]:  Si une fenêtre est déjà ouverte et que vous ouvrez une autre fenêtre avec l'attribut _keepinback, les champs d'édition de la fenêtre qui était déjà ouverte sont désactivés. La fenêtre modale fonctionne correctement et ce n'est pas une palette.
[R]:  Dans FBII, il n'y a pas ce qu'on appelle réellement des palettes. Il y a des fenêtres (d'arrière-plan) keepinback et les autres fenêtres. Lorsqu'une fenêtre keepinback est présente, les autres fenêtres sont des palettes. Quand il n'y a pas de fenêtre keepinback les autres fenêtres sont juste des fenêtres.
Est-ce qu'une fenêtre modale est une palette? Oui, si une fenêtre document keepinback est présente. Non, s'il n'y a pas de fenêtre document avec l'attribut keepinback

[haut de la page]

DÉCLARATIONS

[Q]:  Dans une structure "vrai record", j'ai ceci :
DIM to as unsigned Long
Cela fonction bien même si
to est un mot-clé. Pourtant quand j'ai ceci :
DIM Error as Unsigned Long
ce que FB n'a pas l'air d'apprécier; je reçois un message d'erreur "de redéclaration". Par curiosité, peut-on me dire pourquoi certains mots-clés ne posent pas de problème et d'autres oui. Les vrais records me laissent utiliser à peu prêt tout ce qui se fait sous le soleil à l'exception de ce nom de champ.
[R]:  DEFINE échoue si le type de variable est déjà défini. Un mot-clé et un type de variable sont deux choses réellement différentes.

[haut de la page]

ASSEMBLEUR

[Q]:  Je ne suis pas très au point avec l'utilisation de BEGINASSEM et ENDASSEM. Le morceau de code 68K suivant [... coupé...] fonctionne correctement avec FBII ou avec FB3 en compilation 68K. Pourtant, je n'ai pas pu le faire fonctionner dans des compilations Fat ou PPC, même si je l'intègre dans une structure BEGINASSEM cpu68K et ENDASSEM.
[R]:  Désolé. Pas d'assembleur 68k dans les compilations PPC.

[Q]: J'ai des portions en assembleur 68K dans mon application FBII; Dois-je les traduire en assembleur PPC?
[R]:
En règle générale, la réponse est NON! Et voilà pourquoi.
Ce code était en assembleur 68K pour des raisons de rapidité d'exécution. Mais, n'oubliez pas que le code généré par FB^3 est rapide. Dans certains cas, il va plusieurs centaines de fois plus vite qu'avec FBII! Mais FB^3 c'est plus qu'une bête de course, il s'agit aussi d'un tout autre animal. Et ce n'est pas dévoiler un secret que de dire qu'Andy Gariepy - l'ingénieur de FB 'par excellence' - a déclaré que FB^3 était conçu pour être indépendant de la plate-forme. (Il n'a fait aucune promesse cependant...) Cela signifie alors que vous devriez essayer de garder votre code dans la syntaxe la plus pure possible de FB. Pourquoi? Supposons qu'un jour une version de Mac OS voie le jour sur une machine Intel (je ne vois pas qui pourrait Bien vouloir cela, mais puisque nous sommes au royaume des suppositions, oubliez vos croyances et continuer à lire). Bon, si Mac OS se retrouve sur une machine Intel, votre application cessera de fonctionner à cause du code PPC.
Si votre code est en FB cependant, vous n'aurez qu'à procéder à le moteur FB pour cette machine et à changer probablement quelques fichiers headers que Andy vous aura envoyés... et vous serez l'un des premiers à faire tourner une application sur une machine MacIntel!

[Q]: Y-a-t'il des cas où j'aurais besoin de coder en assembleur PPC?
[R]: Il serait présomptueux de répondre 'Non'! Je peux imaginer au moins 2 cas: would be foolhardy to say 'No'! I can imagine at least 2 cases: traitement ultra-rapide des graphiques à l'écran - même si Apple, sous la pression de programmeurs de jeux, a fini par fournir des routines super rapides pour contourner les goulets d'étranglement de QuickDraw. Ces choses sont enfouies dans les librairies GameSprockets. Un autre cas pourrait être le traitement des nombres dans le style de Photoshop, mais dans ce cas vous ne parleriez pas de traitement des nombres en assembleur, mais plus d'une "librairie de calculs pour le G4 et AltiVec", et d'une "librairie de calculs pour le PPC 604"... parce que que si vous êtes vraiment concerné par la vitesse d'exécution, vous aurez besoin d'optimiser pour toutes les générations des différents processeurs.
Tous ces arguments vont à l'encontre de l'utilisation de l'assembleur PPC avec FB^3, mais n'hésitez pas à essayer. Et n'oubliez pas de partager vos expériences avec les aux autres.

[Q]: Salut à tous. J'ai un programme d'acquisition de données qui communique avec les cartes A/D de National Instruments. Cela se fait à travers 20 ou 30 petites fonctions fournies par Nat. Instruments pour FBII. Elles utilisent toutes la syntaxe CALL F&(...) que FB^3 ne semble pas apprécier. En voici un exemple :

LOCAL MODE
DIM f&
LOCAL FN Lab_ISCANCheck(deviceNumber&, bdstatus&,¬
      retrieved&, scanOrder&)
  f& = [FN libraryResource&] + _LabISCANCheck
  ` clr.l -(a7)
  CALL f&(deviceNumber&, bdstatus&, retrieved&, ¬
scanOrder&)
  ` move.l (a7)+,d0
END FN

[R]: Andy a répondu:
LOCAL MODE
DIM f&, longVal&
LOCAL FN Lab_ISCANCheck( devNum&, bdstatus&, ¬
retrieved&, scanOrder&)
 _xParams=_Pascalstk_rtnLong_p1long_p2Long_p3Long_P4Long
 f& = [FN libraryResource&] + _LabISCANCheck
 longVal& = universalfn( f&, _xParams, devNum&, ¬
             bdstatus&, retrieved&, scanOrder&)
END FN = LongVal&

Non testé mais devrait fonctionner en général pour PPC & 68K.

[Q]: J'utilise le code suivant - comment dois-je le traduire pour FB^3?
'-------------------------------------------------------
LOCAL MODE
LOCAL FN shiftColor(@cPtr&,amt%)
' A0 = pointer to current element
'      of the record being processed
' D0 = loop counter (starts at 2, goes to zero)
' D1 = temporary value of the color being mangled
' D2 = amount to shift the color
`  move.l ^cPtr&,A0
`  beq exit            ; nil pointer check
`  move.w ^amt%,D2     ; set up remaining registers
`  ext.l D2
`  moveq.w #2,D0       ; init loop count
`startshiftloop
`  clr.l D1
`  move.w (A0),D1
`  add.l D2,D1         ; shift color value by amount
`testlowerlimit
`  cmpi.l #0,D1        ; ck if d1 = 0
`  bge testupperlimit  ; if the value OK, skip next check
`  move.l #0,D1        ; reset it to zero
`testupperlimit
`  cmpi.l #$FFFF,D1    ; compare value to FFFF
`  ble endshiftloop    ; if the value OK, skip next step
`  move.l #$0000FFFF,D1; set it to max
`endshiftloop
` move.w D1,(A0)+      ; copy final value into dest
` dbra D0,startshiftloop
`exit
END FN

[A]: Andy a répondu:

LOCAL MODE
DIM temp&,i
LOCAL FN shiftColor( @cPtr&, amt%)
   FOR i = 0 TO 3
    temp& = (cPtr&.nil% AND 0xFFFF) + amt%
    IF temp& < 0 THEN temp& = 0
    IF temp& > 65535 THEN temp& = 65535
    cPtr&.nil% = temp&
    cPtr& = cPtr&+2
  NEXT
END FN
avec FB3 ce code devrait être rapide... 

[haut de la page]

ANIMATION BOITEUSE

[Q]:  Coller ce programme FB^3 et exécutez le (à l'aide du runtime FBII) et jouez quelques secondes avec.
'-----The Flasher-----
dim myrect as rect
menu 1,0,1,"Fichier"
menu 1,1,1,"Quitter/Q"
window 1,"Cliquez ou bougez",,_docNoGrow
window 2,"Bougez ou cliquez",,_docNoGrow
call setrect(myRect,0,0,550,450)
do
 window output (1)
 call paintrect(myRect)
 window output (2)
 call paintrect(myRect)
 handleevents
 delay 100
until 0 // cmd-. ou cmd-Q termine
'----------------------

Ça ne vous rappelle rien? À mois, ça me rappelle des heures de combat avec mes programmes d'animation, à essayez d'éradiquer ce comportement. Le phénomène a été discuté en détails dans la liste FB il ya des lustres. L'une des solutions données était un patch ingénieux du runtime de FBII. Je me rappelle que Staz a annoncé non sans une fierté légitime qu'avec FB^3 on pourrait examiner et modifier le runtime.
[A]:
  La zone de contenu doit être effacée ou bien vous finirez avec des gribouillis à l'écran après des redimensionnements et des zooms. Si vous changez le type de fenêtre en _docZoom et que vous placez le rectangle à 10,10, vous verrez tout de suite l'un des problèmes.
Une façon de corriger cela est d'appeler la procédure VALIDRECT après l'appel à PAINTRECT. Mais [...] dessiner dans une fenêtre à un autre moment que lors d'une mise à jour ne fonctionnera simplement pas.

[Q]:  En jetant un œil sur le Runtime Lite, j'ai découver que la cause résidait dans la fonction FN FBWindowUpdate dans le fichier "Rntm FBII.Incl". FN FBWindowUpdate traite les événements _wndRefresh, et contient la ligne
EraseRect(#thisPort&+_PortRect)
Si je mets cette ligne en commentaire, sauvegarde le fichier et ré-exécute The Flasher, [...] le problème est réparé.
[A]:
  C'est un comportement standard du Macintosh. Ce n'est pas quelque chose que nous pouvons contrôler.

[Q]:  Alors pourquoi ma fenêtre est-elle effacée après que j'ai dessiné dedans?
[A]:  Vous ne devriez jamais dessiner dans une fenêtre avant d'avoir reçu un événement de mise à jour. Voici une explication sur la façon dont le Mac gère les mises à jour et pourquoi vous ne devriez réagir qu'au moment opportun :
Quand une fenêtre est construite ou ramenée à l'avant plan, le plus souvent une partie de son contenu doit être raffraîchie. Le Window Manager amasse ces zones "abîmées" dans une structure appelée une région de mise àjour (clobbered region ou update region). Vous pouvez obliger un morceau de la fenêtre à être ajouté à cette région en appelant CALL INVALRECT(t), et forcer des morceaux à être retirés de cette région avec CALL VALIDRECT(t).
Quand rien n'occupe plus le Mac, le Window Manager examine s'il n'y a pas des choses à corriger et s'il n'y a pas une région de mise à jour pour votre fenêtre. Il construit un faux événement (_updatEvt) et l'envoie alors sans la file d'attente des événements.
FutureBASIC voit l'événement de mise à jour et appelle BEGINUPDATE. Cela échange la région visible avec la région abîmée. FB efface alors la zone abîmée, redessine tous les contrôles et les champs, puis appelle votre programme pour qu'il puisse dessiner à la suite du message _updatEvt. Quand votre programme reçoit l'événement _updatEvt, vous êtes supposé dessiner le contenu des fenêtres. Quand tout est fini, FB appelle ENDUPDATE pour réinitialiser toutes les régions dans leur état normal.
Rappelez-vous: à chaque fois qu'une fenêtre est construite, le Window Manager envoie automatiquement un événement de mise à jour - sans coup férir. Vous pouvez compter dessus.
Si vous dessinez dans une fenêtre quand elle est construite pour la première fois ou quand un bouton est cliqué ou un article de menu choisi, plutôt qu'en réponse à un événement de mise à jour, la séquence de mise à jour effacera votre travail; et après la mise à jour vous serez en train de regarder une fenêtre vierge.
Dessinez toujours en réponse aux événements de mise à jour.

  © 2000 Pix&Mix  
  Tous droits réservés
INFO  |  ACQUÉRIR |  PLAN  |  RESSOURCES

  FutureBASIC est une marque déposée appartenant à Staz Software, Inc et utilisée avec permission.