Search code examples
vb.netcodedom

How to compile Windows Form Application source code using CodeDOM


I need to create a VB.NET application that takes the source code of a Windows Form Application and compiles it. I used this link as a reference.

Windows Form Application that I want to create

Public Class Form2
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    MsgBox("test")
End Sub

End Class

My VB.NET application that compiles the code

Imports System.IO
Imports System.Reflection
Imports System.CodeDom
Imports System.CodeDom.Compiler
Imports Microsoft.VisualBasic

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim codeProvider As New VBCodeProvider()
    Dim icc As ICodeCompiler = codeProvider.CreateCompiler
    Dim Output As String = "Out.exe"
    Dim ButtonObject As Button = CType(sender, Button)

    textBox2.Text = ""
    Dim parameters As New CompilerParameters()
    Dim results As CompilerResults
    'Make sure we generate an EXE, not a DLL
    parameters.GenerateExecutable = True
    parameters.OutputAssembly = Output
    results = icc.CompileAssemblyFromSource(parameters, textBox1.Text)

    If results.Errors.Count > 0 Then
        'There were compiler errors
        textBox2.ForeColor = Color.Red
        Dim CompErr As CompilerError
        For Each CompErr In results.Errors
            textBox2.Text = textBox2.Text &
            "Line number " & CompErr.Line &
            ", Error Number: " & CompErr.ErrorNumber &
            ", '" & CompErr.ErrorText & ";" &
            Environment.NewLine & Environment.NewLine
        Next
    Else
        'Successful Compile
        textBox2.ForeColor = Color.Blue
        textBox2.Text = "Success!"
        'If we clicked run then launch the EXE
        If ButtonObject.Text = "Run" Then Process.Start(Output)
    End If
End Sub

Textbox1.text contains the first code i provided. When i run the program it gives me this errors

Line number 0, Error Number: BC30420, ''Sub Main' was not found in 'Out'.;

Line number 2, Error Number: BC30002, 'Type 'EventArgs' is not defined.;

Line number 3, Error Number: BC30451, ''MsgBox' is not declared. It may be inaccessible due to its protection level.;

Line number 3, Error Number: BC32017, 'Comma, ')', or a valid expression continuation expected.;


Solution

  • Well, you are missing a lot of things.

    In the CompilerParameters that you'll pass to your CodeDomProvider you must specify the target exe-type, default is "/target:exe" which means Console Executable (then the compiler tries to find a Sub Main() for Entry Point), so you must specify "/target:winexe" for a WindowsForms project.

    You also must specify the required Imports in the source-code to compile... otherwise that will not be resolved, and the same for the required .NET assembly references for your source-code, you must specify all them in your CompilerParameters.

    And finally you should specify the name of the main class then you will be able to compile it.

    I'll show a working example that you can adapt/replace for your current source-code:

        Public Shared ReadOnly WinFormsTemplate As String =
    <a>
    Imports System
    Imports System.Windows.Forms
    
    Namespace MyNamespace
    
        Public NotInheritable Class Form1 : Inherits Form
    
            Public Sub New()
                Me.StartPosition = FormStartPosition.CenterScreen
            End Sub
    
            Private Sub Form1_Shown(ByVal sender As Object, ByVal e As EventArgs) _
            Handles MyBase.Shown
                MessageBox.Show("VisualBasic.NET WinForms Template.")
            End Sub
    
        End Class
    
    End Namespace
    </a>.Value
    
    Private Sub CompileSourceCode()
    
        Dim cProvider As CodeDomProvider = New VBCodeProvider
        Dim cParams As New CompilerParameters
        Dim cResult As CompilerResults
        Dim sourceCode As String = WinFormsTemplate
    
        With cParams
            .GenerateInMemory = False
            .GenerateExecutable = True
            .OutputAssembly = Path.Combine(My.Application.Info.DirectoryPath, ".\test.exe")
            .CompilerOptions = "/target:winexe"
            .ReferencedAssemblies.AddRange({"System.dll", "System.Windows.Forms.dll", "Microsoft.VisualBasic.dll"})
            .MainClass = "MyNamespace.Form1"
        End With
    
        cResult = cProvider.CompileAssemblyFromSource(cParams, sourceCode)
        cProvider.Dispose()
    
    End Sub