Здравствуйте.
Помогите, пожалуйста, разобраться. Очень странная ситуация.
При тестировании взаимодействия LUA-скрипта и DLL-библиотеки была обнаружена ошибка, когда из DLL-библиотеки в LUA-скрипт передается простой индексированный массив.
Тест был простой: из LUA-скрипта вызывается функция DDL-библиотеки, которая просто возвращает сформированный массив.
Код из DDL-библиотеки на C++:
Код LUA-скрипта:
Весь фокус заключается в том, что ошибка возникает не сразу (не при первом вызове функции из DLL-библиотеки), а после нескольких итераций. Кроме того, ошибка возникает именно в том случае, когда в полученном из DLL массиве все элементы имеют целочисленные индексы. Если же в полученном массиве есть хотя бы один элемент со строковым индексом, никакой ошибки не возникает.
При всем этом не понятно, где ошибка. Я, конечно, не исключаю, что это может быть ошибка в программном коде, который я привел. А если это не так, то в чем тогда дело? Может быть дело в "lua5.1.dll", которая поставляется вместе с торговым терминалом QUIK или в самом QUIK-е?
Самое обидное заключается в том, что эта ошибка проявилась, когда вся DLL-библиотека (для хранения и обмена данными между разными LUA-скриптами: простые типы, строки, любые вложенные массивы) была полностью написана и показала неплохие результаты с точки зрения производительности и потоко-безопасности.
Когда ошибка проявилась, для проведения теста и исключения возможной ошибки в коде DLL-библиотеки был создан самый простой проект в "Visual Studio 2015", а LUA-скрипт запускался из торгового термина QUIK без подключения к серверу.
Ссылка на архив с исходниками для тестирования:
DLL-библиотека компилировалась в "Visual Studio 2015".
LUA-скрипт запускался из торгового терминала QUIK.
Помогите, пожалуйста, разобраться. Очень странная ситуация.
При тестировании взаимодействия LUA-скрипта и DLL-библиотеки была обнаружена ошибка, когда из DLL-библиотеки в LUA-скрипт передается простой индексированный массив.
Тест был простой: из LUA-скрипта вызывается функция DDL-библиотеки, которая просто возвращает сформированный массив.
Код из DDL-библиотеки на C++:
| Код |
|---|
// luaTest.cpp: определяет экспортированные функции для приложения DLL.
#include "stdafx.h"
// ----------------------------------------------------------------------------
// Заголовок Lua
// ----------------------------------------------------------------------------
#ifndef LUA_LIB
// Необходимые для Lua константы
#define LUA_LIB
#define LUA_BUILD_AS_DLL
// Заголовочные файлы LUA из дистрибутива LUA
extern "C" {
#include "./lauxlib.h"
#include "./lua.h"
}
#endif
// -------------------------------------------
// Выбор режима формирования элементов массива
// -------------------------------------------
#define TEST_INDEX_INTEGER
//#define TEST_INDEX_STRING
//#define TEST_INDEX_INTEGER_STRING
// --------------------------------------------------
// Наша единственная функция.
// Формирует и возвращает LUA-скрипту простой массив.
// --------------------------------------------------
static int GetValue(lua_State *L)
{
lua_newtable(L);
for (int i = 1; i <= 15; i++)
{
char strIndex[20] = "";
sprintf_s(strIndex, 10, "%d", i);
// Добавим в стек ключ элемента
#ifdef TEST_INDEX_INTEGER_STRING
// Вот так работает идеально
if (i == 3)
{
// Добавим всего один элемент массива со строковым индексом
lua_pushstring(L, strIndex);
}
else
{
// Все остальные индексы числовые
lua_pushinteger(L, i);
}
#else
#ifdef TEST_INDEX_STRING
// Вот так работает идеально
lua_pushstring(L, strIndex);
#else
// Вот так возникает ошибка (когда все элементы массива имеют целочисленные индексы)
lua_pushinteger(L, i);
#endif
#endif
// Добавим в стек значение элемента
lua_pushinteger(L, i);
// Вставим в стек итератор
lua_settable(L, -3);
}
// Даем lua знать, какое количество значений возвращается нашей функцией
return (1);
}
// ----------------------------------------------------
// Структура "Регистрация реализованных в dll функций",
// что бы те стали доступны из lua.
// ----------------------------------------------------
static struct luaL_reg ls_lib[] =
{
{ "GetValue", GetValue },
{ NULL, NULL }
};
// ------------------------------------------------------------
// Эту функцию lua будет искать при подключении dll,
// ее название заканчиваться названием dll, luaopen_ИмяНашейDLL
// ------------------------------------------------------------
extern "C" LUALIB_API int luaopen_luaTest(lua_State *L)
{
luaL_openlib(L, "luaTest", ls_lib, 0);
return 0;
}
|
| Код |
|---|
-- Добавим в переменную окружения путь расположения нашего скрипта для подключения *.lua скриптов
package.path = package.path..";"..getScriptPath().."\\?.lua";
-- Добавим в переменную окружения путь расположения нашего скрипта для подключения *.dll библиотек
package.cpath = package.cpath..";"..getScriptPath().."\\?.dll";
-- Загружаем DLL
require('luaTest');
-- Признак работы скрипта
local IsRun = false;
-- Функция инициализации вызывается до запуска скрипта,
-- перед началом работы функции main()
function OnInit()
end
-- Функция вызывается, когда пользователь нажимает кнопку "Остановить" или закрывает терминал.
function OnStop(s)
IsRun = false;
end
function main()
IsRun = true;
while IsRun do
-- Вызываем функцию из DLL
local value = luaTest.GetValue();
-- Если в полученном массиве есть хотя-бы один элемент со строковым индексом,
-- то все работает идеально.
-- Если же в полученном массиве все элементы имеют целочисленные индексы,
-- то возникает следующее:
-- Если оставить указанный ниже код, то через 1-2 секунды QUIK падает
if (type(value) == 'table') then
end
-- Если этого кода нет, то все работает, но при остановке скрипта в QUIK
-- (в поле "Ошибки выполнения скрипта") появляется сообщение "LuaVM closed with error"
--if (type(value) == 'table') then
--end
-- пауза
sleep(10)
end
end
|
Весь фокус заключается в том, что ошибка возникает не сразу (не при первом вызове функции из DLL-библиотеки), а после нескольких итераций. Кроме того, ошибка возникает именно в том случае, когда в полученном из DLL массиве все элементы имеют целочисленные индексы. Если же в полученном массиве есть хотя бы один элемент со строковым индексом, никакой ошибки не возникает.
При всем этом не понятно, где ошибка. Я, конечно, не исключаю, что это может быть ошибка в программном коде, который я привел. А если это не так, то в чем тогда дело? Может быть дело в "lua5.1.dll", которая поставляется вместе с торговым терминалом QUIK или в самом QUIK-е?
Самое обидное заключается в том, что эта ошибка проявилась, когда вся DLL-библиотека (для хранения и обмена данными между разными LUA-скриптами: простые типы, строки, любые вложенные массивы) была полностью написана и показала неплохие результаты с точки зрения производительности и потоко-безопасности.
Когда ошибка проявилась, для проведения теста и исключения возможной ошибки в коде DLL-библиотеки был создан самый простой проект в "Visual Studio 2015", а LUA-скрипт запускался из торгового термина QUIK без подключения к серверу.
Ссылка на архив с исходниками для тестирования:
DLL-библиотека компилировалась в "Visual Studio 2015".
LUA-скрипт запускался из торгового терминала QUIK.