Déclaration de variables

Bo57 Messages postés 7 Date d'inscription vendredi 25 septembre 2009 Statut Membre Dernière intervention 10 janvier 2011 - 8 janv. 2011 à 11:27
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 - 10 janv. 2011 à 23:49
Bonjour à tous.

Je bute sur une function comprenant un mot réservé. J'ai parcouru bien des forums sans succès.
J'aimerais lire une valeur dans un automate pour lequel existe une DLL.
La function dans la DLL (EASY_COM.dll) est la suivante (documentation fournie avec la dll) :

Read_Object_Value
long Read_Object_Value(unsigned char net_id, unsigned char object, unsigned short index, unsigned char * data)

que j'ai traduite en delphi par :
Déclaration:
function Read_Object_Value (net_id: byte; object: byte; index: word; var data: byte): integer;stdcall;external 'EASY_COM.dll';

à la compilation j'ai ce message

[DCC Erreur] Unit1.pas(34): E2029 Identificateur attendu(e) mais 'OBJECT' trouvé(e)
Peut on contourner ce problème ?

Par avance merci de ce fabuleux support qu'est votre forum qui m'a déjà permit de franchir bien des obstacles en programmation.

11 réponses

Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
8 janv. 2011 à 11:32
Object est un mot réservé par Delphi. Mais comme les nom de paramètres n'ont pas de significance dans le code compilé final, tu peux écrire quelque chose d'autre comme paramètre (genre Objet ou Object2, ..), ça changera rien. Tu peux changer le nom des paramètres sans problème, tu peux changer le nom de la fonction avec la directive "name".

Cordialement, Bacterius !
0
Bo57 Messages postés 7 Date d'inscription vendredi 25 septembre 2009 Statut Membre Dernière intervention 10 janvier 2011
8 janv. 2011 à 11:54
Waouh ! mieux que le TGV !
Merci pour cette réponse spontanée.
Si j'ai bien compris je peux remplacer le mot "object" dans ma function par n'importe lequel. Sans que cela affecte le fonctionnement interne de la DLL.
Dans ce cas je déclare ma function comme suit ? :

function Read_Object_Value (net_id: byte; obj: byte; index: word; var data: byte): integer;stdcall;external 'EASY_COM.dll' name 'Read_Object_Value';

Encore merci.
0
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
8 janv. 2011 à 12:28
Oui, et dans ton code tu utilises "obj" à la place de "object". Le nom des paramètres ne sont là que pour aider le programmeur, pour le système ce n'est qu'une variable mémoire d'une certaine taille (le nom des fonctions/procédures c'est différent par contre).

Et aussi, dans ta traduction Delphi, j'aurai plutôt mis "var Data" à la fin plutôt que "var Data: Byte", ou encore "Data: Pointer", je n'ai pas testé mais je ne sais pas si ça marchera avec ta version (si ça ne marche pas tu auras des violations d'accès probablement). Car en C, l'astérisque * désigne un type pointeur, et en général l'unsigned char * est le type pointeur par excellence pour des buffers (qu'on traduit en Delphi par pointeur non typé Pointer).

Au fait, le "name" n'est pas requis si tu ne changes pas le nom de la fonction.

Cordialement, Bacterius !
0
Bo57 Messages postés 7 Date d'inscription vendredi 25 septembre 2009 Statut Membre Dernière intervention 10 janvier 2011
8 janv. 2011 à 12:50
Mille merci Bacterius.
Cette histoire de pointeur, je pensais déjà la modifier sous forme de déclaration de tableau.
dans le genre :
var
....
dataeasy : array [0..128] of byte;
....
end;
function Read_Object_Value (net_id: byte; obj: byte; index: word; data: pointer): integer;stdcall;external 'EASY_COM.dll'
(merci pour data: pointer et name)
ensuite dans le code :
var
x: byte;
begin
.....
Read_Object_Value (...,...,..., data := dataeasy [x]);
.....
end;
Je pense que cela devrait fonctionner, je testerai ou du moins je trouverai la solution car là je pense qu'on est un peu hors sujet.
Merci Bacterius
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
8 janv. 2011 à 12:58
Hmm, ça reste un pointeur, il faudrait alors faire @Dataeasy pour accéder au pointeur. Mais le problème c'est que si ton data fait plus de 129 bytes, ça va planter car on aura atteint la fin du buffer. Voici une solution :

dans le code :

var
 Buffer: Pointer;
begin
 GetMem(Buffer, 256);
 // Traitement
 Read_Object_Value(........., Buffer);
 // Traitement
 FreeMem(Buffer, 256);
end;


