0

I've written this simple function to automate the compilation of a single exe assembly with an embedded resource:

Public Shared Function CompileAssembly(ByVal codeProvider As CodeDomProvider,
                                   ByVal isExecutable As Boolean,
                                   ByVal targetFile As String,
                                   Optional ByVal resources As IEnumerable(Of String) = Nothing,
                                   Optional ByVal code As String = "") As CompilerResults

Dim cp As New CompilerParameters
With cp

    ' Generate an exe or a dll.
    .GenerateExecutable = isExecutable

    ' Set the assembly file name to generate.
    .OutputAssembly = targetFile

    ' Set compiler argument to optimize output.
    .CompilerOptions = "/optimize"

    ' Specify the class that contains the main method of the executable.
    If codeProvider.Supports(GeneratorSupport.EntryPointMethod) Then
        .MainClass = "MainClass"
    End If

    ' Set the embedded resource file of the assembly. 
    If codeProvider.Supports(GeneratorSupport.Resources) AndAlso resources IsNot Nothing Then
        .EmbeddedResources.AddRange(resources.ToArray)
    End If

End With

Return codeProvider.CompileAssemblyFromSource(cp, code)

End Function

The problem is that I need to compile a non-commandline application, a Class like this which I provide a method that should be executed when the app runs:

    Dim sourceCode As String =
        <a>
Public Class MainClass 

    Sub MainMethod()
       ' Do Something when the app is executed...
    End Sub

End Class
        </a>.Value

but I can't find the way to do it.

I only can compile console applications because the codeprovider seems that needs an entrypoint, so I only be able to compile this, which is not what I want:

    Dim Sourcecode As String =
        <a>
Module MainModule

    Sub Main()
    End Sub

End Module
        </a>.Value

How I could do this for my needs?.

5
  • without an entry point/Sub Main, it is not an executable and wont run. If you want MainClass.MainMenthod to execute, there has to be code somewhere to instance the class and invoke the method. Maybe you want a DLL? Commented Jun 14, 2015 at 12:11
  • @Plutonix No, I pretend to compile an executable, but just not a commandline executable. I want to compile an exe that does not open the console, just like a WinForms project. Do you understand what I pretend to do?, an exe that don't have console but has a main method, or in other words I want a GUI app that will have set an "nvisible form, but I don't know how to create that sourcecode at execution time like the sourcecodes of the examples above because the codedomprovider seems it only accepts a modules (of a commandline app) not forms, I can't explain it in a better way. Thanks for comment Commented Jun 14, 2015 at 12:31
  • Such an app still requires a Sub Main - The entry point. All apps (executables) have them, they are hidden in VB apps that use a Main Startup form but it is there (Application.Run(New MainForm)). Commented Jun 14, 2015 at 12:36
  • @Plutonix Thanks but the problem is that it stills a commandline app. A WinForms project does not show a console, then I just don't want to show a console when this exe is ran (I don't want to call APIs to hide the console after shown or tricks like that, I just want to avoid the console instance like when compiling a WinForms project), I'm using this code: pastebin.com/DCuX4quL Commented Jun 14, 2015 at 12:44
  • I found the solution, was very easy!! I only need to add this parameter to the compiler parameters: /target:winexe as explained here: stackoverflow.com/questions/2661171/… Commented Jun 14, 2015 at 12:51

1 Answer 1

1

I just want to share my working CodeDomProvider compiler routine:

Imports System.CodeDom.Compiler

