lua 调用C++动态库dll


Home      lua 调用C++动态库      lua如何调用dll      使用LUA调用DLL      在lua中调用DLL      lua 5.2 实现luaL_register 功能      lua调用dll      lua 调用 dll 的简单demo      Lua调用C的动态库      windows下lua调用C动态库文件(.dll)      Qt调用Lua动态链接库      Win32下 Qt与Lua交互使用:配置Qt下Lua运行环境MinGW      Win32下 Qt与Lua交互使用(二):在Lua脚本中使用Qt类      Win32下 Qt与Lua交互使用(三):在Lua脚本中connect Qt 对象      Win32下 Qt与Lua交互使用(四):在Lua脚本中自由执行Qt类中的函数      开启Lua之旅      开启Lua之旅      开启Lua之旅

测试时需要将生成的dll与脚本、lua.exe、lua.dll等等放在同一个文件夹中。
调用DLL一般用于扩展功能,但是不利于前台脚本和后台程序变量交换,除非使用文件方式。
Lua 5.2及以上要使用 lua_newlib代替原来的luaL_Register生成动态库dll.


===================================================================

lua 调用C++动态库
https://blog.csdn.net/sibaison/article/details/74850680

一.生成动态库dll:

1.去官网下载http://www.lua.org/versions.htm,下载lua5.1.5版本,lua5.2以后的有些函数时有改动的

2.下载后解压到一个文件夹中比如lua-5.1.5(本文安装的是lua5.1)

3.VS2015新建一个win32控制台程序,选动态库,空项目,如图


4.新建好工程后,把lua-5.1.5文件夹中的src文件夹拷贝进工程目录,如图所示


5.在解决方案里点击头文件,右键,添加->现有项,把src文件夹中的.h文件全部添加进来如图:


6.同理5步添加源文件,把src里的.c文件除了lua.c和luac.c两个文件不要添加进来,别的文件全部添加进来,如图


7.按Ctrl+Shift+A弹出对话框,分别添加MyDll.h和MyDll.cpp两个文件。分别添加代码

MyDll.h中添加:

#pragma once
extern "C" {
#include "../src/lua.h" //指定正确的路径
#include "../src/lualib.h"
#include "../src/lauxlib.h"
}


#ifdef LUA_EXPORTS
#define LUA_API __declspec(dllexport)
#else
#define LUA_API __declspec(dllimport)
#endif


extern "C" LUA_API int luaopen_MyDll(lua_State *L);//定义导出函数


MyDll.cpp中添加代码:

#include <stdio.h>
#include "MyDll.h"
static int averageFunc(lua_State *L)
{
int n = lua_gettop(L);
double sum = 0;
int i;


/* 循环求参数之和 */
for (i = 1; i <= n; i++)
sum += lua_tonumber(L, i);


lua_pushnumber(L, sum / n); //压入平均值
lua_pushnumber(L, sum); //压入和


return 2; //返回两个结果
}


static int sayHelloFunc(lua_State* L)
{
printf("hello world!");
return 0;
}


static const struct luaL_Reg myLib[] =
{
{ "average", averageFunc },
{ "sayHello", sayHelloFunc },
{ NULL, NULL } //数组中最后一对必须是{NULL, NULL},用来表示结束
};


int luaopen_MyDll(lua_State *L)
{
luaL_register(L, "ss", myLib);
return 1; // 把myLib表压入了栈中,所以就需要返回1
}

8.解决方案配置选择Release

9.按Ctrl+Shift+B键,生成解决方案,

如果是VS2015,应该会报错,大概如下

在解决方案下,选中此报错的文件,右键->属性->

添加_CRT_SECURE_NO_WARNINGS,就不会报错了。所有的文件都如此修改属性,直到正确生成dll文件为止

10.生成的dll如图所示:


11.随便在一个地方建个文件夹,把Mydll.dll拷贝进此文件夹中。在此文件夹中新建一个main.lua文件,输入代码:

require "MyDll"
local ave,sum = ss.average(1,2,3,4,5)--参数对应堆栈中的数据
print(ave,sum) -- 3 15
ss.sayHello() -- hello world!

11.命令行运行输入 lua main.lua,如图



===================================================================
lua如何调用dll
https://blog.csdn.net/wenpinglaoyao/article/details/115716854

如果读者朋友想详细的了解lua与C的通信原理,请移步这里【https://www.zhangshengrong.com/p/ERNnAzWa5W/】;

先说两句废话:怪不得lua不火,因为它对我们新手太不友好了。比如生成一个为lua调用dll的文件这么简单的小事,昨天我按照网上给出的教程总是出错(而且网上关于这方面的资料少的可怜!),最后还是通过自己的不断尝试修成正果,所以还是在这儿写博便记,下面进入正题。

首先是下载一个lua源码包,这里我选择的是lua5.1.5(本来我用的是lua-5.4,但是遇到了各种坑,编译的,运行的等等),朋友们可以去这里下载【https://mp.csdn.net/console/upDetailed】,解压缩之后,把它随便弄到一个地方。

其次,使用VS创建一个动态库项目,具体步骤,打开VS-》创建新项目-》选择window桌面向导,然后给项目命名(不要瞎起名,因为这决定您生成的dll名字),我这里给项目的命名是【MyLuaDll】,记住这个名字!

然后,点击创建,VS会弹出一个【window桌面向导】对话框,这里一定要把应用程序类型改成【动态链接库(.dll)】,最好把下面的【空项目】也勾选上,之后点击确定,项目就创建完成了,记住这个项目创建的路径。

接着,去到我们解压缩后的lua-5.1.5文件夹下的【src】文件夹下,复制里面所有的文件(注意,除了【lua.c】和【luac.c】,这两个文件不要复制!),然后来到我们刚才创建的【MyLuaDll】项目根目录下,把方才复制的所有文件直接粘贴进来。

再接着,打开VS,鼠标右键点击我们的项目,选择【添加】-》【现有项】,点击后弹出一个对话框,在对话框里找到我们的项目根目录,然后选择刚才粘贴进去的所有文件,如下图所示:

完成上面的步骤之后,我们还需要添加一个自定义的cpp文件,鼠标右键项目然后添加新文件,文件名随便取,我选择的是【abcd.cpp】,把它添加到项目里之后,就可以在它上面书写源代码了,我的源代码内容如下:

#include <iostream>
#include <windows.h>
extern "C"
{
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}

extern "C" int func1(lua_State* luaEnv) // 这里可以这样写,也可以写成static
{
	std::cout << "welcome to C world,first at all,allow me to sleep for 3 second." << std::endl;
	Sleep(3000);
	std::cout << "i am dll, now i wake up!" << std::endl;
	return 0;
}
static int func2(lua_State* luaEnv)//在lua中,调用这个函数时,需要传入两个number类型值
{
	auto  op1 = luaL_checknumber(luaEnv, 1);//检查栈顶的元素是不是number类型,然后赋值给op1
	auto  op2 = luaL_checknumber(luaEnv, 2);
	lua_pushnumber(luaEnv, op1+op2); //计算op1+op2的结果值,然后压入lua栈顶(返回给lua)
	lua_pushstring(luaEnv, "i am dll of C,my work is done, goodbye!"); //再返回给lua一个字符串
	return 2; //这句代码作用是告诉lua"本函数要返回给你几个东西",比如上面返回了一个数值和一个字符串,所以这里应该返回2
}

static luaL_Reg mylibs[]  //我们需要弄一个表,而表中的内容就是我们需要导出的这个文件里的函数
=
{
	{"aaa", func1}, //第一项可以随便取名,但要记住,因为在lua中调用这个函数时,用到的就是我们这里取的名字
	{"bbb", func2},
	{NULL , NULL}   //最后不要忘了用null收尾
};

