有关Vb的CodeDom动态编译

来源:互联网 发布:喜马拉雅山攀登 知乎 编辑:程序博客网 时间:2024/06/06 11:40

本人对于代码什么的完全是个渣滓,写的不好也希望不要见怪。


在使用VB6时,想要动态编译的话大部分人会选择Script Control控件,用Windows脚本宿主运行VBS来代替Vb部分功能,从而实现动态编译。然而,VBS毕竟是脚本语言,在各个方面上都有很大的限制,在VB.NET甚至后续去除.NET标签的VB中使用这种方法,局限性被再次放大,很多人开始寻找新的方法。


现在在.NET平台上动态编译已经有CodeDom这种选择了,个人有一次需要动态编译就在网上查了些资料,基本上都是有看没有懂。但在看了有一个关于使用vbc.exe编译的时候突然有所体会。


想使用CodeDom进行动态编译,需要了解两个货色:VBCodeProvider与CompilerParameters。去掉各种难懂的语言通俗地讲,前者是编译器,后者是用来设置的。编译的时候肯定要设置许多编译属性,所以CompilerParameters是主要的操作对象,而VBCodeProvider用作于设置完成后一键编译。这些内容需要了解,不然可能New了这个又New那个,还是没什么成色。所以,就先新建一个类,起名为VBPro,写入:


Imports System.CodeDom.CompilerPublic Class VBPro    Dim VBProvid As New VBCodeProvider()    Dim VBComp As New CompilerParametersEnd Class

既然VBComp是主要的操作对象,就来了解基本要用的VBComp的成员或方法:


GenerateExecutable(Boolean):编译成直接的可执行文件(exe)还是间接的可执行文件(dll)


GenerateInMemory(Boolean):是否在内存中生成


OutputAssembly(String):输出路径


ReferencedAssemblies.Add:添加引用的程序集


CompilerOptions(String):汇编选项,可以理解为命令行参数


了解了大概后,可以写一个公共方法来进行编译:


Imports System.CodeDom.CompilerPublic Class VBPro    Dim VBProvid As New VBCodeProvider()    Dim VBComp As New CompilerParameters    Public Sub BuildProgram(SourcePath As String, BuildPath As String)    End SubEnd Class

用SourcePath指示源代码文件,BuildPath指示输出文件,然后就可以把刚刚了解的一些成员加进去:


Imports System.CodeDom.CompilerPublic Class VBPro    Dim VBProvid As New VBCodeProvider()    Dim VBComp As New CompilerParameters    Public Sub BuildProgram(SourcePath As String, BuildPath As String)        VBComp.GenerateExecutable = True '生成EXE文件而不是DLL        VBComp.GenerateInMemory = False '生成真实的文件而不是在内存中生成        VBComp.OutputAssembly = BuildPath '确定生成路径        VBComp.ReferencedAssemblies.Add("System.dll") '引用System程序集   End SubEnd Class

该设置的都差不多了,那如何进行最重要的编译呢?要知道,如果没有编译这一句,其实上面的可以说是没什么用。编译比想象中的简单,就一句话:


Dim VBPrg As CompilerResults = VBProvid.CompileAssemblyFromFile(VBComp, SourcePath)

选取路径为SourcePath的源代码文件进行编译,VBPrg代表此次编译的程序。为了防止编译时因为源代码文件代码的书写错误,还可以加上错误检测,总体就是:


Imports System.CodeDom.CompilerPublic Class VBPro    Dim VBProvid As New VBCodeProvider()    Dim VBComp As New CompilerParameters    Public Sub BuildProgram(SourcePath As String, BuildPath As String)        VBComp.GenerateExecutable = True '生成EXE文件而不是DLL        VBComp.GenerateInMemory = False '生成真实的文件而不是在内存中生成        VBComp.OutputAssembly = BuildPath '确定生成路径        VBComp.ReferencedAssemblies.Add("System.dll") '引用System程序集        Dim VBPrg As CompilerResults = VBProvid.CompileAssemblyFromFile(VBComp, SourcePath)        If VBPrg.NativeCompilerReturnValue = 0 Then        Else            For Each ErIm As CompilerError In VBPrg.Errors                MsgBox(ErIm.ErrorText, vbCritical, "编译错误     ")            Next        End If   End SubEnd Class

