Lua Proxy Dll

lua-users home
wiki

這個實作了一個名為 lua5.1.dll 的 Win32 DLL,用於取代 LuaBinaries 的同名 DLL。它幾乎沒有自己的程式碼,而是直接把呼叫傳遞到連結到 EXE 的 Lua 核心副本。這讓你的 EXE 可以連結 Lua,但仍然可以使用動態連結到 lua5.1.dll 的 Lua 延伸模組。請參閱 luaproxydll.h 中的註解以取得更多詳細資訊。

-- expand.lua - Generates Lua proxy DLL source code.

local function map(f, t)
  local t = {unpack(t)}
  for k,v in ipairs(t) do t[k] = f(v) end
  return t
end
local function foreach(fmt, t)
  return table.concat(map(function(s) return string.format(fmt, s) end, t))
end

-- API functions defined in LuaBinaries - http://luabinaries.luaforge.net/
local apifuncs = {
  "lua_tolstring","lua_typename","lua_pushfstring","lua_pushvfstring",
  "lua_getlocal","lua_getupvalue","lua_setlocal","lua_setupvalue",
  "lua_topointer","lua_iscfunction","lua_isnumber","lua_isstring",
  "lua_isuserdata","lua_toboolean","lua_type","lua_equal",
  "lua_lessthan","lua_rawequal","lua_checkstack","lua_cpcall",
  "lua_error","lua_getmetatable","lua_gettop","lua_load",
  "lua_next","lua_pcall","lua_pushthread","lua_setfenv",
  "lua_setmetatable","lua_resume","lua_status","lua_yield",
  "lua_dump","lua_gc","lua_gethook","lua_gethookcount",
  "lua_gethookmask","lua_getinfo","lua_getstack","lua_sethook",
  "lua_getallocf","lua_tocfunction","lua_atpanic","lua_tointeger",
  "lua_tonumber","lua_tothread","lua_newstate","lua_newthread",
  "lua_objlen","lua_touserdata","lua_close","lua_call",
  "lua_concat","lua_createtable","lua_getfenv","lua_getfield",
  "lua_gettable","lua_insert","lua_pushboolean","lua_pushcclosure",
  "lua_pushinteger","lua_pushlightuserdata","lua_pushlstring",
  "lua_pushnil","lua_pushnumber","lua_pushstring","lua_pushvalue",
  "lua_rawget","lua_rawgeti","lua_rawset","lua_rawseti",
  "lua_remove","lua_replace","lua_setfield","lua_settable",
  "lua_settop","lua_xmove","lua_newuserdata","lua_setallocf",
  "luaL_prepbuffer","luaL_checklstring","luaL_findtable","luaL_gsub",
  "luaL_optlstring","luaL_newmetatable","luaL_argerror","luaL_callmeta",
  "luaL_checkoption","luaL_error","luaL_getmetafield","luaL_loadbuffer",
  "luaL_loadfile","luaL_loadstring","luaL_ref","luaL_typerror",
  "luaL_checkinteger","luaL_optinteger","luaL_checknumber",
  "luaL_optnumber","luaL_newstate","luaL_openlib","luaL_addlstring",
  "luaL_addstring","luaL_addvalue","luaL_buffinit","luaL_checkany",
  "luaL_checkstack","luaL_checktype","luaL_pushresult","luaL_register",
  "luaL_unref","luaL_where","luaL_checkudata","luaopen_base",
  "luaopen_debug","luaopen_io","luaopen_math","luaopen_os",
  "luaopen_package","luaopen_string","luaopen_table","luaL_openlibs",
  "luaU_dump","luaM_toobig","luaM_realloc_","luaS_newlstr",
  "luaD_growstack","luaF_newproto"
}


