Hier mal ein kleines Tutorial wie Ihr anhand der CodeDom Klasse Quellcode zur Laufzeit kompilieren könnt. Es gibt ähnliche Sourcecodes bzw. Tutorials im Netz, dort fand ich die Erklärung allerdings nicht so gut.
Mit CodeDom (Code Document Object Model) ist es möglich Quellcode zur Laufzeit zu kompilieren. Die Struktur des zu kompilierenden Quellcodes wird als CodeDOM-Diagramm bezeichnet.
Als erstes gehe ich mal auf die Form ein, die aus 1. Button, 4 Textboxen und 3 Labels besteht.
In den oberen 3 Textboxen gebt ihr die „Parameter“ ein, die dem zu kompilierenden Code mitgegeben werden sollen. Bei betätigen der Schaltfläche „Compile“ wird der zu kompilierende Quellcode erstellt.
Die untere Textbox dient dazu, die Fehler die beim Kompilieren auftreten können, auszugeben.
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace Code { public partial class Form1 : Form { Compile Com = new Compile(); public Form1() { InitializeComponent(); } private void compilebutton_Click(object sender, EventArgs e) { Com.Server1 = AdressTextBox.Text; Com.Pass1 = UsernameTextBox.Text; Com.Username1 = PasswordTextBox.Text; Com.compile(); ErrorOutput(); } private void ErrorOutput() { for (int i = 0; i <= Com.Error.Count - 1; i++) { textBox4.AppendText(Com.Error[i] + "\r\n"); } } } }
Instanziieren der Klasse.
Compile Com = new Compile();
Eingaben der Textboxen werden den Eigenschaften der Klasse zugewiesen.
Com.Server1 = AdressTextBox.Text; Com.Pass1 = UsernameTextBox.Text; Com.Username1 = PasswordTextBox.Text;
Aufrufen der Methode die den Code kompiliert.
Com.compile();
Aufrufen der Methode, um die Fehler die aufgetreten sein könnten auszugeben.
ErrorOutput();
Methode um die Fehler auszugeben.
private void ErrorOutput() { for (int i = 0; i <= Com.Error1.Count - 1; i++) { textBox4.AppendText(Com.Error1[i] + "\r\n"); } }
using System.Collections.Generic; using System.Linq; using System.Text; using System.CodeDom.Compiler; using Microsoft.CSharp; using System.Reflection; namespace Code { class Compile { private List<string> Error = new List<string>(); public List<string> Error1 { get { return Error; } set { Error = value; } } private string Server = ""; public string Server1 { get { return Server; } set { Server = value; } } private string Pass = ""; public string Pass1 { get { return Pass; } set { Pass = value; } } private string Username = ""; public string Username1 { get { return Username; } set { Username = value; } } public void compile() { string Sourcecode = ""; StringBuilder myBuilder = new StringBuilder(); CSharpCodeProvider myprovider = new CSharpCodeProvider(); ICodeCompiler compiler = myprovider.CreateCompiler(); CompilerParameters CompilerParameter = new CompilerParameters(); CompilerParameter.GenerateExecutable = true; CompilerParameter.OutputAssembly = "C:\\Users\\silversurfer\\Desktop\\Test.exe"; CompilerParameter.CompilerOptions = "/target:winexe"; CompilerParameter.ReferencedAssemblies.Add("System.Windows.Forms.dll"); myBuilder.Append("using System;\r\n"); myBuilder.Append("using System.Windows.Forms;\r\n"); myBuilder.Append("public class MainClass\r\n"); myBuilder.Append("{\r\n"); myBuilder.Append("public static void Main()\r\n"); myBuilder.Append("{\r\n"); myBuilder.Append("MessageBox.Show(\"Daten: \" + \""); myBuilder.Append("Server:" + Server + "Username:" + Username + "Pass:" + Pass); myBuilder.Append("\", \"Generierte *.exe\", MessageBoxButtons.OK,MessageBoxIcon.Information);"); myBuilder.Append("\r\n"); myBuilder.Append("}\r\n"); myBuilder.Append("}\r\n"); Sourcecode = myBuilder.ToString(); CompilerResults ret = compiler.CompileAssemblyFromSource(CompilerParameter, Sourcecode); if (ret.Errors.Count > 0) { foreach (CompilerError ce in ret.Errors) { Error.Add(ce.ToString()); } } } } }
Wir benötigen eine Liste (Eigenschaft) die die Fehler aufnimmt und ein paar Eigenschaften die die Eingaben aus den Textboxen entgegen nehmen.
private List<string> Error = new List<string>(); public List<string> Error1 { get { return Error; } set { Error = value; } } private string Server = ""; public string Server1 { get { return Server; } set { Server = value; } } private string Pass = ""; public string Pass1 { get { return Pass; } set { Pass = value; } } private string Username = ""; public string Username1 { get { return Username; } set { Username = value; } }
Nun wird ein string benötigt, der den zu kompilierenden Sourcecode später von einem StringBuilder-Objekt zugewiesen bekommt.
string Sourcecode = "";
Nun das StringBuilder Objekt dem wir später den „Source“ zuweisen werden.
StringBuilder myBuilder = new StringBuilder()
In dieser Zeile wird ein Objekt erstellt das uns den Zugriff auf einen C# Codegenerator ermöglicht.
CSharpCodeProvider myprovider = new CSharpCodeProvider();
Nun benötigen wir ein Objekt mit dem wir C# Code kompilieren können.
ICodeCompiler compiler = myprovider.CreateCompiler();
Nun ein Objekt das uns die Parameter zur Verfügung stellt.
CompilerParameters CompilerParameter = new CompilerParameters();
Hier die Parameter zum kompilieren des Codes. Durch GenerateExecutable= true wird eine .exe erstellt. Bei zuweisen von false wird eine Klassenbibliothek erstellt.
OutputAssembly ist grob gesagt der Ort an dem die .exe erstellt wird.
Um die Konsole nicht anzuzeigen steht die Zeile OutputAssembly…..
Mit ReferencedAssemblies.Add werden die benötigten Assemblies angegeben.
CompilerParameter.GenerateExecutable = true; CompilerParameter.OutputAssembly = "C:\\Users\\xxxxxx\\Desktop\\Test.exe"; CompilerParameter.CompilerOptions = "/target:winexe"; CompilerParameter.ReferencedAssemblies.Add("System.Windows.Forms.dll");
Nun der eigentliche Source der kompiliert werden soll.
myBuilder.Append("using System;\r\n"); myBuilder.Append("using System.Windows.Forms;\r\n"); myBuilder.Append("public class MainClass\r\n"); myBuilder.Append("{\r\n"); myBuilder.Append("public static void Main()\r\n"); myBuilder.Append("{\r\n"); myBuilder.Append("MessageBox.Show(\"Daten: \" + \""); myBuilder.Append("Server:" + Server + "Username:" + Username + "Pass:" + Pass); myBuilder.Append("\", \"Generierte *.exe\", MessageBoxButtons.OK,MessageBoxIcon.Information);"); myBuilder.Append("\r\n"); myBuilder.Append("}\r\n"); myBuilder.Append("}\r\n");
Inhalt des StringBuilders wird einem string zugwiesen. Ihr werdet gleich sehen warum.
Sourcecode = myBuilder.ToString();
Nun die Zeile mit dem wir den Code kompilieren werden und gleichzeitig die Resultate (Fehler des Kompilierungsvorgangs) aufnehmen. Die Methode hinter dem = erwartet als 2. Konstruktor einen string, in dem Fall unseren string Sourcode. Es gibt allerdings noch mehrere Methoden um Code zur Laufzeit zu kompilieren siehe z.B. : http://msdn.microsoft.com/de-de/libr…yfromfile.aspx.
CompilerResults ret = compiler.CompileAssemblyFromSource(CompilerParameter, Sourcecode);
In den letzten Zeilen werden die Resultate des Kompilierungsvorgangs aufgenommen.
if (ret.Errors.Count > 0) { foreach (CompilerError ce in ret.Errors) {/*Fehler werden in eine Liste aufgenommen*/ Error.Add(ce.ToString()); } }
Beim ausführen der .exe sollte folgendes erscheinen.