朱皮特的博客 自由的飞翔

在C/C++中使用Lua

2013-02-17
朱皮特
lua
阅读量:

编译

  • 编译lua.lib时工程不包含luac.c文件,
  • 编译luac时工程包含luac.c文件但是不包含lua.c文件。

封装注册Lua C API

Lua原生态逐个函数注册

  • lua_register(L, “test”, test)

数组批量注册

#define MODULE_NAME_STAR	"star"

extern const struct luaL_Reg starlib[] = {
	{"msgbox", msgbox},
	{"log", log},
	{"md5", md5},
	{"trim", trim},
	//……
};


int openMyLuaLib(lua_State *L) {
	luaL_newlibtable(L, starlib);
	lua_pushvalue(L, -1);
	luaL_setfuncs(L, starlib, 0);
	return 1;
}

luaL_requiref(L, MODULE_NAME_STAR, openMyLuaLib, 1);

使用luabind

需要注意的是,使用luabind注册导出类时,类的构造函数需要一并导出,否则可能会导致崩溃问题。

luabind::open(L);

module(L)
    [
        def( "msgbox", &msgbox),
        def( "dbgprint", &dbgprint)
        //class_<CClientControl>("CMyClass")
        //.def(constructor<>())
        //.def("testFunc1", &CMyClass::testFunc1)
        //.def("testFunc2", &CMyClass::testFunc2)
    ];

C函数就要按如下封装:

int msgbox(const char*szText) {
     return ::MessageBoxA(0,szText,NULL,0);
}

注意: 返回值类型和参数类型必须是常见的数据类型,例如:int,long,DWORD,string,char*都是可以的, 结构体或者其他类型指针不支持。而且这里的返回值不再表示返回值个数,就代表返回值。

C/C++执行Lua脚本

  • luaL_dofile
  • luaL_loadbuffer
extern "C" {
	#include <lua/lua.h>
	#include <lua/lauxlib.h>
	#include <lua/lualib.h>
}

extern lua_State *L = NULL;


bool RunScript(LPCTSTR lpszFileName) {
	bool bSuccess = TRUE;

	//关闭上次创建的
	if (L) {
		lua_close(L);
		L = NULL;
	}

	L = luaL_newstate();
	if (L) {
		luaL_openlibs(L);
		luaopen_star(L);
		luaopen_mylib2(L);
	}
	if (lpszFileName != NULL) {
		int err = luaL_dofile(L, lpszFileName);
		if (err) {
			const char *szMsg = lua_tostring(L, -1);
			ShowMessage("脚本错误:" + CString(szMsg));
			bSuccess = FALSE;
		}
	}

	return bSuccess;
}
string strScript;
DWORD dwSize = 0;
DWORD dwReadWrite = 0;

HANDLE hFile = CreateFile(strLuaFile, GENERIC_READ | GENERIC_WRITE, NULL, NULL, OPEN_EXISTING, NULL, NULL);
if (hFile == INVALID_HANDLE_VALUE) { return; }

dwSize = Star::FileUnit::GetFileSize(hFile, NULL);
if ((int)dwSize > 0) {
	PBYTE pBuff = new BYTE[dwSize];
	if (pBuff != NULL) {
		ReadFile(hFile, pBuff, dwSize, &dwReadWrite, NULL);
		strScript.assign((char *)pBuff, dwSize);
		delete[]pBuff;
	}
}
CloseHandle(hFile);

lua_State* L = luaL_newstate();
if (L) {
	luaL_openlibs(L);
	//luaopen_mylibs(L);
	RunLuaScript(L, strScript);
	lua_close(L);
}


bool RunLuaScript(lua_State* L, const string&strScript) {
	if (luaL_loadbuffer(L, i->strScript.data(), i->strScript.length(), "") != 0 || lua_pcall(L, 0, LUA_MULTRET, 0)) {
		const char* serr = lua_tostring(L, -1);
		lua_pop(L, 1);
		return false;
	}

	lua_getglobal(L, "testFunc");
	if (lua_pcall(L, 0, 3, 0) != 0) {
		serr = lua_tostring(L, -1);
		lua_pop(L, 1);
		return false;
	} else {
		if (lua_isnumber(L, -3)) {
			nScriptRet1 = lua_tonumber(L, -3);
		}
		if (lua_isnumber(L, -2)) {
			nScriptRet2 = lua_tonumber(L, -2);
		}
		if (lua_isstring(L, -1)) {
			strScriptRet = lua_tostring(L, -1);
		}
		lua_pop(L, 3);
	}
	
	return true;
}

C/C++交互访问Lua脚本

在C代码中访问Lua脚本的变量

  • lua_getglobal

在C代码中调用Lua脚本中的函数

  • lua_pcall
bool isScriptMatched(lua_State *L, const CString&strAccount, const CString&strParams) {
	bool bMatched = false;
	if (L == NULL) {
		return bMatched;
	}

	lua_getglobal(L, "onMatch");
	if (lua_isfunction(L, -1)) {
		lua_pushstring(L, strAccount);
		lua_pushstring(L, strParams);
		lua_pushstring(L, STRFILEVER);
		int err = lua_pcall(L, 3, 1, 0);
		if (err) {
			const char *szMsg = lua_tostring(L, -1);
			ShowMessage(szMsg, MSGSHOWTYPE::ShowAll, MSGBOXTIP::ScriptError);
		} else {
			int nFit = lua_toboolean(L, -1);
			if (nFit != 0) {
				bMatched = true;
			}
		}
	}

	return bMatched;
}

在C/C++中返回数据给Lua脚本

Lua脚本允许有多个返回值,有多少个返回值就return几,通过lua_pushxxx函数来把返回的数据压到栈上。

  • lua_pushinteger
  • lua_pushstring
  • lua_pushboolean
  • lua_pushnumber
lua_pushnumber(L, nRet);
return 1;

下一篇 Lua位操作

Comments

Content