En remplacant 256 par la bonne taille selon ce que fait la fonction Read_Object_Value. Les traitements porteront sur l'espace mémoire alloué par la fonction GetMem, en utilisant Buffer^ (qui pointe sur le premier octet de mémoire contigüe que représente Buffer), on peut alors utiliser diverses méthodes pour lire/écrire dans cet espace mémoire.

Mais un tableau marcherait aussi bien si la taille ne change jamais (et même si elle change avec les tableaux dynamiques), toutefois l'utilisation d'un pointeur est plus souple et plus efficace.

En fait, pour résoudre ce problème il faudrait savoir ce que la fonction Read_Object_Value fait, et sur quel type de données elle opère. Que doit représenter le paramètre data ?

Cordialement, Bacterius !
0
Bo57 Messages postés 7 Date d'inscription vendredi 25 septembre 2009 Statut Membre Dernière intervention 10 janvier 2011
8 janv. 2011 à 19:53
Merci pour ton appui Bacterius.

Je crois que je me suis quelque peu planté sur la compréhension envers le fonctionnement de cette DLL.
J'avais cherché des exemples de source en Delphi mais sans succès. Que du vb. D'où j'ai donc essayé de traduire et de comprendre.
J'ai certainement voulu brûler les étapes. A déconseiller vivement. Mais tu m'as mis sur le bon chemin.
J'ai découvert Delphi depuis peu (novembre 2010).

En fait dans l'automate on peut gérer une sortie, par exemple d'un "module de données" en lui affectant une valeur que l'on met dans une mémoire interne MB, MW, MD (de l'automate).
Ex. dans l'automate le module DB1 lit durant un front montant l'entrée analogique I07 et met cette valeur dans MD5 (MD double mot de mémoire interne 32 byte, 5 emplacement (opérande) - Nb max d'emplacements (opérandes) = 96).
net_id = le n° de l'automate concerné (participant).
object ce que doit lire l'automate (0 les entrées de l'appareil de base, 1 = les sorties, etc...)
index (si object 6,7,11,12) N° du participant (1..8), (si object = 10) N° de l'opérande (1..96), (si object = 17) accès complet des byte (1..354)
data = pointe sur la zone mémoire où est stocké la valeur (donc en principe, ici MD5)

Je vais relire et relire les documents de cette DLL et le manuel de l'automate.

Je te tiens au courant. Ce que je peu affirmer c'est que le tableau ne risque pas de changer vu que sa taille est fonction de l'emplacement mémoire alloué par l'automate.
La nuit sera longue.

Encore merci à +.
0
Bo57 Messages postés 7 Date d'inscription vendredi 25 septembre 2009 Statut Membre Dernière intervention 10 janvier 2011
9 janv. 2011 à 18:49
Bonjour à tous ! et surtout à toi Bactérius !

Comme promis me revoilà (ah non pas encore lui !)

Bactérius tu m'as mis la puce à l'oreille avec ton buffer. J'ai ressortis mes bouquins et notes ainsi que le manuel de l'automate.
C'est OK, j'arrive à lire ce que je veux à partir de l'automate ! voici un extrait de mon code source :

var
Form1: TForm1;
MW: array[1..96] of Word;
MD: array[1..96] of DWord;
MB: array[1..96] of byte;
...............
function Open_ComPort (com_port_nr: byte; baudrate: LongInt): LongInt;stdcall;external 'EASY_COM.dll'; // pour ouvrir le port COM
function Close_ComPort: LongInt;stdcall;external 'EASY_COM.dll';
function Read_Object_Value(net_id: byte; obj: byte; index: byte; data: pointer): integer;stdcall;external 'EASY_COM.dll';

procedure TForm1.ConnectClick(Sender: TObject);
var
cp: integer;
begin
cp := Open_ComPort (1,19200); //j'ouvre COM1 avec un transfert de 19200 bauds

Edit1.Text := inttostr (cp); //j'affiche le code retour automate (info) m'affiche 0 (Function call up successful.)
end;

procedure TForm1.DisconnectClick(Sender: TObject);
begin
Timer1.Enabled := false;
Close_ComPort;
end;

procedure TForm1.lectureClick(Sender: TObject);
var
rov1,rov2: integer;
begin
timer1.Enabled := true;
rov1 := Read_Object_Value (0,10,1,@MW[1]); //compteur d'événement C1 de l'automate
Edit4.Text := inttostr(rov1); //j'affiche le code retour automate (info) m'affiche 0 (Function call up successful.)
Edit2.Text := inttostr(MW[1]); //j'affiche les valeurs du compteur récupérées de l'automate
Read_Object_Value (0,10,32,@MD[1]); //compteur d'événement C1 avec fonction arithmétique (x10) de l'automate
Edit5.Text := inttostr(MD[1]); //j'affiche les valeurs du compteur récupérées de l'automate
end;

