Renvoi de valeurs par référence en VBA

Résolu
granbapt Messages postés 20 Date d'inscription jeudi 24 mai 2012 Statut Membre Dernière intervention 27 septembre 2012 - 6 juin 2012 à 17:13
granbapt Messages postés 20 Date d'inscription jeudi 24 mai 2012 Statut Membre Dernière intervention 27 septembre 2012 - 14 juin 2012 à 15:05
Bonjour à tou(te)s,

J'ai une DLL contenant une fonction que je voudrais utiliser dans Excel. Ladite fonction renvoie plusieurs valeurs et utilise donc des références :

void A2_Aff_lineique(real_T freq, real_T T, real_T ro, real_T p, real_T *Aff_tot,real_T *Aff_02, real_T *Aff_H20)


Mon problème est que je ne sais pas comment on déclare et on utilise ce genre de fonction...

J'étais bien tenté d'écrire :

Declare Function Aff_Gaz Lib "DLL_Affaiblissement2" Alias "_A2_Aff_lineique" (ByVal freq As Double, ByVal T As Double, ByVal ro As Double, ByVal p As Double, ByRef Aff_tot As Long, ByRef Aff_02 As Long, ByRef Aff_H20 As Long)


mais ça ne marche pas ! En effet, cette fonction ne renvoie rien, et je ne sais même quoi lui fournir pour les trois derniers arguments qui sont définis par référence...(les quatre premiers paramètres étant saisies dans différentes cellules par l'utilisateur).

Si vous avez des conseils ou des éclaircissements à m'apporter, je suis preneur !!

Merci d'avance

8 réponses

granbapt Messages postés 20 Date d'inscription jeudi 24 mai 2012 Statut Membre Dernière intervention 27 septembre 2012 1
14 juin 2012 à 15:05
Bon, ça y est ça fonctionne !
Le problème n'est (en général) pas là où on regarde... Dans mon cas c'était dans le code C que l'export de la fonction vers la DLL était mal fait.

Pour en finir avec ce sujet, et si ça intéresse certains voilà comment j'ai codé en VBA mon appel à la fonction de la DLL (en remettant ma fonction en C dans son état initial, c'est à dire qui sort un type void).


Public Type Aff
    A_tot As Double
    A_02 As Double
    A_H20 As Double
End Type

Declare Sub Aff_Gaz Lib "DLL_Affaiblissement2" Alias "_A2_Aff_lineique@44" (ByVal freq As Double, ByVal T As Double, ByVal ro As Double, ByVal p As Double, ByRef Aff_tot As Double, ByRef Aff_02 As Double, ByRef Aff_H20 As Double)

Dim Aff_tot As Double, Aff_H20 As Double, Aff_02 As Double, A_Gaz As Aff

Public Function Affaiblissement_Gaz(ByVal freq As Double, ByVal T As Double, ByVal ro As Double, ByVal p As Double) As Aff
    
    Call Aff_Gaz(freq, T, ro, p, Aff_tot, Aff_02, Aff_H20)
    
    Affaiblissement_Gaz.A_tot = Aff_tot
    Affaiblissement_Gaz.A_02 = Aff_02
    Affaiblissement_Gaz.A_H20 = Aff_H20
    
End Function

Public Function Affaiblissement_total(ByVal freq As Double, ByVal T As Double, ByVal ro As Double, ByVal p As Double) As Double
    
    A_Gaz = Affaiblissement_Gaz(freq, T, ro, p)
    
    Affaiblissement_total = A_Gaz.A_tot


    
End Function

Public Function Affaiblissement_02(ByVal freq As Double, ByVal T As Double, ByVal ro As Double, ByVal p As Double) As Double
    
    A_Gaz = Affaiblissement_Gaz(freq, T, ro, p)
    

    Affaiblissement_02 = A_Gaz.A_02

    
End Function

Public Function Affaiblissement_H20(ByVal freq As Double, ByVal T As Double, ByVal ro As Double, ByVal p As Double) As Double
    
    A_Gaz = Affaiblissement_Gaz(freq, T, ro, p)
    
    Affaiblissement_H20 = A_Gaz.A_H20
    
End Function
3
cs_Jack Messages postés 14006 Date d'inscription samedi 29 décembre 2001 Statut Modérateur Dernière intervention 28 août 2015 79
7 juin 2012 à 00:49
Salut

