Reputation: 126
I have a winform similar to what the OP has in How to load an internal class in end-user compiled code ? (advanced) where I have a textbox that will be the source of end-user code, and I it will be compiled on the fly when I hit the button.
Here are some parts of the code (where most was copied from How to load an internal class in end-user compiled code ? (advanced) :
Imports System
Imports System.CodeDom.Compiler
Imports System.Reflection
Imports System.Text
Public Class Form1
Private Sub ExecuteB_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExecuteB.Click
Dim Code As String = Me.CodeToExec.Text
Dim CompilerResult As CompilerResults
CompilerResult = Compile(Code)
End Sub
Public Function Compile(ByVal Code As String) As CompilerResults
Dim CodeProvider As New VBCodeProvider
Dim CodeCompiler As System.CodeDom.Compiler.CodeDomProvider = CodeDomProvider.CreateProvider("VisualBasic")
Dim Parameters As New System.CodeDom.Compiler.CompilerParameters
Parameters.GenerateExecutable = False
Parameters.ReferencedAssemblies.Add("System.dll")
Parameters.ReferencedAssemblies.Add("System.Windows.Forms.dll")
Parameters.ReferencedAssemblies.Add("Microsoft.VisualBasic.dll")
Dim CompilerResult As CompilerResults = CodeCompiler.CompileAssemblyFromSource(Parameters, Code)
If CompilerResult.Errors.HasErrors Then
CompileTB.Clear()
For i = 0 To CompilerResult.Errors.Count - 1
CompileTB.AppendText(CompilerResult.Errors(i).ErrorText & vbCrLf)
Next
Return Nothing
Else
Return CompilerResult
End If
End Function
End Class
My controls are: CodeToExec is the textbox where the user puts the custom code, CompileTB is another textbox where the errors are listed, and ExecuteB is the button. There are other classes and object in my program, and here is one of the classes that I want to use:
Public Class ExceptionCriteria
Private _CriteriaName As String
Public Property CriteriaName As String
Get
CriteriaName = _CriteriaName
End Get
Set(value As String)
_CriteriaName = value
End Set
End Property
Private _RuleSet As List(Of String)
Public Property RuleSet As List(Of String)
Get
RuleSet = _RuleSet
End Get
Set(value As List(Of String))
_RuleSet = value
End Set
End Property
Private _SerializationFilePath As String
Public Property SerializationFilePath As String
Get
SerializationFilePath = _SerializationFilePath
End Get
Set(value As String)
_SerializationFilePath = value
End Set
End Property
Public Sub AddRule(newRule As String)
If IsNothing(_RuleSet) Then
_RuleSet = New List(Of String)
End If
_RuleSet.Add(newRule)
End Sub
End Class
And here is one of the members that I want to use/set in the Form1 class:
Public comparisondate As Date = #2/20/2015#
My problem is, I want to access/modify objects, members, properties in the executing assembly and create new objects based on the custom classes there. How can I do this?
Upvotes: 1
Views: 131
Reputation: 139
If you want to use existing classes, you should know how to (self-)reference and how to deliver parameters. Here's a little example:
Do not forget to Imports YourProjectName
in the generated code.
Example Class to do all necessary stuff
Imports System.CodeDom.Compiler
Imports System.Reflection
Public Class MyHelloCompiler
Private Shared _ass As Assembly
Private Shared _YourClass As Type
Private Shared _YourMethod As MethodInfo
Private Shared _YourClassInstance As Object
Public Sub New()
'Code to compile and instantiate the compiled class for later use:
Dim opt As New CompilerParameters _
(Nothing, String.Empty, False)
opt.GenerateExecutable = False
opt.GenerateInMemory = True
' Following is the important self reference
opt.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location)
Console.WriteLine (MyCodeToCompile)
Dim res As CompilerResults = New VBCodeProvider().CompileAssemblyFromSource (opt, MyCodeToCompile)
_ass = res.CompiledAssembly
_YourClass = _ass.GetType ("MyExampleClass")
_YourMethod = _YourClass.GetMethod ("MyExampleProperty")
_YourClassInstance = Activator.CreateInstance ( _YourClass)
End Sub
Public Class MyExampleClass()
Public Property MyExampleProperty as String
End Class
Public Function RunCompiledCodeWithParams( _
instanceOfExampleClass as MyExampleClass) as String
Dim params As Object() = New Object() {instanceOfExampleClass}
Return CStr(_YourMethod.Invoke(_YourClassInstance, params))
End Function
Private Function MyCodeToCompile() as String
Return _
"Imports System" & vbCrLf & _
"Imports YourProjectName" & vbCrLf & _
"Public Class ClassToCompile" & vbCrLf & _
" Public Shared Function GetExampleProperty(prmExampleClassInstance as MyExampleClass) as String" & vbcrlf & _
" Return prmExampleClassInstance.MyExampleProperty" & vbcrlf & _
" End Function" & vbcrlf & _
"End Class"
End Function
End Class
Calling this above:
'....
Dim MyTestCompile As MyHelloCompiler = New MyHelloCompiler
Dim MyDummyClass As MyExampleClass = New MyExampleClass
MyDummyClass.MyExampleProperty = "I am the property value"
Dim MyResult as String = _
MyTestCompile.RunCompiledCodeWithParams(MyDummyClass)
'....
Upvotes: 0
Reputation: 126
I have bumped into the answer, what I lacked was
Parameters.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location)
Then I just needed to make the procedures and members shared. I hope this also helps newbies like me who happen to have the same problem and pass by this page.
Upvotes: 1