A great way of extending an application is to allow users to write their own scripts. Fortunately, with the Dynamic Language Runtime it is fairly simple to provide scripting in your application. Let’s look at how to do it with a simple Windows Forms application and IronPython.

Creating the Windows Forms application Firstly, let’s create a form called MainForm. Add three TextBoxes (TopTextBox, MiddleTextBox and BottomTextBox), three Buttons (UpButton, DownButton and ResetButton), a multi-line TextBox (OutputTextBox) and a Menu with a MenuItem called ScriptMenuItem and two MenuItems within the ScriptMenuItem called WriteToolStripMenuItem and RunToolStripMenuItem. Here’s a shot of what that looks like:

Next we need a simple form to be able to type in our script. Create a form called ScriptForm with a multiline TextBox called ScriptTextBox and a couple of Buttons (called SaveButton and ClearButton.) Here’s what the form looks like:

The first form doesn’t do too much – just lets us move the values on the form around. That means the click events for the buttons looks like this:

That’s the basics taken care of. We can open the script form and type in some Python code. But we can’t run it yet. To do that we need to add scripting support.

Adding Scripting SupportThe first step in adding scripting support is to add the appropriate references to the application. The references you need are IronPython, Microsoft.Scripting and Microsoft.Scripting.Core. You’ll find these dlls in the IronPython distribution and / or the DLR distribution (depending on what you’ve downloaded and installed.)

Once we’ve got the right references, we need to create a script engine and a scope in which our script will execute. To make this simple, let’s hold references to the engine and scope at form level:

The ScriptSource allows us to execute the Python typed into the ScriptForm. The exception handler catches any exceptions in the Python code we write and display them nicely in a Message Box. But there is a problem. You can’t interact with the application.

Setting variables By setting variables, we can enable script to interact with the application while controlling what aspects we expose to script. In this example, let’s expose the TextBoxes. To do that, we need to add them into the scope we created. Add these lines to the CreateScriptRuntime method:

Adding ReferencesWe might also want to add references to some .NET assemblies – so that the script can take advantage of existing functions or to be able to interact with an object model, for example. Let’s say we wanted to add a reference to mscorlib, in which case we’d add the following line to the CreateScriptRuntime method:

this.engine.Runtime.LoadAssembly(typeof(string).Assembly);

Getting output At this point, we can write and execute Python that interacts with the application. The final step is to hook our application up to receive output from the Python code so that, for example, we can see the result of print statements. To do this we need to redirect the output of the script runtime. The simplest thing to do is to redirect it to the Console:

this.engine.Runtime.IO.RedirectToConsole();

If we want to see the output in our application, we’ll also need to redirect the Console. We can redirect the Console to any TextWriter. It’d be good to see the output in the OutputTextBox. Firstly, let’s create a class that subclasses TextWriter and writes out to a TextBox:

This code will extract values from the TextBoxes and print their values (which given our redirection will end up on the main form.) Here’s the result of running it:

As you’d expect, if we click the Up Button a couple of times and run the script again we get this:

ConclusionIt’s simple to add powerful scripting support to your applications, while maintaining control over the scripting runtime means that you can restrict what any user entered code can do. I chose to show this example in IronPython, but the principles for doing this with Ironruby are identical (of course you’ll need a reference to IronRuby.) In fact, you could offer users the choice of languages.