2015-05-05 127 views
2

我正在爲我們的應用程序編寫一個lua(5.1)擴展程序,允許我們的客戶在沒有我們的支持的情況下將其擴展到更多屏幕。如何從另一個lua函數調用lua函數?

一般來說,這工作得很好,有包裝的一打的幫助,甚至很舒服,但現在我有以下情況:

我有兩個用戶的數據對象,對象定時器和對象的窗口。 用戶可以通過簡單定義成員OnTimer和OnSizeChanged來「附加」事件。

這仍然工作得很好: mainLoop(C++) - >檢查所有計時器(C++) - >腳本對象附加? (C++),則:

// get ud by reference/stack: +1/1 
lua_rawgeti(mState, LUA_REGISTRYINDEX, miReferenceId); 
lua_getfenv(mState, -1); // get attached table/+1/2 total 
lua_getfield(mState, -1, functionName.ToChar()); // +1/3 total 
if (!lua_isfunction(mState, -1)) 
{ 
... 
} 
lua_remove(mState, -2); // remove table/-1/2 total 
lua_remove(mState, -2); // remove ud/-1/1 total, just function remaining 
// (.. user data still pushed at this point ..) 
lua_pcall(mState, 1, 0, 0); 

因此,在以下情況下一切仍是完全正常的(堆棧絕對0發起呼叫之前和之後):

function OnTimer(Self) 
Log("Some text") // Log calls C++ luaLog with 1 argument 
end 

myTimer = timer.new() 
myTimer.OnTimer=OnTimer; 

如果LUA腳本是這樣的,雖然:

timer = timer.new() 
window = window.new() 

function OnTimer(Self) 
    window:SetSize(323.5,234.5) 
end 

function OnSizeChanged(Self,NewWidth,NewHeight) 
Log("Sized changed") 
end 

timer.OnTimer = OnTimer 
window.OnSizeChanged = OnSizeChanged 

然後,在C++調用堆棧將是:

timer::HandleTimer (C++) -> 
push "OnTimer" function -> 
push timer ud -> 
pcall (L,1) -> .. (Lua) 
static int luaChangeSize(lua_State *L) (back to C++) -> 
Window::SetSize -> 
The window sees "oooooooh, an event handler has been assigned" -> 
push "OnSizeChanged" function, window ud, x, y -> 
pcall(L,3,0,0) -> .. (Lua) -> 
int luaLog(lua_state* L) (back to C++ again) 

當然,在OnSizeChanged被調用的地方,堆棧仍然包含前一個luaChangeSize回調的內容,並且不是空的。

我想我可以通過在調用Window :: SetSize之前彈出luaChangeSize的所有參數並在之後恢復它們來簡化清理堆棧,但這不起作用。結果是有點隨機的,取決於調用堆棧的星座,從「無法調用數字」到隨機地再次調用堆棧上的前一個函數。 (gettop在所有調用之前和之後肯定是0)。

所以:我怎樣才能「備份」當前堆棧並在之後恢復它,因爲lua在C++ - > Lua - > C++星座中完成它本身?

非常感謝。

回答

2

備份和恢復堆棧的概念似乎是錯誤的。難道你不能離開堆棧嗎?讓新的調用在現有的堆棧上工作。確保所有內容都使用相對於頂部索引而不是絕對索引訪問堆棧上的項目。

+0

感謝您的快速響應,是的,我還考慮過這個備用解決方案,並且可以通過將某種StackOffset變量附加到我們自己的腳本實例對象上,然後可以使用它獲得「真實「參數計數像argumentCount = StackOffset-lua_gettop(L)。 問題是,我們所寫的所有擴展(例如luasocket)仍然依賴gettop來驗證參數計數,但它不起作用。 只是好奇,如果有一個「乾淨」的方式,讓一個遞歸的c調用行爲,就像它已經從一個lua腳本調用。 – Alyxion