热门标签 | 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


推荐阅读
  • 本文详细介绍了一种通过MySQL弱口令漏洞在Windows操作系统上获取SYSTEM权限的方法。该方法涉及使用自定义UDF DLL文件来执行任意命令,从而实现对远程服务器的完全控制。 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • 深入解析Spring启动过程
    本文详细介绍了Spring框架的启动流程,帮助开发者理解其内部机制。通过具体示例和代码片段,解释了Bean定义、工厂类、读取器以及条件评估等关键概念,使读者能够更全面地掌握Spring的初始化过程。 ... [详细]
  • 在尝试使用C# Windows Forms客户端通过SignalR连接到ASP.NET服务器时,遇到了内部服务器错误(500)。本文将详细探讨问题的原因及解决方案。 ... [详细]
  • 本文介绍了如何在React和React Native项目中使用JavaScript进行日期格式化,提供了获取近7天、近半年及近一年日期的具体实现方法。 ... [详细]
  • 本文将指导如何向ReactJS计算器应用添加必要的功能,使其能够响应用户操作并正确计算数学表达式。 ... [详细]
  • 本文详细介绍了如何在现有的Android Studio项目中集成JNI(Java Native Interface),包括下载必要的NDK和构建工具,配置CMakeLists.txt文件,以及编写和调用JNI函数的具体步骤。 ... [详细]
  • 探讨HTML中的DIV样式难题
    本文深入分析了HTML中常见的DIV样式问题,并提供了有效的解决策略。适合所有对Web前端开发感兴趣的读者。 ... [详细]
  • Vue 3.0 翻牌数字组件使用指南
    本文详细介绍了如何在 Vue 3.0 中使用翻牌数字组件,包括其基本设置和高级配置,旨在帮助开发者快速掌握并应用这一动态视觉效果。 ... [详细]
  • Linux环境下C语言实现定时向文件写入当前时间
    本文介绍如何在Linux系统中使用C语言编程,实现在每秒钟向指定文件中写入当前时间戳。通过此示例,读者可以了解基本的文件操作、时间处理以及循环控制。 ... [详细]
  • 本文探讨了为何相同的HTTP请求在两台不同操作系统(Windows与Ubuntu)的机器上会分别返回200 OK和429 Too Many Requests的状态码。我们将分析代码、环境差异及可能的影响因素。 ... [详细]
  • Symfony是一个功能强大的PHP框架,以其依赖注入(DI)特性著称。许多流行的PHP框架如Drupal和Laravel的核心组件都基于Symfony构建。本文将详细介绍Symfony的安装方法及其基本使用。 ... [详细]
  • CentOS 7.6环境下Prometheus与Grafana的集成部署指南
    本文旨在提供一套详细的步骤,指导读者如何在CentOS 7.6操作系统上成功安装和配置Prometheus 2.17.1及Grafana 6.7.2-1,实现高效的数据监控与可视化。 ... [详细]
  • Shell脚本中变量操作详解
    本文基于《鸟哥的Linux私房菜》一书,详细介绍了Shell脚本中变量的使用方法,包括变量的赋值规则、字符串处理技巧以及环境变量的管理等,旨在帮助读者更好地理解和使用Shell中的变量。 ... [详细]
  • 本文介绍了在MacOS上通过Homebrew安装Anaconda3,并配置环境变量以实现不同Python版本之间的快速切换。同时,提供了详细的步骤来创建和管理多个Python环境。 ... [详细]
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社区 版权所有