Wie mit VBCodeProvider erstellte Assembly in separate AppDomain schieben ?

  • VB.NET
  • .NET (FX) 1.0–2.0

    Wie mit VBCodeProvider erstellte Assembly in separate AppDomain schieben ?

    Hallo Gemeinde,

    ich erstelle gerade eine VB.NET-Applikation und bin nun an einem Punkt angelangt, bei dem ich alleine leider nicht mehr weiter komme.
    Vielleicht kann mir ja jemand von Euch weiterhelfen ?

    Es geht um folgendes:

    Es gibt eine Hauptapplikation, die dem User nur als EXE vorliegen soll. Das Programm soll einen Waferprober steuern, der der Reihe
    nach alle Chips auf einem Siliziumwafer durchstept und dabei jeden Chip mit Nadeln kontaktiert, um an ihm Funktionstests durchzuführen.
    Da unterschiedliche Arten von Chips aber unterschiedliche Funktionstests benötigen, sollen diese Tests in eine Subroutine ausgelagert
    werden, die der User nach seinen Anforderungen jeweils editieren kann.
    Die Subroutine soll sich in einer separaten Datei befinden, die zur Laufzeit dann von der Hauptapplikation eingelesen wird und deren
    Quellcode dann mit dem VBCodeProvider zu einer Assembly wird, auf die dann von der Applikation zugegriffen wird.

    Dies funktioniert soweit auch schon; ich kann auch aus der dynamisch kompillierten Subroutine heraus auf Objekte und Public Shared
    Variablen der Hauptapplikation zugreifen.

    Allerdings wird die dynamsich erstellte Assembly zur selben AppDomain hinzugefügt, wie die Hauptapplikation. D. h. sie läßt sich leider
    nur entladen, indem die gesamte Applikation geschlossen wird, was aber nicht in meinem Sinne ist. Ohne Entlademöglichkeit der
    Assembly wächst aber leider der Speicherverbrauch ziemlich stark an, da in der dynamischen Subroutine viel mit mehrdimensionalen
    Arrays gearbeitet wird.

    Ich habe gelesen, daß es eine Möglichkeit gibt, Assemblies wieder zu entladen, wenn sie zu einer anderen AppDomain hinzugefügt
    werden, als der AppDomain der Hauptapplikation. Der Begriff Marshalling ist mir dabei außerdem noch über den Weg gelaufen,
    aber leider kann ich damit nichts anfangen.
    Alles, was ich zu der Thematik gefunden habe, bezog sich nur auf C# und nicht auf VB.NET.
    Ich könnte eines der C#-Beispiele ev. sogar zu VB.NET konvertieren, aber ich bekomme es leider nicht hin, das Thema "separate
    AppDomain" mit "durch VBCodeProvider dynamisch generierte Assembly" zu verheiraten.

    Hier ist eine eingedampfte Beispielapplikation, die aus einer Datei namens "Code.txt" eine Subroutine lädt und mit VBCodeProvider
    eine dynamische Assembly erstellt. Könnte mir vielleicht jemand dieses Beispiel so umschreiben, daß mir daraus ersichtlich wird,
    wie ich die dynamsiche Assembly in eine separate AppDomain bekomme (und weiterhin daraus auf die Hauptapplikation zugreifen
    kann) ?

    VB.NET-Quellcode

    1. Imports System.IO
    2. Imports System.Reflection
    3. Imports System.CodeDom
    4. Imports System.CodeDom.Compiler
    5. Imports Microsoft.VisualBasic
    6. Public Class Form1
    7. Public Shared obj As Object
    8. Public Shared compResults as Object
    9. Public Shared Dummy as Integer = 1
    10. Public Shared Float(1000,1000,50) as Double
    11. Private Sub Form1_Load( ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    12. Dim input = My.Computer.FileSystem.ReadAllText("Code.txt")
    13. Dim code as String = ""
    14. code = code & "Imports Microsoft.VisualBasic" & vbCrLf
    15. code = code & "Imports System" & vbCrLf
    16. code = code & "Imports System.Text" & vbCrLf
    17. code = code & "Imports System.Drawing" & vbCrLf
    18. code = code & "Imports System.Diagnostics" & vbCrLf
    19. code = code & "Imports DynamicCompile.Form1" & vbCrLf
    20. code = code & "Public Class DynamicClass" & vbCrLf
    21. code = code & " Public Sub DynamicSub(ByVal f as DynamicCompile.Form1)" & vbCrLf
    22. code = code & input & vbCrLf
    23. code = code & " End Sub" & vbCrLf
    24. code = code & "End Class" & vbCrLf
    25. Debug.Print(code)
    26. Debug.Print("Dummy: "+Str(Dummy))
    27. Dim vbProv = New VBCodeProvider()
    28. Dim vbParams = New CompilerParameters()
    29. vbParams.ReferencedAssemblies.Add("mscorlib.dll")
    30. Dim asm as Assembly
    31. For Each asm in AppDomain.CurrentDomain.GetAssemblies()
    32. vbParams.ReferencedAssemblies.Add(asm.Location)
    33. Next asm
    34. vbParams.CompilerOptions = "/t:library"
    35. vbParams.GenerateExecutable = False
    36. vbParams.GenerateInMemory = True
    37. vbParams.IncludeDebugInformation = True
    38. compResults = vbProv.CompileAssemblyFromSource(vbParams, code.ToString)
    39. If compResults.Errors.Count > 0 Then
    40. Dim er as CompilerError
    41. For Each er In compResults.Errors
    42. MessageBox.Show(er.ToString())
    43. Next er
    44. Else
    45. 'To do:
    46. 'Um ein Unload der dynamisch kompillierten Assembly zu ermöglichen,
    47. 'muß diese in einer neuen AppDomain erstellt werden.
    48. obj = compResults.CompiledAssembly.CreateInstance("DynamicClass")
    49. End If
    50. End Sub
    51. Public Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    52. Dim args() As Object = {Me}
    53. Dim t As Type
    54. 'Call the dynamically compiled subroutine twice
    55. t = obj.GetType().InvokeMember("DynamicSub", BindingFlags.InvokeMethod, Nothing, obj, args)
    56. t = obj.GetType().InvokeMember("DynamicSub", BindingFlags.InvokeMethod, Nothing, obj, args)
    57. Debug.Print("Dummy: "+Str(Dummy))
    58. End Sub
    59. Public Shared Sub Test(ByVal TextToDisplay as String)
    60. Debug.Print(TextToDisplay)
    61. End Sub
    62. End Class


    Hier ist noch der Inhalt der Datei "Code.txt":

    VB.NET-Quellcode

    1. 'This is a comment
    2. Dim arr(1000,1000,50) as Double
    3. f.Text = "Form1's title changed by subroutine in dynamically compiled class."
    4. f.Button1.Backcolor = Color.Red
    5. f.Textbox1.Text = "Textbox1.Text changed by subroutine in dynamically compiled class."
    6. f.Label1.Text = "Label1.Text modified"
    7. Call Test("Subroutine ""Test"" is called from another dynamically compiled class.")
    8. Debug.Print("""Debug.Print"" is called from another dynamically compiled class.")
    9. Debug.Print("Dummy: "+Str(Dummy))
    10. f.Dummy = 2
    11. Dim i, j, k as Integer
    12. For i = 0 To 1000
    13. For j = 0 To 1000
    14. For k = 0 To 50
    15. f.Float(i,j,k) = arr(i,j,k)
    16. Next k
    17. Next j
    18. Next i


    Ich bedanke mich schon einmal herzlich für jede hilfreiche Antwort !