淺談VB.Net 程序的編譯和動態編譯


 

---恢復內容開始---

一般,我們都是通過Visual Studio(下面簡稱vs)來編寫和編譯vb.net應用程序的,但是,不少的人並不知道vs是通過何種方式編譯程序的。今天,我們就來探討一下編譯vb.net程序的真正原理。

這篇隨筆包含如下幾個部分:

  • 1.VS是怎么編譯的
  • 2.通過vbc.exe來編譯應用程序
  • 3.在代碼中通過VBCodeProvider動態編譯應用程序

ok,首先來說說vs編譯應用程序的方法。其實,vs是通過調用vbc.exe來編譯vbnet應用程序的。vs把用戶編寫的代碼文件和指定定的參數(引用,編譯出的程序的類型,目標文件的保存位置等)一股腦的傳給vbc,然后剩下的工作就交給vbc來做了。

其實,vbnet程序的編譯並不像我們想象的那么困難。對於編譯一些比較簡單的代碼,幾行cmd命令就可以完全搞定。而且,這個vbc.exe並不是vs的專用附屬,不論你是.net2.0還是最新的.net4.5.3預覽版,只要你家有.net Framework,就能找到vbc。vbc的地址是 C:\Windows\Microsoft.NET\Framework\.net版本(比如v4.0.30319)\vbc.exe.

可以cmd來調用它。這是截圖。

首先cd到指定路徑下然后調用vbc。vbc功能強大,這里列出一部分。

 

 

/out:<file>                       指定輸出文件名。
/target:exe                       創建控制台應用程序(默認)。 (縮寫: /t)
/target:winexe                    創建 Windows 應用程序。
/target:library                   創建庫程序集。
/target:module                    創建可添加到程序集的模塊。
/target:appcontainerexe           創建在 AppContainer 中運行的 Windows
                                  應用程序。
/target:winmdobj                  創建 Windows 元數據中間文件
/doc[+|-]                         生成 XML 文檔文件。
/doc:<file>                       將 XML 文檔文件生成到 <file>。

                                  - 輸入文件 -
/addmodule:<file_list>            從指定模塊中引用元數據。
/link:<file_list>                 嵌入所指定互操作程序集中的元數據。 (縮寫: /l)
/recurse:<wildcard>               根據通配符規范,包括當前目錄及子目錄下的所有文
                                  件。
/reference:<file_list>            從指定的程序集引用元數據。 (縮寫: /r)

                                  - 資源 -
/linkresource:<resinfo>           將指定文件鏈接為外部程序集資源。resinfo:
                                  <file>[,<name>[,public|private]] (縮寫:
                                  /linkres)
/nowin32manifest                  默認清單不應嵌入在輸出 PE 的清單部分中。
/resource:<resinfo>               將指定文件添加為嵌入的程序集資源。resinfo:
                                  <file>[,<name>[,public|private]] (縮寫: /res)
/win32icon:<file>                 為默認 Win32 資源指定 Win32 圖標文件(.ico)。
/win32manifest:<file>             提供的文件嵌入在輸出 PE 的清單部分中。
/win32resource:<file>             指定 Win32 資源文件(.res)。

                                  - 代碼生成 -
/optimize[+|-]                    啟用優化。
/removeintchecks[+|-]             移除整數檢查。默認為“關”。
/debug[+|-]                       發出調試信息。
/debug:full                       發出完全調試信息(默認)。
/debug:pdbonly                    只發出 PDB 文件。

                                  - 錯誤和警告 -
/nowarn                           禁用所有警告。
/nowarn:<number_list>             禁用各個警告的列表。
/warnaserror[+|-]                 將所有警告視為錯誤。
/warnaserror[+|-]:<number_list>   將警告列表視為錯誤。

這里詳細介紹幾個參數:

1./target

縮寫為/t 他指定了編譯類型。有四種選項 exe(將編譯成控制台應用程序) ,winexe(將編譯成 窗體應用程序),library(編譯成類庫【*.dll】)和module(編譯成模塊)。

例如 /t:exe

2./reference:<file_list>           

縮寫: /r 從指定的程序集引用元數據。  它的作用就相當於vs里的添加引用。可以通過指定這個參數來添加引用,vbc為我們默認引用了許多類庫。他們保存在vbc.rsp里。默認的vbc.rsp也就是默認添加的引用如下。

# This file contains command-line options that the VB
# command line compiler (VBC) will process as part
# of every compilation, unless the "/noconfig" option
# is specified.

# Reference the common Framework libraries
/r:Accessibility.dll
/r:System.Configuration.dll
/r:System.Configuration.Install.dll
/r:System.Data.dll
/r:System.Data.OracleClient.dll
/r:System.Deployment.dll
/r:System.Design.dll
/r:System.DirectoryServices.dll
/r:System.dll
/r:System.Drawing.Design.dll
/r:System.Drawing.dll
/r:System.EnterpriseServices.dll
/r:System.Management.dll
/r:System.Messaging.dll
/r:System.Runtime.Remoting.dll
/r:System.Runtime.Serialization.Formatters.Soap.dll
/r:System.Security.dll
/r:System.ServiceProcess.dll
/r:System.Transactions.dll
/r:System.Web.dll
/r:System.Web.Mobile.dll
/r:System.Web.RegularExpressions.dll
/r:System.Web.Services.dll
/r:System.Windows.Forms.Dll
/r:System.XML.dll

