Lua Interface |
|
Interface is a library for integration between the Lua language and Microsoft .NET's Common Language Runtime (CLR). Lua scripts can use this to instantiate CLR objects, access properties, call methods, and even handle events with Lua functions.
Web sites:
Dependencies: .NET. Also works on the Mono runtime http://www.mono-project.com on Linux.
Note: Version 1.5.3 builds a C module DLL that can loaded in regular Lua interpreter. Version 2.0 and above are completely managed code. [4][5][6][7][2][3]
Not mentioned in the LuaInterface documentation is how to instantiate .NET arrays. It is done simply by indexing a type reference with a number:
local a = SomeType[5] for i = 1,a.Length do print(i, a[i - 1]) -- .NET arrays are zero-based. end
When using the CLR from Lua, the ordinary method of loading types and classes can seem a little verbose:
net = require "luainterface" net.load_assembly("System.Windows.Forms") net.load_assembly("System.Drawing") Form = net.import_type("System.Windows.Forms.Form") Button = net.import_type("System.Windows.Forms.Button") Point = net.import_type("System.Drawing.Point") local form1 = Form() local button1 = Button() button1.Location = Point(10, 10)
It would be nice if syntax like this could be used:
require "net" Form = net.System.Windows.Forms.Form Button = net.System.Windows.Forms.Button Point = net.System.Drawing.Point local form1 = Form() local button1 = Button() button1.Location = Point(10, 10)
Optionally, the .NET types can be made to appear as toplevel names:
require "net" System = net.System Form = System.Windows.Forms.Form Button = System.Windows.Forms.Button Point = System.Drawing.Point local form1 = Form() local button1 = Button() button1.Location = Point(10, 10)
It should not be necessary to make every type name toplevel:
require "net" System = net.System local form1 = System.Windows.Forms.Form() local button1 = System.Windows.Forms.Button() button1.Location = System.Drawing.Point(10, 10)
Here is the method:
-- Create a metatable for our name components local metatable = { [".NET"] = {getmetatable=getmetatable} } -- Load LuaInterface local g = getfenv(0) setfenv(0, metatable[".NET"]) local init, e1, e2 = loadlib("LuaInterfaceLoader.dll", "luaopen_luainterface") assert(init, (e1 or '') .. (e2 or '')) init() setfenv(0, g) -- Lookup a .NET identifier component. function metatable:__index(key) -- key is e.g. "Form" local mt = getmetatable(self) local luanet = mt[".NET"] -- Get the fully-qualified name, e.g. "System.Windows.Forms.Form" local fqn = ((self[".fqn"] and self[".fqn"] .. ".") or "") .. key -- Try to find either a luanet function or a CLR type local obj = luanet[key] or luanet.import_type(fqn) -- If key is neither a luanet function or a CLR type, then it is simply -- an identifier component. if obj == nil then -- It might be an assembly, so we load it too. luanet.load_assembly(fqn) obj = { [".fqn"] = fqn } setmetatable(obj, mt) end -- Cache this lookup self[key] = obj return obj end -- A non-type has been called; e.g. foo = System.Foo() function metatable:__call(...) error("No such type: " .. self[".fqn"], 2) end -- This is the root of the .NET namespace net = { [".fqn"] = false } setmetatable(net, metatable) -- Preload the mscorlib assembly net.load_assembly("mscorlib") return nil