在C++函数中多次使用lua_call。

首先,我很抱歉我的英语。

我的问题是关于如何在 C++ 函数中多次使用 lua_call。我有一个使用 Lua 作为主要语言的程序,但它接受 C++ 插件以添加功能。我想从 C++ 中调用一个 LUA 函数,并在 LUA 运行时中调用该 C++ 函数。 我想编写一个带有进度的 C++ 函数,同时将此进度传递给负责向用户显示进度的 LUA 函数。

现在我在 LUA 中有一个测试函数:

function ShowText(text)
    Dialog.Message("Hi", text);
    return true;
end

还有一个 C++ 函数:

static int Test(lua_State *L){
    lua_pushstring(L, "Hi There");
    lua_call(L, 1, 1);

    lua_pushstring(L, "Again");
    lua_call(L, 1, 1);

    return 0;
}

然后我使用以下方式从 LUA 中调用此函数:

Test.Test(ShowText);

第一个 lua_call 没问题,但然后 LUA 堆栈被清除了,函数消失了,第二个 lua_call 尝试使用第一个调用的返回布尔值而不是函数。

我想要这样的东西:

static int Test(lua_State *L){
    int total = 10;

    for (int j; j < total; j++){
        lua_pushnumber(L, j);
        lua_pushnumber(L, j);
        lua_call(L, 2, 1);
        bool continue = IRLUA_PLUGIN_CheckBoolean(L, -1);
        lua_pop(L, 1); //删除最后一个布尔值

        if (continue == false){
            break;
        }
    }

    return 0;
}

在 LUA 中:

function ShowProgress(actual, final)
    local percent = (actual/final)*100;

    Dialog.Message("Working", "I'm in "..actual.." from "..final.." ("..percent.."%)");

    return true;
end

注:

Dialog.Message 是我用来显示消息的程序函数。它类似于 c++ 中的 **MessageBox(NULL, Text, Title, MB_OK);**。

IRLUA_PLUGIN_CheckBoolean 是插件 SDK 的一个函数,它检查参数是否为布尔值并返回其值,或者如果不是,则返回错误。

我可以使用 lua_getfield(L, LUA_GLOBALSINDEX , "FunctionName"); 完成,但不是我想要的。

有人知道如何做到吗?

点赞
用户204011
用户204011

你已经很好地理解了问题。这里是如何解决它的。

在你的第一个例子中,lua_call 会从堆栈中弹出函数,所以你需要先复制它。此外,函数返回的布尔值是无用的,所以你需要将其弹出或者将最后一个参数设为0而不要求 lua_call 返回:

static int Test(lua_State *L) {

    lua_pushvalue(L, 1); /* 复制函数 */

    lua_pushstring(L, "Hi There");
    lua_call(L, 1, 0);

    lua_pushstring(L, "Again");
    lua_call(L, 1, 0);

    return 0;
}

现在应用到你的第二个例子中:

static int Test(lua_State *L) {
    int total = 10;

    for (int j = 0; j<total; j++) {
        lua_pushvalue(L, 1); /* 复制函数 */
        lua_pushnumber(L, j);
        lua_pushnumber(L, total);
        lua_call(L, 2, 1);
        bool keep_going = IRLUA_PLUGIN_CheckBoolean(L, -1);
        lua_pop(L, 1); /* 弹出布尔值 */

        if (keep_going == false) {
            break;
        }
    }

    return 0;
}

(我还修复了你代码中的一些问题:传递的第二个数字可能应该是 total 而不是 j,你不应该将 continue 作为变量名...)

2014-05-17 13:32:34