local luaproxydll_h = [[
/**
  luaproxydll.h - C header file for Lua proxy DLL (lua5.1.dll).
  (autogenerated from expand.lua)
 
  == Discussion ==

  Lua extension modules in Windows typically dynamically link
  against the lua5.1.dll defined in Lua Binaries
  (http://luabinaries.luaforge.net/).  This assumes
  your EXE also dynamically links against lua5.1.dll.
  If your EXE instead statically links against lua5.1.dll,
  then you have two copies of the Lua core, which is
  redundant and also can cause subtle problems.

  The proxy DLL defined here is a drop-in-replacement for
  the standard lua5.1.dll.  It acts as a thin proxy that
  exports the same interface as the standard lua5.1.dll and
  transparently forwards calls to the Lua core functions
  defined in the EXE.

  Before extension modules attempt to load and call the
  proxy DLL, the EXE must load the proxy DLL and call the
  additional proxy_init() function in the proxy DLL, passing
  it the addresses of the Lua core functions in the EXE.

  The resultant DLL should be small (less than 10K).
  The compilation can omit the C run-time.

  To use this in your EXE, include luaproxydll.h and then run


  LUAPROXYDLL_INIT().  You may need to remove the "LUAI_FUNC" before
  these functions in the Lua source:
  
    luaU_dump
    luaM_toobig
    luaM_realloc_
    luaS_newlstr
    luaD_growstack
    luaF_newproto

  Note: LUAPROXYDLL_IMPLEMENTATION is undefined in the EXE.
  
  Author: (c) David Manura, 2007-01-30
  Licensed under the same terms as Lua 5.1 itself.
*/

#ifndef LUAPROXYDLL_H
#define LUAPROXYDLL_H

#ifdef __cplusplus
extern "C" {
#endif

typedef const void * const luaproxydll_t;

/** Pointers to Lua core functions in the EXE.
    The EXE should prepare this and pass it to
    the luaproxydll_init function.
  */
struct luaproxydll_Funcs {
]] .. foreach([[
    luaproxydll_t %s;
]], apifuncs) .. [[
};
/* not passed: luaP_opmodes, luaP_opnames */


/* These are only used by the EXE */
#ifndef LUAPROXYDLL_IMPLEMENTATION

/* reference Lua core functions */
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
/* void luaU_dump();
   void luaM_toobig();
   void luaM_realloc_();
   void luaS_newlstr();
   void luaD_growstack();
   void luaF_newproto(); */
#include <lfunc.h>
#include <lundump.h>
#include <lstring.h>
#include <ldo.h>

/** Table of Lua core function pointers. */
const struct luaproxydll_Funcs luaproxydll_funcs = {
]] .. foreach([[
    %s,
]], apifuncs) .. [[
};
/* not passed: luaP_opmodes, luaP_opnames */


/** load proxy DLL. Call this in your EXE to load and initialize the proxy DLL. */
#define LUAPROXYDLL_INIT() \
{ \
    HMODULE hmodule = LoadLibrary("lua5.1.dll"); \
    if (hmodule) { \
        typedef void (*func_t)(const luaproxydll_Funcs *); \
        func_t initfunc = (func_t)GetProcAddress(hmodule, "luaproxydll_init"); \
        if (initfunc) { \
            initfunc(&luaproxydll_funcs); \
        } \
    } \
}

/* Register Lua core functions from the EXE into the proxy DLL.
   funcs must remain valid until the proxy DLL is
   unloaded or no longer used.
  */
void luaproxydll_init(struct luaproxydll_Funcs * funcs);

#endif /* not LUAPROXYDLL_IMPLEMENTATION */

#ifdef __cplusplus
}
#endif

#endif /* first include */
]]

