Scite Lua Dll |
|
以下是我找到的创建可使用 loadlib() 加载的完全功能* Win32 DLL 的解决方案。
版本说明: 此代码基于旧版本的 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 版本,则应使用此选项。
请参阅 创建二进制扩展模块 以构建 Lua 和您的 Dll。
您必须将“lua.dll”复制到您的 <scite> 文件夹中,以及 SciTE.exe,才能使您的 Dll 工作。
将“mydll.dll”复制到您的 <scite> 文件夹中,以及 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)
我没有创建 dll 的 Makefile,我使用批处理文件
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 的提示,您可以构建您的库,将来自 Scite 源代码的 Lua 包含目录提供给编译器,并将 "SciTE.lib" 文件提供给链接器。
在您的 Lua 代码中使用库也非常简单。将 "mydll.dll" 复制到您的 <scite> 文件夹中,以及 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; }
--由 Maciej Radziejewski 为 Scite 1.74 和 Lua 5.1 更新