extern "C" __declspec(dllexport) //下面函数的作用是定义一个module名,以备在lua中require
int luaopen_MyLuaDll(lua_State* luaEnv) //请注意!这句代码中“luaopen_”后面的“MyLuaDll”,不能乱取名,一定要与您的dll名字一致!
{
	/***很重要的一句代码,2参是字符串,内容一定要与上面的luaopen_后面的内容或者说我们的dll名字一致!最后的参数就是我们需要导出的表***/
	luaL_register(luaEnv, "MyLuaDll", mylibs);
	return 1;
}

代码写好之后,点击项目的生成按钮生成文件,不出意外的话VS会报错,大概如下图:

没关系,我们慢慢来【不用设置安全检查为否啥的,因为我试了,在我机器上没用,还是报错】,那么如何解决上面的错误呢,方法很简单,首先双击错误提示最上面的那句话,然后VS会打开对应的文件,在该文件的最上面添加一句代码【#pragma warning(disable : 4996)】,如下图:

完成之后,重新生成一下,不出意外还会报错(但报错的数量比上次要少几个),没关系,重复上一次的步骤:双击某行报错提示,进入对应文件,在文件代码的上面添加【#pragma warning(disable:4996)】,然后再重新生成一下,再报错,再添加,如此重复,报错会不断减少,一直到最后,总有一刻我们会真的生成了dll文件【应该是在项目的debug目录下】

然后,让我们随便在某个地方创建一个lua文件,我这里是在桌面上创建的【test.lua】,内容如下:

local obj = require("MyLuaDll")
print("welcome to lua!")
obj.aaa();
print("now come back lua")
local n, s = obj.bbb(33,66)
print('now in lua,this is last words of C dll: "'..s..'"')
print("dll return value is:",n)

最后,我们去我们刚才的项目里的debug文件夹下,找出我们生成的【MyLuaDll.dll】文件,复制它,然后回到刚才创建的lua文件的同目录下,把【MyLuaDll.dll】文件拷贝进来,运行lua文件,就可以看到我们dll工作的样子的,我的如下图:


===================================================================
使用Lua调用DLL
https://blog.csdn.net/weixin_43570235/article/details/106887670

使用Lua调用DLL

之前希望学点lua来自定义ocgcore,然而官方的脚本机器都是C语言写的,要懂点Lua调用C/C++库的知识。所以看了下在线版的Programming in Lua,下了个5.4测试版的源代码自己编译了一下。

生成Lua编译器

貌似官网只说了*nix的几个发行版上的编译,对Windows上面不太友好(好吧是提供了二进制文件的下载方法)。我早些时候装了个MinGW-win64,所以用mingw32-make mingw(反正是类似的命令)就可以了。不知道为什么,命令后面跟install的话,总是报告找不到文件。我都不知道install是make自带的还是什么东西。反正光生成二进制文件就没问题,所以我就把几个文件从\src拷贝出来开始用了。

不过没想到在5.2版本后语言不支持lua_register之类的一批函数,原书中直接调用loadlib也不支持了(我试了一下package.loadlib好像是可以的)。

C++生成dll

先按照书里写了个C++文件打算编译成动态链接库(.dll)文件,无奈VS技术重回低谷,总是报连接错误,最后简单粗暴地把Lua所有源代码文件都放进项目里了(大概正确做法是把编译生成的lua54.dll放进去?)。

代码都是抄的,最后找到了正确的示例,感谢。

