如何在运行lua程序时替换.dll

如何在运行lua程序时替换.dll,dll,lua,Dll,Lua,Lua可以通过使用require或通过package.loadlib动态加载.dll。但是,没有卸载模块的功能 我希望能够在运行程序时更新模块。程序本身将收到关于.dll新版本的通知。然后它将加载新的模块表,更改模块表并卸载前一个模块表 我通过使用带有unrequire函数的一些奇怪的代码片段,并强制对代码进行垃圾收集,成功地做到了这一点。我希望能以一种更文明的方式做这件事。我知道在windows和linux上有函数dlclose和freebrary。但是,我无法给他们打电话,因为我无法访问库的

Lua可以通过使用
require
或通过
package.loadlib
动态加载.dll。但是,没有卸载模块的功能

我希望能够在运行程序时更新模块。程序本身将收到关于.dll新版本的通知。然后它将加载新的模块表,更改模块表并卸载前一个模块表

我通过使用带有
unrequire
函数的一些奇怪的代码片段,并强制对代码进行垃圾收集,成功地做到了这一点。我希望能以一种更文明的方式做这件事。我知道在windows和linux上有函数
dlclose
freebrary
。但是,我无法给他们打电话,因为我无法访问库的实际句柄


缺少unload函数是因为lua解释器无法真正知道是否不再使用模块中的C函数。在我的情况下,情况并非如此,因为我只想更新库,而不是完全删除它。

有一种方法可以做到这一点,但要让它工作起来会有一些限制

基本思想是在Lua函数和
需要的脚本之间创建一个间接层,并使用模块,以及您试图在幕后更改的实际C函数。这最好在模块本身中完成。也就是说,与其让Lua代码替换函数,不如让C函数自己替换

这样,你就能控制局面了

这个想法很简单。您有两个模块:一个是Lua注册函数的存根模块,另一个是带有函数实现的实际模块。只有后一个模块发生更改

存根模块是一个Lua模块,它有两个向Lua注册的函数。第一个是存根函数,它多次注册。它被注册为具有单个upvalue的闭包

这个upvalue是一个C函数。这个存根函数所做的唯一一件事就是从Lua状态中提取一个upvalue,并使用给定的参数调用它,精确地返回被调用函数返回的值。它需要一些堆栈精处理才能正确通过,但我假设您知道如何处理它。此外,此函数还应检查upvalue的值;如果其
nil
,则不执行任何操作,也不返回任何内容(这可以防止出现错误)

第二个函数是我们稍后要讨论的

存根模块初始化例程将加载实际模块,这实际上只是一个DLL。此DLL需要有一个函数,该函数将提供实际模块导出的函数列表。因此,它可以查询要转发的各种Lua函数

对于从实际模块导出的每个函数,它向Lua注册存根函数,并为其命名。存根的upvalue被设置为导出函数,不加载upvalue

显然,需要保留DLL的句柄,可能是注册表项中的userdata之类的

存根模块导出的第二个函数将重新加载实际模块。为此,请加载新的DLL(而不是先卸载旧的DLL)。为了使这个过程健壮(尽管你保证函数列表是相同的。我不喜欢假设这样的事情),你需要迭代你的模块表

对于不在新DLL中的每个已注册函数,将其upvalue设置为
nil
(并将其从模块表中删除)。对于新DLL中的每个注册函数,将upvalue更改为新函数。如果新DLL中有未注册的函数,请通过使用新的upvalue注册存根函数,将它们保留在表中

完成所有这些之后,您就可以卸载旧的DLL了

在那里;完成了


注意:为了使其工作,您的模块函数必须表现良好。他们不能做注册其他C函数之类的事情。他们不能使用Lua5.2的机制来允许和恢复跨C边界的协同路由。等等否则,您将面临调用已卸载DLL的风险。

回答得很好,非常感谢!最后的警告不应该是问题所在;C模块将仅在lua模块太慢时使用。然而,我注意到了非常有趣的可能性。您认为可以像LuaJIT的FFI一样,使用存根模块加载任意的.dll/.so+.h吗?我想您应该用解析的.h文件替换添加的“GetFunctionList”;除此之外,过程是相同的。请告诉我您对此有何看法。@Bartek:“您认为您可以像LuaJIT的FFI一样,使用存根模块加载任意的.dll/.so+.h吗?”没有。因为任意的dll不公开Lua函数。记住:您不是从存根调用C函数;您正在调用Lua函数,这些函数恰好是用C编写的。它们有一个特定的签名(
int(Lua_State*)
);大多数DLL不公开具有该签名的函数。FFI是关于自动创建函数,将Lua参数和参数转换为C参数和参数。嗯,这是一个很好的观点。如果我使用库中的函数静态地准备链接(类型为
(int(lua_State*))
)的存根函数),我应该能够做到,对吗?我想我可以很容易地从.h生成C文件。然后我需要编译这个文件。我将以3.dll结尾-主lua dll,lua dll和原始库之间的链接,以及原始库本身。@Bartek:是的,但你只是在重写FFI。可能也不一样,因为LuaJIT的FFI可能生成汇编,而您的FFI完全是静态的。您当然是对的。我在问1。古董