Transmission adresse fonction à une dll

Résolu
Oniria Messages postés 292 Date d'inscription dimanche 14 mars 2004 Statut Membre Dernière intervention 18 décembre 2014 - 8 févr. 2012 à 17:48
Oniria Messages postés 292 Date d'inscription dimanche 14 mars 2004 Statut Membre Dernière intervention 18 décembre 2014 - 21 févr. 2012 à 17:19
Bonjour à tous,

ma question est un peu technique.J'ai une interface CAN2.0B de Lawicel (l'interface CANUSB) qui doit me permettre de voir et de communiquer sur le réseau CAN (réseau automobile). Je suis en train de construire un composant permettant d'utiliser la dll de pilotage de cette interface avec notre delphi adoré sauf que la documentation de la dll est basé sur une utilisation de visual C++ et je doit donc traduire les appels des fonctions de la dll en delphi à partir du C (là est la complexité).
La dll posséde une fonction nommé setReceiveCallBack permettant d'appelé une fonction de mon cru lorsqu'une trame sur le réseau arrive. Je ne parviens pas à déclarer correctement(je pense) cette fonction.

La documentation donne :
int setReceiveCallBack( CANHANDLE h,
LPFNDLL_RECEIVE_CALLBACK cbfn )

With this method one can define a function that will receive all incoming messages. Note
that canusb_Read will not work after this call. You can make it work again by calling
this method and set cbfn equal to NULL.

The callback function should be defined as
void fn( CANMsg *pMsg );

Note: that the channel has to be open to be able to set a callback function.

On a LPFNDLL_RECEIVE_CALLBACK qui est défini comme suit dans un header :
typedef void ( __stdcall * LPFNDLL_RECEIVE_CALLBACK) ( CANMsg *pMsg );

alors moi j'ai traduit ca comme ca :

type LPFNDLL_RECEIVE_CALLBACK = Pointer;

...
implementation

Function canusb_setReceiveCallBack( h : DWord;cbfn : LPFNDLL_RECEIVE_CALLBACK) : integer;stdcall ; External 'canusbdrv.dll' name 'canusb_setReceiveCallBack';

... un peu plus loin, lors de l'appel

i:=canusb_setReceiveCallBack(FHandle,@TCANUSB.ReceiveMSG);

avec TCANUSB=class(TComponent)

et ReceiveMsg défini dans TCANUSB comme :
Procedure ReceiveMSG(var CANMSGReceive :TCANMSG);

lorsque j'appelle la fonction setReceiveCallBack, ca ne marche pas car la fonction me renvoi 0 au lieu d'un nombre >0.

Est ce que le LPFNDLL_RECEIVE_CALLBACK est bien défini car pour moi le typedef en C++ est du chinois ?
Est ce que je m'y prend correctement pour transmettre l'adresse de ma fonction ?
Est ce que j'ai correctement traduit la fonction ReceiveMsg car en C void nom_fonction doit être traduit par procedure en delphi si je ne me trompe pas ?

