Scite Lua Dll

lua-users home
wiki

Creating custom Lua Dlls for SciTE

Here is the solution I found to create fully functional* Win32 DLLs to be loaded using loadlib().

VersionNotice: This code is based on an older version of Lua. Lua 5.1. uses package.loadlib.

* fully functional, means that the loaded DLL will be able to define global objects and functions accessible to the Lua scripts.

To make it work, you will have to choose to:

1. make a special SciTE build (actually this is easy)
2. add another lua.dll (better if you want to rely on the offical SciTE build)

Writing your Dll

This sample Dll will add a new metatable "mydll" with two functions:

Dll source, "mydll.c":

#include <windows.h>
#include "lauxlib.h"

/**
 * @method OK MessageBox
 * @param message
 * @param title
 * @return selection
 */
int mydll_msgbox(lua_State* L)
{
	const char* message = luaL_checkstring(L, 1);
	const char* caption = luaL_optstring(L, 2, "");
	int result = MessageBox(NULL, message, caption, MB_OK);
	lua_pushnumber(L, result);
	return 1;
}

/**
 * @method OK / CANCEL MessageBox
 * @param message
 * @param title
 * @return selection
 */
int mydll_confirm(lua_State* L)
{
	const char* message = luaL_checkstring(L, 1);
	const char* caption = luaL_optstring(L, 2, "");
	int result = MessageBox(NULL, message, caption, MB_OKCANCEL);
	lua_pushnumber(L, result);
	return 1;
}

// methods table
static const luaL_reg mydll_methods[] = {
  {"confirm", mydll_confirm},
  {"msgbox", mydll_msgbox},
  {0, 0}
};

/**
 * Register objects and functions
 */
int __declspec(dllexport) libinit (lua_State* L)
{
	// create methods table, add it to the globals
	luaL_openlib(L, "mydll", mydll_methods, 0);
	// create metatable, and add it to the Lua registry
	luaL_newmetatable(L, "mydll");
	return 0;
}

First option: customized SciTE build

Download SciTE source and modify "<scite_src>\scite\lua\include\lua.h", line 94, to have SciTE export Lua API for your Dll:

/* mark for all API functions */
#ifndef LUA_API
// was: #define LUA_API       extern
#define LUA_API       __declspec(dllexport)
#endif

That's all and easy (credit for the tip goes to SteveDonovan - thank you).

Now build scintilla and scite - I'm using Borland C++ compiler:

cd <scite_src>\scintilla\win32
make -f scintilla.mak

cd <scite_src>\scite\win32
make -f scite.mak
implib SciTE SciTE.exe

Now you should have "SciTE.lib" in the "bin" folder. You can build your Dll:

cd <mydll_src>\
bcc32 -w -tWD -I..\scite\lua\include -DLUA_API=__declspec(dllimport) ..\scite\bin\SciTE.lib mydll.c

Second option: add another lua.dll

This option should be used if you want to rely on an offical SciTE build that does not export Lua API.

See CreatingBinaryExtensionModules to build Lua and your Dll.

You have to copy "lua.dll" in your <scite> folder along with SciTE.exe for your Dll to work.

Loading your Dll in Lua

Copy "mydll.dll" in your <scite> folder along with SciTE.exe.

Add this code in your Lua script (for example SciTEStartup.lua):

-- load your custom Dll
libinit = loadlib(props['SciteDefaultHome'].."/mydll.dll", "libinit")
if libinit then libinit()
else
	print ("Error: unable to load mydll.dll")
end

-- test your Dll
if mydll then
	mydll.msgbox("Hello World!", "Hello")
end

--Philippe

Using MinGW

MinGW does not have the implib utility, or at least not in a way I can identify, so I had to create a .dll of the Lua code and then create my dll.

I believe there are some small revisions from Lua that make it different from the standard Lua release, so I chose to name the dll SciTELua.dll

Within SciTE\Win32\Makefile

# after "PROGSTATIC = ../bin/Sc1.exe" I added 
LUA_DLL=../bin/SciTELua.dll
LUA_DLL_LIB=../bin/lscitelua.a
LUA_DLL_DEF=../bin/scitelua.def

# after "LUA_CORE_OBJS" and "LUA_LIB_OBJS" are defined I added
LUA_DLL_OBJS := $(LUA_CORE_OBJS) $(LUA_LIB_OBJS)