// test.cpp
extern "C" {
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
#include <math.h>

//这个extern也许可以改成static吧,我也不清楚
extern "C" int l_sin(lua_State* L) {
    double d = luaL_checknumber(L, 1);
    lua_pushnumber(L, sin(d));
    return 1;  /* number of results */
}

//之前把下面变量命名为mylib,结果在Lua里总是说找不到module
//调用require "mylib"是错的,也许调用require "test"就行了?
//因为require不行,还用过load、loadfile、package.loadlib一堆函数
static const struct luaL_Reg test[] = {
  {"sin", l_sin},
  {NULL, NULL}  /* sentinel */
};

//这个函数当时也命名为luaopen_mylib的
extern "C" _declspec(dllexport) int luaopen_test(lua_State* L) {
    lua_newtable(L);
    luaL_setfuncs(L, test, 0);
    return 1;
}

然后把生成的动态链接库放到根目录下,就可以耍Lua了。

Lua交互界面

下面用了>.\bin\lua.exe,进入lua的REPL(交互模式),所以没有用local来修饰变量(不知道为什么,交互模式里好像不支持用local生成局部变量,之前用local声明的变量都是nil)。这时候已经可以调用函数了。在正确运行前有好几屏幕的错误示范:P

这个代码片功能!居然不能设置为Lua。还是设成python模式吧。

> test = require "test"
> sin = test.sin
> sin(1.57)
> 0.99999968293183

最后吐槽一下REPL一定要通过Ctrl+C来退出,为什么不给个quit()函数呢?如果有的话麻烦告诉我一声。


===================================================================
在lua中调用DLL
https://blog.csdn.net/wotingdaonile/article/details/105949009

整整的花了一个下午的时候,才在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 <Windows.h>

extern "C"{
#include <lua.h>
#include <lauxlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <lualib.h>
#include <math.h>
}

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


===================================================================
lua 5.2 实现luaL_register 功能
https://blog.csdn.net/ljhjason/article/details/28860633

lua 5.2 去掉了luaL_register功能,不能直接注册函数到一个全局table中了。

网上找了很多文章都是要导出到库,再引用库。

// my_math.c
  
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
  
#include <math.h>
#include <stdio.h>
  
  
static int my_math_sin (lua_State *L) {
lua_pushnumber(L, sin(luaL_checknumber(L, 1)));
return 1;
}
  
static int my_math_cos (lua_State *L) {
lua_pushnumber(L, cos(luaL_checknumber(L, 1)));
return 1;
}
  
  
static const luaL_Reg mathlib[] = {
{"my_cos",   my_math_cos},
{"my_sin",   my_math_sin},
{NULL, NULL}
};
  
/*
** Open my_math library
*/
LUALIB_API int luaopen_my_math (lua_State *L) {
  luaL_newlib(L, mathlib);
  return 1;
}

LUALIB_API 是导出导入函数或extern,看是否指定 LUA_BUILD_AS_DLL

// callc.lua
  
my_math = require("my_math") --my_math 是一个dll或so,由下面的.c生成 
  
print(my_math.my_sin(3.14))
print(my_math.my_cos(3.14))


如果要实现luaL_register,可以不导出dll,改用luaL_requiref在c里面注册这个load方法

luaL_requiref(L,"my_math",luaopen_my_math,0);
这样就不用导出dll了,直接在exe里就行了

===================================================================
lua调用dll
https://www.jianshu.com/p/2729a776d8fb

首先先看下lua调用的dll的编写,新建一个新的 Win32 控制台应用程序 ,然后选择dll模板,记得将预编译头去掉(如下图)


// mydall_test.cpp : 定义 DLL 应用程序的导出函数。//

#include "stdafx.h"

#include <stdio.h>

#include <string.h>

#include <lua.hpp>

#include <lauxlib.h>

#include <lualib.h>

extern "C" int average(lua_State* L) // 导出平均函数接口

{

double sum = 0;

int num = lua_gettop(L);

for (int i = 1; i <= num; i++)

{

sum += lua_tonumber(L, i);

}

lua_pushnumber(L, sum / num);

return 1;

}

static luaL_Reg cMethods[] = {

{"average", average},

{NULL, NULL}

};

extern "C" __declspec(dllexport)

int luaopen_mydll_test(lua_State* L){ // luaopen_xxxx 这里的 xxxx 一定要是你的项目名

luaL_newlib(L, cMethods);

return 1;

}

```

// mydall_test.cpp : 定义 DLL 应用程序的导出函数。//

#include "stdafx.h"

#include <stdio.h>

#include <string.h>

#include <lua.hpp>

#include <lauxlib.h>

#include <lualib.h>

extern "C" int average(lua_State* L) // 导出平均函数接口

{

double sum = 0;

int num = lua_gettop(L);

for (int i = 1; i <= num; i++)

{

sum += lua_tonumber(L, i);

}

lua_pushnumber(L, sum / num);

return 1;

}

static luaL_Reg cMethods[] = {

{"average", average},

{NULL, NULL}

};

extern "C" __declspec(dllexport)

int luaopen_mydll_test(lua_State* L){ // luaopen_xxxx 这里的 xxxx 一定要是你的项目名

luaL_newlib(L, cMethods);

return 1;

}

```

以下是lua文件调用代码,将上面生成的dll文件放在lua找得到的地方(CPATH,PATH 配置),也可以直接把它放在lua文件相同的文件夹里。

local mydll = require "mydll_test" -- mydll_test对应C++文件中的 luaopen_xxxx 文件名

print(mydll.average(1.2,2.5,1.5))

以上代码简简单单,一切都顺利,在生成dll的时候,配置lua的动态链接库时,如果直接使用官方下载的文件,最后执行lua文件会出现以下错误:multiple Lua VMs detected


这是因为官方的lua.dll在生成的时候没有指定 LUA_BUILD_AS_DLL 来生成,解决方法是,直接下载一个lua源文件,


然后自己使用以下的bat代码进行编译:



@echo off

md bin

md lib

md include

cd src

cl /c /nologo /W3 /O2 /Ob1 /Oi /Gs /MD /D_CRT_SECURE_NO_DEPRECATE l*.c

ren lua.obj lua.o

ren luac.obj luac.o

lib /OUT:lua53.lib *.obj

copy lua53.lib ..\lib\lua53.lib

del *.o *.obj *.exp *.lib *.dll *.exe

cl /c /nologo /W3 /O2 /Ob1 /Oi /Gs /MD /D_CRT_SECURE_NO_DEPRECATE /DLUA_BUILD_AS_DLL l*.c

ren lua.obj lua.o

ren luac.obj luac.o

link /DLL /IMPLIB:lua53.lib /OUT:lua53.dll *.obj

link /OUT:lua53.exe lua.o lua53.lib

link /OUT:luac53.exe luac.o *.obj

copy lua53.exp ..\bin\lua53.exp

copy lua53.lib ..\bin\lua53.lib

copy lua53.dll ..\bin\lua53.dll

copy lua53.exe ..\bin\lua53.exe

copy luac53.exe ..\bin\luac53.exe

del *.o *.obj *.exp *.lib *.dll *.exe

copy lauxlib.h ..\include\lauxlib.h

copy lua.h ..\include\lua.h

copy lua.hpp ..\include\lua.hpp

copy luaconf.h ..\include\luaconf.h

copy lualib.h ..\include\lualib.h

cd ..\



将上面的bat代码保存为lua_t.bat,并放在与Makefile 文件同层,并点开


进入到bat 所在文件并执行lua_t.bat,最终会编译成功如下图:



接下来便是设置编译需要的链接库,右键项目点开属性,具体配置如下:





这里最重要的是设置 LUA_BUILD_AS_DLL




最后生成dll:



此时便可以正常执行lua调用dll。


===================================================================
lua 调用 dll 的简单demo
https://segmentfault.com/a/1190000002765842

windows下的 lua 与 c 进行交互, 本人新手,只能做到这么多了

c代码

//#include "stdio.h"
#include "windows.h"
#ifdef _cplusplus  
extern "C"{
#endif
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"

extern  int  isquare(lua_State *L);
extern  int  alert(lua_State *L);
#ifdef _cplusplus
}
#endif

int luaopen_add(lua_State *L){
    lua_register(
            L,               /* Lua 状态机 */
            "square",        /*Lua中的函数名 */
            isquare          /*当前文件中的函数名 */
            );  
   lua_register(L,"alert",alert);
//    lua_register(L,"cube",icube);
    return 0;
}


int alert(lua_State *L)
{
    const char * desc = lua_tostring(L,-1);
    MessageBox(NULL,desc,"alert",MB_OK);
    return 1;
}

int isquare(lua_State *L){              /* C中的函数名 */
    float rtrn = lua_tonumber(L, -1);      /* 从Lua虚拟机里取出一个变量,这个变量是number类型的 */
    //printf("Top of square(), nbr=%f\n",rtrn);
    lua_pushnumber(L,rtrn*rtrn);           /* 将返回值压回Lua虚拟机的栈中 */
    return 1;                              /* 这个返回值告诉lua虚拟机,我们往栈里放入了多少个返回值 */
}

编译命令

cl /c add.c /I ../include

include 为 lua 头文件所在目录

link /def:export.def /dll add.obj ../lua53.lib "kernel32.lib" "user32.lib" "gdi32.lib"

导出函数到 dll

export.def

; export.def
LIBRARY ADD
; MY_DLLMAIN 将成为生成的dll的名称
DESCRIPTION  'test'
EXPORTS
    isquare  @ 1
    alert    @ 2
; 这个名称即为函数的实际导出名称 @1为函数的导出编号

lua

square = package.loadlib("ADD.dll", "isquare")
alert=package.loadlib("ADD.dll", "alert")
print(alert)
print ( square(2) )
alert("222")

执行结果

虽然有乱码存在问题,但是期望结果基本已经达到


===================================================================
Lua调用C的动态库
https://blog.csdn.net/zw1996/article/details/122147580

项目背景:
因为lua是单线程的,每个lua执行就相当于是一个线程,因此是没有办法完成调用两个C线程的,不能满足当前项目需求,因此不使用lua脚本的方式进行CDLL的线程调用管理了,而使用python了。

1、 lua基础

https://www.runoob.com/lua/lua-tutorial.html

--两个点表示连接
print("两个点表示连接")
a = "1212" .. "nihao"
print(a)


--测试function及for和if语法
print("测试function及for和if语法")
local function maxs(a)
	local maxi = 1
	local maxnum = a[maxi]
	for i, val in ipairs(a) do
		if val > maxnum then
			maxi = i
			maxnum = val
		end
	end
	return maxi, maxnum
end
print(maxs({8,10,23,12,5,0}))


--table的concat测试
local fruits = {"banana", "orange", "apple"}
print("连接后的字符串", table.concat(fruits))
print("指定连接字符后的字符串", table.concat(fruits, ", "))
print("指定索引来连接table的字符串", table.concat(fruits, ", ", 2, 3))

--测试函数传参可变参数
print("测试函数传参可变参数")
function add(...)
	local s = 0
	local arg = {...}
	for i, v in ipairs{...} do --> {...} 表示一个由所有变长参数构成的数组
		s = s+v
	end
	print("总共传入 " .. select("#",...) .. " 个数")
	print("传入" .. #arg .. "数字")
	return s
end
print(add(1,2,3,4,5,6,7,0))

--获取参数总数
function foo(...)
	for i = 1, select('#', ...) do
		local arg = select(i, ...) --> select(n,…) 可以访问第 n 个到数组最后的参数
		print("arg", arg)
	end
end
print(foo(1,2,3,4))


--运算符.. #
a = "Hello "
b = "World"
print("连接字符串 a 和 b ", a..b )
print("b 字符串长度 ",#b )


--测试模块
《module.lua文件》
module = {}
module.constant = "这是一个变量"
function module.func1()
	io.write("这是一个公有函数!\n")
end
local function func2()
	print("这是一个私有函数")
end

function module.func3()
	func2()
end
return module
《main.lua文件》
local m = require("module") --> 别名
m.func1();
m.func3();
print(m.constant)

--测试元表的__index
print("测试元表的__index")
mytable = setmetatable({key1 = "value1"}, {__index = {key2 = "metatablevalue"}})
print(mytable.key1, mytable.key2)

--测试元表的相加
function table_maxn(t)
	local mn = 0
	for k, v in pairs(t) do
		if mn < k then
			mn = k
		end
	end
	return mn
end
mytable = setmetatable({1, 2, 3}, {
	__add = function(mytable, newtable)
	for i = 1, table_maxn(newtable) do
		table.insert(mytable, table_maxn(mytable)+1, newtable[i])
	end
	return mytable
end
})
secondtable = {4, 5, 6}
mytable = mytable + secondtable
for k, v in ipairs(mytable) do
	print(k, v)
end

2、 C调用lua,执行lua脚本

复制lua源码到工程中或者引入lua的lib文件及头文件也可。
在这里插入图片描述

#include <windows.h> 

extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}

int main()
{
	lua_State* l = luaL_newstate();
	luaL_openlibs(l);
	luaL_dofile(l, "main.lua");
	lua_close(l);
	system("pause"); //为了保证在windows资源管理器中打开main.exe不闪退。需要windows.h。
	return 0;
}

3、lua调用C库

在这里插入图片描述
c工程

extern "C" {
#include "lua.h"  
#include "lualib.h"  
#include "lauxlib.h"
};
#include <thread>
#include <iostream>  
using namespace std;

int number = 0;
int number2 = 0;
int flag = 0;
std::thread *t1 = NULL;
std::thread *t2 = NULL;
void ThreadProc1()
{
	flag = 1;
	while (1)
	{
		cout << "thread 1 :" << number << endl;
		++number;
		this_thread::sleep_for(std::chrono::milliseconds(10));
	}

	return ;
}
void ThreadProc2()
{
	while (number2 < 100)
	{
		cout << "thread 2 :" << number2 << endl;
		++number2;
		this_thread::sleep_for(std::chrono::milliseconds(10));
	}

	return ;
}

extern "C" int ShowMsg(lua_State* luaEnv) {
	cout << "Hello world from clibs!" << endl;
	t1 = new std::thread(ThreadProc1);
	return 1; // 返回值个数为0个.  
}
extern "C" int ShowMsg2(lua_State* luaEnv) {
	cout << "Hello world from clibs222!" << endl;
	t2 = new std::thread(ThreadProc2);

	return 0; // 返回值个数为0个.  
}
// part one: 要导出的函数列表
static luaL_Reg luaLibs[] = {
	{ "ShowMsg", ShowMsg },
	{ "ShowMsg2", ShowMsg2 },
	{ NULL, NULL }
};

// part two: DLL入口函数,Lua调用此DLL的入口函数.  
//testDll是modole名, 将来require这个名字并且这个名称要与dll名称一致,并且不能与lua名称一致
extern "C" __declspec(dllexport)
int luaopen_testDll(lua_State* luaEnv) {   
	const char* const LIBRARY_NAME = "WinFeature"; //这里也写WinFeature
	luaL_register(luaEnv, LIBRARY_NAME, luaLibs);//注册要导出的函数列表
	return 1;
}

lua文件

--加载test库
WinFeature1 = require("testDll")

--定义协程
co = coroutine.create(
    function()
		WinFeature1.ShowMsg()
    end
)

--激活协程
coroutine.resume(co)
--打印协程状态
print(coroutine.status(co))


4、lua无法调起C库中两个线程,以及lua端卡死问题或者lua端协程结束C也跟着结束

在这里插入图片描述
lua函数

--加载test库
WinFeature1 = require("testDll")

function Sleep(n)
   local t0 = os.clock()
   while os.clock() - t0 <= n do end
end

--定义协程
co = coroutine.create(
    function()
		WinFeature1.ShowMsg()
		while true do
			print("coroutine")
			Sleep(0.1)
		end
    end
)

--激活协程
coroutine.resume(co)
--打印协程状态
print(coroutine.status(co))


参考博客:

https://blog.csdn.net/qq_35807952/article/details/79912769 Lua与C++交互初探之Lua调用C++
https://www.runoob.com/lua/lua-tutorial.html Lua 教程
https://www.cnblogs.com/chechen/p/11415104.html VS2015 创建C++动态库及使用
https://blog.51cto.com/u_1433795/1310702 lua 调用C++ DLL函数简单实例
https://www.kancloud.cn/thinkphp/lua-guide/43809 绑定Lua和C/C++的库

检测动态库中导出的函数列表
dumpbin /exports testDll.dll
在这里插入图片描述


===================================================================
windows下lua调用C动态库文件(.dll)
https://blog.csdn.net/qq_22252423/article/details/110855367

置顶,使用git bash + mingw32方式解决lua调用C库问题(推荐)
lua-5.3.6为存放源码的文件夹

cd lua-5.3.6/src
mingw32-make.exe mingw
cp lua53.dll ../../
cp lua.exe ../../
cd ../../
gcc -shared -L. -llua53 myLuaCLib.c -o myLuaCLib.dll
./lua.exe test.lua

lua代码如下:

local clib = require "myLuaCLib"
clib.test()

C库代码如下:

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

#include <stdio.h>

static int l_test(lua_State* L)
{
	printf("hello world\r\n");
	return 0;
}

static const struct luaL_Reg myLuaCLib[] = {
	{ "test", l_test },
	{ NULL  , NULL },
};

__declspec(dllexport) int luaopen_myLuaCLib(lua_State* L)
{
	luaL_newlib(L, myLuaCLib);

	return 1;
}

在这里插入图片描述
感谢大神指点!!!

一下方法过于冗余,建议用上述方法解决

1.lua调用C库时,找不到指定程序问题.

lua代码如下:

local clib = require "myLuaCLib"
clib.test()

C库代码如下:

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

#include <stdio.h>

static int l_test(lua_State* L)
{
	printf("hello world\r\n");
	return 0;
}

static const struct luaL_Reg myLuaCLib[] = {
	{ "test", l_test },
	{ NULL  , NULL },
};

int luaopen_myLuaCLib(lua_State* L)
{
	luaL_newlib(L, myLuaCLib);

	return 1;
}


bash显示如下:

 error loading module 'myLuaCLib' from file '.\myLuaCLib.dll':
        找不到指定的程序。

stack traceback:
        [C]: in ?
        [C]: in function 'require'
        test.lua:1: in main chunk
        [C]: in ?

问题原因:
主要原因是在生成C库.dll文件时忘记在需要导出的函数前加入__declspec(dllexport),修改后接口函数代码如下:

__declspec(dllexport) int luaopen_myLuaCLib(lua_State* L)
{
	luaL_newlib(L, myLuaCLib);

	return 1;
}

注:在lua中使用requir(“xxx_c_dll”)函数去调用一个C的动态链接库时,lua函数内部会默认去寻找并调用luaopen_xxx_c_dll函数,所以在此仅提供C库的入口函数就可以了.

2. lua调用C库时,multiple Lua VMs detected问题

./lua53.exe test.lua
lua53.exe: multiple Lua VMs detected
stack traceback:
        [C]: in ?
        [C]: in function 'require'
        test.lua:1: in main chunk
        [C]: in ?

如果按照①中所述解决了"指定程序找不到"的问题后出现"multiple Lua VMs detected",说明我们编写的C库已被lua虚拟机识别,但由于lua虚拟机使用的动态链接库文件(注:此处指的是lua虚拟机本身所调用的lua源码的dll文件)和我们编译C库时所使用的lua源码的dll文件不同,故导致上述问题的发生.所以需要重新编译整个工程(包含重新编译生成lua虚拟机,C库),使其指向相同的lua源码的dll文件即可.

1.生成lua源码的.dll和.lib文件

具体步骤:
1.找一份新鲜的lua源码(我这边使用的是lua-5.3.6),利用VS建立DLL动态链接库工程,将源码全部加进解决方案(除了lua.c luac.c lua.hpp makefile)
2.在解决方案然的配置属性,C/C+±>预处理器->预处理器定义编辑加入:LUA_BUILD_AS_DLL
3.点击编译,即可在"Debug/Release"文件夹下生成.dll和.lib文件,若没有生成.lib文件就是第二步,预处理器定义编辑有问题

2.生成lua控制台程序

具体步骤:
1.重新建立一个工程,仅把lua.c加入
2.配置解决方案
C/C++ ->常规->附加包含目录:在此添加lua源码头文件路径
链接器->常规->附加库目录:在此添加lua源码的.lib文件路径
链接器->输入->附加依赖项:在此添加lua源码的.lib文件名
将lua源码的.dll文件加在可执行文件目录中
3.点击编译即可生成lua控制台程序

3.生成C库的.dll和.lib文件

1.重新建立一个工程,仅把C库文件加入
2.配置解决方案
C/C++ ->常规->附加包含目录:在此添加源码头文件路径
链接器->常规->附加库目录:在此添加lua源码的.lib文件路径
链接器->输入->附加依赖项:在此添加lua源码的.lib文件名
将lua源码的.dll文件加在可执行文件目录中
3.点击编译即可生成C库的.dll和.lib文件
注:此处的生成文件代码细节参考–lua调用C库时,找不到指定程序问题.不在此赘述

最后,各个工程生成的必要文件如下所示在这里插入图片描述
最后将上述文件放在同一个目录,使用bash输入一下命令:

 ./xxx_vm.exe xxx.lua
hello world

限于本人水平,若有纰漏,欢迎指正!


===================================================================
Qt调用Lua动态链接库
https://www.it610.com/article/1282168822421274624.htm

Qt调用Lua动态链接库

上一篇笔记讲解了如何在VS2017下使用C++调用Lua动态链接库,因笔者平时也喜欢使用Qt,故创作本篇记录Qt是如何调用Lua Dll协助我们工作的

新建Qt工程


Lua实战笔记第3篇 Qt调用lua动态链接库_第1张图片

这是创建好的Qt Console工程Lua实战笔记第3篇 Qt调用lua动态链接库_第2张图片

将Lua5.1源码目录“src”拷贝至Qt工程目录下,如下图所示Lua实战笔记第3篇 Qt调用lua动态链接库_第3张图片

在Qt中打开LearnLua.pro文件,将“INCLUDEPATH += ./src”添加到任意位置,至此头文件路径已经配置OK了Lua实战笔记第3篇 Qt调用lua动态链接库_第4张图片

将lib和dll文件拷贝至生成的exe所在文件目录下Lua实战笔记第3篇 Qt调用lua动态链接库_第5张图片

在Qt工程main函数中插入如下代码

lua_State *L = lua_open();        
luaopen_base(L);        
luaopen_table(L);        
luaopen_string(L);        
if (luaL_loadfile(L, "Print.lua"))       
{           
//std::string error = "cannot run Lua file: " + filename;            //throw Exception(error.c_str());            //LOGDEBUG(error.c_str());            //cout<

新建Print.lua脚本,将其置于exe所在目录的上级目录下Lua实战笔记第3篇 Qt调用lua动态链接库_第6张图片

以下代码为Print.lua脚本中的内容

--[[
File name: Print.lua
Description: lua编程Demo1:熟悉lua的基本语法,如变量声明,C语言中if else等语句
                         在lua中的实现
Function List:

Author: Hanc
Version: V0.0
Other:
                1. lua中没有i++这类用法 
                2. while中不能像C一样使用continue功能 
                3. 除了nil和false都为真 
                4. 拼接字符串使用 .. 
                5. C语言中的“&&”“||”“!”在lua中为 and or not 
                6. lua中 != 要用 ~=
                7. 与C/C++不同,lua中的下标是从1开始的
History:
        2019.1.5 创建


]]--
print("hello Lua !!")
--[[
        a = 10  声明全局变量  
        local a = 10    声明局部变量
        lua中尽量使用局部变量,保证垃圾回收及时
        全局变量赋值为“nil”才会交给垃圾回收
--]]
a = 10  

--打印变量的数据类型
print(type(a))
-- 将字符串转换为数字
local c = tonumber("256")
print(c)
--字符串连接使用“..”
local d = "hello baba".."\two shi\n"
--local e = string.len(d)
--print(string.len("we"))

--if else 用法
if(1==1 and 1==2) then
        print("1==1")
else
        print("1 != 1")
end

-- if elseif 用法
if(1==1 and 1==2) then
        print("1==1")
elseif(2==2) then
        print("2 == 2")
end

--break退出,未实现continue
while(nil)      do
print("while")
end

--lua中的do while语句
local i = 100;
repeat
        i = i+1
        print("i = "..i)
until i>110

for var =1,5,1 do
        print("var = "..var)
end

--pairs遍历所有
--ipairs 按照标准数组去访问
local days = {"Sun","Mon","Tus"}
for i,v in ipairs(days) do
        print(i..":"..v)
end

编译运行Qt程序
Lua实战笔记第3篇 Qt调用lua动态链接库_第7张图片


===================================================================
Win32下 Qt与Lua交互使用:配置Qt下Lua运行环境MinGW
https://www.cnblogs.com/lvdongjie/p/4070840.html

Lua与C++之间可以实现非常强的交互性。Lua中可以使用C++中的函数,C++中也可以使用Lua中的函数。由此可以引发出很多奇思妙想了。

    简单来说,Lua动态的特性补充了C++的功能。当然,也看你具体怎么用。

    笔者经常使用Qt,故准备将Qt和Lua结合在一起。想象一下在Lua脚本中调用如下代码:

w = QWidget:new()
w:show()

    然后弹出一QWidget的窗口,是多么感人的一件事情呀。

 

    好,下面开始配置环境吧。

    1. 下载Lua 5.1。目前的最新版本是5.2,但是因为使用到的toLua不支持Lua 5.2,故仍然使用5.1版。

        在http://www.lua.org/versions.html#5.1可以找到5.1版的Lua,下载下来,解压待用。

    2. 下载toLua。笔者找到的是目前最新的toLua 0.95,下载下来后,解压。

        将include/toLua++.h,src/lib中*.c/*.h文件,src/bin/toluabind.c,共8个文件复制到Lua解压目录/src目录下,仅复制文件。

    3. 编译。在Lua解压目录下新建文件夹bin,新建一build.bat文件,输入以下代码:

@setlocal
@if "%1" == "mingw" goto :build_mgw
@if "%1" == "vs" goto :build_vs
@if "%1" == "dist" goto :install
@if "%1" == "" goto :build_mgw

@echo usage: %1 [mingw|vs|dist]
@goto :EOF


:build_mgw
@set srcdir=..\src\
@set CFLAGS=-s -O3 -Wall -I. "-DLUA_USER_H=<luacpath.h>"

@echo build lua52.dll ...
gcc %CFLAGS% -DLUA_BUILD_AS_DLL -c %srcdir%*.c
@del lua.o luac.o
gcc -s -mdll -o lua52.dll -Wl,--out-implib,liblua52.dll.a *.o
@echo build lua.exe ...
gcc %CFLAGS% -o lua.exe %srcdir%lua.c -L. -llua52
@echo build luac.exe ...
gcc %CFLAGS% -c %srcdir%*.c
@del lua.o luac.o
ar rcs liblua52.a *.o
gcc %CFLAGS% -o luac.exe %srcdir%luac.c -L. -static -llua52
@del *.o 2>nul
goto :dist

:build_vs
@set srcdir=..\src\
@set MYCOMPILE=/nologo /MD /O2 /W3 /c /D_CRT_SECURE_NO_DEPRECATE "/DLUA_USER_H=<luacpath.h>"
@set MYLINK=link /nologo
@set MYLIB=lib /nologo
@set MYMT=mt /nologo

@echo build lua52.dll ...
%MYCOMPILE% /DLUA_BUILD_AS_DLL %srcdir%*.c
@del lua.obj luac.obj
%MYLINK% /DLL /out:lua52.dll *.obj
if exist lua52.dll.manifest^
  %MYMT% -manifest lua52.dll.manifest -outputresource:lua52.dll;2
%MYCOMPILE% /DLUA_BUILD_AS_DLL %srcdir%lua.c
%MYLINK% /out:lua.exe lua.obj lua52.lib
if exist lua.exe.manifest^
  %MYMT% -manifest lua.exe.manifest -outputresource:lua.exe
%MYCOMPILE% %srcdir%*.c
del lua.obj luac.obj
%MYLIB% /out:lua52s.lib *.obj
%MYCOMPILE% %srcdir%luac.c
%MYLINK% /out:luac.exe luac.obj lua52s.lib
if exist luac.exe.manifest^
  %MYMT% -manifest luac.exe.manifest -outputresource:luac.exe
@del *.exp *.obj *.manifest
goto :dist


:dist
@echo install ...
@set dstdir=.\Lua52\
mkdir %dstdir%         2>nul
mkdir %dstdir%clibs    2>nul
mkdir %dstdir%include  2>nul
mkdir %dstdir%lib      2>nul
mkdir %dstdir%lua      2>nul

copy /y *.dll            %dstdir%           >nul
copy /y *.exe            %dstdir%           >nul
copy /y *.a              %dstdir%lib        >nul
copy /y %srcdir%lua*.h*  %dstdir%include    >nul
copy /y %srcdir%laux*.h  %dstdir%include    >nul
copy /y %dstdir%lua.exe  %dstdir%lua52.exe  >nul
copy /y %dstdir%luac.exe %dstdir%lua52c.exe >nul


:EOF
echo finish

        这是一位Lua爱好者为编译Lua 5.2编写的脚步,在这里可以直接使用。

        注意建议使用MinGW编译,VS会导致一些问题。没有安装MinGW的可以百度一下,配置好MinGW的环境,并将bin目录加入环境变量path中。

    4. 运行编译脚步。建议先打开CMD窗口,在CMD窗口中进入该目录,执行build.bat。这样报错的话可以看到一些信息。

        可能会有Warnning,不过还是可以顺利通过编译的。在生成的Lua52文件夹中,就有我们想要的东西。

        确保Lua52/lib目录下,生成了liblua52.a文件。

    5. 测试使用。使用MinGW编译,建议使用MinGW版的Qt。

        在Qt Creator中新建一个工程。删除到只剩下mian.cpp即可。

        复制Lua52/include下所有文件,以及之前复制的toLua++.h,到Qt工程目录下。在Qt Creator中加入这些新文件。

        复制Lua52/lib/liblua52.a文件到Qt工程目录下。在Qt工程的*.pro文件中加入

        LIBS+=../LuaTest/liblua52.a

        笔者的工程名为LuaTest,具体的目录名按照你的工程名以及你的build文件夹地址修改。如果提示找不到文件,就该为绝对路径。

        在main.cpp文件中,加入

extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "tolua++.h"
}

    将main函数改为:

    
lua_State *lu = luaL_newstate();
    luaL_openlibs(lu);

    //执行内存脚本
    string str = "print (\"Hello world!\")";
    luaL_loadbuffer(lu, str.c_str(), str.length(), "line");
    lua_pcall(lu, 0, 0, 0);

    顺利运行则配置成功。(在.pro文件中加入CONFIG+=console,在项目-〉运行中勾选Run in terminal,可以打开控制台)

 

    那么如何做到在Lua中新建Qt的窗口呢?下篇博客继续探讨。

    如有问题,可以留言。发现错误,欢迎指正。


===================================================================
Win32下 Qt与Lua交互使用(二):在Lua脚本中使用Qt类
https://www.cnblogs.com/lvdongjie/p/4070870.html

    话接上篇。成功配置好Qt+Lua+toLua后,我们可以实现在Lua脚本中使用各个Qt的类。直接看代码吧。

#include "include/lua.hpp"
#include <QWidget>
#include <QApplication>
#include <QFile>
#include <QDebug>

static int tolua_new_QWidget(lua_State* pState)
{
    QWidget* widget = new QWidget();
    tolua_pushusertype(pState, widget, "QWidget");
    return 1;
}

static int tolua_delete_QWidget(lua_State* pState)
{
    QWidget* widget = (QWidget* )tolua_tousertype(pState, 1, 0);
    if(NULL != widget)
    {
        widget->close();
        delete widget;
    }
    return 1;
}

static int tolua_Show_QWidget(lua_State* pState)
{
    QWidget* widget = (QWidget* )tolua_tousertype(pState, 1, 0);

    if(widget != NULL)
    {
        widget->show();
    }
    return 1;
}

static int tolua_Resize_QWidget(lua_State* pState)
{
    QWidget* widget = (QWidget* )tolua_tousertype(pState, 1, 0);
    double a = tolua_tonumber(pState, 2, 0);
    double b = tolua_tonumber(pState, 3, 0);
    qDebug() << a;
    qDebug() << b;

    if(widget)
    {
        widget->resize((int)a, (int)b);
    }
    return 1;
}

int main(int argc, char * argv[])
{
    Q_INIT_RESOURCE(resources);
    QApplication a(argc, argv);

    // 初始化Lua对象
    lua_State *lu = luaL_newstate();
    luaL_openlibs(lu);

    // 使用tolua对QWidget类进行“描述”
    tolua_open(lu);
    tolua_module(lu, NULL, 0);

    tolua_beginmodule(lu, NULL);
    tolua_usertype(lu, "QWidget");
    tolua_cclass(lu, "QWidget", "QWidget", "", tolua_delete_QWidget);

    tolua_beginmodule(lu, "QWidget");
    tolua_function(lu, "new", tolua_new_QWidget);
    tolua_function(lu, "show", tolua_Show_QWidget);
    tolua_function(lu, "resize", tolua_Resize_QWidget);
    tolua_endmodule(lu);

    tolua_endmodule(lu);

    // 读取资源文件
    QFile file("://test.lua");
    file.open(QIODevice::ReadOnly | QIODevice::Text);

    // 注意,笔者使用的事UTF-8编码,如果是ANSI编码可以去掉这句
    QTextStream in(&file);
    in.setCodec("UTF-8");

    // 读取,并打印下来查看是否正确
    QString str = in.readAll();
    qDebug() << str;

    // Lua加载并执行脚本
    luaL_loadbuffer(lu, str.toLocal8Bit().data(), str.length(), "line");
    lua_pcall(lu, 0, 0, 0);

    return a.exec();
}

    笔者将QWidget的几个函数都写成了static的形式,用tolua进行绑定。这样在Lua脚本中,就可以顺利使用绑定的函数了。下面的Lua脚本的内容:

w = QWidget:new()
w:show()

w:resize(300,400)

    如果成功执行的话,运行结果应该是这样的:

    可以看到成功建立了一个新的QWidget对象,并且大小更改了。

    这就是在Lua中调用Qt类的一种方法。我们可以将Qt类中绝大多数类绑定进去,就可以在Lua脚本中自有的使用Qt。

    对Lua的各个操作可以封装到类里,使代码结构更清晰。

    我觉得现在已经可以实现你的很多奇思妙想了,不是吗?

    附完整工程文件,可能要修改.pro文件中.lib文件的相对路径:

    http://pan.baidu.com/s/1c0rbirm

    附《Lua程序设计》电子书一本,希望有兴趣的同学可以共同学习交流:

    http://pan.baidu.com/s/1c01k2J2


===================================================================
Win32下 Qt与Lua交互使用(三):在Lua脚本中connect Qt 对象
https://www.cnblogs.com/lvdongjie/p/4070872.html

    话接上文。笔者为了方便使用Lua,自己编写了一个Lua的类。主要代码如下:

    QLua.h

 1 #ifndef QLUA_H
 2 #define QLUA_H
 3 
 4 // own
 5 #include "include/lua.hpp"
 6 
 7 // qt
 8 #include <QObject>
 9 #include <QFile>
10 #include <QDebug>
11 
12 #include <QWidget>
13 #include <QLineEdit>
14 #include <QPushButton>
15 #include <QMessageBox>
16 
17 class QLua : public QObject
18 {
19     Q_OBJECT
20 public:
21     QLua(QObject *parent = 0);
22     ~QLua();
23 
24     // lua
25     void init();
26     void close();
27 
28     void pushFunction(QString funcName, lua_CFunction func);
29 
30     void beginModule(QString);
31     void addType(QString, lua_CFunction deleteFunc);
32     void moduleTypeFunction(QString, lua_CFunction);
33     void endModule();
34 
35     void run(QString);
36 signals:
37 
38 public slots:
39 
40 private:
41     lua_State *luaState;
42 
43     bool isStartModule;
44 };
45 
46 #endif // QLUA_H

    QLua.cpp

 1 #include "qlua.h"
 2 
 3 QLua::QLua(QObject *parent) :
 4     QObject(parent)
 5   , luaState(NULL)
 6   , isStartModule(false)
 7 {
 8     init();
 9 }
10 
11 QLua::~QLua()
12 {
13     close();
14 }
15 
16 void QLua::init()
17 {
18     luaState = luaL_newstate();
19     luaL_openlibs(luaState);
20 }
21 
22 void QLua::close()
23 {
24     if(luaState != NULL)
25     {
26         lua_close(luaState);
27         luaState = NULL;
28     }
29 }
30 
31 void QLua::pushFunction(QString funcName, lua_CFunction func)
32 {
33     if (funcName.isEmpty()) return;
34     if (func == NULL)       return;
35 
36     lua_pushcfunction(luaState, func);
37     lua_setglobal(luaState, funcName.toLocal8Bit().data());
38 }
39 
40 void QLua::beginModule(QString name)
41 {
42     if(luaState == NULL) return;
43 
44     if (isStartModule == false)
45     {
46         tolua_open(luaState);
47         tolua_module(luaState, NULL, 0);
48         isStartModule = true;
49     }
50 
51     const char *str = name.isEmpty()? NULL : name.toLocal8Bit().data();
52     tolua_beginmodule(luaState, str);
53 }
54 
55 void QLua::addType(QString name, lua_CFunction deleteFunc)
56 {
57     if (luaState == NULL) return;
58     if (name.isEmpty())   return;
59     if (deleteFunc == NULL) return;
60 
61     tolua_usertype(luaState, name.toLocal8Bit().data());
62     const char *str = name.toLocal8Bit().data();
63     tolua_cclass(luaState, str, str, "", deleteFunc);
64     beginModule(name);
65 }
66 
67 void QLua::moduleTypeFunction(QString name, lua_CFunction func)
68 {
69     if(luaState == NULL) return ;
70     if (name.isEmpty())  return;
71 
72     const char *str = name.toLocal8Bit().data();
73     tolua_function(luaState, str, func);
74 }
75 
76 void QLua::endModule()
77 {
78     tolua_endmodule(luaState);
79 }
80 
81 void QLua::run(QString str)
82 {
83     luaL_loadbuffer(luaState, str.toLocal8Bit().data(), str.length(), "line");
84     lua_pcall(luaState, 0, 0, 0);
85 }

 

    QLua类可以方便的实现一些简单的Lua操作,如初始化,关闭,运行Lua代码,绑定函数等。

 

    笔者目前想做到的是能在Lua代码中自有的生成Qt对象,然后能连接Qt原生对象的信号与槽。那么如何实现呢?

    Qt中连接信号与槽的函数是QObject::connect(QObject * a, SIGNAL(), QObject * b, SLOT())。首先,我们要弄清楚SIGNAL和SLOT到底是什么。

    从connect的参数列表中,我们可以很清晰的看到SIGNAL和SLOT的结果都是char*类型的字符串。我们可以直接在SIGNAL上点右键,转到SIGNAL的定义。或者做个简单的实验。测试如下Qt代码:

    qDebug() << QString::fromLocal8Bit(SIGNAL(clicked()));
    qDebug() << QString::fromLocal8Bit(SLOT(close()));

    得到的结果很有意思:

"2clicked()" 
"1close()" 

    简单总结就是我们只要传入函数名的字符串,加上前缀即可。SIGNAL的前缀是2,SLOT的前缀是1。

    这样我们就可以实现在Lua中的connect函数了。仍在使用C++编写,然后绑定到Lua里。如下:

 1 static int connect(lua_State* state)
 2 {
 3     QObject * a = (QObject*)tolua_tousertype(state, 1, 0);
 4     const char * signal = tolua_tostring(state, 2, 0);
 5     QObject * b = (QObject*)tolua_tousertype(state, 3, 0);
 6     const char * slot = tolua_tostring(state, 4, 0);
 7 
 8     QObject::connect(a, QString("2%0").arg(signal).toLocal8Bit().data(),
 9                      b, QString("1%0").arg(slot).toLocal8Bit().data());
10 }

    绑定时可以使用上面的QLua类:

lua.pushFunction("connect", connect);

 

    完整main.cpp代码如下:

#include "include/lua.hpp"
#include "qlua.h"
#include <QWidget>
#include <QApplication>
#include <QFile>
#include <QDebug>

static int test(lua_State* state)
{
    QPushButton* a = (QPushButton*)tolua_tousertype(state, 1, 0);
    if(a)
        a->show();
}

static int connect(lua_State* state)
{
    QObject * a = (QObject*)tolua_tousertype(state, 1, 0);
    const char * signal = tolua_tostring(state, 2, 0);
    QObject * b = (QObject*)tolua_tousertype(state, 3, 0);
    const char * slot = tolua_tostring(state, 4, 0);

    QObject::connect(a, QString("2%0").arg(signal).toLocal8Bit().data(),
                     b, QString("1%0").arg(slot).toLocal8Bit().data());
}

static int tolua_new_QWidget(lua_State* state)
{
    QWidget* widget = new QWidget();
    tolua_pushusertype(state, widget, "QWidget");
    return 1;
}

static int tolua_delete_QWidget(lua_State* state)
{
    qDebug() << "delete Start";
    QWidget* widget = (QWidget* )tolua_tousertype(state, 1, 0);
    if(NULL != widget)
    {
        qDebug() << "delete~";
        widget->close();
        delete widget;
    }
    return 1;
}

static int tolua_Show_QWidget(lua_State* state)
{
    QWidget* widget = (QWidget* )tolua_tousertype(state, 1, 0);

    if(widget != NULL)
    {
        widget->show();
    }
    return 1;
}

static int tolua_new_QPushButton(lua_State* state)
{
    QPushButton* button = new QPushButton();
    tolua_pushusertype(state, button, "QPushButton");
    return 1;
}

static int tolua_delete_QPushButton(lua_State* state)
{
    QPushButton* button = (QPushButton* )tolua_tousertype(state, 1, 0);
    if(NULL != button)
    {
        button->close();
        delete button;
    }
    return 1;
}

static int tolua_Show_QPushButton(lua_State* state)
{
    QPushButton* button = (QPushButton* )tolua_tousertype(state, 1, 0);

    if(button != NULL)
    {
        button->show();
    }
    return 1;
}

static int tolua_setText_QPushButton(lua_State* state)
{
    QPushButton* button = (QPushButton* )tolua_tousertype(state, 1, 0);
    const char * text = tolua_tostring(state, 2, 0);

    if(button != NULL)
    {
        button->setText(QString::fromLocal8Bit(text));
    }
    return 1;
}

static int tolua_Resize_QWidget(lua_State* state)
{
    QWidget* widget = (QWidget* )tolua_tousertype(state, 1, 0);
    double a = tolua_tonumber(state, 2, 0);
    double b = tolua_tonumber(state, 3, 0);

    if(widget)
    {
        widget->resize((int)a, (int)b);
    }
    return 1;
}

static int QApplication_instance(lua_State* state)
{
    tolua_pushusertype(state, QApplication::instance(), "QApplication");
    return 1;
}

static int QApplication_quit(lua_State* state)
{
    QApplication * app = (QApplication *)tolua_tousertype(state, 1, 0);
    if(app)
        app->quit();
    return 1;
}

static int QApplication_delete(lua_State*)
{
    return 1;
}

int main(int argc, char * argv[])
{
    Q_INIT_RESOURCE(resources);
    QApplication a(argc, argv);

    QLua lua;

    lua.beginModule("");

    lua.addType("QWidget", tolua_delete_QWidget);
    lua.moduleTypeFunction("new", tolua_new_QWidget);
    lua.moduleTypeFunction("show", tolua_Show_QWidget);
    lua.moduleTypeFunction("resize", tolua_Resize_QWidget);
    lua.endModule();

    lua.addType("QPushButton", tolua_delete_QPushButton);
    lua.moduleTypeFunction("new", tolua_new_QPushButton);
    lua.moduleTypeFunction("show", tolua_Show_QPushButton);
    lua.moduleTypeFunction("setText", tolua_setText_QPushButton);
    lua.endModule();

    lua.addType("QApplication", QApplication_delete);
    lua.moduleTypeFunction("instance", QApplication_instance);
    lua.moduleTypeFunction("quit", QApplication_quit);
    lua.endModule();

    lua.endModule();

    lua.pushFunction("test", test);
    lua.pushFunction("connect", connect);

    // 读取资源文件
    QFile file("://test.lua");
    file.open(QIODevice::ReadOnly | QIODevice::Text);

    QTextStream in(&file);
    in.setCodec("UTF-8");

    // 执行
    lua.run(in.readAll());

    return a.exec();
}

    test.lua代码如下:

widget = QWidget:new()
widget:show()

button = QPushButton:new()
button:setText("China")
button:show()

connect(button, "clicked()", widget, "close()")
connect(button, "clicked()", button, "close()")

print("run over")

    程序运行结果如下:

    点击China按钮,button和widget的窗口都会关闭。

    至此,已经实现了连接 Qt 对象的信号与槽。

    如果继续做下去,完全可以实现在Lua脚本中使用Qt的类和对象,写出Lua的Gui程序。

    附完整代码工程文件:http://pan.baidu.com/s/1ntmFdjj

    附个偶的博客地址:http://www.cnblogs.com/IT-BOY/


===================================================================
Win32下 Qt与Lua交互使用(四):在Lua脚本中自由执行Qt类中的函数
https://www.cnblogs.com/lvdongjie/p/4070876.html

    话接上篇。通过前几篇博客,我们实现在Lua脚本中执行Qt类中函数的方法,以及在Lua脚本中连接Qt对象的信号与槽。

    但是,我们也能发现,如果希望在Lua脚本中执行Qt类的函数,就必须绑定一个真正实现功能的函数。如QWidget::show(),需要写一个在栈中取出widget指针,widget调用show()函数的方式。如果希望在Lua中调用大量函数,就需要编写大量的C++实现函数。有没有什么省时省力的好方法呢?

    上一篇中我们实现了在Lua脚本中连接信号与槽。我们只是传过去了两个QObject的对象,和两个字符串的函数名。我们并没有具体实现那个函数,但是槽函数顺利执行了。这给了笔者启发。如果我传过去一个函数名,理论上我可以找一个信号连接并激发它,也就达到了执行的目的。

    OK,我们写这样一个函数:

static int exec(lua_State *state)
{
    QObject* obj = (QObject* )tolua_tousertype(state, 1, 0);
    const char * slot = tolua_tostring(state, 2, 0);

    if(obj != NULL)
    {
        RunSLOT run;
        QObject::connect(&run, SIGNAL(sendSignal()),
                obj, QString("1%0()").arg(slot).toLocal8Bit().data());
    }

    return 1;
}

    取得QObject对象,以及字符串的槽函数名称。然后我们新建了一个RunSLOT对象,连接了run和obj对象。这样就能执行字符串代表的函数?

    继续看RunSLOT类:

#ifndef RUNSLOT_H
#define RUNSLOT_H

#include <QObject>

class RunSLOT : public QObject
{
    Q_OBJECT
public:
    RunSLOT(QObject *parent = 0);
    ~RunSLOT();

signals:
    void sendSignal();
};

#endif // RUNSLOT_H
#include "runslot.h"

RunSLOT::RunSLOT(QObject *parent) :
    QObject(parent)
{
}

RunSLOT::~RunSLOT()
{
    emit sendSignal();
}

    在析构是发出sendSignal信号,激发槽函数。而RunSLOT类对象run在遇到‘}’自动析构(C++局部变量原则),也就间接的执行了槽函数。

    在绑定函数时将exec绑定到类里,然后写个测试脚本看看:

widget = QWidget:new()
widget:exec("show")

button = QPushButton:new()
button:exec("show")

connect(button, "clicked()", widget, "hide()")

    成功显示一个窗体,一个按钮。

    完整main.cpp如下:

// own
#include "include/lua.hpp"
#include "qlua.h"
#include "runslot.h"

// qt
#include <QWidget>
#include <QApplication>
#include <QFile>
#include <QDebug>

static int connect(lua_State* state)
{
    QObject * a = (QObject*)tolua_tousertype(state, 1, 0);
    const char * signal = tolua_tostring(state, 2, 0);
    QObject * b = (QObject*)tolua_tousertype(state, 3, 0);
    const char * slot = tolua_tostring(state, 4, 0);

    QObject::connect(a, QString("2%0").arg(signal).toLocal8Bit().data(),
                     b, QString("1%0").arg(slot).toLocal8Bit().data());

    return 1;
}

static int exec(lua_State *state)
{
    QObject* obj = (QObject* )tolua_tousertype(state, 1, 0);
    const char * slot = tolua_tostring(state, 2, 0);

    if(obj != NULL)
    {
        RunSLOT run;
        QObject::connect(&run, SIGNAL(sendSignal()),
                obj, QString("1%0()").arg(slot).toLocal8Bit().data());
    }

    return 1;
}

static int QObject_delete(lua_State* state)
{
    qDebug() << "delete Start";
    QObject* obj = (QObject* )tolua_tousertype(state, 1, 0);
    if(NULL != obj)
    {
        qDebug() << "delete~";
        delete obj;
    }
    return 1;
}

static int QWidget_new(lua_State* state)
{
    QWidget* widget = new QWidget();
    tolua_pushusertype(state, widget, "QWidget");
    return 1;
}

static int QPushButton_new(lua_State* state)
{
    QPushButton* button = new QPushButton();
    tolua_pushusertype(state, button, "QPushButton");
    return 1;
}

static int QWidget_resize(lua_State* state)
{
    QWidget* widget = (QWidget* )tolua_tousertype(state, 1, 0);
    double a = tolua_tonumber(state, 2, 0);
    double b = tolua_tonumber(state, 3, 0);

    if(widget)
    {
        widget->resize((int)a, (int)b);
    }
    return 1;
}

int main(int argc, char * argv[])
{
    Q_INIT_RESOURCE(resources);
    QApplication a(argc, argv);

    QLua lua;

    lua.beginModule("");

    lua.addType("QWidget", QObject_delete);
    lua.moduleTypeFunction("new", QWidget_new);
    lua.moduleTypeFunction("resize", QWidget_resize);
    lua.moduleTypeFunction("exec", exec);
    lua.endModule();

    lua.addType("QPushButton", QObject_delete);
    lua.moduleTypeFunction("new", QPushButton_new);
    lua.moduleTypeFunction("exec", exec);
    lua.endModule();

    lua.endModule();

    lua.pushFunction("connect", connect);

    // 读取资源文件
    QFile file("../../LuaTest/test.lua");
    file.open(QIODevice::ReadOnly | QIODevice::Text);

    QTextStream in(&file);
    in.setCodec("UTF-8");

    // 执行
    lua.run(in.readAll());

    return a.exec();
}

    我们可以在将绑定exec函数写在QLua类里,添加类时就绑定这个函数。

    当然,这个方法的局限性在于执行的函数无参数,而且必须是槽函数。如果想自由一个,可以在调用时写上参数,参数类型,C++这边判断并选择不同的信号连接方式,一劳永逸。

    通过这个例子,我们可以发现,Qt本身就具备由字符串执行函数的能力,按照我的见解,这就是一种半动态。笔者会继续做下去,因为这个真的很有趣。

    完整例程代码下载:http://pan.baidu.com/s/1sjFDiRb

    转载注明出处:http://www.cnblogs.com/IT-BOY/


===================================================================

===================================================================

===================================================================