Du peu que je connaisse (c'est du C, non ?), si on voit "void", c'est que la commande ne renvoie rien, donc, à priori, je verrais plutôt une Sub qu'une Function.

Quant aux paramètres, Real_T semble représenter des Double (d'après ce que tu écris).
Pourquoi alors tes 3 derniers paramètres sont-ils déclarés "As Long" ?

En fait, ce n'est pas que ta Sub ne renvoie pas de valeur; elle en renvoie; mais pas en résultat unique : D'après ce que tu expliques, les 3 derniers paramètres sont surement les valeurs renvoyées par le fonction.
Il te suffit donc de dimensionner une variable (rendu obligatoire par le ByRef) pour chacun de ces paramètres et de les passer en argument - ils devraient revenir avec des valeurs.

Vala
Jack, MVP VB
NB : Je ne répondrai pas aux messages privés

Le savoir est la seule matière qui s'accroit quand on la partage (Socrate)
0
granbapt Messages postés 20 Date d'inscription jeudi 24 mai 2012 Statut Membre Dernière intervention 27 septembre 2012 1
7 juin 2012 à 14:41
Merci pour ces explications, je vais essayer de voir si je peux les appliquer (je suis novice en VBA...)
0
granbapt Messages postés 20 Date d'inscription jeudi 24 mai 2012 Statut Membre Dernière intervention 27 septembre 2012 1
7 juin 2012 à 15:05
Petite précision tout de même :

Si j'utilise l'instruction "Declare" pour récupérer ma fonction dans la dll, je ne peux pas modifier cette fonction, non?
Si je veux donc suivre tes conseils, ne faut-il pas que je crée une Sub (ou une Function) qui utilise la fonction de la dll avec les corrections que tu m'as suggéré (définition d'une variable pour chaque paramètre de sortie et attribution des valeurs calculées)?

Qu'en penses-tu ?
(N'étant pas très expérimenté j'espère que je suis assez claire, et que je ne dis pas trop de bêtises )

Merci !
0

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

Posez votre question
granbapt Messages postés 20 Date d'inscription jeudi 24 mai 2012 Statut Membre Dernière intervention 27 septembre 2012 1
7 juin 2012 à 17:04
Bon, j'en rajoute encore une couche (mais faut dire aussi que j'en tiens une sacrée...), là je patauge comme il faut.

Voilà ce que j'ai essayé de faire :

Declare Sub Aff_Gaz Lib "DLL_Affaiblissement2" Alias "_A2_Aff_lineique" (ByVal freq As Double, ByVal T As Double, ByVal ro As Double, ByVal p As Double, ByRef Aff_tot As Double, ByRef Aff_02 As Double, ByRef Aff_H20 As Double)

Public Function Affaiblissement_Gaz(ByVal freq As Double, ByVal T As Double, ByVal ro As Double, ByVal p As Double) As Double

Dim Aff_tot As Double, Aff_H20 As Double, Aff_02 As Double
Aff_Gaz(freq, T, ro, p, Aff_tot, Aff_H20, Aff_02)
Affaiblissement_Gaz = Aff_tot
End Function


Alors ça ne va pas te surprendre...ça ne marche pas !!

En gros, d'après tes conseils ce que je me suis dit c'était :
1. Je déclare une Sub qui va chercher ma fonction _A2_Aff_lineique dans la dll

2. Comme ma Sub ne renvoie rien, je definis une fonction qui prendra en entree les 4 parametres que je connais et renverra un Double (idealement il faudrait qu'elle en revoie trois mais on va deja se satisfaire d'un...)

