开发者

How to pass a reference to a form to dynamically compiled code

I am trying to create a application scripting environment for my VB .Net application. I have a form type in the application called Project. What I want to do is dynamically compile (i.e Eval) VB .Net code on a Project form. This dynamic code always has a Main function. One of the arguments to Main is a reference to the calling Project form. Here is the Eval code:

    Public Function Eval(ByVal vbCode As String, ByRef MyAssembly As System.Reflection.Assembly, ByRef ProjectForm As Project) As ArrayList
    Dim Provider As VBCodeProvider = CodeDomProvider.CreateProvider("VisualBasic")
    Dim CompParams As CompilerParameters = New CompilerParameters
    Dim CResult As CompilerResults
    Dim EvalAssy As System.Reflection.Assembly
    Dim InstanceObject As Object
    Dim InstanceType As Type
    Dim InstanceMI As MethodInfo
    Dim CompError As CompilerError
    Dim NumberOfErrors As Integer = 0
    Dim ReturnValues As New ArrayList
    Dim SkipAssembly As Boolean = False
    Dim DebugTextBox As TextBox = ProjectForm.CompilationErrors
    Dim DebugFilename As String = ProjectForm.DebugFile
    Dim StatusBar As ToolStripStatusLabel = ProjectForm.MyMainForm.MessageToolStripStatusLabel

    'Result = MsgBox("HMMM: " & CodeDomProvider.IsDefinedLanguage("VisualBasic").ToString(), MsgBoxStyle.OkOnly + MsgBoxStyle.Exclamation, "HMMM")
    If Not DebugTextBox Is Nothing Then
        DebugTextBox.Text &= "Running Eval On Assembly """ & MyAssembly.FullName & """." & vbCrLf
    End If
    CompParams.ReferencedAssemblies.Add("system.dll")
    CompParams.ReferencedAssemblies.Add("system.xml.dll")
    CompParams.ReferencedAssemblies.Add("system.data.dll")
    CompParams.ReferencedAssemblies.Add("System.Windows.Forms.dll")
    ' Pass Myself In
    CompParams.ReferencedAssemblies.Add(System.Reflection.Assembly.GetExecutingAssembly.Location)
    CompParams.CompilerOptions = "/t:library"
    CompParams.GenerateInMemory = True

    CResult = Provider.CompileAssemblyFromSource(CompParams, vbCode)
    For Each CompError In CResult.Errors
        If Not CompError.IsWarning Then
            ' "Real Error"
            NumberOfErrors += 1
        End If
        ReturnValues.Add("Error " & CompError.ErrorNumber & " On Line " & CompError.Line & ": " & CompError.ErrorText)
    Next
    If NumberOfErrors = 0 Then
        Try
            EvalAssy = CResult.CompiledAssembly
            InstanceObject = EvalAssy.CreateInstance("Translation")
            InstanceType = InstanceObject.GetType()
            InstanceMI = InstanceType.GetMethod("Main")
            InstanceMI.Invoke(InstanceObject, New Object() {MyAssembly, ProjectForm})
            'InstanceMI.Invoke(InstanceObject, BindingFlags.Default, Nothing, New Object() {MyAssembly, ProjectForm}, System.Globalization.CultureInfo.CurrentCulture)
        Catch Ex As Exception
            If Ex.InnerException Is Nothing Then
                WriteDebugMsg(DebugTextBox, "Error Evaling Compiled Code.  The Error Is """ & Ex.Message)
            Else
                WriteDebugMsg(DebugTextBox, "Error Evaling Compiled Code.  The Error Is:" & vbCrLf & Ex.Message & vbCrLf & "Inner Exception Is:" & vbCrLf & Ex.InnerException.ToString)
            End If
        End Try
    End If
    Return ReturnValues
End Function

The Main function in the dynamic (Eval) code is:

Imports System
Imports System.Xml
Imports System.Data
Imports Microsoft.VisualBasic
Imports System.Reflection
Imports System.Diagnostics
Imports System.IO
Imports System.Windows.Forms
Imports System.Collections
Imports System.Text
Imports UniversalTranslator

Public Sub Main(ByRef MyAssembly As System.Reflection.Assembly, ByRef MyProjectForm As Project)
    ' Create functions needed to parse assembly here and in subroutines called from here
    Me.ProjectForm = MyProjectForm
    DebugFile = ProjectForm.DebugFile  ' Set Global Debug Filename Variable
    DebugTB = ProjectForm.CompilationErrors 
    ' Initialize Log Fi开发者_如何学运维les And Debug Textboxes
    If Dir(DebugFile,FileAttribute.Normal) > "" Then 
        Kill(DebugFile)
    End If
    If Not DebugTB is Nothing Then
        DebugTB.Text = ""
    end if 
    RecurseAssemblyForms(MyAssembly,AddressOf OutputControlInfo)
End Sub

Everything is compiling fine. The compiled code recognizes the MyProjectForm as type Project from the calling assembly. However, when the code is executed with a reference to a calling assembly project form I get the following error:

Running Eval On Assembly "LaserTrak V4 Software, Version=4.507.3992.19399, Culture=neutral, PublicKeyToken=null". Error Evaling Compiled Code. The Error Is: Exception has been thrown by the target of an invocation. Inner Exception Is: System.MissingMemberException: Public member 'CompilationErrors' on type 'Project' not found. at Microsoft.VisualBasic.CompilerServices.Symbols.Container.GetMembers(String& MemberName, Boolean ReportErrors) at Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateGet(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack) at Translation.Main(Assembly& MyAssembly, Project& MyProjectForm)

My guess is that the Main procedure does not have "trusted" access to the calling assemblies active Project forms. How do I give it that access? Thanks for you help.


I'm guessing CompilationErrors is not a public member? Is it a Friend? Or Private? Or Protected?

If it's a Friend member, you could use the InternalsVisibleToAttribute, but otherwise, you will not be able to access it this way.

If you were using C# 4.0, you could hypothetically use a DynamicObject that permits private member access...but that's another story...


CompilationErrors is a textbox on the Project form. I forgot to set its Modifiers property to Public because I am an idiot ;-).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