Ceci est une page optimisée pour les mobiles. Cliquez sur ce texte pour afficher la vraie page.

XL 2016 Pourquoi Evaluate s'exécute toujours 2 fois ?

Lu76Fer

XLDnaute Occasionnel
Bonjour,

J'ai testé sur différente version d'excel et le résultat est le même :
VB:
Function TestEval() As Boolean
    Debug.Print "TEST EN COURS ..."
    TestEval = True
End Function

Sub TestAppel()
Dim b As Boolean
    b = Evaluate("TestEval()")
    'b = [TestEval()] 'Même résultat
End Sub
Résultat :
TEST EN COURS ...
TEST EN COURS ...

Qui aurait des explications ou un lien pour m'éclairer ?
 
C

Compte Supprimé 979

Guest
Bonsoir Lu76Fer

Evaluate n'est pas fait pour ça..

Pourquoi vouloir l'utiliser pour une fonction VBA
VB:
Sub TestAppel()
  Dim b As Boolean
  b = TestEval()
End Sub
tout simplement

Bonne soirée
 

Lu76Fer

XLDnaute Occasionnel
Bonsoir BrunoM45,
Je voudrais appeler une fonction de façon dynamique via une chaîne de caractère. Je sais qu'il y a des spécificités avec Evaluate mais c'est une réaction assez étrange ...
Je souhaitais avoir plus d'infos à ce sujet
 

Lu76Fer

XLDnaute Occasionnel
Bonsoir Lu76Fer,
Si vous faites :
VB:
Sub TestAppel()
Dim b As Boolean
    b = TestEval()
End Sub
Vous n'avez qu'une seule exécution de TestEval.
Quel intérêt de faire un Evaluate ?
Ce n'est qu'un exemple car dans mon cas je souhaite passer le nom d'une fonction via une variable String.
Du coup je me demandais si on pouvait bloquer cet effet Kiscool ?
 

Lu76Fer

XLDnaute Occasionnel
Bonsoir PatrickToulon,
Je ne vois pas mais voici un exemple simplifié et même résultat, cela s'affiche 2 fois :
VB:
Function TestEval2() As Boolean
    Debug.Print "TEST EN COURS ..."
End Function

Sub TestAppel2()
    Evaluate ("TestEval2()")
End Sub
Il n'y a que si on appel la fonction depuis une feuille =TestEval2() que la fonction ne s'exécute qu'une seule fois.
 

Lu76Fer

XLDnaute Occasionnel
Je vois une solution et difficile d'utiliser Evaluate directement sans que celui-ci ne s'exécute deux fois de suite.
VB:
Function TestEval() As Boolean
    Debug.Print "TEST EN COURS ..."
    TestEval = True
End Function

Sub TestAppel2()
Dim b As Variant
    Range("A1") = "=TestEval()"
    DoEvents
    b = Range("A1")
    Range("A1") = ""
End Sub
Dommage que cette fonction ne réagisse pas mieux ... Elle est disponible après tout, pourquoi l'avoir laissé à disposition des utilisateurs si on ne peut pas l'utiliser librement ?
Personnellement, je vois juste un bug de plus.
 

Katido

XLDnaute Occasionnel
Bonjour,

Evaluate n'est effectivement pas fait pour ça, mais par exemple pour faire :
debug.Print Evaluate("3 * 5")
ce qui donne bien 15

Ou encore :
Public Sub Appel()
Debug.Print Evaluate("3 * Increment(5)")
End Sub

Public Function Increment(i%)
Test = i + 1
End Function
ce qui donne bien 18.

Je n'aurais jamais imaginé faire un print dans une fonction appelée avec Evaluate, mais quand on lance Evaluate("Test()" depuis la fenêtre d'exécution avec :
Public Function Test()
Debug.Print "aaa"
End Function
le double print est quand même déroutant.
 

patricktoulon

XLDnaute Barbatruc
re
non ce n'est pas déroutant c'est normal
evaluate fait l'operation pour l'evaluer
comme c'est une fonction a l'interieur du bin du classeur elle est donc evaluer et executer
vba te renvoie donc a un event propagation

event propagation
lorsque la fonction est lancé par evaluate
elle est appelée DANS EVALUATE et donc par conséquent dans vba
evaluate est issue des bonne vielle macro 4 qui ne fait pas partie de vba

