结合控制台重定向和C#即使编译器(见我上面两篇文章)写的WinForm即时C#编译器,功能还不错。
文本框就是你Main方法内的语句,可以输入任意测试代码,支持错误行号定位,编译结果捕获,自动拆分窗格等,程序按F5执行,F5…… 忘记在代码里面加说明了:( 时间不早了,上传睡觉,带批处理build代码和SharpDevelop方式源代码哦。
可以拿下面的代码测试程序
//F5: Compile and Run the app F6:Kill current Running App
//-----------------------------------------------------------
System.Diagnostics.Process.Start("notepad");
//test Generic Collection
List<int> lstInt = new List<int>{
1,3,5,7,9,11
};
foreach(var v in lstInt)
Console.WriteLine(v);
//test Timer
System.Timers.Timer timer = new System.Timers.Timer(1000);
timer.Elapsed += delegate{
System.Console.WriteLine(DateTime.Now.TimeOfDay.ToString());
};
timer.Start();
Console.ReadKey();
//test WinForm Application
//Application.Run(new Form());
//-----------------------------------------------------------
System.Diagnostics.Process.Start("notepad");
//test Generic Collection
List<int> lstInt = new List<int>{
1,3,5,7,9,11
};
foreach(var v in lstInt)
Console.WriteLine(v);
//test Timer
System.Timers.Timer timer = new System.Timers.Timer(1000);
timer.Elapsed += delegate{
System.Console.WriteLine(DateTime.Now.TimeOfDay.ToString());
};
timer.Start();
Console.ReadKey();
//test WinForm Application
//Application.Run(new Form());
这个程序用了我两天的时间,涉及到技术有:
1、同线程的控制台重定向到文本框
2、不同线程的控制台重定向到文本框-异步方式
3、编译代码并执行(Invoke方式和Process方式)
4、结束进程树
5、文件操作等
实现编译器的代码如下:
//#define CompileIntoMemory
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace PhoenixCompiler
{
/// <summary>
/// director the Console output to ListBox
/// in MainForm Construction:
/// </summary>
public class PhoenixWriter : System.IO.TextWriter
{
delegate void VoidAction();
System.Windows.Forms.TextBox txtBox;
public PhoenixWriter(System.Windows.Forms.TextBox box)
{
this.txtBox = box;
}
public override System.Text.Encoding Encoding {
get { return System.Text.Encoding.UTF8;}
}
//here, must use parameter: char value
public override void Write(char value)
{
VoidAction action = delegate{
txtBox.AppendText(value.ToString());
};
txtBox.BeginInvoke(action);
}
}
/// <summary>
/// Description of PhoenixCompiler.
/// </summary>
public class PhoenixCompiler
{
public PhoenixCompiler()
{
}
public string GenerateCode(string userCode)
{
string namespaces =@"using System;
using System.ComponentModel;
using System.Text;using System.Text.RegularExpressions;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms
;using System.Threading;
using System.Reflection;
";
string codeHead = @"
sealed class Phoenix
{
public static void Main()
{
//----------your code here-----------
";
//userCode here
string codeTail = @"
//----------your code here-----------
}
}
";
string compileCodes = namespaces + codeHead + userCode + codeTail;
return compileCodes;
}
public CompilerResults Compile(string codes)
{
//CSharpCodeProvider
System.CodeDom.Compiler.CodeDomProvider compiler = new Microsoft.CSharp.CSharpCodeProvider();
//CompilerParameters
System.CodeDom.Compiler.CompilerParameters parameters = new CompilerParameters();
parameters.WarningLevel = 4;
parameters.ReferencedAssemblies.Add("System.dll");
parameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");
#if CompileIntoMemory
parameters.GenerateInMemory = true;
#else
parameters.GenerateExecutable=true;
#endif
return compiler.CompileAssemblyFromSource(parameters,codes);
}
}
/// <summary>
/// Description of MainForm.
/// </summary>
public partial class MainForm : Form
{
System.Diagnostics.Process process;
public MainForm()
{
InitializeComponent();
//redirector Console output to ListBox lstResult
Console.SetOut(new PhoenixWriter(txtResult));
}
//KillProcessTreeById
public void KillProcessTreeById(int parentId)
{
//find all the process id created by parentId, Saved it to List childIds
System.Collections.Generic.List<int> childIds=
new System.Collections.Generic.List<int>();
System.Diagnostics.Process[] processes =
System.Diagnostics.Process.GetProcesses();
foreach (var element in processes) {
string path = string.Format("win32_process.handle='{0}'",element.Id);
using (var mo= new System.Management.ManagementObject(path)) {
try {
mo.Get();
} catch (System.Management.ManagementException me) {
throw me;
}
int id=Convert.ToInt32(mo["ParentProcessId"]);
if (id==parentId) {
childIds.Add(element.Id);
}
}
}
foreach (var element in childIds) {
//Console.WriteLine(element);
System.Diagnostics.Process processKill =
System.Diagnostics.Process.GetProcessById(element);
if (processKill.ProcessName !="conhost") {
processKill.Kill();
}
//processKill.CloseMainWindow();
//processKill.Close();
}
var processParent = System.Diagnostics.Process.GetProcessById(parentId);
if (processParent !=null) {
processParent.Kill();
}
}
void TxtCodeKeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{//F5:116 e.KeyCode.ToString() + ":" + e.KeyValue.ToString();
if (e.KeyValue == 116) {
if (process!=null) {
this.KillProcessTreeById(process.Id);
process=null;
}
PhoenixCompiler compiler = new PhoenixCompiler();
string code = compiler.GenerateCode(txtCode.Text);
System.CodeDom.Compiler.CompilerResults result = compiler.Compile(code);
ShowResult(result);
}
if (e.KeyValue==117) {//F6:117 here should terminate the process tree ... ...
if (process != null) {
this.KillProcessTreeById(process.Id);
process=null;
}
}
}
public void ShowResult(System.CodeDom.Compiler.CompilerResults result)
{
txtResult.Text="";
Console.WriteLine("Phoenix Compiler! \r\n\tCopyright by XUMINGHUI(2013)");
Console.WriteLine("-----------------------------------------------\n");
if (result.Errors.HasErrors) {
Console.WriteLine("Build ERROR:\r\n");
foreach (System.CodeDom.Compiler.CompilerError error in result.Errors) {
Console.WriteLine(error.Line + ":" + error.ErrorText);
}
return;
}
//build OK
Console.WriteLine("Build Successfully:\r\n");
try {//call Main entry, Console output --> WinForm Control
#if CompileIntoMemory
Type Phoenix = result.CompiledAssembly.GetType("Phoenix");
Phoenix.GetMethod("Main").Invoke(null,new string[]{});
#else //start another thread to run the generated application
System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo{
FileName=result.PathToAssembly,
UseShellExecute=false,
CreateNoWindow=true,
RedirectStandardError=true,
RedirectStandardOutput=true
};
process = new System.Diagnostics.Process();
process.OutputDataReceived +=(s,e)=>{
if (e.Data!=null) {
Console.WriteLine(e.Data);
}
};
process.ErrorDataReceived +=(s,e)=>{
if (e.Data!=null) {
Console.WriteLine(e.Data);
}
};
process.StartInfo = info;
process.EnableRaisingEvents = true;
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
#endif
} catch (System.Reflection.TargetInvocationException ex) {
Console.WriteLine("Exception:" + ex.InnerException.Message);
}
}
void MainFormFormClosing(object sender, FormClosingEventArgs e)
{
if (process != null) {
this.KillProcessTreeById(process.Id);
process=null;
}
}
void TxtResultDoubleClick(object sender, EventArgs e)
{
if (txtResult.Text=="") {
return;
}
string path = System.IO.Path.GetTempFileName();
System.IO.File.AppendAllText(path,txtResult.Text);
System.Diagnostics.Process.Start("notepad",path);
}
void TxtCodeDoubleClick(object sender, EventArgs e)
{
PhoenixCompiler compiler = new PhoenixCompiler();
string code = compiler.GenerateCode(txtCode.Text);
string path = System.IO.Path.GetTempFileName();
System.IO.File.AppendAllText(path,code);
System.Diagnostics.Process.Start("notepad",path);
}
}
}
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace PhoenixCompiler
{
/// <summary>
/// director the Console output to ListBox
/// in MainForm Construction:
/// </summary>
public class PhoenixWriter : System.IO.TextWriter
{
delegate void VoidAction();
System.Windows.Forms.TextBox txtBox;
public PhoenixWriter(System.Windows.Forms.TextBox box)
{
this.txtBox = box;
}
public override System.Text.Encoding Encoding {
get { return System.Text.Encoding.UTF8;}
}
//here, must use parameter: char value
public override void Write(char value)
{
VoidAction action = delegate{
txtBox.AppendText(value.ToString());
};
txtBox.BeginInvoke(action);
}
}
/// <summary>
/// Description of PhoenixCompiler.
/// </summary>
public class PhoenixCompiler
{
public PhoenixCompiler()
{
}
public string GenerateCode(string userCode)
{
string namespaces =@"using System;
using System.ComponentModel;
using System.Text;using System.Text.RegularExpressions;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms
;using System.Threading;
using System.Reflection;
";
string codeHead = @"
sealed class Phoenix
{
public static void Main()
{
//----------your code here-----------
";
//userCode here
string codeTail = @"
//----------your code here-----------
}
}
";
string compileCodes = namespaces + codeHead + userCode + codeTail;
return compileCodes;
}
public CompilerResults Compile(string codes)
{
//CSharpCodeProvider
System.CodeDom.Compiler.CodeDomProvider compiler = new Microsoft.CSharp.CSharpCodeProvider();
//CompilerParameters
System.CodeDom.Compiler.CompilerParameters parameters = new CompilerParameters();
parameters.WarningLevel = 4;
parameters.ReferencedAssemblies.Add("System.dll");
parameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");
#if CompileIntoMemory
parameters.GenerateInMemory = true;
#else
parameters.GenerateExecutable=true;
#endif
return compiler.CompileAssemblyFromSource(parameters,codes);
}
}
/// <summary>
/// Description of MainForm.
/// </summary>
public partial class MainForm : Form
{
System.Diagnostics.Process process;
public MainForm()
{
InitializeComponent();
//redirector Console output to ListBox lstResult
Console.SetOut(new PhoenixWriter(txtResult));
}
//KillProcessTreeById
public void KillProcessTreeById(int parentId)
{
//find all the process id created by parentId, Saved it to List childIds
System.Collections.Generic.List<int> childIds=
new System.Collections.Generic.List<int>();
System.Diagnostics.Process[] processes =
System.Diagnostics.Process.GetProcesses();
foreach (var element in processes) {
string path = string.Format("win32_process.handle='{0}'",element.Id);
using (var mo= new System.Management.ManagementObject(path)) {
try {
mo.Get();
} catch (System.Management.ManagementException me) {
throw me;
}
int id=Convert.ToInt32(mo["ParentProcessId"]);
if (id==parentId) {
childIds.Add(element.Id);
}
}
}
foreach (var element in childIds) {
//Console.WriteLine(element);
System.Diagnostics.Process processKill =
System.Diagnostics.Process.GetProcessById(element);
if (processKill.ProcessName !="conhost") {
processKill.Kill();
}
//processKill.CloseMainWindow();
//processKill.Close();
}
var processParent = System.Diagnostics.Process.GetProcessById(parentId);
if (processParent !=null) {
processParent.Kill();
}
}
void TxtCodeKeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{//F5:116 e.KeyCode.ToString() + ":" + e.KeyValue.ToString();
if (e.KeyValue == 116) {
if (process!=null) {
this.KillProcessTreeById(process.Id);
process=null;
}
PhoenixCompiler compiler = new PhoenixCompiler();
string code = compiler.GenerateCode(txtCode.Text);
System.CodeDom.Compiler.CompilerResults result = compiler.Compile(code);
ShowResult(result);
}
if (e.KeyValue==117) {//F6:117 here should terminate the process tree ... ...
if (process != null) {
this.KillProcessTreeById(process.Id);
process=null;
}
}
}
public void ShowResult(System.CodeDom.Compiler.CompilerResults result)
{
txtResult.Text="";
Console.WriteLine("Phoenix Compiler! \r\n\tCopyright by XUMINGHUI(2013)");
Console.WriteLine("-----------------------------------------------\n");
if (result.Errors.HasErrors) {
Console.WriteLine("Build ERROR:\r\n");
foreach (System.CodeDom.Compiler.CompilerError error in result.Errors) {
Console.WriteLine(error.Line + ":" + error.ErrorText);
}
return;
}
//build OK
Console.WriteLine("Build Successfully:\r\n");
try {//call Main entry, Console output --> WinForm Control
#if CompileIntoMemory
Type Phoenix = result.CompiledAssembly.GetType("Phoenix");
Phoenix.GetMethod("Main").Invoke(null,new string[]{});
#else //start another thread to run the generated application
System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo{
FileName=result.PathToAssembly,
UseShellExecute=false,
CreateNoWindow=true,
RedirectStandardError=true,
RedirectStandardOutput=true
};
process = new System.Diagnostics.Process();
process.OutputDataReceived +=(s,e)=>{
if (e.Data!=null) {
Console.WriteLine(e.Data);
}
};
process.ErrorDataReceived +=(s,e)=>{
if (e.Data!=null) {
Console.WriteLine(e.Data);
}
};
process.StartInfo = info;
process.EnableRaisingEvents = true;
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
#endif
} catch (System.Reflection.TargetInvocationException ex) {
Console.WriteLine("Exception:" + ex.InnerException.Message);
}
}
void MainFormFormClosing(object sender, FormClosingEventArgs e)
{
if (process != null) {
this.KillProcessTreeById(process.Id);
process=null;
}
}
void TxtResultDoubleClick(object sender, EventArgs e)
{
if (txtResult.Text=="") {
return;
}
string path = System.IO.Path.GetTempFileName();
System.IO.File.AppendAllText(path,txtResult.Text);
System.Diagnostics.Process.Start("notepad",path);
}
void TxtCodeDoubleClick(object sender, EventArgs e)
{
PhoenixCompiler compiler = new PhoenixCompiler();
string code = compiler.GenerateCode(txtCode.Text);
string path = System.IO.Path.GetTempFileName();
System.IO.File.AppendAllText(path,code);
System.Diagnostics.Process.Start("notepad",path);
}
}
}