local luaproxydll_c = [[
/***
  luaproxydll.c - C implementation file for the Lua proxy dll.
  (autogenerated from expand.lua)
  
  Author: (c) David Manura, 2007-01-30
  Licensed under the same terms as Lua 5.1 itself.
 ***/

#define LUAPROXYDLL_IMPLEMENTATION /* used by luaproxydll.h */

#include <windows.h>
#include "luaproxydll.h"

static struct luaproxydll_Funcs s_funcs;

/* Macro for defining a proxy function.
   This is a direct jump (single "jmp" assembly instruction"),
   preserving stack and return address.
   The following uses MSVC inline assembly which may not be
   portable with other compilers.
 */

#define PROXY(name) \
  void __declspec(naked) name() { __asm { jmp s_funcs.name } }

/* Define all the proxy functions specified in lua5.1.def. */
]] .. foreach([[
PROXY(%s)
]], apifuncs) .. [[
/* note: luaP_opmodes and luaP_opnames are defined in lopcodes.c */


    BOOL APIENTRY
DllMain(HANDLE module, DWORD reason, LPVOID reserved)
{
    /* DEBUG: MessageBox(NULL, "proxyload", "", MB_OK); */
    return TRUE;
}

    void
luaproxydll_init(struct luaproxydll_Funcs * funcs)
{
    int n;
    for (n=0; n < sizeof(struct luaproxydll_Funcs); n++) {
      ((unsigned char*)(void*)&s_funcs)[n] = 
        ((unsigned char*)(void*)funcs)[n];
    }
    /* nope: s_funcs = funcs; */
}
]]

local GNUmakefile = [[
# GNUmakefile - Makefile for luaproxydll.dll for MSVC compiler.
# (autogenerated from expand.lua)

all:
	cl /O2 /LD /GS- luaproxydll.c ../lua/src/lopcodes.c \
	    /link /def:lua5.1.def /out:lua5.1.dll /nodefaultlib /entry:DllMain

clean:
	rm -f *~ *.obj *.exp *.lib
purge: clean
	rm -f luaproxydll.[hc] lua5.1.def GNUmakefile lua5.1.dll
]]

local lua5_1_def = [[
; lua5.1.def
; (autogenerated from expand.lua)
VERSION 5.1
EXPORTS
]] .. foreach([[
  %s
]], apifuncs) .. [[
  luaP_opmodes
  luaP_opnames

  ; special
  luaproxydll_init
]]

for k,v in pairs{
  [luaproxydll_h] = "luaproxydll.h",
  [luaproxydll_c] = "luaproxydll.c",
  [lua5_1_def] = "lua5.1.def",
  [GNUmakefile] = "GNUmakefile"
} do
  io.output(v); io.write(k)
end

--DavidManura

David,上述組態對比於普遍的組態(lua.exe + lua5.1.dll)有哪些優點? --ShmuelZeigerman

部分看法在於封裝。在標準組態中,你有 (app.exe + lua5.1.dll + extension.dll),其中 app.exe 永遠依賴於 lua5.1.dll。在 Proxy 組態中,你也有 (app.exe + lua5.1.dll + extension.dll),但這裡的 lua5.1.dll 小於 10K,且 app.exe 僅在需要使用 extension.dll 時才會依賴於 lua5.1.dll。如果你不使用延伸模組,app.exe 本身就可以執行。此外,Lua 的所有修補程式或變體建置通常會套用至 app.exe,且 lua5.1.dll 保持不變。事實上,你可以讓 app1.exe 採用一種 Lua 變體建置(例如,連結 VC6 CRT),讓 app2.exe 採用另一種變體建置(例如,連結 VC8 CRT),兩者都能透過同一個 lua5.1.dll 檔案進行 Proxy(這是可能的,因為 lua5.1.dll 沒有連結到 CRT,且每個程序都會載入 DLL 的獨立記憶體實例)。也許其他人有想法可以改善,上述有些許技巧。--DavidManura

你也可以使用這個秘訣(我使用了以下第 3 個版本),建立一個正常的 lua5.1.dll,用於 Proxy 到 LuaPlus_1100.dll 等經過調整的發行版。目的是讓 LuaBinaries dll 發揮作用。--ferrix

另請參閱

有任何讓這些頁面名稱更為具說明性的想法嗎?


最近變更 · 喜好設定
編輯 · 歷史記錄
最後編輯時間為 2008 年 9 月 6 日下午 3:56 GMT (diff)