Bonjour,
Quelqu'un a déjà exécuté du code VBA généré à la volé dans une même fonction/procédure ?
Cordialement,
Version imprimable
Bonjour,
Quelqu'un a déjà exécuté du code VBA généré à la volé dans une même fonction/procédure ?
Cordialement,
Salut Fabrice !!!
Waw ! Dans quoi tu te lances là ???
Bon, alors, générer du code ... ok
Exécuter le code généré...ok
Mais que la fonction génère elle-même son code pour s'exécuter, cela me pose un problème quand même !
Tu peux entrer plus en détail dans ton explication ?
Ca sent le challenge !
Salut Max,
Le but aurait été de générer du code dans une fonction existante, mais toujours la même (et c'est là le hic).
On la vide si elle est remplie, puis on la rempli avec du code, on l'éxécute... ainsi de suite autant de fois qu'on en a besoin et avec un code différent.
Après quelques tests on s'aperçois que pour la première sa fonctionne, puis à la deuxième génération, bien que le code y soit, il exécute toujours la première. Sans compter les instabilités récurentes (point d'arrêts impossible, remontée d'erreur aléatoire/voire impossible, plantages...)
La seule chose que j'ai fait et qui reprennait ce concept de calcul à la volée c'est avec un Eval(). Mais ce n'est pas suffisant, il voudrait y coller des procédures complètes. Perso je pense que VBA seul n'est pas prévu pour un tel fonctionnement.
Cordialement,
Ah oui... je comprends mieux...
Dans ce cas, je présume que c'est parce que, lors de la première exécution, il y a compilation et qu'ensuite, il utilise la version compilée, peu importe le texte généré dans le module.
Ceci expliquerait complètement les symptômes que tu décris.
Bonjour Loufab et Maxence
pour écrire et ré-écrire une fonction dans un module de form par exemple, la difficulté est de supprimer préalablement le code placé antérieurement
Voici un code qui supprime une procédure qui commence par StrProc (qui peut être un sub ou une function) dans un formulaire strFrm préalablement ouvert en mode Design
quand à écrire un module à la volée, par exemple :Code:
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 Public Sub Delete_VBA_Procedure(strFrm As String, strProc As String) Dim ProcKind As VBIDE.vbext_ProcKind Dim oMod As Module, startLine As Integer, numLines As Long Dim ProcName As String Dim oForm As Form, oCtl As Control, i As Integer, j As Integer Dim nLoop As Long, debutLigSuppr As Long, nbLigSuppr As Long debutLigSuppr = 0 Set oForm = Forms(strFrm).Form Set oMod = oForm.Module ' déterminer le début et le nombre des lignes à supprimer ' ------------------------------------------------------- With oMod nLoop = 0 Do Until numLines >= .CountOfLines nLoop = nLoop + 1 If nLoop = 1 Then numLines = .CountOfDeclarationLines + 1 Else numLines = .ProcStartLine(ProcName, ProcKind) + _ .ProcCountLines(ProcName, ProcKind) + 1 End If ProcName = .ProcOfLine(numLines, ProcKind) Debug.Print ProcName & vbTab & vbTab & numLines If ProcKind = vbext_pk_Proc Then If Left(ProcName, Len(strProc)) = strProc Then ' on stocke le début et la fin des lignes debutLigSuppr = .ProcStartLine(ProcName, ProcKind) nbLigSuppr = .ProcCountLines(ProcName, ProcKind) Debug.Print "A supprimer: " & ProcName & " nblignes: " & nbLigSuppr _ & " depuis: " & debutLigSuppr Exit Do End If End If Loop ' On supprime les lignes ' --------------------- If debutLigSuppr > 0 Then 'si le module a été trouvé .DeleteLines startLine:=debutLigSuppr, Count:=nbLigSuppr End If End With Exit_0: Set oMod = Nothing Set oForm = Nothing End Sub
Bon usageCode:
1
2
3
4
5
6
7
8
9
10 ... Case "DATE DE VALEUR": startLine = oMod.CreateEventProc("BeforeUpdate", .Name) oMod.InsertLines startLine + 1, _ "If Not isNothing(Me.ActiveControl) And Not IsDate(Me.ActiveControl) Then" & vbCrLf _ & "MsgBox " & Chr(34) & "La date saisie n'est pas correcte. Recommencez" & Chr(34) & vbCrLf _ & "Cancel = True" & vbCrLf _ & "Exit Sub" & vbCrLf _ & "End If"
:D
Bonjour Micniv,
Merci pour le code, j'ai déjà tout ce qu'il faut ;). Le problème ne vient pas de l'écriture du code dans la procédure mais plutot du remplacement de celui-ci.
Je poste les 2 fichiers.
Il y a le lanceur et la bibliothèque.
Ouvrez le lanceur afficher le code et lancer la procédure ManipuleModules.
En y mettant des stop on peut voir les différents codes s'y écrire. Mais il n'exécute toujours que le premier, quel qu'il soit.
[EDIT] la cgNewBody3 comporte volontairement une erreur. Elle n'est pas remontée (du fait de la non exécution ?). Si on la passe en premier la réaction n'est pas habituelle d'une erreur.
La compilation peut en effet être une cause. J'ai fait un test avec des demande de compilation entre chaque... idem.
Cordialement,
Effectivement, dans l' exécution multiple d'une procédure unique,
le code de la fonction fCalcul n'est pas rechargé en mémoire
alors que dans des procédures distinctes il est rechargé.
Il faudrait donc pouvoir décharger (unload , Clear ... ?) le code d'une fonction chargée en mémoire ...
A suivre:?
Effectivement je crois que le problème est là.
Je suis ne train d'expérimenter cette piste.
Quand on exécute à la suite dans le même module voici la liste des pointeurs :
163605496
résultat 100
163605496
résultat 100
163605496
résultat 100
Lorsqu'on exécute 1 par 1 via la fenêtre d'exécution :
163605568
résultat 38
163605640
résultat 100099
163605856
résultat 100
Je poursuis mes investigations.
juste pour aide éventuelle
Si tu arrives à avoir le handle de la mise en mémoire de Fcalcul moi, je n'y suis pas arrivé)
alors tu peux peut-être utiliser localfree() pour la libérer ...
Bonne suiteCitation:
'--------------------------Memory API
Private Declare Function LocalAlloc Lib "kernel32" (ByVal uFlags As Long, ByVal uBytes As Long) As Long
Private Declare Function LocalFree Lib "kernel32" (ByVal hMem As Long) As Long
...
'Free memory associated with file
Call LocalFree(lptrBuffer)
...
J'ai encapsulé fCalcul dans une classe (cCalcul instancié dans l'objet Ccalc) pour pouvoir la décharger de la mémoire.
- même problème
J'ai mis des traceurs de pointeur mémoire (comme indiqué dans mon mail précédent) à l'aide de la fonction VBA :
Puis avec l'API HeapFree j'ai fait une tentative de désalloc... jolie plantage (est-ce la bonne méthode ?!).Code:ObjPtr(Ccalc)
Je viens d'essayer avec l'API que tu as posté.
- pas de plantage mais pas de désalloc, même comportement.
J'ai essayé en utiliser un Getter et une méthode.
- même problème.
Au vu de l'instabilité je pense que même si ça fonctionne, cela restera un nid à problèmes. Je vais gratter encore un peu mais sans grand espoir.
Cordialement,
Sous 2010, l'exécution de ton code m'a fait un beau plantage !
Comme je le disait c'est tellement capilotractée comme approche que ça rend le tout instable.
Je suis sous 2010 chez moi et 2007 au boulot et ça part des fois en cacahuète. :lol:
fabrice,
J'ai peur que cela ne fonctionne jamais.
Comme je te le disais précédemment, ce qui est exécuté, c'est du code "compilé". Pas le code du module.
Pour que cela fonctionne, il faudrait recompiler le code alors que tu es cours d'exécution !
Gaaarglll !!!!
C'est bien le sentiment que j'ai eu lorsqu'on m'a présenté l'idée.
Ce fut un bel exercice de style.
Merci à tous. :ccool:
salut,
je propose de générer et d'exécuter non pas du vba mais du vbs.
Tu écrirais le contenu dans un fichier texte, et appellerai le fichier en question par Shell :)
Je fais la même chose en batch pour mes taches planifiées :ccool:
J'avais pensé à du PL/SQL puisqu'on utilise Oracle et SQL server. Mais VBS en effet c'est peut-être plus léger. :ccool:
Faut voir si on peut récupérer une valeur de retour et comment.
Il y a aussi la génération de MACRO, il me semble qu'elles échappent au problème de l'accde.