Executing a .CS file

There is VBScript, JScript and PHP. But there isn't anything like C#-Script. So, I decided to play around a bit, only as a matter of checking out the possibilties. The plan: Create a CS-Script.exe file that we can use to ' launch ' a .cs file. Without having to add the file to a solution or anything. A very basic tool, that can launch one .cs file. View it as some sort of batch scripting tool. Where you can quickly open notepad, write something and run it.

We want to let the user know when he mucks up and doesn't provide an argument, so we add a reference to System.Windows.Forms and display a MessageBox .

using System;
using System.Windows.Forms;

namespace CS_Script {
      class CS_Script {
            static void Main(string[] args) {
                  if (args.Length > 0) {
                 
                  } else {
                        MessageBox.Show("You need to provide the filename as an argument!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                  }
            } /* Main */
      } /* CS_Script */
} /* CS_Script */

Next, we want to check if the file exists. Otherwise, just hit them with another MessageBox .

if (File.Exists(args[0])) {
                       
} else {
      MessageBox.Show("You need to provide an existing file as an argument!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

Now we read the file, just use an example from MSDN.

try {
      using (StreamReader textReader = new StreamReader(args[0])) {
            String textFile = textReader.ReadToEnd();
            Console.WriteLine(textFile);
      }
}    catch (Exception e) {
      MessageBox.Show("The file could not be read:\n" + e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

After we have read in the source we're going to compile it and run it. This is the hardest part :) There are some samples out there, but they all seemed to fail on my test data.

try {
      ExecuteSource(textFile);
} catch (Exception e) {
      MessageBox.Show("The file could not be executed:\n" + e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

The first thing we have to do is setup the compiler. Here I've put some restrictions. Every file should have a class CScript with a public void Main in it. If you want to extend this, be sure to get rid of that ;)

CSharpCodeProvider codeProvider = new CSharpCodeProvider();

ICodeCompiler compiler = codeProvider.CreateCompiler();
CompilerParameters parameters = new CompilerParameters();
parameters.GenerateExecutable = false;
parameters.GenerateInMemory = true;
parameters.OutputAssembly = "CS-Script-Tmp-Junk";
parameters.MainClass = "CScript.Main";
parameters.IncludeDebugInformation = false;


Another important parameter is the assemblies we involve in compiling our source. A "good" thing would be to put the most important namespaces in your project with using. We're going to include all the ones our project uses.

foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) {
      parameters.ReferencedAssemblies.Add(asm.Location);
}

And now it's time to compile our source, let's hope everything goes fine.

CompilerResults results = compiler.CompileAssemblyFromSource(parameters, sourceText);

Of course not everything went fine. Someone messed up his source, let's give him another error.

if (results.Errors.Count > 0) {
      string errors = "Compilation failed:\n";
      foreach (CompilerError err in results.Errors) {
            errors += err.ToString() + "\n";
      }
      MessageBox.Show(errors, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

But some people don't make mistakes, and we run their code. The compiler gave back an Assembly to use. It's very simply to invoke this one.
One strange issue, even thou we have set GenerateInMemory , it does create a file on our harddisk (at least here), so we have to clean that up.

object o = results.CompiledAssembly.CreateInstance("CScript");
Type type = o.GetType();
MethodInfo m = type.GetMethod("Main");
m.Invoke(o, null);
if (File.Exists("CS-Script-Tmp-Junk")) { File.Delete("CS-Script-Tmp-Junk"); }

If everything was fine, we now launched our program!

Here's a the little program I tested on:

using System;
using System.Windows.Forms;

class CScript {
      public void Main() {
            MessageBox.Show("I'm being loaded dynamicly!");
      }
}

We reached our goal of running code from a text file for now. As always, I've uploaded the sources for this project.

If you want to be able to make this program reachable through the right click menu in the shell (for every file!), take a look here.

You might also like...

Comments

David Cumps

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Measuring programming progress by lines of code is like measuring aircraft building progress by weight.” - Bill Gates