一个Lua库实际上是一个定义了一系列Lua函数的代码块,并将这些函数保存在适当的地方,通常作为table的域来保存。Lua的C库就是这样实现的。
作为一个完整的库,我们还需要写一个函数来负责把库中的所有公共函数放到table里,然后注册到Lua全局变量里,就像
luaopen_*做的一样。 Lua为这种需求提供了辅助函数
luaL_register,它接受一个C函数的列表和他们对应的函数名,并且作为一个库在一个table中注册所有这些 函数。
下例中注册了一个名为Files的库,定义了三个库函数:FindFirst,FindNext,FindClose。
- extern "C" {
- #include "lua.h"
- #include "lualib.h"
- #include "lauxlib.h"
- }
-
- #include
- #include
- #include
- using namespace std;
-
- int findfirst( lua_State *L )
- {
- WIN32_FIND_DATAA FindFileData;
- HANDLE hFind = ::FindFirstFileA(luaL_checkstring(L,1), &FindFileData);
-
- if(INVALID_HANDLE_VALUE == hFind)
- lua_pushnil(L);
- else
- lua_pushlightuserdata(L, hFind);
-
- lua_pushstring(L, FindFileData.cFileName);
-
- return 2;
- }
-
- int findnext( lua_State *L )
- {
- WIN32_FIND_DATAA FindFileData;
- if(::FindNextFileA(lua_touserdata(L,1),&FindFileData))
- lua_pushstring(L, FindFileData.cFileName);
- else
- lua_pushnil(L);
- return 1;
- }
-
- int findclose( lua_State *L )
- {
- ::FindClose(lua_touserdata(L,1));
- return 0;
- }
-
- static const struct luaL_reg lrFiles [] = {
- {"FindFirst", findfirst},
- {"FindNext", findnext},
- {"FindClose", findclose},
- {NULL, NULL}
- };
- int luaopen_Files (lua_State *L) {
- luaL_register(L, "Files", lrFiles);
- return 1;
- }
-
- int main()
- {
- char* szLua_code=
- "hFind,sFile = Files.FindFirst('c:\\\\*.*'); "
- "if hFind then "
- " repeat "
- " print(sFile) "
- " sFile = Files.FindNext(hFind) "
- " until sFile==nil; "
- " Files.FindClose(hFind) "
- "end";
- lua_State *L = luaL_newstate();
- luaL_openlibs(L);
- luaopen_Files(L);
-
- bool err = luaL_loadstring(L, szLua_code) || lua_pcall(L, 0, 0, 0);
- if(err)
- {
- cerr << lua_tostring(L, -1);
- lua_pop(L, 1);
- }
- lua_close(L);
- return 0;
- }
本例运行结果是显示出C盘根目录下所有的文件名。
Lua官方建议把函数库写进动态链接库中(
windows下.dll文件,linux下.so文件),这样就可以在Lua代码中使用
loadlib函数动 态载入函数库
例如,我们把上面的例子改成动态链接库版本:
DLL代码,假定生成的文件名为
fileslib.dll:
- extern "C" {
- #include "lua.h"
- #include "lualib.h"
- #include "lauxlib.h"
- }
- #include
-
- BOOL APIENTRY DllMain( HMODULE hModule,
- DWORD ul_reason_for_call,
- LPVOID lpReserved
- )
- {
- return TRUE;
- }
-
- int findfirst( lua_State *L )
- {
- WIN32_FIND_DATAA FindFileData;
- HANDLE hFind = ::FindFirstFileA(luaL_checkstring(L,1), &FindFileData);
-
- if(INVALID_HANDLE_VALUE == hFind)
- lua_pushnil(L);
- else
- lua_pushlightuserdata(L, hFind);
-
- lua_pushstring(L, FindFileData.cFileName);
-
- return 2;
- }
-
- int findnext( lua_State *L )
- {
- WIN32_FIND_DATAA FindFileData;
- if(::FindNextFileA(lua_touserdata(L,1),&FindFileData))
- lua_pushstring(L, FindFileData.cFileName);
- else
- lua_pushnil(L);
- return 1;
- }
-
- int findclose( lua_State *L )
- {
- ::FindClose(lua_touserdata(L,1));
- return 0;
- }
-
- static const struct luaL_reg lrFiles [] = {
- {"FindFirst", findfirst},
- {"FindNext", findnext},
- {"FindClose", findclose},
- {NULL, NULL}
- };
- extern "C" __declspec(dllexport) int luaopen_Files (lua_State *L) {
- luaL_register(L, "Files", lrFiles);
- return 1;
- }
Lua调用代码(
或者直接使用Lua.exe调用,dll文件必须处于package.cpath指定的目录中,默认与执行文件在同一目录即可):
- extern "C" {
- #include "lua.h"
- #include "lualib.h"
- #include "lauxlib.h"
- }
-
- #include
- #include
- #include
- using namespace std;
-
- int main()
- {
- char* szLua_code=
- "fileslib = package.loadlib('fileslib.dll', 'luaopen_Files') "
- "fileslib() "
- "hFind,sFile = Files.FindFirst('c:\\\\*.*'); "
- "if hFind then "
- " repeat "
- " print(sFile) "
- " sFile = Files.FindNext(hFind) "
- " until sFile==nil; "
- " Files.FindClose(hFind) "
- "end";
- lua_State *L = luaL_newstate();
- luaL_openlibs(L);
-
- bool err = luaL_loadstring(L, szLua_code) || lua_pcall(L, 0, 0, 0);
- if(err)
- {
- cerr << lua_tostring(L, -1);
- lua_pop(L, 1);
- }
- lua_close(L);
- return 0;
- }
Lua代码里使用
package.loadlib得到动态链接库中的
luaopen_Files函数,然后调用它注册到Lua中,如果动态链接库中的导出 函数名称满足
luaopen_<库名>的话,还可以使用
require直接载入。
比如,如果把本例中的DLL代码里的导出函数名
luaopen_Files改成
luaopen_fileslib的话,Lua代码便可以改成:
- char* szLua_code=
- "require('fileslib') "
- "hFind,sFile = Files.FindFirst('c:\\\\*.*'); "
- ...
阅读(4845) | 评论(0) | 转发(0) |