Lua Proxy Dll Two

lua-users home
wiki

下面介绍的工具 mkproxy.lua 旨在构建一个代理 DLL,该 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 时,您可以清楚地看到这些入口点被标记为 forwards/aliases。

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

-- JeromeVuarand

另请参阅


RecentChanges · preferences
编辑 · 历史
最后编辑于 2008 年 9 月 5 日上午 6:26 GMT (diff)