DLL для LUA: Ошибка при получении индексированного массива из DLL

Страницы: 1
RSS
DLL для LUA: Ошибка при получении индексированного массива из DLL, В LUA-скрипте при получении индексированного массива из DLL-библиотеки возникает ошибка и 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-скрипта:
Код
-- Добавим в переменную окружения путь расположения нашего скрипта для подключения *.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 без подключения к серверу.

Ссылка на архив с исходниками для тестирования: https://yadi.sk/d/4_WNa6WWWBpMbQ
DLL-библиотека компилировалась в "Visual Studio 2015".
LUA-скрипт запускался из торгового терминала QUIK.
 
Алексей, не тот lib файл, либо криво собран.
заменил на тот что идет из поставки Lua_For_Windows, для простоты залил судаhttps://yadi.sk/d/D2kMgI1Cj7FfeQ
больше ничего не трогал. просто заменить 1 файл
ps для своего проекта билд настроен отсуда https://github.com/LuaDist/lua.git . проблема выплыла таже(был очень удивлен, похоже придется менять).

тест уменьшил вплоть до создания пустой таблицы, потом вылетает ошибка VM
Код
#define LUA_LIB
#define LUA_BUILD_AS_DLL

extern "C" {
    #include <lua.h>
    #include <lauxlib.h>
    #include <lualib.h>
    #include <luaconf.h>
}
extern "C" __declspec(dllexport) int luaopen_table_export(lua_State *L)
{
    lua_newtable(L);
    lua_setglobal(L, "asd");
    return 0;
}
ошибку можно убирать разными хаками типа не заполнять 1й элемент начинать со 2го либо заполнить нулевой. не передавать пустые таблицы, но лучше ее на корню исправить используя оригинальные сорцы этой версии(из квика) луа.
 
Антон. Огромное спасибо за ваш ответ. Все проверил, работает "как часы". Честно говоря, о таком очевидном решении (правда, оно стало очевидным только после того, как вы его подсказали) у меня даже и предположений не было. Не помню, откуда я скачал сборку библиотеки "lua5.1.lib", скорее всего по какой-нибудь ссылке с примерами по созданию DLL-библиотек для QLUA или что-то подобное. Хорошо, что ошибка проявилась на этапе тестирования (путем непрерывного вызова из функции main() LUA-скрипта соответствующих функций DLL-библиотеки с выводом результата в LOG-файл), а не в процессе реальной работы с деньгами.

К стати, именно по причине появления подобных ошибок, я не стал использовать свою GUI DLL-библиотеку (нормальные окна, кнопки и прочие контролы WinAPI) при создании торгового инструмента, а перешел на "таблицы QUIK",убого правда, но зато стабильно работает. А опять менять интерфейс, рука не поворачивается, слишком много времени было потрачено на его организацию с помощью "таблиц квика".

Еще раз, большое спасибо, Алексей.
Страницы: 1
Читают тему
Наверх