Вызов функций QLua(Lua) из DLL, написанной на C/C++

Автор записи: Дмитрий (Admin)

Qlua-csharp-connector-dllДля этого нужна обычная библиотека DLL, подключаемая к QLua, о том, как ее создать можете посмотреть здесь.

Пусть созданная Вами DLL называется "LuaCallback.dll", которая находится в корневом каталоге терминала QUIK.

Следующий пример 10 раз, с периодичностью в 1 секунду выведет сообщение с текстом "Привет из DLL" посредством вызова из DLL функции из Qlua скрипта MyLuaCallback():

Код скрипта QLua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
require("LuaCallback"); -- Подключает библиотеку "LuaCallback.dll"
 
Run = true; -- Флаг поддержания работы скрипта
 
-- Основная функция скрипта, пока работает она, работает скрипт
function main()
   LuaCallback.StartCallback(); -- Запускает механизм вызова функции MyLuaCallback из DLL
   while Run do sleep(1000); end; -- Поддерживает работу скрипта
end;
 
-- Функция, вызываемая из DLL
function MyLuaCallback(Text)
   message(Text); -- Выводит сообщение, переданное в функцию из DLL
end;
 
-- Функция завершения работы скрипта
function OnStop()
   Run = false; -- Завершает цикл while, следовательно завершается main() и сам скрипт останавливается
end;
Код DLL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <windows.h> //Подключает все необходимое
#include <thread> //Подключает возможность работы с потоками
 
//=== Необходимые для Lua константы ============================================================================//
#define LUA_LIB
#define LUA_BUILD_AS_DLL
 
//=== Заголовочные файлы LUA ===================================================================================//
extern "C" {
#include "Lua\lauxlib.h"
#include "Lua\lua.h"
}
 
//=== Стандартная точка входа для DLL ==========================================================================//
BOOL APIENTRY DllMain(HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
   return TRUE;
}
 
//Функция вызывает функцию из QLua с периодичностью в 1 секунду
static int MyCallback(lua_State *L)
{
   lua_getglobal(L, "MyLuaCallback"); //Находит в стеке Lua функцию по ее названию и помещает ее наверх стека
   int callbackRef = luaL_ref(L, LUA_REGISTRYINDEX); //Получает индекс функции в специальной внутренней таблице(реестре) Lua
 
   for (int i = 0; i < 10;i++)
   {
      lua_rawgeti(L, LUA_REGISTRYINDEX, callbackRef); //Достает функцию из реестра Lua по индексу и помещает в стек
      lua_pushstring(L, "Привет из DLL"); //Добавляет в стек параметр, который будет передан функции
      lua_call(L, 1, 1); //Вызывает выбранную функцию в скрипте QLua, передавая в нее 1 параметр (L - стек, 1 - количество передаваемых параметров, 1 - количество возвращаемых значений(нужно, чтобы обновлять стек))
      Sleep(1000); //Пауза в 1 секунду
   }
 
   return 0; //Выход из функции
}
 
//=== Реализация функций, вызываемых из LUA ====================================================================//
static int forLua_StartCallback(lua_State *L)
{
   std::thread thr(MyCallback, L); //Запускает выполнение функции MyCallback() в отдельном потоке
   thr.detach(); //Отсоединяет созданный поток от основного, делая его "фоновым"
 
   return (0); //Завершает работу функции forLua_StartCallback, при этом функция MyCallback продолжает работать в отдельном потоке
}
 
//=== Регистрация реализованных в dll функций, чтобы они стали "видимы" для Lua ================================//
static struct luaL_reg ls_lib[] = {
   { "StartCallback", forLua_StartCallback }
};
 
//=== Регистрация названия библиотеки, видимого в скрипте Lua ==================================================//
extern "C" LUALIB_API int luaopen_LuaCallback(lua_State *L) {
   luaL_openlib(L, "LuaCallback", ls_lib, 0);
   return 0;
}

Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!