[VB.NET]利用反射載入並運行資源檔中的組件

[VB.NET]利用反射載入並運行資源檔中的組件

要載入並運行資源檔中的組件,最簡單的方法就是開個新的專案,把要真正要執行的組件加入資源檔中。

image

 

再用Assembly.Load載入組件後,呼叫EntryPoint.Invoke去執行組件即可。

 

Imports System.IO
Imports System.Reflection

Module MainModule

    <STAThread()> _
    Public Sub main(ByVal args() As String)
        Assembly.Load(My.Resources.ColorPicker).EntryPoint.Invoke(Nothing, New Object() {args})
    End Sub
End Module

 

同樣的概念,其實放在資源檔中的組件可以先經過壓縮處理,再放入資源檔中。載入時只要先經過解壓縮的動作,把要執行的組件從壓縮中解出,就可以執行了。

Imports System.IO
Imports System.Reflection
Imports ICSharpCode.SharpZipLib.Zip

Module MainModule

    <STAThread()> _
    Public Sub main(ByVal args() As String)
        Using compressedMS As New MemoryStream(My.Resources.ColorPicker)
            Dim zf As New ZipFile(compressedMS)
            Dim ze As ZipEntry = zf.GetEntry("ColorPicker.exe")
            Dim zs As Stream = zf.GetInputStream(ze)
            Dim buffer(ze.Size - 1) As Byte
            zs.Read(buffer, 0, buffer.Length - 1)
            Assembly.Load(buffer).EntryPoint.Invoke(Nothing, New Object() {args})
        End Using
    End Sub
End Module

 

 

那若是放在資源檔中的組件需要參考多個組件呢?這邊借用小朱大的PLURK小圈圈管理工具來作實驗,我們可以把所有需要的組件壓縮成一個壓縮檔後,同樣也把它放入資源檔中。

image

 

利用CurrentDomain.AssemblyResolve事件,從壓縮中取出欲執行的組件會參考到的組件,把Assembly.Load載入的組件回傳就可以了。

Imports System.IO
Imports System.Reflection
Imports ICSharpCode.SharpZipLib.Zip

Module MainModule

    Private Function GetAssembly(ByVal assemblyName As String) As Assembly
        Using compressedMS As New MemoryStream(My.Resources.CliqueManager)
            Dim zf As New ZipFile(compressedMS)
            Dim ze As ZipEntry = zf.GetEntry(assemblyName)
            Dim zs As Stream = zf.GetInputStream(ze)
            Dim buffer(ze.Size - 1) As Byte
            zs.Read(buffer, 0, buffer.Length - 1)
            Return Assembly.Load(buffer)
        End Using
    End Function

    <STAThread()> _
    Public Sub main(ByVal args() As String)
        Dim currentDomain As AppDomain = AppDomain.CurrentDomain
        AddHandler currentDomain.AssemblyResolve, AddressOf currentDomain_AssemblyResolve

        GetAssembly("CliqueManager.exe").EntryPoint.Invoke(Nothing, Nothing)
    End Sub

    Private Function currentDomain_AssemblyResolve(ByVal sender As Object, ByVal e As ResolveEventArgs) As Assembly
        Return GetAssembly(e.Name.Substring(0, e.Name.IndexOf(","c)) & ".dll")
    End Function
End Module

 

以此例子來看,處理下來最後檔案總容量會變為執行檔195KB與壓縮組件196KB,共391KB,檔案大小會變得比較小,佈署的組件數量也會比較少。

 

Download

ExecuteAssemblyFromResource.zip