Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Mini C# Compiler

0.00/5 (No votes)
25 Oct 2008 1  
MiniCompiler is a simple application for compiling single file C# source code. I've used interfaces provided by the .NET platform.
MiniCom.png

Code Explanation

C# MiniCompiler is a simple application that uses CSharpCodeProvider to create an instance of C# code compiler, then uses ICodeCompiler for all .NET compilers like VB, J#. So if we want to compile C# code, assign the interface ICodeProvider to provider.CreateCompiler().

Now we have the engine that compiles the code. We don't do anything unless we give this engine (ICodeProvider) some information about the code we want to compile. You pass this information to CompilerParameters. This information includes the Main class as you should tell it the name of the main class which it cannot get by itself. It also includes OutPutAssembly name, and referenced assemblies. So we have two problems.
The first is to give CompilerParameters Main class. We can give it from TextBox (from user), but we don't want that. We want to make it get the Main class automatically. So I wrote a basic parser (ManiPulateMainClass.cs) that manipulates the Main class from the source code.
The second problem is referenced assemblies. We can give the compiled assembly some referenced assemblies, but it may need it and may not need others. We can also make the user choose his assemblies. But many users don't know the path of all assemblies. So, what I did is parse the referenced namespaces from the code, such as "using System.Windows;". If the compiler sees this statement, it references System.Windows.dll and so on...

ManiPulateManiPulateMainClass.cs

This class has some functions that split the source code in namespaces, then classes, then check each class to see if this class is the main class or not by searching for the Main() function:

public static string GetMainClass(List<string> classname, List<string> classCode) 
{ 
    for (int i = 0; i < classCode.Count; i++) 
    { 
        if (classCode[i].Contains("Main(") && !classCode.Contains("\"")) 
        { 
            return classname[i]; 
        } 
    } 
    return "not found"; 
}

This function takes the class' sources codes as parameters and classNames that correspond to each class sourcecode. If it finds "Main()" without quotations, it means that it is the main class.

public void CompileCSharp(string code,string outputassembly ) 
{ 
    CSharpCodeProvider provider = new CSharpCodeProvider(); 
    ICodeCompiler compiler = provider.CreateCompiler(); 
#region CompilerParameters 
    CompilerParameters parameters = new CompilerParameters() 
    { 
        MainClass = Classname(code), 
            GenerateExecutable = true, 
            OutputAssembly = outputassembly, 
            IncludeDebugInformation = true, 
    }; 
    parameters.ReferencedAssemblies.Clear(); 
    foreach (Assembly asm in assemblies) 
    { 
        parameters.ReferencedAssemblies.Add(asm.Location); 
    } 
#endregion 
    CompilerResults result = compiler.CompileAssemblyFromSource(parameters, code); 
    if (result.Errors.Count == 0) 
    { 
        if (!System.IO.File.Exists(outputassembly)) 
        { 
            OnFileNotExists(new EventArgs()); 
            return; 
        } 
        ProcessStartInfo startInfo = new ProcessStartInfo(); 
        startInfo.FileName =outputassembly; 
        startInfo.WindowStyle = ProcessWindowStyle.Maximized; 
        startInfo.Arguments = "\\S"; 
        Process process = new Process(); 
        process.StartInfo = startInfo; 
        process.Start(); 
        IntPtr hwnd = GetConsoleWindow(); 
        ShowWindow(hwnd, 0); 
    } 
    else 
    { 
        foreach (CompilerError er in result.Errors) 
        { 
            List<string> cerrors = new List<string>(); 
            cerrors.Clear(); 
            cerrors.Add(
                 er.ErrorText+ " Line ("+er.Line.ToString()+") error :"+er.ErrorNumber ); 
            OnCompilationError(new ErrorEventArgs(cerrors)); 
        } 
        result.Errors.Clear(); 
    } 
}

First, we use ICodeProvider interface to compile CSharpCode:

ICodeCompiler compiler = provider.CreateCompiler();

Then, we create Compiler Parameters Object and give it some compilation information like the Main class. The Classname method uses the parser to get the Main class, so we call it to get the Main class name in this form, e.g.: Mynamespace.MyClass, OutPutAssembly property is the path of the output compiled program.

CompilerParameters parameters = new CompilerParameters() 
{ 
    MainClass = Classname(code), 
        GenerateExecutable = true, 
        OutputAssembly = outputassembly, 
        IncludeDebugInformation = true, 
}; 
//here we populate the compiled program with referenced assemblies 
foreach (Assembly asm in assemblies) 
{ 
    parameters.ReferencedAssemblies.Add(asm.Location); 
}

I got the referenced assemblies by parsing the referenced namespaces, but it is not a robust method. First, I collect all the common assemblies by getting the assemblies directories from the registry:

//get all assemblies directories 
public List<string> AssemblyDirectories() 
{ 
    List<string> assemblies = new List<string>(); 
    Microsoft.Win32.RegistryKey key = Registry.LocalMachine; 
    key = key.OpenSubKey(@"SOFTWARE\Microsoft\.NETFramework\AssemblyFolders"); 
    string[] SubKeynames = key.GetSubKeyNames(); 
    foreach (string subkeys in SubKeynames) 
    { 
        RegistryKey subkey = Registry.LocalMachine; 
        subkey = subkey.OpenSubKey(
            @"SOFTWARE\Microsoft\.NETFramework\AssemblyFolders\" + subkeys); 
        string[] l = subkey.GetValueNames(); 
        foreach (string v in l) 
        { 
            if (subkey.GetValueKind(v) == RegistryValueKind.String) 
            { 
                string value = (string)subkey.GetValue(v); 
                assemblies.Add(value); 
            } 
        } 
    } 
    assemblies.Add( Environment. @":\Windows\Microsoft.NET\Framework\v2.0.50727"); 
    return assemblies; 
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here