Howdy, Stranger!

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

Categories

help on how to compile code at runtime dynamically?

jeffmanjeffman Member Posts: 112
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 Member Posts: 448
    Jeff have you solved this?

    ~rlc
  • jeffmanjeffman Member Posts: 112
    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 Member Posts: 448
    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 Member Posts: 112
    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 Member Posts: 448
    Yes this code is out of a 2005 project.

    ~rlc
  • jeffmanjeffman Member Posts: 112
    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.