The .NET Developer Community

Dynamically Read, Compile, and Run Source Code From a Text File

Here is a simple tutorial on how to read, compile, and run code that is written in a text file. In this example, we will be reading properly formatted VB.NET code from a text file which will change the text of a TextBox in a Windows Forms application to "Hello vbCity!!" when a button is pressed.

frmMain


 

Here is the code contained in the text file (Code.txt). This file located in the project's bin directory (ensure you set it to "copy if newer") in the file properties section of Visual Studio. This is the code we will be compiling and running from our WinForms application.

txtOutput.Text = "Hello vbCity!!"

 

Now, to the meat of the sample. There are a few simple steps we must complete to read, compile, and run the code. In order:

  1. Read the code from the file.
  2. Create an instance of a VB.NET compiler
  3. Create compiler parameters and pass them to the compiler
  4. Compile the code
  5. Check for errors
  6. Create an instance of the class containing the code
  7. Create arguments to pass to our compiled code
  8. Execute the code and see results

All these steps are in order in the following code fragment. This code is executed when the "Press Me" button is clicked.

Imports System.IO
Imports System.Reflection
Imports System.CodeDom
Imports System.CodeDom.Compiler
Imports Microsoft.VisualBasic

Public Class frmMain

    ' Button to start compiling code.
    Private Sub btnPressMe_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPressMe.Click

        ' Read code from file
        Dim input = My.Computer.FileSystem.ReadAllText("Code.txt")

        ' Create "code" literal to pass to the compiler.
        '
        ' Notice the <% = input % > where the code read from the text file (Code.txt) 
        ' is inserted into the code fragment.
        Dim code = <code>
                       Imports System
                       Imports System.Windows.Forms

                       Public Class TempClass
                           Public Sub UpdateText(ByVal txtOutput As TextBox)
                               <%= input %>
                           End Sub
                       End Class
                   </code>

        ' Create the VB.NET compiler.
        Dim vbProv = New VBCodeProvider()
        ' Create parameters to pass to the compiler.
        Dim vbParams = New CompilerParameters()
        ' Add referenced assemblies.
        vbParams.ReferencedAssemblies.Add("mscorlib.dll")
        vbParams.ReferencedAssemblies.Add("System.dll")
        vbParams.ReferencedAssemblies.Add("System.Windows.Forms.dll")
        vbParams.GenerateExecutable = False
        ' Ensure we generate an assembly in memory and not as a physical file.
        vbParams.GenerateInMemory = True

        ' Compile the code and get the compiler results (contains errors, etc.)
        Dim compResults = vbProv.CompileAssemblyFromSource(vbParams, code.Value)

        ' Check for compile errors
        If compResults.Errors.Count > 0 Then

            ' Show each error.
            For Each er In compResults.Errors
                MessageBox.Show(er.ToString())
            Next

        Else

            ' Create instance of the temporary compiled class.
            Dim obj As Object = compResults.CompiledAssembly.CreateInstance("TempClass")
            ' An array of object that represent the arguments to be passed to our method (UpdateText).
            Dim args() As Object = {Me.txtOutput}
            ' Execute the method by passing the method name and arguments.
            Dim t As Type = obj.GetType().InvokeMember("UpdateText", BindingFlags.InvokeMethod, Nothing, obj, args)

        End If

    End Sub
End Class

When ran, the output show display:

 

You could also change the text to something a little more elaborate, such as:

Dim sum As Integer = 0
For i As Integer = 1 To 100 Step 10
    sum += i
Next

txtOutput.Text = Convert.ToString(sum)

When executed, it will output:

 

And for a C# version (minor changes):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Reflection;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.CodeDom;