TOUS CELA FONCTIONNE A MERVEILLE. Et en temps réel.

Puis j'ai essayé de passer par Ethernet avec le convertisseur prévu pour ces automates.
J'arrive à programmer l'automate par ethernet, y transférer et récupérer un programme avec mon logiciel de programmation de l'automate.
Malheureusement avec Delphi pour afficher une valeur dans un TEdit sur ma Form j'ai pas de succès.
Voici la function de la DLL :

Open_EthernetPort
long Open_EthernetPort (const char * szIpAddress, long IpPort, long baudrate, bool no_baudrate_scan)

szIpAddress = IPv4 address as 0 terminated string. As a rule 4 digit e.g. "10.1.41.31"
IpPort = IP port number { 1200, 10001…10999 }
baudrate = Baud rate set in device { 4800, 9600, 19200, 38400, 57600 }
no_baudrate_scan Switches the baud rate test off. "true"> only the given baud rate will be tested

Que j'ai traduite par :

function Open_EthernetPort(szIpAddress: PChar; IpPort: integer; baudrate: integer; no_baudrate_scan: boolean): integer;stdcall;external 'EASY_COM';
avec comme valeurs : Open_EthernetPort('192.168.1.20', 10001, 19200, true); //configuration du convertisseur.

Quand je click pour ouvrir la communication j'ai bien mon ParFeu qui me demande l'autorisation, puis au bout de 5 secondes l'automate me retourne le code 14 qui veut dire (TCP/IP station doesn't respond or the TCP/IP port is already occupied by another opened connection)
Pourtant j'arrive à communiquer par ethernet quand je transfère un programme écrit vers l'automate.
Le ping '192.168.1.20' fonctionne aussi.
Y aurait-il un paramètre dans la function encore mal traduit ?

Désolé d'importuner de la sorte mais ce projet me tiens à coeur pour la compréhension.
Encore Merci.
0
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
10 janv. 2011 à 00:22
Non, cette fois les paramètres me semblent corrects ... je pense que là ça ne vient pas de la fonction puisqu'elle fonctionne bien apparemment et crée la connection, seulement elle se ferme plus tard. Là je ne vois pas du tout, peut-être faut-il garder la connection vivante (keep-alive) en envoyant périodiquement des données, sinon l'automate croit que tu t'es déconnecté et ferme la connection, mais à part ça je ne vois pas trop, en tout cas ça ne vient pas de la fonction (en général une erreur de paramètre conduit à une violation d'accès, une exception externe ou une fonction qui retourne toujours échec.

Cordialement, Bacterius !
0
Bo57 Messages postés 7 Date d'inscription vendredi 25 septembre 2009 Statut Membre Dernière intervention 10 janvier 2011
10 janv. 2011 à 17:23
Merci, pour la confirmation que ma traduction semble correct.
J'ai oublié de préciser que quand je click sur "Déconnection" (Close_EthernetPort) mon application se ferme.
Je vais bûcher ce problème et mettre la function dans chaque procédure d'appel (Read_). D'après les exemples en VB que j'ai consulté la déclaration de Open_Ethernet se fait qu'une seule fois lors de la demande de connexion.
Au fait chapeau pour ton tutorial sur les pointeurs, je l'ai trouvé hier sur le site. J'en ai appris des choses, cela simplifiera certainement mes traitements dans mon programme. Je te tiens informé de mes évolutions.
Merci Bactérius.
0
Bo57 Messages postés 7 Date d'inscription vendredi 25 septembre 2009 Statut Membre Dernière intervention 10 janvier 2011
10 janv. 2011 à 19:55
slt Bactérius
Problème résolu. Il fallait mettre PAnsiChar au lieu de PChar dans la function Open_EthernetPort.
J'ai vérifié dans les solutions de conversions de Delphi et en provoquant volontairement des erreurs (vue que j'avais l'info codé des erreurs en retour de l'automate). Désolé mais j'avais omis de préciser que j'ai Delphi 2010, (et comme la DLL est antérieure ...).

Je te remercie très sincèrement de ton appui, Bactérius, de tes conseils riches en connaissances.
J'ai hâte de relire ton tut sur les pointeurs car je suis sûr qu'il m'apportera beaucoup dans mon projet.

De plus j'aimerais souligner l'efficacité de ce forum sur lequel j'ai pu puiser d'innombrables informations qui m'ont permis de reprendre confiance.
MERCI A TOUS POUR VOTRE PRÉSENCE.

Pour ma part je peux donc clore cette partie.
0
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
10 janv. 2011 à 23:49
De rien, content que ton problème soit résolu et que mon tutoriel t'ai servi, et bonne programmation

Cordialement, Bacterius !
0
Rejoignez-nous