help on how to compile code at runtime dynamically? - Programmers Heaven

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories

Welcome to the new platform of Programmer's Heaven! We apologize for the inconvenience caused, if you visited us from a broken link of the previous version. The main reason to move to a new platform is to provide more effective and collaborative experience to you all. Please feel free to experience the new platform and use its exciting features. Contact us for any issue that you need to get clarified. We are more than happy to help you.

help on how to compile code at runtime dynamically?

jeffmanjeffman Posts: 112Member
this is my code except i do the vbcodeprovider or compiler directly instead of using a class here and i get 2 errors initilization error and system cannot find the file specified (the dll file my program creates):

Form with rich text box controls code:

Imports System.Text
Public Class frmMain
Private Sub btnGo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGo.Click
Dim oRetVal As Object = CompileAndRunCode(Me.RichTextBox1.Text)
MsgBox(oRetVal)
End Sub
Private Function GenerateCannedRoutine() As StringBuilder
Dim oRetSB As New StringBuilder
' Grab a variable from somewhere....
Dim sText As String = "July 30, 2006"
oRetSB.Append("If Date.Parse(""" & sText & """) < System.DateTime.Now() Then " & vbCrLf)
oRetSB.Append(" Return ""OLD"" " & vbCrLf)
oRetSB.Append("Else " & vbCrLf)
oRetSB.Append(" Return ""NEW"" " & vbCrLf)
oRetSB.Append("End If " & vbCrLf)
Return oRetSB
End Function
Public Function CompileAndRunCode(ByVal VBCodeToExecute As String) As Object
Dim sReturn_DataType As String
Dim sReturn_Value As String = ""
Try
' Instance our CodeDom wrapper
Dim ep As New cVBEvalProvider
' Compile and run
Dim objResult As Object = ep.Eval(VBCodeToExecute)
If ep.CompilerErrors.Count <> 0 Then
Diagnostics.Debug.WriteLine("CompileAndRunCode: Compile Error Count = " & ep.CompilerErrors.Count)
Diagnostics.Debug.WriteLine(ep.CompilerErrors.Item(0))
Return "ERROR" ' Forget it
End If
Dim t As Type = objResult.GetType()
If t.ToString() = "System.String" Then
sReturn_DataType = t.ToString
sReturn_Value = Convert.ToString(objResult)
Else
' Some other type of data - not really handled at
' this point. rwd
'ToDo: Add handlers for other data return types, if needed
End If
Catch ex As Exception
Dim sErrMsg As String
sErrMsg = String.Format("{0}", ex.Message)
' Do Nothing - This is just a negative case
' This outcome is expected in late interpreting
' I suppose what I am saying is: Don't stop my program because the script writer can't write
' script very well. To be fair, we could log this somewhere and notify somebody.
End Try
Return sReturn_Value
End Function

Public Sub New()
' This call is required by the Windows Form Designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
' Build our code fragment
Dim sCode As System.Text.StringBuilder
sCode = GenerateCannedRoutine()
Me.RichTextBox1.Text = sCode.ToString
End Sub
End Class

cVBEvalProvider class code:
just use this code alone with a textbox and i get 2 errors initilization error and system cannot find the file specified (the dll file my program creates):

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

Public Class cVBEvalProvider
Private m_oCompilerErrors As CompilerErrorCollection
Public Property CompilerErrors() As CompilerErrorCollection
Get
Return m_oCompilerErrors
End Get
Set(ByVal Value As CompilerErrorCollection)
m_oCompilerErrors = Value
End Set
End Property
Public Sub New()
MyBase.New()
m_oCompilerErrors = New CompilerErrorCollection
End Sub
Public Function Eval(ByVal vbCode As String) As Object
Dim oCodeProvider As VBCodeProvider = New VBCodeProvider
Dim oCParams As CompilerParameters = New CompilerParameters
Dim oCResults As CompilerResults
Dim oAssy As System.Reflection.Assembly
Dim oExecInstance As Object = Nothing
Dim oRetObj As Object = Nothing
Dim oMethodInfo As MethodInfo
Dim oType As Type
Try
' Setup the Compiler Parameters
' Add any referenced assemblies
oCParams.ReferencedAssemblies.Add("system.dll")
oCParams.ReferencedAssemblies.Add("system.xml.dll")
oCParams.ReferencedAssemblies.Add("system.data.dll")
oCParams.CompilerOptions = "/t:library"
oCParams.GenerateInMemory = True
' Generate the Code Framework
Dim sb As StringBuilder = New StringBuilder("")
sb.Append("Imports System" & vbCrLf)
sb.Append("Imports System.Xml" & vbCrLf)
sb.Append("Imports System.Data" & vbCrLf)
' Build a little wrapper code, with our passed in code in the middle
sb.Append("Namespace dValuate" & vbCrLf)
sb.Append("Class EvalRunTime " & vbCrLf)
sb.Append("Public Function EvaluateIt() As Object " & vbCrLf)
sb.Append(vbCode & vbCrLf)
sb.Append("End Function " & vbCrLf)
sb.Append("End Class " & vbCrLf)
sb.Append("End Namespace" & vbCrLf)
Debug.WriteLine(sb.ToString())
Try
' Compile and get results
' 2.0 Framework - Method called from Code Provider
oCResults = oCodeProvider.CompileAssemblyFromSource(oCParams, sb.ToString)
' Check for compile time errors
If oCResults.Errors.Count <> 0 Then
Me.CompilerErrors = oCResults.Errors
Throw New Exception("Compile Errors")
Else
' No Errors On Compile, so continue to process...
oAssy = oCResults.CompiledAssembly
oExecInstance = oAssy.CreateInstance("dValuate.EvalRunTime")
oType = oExecInstance.GetType
oMethodInfo = oType.GetMethod("EvaluateIt")
oRetObj = oMethodInfo.Invoke(oExecInstance, Nothing)
Return oRetObj
End If
Catch ex As Exception
' Compile Time Errors Are Caught Here
' Some other weird error
Debug.WriteLine(ex.Message)
Stop
End Try
Catch ex As Exception
Debug.WriteLine(ex.Message)
Stop
End Try
Return oRetObj
End Function
End Class

Comments

  • rlcrlc Posts: 448Member
    Jeff have you solved this?

    ~rlc
  • jeffmanjeffman Posts: 112Member
    no i havent solved this i want to compile my own code in a dll file and then execute routines and code from the dll file. do you know anything about reflection i know that this code involves compileing to a dll using reflection and other similar things. the reason for compiling this code dynamically is iam using it in from a addin dll or exe and executing the code to change controls on my main forms but not really replace them and i think i will do late binding because i might have to change a lot of my code if i dont.
    any help you or any one else can offer would be appreciated.
    thanks for any help again
    jeffman
    the planner

    : Jeff have you solved this?
    :
    : ~rlc
  • rlcrlc Posts: 448Member
    I don't have time right now to look through all that code, but I do routinely use the dynamic compile in my code. I have made a class from various sources I found and I will post it below.

    Here is a brief description of how I use it since there is no commenting in this class. Try this method it should work for you. You may have to change a few vars I use ex:WORKDIR


    ~rlc

    1) At start up of my service I create assemblies with custom processing by calling the compile command and passing it a code string and a string of references. Really the code string is a file I load and .readtoend into a string, but you could create this yourself dynamically as well. The refs string is semi-colon delimited and must always have 'system.dll'. The Assembly object is stored in a collection in my code.

    2)I call the CallMethod with proper parameters including the assembly we compiled and I have stored as


    [code]
    Public Class clsDynamicCompile

    Public Sub New()

    End Sub

    Public Function Compile(ByVal v_Refs As String(), _
    ByVal v_Source As String) As System.CodeDom.Compiler.CompilerResults

    Dim l_Provider As Microsoft.VisualBasic.VBCodeProvider
    Dim l_Compiler As System.CodeDom.Compiler.ICodeCompiler
    Dim l_Params As System.CodeDom.Compiler.CompilerParameters

    l_Params = New System.CodeDom.Compiler.CompilerParameters
    l_Params.GenerateInMemory = True 'Assembly is created in memory
    l_Params.TreatWarningsAsErrors = False
    l_Params.WarningLevel = 4
    l_Params.ReferencedAssemblies.AddRange(v_Refs)
    l_Params.TempFiles = New System.CodeDom.Compiler.TempFileCollection(WORKDIR)

    Try
    l_Provider = New Microsoft.VisualBasic.VBCodeProvider
    l_Compiler = l_Provider.CreateCompiler

    'return the results of the compile
    Return l_Compiler.CompileAssemblyFromSource(l_Params, v_Source)

    Catch ex As Exception
    'Compile errors don't throw exceptions; you've got some deeper problem...
    Return Nothing
    End Try

    End Function

    Public Function CallMethod(ByVal v_ClassName As String, _
    ByVal v_MethodName As String, _
    ByVal v_Asm As System.Reflection.Assembly, _
    ByVal v_Args As Object()) As Boolean

    Dim l_ClassType As Type
    Dim l_instance As Object


    Try

    l_ClassType = v_Asm.GetType(v_ClassName)
    l_instance = v_Asm.CreateInstance(v_ClassName)
    CallMethod = l_ClassType.InvokeMember(v_MethodName, _
    System.Reflection.BindingFlags.Public Or _
    System.Reflection.BindingFlags.InvokeMethod Or _
    System.Reflection.BindingFlags.Instance, _
    Nothing, l_instance, v_Args)

    Return CallMethod

    Catch ex As Exception

    Return Nothing
    End Try


    End Function
    End Class
    [/code]

    short ex
    [code]

    Private m_Compile As New clsDynamicCompile

    ...
    'in some functoin that comiles
    Dim l_Results As CodeDom.Compiler.CompilerResults
    l_Results = m_Compile.Compile(l_Refs, l_Source)

    For Each l_CurrErr As System.CodeDom.Compiler.CompilerError In l_Results.Errors

    'errors are bad do something here

    next


    If l_Results.Errors.Count = 0 Then
    'this is the assembly keep it somewhere like in a member var collection on your main form.
    MyAssembly = l_Results.CompiledAssembly
    end if
    ....

    Dim l_Args() As Object = {mystuffhere}

    Return m_Compile.CallMethod("CustomProcess", "Process", MyAssembly, l_Args)

    ....

    'code string something like this
    Public Class CustomProcess

    Public Function Process(ByRef r_SomeStuff as object) As Boolean

    'here is code
    End function
    End Class

    [/code]
  • jeffmanjeffman Posts: 112Member
    i use visual basic 2005 and from what i heard so classes have changed can you change this code so that it will be more likely to work in visual basic 2005. but thanks i will try the code above first but please tell me if the code provided above will work in visual basic 2005 because that is what iam using ( the express edition to be exact).

    : I don't have time right now to look through all that code, but I do
    : routinely use the dynamic compile in my code. I have made a class
    : from various sources I found and I will post it below.
    :
    : Here is a brief description of how I use it since there is no
    : commenting in this class. Try this method it should work for you.
    : You may have to change a few vars I use ex:WORKDIR
    :
    :
    : ~rlc
    :
    : 1) At start up of my service I create assemblies with custom
    : processing by calling the compile command and passing it a code
    : string and a string of references. Really the code string is a file
    : I load and .readtoend into a string, but you could create this
    : yourself dynamically as well. The refs string is semi-colon
    : delimited and must always have 'system.dll'. The Assembly object is
    : stored in a collection in my code.
    :
    : 2)I call the CallMethod with proper parameters including the
    : assembly we compiled and I have stored as
    :
    :
    : [code]:
    : Public Class clsDynamicCompile
    :
    : Public Sub New()
    :
    : End Sub
    :
    : Public Function Compile(ByVal v_Refs As String(), _
    : ByVal v_Source As String) As System.CodeDom.Compiler.CompilerResults
    :
    : Dim l_Provider As Microsoft.VisualBasic.VBCodeProvider
    : Dim l_Compiler As System.CodeDom.Compiler.ICodeCompiler
    : Dim l_Params As System.CodeDom.Compiler.CompilerParameters
    :
    : l_Params = New System.CodeDom.Compiler.CompilerParameters
    : l_Params.GenerateInMemory = True 'Assembly is created in memory
    : l_Params.TreatWarningsAsErrors = False
    : l_Params.WarningLevel = 4
    : l_Params.ReferencedAssemblies.AddRange(v_Refs)
    : l_Params.TempFiles = New System.CodeDom.Compiler.TempFileCollection(WORKDIR)
    :
    : Try
    : l_Provider = New Microsoft.VisualBasic.VBCodeProvider
    : l_Compiler = l_Provider.CreateCompiler
    :
    : 'return the results of the compile
    : Return l_Compiler.CompileAssemblyFromSource(l_Params, v_Source)
    :
    : Catch ex As Exception
    : 'Compile errors don't throw exceptions; you've got some deeper problem...
    : Return Nothing
    : End Try
    :
    : End Function
    :
    : Public Function CallMethod(ByVal v_ClassName As String, _
    : ByVal v_MethodName As String, _
    : ByVal v_Asm As System.Reflection.Assembly, _
    : ByVal v_Args As Object()) As Boolean
    :
    : Dim l_ClassType As Type
    : Dim l_instance As Object
    :
    :
    : Try
    :
    : l_ClassType = v_Asm.GetType(v_ClassName)
    : l_instance = v_Asm.CreateInstance(v_ClassName)
    : CallMethod = l_ClassType.InvokeMember(v_MethodName, _
    : System.Reflection.BindingFlags.Public Or _
    : System.Reflection.BindingFlags.InvokeMethod Or _
    : System.Reflection.BindingFlags.Instance, _
    : Nothing, l_instance, v_Args)
    :
    : Return CallMethod
    :
    : Catch ex As Exception
    :
    : Return Nothing
    : End Try
    :
    :
    : End Function
    : End Class
    : [/code]:
    :
    : short ex
    : [code]:
    :
    : Private m_Compile As New clsDynamicCompile
    :
    : ...
    : 'in some functoin that comiles
    : Dim l_Results As CodeDom.Compiler.CompilerResults
    : l_Results = m_Compile.Compile(l_Refs, l_Source)
    :
    : For Each l_CurrErr As System.CodeDom.Compiler.CompilerError In l_Results.Errors
    :
    : 'errors are bad do something here
    :
    : next
    :
    :
    : If l_Results.Errors.Count = 0 Then
    : 'this is the assembly keep it somewhere like in a member var collection on your main form.
    : MyAssembly = l_Results.CompiledAssembly
    : end if
    : ....
    :
    : Dim l_Args() As Object = {mystuffhere}
    :
    : Return m_Compile.CallMethod("CustomProcess", "Process", MyAssembly, l_Args)
    :
    : ....
    :
    : 'code string something like this
    : Public Class CustomProcess
    :
    : Public Function Process(ByRef r_SomeStuff as object) As Boolean
    :
    : 'here is code
    : End function
    : End Class
    :
    : [/code]:
  • rlcrlc Posts: 448Member
    Yes this code is out of a 2005 project.

    ~rlc
  • jeffmanjeffman Posts: 112Member
    when i go to compile my code i get an error that i need to specifi the option r or something like that and it didnt work because of that. do you know whats wrong? i dont know what happened but up to that point it worked fine. do you know what went wrong? i tryed the code like you said but this was the only real error i had till i started the compile function.
    the whole error says this: error: option 'r' requires ': '


    thanks for any help again jeffman

    the planner

    : Yes this code is out of a 2005 project.
    :
    : ~rlc
Sign In or Register to comment.