在做游戏的时候,经常会要使用dll来封装库给lua来使用。本文将用于说明如何来通过lua来加载dll。
在loadlib.c文件中的127lines
static void *ll_load (lua_State *L, const char *path) {
HINSTANCE lib = LoadLibraryA(path);
if (lib == NULL) pusherror(L);
return lib;
}
static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) {
lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym);
if (f == NULL) pusherror(L);
return f;
}
当加载dll文件的时候,分为两步来走:
首先通过预定的package.cpath搜索目录来查找dll文件是否存在。
这里是一个指定加载目录的实例
package.cpath = package.cpath .. ';c:/my_lua_dll_lib/?dll;'
通过GetProcAddress到你的dll文件中查找入口函数。这个函数名是一个固定的:
loadlib.c文件中能读到这个代码:
/* prefix for open functions in C libraries */
#define LUA_POF "luaopen_"
#define POF LUA_POF
static int loader_C (lua_State *L) {
const char *funcname;
const char *name = luaL_checkstring(L, 1);
const char *filename = findfile(L, name, "cpath");
if (filename == NULL) return 1; /* library not found in this path */
funcname = mkfuncname(L, name);
if (ll_loadfunc(L, filename, funcname) != 0)
loaderror(L, filename);
return 1; /* library loaded successfully */
}
static const char *mkfuncname (lua_State *L, const char *modname) {
const char *funcname;
const char *mark = strchr(modname, *LUA_IGMARK);
if (mark) modname = mark + 1;
funcname = luaL_gsub(L, modname, ".", LUA_OFSEP);
funcname = lua_pushfstring(L, POF"%s", funcname);
lua_remove(L, -2); /* remove 'gsub' result */
return funcname;
}
输入的参数只有”your_dll_name”,在mkfuncname函数将会拼接函数。
lua是一个默认为c语言的引擎,在使用vs来编写dll的时候,默认创建源文件的时候将会为cpp文件。所以这个里面写的function的时候,默认是使用的c++的语法。当被导出的时候我们可以通过depends工具来分析dll中的function:
如果代码是C和C++混编的时候,注意这个点。如果函数是在cpp中编写的那就需要在函数开始的地方加上:
extern "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虚拟机,我们往栈里放入了多少个返回值 */
}
// test_load_dll.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
#include
#include
#include
#define WIN32_LEAN_AND_MEAN
#include
typedef int(*lua_CFunction) (lua_State *L);
int main(int argn, char *argv[])
{
if (argn != 2)
{
return -100;
}
std::string dll = argv[1];
std::stringstream ss;
ss << "xxxxxxxxxxxxxxxxxxxxx" << dll << ".dll";
std::string dll_name = ss.str();
HINSTANCE lib = ::LoadLibraryA(dll_name.c_str());
if (lib == NULL) {
std::cerr << "LoadLibraryA failed, errorcode: " << ::GetLastError() << std::endl;
return -1;
}
ss.str("");
ss << "luaopen_" << dll;
std::string sym = ss.str();
lua_CFunction f = (lua_CFunction)::GetProcAddress((HINSTANCE)lib, sym.c_str());
if (f == NULL)
{
std::cerr << "GetProcAddress failed: " << ::GetLastError() << std::endl;
}
return 0;
}