Merci à ceux qui prendront le temps pour me répondre. ( pour préciser, j'ai déja cherché sur google et les seules choses que j'ai vu, ce sont des explications sur la création de dll vers d'autre langage mais pas sur ce cas précis).

Oniria

11 réponses

WhiteHippo Messages postés 1154 Date d'inscription samedi 14 août 2004 Statut Membre Dernière intervention 5 avril 2012 3
9 févr. 2012 à 19:58
Bonjour

D'après ce que tu donnes comme information, tu devrais avoir dans tes déclarations :
type
  PCANMsg = ^TCANMsg;
  TCanMsg = record
    // ici la définitions des éléments constituants la structure
  end ;

  LPFNDLL_RECEIVE_CALLBACK = procedure ( CANMsg : PCANmsg ); stdcall;
// ou éventuellement LPFNDLL_RECEIVE_CALLBACK = procedure ( var CANMsg : TCANmsg ); stdcall;

Function CANUSBSetReceiveCallBack
  ( h    : DWord  
  ; cbfn : LPFNDLL_RECEIVE_CALLBACK
  ) : CANUSB_Result 
  ; stdcall ; External 'canusbdrv.dll' name 'canusb_setReceiveCallBack'
;

Et pour l'appel, il faudrait soit définir une fonction n'appartenant pas une classe (Pourquoi ? Simplement parce qu'une méthode de classe contient un paramètre supplémentaire caché le "self"), soit déclarer une méthode de classe.

Méthode de classe :
TCanUSB = class
  class Procedure ReceiveMSG( var CANMSGReceive : TCANMSG ); 
end ;

Fonction externe :
Procedure ReceiveMSG( var CANMSGReceive : TCANMsg ); 
begin
  // ...
end ;

TCANUSB = class
private
  FReceiveCallBackResult : integer ;
public
  procedure Receive ;
end ;

procedure TCANUSB.Receive ;
begin
  FReceiveCallBackResult := canusb_setReceiveCallBack(FHandle, @ReceiveMSG); 
end ;


P.S. Tout ça n'est bien sur qu'un point de vue rapide (Ne connaissant ni le composant, ni son contexte d'utilisation) et purement théorique (A toi de faire les tests et d'adapter en fonction de tes besoins)

Cordialement.[hr]"L'imagination est plus importante que le savoir." Albert Einstein
3
beckerich Messages postés 302 Date d'inscription jeudi 29 septembre 2005 Statut Membre Dernière intervention 17 septembre 2013 2
9 févr. 2012 à 13:10
bonjour,

je n'ai pas d'expérience avec ce que tu désires faire, mais une chose me saute aux yeux :
tu passes comme paramètre l'adresse d'une méthode de classe @TCANUSB.ReceiveMSG
Je pense que ça ne peut pas aller. Essaye plutôt une procedure (statique ??? on dit comme cela ?), qui ne soit pas contenue dans une classe. Ou éventuellement l'adresse de la méthode d'une instance de la classe, ou TCANUSB.@ReceiveMsg (qu'on peut lire comme l'adresse de la méthode ReceiveMsg de la classe TCANUSB), enfin qque chose dans ce genre.

Bonne continuation,
Luc.
0
Oniria Messages postés 292 Date d'inscription dimanche 14 mars 2004 Statut Membre Dernière intervention 18 décembre 2014 3
9 févr. 2012 à 13:58
Bonjour,

merci pour ta réponse. Je vais essayer ce que tu viens de me dire. C'est vrai que peut-être, le @TCANUSB.ReceiveMSG n’existe pas car, j'ai créé le composant dans la fiche principale en écrivant PCANUSB:=TCANUSB.create(Self) mais l'instruction @TCANUSB.ReceiveMSG ne pointe peut-être pas sur la procédure. Je vais essayer avec une procédure statique.
En tout cas merci de m'aider ! Ca me donne d'autres idées comme récipérer l'adresse de l'objet PCANUSB par le composant TCANUSB. c'est peut-être là la solution .


Oniria
0
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
9 févr. 2012 à 14:42
Salut,

je n'ai pas plus d'expérience dans ce domaine que Beckerich mais la même chose me saute aux yeux

Il me semble qu'on ne peut pas passer une méthode de classe en paramètre dans le cas qui nous intéresse ici ... Les méthodes de classes font l'objet d'une gestion différente des méthodes externes classiques.

La méthode externe est la meilleur solution et il me semble même (de mémoire) qu'il faut y ajouter "stdcall ; External" à sa déclaration.

à toi de faire les testes ...


[hr]@+Cirec
[hr]
0

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

Posez votre question
WhiteHippo Messages postés 1154 Date d'inscription samedi 14 août 2004 Statut Membre Dernière intervention 5 avril 2012 3
9 févr. 2012 à 20:09
Et pour l'appel, il faudrait soit définir une fonction n'appartenant pas une classe (Pourquoi ? Simplement parce qu'une méthode de classe contient un paramètre supplémentaire caché le "self"), soit déclarer une méthode de classe.


Attention, pour une compréhension non ambigue, j'aurais du écrire :

Et pour l'appel, il faudrait soit définir une fonction n'appartenant pas une classe (Pourquoi ? Simplement parce que la méthode d'une classe contient un paramètre supplémentaire caché le "self"), soit déclarer une méthode de classe.

Désolé...

Cordialement.[hr]"L'imagination est plus importante que le savoir." Albert Einstein
0
Oniria Messages postés 292 Date d'inscription dimanche 14 mars 2004 Statut Membre Dernière intervention 18 décembre 2014 3
9 févr. 2012 à 21:37
En tout cas, merci à vous tous. Mon problème n'est pas très simple car je dois transmettre l'adresse d'une fonction à cette dll. En plus, j'aimerais construire une fonction callback dans le TCANUSB (mon composant) pour prévenir le programme principal de l'arrivée d'une trame.
J'ai essayé de transmettre une adresse d'une fonction statique et le résultat n'est toujours pas fameux, la fonction de dll me renvoi une valeur de défaut général. Je vais essayer une autre approche en branchant un boitier électronique qui va envoyer des trames sur le réseau CAN à mon interface et voir si par hazard, il n'y aurait pas un bug dans la dll et que ma fonction fonctionne bien.

Sinon, existe t-il une méthode pour pouvoir échanger des données entre un thread et un autre objet TComponent. Je peux peut-être créer un thread qui interroge la dll et si une trame se présente, la transmette à mon TCANUSB qui utilisera un callback pour la transmettre au programme principal. Et le tour est joué en utilisant une autre méthode.
En fait, je veux vraiment utiliser des callbacks entre mon composant et le programme principal de manière à obtenir une interface simple pour les futurs développeurs utilisant cette interface. J'ai vu que le composant TCOMPORT utilise un principe comme ca même si je n'ai pas compris comment les données parviennent au programme principal.

Pour l'instant, je suis au point mort mais je ne déséspére pas.


Oniria
0
WhiteHippo Messages postés 1154 Date d'inscription samedi 14 août 2004 Statut Membre Dernière intervention 5 avril 2012 3
10 févr. 2012 à 11:54
Bonjour

Juste au cas où tu ne l'aurais pas vu, sur le site, dans la section "CANUSB DLL & ActiveX Driver" tu as le fichierdes drivers qui contient un exemple en Delphi2005.

Pour la création d'un composant afin d'encapsuler une DLL qui communique avec un périphérique externe, je l'ai déjà fait de nombreuses fois. Dès que j'aurais un peu plus de temps, si cela t'intéresse, je veux bien te faire un "squelette" que tu pourras adapter à ta carte (les fonctions sont souvent faites sur le même moule).

N.B. Je ne peux pas te donner un code original car ils appartiennent à mon entreprise.

Cordialement.[hr]"L'imagination est plus importante que le savoir." Albert Einstein
0
Oniria Messages postés 292 Date d'inscription dimanche 14 mars 2004 Statut Membre Dernière intervention 18 décembre 2014 3
10 févr. 2012 à 13:16
Bonjour WhiteHippo,

j'ai effectivement lu l'exemple de la carte sauf que l'exemple ne prend pas en compte le callback. Dans leurs exemples, seul le programme en C++ le fait d'où mes difficultés. Pour faire mon composant, je me suis largement inspiré de leur exemple en delphi 2005 (surtout pour la définition des fonctions de la dll).

Sinon, pour ta proposition, je suis tout à fait intéressé car j'aime bien découvrir de nouvelles choses. Mais ne prend pas tout ton temps à cela...

En tout cas, merci. Là, j'essaye la carte avec les exemples fourni et rien ne marche. alors qu'en face de l'interface, j'ai mis un calculateur qui "normalement cause".Je suis en train de me demander si cette foutu interface n'est pas HS. Je pourrais le vérifier au boulot lundi car nous avons des logiciels et des interfaces CAN et je pourrais comparer mon interface avec les autres interfaces qui fonctionnent.


Oniria
0
WhiteHippo Messages postés 1154 Date d'inscription samedi 14 août 2004 Statut Membre Dernière intervention 5 avril 2012 3
10 févr. 2012 à 13:39
En faisant travailler google, vu que moi je n'ai pas le temps , il a trouvé cela(site)
Tu y trouveras sans doute de l'inspiration.

Cordialement.[hr]"L'imagination est plus importante que le savoir." Albert Einstein
0
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
11 févr. 2012 à 17:18
Bonjour,

J'ai plus ou moins autant d'expérience en C qu'en Delphi et le code de WhiteHippo me paraît correcte. J'ai juste un doute sur le stdcall de:
Function CANUSBSetReceiveCallBack
  ( h    : DWord  
  ; cbfn : LPFNDLL_RECEIVE_CALLBACK
  ) : CANUSB_Result 
  ; stdcall ; External 'canusbdrv.dll' name 'canusb_setReceiveCallBack'
;


En effet, si la fonction est définie tel que tu nous l'a donné:
int setReceiveCallBack( CANHANDLE h,
LPFNDLL_RECEIVE_CALLBACK cbfn ) 


Alors, si la fonction est compilée avec les paramètres de compilation par défaut, sa convention d'appel est cdecl, pas stdcall.
0
Oniria Messages postés 292 Date d'inscription dimanche 14 mars 2004 Statut Membre Dernière intervention 18 décembre 2014 3
21 févr. 2012 à 17:19
Bonjour à tous et un grand merci à WhiteHippo,

la réponse à mon probléme est d'utiliser une fonction externe et de déclarer en variable globale un PCANInterne : TCANUSB.
Dans la fonction create du TCANUSB, on place PCANInterne:=Self; pour récupérer l'adresse de mon composant et ainsi pouvoir activer les fonctions callback lors de l'appel à cette fonction extérieure. J'espére que j'ai été clair pour les autres. De toute facon, dans quelques semaines (après avoir testé mon composant en long et en large) je vais le diffuser à titre d'exemple même s'il est adapté à une application spécifique, elle reprend ce petit truc qui n'est pas évident.

Oniria

Mon site web : http://www.devinfotronique.fr/
0
Rejoignez-nous