Namespace Tools

    Public NotInheritable Class CodeDomUtil

        ''' <summary>
        ''' Specifies a <see cref="CompilerParameters"></see> target assembly.
        ''' </summary>
        Public Enum TargetAssembly As Integer

            ''' <summary>
            ''' A Command line interface executable.
            ''' </summary>
            Cli = 0

            ''' <summary>
            ''' A Graphical user interface executable.
            ''' </summary>
            Gui = 1

            ''' <summary>
            ''' A Dynamic-link library.
            ''' </summary>
            Dll = 2

        End Enum

        ''' <remarks>
        ''' *****************************************************************
        ''' Title : Compile Assembly (from reaource).
        ''' Author: Elektro
        ''' Date  : 14-June-2015
        ''' Usage : 
        ''' 
        ''' Using vbCodeProvider As New Microsoft.VisualBasic.VBCodeProvider
        ''' 
        '''     Dim resultVB As CompilerResults =
        '''         CodeDomUtil.CompileAssembly(codeProvider:=vbCodeProvider,
        '''                                     targetAssembly:=CodeDomUtil.TargetAssembly.Dll,
        '''                                     targetFile:="C:\VB Assembly.dll",
        '''                                     resources:={"C:\MyResources.resx"},
        '''                                     referencedAssemblies:={"System.dll"},
        '''                                     mainClassName:="MainNamespace.MainClass",
        '''                                     sourceCode:=<a>
        '''                                                 Imports System
        ''' 
        '''                                                 Namespace MainNamespace
        ''' 
        '''                                                     Public NotInheritable MainClass
        ''' 
        '''                                                     End Class
        ''' 
        '''                                                 End Namespace
        '''                                                 </a>.Value)
        ''' 
        '''     Dim warnings As IEnumerable(Of CompilerError) =
        '''         From ce As CompilerError In resultVB.Errors.Cast(Of CompilerError)()
        '''         Where ce.IsWarning
        ''' 
        '''     Dim errors As IEnumerable(Of CompilerError) =
        '''         From ce As CompilerError In resultVB.Errors.Cast(Of CompilerError)()
        '''         Where Not ce.IsWarning
        ''' 
        '''     For Each war As CompilerError In warnings
        '''         Debug.WriteLine(String.Format("{0}| Warning: {1}", war.ErrorNumber, war.ErrorText))
        '''     Next war
        ''' 
        '''     For Each err As CompilerError In errors
        '''         Debug.WriteLine(String.Format("{0}| Error: {1}", err.ErrorNumber, err.ErrorText))
        '''     Next err
        ''' 
        ''' End Using
        ''' -----------------------------------------------------------------
        ''' Using csCodeProvider As New Microsoft.CSharp.CSharpCodeProvider
        '''
        '''     Dim resultCS As CompilerResults =
        '''         CodeDomUtil.CompileAssembly(codeProvider:=csCodeProvider,
        '''                                     targetAssembly:=CodeDomUtil.TargetAssembly.Dll,
        '''                                     targetFile:="C:\C# Assembly.dll",
        '''                                     resources:={"C:\MyResources.resx"},
        '''                                     referencedAssemblies:={"System.dll"},
        '''                                     mainClassName:="MainNamespace.MainClass",
        '''                                     sourceCode:=<a>
        '''                                                 using System;
        '''
        '''                                                 namespace MainNamespace
        '''                                                 {
        '''                                                     class MainClass
        '''                                                     {
        '''
        '''                                                     }
        '''                                                 }
        '''                                                 </a>.Value)
        '''
        '''     Dim warnings As IEnumerable(Of CompilerError) =
        '''         From ce As CompilerError In resultCS.Errors.Cast(Of CompilerError)()
        '''         Where ce.IsWarning
        '''
        '''     Dim errors As IEnumerable(Of CompilerError) =
        '''         From ce As CompilerError In resultCS.Errors.Cast(Of CompilerError)()
        '''         Where Not ce.IsWarning
        '''
        '''     For Each war As CompilerError In warnings
        '''         Debug.WriteLine(String.Format("{0}| Warning: {1}", war.ErrorNumber, war.ErrorText))
        '''     Next war
        '''
        '''     For Each err As CompilerError In errors
        '''         Debug.WriteLine(String.Format("{0}| Error: {1}", err.ErrorNumber, err.ErrorText))
        '''     Next err
        '''
        ''' End Using
        ''' *****************************************************************
        ''' </remarks>
        ''' <summary>
        ''' Compiles a .Net assembly as executable or link library.
        ''' </summary>
        ''' <param name="codeProvider">The code provider.</param>
        ''' <param name="targetAssembly">The kind of assembly to generate.</param>
        ''' <param name="targetFile">The target file to create.</param>
        ''' <param name="resources">The embedded resources (if any).</param>
        ''' <param name="referencedAssemblies">The referenced assemblies (if any).</param>
        ''' <param name="mainClassName">The code to compile (if any).</param>
        ''' <param name="sourceCode">The sourcecode to compile (if any).</param>
        ''' <exception cref="Exception">The current CodeDomProvider does not support resource embedding.</exception>
        ''' <exception cref="NotImplementedException">Default sourcecode is not implemented for the specified CodeDomProvider. Please, set a sourcecode yourself.</exception>
        ''' <returns>The results of the compiler operation.</returns>
        Public Shared Function CompileAssembly(ByVal codeProvider As CodeDomProvider,
                                               ByVal targetAssembly As TargetAssembly,
                                               ByVal targetFile As String,
                                               Optional ByVal resources As IEnumerable(Of String) = Nothing,
                                               Optional ByVal referencedAssemblies As IEnumerable(Of String) = Nothing,
                                               Optional ByVal mainClassName As String = "MainNamespace.MainClass",
                                               Optional ByVal sourceCode As String = Nothing) As CompilerResults

            ' Set a default assembly reference.
            If referencedAssemblies Is Nothing Then
                referencedAssemblies = {"System.dll"}
            End If

            Dim cp As New CompilerParameters
            With cp

                ' Set compiler arguments.
                Select Case targetAssembly

                    Case CodeDomUtil.TargetAssembly.Gui
                        .CompilerOptions = "/optimize /target:winexe"

                    Case Else
                        .CompilerOptions = "/optimize"

                End Select

                ' Generate an exe or a dll.
                .GenerateExecutable = (targetAssembly <> CodeDomUtil.TargetAssembly.Dll)

                ' Save the assembly as a physical file.
                .GenerateInMemory = False

                ' Generate debug information (pdb).
                .IncludeDebugInformation = False

                ' Set the assembly file name to generate.
                .OutputAssembly = targetFile

                ' Add an assembly reference.
                .ReferencedAssemblies.AddRange(referencedAssemblies.ToArray)

                ' Set a temporary files collection. 
                ' The TempFileCollection stores the temporary files generated during a build in the current directory.
                .TempFiles = New TempFileCollection(tempdir:=IO.Path.GetTempPath(), keepFiles:=True)

                ' Set whether to treat all warnings as errors.
                .TreatWarningsAsErrors = False

                ' Set the level at which the compiler should start displaying warnings.
                ' 0 - Turns off emission of all warning messages.
                ' 1 - Displays severe warning messages.
                ' 2 - Displays level 1 warnings plus certain, less-severe warnings, such as warnings about hiding class members.
                ' 3 - Displays level 2 warnings plus certain, less-severe warnings, such as warnings about expressions that always evaluate to true or false.
                ' 4 - Displays all level 3 warnings plus informational warnings. This is the default warning level at the command line.
                .WarningLevel = 3

                ' Set the embedded resource file of the assembly. 
                If codeProvider.Supports(GeneratorSupport.Resources) AndAlso (resources IsNot Nothing) Then
                    .EmbeddedResources.AddRange(resources.ToArray)

                ElseIf (Not codeProvider.Supports(GeneratorSupport.Resources)) AndAlso (resources IsNot Nothing) Then
                    Throw New Exception(message:="The current CodeDomProvider does not support resource embedding.")

                End If

                ' Specify the class that contains the main method of the executable.
                If codeProvider.Supports(GeneratorSupport.EntryPointMethod) Then

                    .MainClass = mainClassName

                    If (TypeOf codeProvider Is Microsoft.VisualBasic.VBCodeProvider) AndAlso
                       (String.IsNullOrEmpty(sourceCode)) AndAlso
                       .GenerateExecutable Then

                        sourceCode =
                            <a>
                            Imports System

                            Namespace MainNamespace

                                Module MainClass

                                    Sub Main()
                                    End Sub

                                End Module

                            End Namespace
                            </a>.Value

                    ElseIf (TypeOf codeProvider Is Microsoft.VisualBasic.VBCodeProvider) AndAlso
                           (String.IsNullOrEmpty(sourceCode)) AndAlso
                           Not .GenerateExecutable Then

                        sourceCode =
                            <a>
                            Imports System

                            Namespace MainNamespace

                                Public NotInheritable MainClass

                                End Class

                            End Namespace
                            </a>.Value

                    ElseIf (TypeOf codeProvider Is Microsoft.CSharp.CSharpCodeProvider) AndAlso
                           (String.IsNullOrEmpty(sourceCode)) AndAlso
                          .GenerateExecutable Then

                        sourceCode =
                            <a>
                            using System;

                            namespace MainNamespace
                            {
                                class MainClass
                                {
                                    static void Main(string[] args)
                                    {

                                    }
                                }
                            }
                            </a>.Value

                    ElseIf (TypeOf codeProvider Is Microsoft.CSharp.CSharpCodeProvider) AndAlso
                           (String.IsNullOrEmpty(sourceCode)) AndAlso
                           Not .GenerateExecutable Then

                        sourceCode =
                            <a>
                            using System;

                            namespace MainNamespace
                            {
                                class MainClass
                                {

                                }
                            }
                            </a>.Value

                    ElseIf String.IsNullOrEmpty(sourceCode) Then
                        Throw New NotImplementedException(message:="Default sourcecode is not implemented for the specified CodeDomProvider. Please, specify a sourcecode.")

                    End If

                End If

            End With

            Return codeProvider.CompileAssemblyFromSource(cp, sourceCode)

        End Function

        ''' <remarks>
        ''' *****************************************************************
        ''' Title : Compile Assembly (from file).
        ''' Author: Elektro
        ''' Date  : 14-June-2015
        ''' Usage : 
        ''' 
        ''' Using vbCodeProvider As New Microsoft.VisualBasic.VBCodeProvider
        '''
        '''     Dim resultVB As CompilerResults =
        '''         CodeDomUtil.CompileAssembly(codeProvider:=vbCodeProvider,
        '''                                     targetAssembly:=CodeDomUtil.TargetAssembly.Dll,
        '''                                     sourceFile:="C:\SourceCode.vb",
        '''                                     targetFile:="C:\VB Assembly.dll",
        '''                                     resources:={"C:\MyResources.resx"},
        '''                                     referencedAssemblies:={"System.dll"},
        '''                                     mainClassName:="MainNamespace.MainClass")
        '''
        '''     Dim warnings As IEnumerable(Of CompilerError) =
        '''         From ce As CompilerError In resultVB.Errors.Cast(Of CompilerError)()
        '''         Where ce.IsWarning
        '''
        '''     Dim errors As IEnumerable(Of CompilerError) =
        '''         From ce As CompilerError In resultVB.Errors.Cast(Of CompilerError)()
        '''         Where Not ce.IsWarning
        '''
        '''     For Each war As CompilerError In warnings
        '''         Debug.WriteLine(String.Format("{0}| Warning: {1}", war.ErrorNumber, war.ErrorText))
        '''     Next war
        '''
        '''     For Each err As CompilerError In errors
        '''         Debug.WriteLine(String.Format("{0}| Error: {1}", err.ErrorNumber, err.ErrorText))
        '''     Next err
        '''
        ''' End Using
        ''' -----------------------------------------------------------------
        ''' Using csCodeProvider As New Microsoft.CSharp.CSharpCodeProvider
        '''
        '''     Dim resultCS As CompilerResults =
        '''         CodeDomUtil.CompileAssembly(codeProvider:=csCodeProvider,
        '''                                     targetAssembly:=CodeDomUtil.TargetAssembly.Dll,
        '''                                     sourceFile:="C:\SourceCode.cs",
        '''                                     targetFile:="C:\CS Assembly.dll",
        '''                                     resources:={"C:\MyResources.resx"},
        '''                                     referencedAssemblies:={"System.dll"},
        '''                                     mainClassName:="MainNamespace.MainClass")
        '''
        '''     Dim warnings As IEnumerable(Of CompilerError) =
        '''         From ce As CompilerError In resultCS.Errors.Cast(Of CompilerError)()
        '''         Where ce.IsWarning
        '''
        '''     Dim errors As IEnumerable(Of CompilerError) =
        '''         From ce As CompilerError In resultCS.Errors.Cast(Of CompilerError)()
        '''         Where Not ce.IsWarning
        '''
        '''     For Each war As CompilerError In warnings
        '''         Debug.WriteLine(String.Format("{0}| Warning: {1}", war.ErrorNumber, war.ErrorText))
        '''     Next war
        '''
        '''     For Each err As CompilerError In errors
        '''         Debug.WriteLine(String.Format("{0}| Error: {1}", err.ErrorNumber, err.ErrorText))
        '''     Next err
        '''
        ''' End Using
        ''' *****************************************************************
        ''' </remarks>
        ''' <summary>
        ''' Compiles a .Net assembly as executable or link library.
        ''' </summary>
        ''' <param name="codeProvider">The code provider.</param>
        ''' <param name="targetAssembly">The kind of assembly to generate.</param>
        ''' <param name="sourceFile">The source file to compile.</param>
        ''' <param name="targetFile">The target file to create.</param>
        ''' <param name="resources">The embedded resources (if any).</param>
        ''' <param name="referencedAssemblies">The referenced assemblies (if any).</param>
        ''' <param name="mainClassName">The code to compile (if any).</param>
        ''' <exception cref="Exception">The current CodeDomProvider does not support resource embedding.</exception>
        ''' <returns>The results of the compiler operation.</returns>
        Public Shared Function CompileAssembly(ByVal codeProvider As CodeDomProvider,
                                               ByVal targetAssembly As TargetAssembly,
                                               ByVal sourceFile As String,
                                               ByVal targetFile As String,
                                               Optional ByVal resources As IEnumerable(Of String) = Nothing,
                                               Optional ByVal referencedAssemblies As IEnumerable(Of String) = Nothing,
                                               Optional ByVal mainClassName As String = "MainNamespace.MainClass") As CompilerResults

            ' Set a default assembly reference.
            If referencedAssemblies Is Nothing Then
                referencedAssemblies = {"System.dll"}
            End If

            Dim cp As New CompilerParameters
            With cp

                ' Set compiler arguments.
                Select Case targetAssembly

                    Case CodeDomUtil.TargetAssembly.Gui
                        .CompilerOptions = "/optimize /target:winexe"

                    Case Else
                        .CompilerOptions = "/optimize"

                End Select

                ' Generate an exe or a dll.
                .GenerateExecutable = (targetAssembly <> CodeDomUtil.TargetAssembly.Dll)

                ' Save the assembly as a physical file.
                .GenerateInMemory = False

                ' Generate debug information (pdb).
                .IncludeDebugInformation = False

                ' Set the assembly file name to generate.
                .OutputAssembly = targetFile

                ' Add an assembly reference.
                .ReferencedAssemblies.AddRange(referencedAssemblies.ToArray)

                ' Set a temporary files collection. 
                ' The TempFileCollection stores the temporary files generated during a build in the current directory.
                .TempFiles = New TempFileCollection(tempdir:=IO.Path.GetTempPath(), keepFiles:=True)

                ' Set whether to treat all warnings as errors.
                .TreatWarningsAsErrors = False

                ' Set the level at which the compiler should start displaying warnings.
                ' 0 - Turns off emission of all warning messages.
                ' 1 - Displays severe warning messages.
                ' 2 - Displays level 1 warnings plus certain, less-severe warnings, such as warnings about hiding class members.
                ' 3 - Displays level 2 warnings plus certain, less-severe warnings, such as warnings about expressions that always evaluate to true or false.
                ' 4 - Displays all level 3 warnings plus informational warnings. This is the default warning level at the command line.
                .WarningLevel = 3

                ' Set the embedded resource file of the assembly. 
                If codeProvider.Supports(GeneratorSupport.Resources) AndAlso (resources IsNot Nothing) Then
                    .EmbeddedResources.AddRange(resources.ToArray)

                ElseIf (Not codeProvider.Supports(GeneratorSupport.Resources)) AndAlso (resources IsNot Nothing) Then
                    Throw New Exception(message:="The current CodeDomProvider does not support resource embedding.")

                End If

                ' Specify the class that contains the main method of the executable.
                If codeProvider.Supports(GeneratorSupport.EntryPointMethod) Then
                    .MainClass = mainClassName
                End If

            End With

            Return codeProvider.CompileAssemblyFromFile(cp, {sourceFile})

        End Function

    End Class

End Namespace
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.