Batch File Compiler Concept

The following applies to the MS .NET languages.
In C#.NET and VB.NET there is a namespace that contains a set of objects that we can use to compile VB.NET or C# code.
That’s right, we have the power to create .NET Programs that can create other .NET programs.

The namespace is known as System.CodeDom
In this article I will demonstrate a simple batch file compiler using System.CodeDom.

The way this batch file compiler will work is that the output exe from the given batch file source will have the batch file
as an embedded resource. When executed, the program will extract that batch file to a folder and run that batch file.
After the batch file exits, the program will delete the extracted batch file and close.

So here is the batch file compiler in VB:

Module Program
   Dim cin As System.IO.TextReader = console.In
   Dim cout As System.IO.TextWriter = console.Out
   Dim args = my.Application.CommandLineArgs
   
   Sub Main()
      
      If my.Application.CommandLineArgs.Count ( 2 Then
         help()
         Return
      End If
      
      Dim compar As New System.CodeDom.Compiler.CompilerParameters
      
      compar.CompilerOptions = "/target:winexe"
      compar.GenerateExecutable = True
      compar.IncludeDebugInformation = False

      'Embed batch file as resource to exe
      compar.EmbeddedResources.Add(args.Item(0))
      
      'Output exe filename
      compar.OutputAssembly = args.Item(1)
      compar.GenerateInMemory = False
      compar.TreatWarningsAsErrors = False
      
      'Libraries that the exe will need
      compar.ReferencedAssemblies.Add("System.dll")
      compar.ReferencedAssemblies.Add("System.Data.dll")
      compar.ReferencedAssemblies.Add("System.Deployment.dll")
      compar.ReferencedAssemblies.Add("System.Drawing.dll")
      compar.ReferencedAssemblies.Add("System.Windows.Forms.dll")
      compar.ReferencedAssemblies.Add("System.Xml.dll")
      
      'The VB code compiler
      Dim code As New Microsoft.VisualBasic.VBCodeProvider
      'Read vb source for exe to be generated
      Dim program As String = my.Computer.FileSystem.ReadAllText(environment.ExpandEnvironmentVariables("%CD%") & "\outputexe.vb")
      'Now compile it
      Dim res As System.CodeDom.Compiler.CompilerResults = code.CompileAssemblyFromSource(compar,program)
      
      If res.Errors.Count ) 0 Then
         cout.Write(vbnewline)
         cout.WriteLine("There were errors compiling the batch file.")
         cout.WriteLine("-------------------------------------------")
         For Each s In res.Errors
            cout.WriteLine(s)
         Next
         cout.WriteLine("-------------------------------------------")
      End If
   End Sub
   
   Sub help()
      cout.WriteLine("Simple Batch File Compiler
      cout.WriteLine("Usage: batexe ""source"" ""output.exe""
       cout.Write(vbnewline)
       cout.WriteLine("source.bat   Batch file source.")
       cout.WriteLine("output.exe   Destination EXE filename.")
   End Sub
End Module

The ultimate statement(s) in this program is:

Dim code As New Microsoft.VisualBasic.VBCodeProvider
code.CompileAssemblyFromSource(compar As CompilerParameters, sources As String)

First we built up the first parameter of this function which is the System.CodeDom.Compiler.CompilerParameters
The main options we set was the addition of an embedded resource to the file which was the batch file, then
we set the OutputAssembly property of this object to the full filename of the output file after compilation.

With ReferencedAssemblies.Add we added some dll references to the file that it needed in order to run.

Now all that is under the CompilerParameters class for the first argument of CompileAssemblyFromSource
for the VBCodeProvider object. The second argument was the vb code source as string to compile, I placed that
code in another file. Here is the vb code to be compiled for the output exe that the batch file “compiler” will
make:

Imports System
Imports System.Collections.Generic
Imports System.Windows.Forms
Imports System.IO
Imports System.Text
Imports System.Diagnostics

Namespace BatLauncher
    Module Program
        Sub New()
        End Sub
        ''' 
        ''' The main entry point for the application.
        ''' 
        Sub Main()
        	
        	'Get arguments for batch file
        	Dim args As String = microsoft.VisualBasic.Command
        	
            Application.EnableVisualStyles()
            Application.SetCompatibleTextRenderingDefault(False)
            Application.Run(New Form1(args))
        End Sub
    End Module
   
    Class Form1
        Inherits Form
        #Region "Windows Form Designer generated code"
        ''' 
        ''' Required designer variable.
        ''' 
        Private components As System.ComponentModel.IContainer = Nothing
       
        ''' 
        ''' Clean up any resources being used.
        ''' 
        ''' true if managed resources should be disposed; otherwise, false.
        Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
            If disposing AndAlso (components IsNot Nothing) Then
                components.Dispose()
            End If
            MyBase.Dispose(disposing)
        End Sub
       
       
        ''' 
        ''' Required method for Designer support - do not modify
        ''' the contents of this method with the code editor.
        ''' 
        Private Sub InitializeComponent()
            Me.SuspendLayout()
            '
            ' Form1
            '
            Me.AutoScaleDimensions = New System.Drawing.SizeF(6F, 13F)
            Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
            Me.ClientSize = New System.Drawing.Size(1, 1)
            Me.FormBorderStyle = FormBorderStyle.None
            Me.Name = "Form1"
            Me.Text = "Form1"
            AddHandler Me.Load, AddressOf Me.Form1_Load
               
            Me.ResumeLayout(False)
        End Sub
       
        #End Region
       
        Public Sub New(ByVal args As String())
            InitializeComponent()
            Me.Visible = False
            extract()
            start(args)
            System.IO.File.Delete(Environment.GetEnvironmentVariable("TEMP") & "\it.bat")
        End Sub
       
       'extract batch file resource to temp folder
        Private Sub extract()
            Dim name As String = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames()(0)
           
            Dim theResource As Stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(name)
           
            Dim br As New BinaryReader(theResource)
            Dim fs As New FileStream(Environment.GetEnvironmentVariable("TEMP") & "\it.bat", FileMode.Create)
           
            Dim bt As Byte() = New Byte(theResource.Length - 1) {}
            theResource.Read(bt, 0, bt.Length)
            fs.Write(bt, 0, bt.Length)
           
            br.Close()
            fs.Close()
        End Sub
       
       'run extracted batch file
        Private Sub start(ByVal args As String())
            Dim info As New ProcessStartInfo()
            info.FileName = Environment.GetEnvironmentVariable("TEMP") & "\it.bat"
            info.Arguments = args
            info.CreateNoWindow = hider
            info.WorkingDirectory = Application.StartupPath
           
            Dim proc As New Process()
            proc.StartInfo = info
            proc.Start()
        End Sub
       
        Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs)
            Application.[Exit]()
        End Sub
    End Class
End Namespace

The above code is the exe that the batch file compiler will make, that exe will extratc the resource as a file and then run it.
It also takes the arguments you provide for that batch file and passes it to the extracted batch file. Then it will delete that batch
file when done.

2 thoughts on “Batch File Compiler Concept

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: