Jump to content
Xtreme .Net Talk

Recommended Posts

Posted

I would like to compile and execute code at runtime and access the main form from the runtime code.

 

Public Class Form1
   Public TestVariable As Integer = 7
   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
       ExecuteTxtCode("Form1.TestVariable = 2") 'How should I alter this????
       Me.Text = TestVariable 'Should be 2 and not the initial value of 7.
   End Sub
   Private Sub ExecuteTxtCode(ByVal Code As String)
       'What should I put here????
   End Sub
End Class

  • Leaders
Posted

Are you having more trouble compiling code at runtime, or having that code access your form?

 

A search for "vb compile at runtime" gave this result. The code in the article contains errors, but it shows you everything you need to know to compile code at runtime.

 

Note this important piece of code.

For Each ASM In AppDomain.CurrentDomain.GetAssemblies()
   PM.ReferencedAssemblies.Add(ASM.Location)
Next

This adds a reference to all loaded assemblies, including your assembly containing Form1.

 

Now that we have a reference to the assembly that defines Form1, all we need in order to get the code to interact with a Form1 is a reference to an instance of Form1. There are a few ways to do this. The code could just look through Application.OpenForms for an instance. Form1 could store an instance of itself in a public shared property that the code could read. The method I chose was to have the code being compiled to accept a Form1 in the constructor.

 

Here is the code from the article, updated to work. You'll need a mulitline textbox named "TextBox1" and a button named "Button1."

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
       Dim errors As New StringBuilder

       Try
           If TextBox1.Text.Trim <> "" Then
               Dim VBP As New VBCodeProvider
               Dim CVB As System.CodeDom.Compiler.ICodeCompiler
               CVB = VBP.CreateCompiler
               Dim PM As New System.CodeDom.Compiler.CompilerParameters
               PM.GenerateInMemory = True
               '  PM.GenerateExecutable = True
               PM.OutputAssembly = "Generated.dll"
               PM.MainClass = "ClassMain"
               PM.IncludeDebugInformation = True

               Dim ASM As System.Reflection.Assembly
               For Each ASM In AppDomain.CurrentDomain.GetAssemblies()
                   PM.ReferencedAssemblies.Add(ASM.Location)
               Next

               'Get compilation results
               Dim Results As System.CodeDom.Compiler.CompilerResults
               Results = CVB.CompileAssemblyFromSource(PM, TextBox1.Text)

               'Show possible compilation errors
               Dim Err As System.CodeDom.Compiler.CompilerError
               For Each Err In Results.Errors
                   errors.AppendLine("Error N. " & Err.ErrorNumber & _
                   " Message: " & Err.ErrorText & " Line " & Err.Line)
               Next

               'Use the compiled assembly
               Dim RunObj As New Object
               [color="Red"]Dim vArgs As Object() = {Me}[/color]

               RunObj = Results.CompiledAssembly.[color="Orange"]CreateInstance[/color]( _
                 "[color="Blue"]Generated.ClassMain[/color]", True, _
                 Reflection.BindingFlags.CreateInstance, Nothing, _
                 [color="Red"]vArgs[/color], Nothing, Nothing)

               If Not RunObj Is Nothing Then
                   Dim method As MethodInfo = RunObj.GetType().GetMethod("[color="Magenta"]DoIt[/color]")
                   method.Invoke(RunObj, _
                       BindingFlags.Static Or BindingFlags.Instance Or BindingFlags.Public Or BindingFlags.NonPublic, _
                       Nothing, Nothing, Nothing)
               Else
                   MessageBox.Show("Compile Error:" & vbCrLf & vbCrLf & errors.ToString())
               End If

           Else
               MessageBox.Show("Write VB.Net code to compile")
           End If
       Catch err As Exception
           MessageBox.Show(err.Message & " " & err.StackTrace)
       End Try
   End Sub

As you can see, the code looks for a class named "ClassMain" in the namespace "Generated", which has a method, "DoIt", and a constructor that accepts a Form1.

 

Here is the code that I used that meets those criteria.

Imports System.Windows.Forms
Imports Microsoft.VisualBasic

namespace [color="Blue"]Generated[/color]
  public class [color="Blue"]ClassMain[/color]
     public sub [color="Orange"]New[/color]([color="Red"]frm as WindowsApplication1.Form1[/color])
         frm.Text = "EXPERIMENT"
     end sub

      public shared sub [color="Magenta"]DoIt[/color]()
          messagebox.show("It works!")
      end sub

  end class
end namespace

If you enter this code and click the button, the form's caption will change to "EXPERIMENT" and a message box will display "It works!".

[sIGPIC]e[/sIGPIC]
Posted

Thank you snarfblam!

 

Actually I had already googled the site you suggested. I wanted to leave more choice for the one answering my question as I just wasn't sure they did everything in the best possible way. But if you vouch for the code sample I gues it's a proper way to do it.

 

My main problem was figuring out how to have my code access back to Form1. I'm sorry for not achieving to explain this in my original question. Anyway after seeing this piece of code

frm as WindowsApplication1.Form1

I got back on track.

 

Thanks!

  • Leaders
Posted
I'm just going to add one thing. If you're writing a program with some kind of "interpreter" or using some other scenario where the user can frequently enter and run code, understand that each time you compile code, you're compiling and loading a whole new assembly, which can't be unloaded until the application exits. Things could pile up in memory pretty quickly.
[sIGPIC]e[/sIGPIC]

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...