Novembre 2024 | Lun | Mar | Mer | Jeu | Ven | Sam | Dim |
---|
| | | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | | Calendrier |
|
|
| Des DLL pour Panoramic ? | |
| | |
Auteur | Message |
---|
jean_debord
Nombre de messages : 1266 Age : 70 Localisation : Limoges Date d'inscription : 21/09/2008
| Sujet: Des DLL pour Panoramic ? Dim 12 Déc 2021 - 9:25 | |
| Je suis en train de modifier FBCroco afin qu'il puisse produire des DLL utilisables par Panoramic. Je profite de l'occasion pour vous demander si les règles d'utilisation des DLL dans Panoramic sont toujours les mêmes, à savoir : - Code:
-
1. La DLL est chargée en mémoire par l'instruction :
dll_on "xxx.dll"
où xxx.dll est le nom de la bibliothèque. Quand la DLL n'est plus nécessaire, la mémoire peut être libérée par l'instruction dll_off
2. La syntaxe d'appel d'une fonction de DLL est de la forme :
result% = dll_calln("DllFunctionName", par1%, ..., parn%)
où n est un entier de 0 à 6 qui représente le nombre de paramètres passés à la fonction. Il y a en fait 7 routines différentes :
dll_call0("DllFunctionName") dll_call1("DllFunctionName", par1%) dll_call2("DllFunctionName", par1%, par2%) ..........................................
Le premier paramètre est une chaîne contenant le nom de la fonction appelée. Il est suivi par les paramètres de la fonction, qui sont théoriquement de type entier mais peuvent être des adresses, ce qui permet de passer des nombres réels ou des chaînes de caractères (voir paragraphe 3).
Notez aussi que :
* PANORAMIC ne peut appeler que des fonctions dans une DLL, pas de sous-programmes.
* Toute fonction appelée par dll_call doit retourner une valeur entière.
3. Les paramètres entiers peuvent être passés par valeur ou par référence. Dans ce dernier cas, on utilise la fonction adr() de PANORAMIC.
4. Les nombres réels sont obligatoirement passés par référence. Il en est de même pour les chaînes de caractères. Dans ce dernier cas cependant, le paramètre de la fonction appelée doit être un pointeur sur une chaîne à zéro terminal.
5. Les chaînes de caractères passées aux fonctions de la DLL doivent être dimensionnées à une longueur suffisante dans le programme appelant. C'est particulièrement important si la chaîne est modifiée par la DLL, car alors sa longueur peut varier.
6. Au stade actuel du développement de PANORAMIC, aucun tableau ne peut être passé, ni par valeur ni par référence avec adr().
7. L'appel des fonctions doit se faire selon la convention stdcall.
8. Le nom de la fonction appelée ("DllFunctionName") doit respecter les majuscules et les minuscules.
Je sais qu'il y a un nouveau mot-clé LIBRARY mais je ne le trouve pas dans ma version de Panoramic (0.9.29i11) | |
| | | Minibug
Nombre de messages : 4570 Age : 58 Localisation : Vienne (86) Date d'inscription : 09/02/2012
| Sujet: Re: Des DLL pour Panoramic ? Dim 12 Déc 2021 - 11:33 | |
| Bonjour Jean, En voilà une bonne idée. Je pense que Jack ou Klaus pourront te renseigner... Concernant LIBRARY voici ce que disait Jack sur ce fil de discussion. Bonne journée et à bientôt. | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Des DLL pour Panoramic ? Dim 12 Déc 2021 - 17:26 | |
| Dans les conventions d'appel d'une DLL, tout est correct, sauf: - Citation :
- 6. Au stade actuel du développement de PANORAMIC, aucun tableau ne peut être passé, ni par valeur ni par référence avec adr().
En réalité, tu peux faire: - Code:
-
dim entiers%(10), flottants(15), res% ... res% = dll_call2("TestDesTableaux",adr(entier%),adr(flottant)) La fonction TestDesTableaux recevra alors les adresses de premiers éléments des deux tableaux, à savoir l'adresse des données de entiers%(0) et flottant(0). Et les autres éléments sont rangés juste aprèsn sans parasites intermédiaire et sans coupures. On peut même faire cela avec un tableau à 2 ou plusieurs dimensions. Cependant, seule l'adresse du premier élément est passée: - Code:
-
dim entiers2%(5,20), res% ... res% = dll_call1("AutreTest",adr(entiers2%))
c'est l'adresse de entiers%(0,0) qui et passée. On ne peut pas passer l'adresse d'un tableau de chaînes de caractères. Et adr(s$) donne l'adresse d'une variable STRING en Delphi. A cette adresse, on trouve un pointeur vers le premier caractère des données. Avec l'offset -2, on a la longueur de la chaîne (peu utile car terminée par 0) et avec -4, on a le référence count. Pour mapart, j'utilise les routines auxiliaires suivantes: - Code:
-
// fonction compatible avec la version compilée de PANORAMIC // par = identifiant de destination soit ADR(s$) soit HANDLE(memo%) // Cette fonction prend des données string à partit d'un sgtring Panoramic, // mais aussi le contenu d'un MEMO ou d'un LIST dont on a passé le handle en paramètre, // et elle gère les particularités de Panoramic compilé. function GetStringFromPanoramic(par: integer): string; var n, Len, cnt, i: integer; memo: TMemo; lb: TListBox; s1, s2: string; control: TWinControl; pb: pbyte; pi: pinteger;
function GetClassName(Handle: THandle): String; var Buffer: array[0..MAX_PATH] of Char; begin Windows.GetClassName(Handle, @Buffer, MAX_PATH); Result := String(Buffer); end;
begin result := ''; if par=0 then exit; try memo := TMemo(par); if memo.ClassName='TMemo' then begin result := memo.Text; exit; end; except end;
try if GetClassName(par)='TMemo' then begin
Len := SendMessage(par, WM_GETTEXTLENGTH, 0, 0); if Len>0 then begin SetLength(s1, Len+1); Len := SendMessage(par, WM_GETTEXT, Len+1, LPARAM(PChar(s1))); delay(100); SetLength(s1, Len); end;
result := Trim(s1); exit; end; except end;
try if GetClassName(par)='TListBox' then begin
cnt := SendMessage(par, LB_GETCOUNT, 0, 0); s1 := ''; if cnt<>LB_ERR then begin for i:=0 to cnt-1 do begin s2 := ''; Len := SendMessage(par, LB_GETTEXTLEN, i, 0); if Len>0 then begin SetLength(s2, Len+1); SendMessage(par, LB_GETTEXT, i, LPARAM(PChar(s2))); delay(100); s1 := s1 + Trim(s2) + #13#10; end; end; end;
result := Trim(s1); exit; end; except end;
if PCompiledMode then begin cnt := 0; {$if StringParameterMethod=1} pb := pbyte(par); // méthode V1 (Jack): ADR(s$) pointe vers l'adresse du premier caractère {$else} if pinteger(par)^<>0 then begin pb := pbyte(pinteger(par)^); // méthode V2 (Jack): ADR(s$) pointe vers un mot contenant l'adresse du premier caractère {$ifend} while pb^<>0 do begin inc(pb); inc(cnt); end; end; SetLength(result,cnt); if cnt>0 then begin pb := pbyte(pinteger(par)^); for i:=1 to cnt do begin result[i] := chr(pb^); inc(pb); end; end; end else begin result := pstring(par)^; end; end;
// procédure compatible avec la version compilée de PANORAMIC // s = string (éventuellement multi-ligne) à envoyer à Panoramic // par = identifiant de destination soit ADR(s$) soit HANDLE(memo%) soit handle(list%) procedure CopyStringToPanoramic(s: string; par: integer); var p1, p2: pchar; n, p: integer; memo: TMemo; s1, s2: string; control: TWinControl; pi, po: pbyte; zero: byte;
function GetClassName(Handle: THandle): String; var Buffer: array[0..MAX_PATH] of Char; begin Windows.GetClassName(Handle, @Buffer, MAX_PATH); Result := String(Buffer); end;
begin if par=0 then exit; try memo := TMemo(par); if memo.ClassName='TMemo' then begin s1 := s; memo.Text := trim(s1+' '); exit; end; except end;
try if GetClassName(par)='TMemo' then begin s1 := s; SendMessage(par,WM_SETTEXT,0,integer(pchar(s1))); exit; end; except end;
try if GetClassName(par)='TListBox' then begin SendMessage(par,LB_RESETCONTENT,0,0); s1 := s + #13#10; while s1<>'' do begin p := pos(#13#10,s1); if p>0 then begin s2 := LeftStr(s1,p-1); s1 := MidStr(s1,p+2,Length(s1)); SendMessage(par,LB_ADDSTRING,0,integer(pchar(s2))); end; end; if s1<>'' then SendMessage(par,LB_ADDSTRING,0,integer(pchar(s1))); exit; end; except end;
zero := 0; p1 := @zero; n := length(s); if n>0 then p1 := @s[1]; if PCompiledMode then begin // mode compilé pi := pbyte(@s[1]); {$if StringParameterMethod=1} po := pbyte(par); // méthode V1 (Jack): ADR(s$) pointe vers l'adresse du premier caractère {$else} po := pbyte(pinteger(par)^); // méthode V2 (Jack): ADR(s$) pointe vers un mot contenant l'adresse du premier caractère {$ifend} while po^<>0 do begin if pi^<>0 then begin po^ := pi^; inc(po); inc(pi); end else begin po^ := 32; inc(po); end; end; end else begin //mode interprété if n>0 then p1 := pchar(@s[1]); p2 := pchar(pinteger(par)^); while p2^<>#0 do begin if n>0 then begin if p1<>#0 then p2^ := p1^ else dec(p2); end else begin p2^ := #32; end; inc(p1); inc(p2); dec(n); end; end; end;
// Cette procédure écrit une chaîne de caractères dans un sgtring Panoramic en le remplaçant partiellement procedure CopyStringOverPanoramicString(sIn: string; offs,sOut: integer); var cnt: integer; pi, po: pbyte; begin
if PCompiledMode then begin cnt := 0; pi := pbyte(@sIn[1]); {$if StringParameterMethod=1} po := pbyte(sOut+offs); {$else} if sIn<>'' then begin po := pbyte(pinteger(sOut)^+offs); {$ifend} while (pi^<>0) and (po^<>0) do begin po^ := pi^; inc(pi); inc(po); end; end; end else begin pi := pbyte(@sIn[1]); po := pbyte(pinteger(sOut)^+offs); while (pi^<>0) and (po^<>0) do begin po^ := pi^; inc(pi); inc(po); end; end;
end;
| |
| | | jean_debord
Nombre de messages : 1266 Age : 70 Localisation : Limoges Date d'inscription : 21/09/2008
| Sujet: Re: Des DLL pour Panoramic ? Lun 13 Déc 2021 - 10:11 | |
| Merci pour vos réponses ! Je vais tester le passage des tableaux. En attendant, voici un exemple avec les chaines de caractères. Code de la DLL en FBCroco : - Code:
-
function strcmp% (a$, b$) ' Comparaison de 2 chaines de caracteres if a = b then return 0 elseif a > b then return 1 else return -1 end_if end_function
Résultat de la traduction en FreeBASIC ( avec la future version de FBCroco ! ) - Code:
-
extern "Windows-MS"
function strcmp(byref p_a as zstring ptr, byref p_b as zstring ptr) as long export dim as string a = *p_a dim as string b = *p_b
' Comparaison de 2 chaines de caracteres if a = b then return 0 elseif a > b then return 1 else return -1 end if
*p_a = a *p_b = b end function
La DLL compilée ainsi qu'un programme test en Panoramic sont disponibles sur mon WebDav (dossier FBCroco, fichier strcmp.zip) | |
| | | jean_debord
Nombre de messages : 1266 Age : 70 Localisation : Limoges Date d'inscription : 21/09/2008
| Sujet: Re: Des DLL pour Panoramic ? Mar 14 Déc 2021 - 16:57 | |
| Exemple avec un tableau d'entiers : Code de la DLL en FreeBASIC : - Code:
-
extern "Windows-MS"
function init_array (p as long ptr, byval n as long) as long export
for i as long = 0 to n p[i] = i next i
return n + 1 ' Nb d'elements end function
end extern
Programme d'appel en Panoramic : - Code:
-
dll_on "C:\FBCroco\exemples\lib\panoramic\array.dll"
dim a%(10), res%, i%
res% = dll_call2("init_array", adr(a%), 10)
for i% = 0 to 10 print a%(i%) next i%
print : print res%, " elements"
end
On passe un pointeur, d'où le changement de notation en FreeBASIC : p[i] au lieu de p(i) Si l'on veut garder la notation habituelle, soit p(i), dans le code FBCroco, il faudra prévoir un mécanisme de traduction. | |
| | | papydall
Nombre de messages : 7017 Age : 74 Localisation : Moknine (Tunisie) Entre la chaise et le clavier Date d'inscription : 03/03/2012
| Sujet: Re: Des DLL pour Panoramic ? Mer 15 Déc 2021 - 2:40 | |
| Merci Jean et bon courage pour la suite!
| |
| | | jean_debord
Nombre de messages : 1266 Age : 70 Localisation : Limoges Date d'inscription : 21/09/2008
| Sujet: Re: Des DLL pour Panoramic ? Jeu 16 Déc 2021 - 16:44 | |
| Merci papydall Du courage, il m'en faut car je n'arrive pas à faire la même chose avec un tableau à deux dimensions. Code de la DLL : - Code:
-
extern "Windows-MS"
function init_array (p as long ptr, byval n1 as long, byval n2 as long) as long export
for i as long = 0 to (n1 + 1) * (n2 + 1) - 1 p[i] = i next i
return (n1 + 1) * (n2 + 1) ' Nb d'elements end function
end extern
Programme d'appel en Panoramic : - Code:
-
dll_on "C:\FBCroco\exemples\lib\panoramic\array.dll"
dim a%(3,4), res%, i%, j% res% = dll_call3("init_array", adr(a%), 3, 4)
for i% = 0 to 3 for j% = 0 to 4 print a%(i%,j%) next j% print next i% print : print res%, " elements"
end
Seule la première ligne du tableau a% est initialisée. | |
| | | Marc
Nombre de messages : 2466 Age : 63 Localisation : TOURS (37) Date d'inscription : 17/03/2014
| Sujet: Re: Des DLL pour Panoramic ? Jeu 16 Déc 2021 - 17:24 | |
| Bonjour Jean,
Lorsque j’avais fait des essais, pour un tableau d’entiers (% en Panoramic), La première ligne du tableau était à l’adresse adr(a%) La deuxième ligne à l’adresse adr(a% + 880) La troisième ligne à l’adresse adr(a%+1760) Etc
Avec la version 0.9.29i9 de Panoramic.
| |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Des DLL pour Panoramic ? Jeu 16 Déc 2021 - 17:28 | |
| - Citation :
- Du courage, il m'en faut car je n'arrive pas à faire la même chose avec un tableau à deux dimensions.
Ben, c'est normal... Relis les contraintes que j'ai énoncé dans ma première réponse à ta question innitiale. On ne peut en aucun cas transmettre un tableau en deux dimensions. Tout simplement parce que l'allocation de mémoire pour des différente colonnes ne se suivent pas. Chaque colonne est mémorisée à part, de façon non prévisible. Pire; la position des données en mémoire peut changer dynamiquement, ainsi que cellle d'une variable simple dont on a âssé l'adresse ! Il est donc impossible de mémoriser une adresse d'une variable Panoramic dans une variable interne à la DLL et espérer qu'ultérieurement, les données se trouvent au même endroit. Violation de mémoire assurée. | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Des DLL pour Panoramic ? Jeu 16 Déc 2021 - 17:38 | |
| @Marc: C'est un effet aléatoire. Tout dépend, d'une part de la version de Panoramic, et d'autre part, de l'affectation de valeurs à ds variables de type string dont la déclaration se situe "devant" la déclaration du tableau. Le gestionnaire de mémoire de Delphi (langage dans lequel Panoramic est réalisé) réaffecte ses zones mémoire à sa guise, et les adresses virtuelles changent donc, même si les données n'ont pas changé. Si, en plus, on utilise la possibilité de redimensionner un tableau en Panoramic, alors là, tu imagines la salade...
Non. Le principe et simple et tient en 2 règles:
1. seule les variables simples de type entier, flottant ou string peuvent être passées par ADR(), ainsi que les tableaux à une seule dimension de type entier ou flottant. Techniquement, on peut aussi passer un tableau à une seule dimension de type string, mais l'accès aux données est nettement plus complique, car ce qui est mémorisé "en continu", ce sont les "descripteurs" des strings représentant les cellules et non les cellules elles-même.
2. l'adresse d'une variable n'est valable que pendant l'exécution de la fonction DLL appelée. Il ne sert à rien de vouloir mémoriser une telle adresse dans une variable persistante (globale) à l'intérieur de la DLL pour la réutiliser plus tard - ces adresses virtuelles peuvent changer de fa)on imprévisible suite à des actions du gestionnaire de mamoire de Delphi.
Tout non-respect de ces deux règles conduit, au mieux, à des données fantaisistes, mais plus probablement à des violation de mémoire, même en lecture. Je me suis assez cassé les dents sur ces problèmes pour être sûr de ce que j'avance. | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Des DLL pour Panoramic ? Jeu 16 Déc 2021 - 18:15 | |
| Complément d'information:
Ce qui ne change pas, ce sont les handles des objets. Si je dois mémoriser de façon persistante un lien avec des données de Panoramic à l'intérieur d'une DLL, j'utilise le handle d'un objet EDIT, MEMI ou LIST. Le handle de ces objets ne change pas (à condition, bien entendu, de ne pas faire DELETE sur ces objets...). Dans la DLL, je peux librement récupérer le contenu de ces objets et je peux le modifier ou remplacer, dans aucun problème d'allocation de mémoire.
Pourquoi ? C'est parce que Windows se charge dans ce cas des allocations de mémoire, pas Delphi. | |
| | | Marc
Nombre de messages : 2466 Age : 63 Localisation : TOURS (37) Date d'inscription : 17/03/2014
| Sujet: Re: Des DLL pour Panoramic ? Ven 17 Déc 2021 - 1:09 | |
| Merci Klaus pour ces informations. | |
| | | Minibug
Nombre de messages : 4570 Age : 58 Localisation : Vienne (86) Date d'inscription : 09/02/2012
| Sujet: Re: Des DLL pour Panoramic ? Ven 17 Déc 2021 - 8:11 | |
| Ah oui effectivement cela n'est pas aussi simple qu'il y parait ! Bon courage pour la suite Jean... | |
| | | jean_debord
Nombre de messages : 1266 Age : 70 Localisation : Limoges Date d'inscription : 21/09/2008
| Sujet: Re: Des DLL pour Panoramic ? Ven 17 Déc 2021 - 8:27 | |
| - Klaus a écrit:
1. seule les variables simples de type entier, flottant ou string peuvent être passées par ADR(), ainsi que les tableaux à une seule dimension de type entier ou flottant.
Merci Klaus. C'est parfaitement clair. Je vais dans un premier temps m'en tenir aux variables simples. Ensuite j'ajouterai peut-être les tableaux numériques à 1 dimension. | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Des DLL pour Panoramic ? Ven 17 Déc 2021 - 10:23 | |
| Voici coment lire et écrire un tableau d'entiers ou de flottants: - Code:
-
// copier un tableau de type integer de Panoramic dans un tableau dynamique Delphi dans la DLL function GetIntegerArrayFromPanoramic(aIntegerArray: pinteger; nDimension: integer): integer; stdcall; export; var IntegerArray: array of Integer; i: integer; pi: pinteger; begin result := -1; try if aIntegerArray=nil then exit; // il faut au moins une adresse if nDimension<0 then exit; // il faut une dimenion Panoramic valide SetLength(IntegerArray,nDimension+1); // affecter la mémoire pi := aIntegerArray; // boucle de lecture for i:=0 to nDimension do begin IntegerArray[i] := pi^; // ccpier un élément inc(pi); // ajuster le pointeur showmessage(format('%d: %d',[i,IntegerArray[i]])); // juste pour montrer le résultat - ligne à supprimer ! end; result := 0; except end; end; exports GetIntegerArrayFromPanoramic;
// copier un tableau de type integer d'un tableau dynamique Delphi dans la DLL vers un tableau dans Panoramic function SetIntegerArrayFromPanoramic(aIntegerArray: pinteger; nDimension: integer): integer; stdcall; export; var IntegerArray: array of Integer; i: integer; pi: pinteger; begin result := -1; try if aIntegerArray=nil then exit; // il faut au moins une adresse if nDimension<0 then exit; // il faut une dimenion Panoramic valide
// les 2 lignes suivantes sont là pour "simuler" un tableau existant dans la DLL... SetLength(IntegerArray,nDimension+1); // affecter la mémoire for i:=0 to nDimension do IntegerArray[i] := i*2;
if nDimension>=Length(IntegerArray) then exit; // trop de données demandées ? pi := aIntegerArray; // boucle d'écriture for i:=0 to nDimension do begin pi^ := IntegerArray[i]; // ccpier un élément inc(pi); // ajuster le pointeur showmessage(format('%d: %d',[i,IntegerArray[i]])); // juste pour montrer le résultat - ligne à supprimer ! end; result := 0; except end; end; exports SetIntegerArrayFromPanoramic;
// copier un tableau de type float de Panoramic dans un tableau dynamique Delphi dans la DLL function GetFloatArrayFromPanoramic(aFloatArray: pfloat; nDimension: integer): integer; stdcall; export; var FloatArray: array of double; i: integer; pf: pfloat; begin result := -1; try if aFloatArray=nil then exit; // il faut au moins une adresse if nDimension<0 then exit; // il faut une dimenion Panoramic valide SetLength(FloatArray,nDimension+1); // affecter la mémoire pf := aFloatArray; // boucle de lecture for i:=0 to nDimension do begin FloatArray[i] := pf^; // ccpier un élément inc(pf); // ajuster le pointeur showmessage(format('%d: %f',[i,FloatArray[i]])); // juste pour montrer le résultat - ligne à supprimer ! end; result := 0; except end; end; exports GetFloatArrayFromPanoramic;
// copier un tableau de type float d'un tableau dynamique Delphi dans la DLL vers un tableau dans Panoramic function SetFloatArrayFromPanoramic(aFloatArray: pfloat; nDimension: integer): integer; stdcall; export; var FloatArray: array of double; i: integer; pf: pfloat; begin result := -1; try if aFloatArray=nil then exit; // il faut au moins une adresse if nDimension<0 then exit; // il faut une dimenion Panoramic valide
// les 2 lignes suivantes sont là pour "simuler" un tableau existant dans la DLL... SetLength(FloatArray,nDimension+1); // affecter la mémoire for i:=0 to nDimension do FloatArray[i] := i*2.002;
if nDimension>=Length(FloatArray) then exit; // trop de données demandées ? pf := aFloatArray; // boucle de lecture for i:=0 to nDimension do begin pf^ := FloatArray[i]; // ccpier un élément inc(pf); // ajuster le pointeur showmessage(format('%d: %f',[i,FloatArray[i]])); // juste pour montrer le résultat - ligne à supprimer ! end; result := 0; except end; end; exports SetFloatArrayFromPanoramic; Note importante:Le code Delphi d'une DLL n'a AUCUN moyen de détecter la dimension d'un tableau Panioramic passé en paramètre. Il faut donc l'indiquer à la fonction sous forme d'un paramètre supplémentaire. On peut bien sûr tenter de parcourir la table des symboles de Panoramic pour trouver cette information. Problème: la structure de cette table des symboles est susceptible de varier selon les versions de PAnoramic. Ceci est donc à évirer. Ceci dit, il y a moyen d'y arriver pour une version donnée de Panormic. Voici une fonction qui m'a servi à localiser le début de la table de symboles de Panoramic: - Code:
-
// trouver et mémoriser l'adresse de début de la table de symboles Panoramic function LocalizePanoramicSymbolTable(a: integer):integer; stdcall; export; { Pour tomber sur le début d'une entrée de table de symbole (pointeur vers le nom), il faut calculer adr(variable)-delta avec delta=12 pour un entier et delta=24 pour un flottant. Donc, cette fonction suppose être appelée avec adr(number_click). Cette variable est toujours définie et est de type flottant. Ensuite, chaque entrée dans la table de synboles a une longueur de 80 ou 4*26 caractères (50 hexa).
Pour les tableaux, on sait les éléments suivants; - dim t%(3) t% n'est pas dans la table de symbole de base - dim t%(3) adr(t%) pointe vers la liste des éléments t%(0),t%(1),t%(2),t%(3)
Une entrée dans la table de symboles Panoramic a la structure suivante: mot offset utilisation ---------------------------------------------------------------------------- 0 0 adresse du nom sous forme de chaîne de caractères (majuscules) 1 4 type de variable (1...9) 2 8 3 12 valeur entière si type=1 4 16 5 20 6 24 valeur flottante si type=3 (premier mot) 7 28 valeur flottante si type=3 (deuxième mot) 8 32 dimension 1 si type=4 ou type=7: nombre de segments utilisés de ce type + 1 9 36 dimension 1 si type=5 ou type=8: nombre de segments utilisés de ce type + 1 10 40 dimension 1 si type=6 ou type=9: nombre de segments utilisés de ce type + 1 11 44 dimension 1 si type=4: nombre de segments utilisés de ce type + 1 12 48 dimension 1 si type=8: nombre de segments utilisés de ce type + 1 13 52 dimension 1 si type=9: nombre de segments utilisés de ce type + 1 14 56 dimension 1 si type=4 ou type=7 15 60 dimension 1 si type=5 ou type=8 16 64 dimension 1 si type=6 ou type=9 17 68 dimension 2 si type=7 18 72 dimension 2 si type=8 19 76 dimension 2 si type=9
Types: 1 entier simple 2 flottant simple 3 chaîne de caractères simple 4 tableau d'entiers en une dimension 5 tableau de flottants en une dimension 6 tableau de chaînes de caractères en une dimension 7 tableau d'entiers en deux dimensions 8 tableau de flottants en deux dimensions 9 tableau de chaînes de caractères en deux dimensions
} var pi1: pinteger; begin pi1 := pinteger(a-24); while pi1^<>0 do pi1 := pinteger(integer(pi1)-4*PanoramicSymbolTableEntrySize); pi1 := pinteger(integer(pi1)+4*PanoramicSymbolTableEntrySize); PanoramicSymbolTable := pi1; result := integer(PanoramicSymbolTable); {$ifdef debugit} showmessage('LocalizePanoramicSymbolTable: PanoramicSymbolTable='+inttostr(result)+' '+inttohex(result,8)); {$endif} end; exports LocalizePanoramicSymbolTable; ou: - Code:
-
// Cette fonction retourne l'adresse du début de la table des variables de Panoramic. // Elle doit être appelée avec l'adresse d'une variable système en format flottant, // comme NUMBER_CLICK par exemple. function FindSymbolTableStartAddress(a_number_click: pinteger):integer; stdcall; export; var ptr: pinteger; begin result := integer(PanoramicSymbolTable); exit;
result := 0; // supposer "erreur" ptr := a_number_click; inc(ptr,-6); // pointer sur l'adresse du nom de NUMBER_CLICK if pstring(ptr)^='NUMBER_CLICK' then begin while ptr^<>0 do inc(ptr,-PanoramicSymbolTableEntrySize); inc(ptr,PanoramicSymbolTableEntrySize); result := integer(ptr); end; end; exports FindSymbolTableStartAddress;
voir la valeur de PanoramicSymbolTableEntrySize dans les commentaires de la première solution. | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Des DLL pour Panoramic ? Ven 17 Déc 2021 - 14:58 | |
| Voici une petite démo pour lire et écrire des tableaux d'entiers et de flottants. ll suffit de recharger KGF.dll à partir de ma signature et de lancer le code suuivant: - Code:
-
' test_accès_tableaux.bas
dim res%, entiers%(5), flottants(7), i%
for i%=0 to 5 entiers%(i%) = i%+100*i% next i% for i%=0 to 7 flottants(i%) = 1/(i%+1) next i%
dll_on "KGF.dll"
res% = dll_call2("GetIntegerArrayFromPanoramic",adr(entiers%),5) res% = dll_call2("SetIntegerArrayFromPanoramic",adr(entiers%),5) for i%=0 to 5 message "SetIntegerArrayFromPanoramic "+str$(i%)+": "+str$(entiers%(i%)) next i%
res% = dll_call2("GetFloatArrayFromPanoramic",adr(flottants),7) res% = dll_call2("SetFloatArrayFromPanoramic",adr(flottants),7) for i%=0 to 7 message "SetFlottantArrayFromPanoramic "+str$(i%)+": "+str$(flottants(i%)) next i%
end
Ce code commence par initialiser un tableau d'entiers et de flottants. Il appelle ensuite la fonction GetIntegerArrayFromPanoramic qui lit le tableau des entiers de Panoramic et affiche les valeurs reçues. Puis, il appelle la fonction SetIntegerArrayFromPanoramic qui remplace les éléments du tableau des entiers par d'autres valeurs et affiche ensuite (en Panoramic) les nouvelles valeurs. Puis, il appelle la fionction GetFloatArrayFromPanoramic qui lit le tableau des flottants de Panoramic et affiche les valeurs reçues. Puis, il appelle la fonction SetFloatArrayFromPanoramic qui remplace les éléments du tableau des flottants par d'autres valeurs et affiche ensuite (en Panoramic) les nouvelles valeurs. Voici le code de ces 4 fonctions: - Code:
-
// copier un tableau de type integer de Panoramic dans un tableau dynamique Delphi dans la DLL function GetIntegerArrayFromPanoramic(aIntegerArray: pinteger; nDimension: integer): integer; stdcall; export; var IntegerArray: array of Integer; i: integer; pi: pinteger; begin result := -1; try if aIntegerArray=nil then exit; // il faut au moins une adresse if nDimension<0 then exit; // il faut une dimenion Panoramic valide SetLength(IntegerArray,nDimension+1); // affecter la mémoire pi := aIntegerArray; // boucle de lecture for i:=0 to nDimension do begin IntegerArray[i] := pi^; // ccpier un élément inc(pi); // ajuster le pointeur showmessage(format('GetIntegerArrayFromPanoramic %d: %d',[i,IntegerArray[i]])); // juste pour montrer le résultat - ligne à supprimer ! end; result := 0; except end; end; exports GetIntegerArrayFromPanoramic;
// copier un tableau de type integer d'un tableau dynamique Delphi dans la DLL vers un tableau dans Panoramic function SetIntegerArrayFromPanoramic(aIntegerArray: pinteger; nDimension: integer): integer; stdcall; export; var IntegerArray: array of Integer; i: integer; pi: pinteger; begin result := -1; try if aIntegerArray=nil then exit; // il faut au moins une adresse if nDimension<0 then exit; // il faut une dimenion Panoramic valide
// les 2 lignes suivantes sont là pour "simuler" un tableau existant dans la DLL... SetLength(IntegerArray,nDimension+1); // affecter la mémoire for i:=0 to nDimension do IntegerArray[i] := i*2;
if nDimension>=Length(IntegerArray) then exit; // trop de données demandées ? pi := aIntegerArray; // boucle d'écriture for i:=0 to nDimension do begin pi^ := IntegerArray[i]; // ccpier un élément inc(pi); // ajuster le pointeur end; result := 0; except end; end; exports SetIntegerArrayFromPanoramic;
// copier un tableau de type float de Panoramic dans un tableau dynamique Delphi dans la DLL function GetFloatArrayFromPanoramic(aFloatArray: pfloat; nDimension: integer): integer; stdcall; export; var FloatArray: array of double; i: integer; pf: pfloat; begin result := -1; try if aFloatArray=nil then exit; // il faut au moins une adresse if nDimension<0 then exit; // il faut une dimenion Panoramic valide SetLength(FloatArray,nDimension+1); // affecter la mémoire pf := aFloatArray; // boucle de lecture for i:=0 to nDimension do begin FloatArray[i] := pf^; // ccpier un élément inc(pf); // ajuster le pointeur showmessage(format('GetFloatArrayFromPanoramic %d: %f',[i,FloatArray[i]])); // juste pour montrer le résultat - ligne à supprimer ! end; result := 0; except end; end; exports GetFloatArrayFromPanoramic;
// copier un tableau de type float d'un tableau dynamique Delphi dans la DLL vers un tableau dans Panoramic function SetFloatArrayFromPanoramic(aFloatArray: pfloat; nDimension: integer): integer; stdcall; export; var FloatArray: array of double; i: integer; pf: pfloat; begin result := -1; try if aFloatArray=nil then exit; // il faut au moins une adresse if nDimension<0 then exit; // il faut une dimenion Panoramic valide
// les 2 lignes suivantes sont là pour "simuler" un tableau existant dans la DLL... SetLength(FloatArray,nDimension+1); // affecter la mémoire for i:=0 to nDimension do FloatArray[i] := i*2.002;
if nDimension>=Length(FloatArray) then exit; // trop de données demandées ? pf := aFloatArray; // boucle de lecture for i:=0 to nDimension do begin pf^ := FloatArray[i]; // ccpier un élément inc(pf); // ajuster le pointeur end; result := 0; except end; end; exports SetFloatArrayFromPanoramic; Voila pour le "prrof of concept". Je n'ai pas fait une nouvelle version de KGF.dll. Ces fonctions étaient présentes mais non exportées et non documentées. Je les ai simplement exportées. | |
| | | jean_debord
Nombre de messages : 1266 Age : 70 Localisation : Limoges Date d'inscription : 21/09/2008
| Sujet: Re: Des DLL pour Panoramic ? Sam 18 Déc 2021 - 11:12 | |
| Merci encore pour ces exemples, Klaus C'est bien ce que j'avais prévu de faire en FreeBASIC. Mais j'ai besoin des tableaux à 2 dimensions (matrices) pour mes applications. Donc il faut que je trouve une astuce. Le plus simple serait de passer tout le tableau dans une chaîne de caractères. par exemple : "{1,2,3,4}" "{{1,2,3,4}, {5,6,7,8}}" Il suffirait de se mettre d'accord sur la syntaxe (ici j'ai repris celle de FreeBASIC) | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Des DLL pour Panoramic ? Sam 18 Déc 2021 - 11:41 | |
| Ouais... c'est imaginable en "entrée", en tant que valeur constante. C'est impossible en "sortie", et c'est impossible en entrée en tant que variable existant de façon permmanente dans le programme appelant.
Je ne connais pas l'implémentation des tableaux multi-dimensionnels en FreeBasic. En ce qui concerne Panoramic, le passage de ce genre de tableaux est impossible, tant entrée qu'en sortie.
Mais tu peux essayer autre chose. Par définition, le canvas d'une image est une matrice à deux dimensions, et si tu crées la bitmap en format 32 bits, tu as un tableau en deux dimensions de valeurs de type integer. Il suffira alors de passer le handle du canvas pour y avoir accès. Là encore, pas question de mémoriser ce handle d'un appel d'une fonction DLL à unn autre - le handle du canvas peut changer après chaue opération modifiant le canvas.
Autre possibilité: utiliser un objet LIST caché (je parle toujours pour le couple Panoramic/Delphi que je connais bien) et dont le handle ne varie jamais pendant la durée de vie de l'objet. Tu peux imaginer de lacer dans chaque ligne de l'objet une suite de données déparées par des virgules simulant ainsi la deuxième dimension. Dans la DLL, tu récupères une ligne quelconque selon le premier indice, tu la charge dans un objet TStringList temporaire (Delphi...) et tu utilises le second indice pour trouver l'élément choisi dans cette liste. Idem pour le retour d'information - il suffira de remplacer els données de l'objet LIST initial via le handle passé en paramètre. Tu as ainsi une olution bi-directionnelle pour une simulation de tableaux en deux dimensions. | |
| | | papydall
Nombre de messages : 7017 Age : 74 Localisation : Moknine (Tunisie) Entre la chaise et le clavier Date d'inscription : 03/03/2012
| Sujet: Re: Des DLL pour Panoramic ? Sam 18 Déc 2021 - 13:45 | |
| Bonjour tout le monde @Klaus et Jean_debord. Suggestion : Il est toujours possible de simuler un tableau à deux dimensions ou plus en un tableau à une seule dimension. Exemple dim x,y x = 10 : y = 7 dim tab2(x,y) peut être simulé par dim tab1(x*y) Pour accéder au contenu de tab2(3,5) par exemple, on fait valeur = tab2(3,5) Pour le tableau à une seule dimension tab1() ça sera valeur = tab1(3*x+5). J'ai traité la simulation d'un tableau à 3 dimensions en un tableau à 2 dimensions sur ce post C'est peut-être une idée à approfondir. | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Des DLL pour Panoramic ? Sam 18 Déc 2021 - 14:09 | |
| Très bien, ton idée, Papydall ! Surtout parce qu'on peut déclarer uen fonction du même nom que le tableau à 2 dimensions à laquelle on passe les deux indices et qui fait le calcul àn l'intérieur? Idem avec une SUB pour l'écriture dans le tableau.
Ainsi, par extension, on peut traiter un tableau de n'importe quelle dimension par un tableau physique d'une seule dimension, et ce en Panioramic pur. Du coup, le probème de passage de tableaux multi-dimensions à une DLL est résolu... | |
| | | papydall
Nombre de messages : 7017 Age : 74 Localisation : Moknine (Tunisie) Entre la chaise et le clavier Date d'inscription : 03/03/2012
| Sujet: Re: Des DLL pour Panoramic ? Sam 18 Déc 2021 - 15:08 | |
| | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Des DLL pour Panoramic ? Sam 18 Déc 2021 - 15:43 | |
| Nicht nur geholfen - ich glaube, das ist DIE Lösung ! | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Des DLL pour Panoramic ? Sam 18 Déc 2021 - 18:38 | |
| Selon la suggestion de Papydall, j'ai fait une petite démo montrant comment on peut gérer un tableau d'entiers de 6 lignes sur 4 colonnes, dans un tableau uni-dimensionnel. Ce tableau peut alors facilement être passé à une fonction d'une DLL: - Code:
-
' Tableau_en_2_dimensions_avec_Panoramic_et_DLL.bas
dim res%, i%, j%, s$
' dim entiers%(5,3) dim entiers%(6*4-1) : ' les longueurs des dimensions sont 6 x 4 cases !
for i%=0 to 5 for j%=0 to 3 entiers(i%*100+j%,i%,j%) next j% next i%
for i%=0 to 5 s$ = "" for j%=0 to 3 s$ = s$ + str$(fentiers%(i%,j%)) + " " next j% print s$ next i%
end
' *** lire l'élément (i%,j%) du tableau entiers% ' ATTENTION: la fonction ne peut PAS avoir le même nom que le tableau ! ' Son nom est donc précédé d'un "f" pour signaler "fonction" fnc fentiers%(i%,j%) result entiers%(i%*4+j%) : ' la première dimension a une longueur de 6 ! end_fnc
' *** écrire la valeur v% dans l'élémént (i%,j%) du tableau entiers% sub entiers(v%,i%,j%) entiers%(i%*4+j%) = v% end_sub
Dernière édition par Klaus le Lun 20 Déc 2021 - 12:22, édité 1 fois | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Des DLL pour Panoramic ? Dim 19 Déc 2021 - 7:49 | |
| J'ai créé un objet MDA (Multi-DimensionalArray) permettant de gérer des tableaux Panoramic en 2 ou 3 dimensions à condition que ces tableaux soient simulés dans un tableau uni-dimensionnel. Il 'agit d'un objet interne à une DLL en Delphi (ou implémentation similaire dans d'autres langages). Deux fonctions exportées permettent de déclarer les tableaux multi-dimensionnels simulés, l'autre permet d'effacer toutes les déclarations. Puis, non accessibles par Panoramic mais utilisables à l'intérieur de la DLL, des fonctions et procédures permettant d'accéder ces tableaux directement à partir de la DLL sans avoir à les recopier. La condition incontournable est que l'adresse du talbleau uni-dimensionnel soit passée à la fonction DLL appelée par Panoramic. Voici le code de l'objet en Delphi: - Code:
-
{ Objet MDA - Multi-DimensionalArray
Cet objet permet de gérer des tableaux multi-dimensionnels simulés dans un tableau Panoramic uni-dimensionnel. L'intérêt de ce système est que les tableaux uni-dimensionnels peuvent facilement être passés en paramètre à la DLL. Ce n'est pas le cas des tableaux uni-dimensionnels. L'objet MDA est conçu pour donner accès aux fonctions d'une DLL aux données d'un tableau multi-dimensionnel de Panoramic. Pour cela, il faut déclarer en Panoramic un tableau uni-dimensionnel selon la formule: dim MonTableau((dim1+1) * (dim2+1) * (dim3+1) - 1) Exemple: dim MonTableau(5,3,7) sera remplacé par dim MonTableau(6*4*8-1)
L'implémentation actuelle est prévue pour des tableaux jusqu'à 3 dimensions.
Un tableau multi-dimensionnel doit être déclaré avec son nom et ses dimenions. L'objet MDA mémorise et gère toutes les déclarations ainsi que l'accès physique aux données. Deux fonctions exportées (accessibles en Panoramic) permettent définir les tableaux: res% = dll_call4("DefineMDA",adt(tableau$),d1%,d2%,d3%) : ' crée ou modifie la déclaration d'un tableau res% = dll_call0("ResetMDA") : ' efface toutes les déclarations de tableaux Les fonctions et procédures suivantes sont utilisables dans la DLL (en Delphi), mais pas appelables par Panoramic: MDA.IndexOfArray(aName: string): string retourne l'index du tableau ou -1 si non déclaré MDA.TypeOfArray(aName: string): TypMDA retourne le type d'un tableau MDA.GetIntegerArrayElement(aIndex, d1,d2,d3: integer; aPanoramic: pinteger): integer retourne le contenu d'un élément MDA.GetFloatArrayElement(aIndex, d1,d2,d3: integer; aPanoramic: pfloat): double retourne le contenu d'un élément MDA.SetIntegerArrayElement(aIndex, d1,d2,d3: integer; aValue: integer; aPanoramic: pinteger) remplace le contenu d'un élément MDA.SetFloatArrayElement(aIndex, d1,d2,d3: integer; aValue: double; aPanoramic: pfloat) remplace le contenu d'un élément } type TypMDA = (tMDAundefined, tMDAfloat, tMDAinteger, tMDAstring); type TMDA = class private fNames: array of string; fTypes: array of TypMDA; fDimensions: array of array of integer; published function IndexOfArray(aName: string): integer; function TypeOfArray(aName: string): TypMDA; function GetIntegerArrayElement(aIndex, d1,d2,d3: integer; aPanoramic: pinteger): integer; function GetFloatArrayElement(aIndex, d1,d2,d3: integer; aPanoramic: pfloat): double; procedure SetIntegerArrayElement(aIndex, d1,d2,d3: integer; aValue: integer; aPanoramic: pinteger); procedure SetFloatArrayElement(aIndex, d1,d2,d3: integer; aValue: double; aPanoramic: pfloat); procedure AddArray(aName: string; d1, d2, d3: integer); procedure ModifyArray(aName: string; d1, d2, d3: integer); constructor CreateNew; destructor Destroy; end;
var MDA: TMDA;
Implementation
constructor TMDA.CreateNew; begin inherited; SetLength(fNames,0); SetLength(fTypes,0); SetLength(fDimensions,0); end;
destructor TMDA.Destroy; begin SetLength(fNames,0); SetLength(fTypes,0); SetLength(fDimensions,0); inherited; end;
function TMDA.IndexOfArray(aName: string): integer; var i: integer; begin result := -1; if Length(fNames)=0 then exit; for i:=0 to high(fNames) do begin if fNames[i]=aName then begin result := i; exit; end; end; end;
function TMDA.TypeOfArray(aName: string): TypMDA; var i: integer; begin result := tMDAundefined; i := IndexOfArray(aName); if i>=0 then result := fTypes[i]; end;
function TMDA.GetIntegerArrayElement(aIndex, d1,d2,d3: integer; aPanoramic: pinteger): integer; var pi: pinteger; offset: integer; begin result := 0; if (aIndex<0) or (aIndex>high(fNames)) then exit; pi := aPanoramic; offset := d1*fDimensions[aIndex][1] + d2*fDimensions[aIndex][2] + d3; inc(pi,offset); result := pi^; end;
function TMDA.GetFloatArrayElement(aIndex, d1,d2,d3: integer; aPanoramic: pfloat): double; var pf: pfloat; offset: integer; begin result := 0; if (aIndex<0) or (aIndex>high(fNames)) then exit; pf := aPanoramic; offset := d1*fDimensions[aIndex][1] + d2*fDimensions[aIndex][2] + d3; inc(pf,offset); result := pf^; end;
procedure TMDA.SetIntegerArrayElement(aIndex, d1,d2,d3: integer; aValue: integer; aPanoramic: pinteger); var pi: pinteger; offset: integer; begin if (aIndex<0) or (aIndex>high(fNames)) then exit; pi := aPanoramic; offset := d1*fDimensions[aIndex][1] + d2*fDimensions[aIndex][2] + d3; inc(pi,offset); pi^ := aValue; end;
procedure TMDA.SetFloatArrayElement(aIndex, d1,d2,d3: integer; aValue: double; aPanoramic: pfloat); var pf: pfloat; offset: integer; begin if (aIndex<0) or (aIndex>high(fNames)) then exit; pf := aPanoramic; offset := d1*fDimensions[aIndex][1] + d2*fDimensions[aIndex][2] + d3; inc(pf,offset); pf^ := aValue; end;
procedure TMDA.AddArray(aName: string; d1, d2, d3: integer); var i: integer; begin i := Length(fNames); SetLength(fNames,i+1); SetLength(fTypes,i+1); SetLength(fDimensions,i+1); SetLength(fDimensions[i],3); fNames[i] := aName; fTypes[i] := tMDAfloat; if RightStr(aName,1)='%' then fTypes[i] := tMDAinteger; if RightStr(aName,1)='$' then fTypes[i] := tMDAstring; fDimensions[i][0] := d1; fDimensions[i][1] := d2; fDimensions[i][2] := d3; end;
procedure TMDA.ModifyArray(aName: string; d1, d2, d3: integer); var i: integer; begin i := self.IndexOfArray(aName); fNames[i] := aName; fTypes[i] := tMDAfloat; if RightStr(aName,1)='%' then fTypes[i] := tMDAinteger; if RightStr(aName,1)='$' then fTypes[i] := tMDAstring; fDimensions[i][0] := d1; fDimensions[i][1] := d2; fDimensions[i][2] := d3; end;
Et les fonctions exportées: - Code:
-
// cette fonction ajoute ou modifie la déclaration d'un tableau function DefineMBA(aName: integer; d1, d2, d3: integer): integer; stdcall; export; var s: string; index: integer; begin result := -1; try if not assigned(MDA) then MDA := TMDA.CreateNew; // créer la table maître si besoin s := Trim(GetStringFromPanoramic(aName)); // prendre le nom Panoramic du tableau if s='' then exit; // nom manquant ? index := MDA.IndexOfArray(s); // chercher le tableau dans la table maître if index<0 then begin // tableau pas encore enregistré ? MDA.AddArray(s,d1,d2,d2); // ajouter une nouvelle déclaration end else begin // tableau déjà enregistré - changer dimensions MDA.ModifyArray(s,d1,d2,d3); // modifier la définition du tableau end; result := 0; except end; end; exports DefineMBA;
// cette fonctiob efface toutes les déclarations de tableaux (PAS LES TABLEAUX !) function ResetMDA: integer; stdcall; export; begin result := -1; try if not assigned(MDA) then exit; MDA.Free; result := 0; except end; end; exports ResetMDA; Ainsi, une fonction DLL peut recevoir l'adresse du tableau simulé et éventuellement des indices en paramètre, puis travailler directement surb les données, en lécture et en mise à jour. Il faut juste passer chaque foir l'adresse de ce tableau simulée et non une valeur stockée dans une variable, l'adresse pouvant changer dynamiquement (pendant l'exécution du code Panoramic, pas pendant l'exécution de la fonction DLL !). | |
| | | papydall
Nombre de messages : 7017 Age : 74 Localisation : Moknine (Tunisie) Entre la chaise et le clavier Date d'inscription : 03/03/2012
| Sujet: Re: Des DLL pour Panoramic ? Dim 19 Déc 2021 - 8:11 | |
| Belle avancée, merci Klaus ! « La persévérance et le travail finissent toujours par payer ! » | |
| | | Contenu sponsorisé
| Sujet: Re: Des DLL pour Panoramic ? | |
| |
| | | | Des DLL pour Panoramic ? | |
|
Sujets similaires | |
|
| Permission de ce forum: | Vous ne pouvez pas répondre aux sujets dans ce forum
| |
| |
| |