# I modified "ALL" to be
ALL:	$(PROG) $(PROGSTATIC) $(DLLS) $(PROPS) $(LUA_DLL) $(LUA_SCRIPTS)

#this is at the bottom, below "SciTEBase.o: $(OTHER_OBJS)"
$(LUA_DLL): $(LUA_DLL_OBJS)
	$(DLLWRAP) --no-idata4 --no-idata5 --target i386-mingw32 -mno-cygwin --output-lib $(LUA_DLL_LIB)  --output-def $(LUA_DLL_DEF) -o $(LUA_DLL) $(LUA_DLL_OBJS)

I have not made a Makefile to create my dll, I use a batch file

SET OUTDIR=../scite/bin
SET OUTFILE=aprillua

gcc 2>&1 -mno-cygwin -DLUA_API=__declspec(dllimport) -c -Wall -I../scite/lua/include aprilluadll.c
dllwrap 2>&1 --no-idata4 --no-idata5 --target i386-mingw32 -mno-cygwin --output-def %OUTDIR%/%OUTFILE%.def --output-lib %OUTDIR%/l%OUTFILE%.a -o %OUTDIR%/%OUTFILE%.dll aprilluadll.o -L%OUTDIR% -lscitelua -mwindows

My test dll is based on the code msgbox() & confirm() functions, though I also wrote getsavefilename() which is a link to the GetSaveFileName?() Win32 API.

MinGW does not prefix the initialization library name with an underscore, so my SciTE startup script is:

local libinit = loadlib(props.SciteDefaultHome .. "\\aprillua.dll", "libinit")

--April White

For your library libinit() method, use this for calling luaL_openlib()

// create methods table, add it to the globals
const char* tblname = luaL_optstring(L, 1, "mydll" );
luaL_openlib(L, tblname, dll_methods, 0);

which makes libinit() accept an optional parameter as the name of the table. So your Lua code could read

local libinit = loadlib(props.SciteDefaultHome .. "\\test.dll", "libinit")
if libinit then
	libinit() -- defaults to mydll
else
	alert("Error: unable to load " .. props.SciteDefaultHome .. "\\test.dll" )
end

or

local libinit = loadlib(props.SciteDefaultHome .. "\\test.dll", "libinit")
if libinit then
	libinit( "Aprilz" ) -- creates the table as Aprilz
else
	alert("Error: unable to load " .. props.SciteDefaultHome .. "\\test.dll" )
end
--April White, September 24, 2005

Using MinGW DLLs without separate Lua DLL

It's actually possible to link MinGW DLLs against the patched version of SciTE itself. For this, you will need a scite.def file containing all the lua functions.

LIBRARY "SciTE.exe"
EXPORTS
luaL_addlstring
luaL_addstring
luaL_addvalue
...
I've put my version of scite.def in the file manager under Files:wiki_insecure/editors/SciTE/scite.def.

To make an import library from scite.def, use dlltool:

dlltool -d scite.def -l scite.la
and then to build your DLL (such as the execellent LuaFileSystem), just use:
gcc -shared -I..\scite\lua\include lfs.c -o lfs.dll scite.la
--Steve Donovan, July 2, 2007

Update for SciTE 1.74 or later and Lua 5.1

Using Visual Studio 2005 and SciTE 1.74 or later, the process of building the library is quite simple since it looks like SciTE's official sources have already been patched to accommodate the first option above.

You need to get the sources of Scite and rebuild. The library file "SciTE.lib" should be created and you can find it among the binaries. I do not know if the same is true for other compilers. Now, following the tip by Steve Donovan, you can build your library supplying the Lua include directory from Scite sources to the compiler and the "SciTE.lib" file to the linker.

Using the library in your Lua code is also very simple. Copy "mydll.dll" in your <scite> folder along with SciTE.exe. Then put this code in your Lua startup script:

-- load your custom Dll
require 'mydll'

-- test your Dll
if mydll then
        mydll.msgbox("Hello World!", "Hello")
end

The updated function to register objects and functions for Lua 5.1 is thus:

/**
 * Register objects and functions
 */
int __declspec(dllexport) luaopen_mydll (lua_State* L)
{
	// Add the methods table to the globals
	luaL_register(L, "mydll", mydll_methods); 
	return 1;
}

--Updated for Scite 1.74 and Lua 5.1 by Maciej Radziejewski


RecentChanges · preferences
edit · history
Last edited October 10, 2008 6:47 pm GMT (diff)