这样就可以生成了,这里的代码面向的是.NET Framework 4.5+,较低的版本编译的时候可能会生成在默认的随机隐藏路径,这个时候就要用MoveFile剪切过去。


在SourcePath指向的路径中可以写下一些代码,如:


Imports System.Windows.FormsModule Module1    Sub Main        MessageBox.Show("Hello World")    End SubEnd Module

需要注意的是,它默认没有引用程序集,所以要手动Imports。最后生成运行,会发现其他的地方都还好,就是生成的是控制台应用,可能有些人会反感。下面的例子让VB编译器生成WindowsForm窗体程序:


Imports System.CodeDom.CompilerPublic Class VBPro    Dim VBProvid As New VBCodeProvider()    Dim VBComp As New CompilerParameters    Public Sub BuildProgram(SourcePath As String, BuildPath As String)        VBComp.GenerateExecutable = True '生成EXE文件而不是DLL        VBComp.GenerateInMemory = False '生成真实的文件而不是在内存中生成        VBComp.OutputAssembly = BuildPath '确定生成路径        VBComp.ReferencedAssemblies.Add("System.dll") '引用System程序集        VBComp.CompilerOptions = ("/target:winexe") '命令参数        Dim VBPrg As CompilerResults = VBProvid.CompileAssemblyFromFile(VBComp, SourcePath)        If VBPrg.NativeCompilerReturnValue = 0 Then        Else            For Each ErIm As CompilerError In VBPrg.Errors                MsgBox(ErIm.ErrorText, vbCritical, "编译错误     ")            Next        End If   End SubEnd Class

只是多了“命令参数”这一段,就可以生成窗体程序,对应的有


/target:exe
/target:winexe
/target:library
/target:module

共四种编译模式。窗体程序也是默认不带窗体,因为VS给的是模板而这里是空的,需要WithEvents之类的手动生成完整的一个窗体。然而问题还没有解决完成,运行后发现窗体会一闪而过,就是执行完全部代码自动退出而不保留窗体。这就不是编译的问题了,而是我们习惯用"Show"启动窗体的关系,要在选取的源代码文件上做文章:


Imports System.Windows.FormsModule Module1    Public WithEvents Form1 As New Form    Public WithEvents Butn1 As New Button    Sub Main()        Form1.Visible = True        'Form1.Show() 不使用"Show",换成下面的:        Application.Run(Form1)    End Sub    Private Sub Form1_Load() Handles Form1.Load        Form1.Controls.Add(Butn1)    End Sub    Private Sub Butn1_Click() Handles Butn1.Click        MessageBox.Show("Hello World")    End SubEnd Module

窗体就不会自动卸载了,同时由于不是模板的关系,XP视觉效果自动关闭,要在过程中添加。完整的就是:


Imports System.Windows.FormsModule Module1    Public WithEvents Form1 As New Form    Public WithEvents Butn1 As New Button    Sub Main()        Application.EnableVisualStyles() '添加XP视觉效果(XPManifest)       Form1.Visible = True        'Form1.Show() 不使用"Show",换成下面的:        Application.Run(Form1)    End Sub    Private Sub Form1_Load() Handles Form1.Load        Form1.Controls.Add(Butn1)    End Sub    Private Sub Butn1_Click() Handles Butn1.Click        MessageBox.Show("Hello World")    End SubEnd Module

将视觉效果(XPManifest)添加上去后,一个简单的CodeDom动态编译器就算是完成了。


写的很渣,有什么描述错误的地方也希望大家提出来,我也会进行改正。

原创粉丝点击