热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

在lua中调用DLL

整整的花了一个下午的时候,才在lua中调用了动态链接库。比起其他脚本语言,lua的调用方式算是比较繁琐的,但是lua的编程思想非常的统一&

整整的花了一个下午的时候,才在lua中调用了动态链接库。比起其他脚本语言,lua的调用方式算是比较繁琐的,但是lua的编程思想非常的统一,即lua和C之间的传值都是通过栈进行的,目前为止我还没有深入的去了解这个“栈”,但是这并不妨碍去使用”栈“。

当我们在一个空的工程中写下几个C/C++的函数,然后把属性类型设置为“动态链接库”以后,编译虽然成功了,DLL也产生了,但是我们得到的DLL是一个没有价值的数据文件,它缺少export函数(通过dumpbin /exports xxx.dll 观察),我们的lua也无法使用它。为了把我们写好的函数export出去,必须在函数名前,返回类型之后加上__declspec(dllexport),比如:

int add(int a, int b)
{
    return a + b;
}
 
//要修改为--->>>
int __declspec(dllexport) add(int a , int b)
{
    return a + b;
}

这是你就可以用dumpbin看到我们的add了。不对??是的,也行你看到的不是add,而是@ILT#$%^add(@$%) (我随便写个大概),那么你的工程一定是C++工程。这样的DLL只能通过引导库(lib)来实现,LUA用不了。为了能建立lua可以使用的库,必须在导出函数的最前面加上extern "C" (不能是__stdcall),所以此时的函数变成了:
extern "C" int __declspec(dllexport) add(int a , int b)
{
    return a + b;
}
还有一种常用的方法也可以得到extern的效果,那就是建立def文件,例如:
LIBRARY  mylib  
DESCRIPTION "Just for test"  
VERSION 1.0
EXPORTS  
    add
有了def,你就不需要再每个函数前加上extern “C”了。记得要在属性/连接器/输入/模块定义文件中输入def的文件名称。我们这个动态链接库以及lua.exe必须动态的连接lua.dll (lua5.2.dll),而不能静态的链接,否则你会得到错误:

stack traceback :
      [C]:?
      [C]:in function 'require'
      test.lua:1:in main chunk
      [C]:?
有了上面的知识铺垫,我们可以进入下一个环节了——让lua调用DLL。下面代码可以生成一个DLL。

#include
 
extern "C"{
#include
#include
#include
#include
#include
#include
#include
}
 
static int mysin (lua_State *L) 
{
    double d = luaL_checknumber(L, 1);
    lua_pushnumber(L, sin(d));
    return 1;
}
 
static int l_printf(lua_State *L)
{
    const char * pPattern = luaL_checkstring(L, 1);
    const char * str = luaL_checkstring(L, 2);
    lua_pushnumber(L, printf(pPattern, str));
    return 1;
}
 
static int l_MessageBox(lua_State *L)
{
    const char * sTitle = luaL_checkstring(L, 1);
    const char * sText = luaL_optstring(L, 2, "");
    MessageBox(NULL, sTitle, sText, 0);
    return 1;
}
 
static const struct luaL_Reg mylib[] = 
{
    {"mysin", mysin},
    {"printf", l_printf},
    {"messagebox", l_MessageBox},
    {NULL, NULL}
};
 
extern "C" int __declspec(dllexport) luaopen_mylib(lua_State *L)
{
    luaL_newlib(L, mylib);
    return 1;
}
上面的代码中,最后export出去的函数是luaopen_mylib,一定要注意:函数名luaopen_mylib表明了最后输出的dll名称必须为mylib.dll,而且大小写要一致,否则lua无论如何都找不到luaopen_mylib函数的。我们可以在lua脚本中这样使用。

mylib = require("mylib")
mylib.printf("Say: %s\n", "hello world")
msgbox = mylib.messagebox

msgbox("hello from luaopen_mylib")
另外,我要介绍一下另一种老方法。在DLL代码中添加:

extern "C" int  __declspec(dllexport) MyMessageBox(lua_State *L)
{
    const char * sText = luaL_checkstring(L, 1);
    const char * sTitle = luaL_checkstring(L, 2);
    return MessageBox(NULL, sText, sTitle, 0);;
}
你猜对了,我们要export另一个函数,然后我们可以在lua中这样用到:
pf = package.loadlib("mylib.dll","MyMessageBox")

print(pf)
pf("hello", "again")

这两种方法的效果是一致的,但是第一种方式是最新的,后面一种似乎有点out of date了。
————————————————
版权声明:本文为CSDN博主「语言观止」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/snlscript/article/details/16340653


推荐阅读
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 本文介绍了C函数ispunct()的用法及示例代码。ispunct()函数用于检查传递的字符是否是标点符号,如果是标点符号则返回非零值,否则返回零。示例代码演示了如何使用ispunct()函数来判断字符是否为标点符号。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
author-avatar
夏目nyako酱丶
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有