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

Автор записи: Дмитрий (Admin)
1 звезда2 звезды3 звезды4 звезды5 звезд (Голосов 2, среднее: 5,00 из 5)
Загрузка...

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

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

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

Код скрипта QLua
Код DLL

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

Добавить комментарий

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

  1. Это пожалуй маленькая революция получилась!!! Спасибо. Надо будет обдумать новые возможности. В своё время смотрел в данную сторону, но так как используется конструкция GLOBALSINDEX, которая вроде упразднилась в Lua 5.2 и выше. Решил данное направление не развивать, а вдруг quik перейдет на другую версию Lua... Если кто знает больше , поправьте меня 🙂 Ещё раз Спасибо. Прояснили окончательно технологию.

  2. Дмитрий, извините за навязчивость, Вы сможете показать рабочий код для DLL чтобы там отловить OnQuote(class, sec) или OnTrade(trade) ?
    Буду признателен, если так же подскажете как там получить данные из переменных class, sec и trade?

    1. Я вчера начал писать, но не успел закончить, проверил пример с main, все работает, как ожидалось, почти дописал вчера пример для OnAllTrade, но ночью сервера не работают, сегодня надеюсь сделаю и сразу отпишусь по результатам.

        1. Реализовал OnAllTrade, если main и OnStop еще впихнуть в DLL, то вообще скрипт из одного require будет 🙂
          Код Lua

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          
          require("QLuaCallbacks");
           
          Run = true;
           
          function main()
          	while Run do
          		sleep(1);
          	end;
          end;
           
          function OnStop()
          	Run = false;
          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
          56
          57
          58
          59
          60
          61
          62
          63
          64
          65
          66
          67
          68
          69
          70
          71
          72
          73
          74
          75
          76
          77
          78
          79
          80
          81
          82
          83
          84
          85
          86
          87
          88
          89
          90
          91
          92
          93
          94
          95
          96
          97
          98
          99
          100
          101
          102
          103
          104
          105
          106
          107
          108
          109
          110
          111
          112
          113
          114
          115
          116
          117
          118
          119
          120
          121
          122
          123
          124
          125
          126
          127
          128
          129
          130
          131
          132
          133
          134
          135
          136
          137
          138
          139
          140
          141
          142
          143
          144
          145
          146
          147
          148
          149
          150
          151
          152
          153
          154
          155
          156
          157
          158
          159
          160
          161
          162
          163
          164
          165
          166
          167
          168
          
          #include <windows.h>
          #include <string>
           
          //=== Необходимые для 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  fdwReason, LPVOID lpReserved)
          {
             return TRUE;
          }
           
          struct DateTime
          {
             int mcs;  //Микросекунды
             int ms;  //Миллисекунды
             int sec;  //Секунды
             int min;  //Минуты
             int hour;  //Часы
             int day; //День
             int week_day;  //Номер дня недели
             int month;  //Месяц
             int year;  //Год
          };
           
           
          std::string  getFieldValue(lua_State *L, const char *key)
          {
             std::string result;
             lua_pushstring(L, key); /* поместить ключ на стек */
             lua_gettable(L, -2); /* получить значение */
           
             result = lua_tostring(L, -1);
             lua_pop(L, 1);
           
             return result;
          }
           
          DateTime getDateTimeField(lua_State *L)
          {
             DateTime datetime;
           
             lua_pushstring(L, "datetime"); /* поместить ключ на стек */
             lua_gettable(L, -2); /* получить таблицу datetime */
           
             lua_pushstring(L, "mcs");  //Микросекунды
             lua_gettable(L, -2);
             datetime.mcs = lua_tonumber(L, -1);
             lua_pop(L, 1);
             lua_pushstring(L, "ms");  //Миллисекунды
             lua_gettable(L, -2);
             datetime.ms = lua_tonumber(L, -1);
             lua_pop(L, 1);
             lua_pushstring(L, "sec");  //Секунды
             lua_gettable(L, -2);
             datetime.sec = lua_tonumber(L, -1);
             lua_pop(L, 1);
             lua_pushstring(L, "min");  //Минуты
             lua_gettable(L, -2);
             datetime.min = lua_tonumber(L, -1);
             lua_pop(L, 1);
             lua_pushstring(L, "hour");  //Часы
             lua_gettable(L, -2);
             datetime.hour = lua_tonumber(L, -1);
             lua_pop(L, 1);
             lua_pushstring(L, "day"); //День
             lua_gettable(L, -2);
             datetime.day = lua_tonumber(L, -1);
             lua_pop(L, 1);
             lua_pushstring(L, "week_day");  //Номер дня недели
             lua_gettable(L, -2);
             datetime.week_day = lua_tonumber(L, -1);
             lua_pop(L, 1);
             lua_pushstring(L, "month");  //Месяц
             lua_gettable(L, -2);
             datetime.month = lua_tonumber(L, -1);
             lua_pop(L, 1);
             lua_pushstring(L, "year"); //Год
             lua_gettable(L, -2);
             datetime.year = lua_tonumber(L, -1);
             lua_pop(L, 1);
             lua_pop(L, 1);
           
             return datetime;
          }
           
           
          //=== Реализация функций обратного вызова ====================================================================//
          static int forLua_OnAllTrade(lua_State *L) //
          {
             // Проверяет, является-ли первый элемент стека массивом (таблицей Lua)
             if (lua_istable(L, 1))
             {
                std::string trade_num = getFieldValue(L, "trade_num");       // Номер сделки в торговой системе
                std::string flags = getFieldValue(L, "flags");           // Набор битовых флагов
                std::string price = getFieldValue(L, "price");           // Цена
                std::string qty = getFieldValue(L, "qty");             // Количество бумаг в последней сделке в лотах
                std::string value = getFieldValue(L, "value");           // Объем в денежных средствах
                std::string accruedint = getFieldValue(L, "accruedint");      // Накопленный купонный доход
                std::string yield = getFieldValue(L, "yield");           // Доходность
                std::string settlecode = getFieldValue(L, "settlecode");      // Код расчетов
                std::string reporate = getFieldValue(L, "reporate");        // Ставка РЕПО(%)
                std::string repovalue = getFieldValue(L, "repovalue");       // Сумма РЕПО
                std::string repo2value = getFieldValue(L, "repo2value");      // Объем выкупа РЕПО
                std::string repoterm = getFieldValue(L, "repoterm");        // Срок РЕПО в днях
                std::string sec_code = getFieldValue(L, "sec_code");        // Код бумаги заявки
                std::string class_code = getFieldValue(L, "class_code");      // Код класса
                DateTime    datetime = getDateTimeField(L);     // Дата и время
                std::string period = getFieldValue(L, "period");          // Период торговой сессии.Возможные значения : «0» – Открытие; «1» – Нормальный; «2» – Закрытие
           
                if (sec_code == "SBER")
                {
                   std::string TradeInfo =
                      "trade_num=" + trade_num + " " +
                      "flags=" + flags + " " +
                      "price=" + price + " " +
                      "qty=" + qty + " " +
                      "value=" + value + " " +
                      "accruedint=" + accruedint + " " +
                      "yield=" + yield + " " +
                      "settlecode=" + settlecode + " " +
                      "reporate=" + reporate + " " +
                      "repovalue=" + repovalue + " " +
                      "repo2value=" + repo2value + " " +
                      "repoterm=" + repoterm + " " +
                      "sec_code=" + sec_code + " " +
                      "class_code=" + class_code + " " +
                      "time=" + std::to_string(datetime.hour) + ":" +
                      std::to_string(datetime.min) + ":" +
                      std::to_string(datetime.sec) + "." +
                      std::to_string(datetime.mcs) + " " +
                      "trade_num=" + trade_num + " " +
                      "period=" + period;
           
                   //Выводит сообщение в терминале с информацией по сделке
                   lua_getglobal(L, "message");
                   lua_pushfstring(L, TradeInfo.c_str());
                   lua_pcall(L, 1, 0, 0);
                }
           
             }
             return 0;
          }
           
           
          //=== Регистрация реализованных в dll функций, чтобы они стали "видимы" для Lua ================================//
          static struct luaL_reg ls_lib[] = {
             { NULL, NULL }
          };
           
          //=== Регистрация названия библиотеки, видимого в скрипте Lua ==================================================//
          extern "C" LUALIB_API int luaopen_QLuaCallbacks(lua_State *L) {
             luaL_openlib(L, "QLuaCallbacks", ls_lib, 0);
           
             //Добавляет функцию в стек
             lua_pushcclosure(L, forLua_OnAllTrade, 0);
             //Регистрирует её как колбэк на OnAllTrade
             lua_setfield(L, LUA_GLOBALSINDEX, "OnAllTrade");
           
             return 0;
          }
  3. Здравствуйте!

    Подскажите, пожалуйста:
    1. к встроенным функциям QLua обращаться по такому же принципу, как Вы описали выше? Как передавать в них больше 1 параметра и как получать возвращаемые значения?
    2. как в DLL обращаться к функциям обратного вызова? При этом не указывать её (функцию обратного вызова) в коде Lua.

      1. Дмитрий, чтобы понять механизм как QScalp, ATAS и StockSharp так делают, что у них в скрипте Lua, только require("...") и настройки. А вообще хочу прописать все функции в DLL на C++, а потом програмить только на C# не думая больше о Lua.

        1. Понимаю Вас, у меня тоже есть такая задача. Но недавние мои изыскания не дали результата, хотя не сказать, что я очень усердно пытался найти решение. Здесь задача не вызвать функцию обратного вызова из DLL, а отловить в DLL вызов этой функции терминалом и я на данный момент не представляю как это сделать, хотя, как это обычно бывает, решение, возможно, очень простым окажется)

          1. Вот тут, в самом низу человеку удалось сделать это с main: http://quik2dde.ru/viewtopic.php?id=143

            Он так сделал:

            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14
            15
            16
            17
            18
            19
            20
            21
            22
            
             //Функция бросает сообщение в КВИКе, её будем регистрировать как main
            static int forLua_LuaMessage(lua_State* L){
                lua_getglobal(L, "message");
                lua_pushfstring(L, "Main!");
                lua_pcall(L, 1, 0, 0);
             
                return 0;
            }
             
            ...
             
             
            extern "C" LUALIB_API int luaopen_testQUIKCOnnector(lua_State* L) {
                luaL_openlib(L, "testQUIKCOnnector", ls_lib, 0);
             
                //Заталкиваем функцию в стек
                lua_pushcclosure(L, forLua_LuaMessage, 0);
                //Регистрируем её как колбэк на main
                lua_setfield(L, LUA_GLOBALSINDEX, "main");
             
                return 0;
            }

            Но как сделать это например с OnQuote()? Тут, косвенно подтверждается что сделать можно: http://quik2dde.ru/viewtopic.php?id=90

            Эти ссылки могут как то помочь? Куда "копать"?

              1. Я честно говоря не врубился как 🙂 Напишите, пожалуйста рабочий код для DLL чтобы там отловить OnQuote(class, sec) или OnTrade(trade) . И как там получить данные из переменных class, sec и trade?