C# Script
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.
Our goal is to reach it through the right click menu in the shell. For every file! So we'll create a console app (CS-Script) that accepts one argument, the filename.
We want to let the user know when he fucks 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
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);
Ofcourse 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("
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
MessageBox.Show("I'm being loaded dynamicly!");
}
}
We reached our goal of running code from a text file
for now.
In my next article I'll talk about
adding our CS-Script.exe file to the shell menu so we can
use it on our files.
As always, I've
uploaded the sources
for this project.
Update: Here is the article about adding your menu to the shell: Associating your program with every file - ShellExtension