【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

不知道大家有没有玩过plc设备。plc设备从本质上来说,就是一个单片机设备,只不过它的电源、输入、输出做了很多的加强措施。但是从功能说,plc又不是一个简单的io设置,好像只需要设置一个高低电平就可以了。所以使用plc的人,要想把plc用的好,让plc用在更多的场景上面,仅仅会接线是不够的,他还要知道怎么编写梯形图,或者知道怎么编写脚本。

这就我们一个启示。如果我们的上位机只是简单的应用,那么功能就不需要设置地很复杂。但是一旦大家希望把自己的上位机部署到更多的场景当中,那么不管怎么开发,都不一定能满足特定场景的需要。这个时候就有必要在上位机当中嵌入一个虚拟机脚本软件,这一点就非常重要了。某种意义上来说,这相当于给你的上位机赋予了第二次生命,软件本身有了更广阔的发展舞台,而不仅仅是我们提供什么,客户就只能做什么。今天呢,我们正好借助于lua语言,看看怎么在上位机当中嵌入一个虚拟机。

1、创建一个基础widget工程

创建这个widget工程的目的仅仅是为了演示,其实纯console工程也是可以的。

2、下载lua

既然vs支持nuget下载,那么除了c# wpf之外,我们也可以用nuget下载一下lua第三方包。输入lua,寻找到第一个选项即可,十分方便。目前下载的版本是5.4.6,还算是比较新的版本。

3、增加lua调用c的函数

如果是lua调用c,那么需要利用lua_register注册一个函数。这个函数最好用extern “C”包起来,这样保证链接没有问题。当然,我们为了方便测试,直接把lua_State虚拟机变量放在了外面。

#include using namespace std;#include #include #include "lua.hpp"#include "QtWidgetsApplication.h"// static variablestatic lua_State* L = NULL;// lua call cextern "C" int exampleFunction() {const char* arg = lua_tostring(L, 1); qDebug()<< "C++ function called with argument: " << arg ;return 0; }void registerFunction(const QString& functionName, lua_CFunction function) {lua_register(L, functionName.toUtf8().constData(), function);}bool executeScript(const QString& script) {int result = luaL_dostring(L, script.toUtf8().constData()); return (result == LUA_OK);}

4、c调用lua函数

如果是c调用lua函数,那么需要一开始利用luaL_dofile加载一下lua文件。文件中因为只有函数,所以等于没执行。注意lua文件要和cpp文件在同一层级的目录下。加载好了之后,就可以利用lua_pcall进行加载和处理了。

// c call luabool loadLuaScript(const QString& filePath) {int result = luaL_dofile(L, filePath.toUtf8().constData());return (result == LUA_OK);}void callLuaFunction(const QString& functionName, const QString& arg) {lua_getglobal(L, functionName.toUtf8().constData()); lua_pushstring(L, arg.toUtf8().constData());lua_pcall(L, 1, 0, 0);}

其中LuaScript.lua内容如下所示,

-- LuaScript.luafunction luaFunctionFromCpp(arg)print("Lua function called from C++ with argument: " .. arg)---os.execute('mkdir 456')end

5、测试和准备

前面虽然也写了lua调用c,以及c调用lua,但是怎么测试没有讲。这部分呢,其实不复杂。首先我们创建一个lua虚拟机,接着先测试lua调用c,然后测试c调用lua,最后删除lua虚拟机。整个test测试函数可以放在main函数的任何一个位置。

static void test(){// create a vmL = luaL_newstate();luaL_openlibs(L);// lua call cregisterFunction("exampleFunction", (lua_CFunction)&exampleFunction);executeScript("exampleFunction('Hello from Lua!')");// c call lualoadLuaScript("./LuaScript.lua");callLuaFunction("luaFunctionFromCpp", "Hello from C++!");// close vmlua_close(L);}

最后有一点需要注意下,如果是lua调用c还比较好测试,直接在c函数设置断点,就能判断有没有调用成功。如果是c调用lua,可以通过在lua文件创建目录,或者生成文件的方法,来判断lua函数是不是真得执行到了。这一点可以参考上述lua文件中被注释掉的内容。