/r:System.Workflow.Activities.dll
/r:System.Workflow.ComponentModel.dll
/r:System.Workflow.Runtime.dll
/r:System.Runtime.Serialization.dll
/r:System.ServiceModel.dll

/r:System.Core.dll
/r:System.Xml.Linq.dll
/r:System.Data.Linq.dll
/r:System.Data.DataSetExtensions.dll
/r:System.Web.Extensions.dll
/r:System.Web.Extensions.Design.dll
/r:System.ServiceModel.Web.dll

# Import System and Microsoft.VisualBasic
/imports:System
/imports:Microsoft.VisualBasic
/imports:System.Linq
/imports:System.Xml.Linq

/optioninfer+


下面我們來一個簡單的vbc編譯例子。

首先我們編寫了一個最最簡單的vb代碼。如下:

Imports System.Windows.Forms
Module Module1

    Sub Main()
        MessageBox.Show("Hello World")
    End Sub

End Module

我們把它保存到vbc的目錄下。名為a.txt

我們調用cmd,cd 到指定目錄下,調用vbc.exe執行下面的命令:vbc.exe a.txt.然后回車。編譯成功。

這時目錄下出現了一個a.exe的文件。點擊執行,效果如下。

消息框彈出了。后面還有個黑框框。有人可能會問了,這里並沒有什么/r /t的,為什么會成功呢?這就是默認的緣故。我們說了,/t默認為exe(控制台),/r默認引用了vbc.rsp里的程序集。所以可以成功。

好了,這里就不多講了,大家可以自己看着參數摸索一下,很容易就會掌握了。


 

 下面進入第三部分,vbnet的動態編譯。

動態編譯,即在代碼中動態編譯出程序。方法有很多,可以調用vbc,也可以使用反射,但我們這里使用一種較為簡單的方法VBCodeProvider。

為使用,首先添加引用

Imports System.Reflection
Imports System.CodeDom.Compiler

然后,聲明VBCodeProvider對象。

 

      Dim cp As New VBCodeProvider()

這樣,就創建了一個vb編譯器實例。

我們還要再聲明一個參數對象。CompilerParameters

  Dim cParameters As New CompilerParameters()

我就不放出CompilerParameters的成員列表了。大家可從http://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=ZH-CN&k=k%28System.CodeDom.Compiler.CompilerParameters%29;k%28TargetFrameworkMoniker-.NETFramework 查看。

這里講一下它的幾個重要的屬性

1.GenerateExecutable 通過它可以設置是否編譯成exe文件。我們這里為true。

2.GenerateInMemory 他可以指示是否在內存中生成輸出。 這里為false。

3. OutputAssembly 用它來設置輸出程序集的名稱。

4.ReferencedAssemblies 獲取本程序引用的程序集。可以通過ReferencedAssemblies的Add方法添加引用。

設置完了之后來上這一句獲得編譯結果

Dim cresult As CompilerResults = pc.CompileAssemblyFromFile(cParameters, "a.txt")

 

這就是說,用cParameters作為參數編譯a.txt這個文件,返回編譯結果給cresult

 

然后對cresult進行操作保存生成的exe,詳見代碼。

好了,用這個方法方法,我們用代碼編譯a.txt

我很懶,就直接寫在form的load里面了。

 

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        '聲明
        Dim pc As VBCodeProvider = New VBCodeProvider
        Dim cParameters As New CompilerParameters()
        cParameters.GenerateExecutable = True '生成exe文件
        cParameters.GenerateInMemory = False '不在內存中生成



        '添加引用
        cParameters.ReferencedAssemblies.Add("System.dll")
        cParameters.ReferencedAssemblies.Add("System.Windows.Forms.dll")

        '編譯並返回結果
        Dim cresult As CompilerResults = pc.CompileAssemblyFromFile(cParameters, "a.txt")
        If cresult.NativeCompilerReturnValue = 0 Then
            '如果編譯成功
            Try
                '避免重名而報錯,刪除舊文件
                My.Computer.FileSystem.DeleteFile("a.exe")
            Catch ex As Exception

            End Try
            '把生成的文件移動到目標目錄下(因為他是保存在一個特定的地方, 文件名也是隨機的)
            My.Computer.FileSystem.MoveFile(cresult.PathToAssembly, "a.exe")
        Else
            For Each a As CompilerError In cresult.Errors
                '出錯,顯示錯誤信息
                MsgBox(a.ErrorText)
            Next
        End If



    End Sub

這樣,一個簡單編譯器就做好了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM