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 檔案,連結到匯入函式庫中的 stub,並將這些 stub 重新公開為 dll 介面。這表示你所產生的 DLL

1. 包含程式碼(DllMain,和匯入函式庫)
2. 在每個 API 呼叫中加入一個函式調用的額外負擔
這不是必需的。Windows DLL 格式中有一個機制,可以在 DLL 載入時讓 DLL 載入器動態建立別名。當你在 depends.exe 中開啟 DLL 時,你可以清楚地看到這些標示為轉發/別名的進入點。

告訴我是否誤解了你的程式碼。

-- JeromeVuarand

另請參閱


RecentChanges · preferences
edit · history
上次編輯時間為 2008 年 9 月 5 日下午 12:26 GMT (diff)