2010-08-26 92 views
9

我有一個使用Lua鏈接爲dll(非靜態)的小應用程序。我想加載我自己的C++ - 通過Lua使用package.loadlib (libname, funcname)編寫的dll。爲此,我需要導出一個遵循Lua的lua_CFunction協議的函數。很顯然,爲此我必須將lua.h合併到我的項目中,並使用Lua的函數來傳遞參數和結果。所以我的問題是:創建一個可由Lua加載的C++ DLL

  1. 我的DLL會使用已加載到小應用程序的過程中的Lua dll嗎?
  2. 是否package.loadlib立即加載和卸載我的DLL或我的DLL加載一直保持,直到結束lua scrpit執行或應用程序終止?

回答

8

與您的具體問題開始:

  1. 是的,但只有當你的DLL被隱式鏈接到它。注意這一點,因爲如果你不小心將Lua VM的兩個副本鏈接到你的應用程序中,這可能會導致很大的混淆。就此而言,類似的問題也適用於C運行時。我將在Dependency Walker下加載整個應用程序,以驗證它只涉及Lua DLL的一個實例和一個C運行時。

  2. 我的理解是,package.loadlib()只負責加載和鏈接到指定庫中的指定函數。只要返回的函數對象(表示您指定的lua_CFunction)處於活動狀態,那麼DLL肯定會加載。如果你放棄了對函數的最後一個引用,那麼該庫可用於垃圾收集,如果收集它將被卸載。在Lua-L郵件列表上,有關於如何確保特定DLL被卸載的討論,如果這是您的擔憂。否則,如果你只是假設DLL被加載,只要你可以到達存儲在其中的函數,你就會沒事的。

讓我補充一點,構建在這個之上的模塊系統是一種更好的方式來將Lua用C或C++代碼進行擴展。 Chapter 26 of Programming in Lua更詳細地描述了這一點,並鏈接到第一版聯機副本中的那一章(它描述了Lua 5.0)。請注意,在Lua 5.1中,模塊系統確實發生了一些變化,而在Lua 5.2中也是如此。獲得PiL第二版或第三版(可通過書商提供的紙質和電子書形式)副本可能會有所幫助。

下面是一個執行摘要:要在C中創建一個名爲foo的模塊,您可以創建foo.dll,該函數至少用原型int luaopen_foo(lua_State *L)導出函數。該函數應該加載你的模塊(通常在Lua 5.1中使用luaL_register(),或者在Lua 5.2中使用luaL_newlib()luaL_setfuncs()來註冊一個充滿C函數的表)並返回該表。在Lua方面,您將DLL放在package.cpath中描述的路徑的某處,然後可以通過代碼如local foo = require "foo"加載它。各種Lua 5.x版本之間還有其他細微的差別,但創建可以爲其中任何一個編譯的C代碼相對簡單。

這樣做的好處是,模塊可以從路徑加載,可以用C語言或Lua語言編寫,也可以混合使用,並且可以與其他模塊一起使用。您還可以通過一次調用require來加載所需或多或少的C函數。

+0

非常感謝您的回答。這對我幫助很大!除了Lua功能之外,我希望我的DLL能夠掛接到應用程序的WndProc並添加我的自定義工具欄,因此我不希望我的DLL在我沒有意識到的情況下卸載。 – 2010-08-27 08:40:33

+1

您可以通過保留自己的額外引用來獲得對其生命週期的一些明確控制,只有在您準備好時纔會釋放它。你可以在'LUA_REGISTRYINDEX'處使用'luaL_ref()'來引用C端可以保存的任何對象(以整數形式),並用'luaL_unref()'釋放。 – RBerteig 2010-08-27 17:23:06

+0

對於任何人只是發現這個問題,作爲Lua 5.2,'luaL_register'已被棄用;應該使用'luaL_newlib',因爲動態加載的模塊不應該在全局環境中註冊任何東西。 – bcrist 2014-02-06 03:49:07

-1

您可以動態鏈接到與您的應用程序相同的Lua dll。

至於package.loadlib,我不知道它是如何工作的。閱讀來源?