作者:夏目nyako酱丶 | 来源:互联网 | 2023-10-14 18:22
整整的花了一个下午的时候,才在lua中调用了动态链接库。比起其他脚本语言,lua的调用方式算是比较繁琐的,但是lua的编程思想非常的统一,即lua和C之间的传值都是通过栈进行的,目前为止我还没有深入的去了解这个“栈”,但是这并不妨碍去使用”栈“。
当我们在一个空的工程中写下几个C/C++的函数,然后把属性类型设置为“动态链接库”以后,编译虽然成功了,DLL也产生了,但是我们得到的DLL是一个没有价值的数据文件,它缺少export函数(通过dumpbin /exports xxx.dll 观察),我们的lua也无法使用它。为了把我们写好的函数export出去,必须在函数名前,返回类型之后加上__declspec(dllexport),比如:
int add(int a, int b)
{
return a + b;
}
//要修改为--->>>
int __declspec(dllexport) add(int a , int b)
{
return a + b;
}
这是你就可以用dumpbin看到我们的add了。不对??是的,也行你看到的不是add,而是@ILT#$%^add(@$%) (我随便写个大概),那么你的工程一定是C++工程。这样的DLL只能通过引导库(lib)来实现,LUA用不了。为了能建立lua可以使用的库,必须在导出函数的最前面加上extern "C" (不能是__stdcall),所以此时的函数变成了:
extern "C" int __declspec(dllexport) add(int a , int b)
{
return a + b;
}
还有一种常用的方法也可以得到extern的效果,那就是建立def文件,例如:
LIBRARY mylib
DESCRIPTION "Just for test"
VERSION 1.0
EXPORTS
add
有了def,你就不需要再每个函数前加上extern “C”了。记得要在属性/连接器/输入/模块定义文件中输入def的文件名称。我们这个动态链接库以及lua.exe必须动态的连接lua.dll (lua5.2.dll),而不能静态的链接,否则你会得到错误:
stack traceback :
[C]:?
[C]:in function 'require'
test.lua:1:in main chunk
[C]:?
有了上面的知识铺垫,我们可以进入下一个环节了——让lua调用DLL。下面代码可以生成一个DLL。
#include
extern "C"{
#include
#include
#include
#include
#include
#include
#include
}
static int mysin (lua_State *L)
{
double d = luaL_checknumber(L, 1);
lua_pushnumber(L, sin(d));
return 1;
}
static int l_printf(lua_State *L)
{
const char * pPattern = luaL_checkstring(L, 1);
const char * str = luaL_checkstring(L, 2);
lua_pushnumber(L, printf(pPattern, str));
return 1;
}
static int l_MessageBox(lua_State *L)
{
const char * sTitle = luaL_checkstring(L, 1);
const char * sText = luaL_optstring(L, 2, "");
MessageBox(NULL, sTitle, sText, 0);
return 1;
}
static const struct luaL_Reg mylib[] =
{
{"mysin", mysin},
{"printf", l_printf},
{"messagebox", l_MessageBox},
{NULL, NULL}
};
extern "C" int __declspec(dllexport) luaopen_mylib(lua_State *L)
{
luaL_newlib(L, mylib);
return 1;
}
上面的代码中,最后export出去的函数是luaopen_mylib,一定要注意:函数名luaopen_mylib表明了最后输出的dll名称必须为mylib.dll,而且大小写要一致,否则lua无论如何都找不到luaopen_mylib函数的。我们可以在lua脚本中这样使用。
mylib = require("mylib")
mylib.printf("Say: %s\n", "hello world")
msgbox = mylib.messagebox
msgbox("hello from luaopen_mylib")
另外,我要介绍一下另一种老方法。在DLL代码中添加:
extern "C" int __declspec(dllexport) MyMessageBox(lua_State *L)
{
const char * sText = luaL_checkstring(L, 1);
const char * sTitle = luaL_checkstring(L, 2);
return MessageBox(NULL, sText, sTitle, 0);;
}
你猜对了,我们要export另一个函数,然后我们可以在lua中这样用到:
pf = package.loadlib("mylib.dll","MyMessageBox")
print(pf)
pf("hello", "again")
这两种方法的效果是一致的,但是第一种方式是最新的,后面一种似乎有点out of date了。
————————————————
版权声明:本文为CSDN博主「语言观止」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/snlscript/article/details/16340653