Hello, I have another question about dynamically compiled code. I am using the VBCodeProvider class to compile, test, and run "scripts" that users type into my program (Code Below).

Public Function Compile(ByVal vbCode As String, ByVal argsString As String) As Object

        Dim oCodeProvider As VBCodeProvider = New VBCodeProvider
        ' Obsolete in 2.0 framework
        ' Dim oICCompiler As ICodeCompiler = oCodeProvider.CreateCompiler

        Dim oCParams As CompilerParameters = New CompilerParameters
        Dim oCResults As CompilerResults
        Dim oAssy As System.Reflection.Assembly
        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)
            sb.Append("Imports System.Collections.Generic" & vbCrLf)
            sb.Append("Imports RBDS_Control.RBDS" & 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(" & argsString & ") 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)
                ' 1.1 Framework - Method called from CodeCompiler Interface
                ' cr = oICCompiler.CompileAssemblyFromSource (cp, sb.ToString)


                ' Check for compile time errors 
                If oCResults.Errors.Count <> 0 Then
                    Me.CompilerErrors = oCResults.Errors
                    Throw New Exception(oCResults.Errors.Item(0).ToString)
                Else
                    ' No Errors On Compile, so continue to process...

                    oAssy = oCResults.CompiledAssembly
                    oExecInstance = oAssy.CreateInstance("dValuate.EvalRunTime")


                    oType = oExecInstance.GetType
                    oMethodInfo = oType.GetMethod("EvaluateIt")
                End If

            Catch ex As Exception
                ' Compile Time Errors Are Caught Here
                ' Some other weird error 
                Debug.WriteLine(ex.Message)
            End Try

        Catch ex As Exception
            Debug.WriteLine(ex.Message)
        End Try

        Return Nothing
    End Function

Everything works great, however I am unable to add reference to more code. I have a class in my project which defines a new data type used troughout my program. The code the user writes is contained in a predefined function which is passed a dictionary of this datatype in my code. However, VB complains that it cannot find this class because the dynamically compiled code is run out of its own dll. The VBCodeProvider has the ability to add referenced assemblies oCParams.ReferencedAssemblies.Add("system.dll") however I do not know how to add my class since it is not in a dll and is not part of the .NET framework.

Any help is greatly appreciated. Thank you in advance.

Recommended Answers

All 5 Replies

Converting method 'EvaluateIt' to 'shared'

Imports System.Text
Imports System.CodeDom.Compiler
Imports System.Reflection

Module Module1


    Sub Main()
        Compile("return 2+3", "")
    End Sub
    Public Sub Compile(ByVal vbCode As String, ByVal argsString As String)
        Dim oCodeProvider As VBCodeProvider = New VBCodeProvider
        Dim oCParams As CompilerParameters = New CompilerParameters
        Dim oCResults As CompilerResults
        Dim oAssy As System.Reflection.Assembly
        '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)
            sb.Append("Imports System.Collections.Generic" & vbCrLf)
            sb.Append("Imports RBDS_Control.RBDS" & 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 shared Function EvaluateIt(" & argsString & ") 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)
                ' 1.1 Framework - Method called from CodeCompiler Interface
                ' cr = oICCompiler.CompileAssemblyFromSource (cp, sb.ToString)


                ' Check for compile time errors 
                If oCResults.Errors.Count <> 0 Then
                    Console.WriteLine(oCResults.Errors.Item(0).ToString)
                Else
                    ' No Errors On Compile, so continue to process...
                    oAssy = oCResults.CompiledAssembly
                    Dim vModules() As System.Reflection.Module = oAssy.GetModules()
                    For Each tI As TypeInfo In vModules(0).Assembly.DefinedTypes
                        If tI.Name = "EvalRunTime" Then
                            Dim mI As MethodInfo = tI.GetMethod("EvaluateIt")
                            Console.WriteLine(mI.Invoke(Nothing, Nothing))' console output= 5
                            Exit For
                        End If
                    Next
                End If

            Catch ex As Exception
                ' Compile Time Errors Are Caught Here
                ' Some other weird error 
                Debug.WriteLine(ex.Message)
            End Try

        Catch ex As Exception
            Debug.WriteLine(ex.Message)
        End Try
    End Sub

