Lua 代理 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。在代理配置中,您也有 (app.exe + lua5.1.dll + extension.dll),但这里 lua5.1.dll 小于 10K,app.exe 不依赖于 lua5.1.dll,除非需要使用 extension.dll。如果您不使用扩展,那么 app.exe 将能够独立运行。此外,Lua 的任何补丁或变体构建通常都应用于 app.exe,而 lua5.1.dll 保持不变。实际上,您可以拥有 app1.exe 使用一个变体构建的 Lua(例如,链接到 VC6 CRT),而 app2.exe 使用另一个变体构建(例如,链接到 VC8 CRT),它们都通过同一个 lua5.1.dll 文件进行代理(这是可能的,因为 lua5.1.dll 不链接到 CRT,并且每个进程都加载 DLL 的一个单独的内存实例)。也许其他人有改进的想法——上述方法中有一些技巧。--DavidManura

您也可以使用此技巧(我在下面使用了版本 3)来创建一个看起来正常的 lua5.1.dll,它代理到一个经过调整的分布,例如 LuaPlus_1100.dll。再次是为了让 LuaBinaries dll 工作。--ferrix

另请参阅

您对使这些页面名称更具描述性有什么想法吗?


最近更改 · 偏好设置
编辑 · 历史
最后编辑于 2008 年 9 月 6 日下午 3:56 GMT (差异)