3. Dans cette fonction:
__3.1 je définis mes trois variables censées accueillir les "sorties" passées en référence dans ma Sub
__3.2 je lance la Sub (pb : je ne peux pas l'attribuer à une variable puisqu'elle ne renvoie rien, ni la mettre sans rien comme je l'ai fait dans le code...)
__3.3 je récupère mon résultat

C'était pas idiot, non ?!

Si quelqu'un peut me dire ce j'ai raté dans l'histoire là, ça m'aiderait grandement !

Merci bien
0
cs_Jack Messages postés 14006 Date d'inscription samedi 29 décembre 2001 Statut Modérateur Dernière intervention 28 août 2015 79
8 juin 2012 à 16:48
Pourquoi avoir tout basculé en ByVal ?
Le C ne fonctionne qu'avec les adresses des variables, donc ByRef serait plus judicieux.

Il faut que tu comprennes les avantages et inconvénients des méthodes ByVal et ByRef, c'est important - pas mal de sources la dessus.
Si tu déclares un Sub/Function comme ceci :
Declare Sub Toto Lib "file.xxx"( _
     ByVal ParamA As Long, ByRef ParamB As Long)
la variable ParamB sera la seule à pouvoir redescendre une valeur de la Sub vers l'appelant - ByRef signifie (entre autre) que le contenu de ta variable peut être altéré par la Sub, ce qui est le but dans ton cas.
0
granbapt Messages postés 20 Date d'inscription jeudi 24 mai 2012 Statut Membre Dernière intervention 27 septembre 2012 1
11 juin 2012 à 09:27
Merci pour ta réponse !

Au début j'ai fait des analogies d'un côté entre le ByVal et le fait que ma fonction en C prend en entrée la valeur des paramètres, et d'un autre côté entre le ByRef et le fait que ma fonction en C prend des pointeurs sur les variables censées ressortir les résultats.

Je n'avais pas vraiment vu ça comme tu l'expliques, mais au final j'ai l'impression que ça colle plutôt pas mal : toutes les données en ByVal sont des paramètres qui ne sont pas destinés à être modifiés (puisque ce sont simplement des entrées)...et les Aff_*** en ByRef sont les sorties. Qu'en penses-tu ?

Mon problème reste donc toujours le même, il faut que je trouve comment appeler ma fonction et comment récupérer les trois valeurs Aff_tot, Aff_02 et Aff_H20...
0
granbapt Messages postés 20 Date d'inscription jeudi 24 mai 2012 Statut Membre Dernière intervention 27 septembre 2012 1
13 juin 2012 à 11:33
Bon, j'ai avancé sur le sujet mais ça coince encore...

Tout d'abord pour me faciliter la vie, j'ai modifié (à contre cœur) mon code C : ma fonction
void A2_Aff_lineique(real_T freq, real_T T, real_T ro, real_T p, real_T *Aff_tot,real_T *Aff_02, real_T *Aff_H20) 

est devenue
int A2_Aff_lineique(real_T freq, real_T T, real_T ro, real_T p, real_T *Aff_tot,real_T *Aff_02, real_T *Aff_H20)

et renvoie 1 (simplement pour pouvoir l'appeler plus aisément en VBA (je ne sais pas si c'est une bonne idée mais je n'en ai plus d'autre...)

J'ai donc maintenant dans mon code VBA :

Declare Function Aff_Gaz Lib "DLL_Affaiblissement2" Alias "_A2_Aff_lineique" (ByVal freq As Double, ByVal T As Double, ByVal ro As Double, ByVal p As Double, ByRef Aff_tot As Double, ByRef Aff_02 As Double, ByRef Aff_H20 As Double) As Integer

Dim Aff_tot As Double, Aff_H20 As Double, Aff_02 As Double

Function Affaiblissement_Gaz(ByVal freq As Double, ByVal T As Double, ByVal ro As Double, ByVal p As Double) As Double
    
    y =  Aff_Gaz(freq, T, ro, p, Aff_tot, Aff_02, Aff_H20)
    
    Affaiblissement_Gaz = Aff_tot
    
End Function


Lorsque je saisis les valeurs des différents paramètres dans les cellules et que je tape la commande =Affaiblissement_Gaz(B2;B3;B4;B5) dans la case Excel destinée au résultat j'obtiens #VALEUR! .

Avez-vous une idée du problème ?
Merci d'avance !!


P.S :
Ça, c'est pour récupérer une seule des trois valeurs qui m'intéressent. Quand j'y serai parvenu (je ne désespère pas), on m'a conseillé la stratégie suivante pour récupérer les différentes valeurs souhaitées

Public Type Aff
    Aff_tot As Double
    Aff_02 As Double
    Aff_H20 As Double
End Type


et dans la fonction :
Aff.Aff_tot =...
Aff.Aff_02=...
Aff.Aff_H20=...
0
Rejoignez-nous