End Module

Sorry for the delay, I tried this however, when a customer script is run, it still says that "Type InputData is not defined" (this is my class I am attempting to get access to).

Change the above to something like:

                If oCResults.Errors.Count <> 0 Then
                    Console.WriteLine(oCResults.Errors.Item(0).ToString)
                Else
                    ' No Errors On Compile, so continue to process...
                    oAssy = oCResults.CompiledAssembly
                    Dim vModules() As System.Reflection.Module = oAssy.GetModules()
                    For Each tI As TypeInfo In vModules(0).Assembly.DefinedTypes
                        If tI.Name = "EvalRunTime" Then
                            Dim mI As MethodInfo = tI.GetMethod("EvaluateIt")
                            Console.WriteLine(mI.Invoke(Nothing, Nothing).ToString) '--> 5
                            Dim myType As Type = tI.UnderlyingSystemType
                            Dim o As Object = Activator.CreateInstance(myType)
                            Console.WriteLine(o.EvaluateItNonShared().ToString) ' --> 5
                            Exit For
                        End If
                    Next
                End If

This still does not fix the issue because the class that cannot be found is being caught as a compiler error and thus the above code is never reached. In the background, is the compiled code being run as a separate program? How does VB normally access its imports?

For me works fine: in last line number 12. the instance of class EvalRunTime is created in variable "o".
You just need to add a method called "EvaluateItNonShared" in class EvalRunTime. In this manner in line 13. will be invoked properly as does in mine.
Here is the complete code (working):

Imports System.Text
Imports System.CodeDom.Compiler
Imports System.Reflection

Module Module1

    Sub Main()
        Compile("return 2+3", "")
    End Sub
    Public Sub Compile(ByVal vbCode As String, ByVal argsString As String)
        Dim oCodeProvider As VBCodeProvider = New VBCodeProvider
        Dim oCParams As CompilerParameters = New CompilerParameters
        Dim oCResults As CompilerResults
        Dim oAssy As System.Reflection.Assembly
        '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)
            sb.Append("Imports System.Collections.Generic" & vbCrLf)
            sb.Append("Imports RBDS_Control.RBDS" & 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 Sub New()" & vbCrLf)
            sb.Append("End Sub " & vbCrLf)
            sb.Append("Public Shared Function EvaluateIt(" & argsString & ") As Object " & vbCrLf)
            sb.Append(vbCode & vbCrLf)
            sb.Append("End Function " & vbCrLf)
            sb.Append("Public Function EvaluateItNonShared(" & argsString & ") 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)
                ' 1.1 Framework - Method called from CodeCompiler Interface
                ' cr = oICCompiler.CompileAssemblyFromSource (cp, sb.ToString)


                ' Check for compile time errors 
                If oCResults.Errors.Count <> 0 Then
                    Console.WriteLine(oCResults.Errors.Item(0).ToString)
                Else
                    ' No Errors On Compile, so continue to process...
                    oAssy = oCResults.CompiledAssembly
                    Dim vModules() As System.Reflection.Module = oAssy.GetModules()
                    For Each tI As TypeInfo In vModules(0).Assembly.DefinedTypes
                        If tI.Name = "EvalRunTime" Then
                            Dim mI As MethodInfo = tI.GetMethod("EvaluateIt")
                            Console.WriteLine(mI.Invoke(Nothing, Nothing).ToString) '--> 5
                            Dim myType As Type = tI.UnderlyingSystemType
                            Dim o As Object = Activator.CreateInstance(myType)
                            Console.WriteLine(o.EvaluateItNonShared().ToString) ' --> 5
                            Exit For
                        End If
                    Next
                End If

            Catch ex As Exception
                ' Compile Time Errors Are Caught Here
                ' Some other weird error 
                Debug.WriteLine(ex.Message)
            End Try

        Catch ex As Exception
            Debug.WriteLine(ex.Message)
        End Try
    End Sub

End Module
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.