1 (2021-04-07 09:01:33 отредактировано swerg)

Тема: Вызовы COM из Lua

Для работы с интерфейсом COM из Lua есть готовая библиотека luacom.

Оригинальная библиотека

Исходники: [url]https://github.com/davidm/luacom/[/url]

Доработанная библиотека

Я немного подпилил luacom. В частности, поправлена передача кириллицы из скриптов в кодировке ANSI в UNICODE (скрипты для QUIK всегда в кодировке ANSI, иначе из скриптов будут выводиться кракозябры в сообщениях).
дополнительно в исходники добавлены все файлы, необходимые для сборки, в том числе для разных вариаций платформы и версии Lua, какие бывают в QUIK.

Исходники: [url]https://github.com/swerg/qlua-luacom[/url]
Скачать: [url=https://quik2dde.ru/static-img/81/luacom.dll.zip]архив luacom.dll[/url] для разных версий QUIK

2 (2021-04-07 08:59:26 отредактировано swerg)

Re: Вызовы COM из Lua

Рассмотрим работу с библиотекой luacom на паре простых примеров

Примеры взяты [url=http://forum-archive.quik.ru/forum/lua/109335/109335/?page=2]с форума QUIK[/url], спасибо их автору.

Пример номер 1.
Открываем MSExcel и выводим в него текущее значение вариационной маржи. После чего ждем 3 сек. и закрываем Excel.

require "luacom"
excel = luacom.CreateObject("Excel.Application")
excel.Visible = true
wb = excel.Workbooks:Add()
ws = wb.Worksheets(1)
row = 1
col = 2
vm = getItem("futures_client_holding", 0).varmargin
ws.Cells(row,col).Value2 = vm
sleep(3000)
excel.DisplayAlerts = false
excel:Quit()
excel = nil

Пример номер 2.
Здесь мы будем значение вариационной маржи выводить в цикле, раз в 3 секунды, каждый раз в новую ячейку. Работа скрипта  завершается при нажатии кнопки "Стоп" из диалога управления скриптами. При этом Excel также закрывается.

В этом примере хотелось бы обратить внимание на следующие детали. Цикл вывода в MS Excel расположен в main(), которая - не забываем! - [url=https://quik2dde.ru/viewtopic.php?id=16]выполняется в отдельно потоке[/url]. Поэтому:

  • всю работу по созданию COM-объектов выполняем только в main(); не следует создавать COM-объекты в обработчиках, например, а обращаться к ним из main()

  • в потоке, где идет работа с COM обязательно должны быть вызваны функции CoInitialize() и CoUninitialize(), для работы c которыми подключим еще [url=https://quik2dde.ru/viewtopic.php?id=78]библиотеку w32[/url].

require "w32"
require "luacom"

row = 1
col = 2
is_run = true

function main()
  w32.CoInitialize()
  excel = luacom.CreateObject("Excel.Application")
  excel.Visible = true
  wb = excel.Workbooks:Add()
  ws = wb.Worksheets(1)
  while is_run do
    vm = getItem("futures_client_holding", 0).varmargin
    ws.Cells(row,col).Value2 = vm
    row = row + 1  -- для вывода следующего значения перейдем на одну строку ниже
    sleep(3000)
  end
  excel.DisplayAlerts = false
  excel:Quit()
  excel = nil
  w32.CoUninitialize()
end 

function OnStop(signal)
  is_run = false
end

3

Re: Вызовы COM из Lua

Если кого-нибудь выложит какие-нибудь примерчики работы с COM из Lua - буду за них очень признателен.
Есть желание подключить какие-либо программы через COM-интерфейс к QUIK через Lua, но есть затруднения - не стесняемся, оставляем комментарии )

4

Re: Вызовы COM из Lua

Добрый день!

В инете особо нет информации по этому поводу, мб вы сможете мне помочь.

Используя библиотеку w32 с этого сайта smile, удалось запустить из QUIK (6.8.4.14) Excel 2010 (русская версия) (ОС Windows XP).
При передаче данных из QUIK в ячейки листа Excel цифры, английские символы, знаки препинания нормально отображаются, а русские символы не отображаются совсем.

Если кто-то знает, что можно попробовать сделать в данной ситуации, буду очень признателен за ответ smile

5 (2021-04-07 09:00:32 отредактировано swerg)

Re: Вызовы COM из Lua

Про русские буквы оказалось штука вот в чем.

Библиотека luacom подразумевает, что в нее запихиваются данные в кодировке Utf8. Соответственно, если записывается обычный текст в виндовой кодировке - то остается только латиница и цифры.

Вариантов решения проблемы видится несколько.

1. Если в Excel (или другой COM-объект) нужно выводить лишь заданные в тесте Lua-скрипта константы - то достаточно этот Lua-скрипт сохранить в кодировке Utf8 и все волшебно заработает, проверено.

2. Можно взять библиотеку w32 с этого сайта, в нее по данному поводу добавлены две функции: AnsiToUtf8() и Utf8ToAnsi(), т.е. для корректного вывода в ячейку Excel надо написать:
        ws.Cells(row,col).Value2 = w32.AnsiToUtf8("Мама мыла раму")

3. Раз уж разобрался во всей этой фигне - поправил исходники luacom так, чтобы она работала в кодировке Ansi, т.е. обычной Windows-кодировке. (Для этого в файле tUtil.cpp в 4-х местах константа CP_UTF8 заменена на CP_ACP.)
[url=https://quik2dde.ru/static-img/81/luacom.dll.zip]Ссылка на скачивание архива с luacom.dll[/url], в которой используется кодировка Windows.


PS
Кстати, в приведенном коде работы с MS Excel тоже не всё чисто. А именно: после его выполнения остается висеть в процессах Excel, к тому же процесс info.exe после завершения работы QUIK тоже не исчезает, если выполнить приведенный Lua-скрипт работы с Excel! Интернет и на эту тему пестрит сообщениями о данной проблеме, кстати (про незавершение процесса Excel), но рабочие способ избавиться от этой проблемы найти подобрать мне как-то не удалось.

6

Re: Вызовы COM из Lua

Спасибо за помощь!

3 метод (перекомпилированная версия luacom.dll) для меня отлично сработал

7 (2015-06-05 11:33:18 отредактировано kalikazandr)

Re: Вызовы COM из Lua

swerg пишет:

Если кого-нибудь выложит какие-нибудь примерчики работы с COM из Lua - буду за них очень признателен.
Есть желание подключить какие-либо программы через COM-интерфейс к QUIK через Lua, но есть затруднения - не стесняемся, оставляем комментарии )

--Speak.lua--
local is_run = true
function OnStop() is_run = false end
local w32 = require ("w32")
--говорилка Марина--
local luacom = require("luacom")
--
require("StaticVar")
stv.UseNameSpace("RSENDRZ")
--
local firmid, clientcode = "---------", "--------"
local math_floor, string_sub = math.floor, string.sub

local base_limit = 16000000
--реинвестирование
local PortfolioInfo = function ()
    local item = getPortfolioInfoEx (firmid, clientcode,2)
    local assets = 0 + item.all_assets
    if assets and assets ~= base_limit then 
        if assets > base_limit then return math_floor (assets)
        else return base_limit end
    end
end
local limit = PortfolioInfo ()
local old_limit = limit
stv.SetVar("limit", limit)
stv.SetVar("TRANS_ID", 7777)
local ending_limit = string_sub (limit, -2) + 0
local mEndLim = {
                [1]="ь",[21]="ь",[31]="ь",[41]="ь",[51]="ь",[61]="ь",[71]="ь",[81]="ь",[91]="ь",
                [2]="я",[3]="я",[4]="я",[22]="я",[23]="я",[24]="я",
                [32]="я",[33]="я",[34]="я",[42]="я",[43]="я",[44]="я",
                [52]="я",[53]="я",[54]="я",[62]="я",[63]="я",[64]="я",
                [72]="я",[73]="я",[74]="я",[82]="я",[83]="я",[84]="я",
                [92]="я",[93]="я",[94]="я"
                }

function main()
    w32.CoInitialize()
    local vObj = luacom.CreateObject("Sapi.SpVoice")
    vObj:Speak ("Вас приветствует робот Марина. Рабочий лимит " .. limit .. " рубл".. (mEndLim[ending_limit] or "ей") ..". Приятного заработка.")
    while is_run do
        --limit = money_limits(getNumberOf("money_limits")-1,limit)
        limit = PortfolioInfo ()
        if limit > old_limit then
            ending_limit = string_sub (limit, -2) + 0
            stv.SetVar ("limit", limit)
            vObj:Speak ("Текущий лимит " .. limit .. " рубл".. (mEndLim[ending_limit] or "ей"))
            old_limit = limit
        end 
        sleep(1000) 
    end
    w32.CoUninitialize()
end

8 (2015-06-05 13:25:15 отредактировано swerg)

Re: Вызовы COM из Lua

Какой замечательный пример! спасибо

Подскажите, что вы используете для синтеза русской речи?

От себя добавлю, что если вызывать vObj:Speak() из обработчика, то надо добавлять параметр, чтобы фраза произносилась асинхронно, не останавливая терминал на время произнесения, т.к. по умолчанию работа производится синхронно и из метода Speak() возращается только после произнесения всей фразы:

vObj:Speak("Текст", 1)

9

Re: Вызовы COM из Lua

swerg пишет:

Какой замечательный пример! спасибо

Подскажите, что вы используете для синтеза русской речи?

От себя добавлю, что если вызывать vObj:Speak() из обработчика, то надо добавлять параметр, чтобы фраза произносилась асинхронно, не останавливая терминал на время произнесения, т.к. по умолчанию работа производится синхронно и из метода Speak() возращается только после произнесения всей фразы:

vObj:Speak("Текст", 1)

Для синтеза использую w8.1)) там встроенная говорилка Марина, но можно скачать из инета по-моему.
Не знал о такой тонкости, спасибо.

10

Re: Вызовы COM из Lua

Здравствуйте!
Я только начал изучать Lua для Quik.
Простенькие программки работают.

Тема Luacom очень интересна, хотел попробовать пример.

Скачал в папку с моими луа-программками luacom.dll, запустил первый пример из ветки.

Сразу ошибка в команде require "luacom":  "не найден  luacom.dll"


Я ни разу не подключал никакие файлы, кроме *.lua
Не могли бы помочь - куда положить файл luacom.dll и что сделать, чтобы пример заработал?

Lua for Windows не установлен.

11

Re: Вызовы COM из Lua

f1manager пишет:

Не могли бы помочь - куда положить файл luacom.dll и что сделать, чтобы пример заработал?

Здравствуйте, в папку с QUIK

12 (2015-07-18 17:33:26 отредактировано f1manager)

Re: Вызовы COM из Lua

Спасибо за совет, kalikazandr!

Я это уже сделал, положил файл luacom.dll в папку с квиком и в папку с моим LUA - файлом.

Выдает ошибку:

error loading module 'luacom' from file '.\luacom.dll':
    .\luacom.dll:1: '=' expected near 'ђ'

Что с этим делать  - ума не приложу.

Пробовал luacom.dll 1.4 и 1.3



Кстати, с w32.dll та же петрушка - положил в папку с Quik -


error loading module 'w32' from file '.\w32.dll':
    .\w32.dll:1: '=' expected near 'ђ'

Quik не инсталлирован, просто переписана папка.
Если это важно.

13

Re: Вызовы COM из Lua

Очень похоже, что для поиска C загрузчика вместо package.сpath ипользуется package.path

14 (2015-07-19 02:47:26 отредактировано kalikazandr)

Re: Вызовы COM из Lua

f1manager пишет:

Quik не инсталлирован, просто переписана папка.
Если это важно.

Не инсталлирован -  не важно. Что значит "просто переписана папка"? Версия квик какая? Откуда брали библиотеки?
Первый пример в посте у меня работает нормально

15

Re: Вызовы COM из Lua

kalikazandr пишет:
--Speak.lua--
local is_run = true
function OnStop() is_run = false end
local w32 = require ("w32")
--говорилка Марина--
local luacom = require("luacom")
--
require("StaticVar")
stv.UseNameSpace("RSENDRZ")
--
local firmid, clientcode = "---------", "--------"
local math_floor, string_sub = math.floor, string.sub

local base_limit = 16000000
--реинвестирование
local PortfolioInfo = function ()
    local item = getPortfolioInfoEx (firmid, clientcode,2)
    local assets = 0 + item.all_assets
    if assets and assets ~= base_limit then 
        if assets > base_limit then return math_floor (assets)
        else return base_limit end
    end
end
local limit = PortfolioInfo ()
local old_limit = limit
stv.SetVar("limit", limit)
stv.SetVar("TRANS_ID", 7777)
local ending_limit = string_sub (limit, -2) + 0
local mEndLim = {
                [1]="ь",[21]="ь",[31]="ь",[41]="ь",[51]="ь",[61]="ь",[71]="ь",[81]="ь",[91]="ь",
                [2]="я",[3]="я",[4]="я",[22]="я",[23]="я",[24]="я",
                [32]="я",[33]="я",[34]="я",[42]="я",[43]="я",[44]="я",
                [52]="я",[53]="я",[54]="я",[62]="я",[63]="я",[64]="я",
                [72]="я",[73]="я",[74]="я",[82]="я",[83]="я",[84]="я",
                [92]="я",[93]="я",[94]="я"
                }

function main()
    w32.CoInitialize()
    local vObj = luacom.CreateObject("Sapi.SpVoice")
    vObj:Speak ("Вас приветствует робот Марина. Рабочий лимит " .. limit .. " рубл".. (mEndLim[ending_limit] or "ей") ..". Приятного заработка.")
    while is_run do
        --limit = money_limits(getNumberOf("money_limits")-1,limit)
        limit = PortfolioInfo ()
        if limit > old_limit then
            ending_limit = string_sub (limit, -2) + 0
            stv.SetVar ("limit", limit)
            vObj:Speak ("Текущий лимит " .. limit .. " рубл".. (mEndLim[ending_limit] or "ей"))
            old_limit = limit
        end 
        sleep(1000) 
    end
    w32.CoUninitialize()
end

нарыл вот тут [url]http://bot4sale.ru/blog-menu/qlua/spisok-statej/477-ending.html[/url] очень хорошую функцию:

function string_ending(what,end1,end234,default)
   what = tostring(math.floor(what))
   return what:sub(-2,-2) ~= "1" and ({ ["1"] = end1,
                                        ["2"] = end234,
                                        ["3"] = end234,
                                        ["4"] = end234 })[what:sub(-1)] or default
end

соответственно использую в коде выше:

vObj:Speak ("Вас приветствует робот ДАТА МКС. Рабочий лимит " .. limit .. " " .. string_ending(limit,"рубль","рубля","рублей") ..". Приятного заработка.",1)

и тут:

vObj:Speak ("Текущий лимит " .. limit .. " " .. string_ending(limit,"рубль","рубля","рублей"),1)

16

Re: Вызовы COM из Lua

Поставил w.10, Марина сломалась - говорит медленно, в настройках речи задал скорость - пофик, все равно медленно.

17

Re: Вызовы COM из Lua

У меня практически такая же проблема!
Пытаюсь подключить модуль luacom.dll. Пишу просто require "luacom.dll", а в ответ:
"error loading module 'luacom.dll' from file 'C:\Program Files (x86)\QUIK_OpenBroker\luacom.dll':
Не найден указанный модуль."
При том, что модуль находится именно там, где написано.
Что такое и что нужно сделать, чтобы подключить всё таки этот модуль?

18 (2015-10-19 02:45:58 отредактировано kalikazandr)

Re: Вызовы COM из Lua

require "luacom"

19 (2015-10-19 20:25:07 отредактировано Metallurg)

Re: Вызовы COM из Lua

kalikazandr пишет:

require "luacom"

я с этого, конечно, начинал. ответ тот же самый:
error loading module 'luacom' from file '.\luacom.dll':
    Не найден указанный модуль.

Пробовал на WinXP 32b (установлена VS 2013, правда только C#) и Win7 64b (с такой же шарповской VS 2015) - результат один и тот же.

Версия Quik - 6.17.1.17

20

Re: Вызовы COM из Lua

Если вы используете luacom.dll из луафорвиндовс, то подключаться она не будет, скачайте с этой ветки библиотеку.

21

Re: Вызовы COM из Lua

kalikazandr пишет:

Если вы используете luacom.dll из луафорвиндовс, то подключаться она не будет, скачайте с этой ветки библиотеку.

замечательно! заработало! большое спасибо! но позвольте узнать - что в этом варианте библиотеке изменено, что он работает?

22

Re: Вызовы COM из Lua

Metallurg пишет:

что в этом варианте библиотеке изменено, что он работает?

Run-time влинкован, т.е. не требуются дополнительные DLL.
Та сборка, что идёт "родная" - требует run-time библиотек VisualC++ подходящей версии.

23

Re: Вызовы COM из Lua

swerg пишет:

Run-time влинкован, т.е. не требуются дополнительные DLL.
Та сборка, что идёт "родная" - требует run-time библиотек VisualC++ подходящей версии.

то есть, если бы у меня визуал студия была полной (с с++, а не только c#), то всё было бы ок?

24

Re: Вызовы COM из Lua

Metallurg пишет:

что в этом варианте библиотеке изменено, что он работает?

Было написано:

swerg пишет:

требует run-time библиотек VisualC++ подходящей версии.

Т.е. суть не в полноте установленной студии. Студии как таковой может при этом не быть, она ведь платная (внезапно!).
Суть именно в той версии run-time библиотек (т.е. dll файлов с именем типа msvcrt), на которой собирался данный проект.
При этом студия не обязательна.
Microsoft выпускает инсталляторы так называемых "redistributable package", который бесплатны, и содержат как раз все run-time DLL от соответствующей версии VisualC++. Они так и называются:
"Microsoft Visual C++ 2005 Redistributable Package"
"Microsoft Visual C++ 2010 Redistributable Package"
ну и т.д.

Чтобы знать, какой именно пакет нужно установить - надо знать на какой версии студии была собрана та библиотека, которая есть у вас в руках.

25

Re: Вызовы COM из Lua

swerg пишет:

Есть желание подключить какие-либо программы через COM-интерфейс к QUIK через Lua, но есть затруднения - не стесняемся, оставляем комментарии )

Такое желание есть и у меня)
Но пока с трудом могу понять схему такого взаимодействия. Наверное из-за того, что слабо понимаю суть СОМ. Мне необходимо из Quik передавать данные, пусть для примера из таблицы всех сделок, в стороннюю программу. По СОМ. Для этого мне нужно написать программу-СОМ-сервер на Lua, в которой будет описана функция обратного вызова OnAllTrade, которая будет складывать полученные от Quik данные в какое-то своё свойство, которому будет присвоен СОМ-идентификатор и, которое сможет по СОМ-интерфейсу прочитать моя сторонняя программа на с#?
Или я в корне неправильно понимаю всю суть?
Как должно быть?