Lua 代理 DLL 二

lua-users home
wiki

下面介绍的实用程序 **mkproxy.lua** 用于构建一个代理 DLL,它将函数调用重定向到包含相同名称函数的“主机”库文件。主机库文件可以是 DLL 或 EXE,只要它包含所有必需的导出函数即可。

该实用程序可以为任何类型的主机构建代理 DLL,它不受 Lua 相关主机的限制。

该实用程序假设(并需要)MinGW 开发系统。

该实用程序包含一个“公共”函数:CreateProxyDll。该函数接受一个参数,一个表,该表必须指定以下字段

PROXY   : (path)name of the proxy DLL to build
HOST    : (path)name of the host library file (file must exist)
DEFFILE : (path)name of the definition file (file must exist)

示例 1:允许将与 lua5.1.dll 和 lua51.dll 中的任何一个链接的应用程序或库组合使用

CreateProxyDll {
  PROXY   = "lua51.dll",
  HOST    = "c:\\exe\\lua5.1.dll",
  DEFFILE = "liblua5.1.def",
}

示例 2:使静态构建的 Lua 解释器能够安全地require()外部库

CreateProxyDll {
  PROXY   = "lua5.1.dll",
  HOST    = "c:\\exe\\lua51x.exe",
  DEFFILE = "liblua5.1.def",
}

mkproxy.lua

-- Name:       mkproxy.lua
-- Goal:       Create a proxy DLL that redirects all calls to the "host" library
-- Written by: Shmuel Zeigerman
-- License:    public domain

local CFile = [[
#include <windows.h>
BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD Reason, LPVOID Reserved) {
  return TRUE;
}
]]

local function execute(s) assert(0 == os.execute(s)) end

local function CreateObjectFile (objname)
  assert(objname:match("%.o$"))
  local cname = objname:gsub("%.o$", ".c")
  local fp = assert(io.open(cname, "w"))
  fp:write (CFile)
  fp:close()
  execute("gcc -c " .. cname .. " -o " .. objname)
  os.remove(cname)
end

function CreateProxyDll (config)
  assert(type(config) == "table", "argument #1: a table expected")
  assert(config.PROXY,   "config.PROXY not specified")
  assert(config.HOST,    "config.HOST not specified")
  assert(config.DEFFILE, "config.DEFFILE not specified")
  assert(io.open(config.HOST)):close()
  assert(io.open(config.DEFFILE)):close()
  -----------------------------------------------------------------------------
  local hostpath, hostname = config.HOST:match ("^(.+)[\\/](.+)$")
  if not hostpath then hostpath, hostname = ".", config.HOST end
  local temp_dll = (hostname:sub(-4):lower() ~= ".dll") and "temp_dll.dll"
  local temp_obj = "temp_obj.o"
  CreateObjectFile(temp_obj)
  local cmdline = table.concat ({
    "gcc -shared -s -nostdlib",
    temp_obj,
    config.DEFFILE,
    "-L" .. (temp_dll and "." or hostpath),
    "-l" .. (temp_dll or hostname):sub(1,-5),
    "-o" .. config.PROXY,
  }, " ")
  if temp_dll then execute("copy " .. config.HOST .. " " .. temp_dll) end
  execute(cmdline)
  os.remove(temp_obj)
  if temp_dll then os.remove(temp_dll) end
end

-- ShmuelZeigerman

评论

--我一直想知道为什么LuaBinaries 将 lua51.dll 重命名为 lua5.1.dll,或者,如果这是更好的方法,为什么 Lua 本身不这样做。这只会让新用户和不熟悉规则的模块作者感到不必要地复杂。这不是一件好事(TM),因为我们遇到了上述问题。我看到LuaBinaries 现在也附带了这样的包装器。--DavidManura

这已经在邮件列表中讨论过:[1] --ShmuelZeigerman

以下构建适用于 MSVC2005。它使用“nodefaultlib”链接器选项。最终的代理 DLL 大约为 9 KB。

local DEFFILE  = "lua5.1.def" -- .def file for lua5.1.dll
local LIBFILE  = "lua5.1.lib" -- .lib file for lua5.1.dll
local CFILE   = "luaproxy.c"-- output file
local MAKFILE = "luaproxy.mak"  -- output file
----------------------------------------------------------------------
local cfile = assert(io.open(CFILE, "w"))
cfile:write [=[
#include <windows.h>
    BOOL APIENTRY
DllMain(HANDLE module, DWORD reason, LPVOID reserved)
    { return TRUE; }
]=]
cfile:close()
----------------------------------------------------------------------
local makfile = assert(io.open(MAKFILE, "w"))
makfile:write(string.format([=[
lua51.dll : luaproxy.c
	cl -I../lua/src /O2 /LD /GS- luaproxy.c /link /def:%s %s \
	   /out:lua51.dll /nodefaultlib /entry:DllMain
]=], DEFFILE, LIBFILE))
makfile:close()
----------------------------------------------------------------------

--DavidManura

似乎您正在做的是构建一个空的 C 文件,它链接到导入库中的存根,并将这些存根重新公开为 dll 接口。这意味着您生成的 DLL

1. 包含代码(DllMain?,以及导入库)
2. 为每个 API 调用添加一个函数调用开销
这没有必要。Windows DLL 格式中有一个机制,允许在 DLL 加载时让 DLL 加载器动态创建别名。当你在 depends.exe 中打开 DLL 时,你可以清楚地看到这些入口点被标记为转发/别名。

如果我误解了你的代码,请告诉我。

-- JeromeVuarand

另请参阅


最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2008 年 9 月 5 日下午 12:26 GMT (差异)