namespace WinFormCodeCompile
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            // Load code from file
            StreamReader sReader = new StreamReader(@"Code.txt");
            string input = sReader.ReadToEnd();
            sReader.Close();

            // Code literal
            string code =
                @"using System;
                  using System.Windows.Forms;

                  namespace WinFormCodeCompile
                  {
                      public class Transform
                      {
                       
                           public void UpdateText(TextBox textBox1)
                           {" + input + @"
                           }
                       }
                   }";

            // Compile code
            CSharpCodeProvider cProv = new CSharpCodeProvider();
            CompilerParameters cParams = new CompilerParameters();
            cParams.ReferencedAssemblies.Add("mscorlib.dll");
            cParams.ReferencedAssemblies.Add("System.dll");
            cParams.ReferencedAssemblies.Add("System.Windows.Forms.dll");
            cParams.GenerateExecutable = false;
            cParams.GenerateInMemory = true;

            CompilerResults cResults = cProv.CompileAssemblyFromSource(cParams, code);

            // Check for errors
            if (cResults.Errors.Count != 0)
            {
                foreach (var er in cResults.Errors)
                {
                    MessageBox.Show(er.ToString());
                }
            }
            else
            {
                // Attempt to execute method.
                object obj = cResults.CompiledAssembly.CreateInstance("WinFormCodeCompile.Transform");
                Type t = obj.GetType();
                object[] arg = { this.textBox1 }; // Pass our textbox to the method
                t.InvokeMember("UpdateText", BindingFlags.InvokeMethod, null, obj, arg);
            }


        }
    }
}


Posted Apr 24 2010, 07:46 AM by James Atkinson
Filed under: , , , ,

Comments

James Atkinson wrote re: Dynamically Read, Compile, and Run Source Code From a Text File
on 4/28/2010 6:02 AM

blog.cwa.me.uk/.../the-morning-brew-588

(posted to reference referrers)

DotNetKicks.com wrote Dynamically Read, Compile, and Run Source Code From a Text File
on 5/7/2010 11:06 PM

You've been kicked (a good thing) - Trackback from DotNetKicks.com

tawanda wrote re: Dynamically Read, Compile, and Run Source Code From a Text File
on 1/5/2011 1:41 AM

hie

thanks for the code on the "cParams.ReferencedAssemblies.Add" howver im facing problems on adding an an adding an office microsoft project reference, it says it cannot find  "Microsoft.Office.Interop.MSProject.dll"

i had referenced it

here's e code

string input = "part=task.Text11;";

                           //sReader.ReadToEnd();

                           // sReader.Close();

                           // Code literal  

                           string code =

                               @"using System;  

                 using System.Windows.Forms;  

 using Microsoft.Office.Interop.MSProject;

                 namespace DCDAddOn

                 {  

                     public class Transform  

                     {  

                          public void UpdateText(Microsoft.Office.Interop.MSProject.Task task, string part)  

                          {" + input + @"  

                          }  

                      }  

                  }";

                           // Compile code  

                           string code2 = "textBox1.Text=Label1.Text;";

 CSharpCodeProvider cProv = new CSharpCodeProvider();

 CompilerParameters cParams = new CompilerParameters();

cParams.ReferencedAssemblies.Add("mscorlib.dll");

cParams.ReferencedAssemblies.Add("System.dll");

cParams.ReferencedAssemblies.Add("System.Windows.Forms.dll");

cParams.ReferencedAssemblies.Add("Microsoft.Office.Interop.MSProject.dll");

cParams.GenerateExecutable = false;

 cParams.GenerateInMemory = true;

                           CompilerResults cResults = cProv.CompileAssemblyFromSource(cParams, code);

                           // Check for errors  

                           if (cResults.Errors.Count != 0) {

                               foreach (var er in cResults.Errors) {

                                   MessageBox.Show(er.ToString());

                               }

                           } else {

                               // Attempt to execute method.  

                               object obj = cResults.CompiledAssembly.CreateInstance("DCDAddOn.Transform");

                               Type t = obj.GetType();

                               object[] arg = {task,part }; // Pass our textbox to the method  

                               t.InvokeMember("UpdateText", BindingFlags.InvokeMethod, null, obj, arg);

                           }

Vidya Dhanam wrote re: Dynamically Read, Compile, and Run Source Code From a Text File
on 7/19/2011 6:01 AM

Really nice

Copyright 1998-2017 vbCity.com LLC