Scite Lua Dll |
|
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:
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; }
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
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.
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
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
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 ...
To make an import library from scite.def, use dlltool:
dlltool -d scite.def -l scite.la
gcc -shared -I..\scite\lua\include lfs.c -o lfs.dll scite.la
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