Hi
I recently made a .net app (wiresim.com) that's main feature was scriptability. In fact, making your application scriptable is very good thing to do for your advanced users, and hopefully with this article, how to do that will be clear
When I first looked into adding scripting support to .net languages, the world seemed bleak, filled with overly complicated windows scripting hosts and the like...
Until I found
LuaInterface!
Of course, all my troubles did not go away after that, I still had to figure out how to put this into my program

Looking through the documentation included with LuaInterface, it has nice examples of running standalone scripts with very little 2-way interaction with their host. This is fine for some applications (lua just calls functions in the host, without the host calling functions in lua), but for my application, I needed full 2-way communication!
So, without recounting a journal of my path in figuring this out, here's a C# class I've made to help future users of LuaInterface. After the code block, I'll explain what stuff does. Ignore the "PHP code," I just want the highlighting. Also, when you see stuff like parentform.Log, that's just a function that logs errors, replace it with your app's.
PHP Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LuaInterface;
namespace wiresim
{
public class LuaStuff
{
public string path;
public Lua lua=new Lua();
private int retries = 0;
public LuaFunction FindFunc(string name){
try
{
LuaFunction retfunc = this.lua.GetFunction(name);
return retfunc;
} catch (Exception e){
this.parentent.parentform.Log(e.Message, true);
return null;
}
}
public void CallFunction(string name)
{
if (FindFunc(name) == null)
{
return;
}
try
{
LuaFunction retfunc = this.lua.GetFunction(name);
retfunc.Call();
}
catch (Exception e)
{
this.parentent.parentform.Log(e.Message, true);
}
}
public void runfileinthread()
{
try
{
lua.DoFile(path);
}
catch (Exception ex)
{
retries++;
if (retries > 10)
{
this.parentent.parentform.Log(ex.Message, true);
this.parentent.parentform.Log("Lua actually *****ed up, probably a syntax error, check the console for more", true);
}
else
{
this.parentent.parentform.Log("Lua *****ed up, this is normal and has to detremental effects, lets try this again", false);
runfileinthread();
}
//MessageBox.Show("Compile Error!", "Script Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
}
}
So, here's the explanation:
I first create a new Lua object, along with some variables to store the location of the lua script. Nothing really new there
PHP Code:
public LuaFunction FindFunc(string name){
try
{
LuaFunction retfunc = this.lua.GetFunction(name);
return retfunc;
} catch (Exception e){
this.parentent.parentform.Log(e.Message, true);
return null;
}
}
This function uses the GetFunction() method of LuaInterface.Lua, however instead of calling it, I just determine if an error is encountered getting the function object. If an error is encountered, it means that the function your named does not exist, so this function returns null. If it does exist (and therefore no error happen), the LuaFunction object is returned. Technically this and the next function really could be in one, but I like keeping the purposes seperate.
PHP Code:
public void CallFunction(string name)
{
if (FindFunc(name) == null)
{
return;
}
try
{
LuaFunction retfunc = this.lua.GetFunction(name);
retfunc.Call();
}
catch (Exception e)
{
this.parentent.parentform.Log(e.Message, true);
}
}
This is where the fun starts. This function is similar to the one above, however instead of just checking if the function exists, it calls the function (retfunc.Call()).
PHP Code:
public void runfileinthread()
{
try
{
lua.DoFile(path);
}
catch (Exception ex)
{
retries++;
if (retries > 10)
{
this.parentent.parentform.Log(ex.Message, true);
this.parentent.parentform.Log("Syntax Error!", true);
}
else
{
this.parentent.parentform.Log("Recoverable Lua Error", false);
runfileinthread();
}
}
}
}
This is effectively a wrapper for the LuaInterface.Lua.DoFile() method, but it has error trapping built in, due do a bug I encountered with Lua. This bug was that, randomly, the lua.DoFile(path) command would fail with a generic error. Run the same command again, and the error would not happen

This is a work around, and I'd recommend you first try removing it and seeing if you get the same issue. You'll note, however, that the number of retries is limited to 10, because the function never fails that many times in a row unless you have a syntax error.
Right about now you'll be thinking "great, I can call functions in Lua, but can Lua call functions in the host app?" Why yes, of course! And as an added bonus, it's incredibly easy to do!
To Export a variable (or native .net object!) to Lua:
Simply
PHP Code:
lua["variablename"]=variable
Where lua is your instance of the LuaInterface.Lua object. variable can be anything, an array, object, int, windows form control, etc. If the object you exported has functions or properties, they can be accessed in lua via
PHP Code:
variablename:function(parameter,parameter)
and
PHP Code:
variablename.property=value
(where variablename is the name of your variable, function/property are the names of the function/property, and parameter/value is anything)
Note: You can read back that variable (or any variable, for that matter) with
PHP Code:
foo=(type)lua["variablename"];
To Export a single function to Lua:
*looks in docs*
PHP Code:
lua.RegisterFunction("functionname",null,typeof(SeeBelow).GetMethod("externalFunctionName"));
Where functionname is the name that the function should be called with from within Lua, SeeBelow is the class that the function is in, and externalFunctionName is the name of the function in the SeeBelow class that you want to register with Lua.
Phew, hope you understood everything, if you have any questions, please post here or contact me via email at
cpf at cpfx.ca
or MSN at
cpf@airenet.com