Общая часть
В основной файл проекта разместим код интерфейсной функции, которая будет вызываться при подключении нашего модуля к программе на Lua (через директиву require) и регистрировать доступные в нем для Lua-скриптов функции. Учитывая имя нашей библиотеки, такая интерфейсная функция должна называться luaopen_SimpleDelphiLua(). Здесь же в константном массиве ls_lib разместим список регистрируемых функций, которые буду доступны нам для вызова из Lua-скриптов.
(Строго говоря, написанное про единственно возможное имя функции не совсем верно; функция может называться и иначе, в этом случае надо будет изменить формат подключения нашего модуля в Lua. Но для простоты делаем так, как написано.)
var
ls_lib: array[1..3] of luaL_reg =
(
(name: 'MultAllNumbers'; func: forLua_MultAllNumbers),
(name: 'GetHostAppPath'; func: forLua_GetHostAppPath),
(name: nil; func: nil)
);
function luaopen_SimpleDelphiLua(L: Plua_State): Integer; cdecl;
begin
luaL_openlib(L, PChar('SimpleDelphiLua'), @ls_lib, 0);
lua_pop(L, 1);
Result := 0;
end;
Не забываем для интерфейсных функций добавлять модификатор соглашений о вызовах cdecl! Для остальных функции, которые используются только внутри DLL-библиотеки, добавлять модификаторы соглашений о вызовах не обязательно.
Т.к. функция инициализации должна экспортироваться из dll-ки, необходимо где-то после ее объявления добавить строчку:
exports luaopen_SimpleDelphiLua;
Теперь добавим в библиотеку собственно те функции, которые будут вызываться из скриптов Lua. Все такие функции должны объявляться одинаково вот по такому шаблону:
function FuncName(L: Plua_State): Integer; cdecl;
На вход они принимают указатель на Lua стек, а возвращать должны количество результирующих значений. Т.к. это интерфейсные функции, которые будут вызываться из Lua-машины, не забывайте указывать для них модификатор cdecl!
Как видно из кода выше, в библиотеке мы реализуем две функции:
MultAllNumbers - перемножает все переданные в качестве аргументов числа и возвращает результат перемножения;
GetHostAppPath - возвращает полный путь, где расположено загрузившее эту DLL приложение; в нашем случае это будет папка, где расположен QUIK.
Сами функции я вынес в отдельный модуль LuaFuncImpl.pas, добавленный в проект. В него подключаем интерфейсы из заголовочных файлов Lua:
uses lua, lauxlib, lualib;
Функция MultAllNumbers представляет из себя «дословное переложение» аналогичной функции из [url=https://quik2dde.ru/viewtopic.php?id=18]примера Lua-библиотек на C[/url]. Вот она:
function forLua_MultAllNumbers(L: Plua_State): Integer; cdecl;
var
n,i: Integer;
res: Double;
isNumberFound: Boolean;
begin
n := lua_gettop(L); // количество переданных аргументов
res := 1;
isNumberFound := false;
for i := 1 to n do
begin
if lua_type(L,i) = LUA_TNUMBER then
begin
res := res * lua_tonumber(L,i);
isNumberFound := true;
end;
end;
if isNumberFound then
lua_pushnumber(L, res) // если найдено хоть одно число в аргументах - возвращаем произведение
else
lua_pushnil(L); // если список аргументов пуст или в нем нет ни одного числа - функция вернет nil
Result := 1; // возвращаемое количество результатов
end;
Реализацию функции GetHostAppPath() можете посмотреть в приложенных исходниках в самом первом посте темы, она совсем простая.
Скомпилируем проект, полученную библиотеку SipmleDelphiLua.dll скопируем в каталог, где установлен QUIK, и создадим тестовый скрипт на Lua:
require "SimpleDelphiLua"
res = SimpleDelphiLua.MultAllNumbers(2, 3, "A", 5.3)
message("MultAllNumbers=" .. tostring(res, 1), 1)
message("GetHostAppPath=" .. SimpleDelphiLua.GetHostAppPath(), 1)
function main()
end
Запустив его в QUIK, увидим результат в виде 2-х сообщений: результат перемножения трех чисел (2, 3 и 5.3) и полный путь к каталогу, откуда запущен терминал QUIK.

Вот у нас и готова библиотека на Delphi или Lazarus для Lua!
Если вдруг захочется использовать визуальные компоненты Delphi для построения GUI - то пожалуйста, конечно, но есть разные нюансы. Проще взять готовую библиотеку, [url=https://quik2dde.ru/viewtopic.php?id=26]например VCLua[/url], которая как раз сделана в Delphi-подобной, только бесплатной среде разработки Lazarus.
В финале хотелось бы добавить еще один штрих. Начиная с версии 6.5.1.19 терминала QUIK, библиотека qlua.dll стала экспортировать из себя все функции поддержки Lua. Это значит, что вместо Lua5.1.dll можно использовать напрямую qlua.dll, т.е. никакая Lua5.1.dll для наших библиотек больше не нужна. Отличная новость!
Для поддержки такого варианта в файле Lua.pas я добавил возможность задания подключения интерфейсных Lua-функций непосредственно из qlua.dll в случае, если определена директива USEQLUA, и сразу включил именно такой режим сборки:
{$DEFINE USEQLUA}
const
{$IFDEF UNIX}
LUA_NAME = 'liblua.5.1.so';
LUA_LIB_NAME = 'liblua.5.1.so';
{$ELSE}
{$IFDEF USEQLUA}
LUA_NAME = 'qlua.dll';
LUA_LIB_NAME = 'qlua.dll';
{$ELSE}
LUA_NAME = 'lua5.1.dll';
LUA_LIB_NAME = 'lua5.1.dll';
{$ENDIF}
{$ENDIF}
Можете проверить и убедиться, что библиотека SipmleDelphiLua.dll работает и при отсутствии файла lua5.1.dll.