Scite Lua Dll |
|
以下是找到建立 Win32 DLL 並使用 loadlib() 載入的完整功能解決方案。
版本公告:程式碼建構於舊版 Lua。Lua 5.1. 使用 package.loadlib。
* 完整功能是指載入的 DLL 能夠定義 Lua 腳本可存取的全域物件和函數。
若要順利運作,您必須選擇下列選項:
這個範例 Dll 會加入一個新的元表「mydll」,其中包含兩個函數
Dll 來源「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; }
下載 SciTE 來源並修改「<scite_src>\scite\lua\include\lua.h」,第 94 行,以讓 SciTE 為您的 Dll 匯出 Lua API
/* mark for all API functions */ #ifndef LUA_API // was: #define LUA_API extern #define LUA_API __declspec(dllexport) #endif
這樣就完成了,非常簡單 (感謝 SteveDonovan 提供這個秘訣,謝謝您)。
現在組譯 scintilla 和 scite,我在使用 Borland C++ 編譯器
cd <scite_src>\scintilla\win32 make -f scintilla.mak cd <scite_src>\scite\win32 make -f scite.mak implib SciTE SciTE.exe
現在應該會有「bin」資料夾中的「SciTE.lib」。您可以組譯 Dll 了
cd <mydll_src>\ bcc32 -w -tWD -I..\scite\lua\include -DLUA_API=__declspec(dllimport) ..\scite\bin\SciTE.lib mydll.c
如果您想依賴未匯出 Lua API 的正式 SciTE 組譯,應該使用這個選項。
參閱 CreatingBinaryExtensionModules 以組譯 Lua 和您的 Dll。
您必須將「<scite>」資料夾中的「lua.dll」與 SciTE.exe 一起拷貝,Dll 才會運作。
將「<scite>」資料夾中的「mydll.dll」與 SciTE.exe 一起拷貝。
在您的 Lua 腳本 (例如 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 沒有 implib 工具程式,或至少無法辨識,所以我必須建立一份 Lua 程式碼的 .dll,才能建立我的 dll。
我相信有些來自 Lua 的小修訂與標準 Lua 釋出版本不同,所以我選擇將 dll 命名為 SciTELua.dll
在 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)
我沒有建立 Makefile 來建立我的 dll,我是使用批次檔
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
我的測試 dll 是根據 msgbox() 和 confirm() 函數的程式碼,即使我也寫了 getsavefilename(),這是 GetSaveFileName?() Win32 API 的連結。
MinGW 並未在初始化函式庫名稱前加上底線,所以我的 SciTE 啟動腳本為
local libinit = loadlib(props.SciteDefaultHome .. "\\aprillua.dll", "libinit")
--April White
對於您的函式庫 libinit() 方法,使用這個來呼叫 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);
讓 libinit() 可以接受一個選擇性參數作為表格名稱。因此,您的 Lua 程式碼可能讀取為
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
或
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
事實上,可以把 MinGW DLL 連結到 SciTE 的修補版本。為此,您將需要一個包含所有 lua 函數的 scite.def 檔案。
LIBRARY "SciTE.exe" EXPORTS luaL_addlstring luaL_addstring luaL_addvalue ...
要從 scite.def 建立匯入函式庫,請使用 dlltool
dlltool -d scite.def -l scite.la
gcc -shared -I..\scite\lua\include lfs.c -o lfs.dll scite.la
使用 Visual Studio 2005 和 SciTE 1.74 或後續版本,建置函式庫的流程非常簡單,因為看起來 SciTE 的官方原始碼已被修補,以適用於上述第一個選項。
您需要取得 Scite 的原始碼並重建。函式庫檔案「SciTE.lib」應會產生,您可以在二進位檔案中找到它。我不知道其他編譯器是否亦適用。 現在,依照 Steve Donovan 的提示,您可以建立函式庫,提供 Lua 包含目錄從 Scite 原始碼到編譯器,以及「SciTE.lib」檔案給連結器。
在您的 Lua 程式碼中使用函式庫也很簡單。在您的 <scite> 資料夾中將「mydll.dll」連同 SciTE.exe 一起複製。然後將此程式碼放入您的 Lua 啟動指令碼
-- load your custom Dll require 'mydll' -- test your Dll if mydll then mydll.msgbox("Hello World!", "Hello") end
因此,註冊 Lua 5.1 物件和函數的更新函數為
/** * 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; }
--針對 Scite 1.74 和 Lua 5.1 更新,Maciej Radziejewski