IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

VB.NET Discussion :

Comment exécuter du code VBA


Sujet :

VB.NET

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2002
    Messages
    168
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 168
    Par défaut Comment exécuter du code VBA
    Bonjour,
    Je cherche à exécuter du code VBA (voir VB.net) dynamiquement. Je m'explique...

    Je souhaiterais appliquer un petit traitement à une valeur chaine de mon programme. Ce traitement serait tapé par l'utilisateur dans une boite texte du programme. Donc je voudrais évaluer les instructions tapées par l'utilisateur sur une variable de mon programme et récupérer le résultat.

    Je sais pas si j'ai été très clair et si c'est possible...
    Merci de votre lecture.

    Alexandre

  2. #2
    Expert éminent Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 197
    Par défaut
    c'est pas très explicite
    mais vb.net permet la compilation d'instructions à la volée
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2002
    Messages
    168
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 168
    Par défaut
    Je vais tenter d'être plus explicite.

    A un moment donné, j'ai une valeur (une chaine) dans mon programme. Celle-ci doit être soumis à un traitement (ex: enlever l'espace du milieu). Donc je voudrais permettre à l'utilisateur de taper quelques lignes en vba ou vb.net et d'éxecuter ce code (qui supprimerait l'espace) dynamiquement sur cette valeur et d'en récupérer le résultat.

    Je demande ce bout de code à l'utilisateur car à chaque utilisation, le traitement varie.

    J'espère avoir été plus clair.
    Sinon tu dis qu'il est possible d'éxecuter du code à la volée. Tu as quelques pistes à m'indiquer ?
    Merci de ta réponse en tout cas !

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2002
    Messages
    168
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 168
    Par défaut
    J'ai trouvé cet ensemble de classes : http://msdn2.microsoft.com/fr-fr/lib...cx(VS.80).aspx

  5. #5
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    J'ai l'impression que tu essayes de faire un lexer-parser. par contre, je ne comprends pas du tout ce que vient faire du VBA dans cette histoire

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2002
    Messages
    168
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 168
    Par défaut
    Pour l'histoire du VBA, je pensais que d'éxecuter du code VBA en VB.NET serait plus simple que directement du code VB.NET.

    Je cherche juste à appliquer des traitements de chaine sur des données de mon programme. La particularité est que ce traitement est tapé par l'utilisateur en VB.NET ou VBA (je n'implémenterais qu'une solution, mais l'un ou l'autre me convient).

  7. #7
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par Alexandre` Voir le message
    Pour l'histoire du VBA, je pensais que d'éxecuter du code VBA en VB.NET serait plus simple que directement du code VB.NET.
    C'est bien connu que, par exemple, exécuter du Cobol en Fortran ou de l'Algol 68 en C c'est une voie plus simple que de rester dans le langage

    C'est vrai, quoi, c'est pas drôle des programmes à langage unique.

    Bon, sérieusement, qu'est ce qui a bien pu te faire penser que mélanger deux techno et deux langages allait te faciliter les chose ? j'ai beau me creuser la cervelle, j'arrive pas à comprendre (et pourtant, dans ma déjà très longue carrière en IT, les raisonnements tordus je croyais les avoir croisés presque tous ...... )

    Je cherche juste à appliquer des traitements de chaine sur des données de mon programme. La particularité est que ce traitement est tapé par l'utilisateur en VB.NET ou VBA (je n'implémenterais qu'une solution, mais l'un ou l'autre me convient).
    Donc, tu veux faire un Parser de formule, mais à partir d'une syntaxe VB ? (ce qui suppose que l'utilisateur connaisse VB, mais je suppose que c'est un pré-requis que tu as envisagé, même si je le trouve quelque peu capillotracté) ?

    Une solution simple en .Net : comme déjà dit par sperot51, compilation à la volée; en gros du prend ta formule et tu la compile, et tu l'exécutes (enfin je crois que c'est ce que tu veux faire).

    Fait donc une recherche avec ces termes, tu devrais trouver des exemples et/ou des tutoriels sans problème.

  8. #8
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2002
    Messages
    168
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 168
    Par défaut
    Enfait l'idée d'utiliser un autre langage me vient du monde du jeu :
    Utiliser un langage de script (lua ou autre) dans un programme C++ par exemple... je me suis dis que VB.NET avait peut être des classes pour gérer son ancetre le vba. Mais apparement non.

    C'est un outil interne qui me simplifierait grandement la vie, donc oui tous les utilisateurs sont des développeurs .NET.

    J'explique un cas simple de l'application :

    J'ai un ensemble de variable source, et un ensemble de variable de destination.
    Je les relis ensemble, ex :
    var_source_1 à var_dest_2

    Lors de cette liaison je demande à l'utilisateur si il veut effectuer un traitement lors du passage de valeur. Il aurait alors la possibilité d'écrire une petite fonction (dont la signature lui serait imposé et l'objet de retour aussi) qui traite la valeur de var_source_1. Je récupère cette valeur et je la balance dans var_dest_2.

    La signature serait proposée automatiquement avec en paramètre une variable qui contient la valeur de var_source_1. Le type de l'objet de retour est lui aussi imposé afin que que je puisse le récupérer aisément.

    C'est une reflexion toute nouvelle, donc il est possible que ce que je souhaite faire ne soit pas possible.
    Merci pour ton post, je vais continuer mes recherches.

  9. #9
    Expert éminent Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 197
    Par défaut
    il est tout à fait possible de faire taper du code vb.net à quelqu'un dans un textbox et d'utiliser ce qu'il a tapé
    à priori tu pourrais meme lui laisser le choix de vb ou c#

    le principe c'est de donner le code source à un objet et de lui dire de le compiler
    la compilation d'une petite fonction c'est une centaine de millisecondes
    ensuite tu obtient un assembly .NET (sur le disque ou en mémoire, c'est au choix)
    à partir de cet assembly tu peux faire de la reflection, tu peux donc obtenir une variable methodinfo et faire des invoke dessus

    c'est pas ce qu'il y a de plus simple en .NET donc il faut que tu aies quelques bases à priori

    à chercher : codedomprovider, compilerparameters, vbcodeprovider peut etre aussi
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  10. #10
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2002
    Messages
    168
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 168
    Par défaut
    Merci pour cette précision !

  11. #11
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Bon, ton problème m'a amusé, alors je t'ai torché (quick and dirty) un début de solution, qui "bouffe" des formules binaires simples avec les 4 opérations (10 + 2, 15 * 4.5, 22 / 7 etc... attention, faut mettre les blancs !!! - donc il faut que tu revois le parser de génération pour admettre des forumules pus complexes bien sur - , mais cela te donne l'idée générale :

    (il est prévu pour être hosté dans une form de test, avec un textBox pour la formule, deux labels - un pour le résultat de compile, un pour le resultat de calcul - et une listbox (lbCompileErrors) pour les erreurs de compile).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
     
     
          private void button1_Click( object sender, EventArgs e )
            {
                CodeCompileUnit unit = prepareCompileUnit( textBox1.Text );
                Assembly dynamicAssembly = compileCSharpCode( unit );
                if (dynamicAssembly != null)
                {
                    object formulaComputer = dynamicAssembly.CreateInstance( "Compute.formulaComputing", true );
                    MethodInfo computeFormula = formulaComputer.GetType().GetMethod( "computeFormula" );
                    double formulaResult = (double) computeFormula.Invoke( formulaComputer, null );
                    lblResult.Text = formulaResult.ToString();
                }
            }
     
     
            private CodeBinaryOperatorExpression computeBasicFormula( string basicFormula )
            {
                CodeBinaryOperatorType binaryOperator;
                string[] items = basicFormula.Split( ' ' );
                if(items == null || items.Length != 3)
                {
                    throw new Exception("Invalid or unsupported formula");
                }
                CodeExpression left = new CodePrimitiveExpression(Convert.ToDouble( items[0] ));            
                CodeExpression right = new CodePrimitiveExpression(Convert.ToDouble(items[2]));
                string operateur = items[1];
                if (operateur == "-")
                {
                    binaryOperator = CodeBinaryOperatorType.Subtract;
                }
                else if (operateur == "+")
                {
                    binaryOperator = CodeBinaryOperatorType.Add;
                }
                else if (operateur == "/")
                {
                    binaryOperator = CodeBinaryOperatorType.Divide;
                }
                else if (operateur == "*" || operateur == "x")
                {
                    binaryOperator = CodeBinaryOperatorType.Multiply;
                }
                else
                {
                    throw new Exception( "Invalid or unsupported operator" );
                }
                return new CodeBinaryOperatorExpression( left, binaryOperator, right );
            }
     
         private Assembly compileCSharpCode( CodeCompileUnit compileunit )
            {
                CompilerParameters cp = new CompilerParameters();
                cp.ReferencedAssemblies.Add( "System.dll" );
                cp.GenerateExecutable = false;
                cp.GenerateInMemory = true;
     
                // Invoke compilation.
                CSharpCodeProvider provider = new CSharpCodeProvider();
                CompilerResults cr = provider.CompileAssemblyFromDom( cp, compileunit );
     
                if (cr.Errors.Count > 0)
                {
                    lblCompileStatus.Text = String.Format( "{0} error in compile.",
                                                cr.Errors.Count );
                    // Display compilation errors.
                    foreach (CompilerError ce in cr.Errors)
                    {
                        lbCompileErrors.Items.Add( ce.ToString() );
                    }
                }
                else
                {
                    lblCompileStatus.Text = String.Format( "Source {0} built into {1} successfully.",
                                                                compileunit.Namespaces[0],
                                                                cr.CompiledAssembly.FullName );
                }
                // Return the results of compilation.
                return (cr.Errors.Count == 0) ? cr.CompiledAssembly : null;
            }
     
            private CodeCompileUnit prepareCompileUnit( string formulaString )
            {
                CodeNamespace compute = new CodeNamespace( "Compute" );
                compute.Imports.Add( new CodeNamespaceImport( "System" ) );
     
                CodeCompileUnit compileUnit = new CodeCompileUnit();
                compileUnit.Namespaces.Add( compute );
     
                CodeTypeDeclaration formulaComputing = new CodeTypeDeclaration( "formulaComputing" );            
                compute.Types.Add( formulaComputing );
                CodeMemberMethod computeFormulaCode = new CodeMemberMethod();
                computeFormulaCode.Attributes = MemberAttributes.Public;
                computeFormulaCode.Name = "computeFormula";
                computeFormulaCode.ReturnType = new CodeTypeReference( typeof( double ) );
                CodeBinaryOperatorExpression formula = computeBasicFormula( formulaString );
                CodeMethodReturnStatement computeFormulaReturnStatement = new CodeMethodReturnStatement( formula );
                computeFormulaCode.Statements.Add( computeFormulaReturnStatement );
                formulaComputing.Members.Add( computeFormulaCode );
                return compileUnit;
            }
    et ca marche !

    Bien entendu, cela ne présente pas d'autre interêt que la génération à al volée (pour des formules aussi simplettes, un analyseur de chaine serait bien plus simple), mais te fournit une base de travail.

    Maintenant pour traduire en VB.Net, tu trouves quelqu'un d'autre.

  12. #12
    Membre confirmé
    Profil pro
    Inscrit en
    Août 2002
    Messages
    168
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 168
    Par défaut
    Merci pour cette réponse !

    J'ai fais quelques essais aussi et voilà comment je vais procéder je pense :

    L'application va créer un fichier maclass.vb avec l'ensemble des fonctions créées (une par liaison).

    Lorsque toutes les fonctions sont écrites, et que l'utilisateur passe à la 2eme étape de l'application. Je génère une dll à partir de ce fichier .vb que je réexploite lors de mon traitement.

    Voici la fonction que j'ai trouvé qui permet de générer un exe ou une dll (Qui n'est pas très loin de la tienne). Désolé je n'ai plus la source :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
        Public Shared Function CompileCode(ByVal provider As CodeDomProvider, _
        ByVal sourceFile As String, ByVal exeFile As String) As Boolean
     
            Dim cp As New CompilerParameters()
     
            ' Generate an executable instead of 
            ' a class library.
            cp.GenerateExecutable = False
     
            ' Set the assembly file name to generate.
            cp.OutputAssembly = exeFile
     
            ' Generate debug information.
            cp.IncludeDebugInformation = True
     
            ' Add an assembly reference.
            cp.ReferencedAssemblies.Add("System.dll")
            cp.ReferencedAssemblies.Add("Microsoft.VisualBasic.dll")
     
            ' Save the assembly as a physical file.
            cp.GenerateInMemory = False
     
            ' Set the level at which the compiler 
            ' should start displaying warnings.
            cp.WarningLevel = 3
     
            ' Set whether to treat all warnings as errors.
            cp.TreatWarningsAsErrors = False
     
            ' Set compiler argument to optimize output.
            cp.CompilerOptions = "/optimize"
     
            ' Set a temporary files collection.
            ' The TempFileCollection stores the temporary files
            ' generated during a build in the current directory,
            ' and does not delete them after compilation.
            cp.TempFiles = New TempFileCollection(".", True)
     
            If provider.Supports(GeneratorSupport.EntryPointMethod) Then
                ' Specify the class that contains 
                ' the main method of the executable.
                cp.MainClass = "Samples.Class1"
            End If
     
            If provider.Supports(GeneratorSupport.Resources) Then
                ' Set the embedded resource file of the assembly.
                ' This is useful for culture-neutral resources, 
                ' or default (fallback) resources.
                'cp.EmbeddedResources.Add("Default.resources")
     
                ' Set the linked resource reference files of the assembly.
                ' These resources are included in separate assembly files,
                ' typically localized for a specific language and culture.
                'cp.LinkedResources.Add("nb-no.resources")
            End If
     
            ' Invoke compilation.
            Dim cr As CompilerResults = _
                provider.CompileAssemblyFromFile(cp, sourceFile)
     
            If cr.Errors.Count > 0 Then
                ' Display compilation errors.
                Console.WriteLine("Errors building {0} into {1}", _
                    sourceFile, cr.PathToAssembly)
                Dim ce As CompilerError
                For Each ce In cr.Errors
                    Console.WriteLine("  {0}", ce.ToString())
                    Console.WriteLine()
                Next ce
            Else
                Console.WriteLine("Source {0} built into {1} successfully.", _
                    sourceFile, cr.PathToAssembly)
                Console.WriteLine("{0} temporary files created during the compilation.", _
                        cp.TempFiles.Count.ToString())
            End If
     
            ' Return the results of compilation.
            If cr.Errors.Count > 0 Then
                Return False
            Else
                Return True
            End If
        End Function 'CompileCode
    Ca fonctionne plutôt pas mal. J'ai pu générer une dll et l'exploiter directement dans le programme.

    Je suis au niveau des tests, donc je n'ai pas pousser la chose très loin.

    En tout cas merci pour ton exemple !

    Edit : Orthographe

  13. #13
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Accessoirement, tu peux avoir la même chose mais qui bouffe n'importe quelle formule retournant un double

    en remplaçant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    CodeBinaryOperatorExpression formula = computeBasicFormula( formulaString );
    par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
     CodeSnippetExpression formula = new CodeSnippetExpression( formulaString );
    Et en virant toute le code de computeBasicFormula qui ne sert plus à rien du tout.

    Plus simple et beaucoup plus réaliste !

    Ca bouffe ensuite des trucs du style "Math.Sin(2*Math.PI) * Math.Cos(40 / 2 * Math.PI)".

Discussions similaires

  1. [VBA]Comment, dans le code VBA, hasher un mot de passe ?
    Par lord abortion dans le forum VBA Access
    Réponses: 6
    Dernier message: 18/04/2007, 16h41
  2. Réponses: 44
    Dernier message: 02/08/2006, 16h12
  3. VBA-E comment exécuter un code sur un classeur complet?
    Par djulegnome dans le forum Macros et VBA Excel
    Réponses: 12
    Dernier message: 13/06/2006, 12h29
  4. Réponses: 7
    Dernier message: 30/03/2006, 15h43
  5. Réponses: 7
    Dernier message: 03/02/2005, 17h20

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo