Chinaunix首页 | 论坛 | 博客
  • 博客访问: 7277682
  • 博文数量: 512
  • 博客积分: 12019
  • 博客等级: 上将
  • 技术积分: 6857
  • 用 户 组: 普通用户
  • 注册时间: 2005-08-01 16:46
文章分类

全部博文(512)

文章存档

2024年(2)

2022年(2)

2021年(6)

2020年(59)

2019年(4)

2018年(10)

2017年(5)

2016年(2)

2015年(4)

2014年(4)

2013年(16)

2012年(47)

2011年(65)

2010年(46)

2009年(34)

2008年(52)

2007年(52)

2006年(80)

2005年(22)

分类: C/C++

2009-09-03 11:56:01

一个Lua库实际上是一个定义了一系列Lua函数的代码块,并将这些函数保存在适当的地方,通常作为table的域来保存。Lua的C库就是这样实现的。
    作为一个完整的库,我们还需要写一个函数来负责把库中的所有公共函数放到table里,然后注册到Lua全局变量里,就像luaopen_*做的一样。 Lua为这种需求提供了辅助函数luaL_register,它接受一个C函数的列表和他们对应的函数名,并且作为一个库在一个table中注册所有这些 函数。
下例中注册了一个名为Files的库,定义了三个库函数:FindFirst,FindNext,FindClose。
  1. extern "C" {
  2. #include "lua.h"
  3. #include "lualib.h"
  4. #include "lauxlib.h"
  5. }
  6.  
  7. #include 
  8. #include 
  9. #include 
  10. using namespace std;
  11.  
  12. //函数库示例,Windows下查找文件功能
  13. //输入:string路径名
  14. //输出:userdata存放Handle(如果没找到,则是nil), string文件名
  15. int findfirst( lua_State *L )
  16. {
  17.     WIN32_FIND_DATAA FindFileData;
  18.     HANDLE hFind = ::FindFirstFileA(luaL_checkstring(L,1), &FindFileData);
  19.    
  20.     if(INVALID_HANDLE_VALUE == hFind)
  21.         lua_pushnil(L);
  22.     else
  23.         lua_pushlightuserdata(L, hFind);
  24.  
  25.     lua_pushstring(L, FindFileData.cFileName);
  26.    
  27.     return 2;
  28. }
  29.  
  30. //输入:userdata:findfirst返回的Handle
  31. //输出:string:文件名,如果没找到,则返回nil
  32. int findnext( lua_State *L )
  33. {
  34.     WIN32_FIND_DATAA FindFileData;
  35.     if(::FindNextFileA(lua_touserdata(L,1),&FindFileData))
  36.         lua_pushstring(L, FindFileData.cFileName);
  37.     else
  38.         lua_pushnil(L);
  39.     return 1;
  40. }
  41.  
  42. //输入:userdata:findfirst返回的Handle
  43. //没有输出
  44. int findclose( lua_State *L )
  45. {
  46.     ::FindClose(lua_touserdata(L,1));
  47.     return 0;
  48. }
  49.  
  50. //注册函数库
  51. static const struct luaL_reg lrFiles [] = {
  52.     {"FindFirst", findfirst},
  53.     {"FindNext", findnext},
  54.     {"FindClose", findclose},
  55.     {NULL, NULL}    /* sentinel */
  56. };
  57. int luaopen_Files (lua_State *L) {
  58.     luaL_register(L, "Files", lrFiles);
  59.     return 1;
  60. }
  61.  
  62. int main()
  63. {
  64.     char* szLua_code=
  65.         "hFind,sFile = Files.FindFirst('c:\\\\*.*'); "
  66.         "if hFind then "
  67.         "    repeat "
  68.         "        print(sFile) "
  69.         "        sFile = Files.FindNext(hFind) "
  70.         "    until sFile==nil; "
  71.         "    Files.FindClose(hFind) "
  72.         "end";
  73.     lua_State *L = luaL_newstate();
  74.     luaL_openlibs(L);
  75.     luaopen_Files(L);
  76.  
  77.     bool err = luaL_loadstring(L, szLua_code) || lua_pcall(L, 0, 0, 0);
  78.     if(err)
  79.     {
  80.         cerr << lua_tostring(L, -1);
  81.         lua_pop(L, 1);
  82.     }
  83.     lua_close(L);
  84.     return 0;
  85. }

    本例运行结果是显示出C盘根目录下所有的文件名。
    Lua官方建议把函数库写进动态链接库中(windows下.dll文件,linux下.so文件),这样就可以在Lua代码中使用loadlib函数动 态载入函数库
例如,我们把上面的例子改成动态链接库版本:
DLL代码,假定生成的文件名为fileslib.dll
  1. extern "C" {
  2. #include "lua.h"
  3. #include "lualib.h"
  4. #include "lauxlib.h"
  5. }
  6. #include 
  7.  
  8. BOOL APIENTRY DllMain( HMODULE hModule,
  9.                        DWORD  ul_reason_for_call,
  10.                        LPVOID lpReserved
  11.                      )
  12. {
  13.     return TRUE;
  14. }
  15.  
  16. //函数库示例,Windows下查找文件功能
  17. //输入:string路径名
  18. //输出:userdata存放Handle(如果没找到,则是nil), string文件名
  19. int findfirst( lua_State *L )
  20. {
  21.     WIN32_FIND_DATAA FindFileData;
  22.     HANDLE hFind = ::FindFirstFileA(luaL_checkstring(L,1), &FindFileData);
  23.    
  24.     if(INVALID_HANDLE_VALUE == hFind)
  25.         lua_pushnil(L);
  26.     else
  27.         lua_pushlightuserdata(L, hFind);
  28.  
  29.     lua_pushstring(L, FindFileData.cFileName);
  30.    
  31.     return 2;
  32. }
  33.  
  34. //输入:userdata:findfirst返回的Handle
  35. //输出:string:文件名,如果没找到,则返回nil
  36. int findnext( lua_State *L )
  37. {
  38.     WIN32_FIND_DATAA FindFileData;
  39.     if(::FindNextFileA(lua_touserdata(L,1),&FindFileData))
  40.         lua_pushstring(L, FindFileData.cFileName);
  41.     else
  42.         lua_pushnil(L);
  43.     return 1;
  44. }
  45.  
  46. //输入:userdata:findfirst返回的Handle
  47. //没有输出
  48. int findclose( lua_State *L )
  49. {
  50.     ::FindClose(lua_touserdata(L,1));
  51.     return 0;
  52. }
  53.  
  54. //注册函数库
  55. static const struct luaL_reg lrFiles [] = {
  56.     {"FindFirst", findfirst},
  57.     {"FindNext", findnext},
  58.     {"FindClose", findclose},
  59.     {NULL, NULL}    /* sentinel */
  60. };
  61. //导出,注意原型为typedef int (*lua_CFunction) (lua_State *L);
  62. extern "C"    __declspec(dllexportint luaopen_Files (lua_State *L) {
  63.     luaL_register(L, "Files", lrFiles);
  64.     return 1;
  65. }
Lua调用代码(或者直接使用Lua.exe调用,dll文件必须处于package.cpath指定的目录中,默认与执行文件在同一目录即可):
  1. extern "C" {
  2. #include "lua.h"
  3. #include "lualib.h"
  4. #include "lauxlib.h"
  5. }
  6.  
  7. #include 
  8. #include 
  9. #include 
  10. using namespace std;
  11.  
  12. int main()
  13. {
  14.     char* szLua_code=
  15.         "fileslib = package.loadlib('fileslib.dll', 'luaopen_Files') "
  16.         "fileslib() "
  17.         "hFind,sFile = Files.FindFirst('c:\\\\*.*'); "
  18.         "if hFind then "
  19.         "    repeat "
  20.         "        print(sFile) "
  21.         "        sFile = Files.FindNext(hFind) "
  22.         "    until sFile==nil; "
  23.         "    Files.FindClose(hFind) "
  24.         "end";
  25.     lua_State *L = luaL_newstate();
  26.     luaL_openlibs(L);
  27.  
  28.     bool err = luaL_loadstring(L, szLua_code) || lua_pcall(L, 0, 0, 0);
  29.     if(err)
  30.     {
  31.         cerr << lua_tostring(L, -1);
  32.         lua_pop(L, 1);
  33.     }
  34.     lua_close(L);
  35.     return 0;
  36. }

Lua代码里使用package.loadlib得到动态链接库中的luaopen_Files函数,然后调用它注册到Lua中,如果动态链接库中的导出 函数名称满足luaopen_<库名>的话,还可以使用require直接载入。
比如,如果把本例中的DLL代码里的导出函数名luaopen_Files改成luaopen_fileslib的话,Lua代码便可以改成:
  1. char* szLua_code=
  2.         "require('fileslib') "
  3.         "hFind,sFile = Files.FindFirst('c:\\\\*.*'); "
  4.         ...
阅读(4845) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~