en fait pour la faire courte
la fonction remonte jusqu'au premier parent c'est à dire au niveau module

et oui comme cette fonction est sensé faire un calcul (ou autre ) il faut bien qu'elle soit executé pour que son return renvoie le STRING DU RETURN
CAR EVALUATE EVALUE UN STRING ELLE EVALUE PAS LA FONCTION ELLE MËME

c'est pigé?

pour vous faire bien comprendre la notion de macro 4 et vba
il vous suffit de déclencher une erreur dans la la fonction
et de demamander msgbox evaluate("nom de la fonction()")
vous verrez non seulement vous n'aurez pas de message d'erreur dans la fonction mais vous n'aurez rien non plus au resultat de evaluate c'est à dire pas de msgbox
j'ajoute une ligne dans la fonction "aa"(qui ne veut rien dire et qui va me declecncher devrait me déclencher une erreur
vous verrez il ne se passe rien
VB:
Function TestEval2() As Boolean
  aa
  Debug.Print "TEST EN COURS ..."
End Function

Sub TestAppelevaluate()
    MsgBox Evaluate("TestEval2()")
End Sub

Sub TestAppelenormal()
    MsgBox TestEval2()
End Sub

j'espère que cet exemple va vous aider à comprendre
tester les deux appels
 
Dernière édition:

Lu76Fer

XLDnaute Occasionnel
Oui cela reste déroutant même si il est vrai que c'est de l'interprétation PatrickToulon (CAR EVALUATE EVALUE UN STRING ELLE EVALUE PAS LA FONCTION ELLE MËME) et les erreurs ne sont pas remontées.
Dans mon cas je désire simplement lancer une fonction dont je ne connais pas forcément le nom et j'ai trouvé une autre solution du coup en évitant d'exécuter le code au premier passage :
VB:
Private Setting As Boolean

Function TestEval3() As Boolean
    If Setting Then Setting = False: Exit Function
    Debug.Print "TEST EN COURS ..."
    TestEval3 = True
End Function

Sub TestAppel3()
Dim b As Boolean
    Setting = True
    b = Evaluate("TestEval3()")
    Debug.Print "Hello World !! Retour = " & b
End Sub
J'ai dû rajouter la variable de module Setting mais j'obtiens le résultat voulu, le code ne s'exécute qu'une fois. Le retour est bien récupérer, et la séquence d'instruction est exécuté dans l'ordre.
 

Katido

XLDnaute Occasionnel
Re,
Si, c'est déroutant car même s'il n'y a rien à évaluer ni à retourner, elle est "exécutée" 2 fois.

Voici un programme tout simple :
Public z as Integer

Public Sub Test()
z = z + 1
End Sub
Chaque fois qu'on lance Evaluate "Test()" dans la fenêtre d'exécution, la valeur de z est incrémentée 2 fois (on obtient 2, 4, 6, etc.)

En fait, la fonction n'est pas exécutée de façon standard.

On peut ajouter une instruction Stop, ça ne lui fait rien (elle marche encore 2 fois)
S'il y a une erreur (par exemple division par 0), elle n'est exécutée qu'une fois !!!

Renvoie z+2 à chaque Evaluate :
Public z As Integer, y As Integer

Public Sub Test()
z = z + 1
y = 1
End Sub

Renvoie z+2 à chaque Evaluate :
Public z As Integer, y As Integer

Public Sub Test()
Stop
z = z + 1
y = 1
End Sub

Renvoie z+1 à chaque Evaluate :
Public z As Integer, y As Integer

Public Sub Test()
z = z + 1
y = 1 / 0
End Sub

Il n'y a aucune raison de faire un Evaluate dans ce cas où il n'y a rien à ramener, mais ce fonctionnement n'est quand même pas très catholique.
Donc n'utiliser Evaluate que pour évaluer une chaine.
 

Lu76Fer

XLDnaute Occasionnel
Oui en cas d'erreur le code est interrompu ! Il est vrai que cela reste plutôt casse-gueule surtout qu'on a pas de retour d'erreur. Mais bon c'est bien de savoir qu'elles sont les possibilités techniques .

Merci à tous de votre participation à la discussion.
 

Discussions similaires

Les cookies sont requis pour utiliser ce site. Vous devez les accepter pour continuer à utiliser le site. En savoir plus…