<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<title type="html"><![CDATA[QUIK -> DDE &mdash; Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)]]></title>
	<link rel="self" href="https://quik2dde.ru/extern.php?action=feed&amp;tid=40&amp;type=atom" />
	<updated>2024-03-02T19:01:59Z</updated>
	<generator>PunBB</generator>
	<id>https://quik2dde.ru/viewtopic.php?id=40</id>
		<entry>
			<title type="html"><![CDATA[Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)]]></title>
			<link rel="alternate" href="https://quik2dde.ru/viewtopic.php?pid=4326#p4326" />
			<content type="html"><![CDATA[<p><strong>Cave Cat</strong>, приветствую вас на форуме!</p><p>Выше в этой теме было сообщение:</p><div class="quotebox"><cite>swerg пишет:</cite><blockquote><p>Разница скорее в том, что версия LUA изменилась. Для нее новые заголовочные файлы нужны.<br />И еще надо раздельно собирать для Lua 5.3 и Lua 5.4, с разными заголовочными файлами.<br />Ну или просто остановиться на одной из этих версий и только для нее собирать, не забывая выбирать соотв. версию Lua в терминале для выполнения скрипта.</p><p>Заголовочники можно стырить из QVCLua, например<br />[url]https://quik2dde.ru/viewtopic.php?id=111[/url]</p><p>В этой теме, увы, пример я пока не обновил с готовыми параметрами сборки.</p><p>Еще в Lua 5.3 / 5.4 поменялось API для инициализации библиотеки в luaopen_ХХХ<br />Вот в этой теме есть подробности<br />[url]https://quik2dde.ru/viewtopic.php?id=18[/url]</p></blockquote></div>]]></content>
			<author>
				<name><![CDATA[swerg]]></name>
				<uri>https://quik2dde.ru/profile.php?id=78</uri>
			</author>
			<updated>2024-03-02T19:01:59Z</updated>
			<id>https://quik2dde.ru/viewtopic.php?pid=4326#p4326</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)]]></title>
			<link rel="alternate" href="https://quik2dde.ru/viewtopic.php?pid=4325#p4325" />
			<content type="html"><![CDATA[<p>Здравствуйте!<br />Где можно скачать заголовочные файлы для Lua 5.4 для сборки dll в Lazarus?<br />Может, кто-то тут выложит?</p>]]></content>
			<author>
				<name><![CDATA[Cave Cat]]></name>
				<uri>https://quik2dde.ru/profile.php?id=3253</uri>
			</author>
			<updated>2024-03-02T07:10:23Z</updated>
			<id>https://quik2dde.ru/viewtopic.php?pid=4325#p4325</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)]]></title>
			<link rel="alternate" href="https://quik2dde.ru/viewtopic.php?pid=3369#p3369" />
			<content type="html"><![CDATA[<div class="quotebox"><cite>pfelix68 пишет:</cite><blockquote><p>остались конструкции, типа:\<br />try<br />&nbsp; ...<br />finally<br />&nbsp; ...<br />end;<br />, ну и внутри нее точку останова пытался установить.</p></blockquote></div><p>Точки останова в таких фрагментах отлично устанавливаются и работают (возможно не на буквально try/finally, а на строки внутри).</p><div class="quotebox"><cite>pfelix68 пишет:</cite><blockquote><p>Интересно, есть ли способ, узнать КОНКРЕТНО, какую процедуру квик/система/qlua/. . . не находит, когда пишет: &quot;...&nbsp; &nbsp;Не найдена указанная процедура.&quot; . . . ???</p></blockquote></div><p>Есть. Но надо бы определиться кто ж выдает это сообщение и при выполнении какого кода.</p>]]></content>
			<author>
				<name><![CDATA[swerg]]></name>
				<uri>https://quik2dde.ru/profile.php?id=78</uri>
			</author>
			<updated>2021-11-17T17:28:55Z</updated>
			<id>https://quik2dde.ru/viewtopic.php?pid=3369#p3369</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)]]></title>
			<link rel="alternate" href="https://quik2dde.ru/viewtopic.php?pid=3368#p3368" />
			<content type="html"><![CDATA[<p>Еще нюанс. . . . ))<br />Меня вообще-то потряхивает больше не от наличия/отсутствия нужного (свободного) компилятора, а от того, найду ли я к нему графические либы, под которые наработок - страшно потерять.</p>]]></content>
			<author>
				<name><![CDATA[pfelix68]]></name>
				<uri>https://quik2dde.ru/profile.php?id=3324</uri>
			</author>
			<updated>2021-11-17T15:56:03Z</updated>
			<id>https://quik2dde.ru/viewtopic.php?pid=3368#p3368</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)]]></title>
			<link rel="alternate" href="https://quik2dde.ru/viewtopic.php?pid=3367#p3367" />
			<content type="html"><![CDATA[<div class="quotebox"><cite>swerg пишет:</cite><blockquote><div class="quotebox"><cite>pfelix68 пишет:</cite><blockquote><p>Знает ли кто-то вот эти тонкости отличия платформ 32 и х64 (или это связано с компилятором xe5)?</p></blockquote></div><p>И еще. Embarcadero теперь предоставляет честно бесплатную [url=https://www.embarcadero.com/ru/products/delphi/starter]Delphi Community Edition[/url].</p></blockquote></div><p>Обязательно присмотрюсь.</p>]]></content>
			<author>
				<name><![CDATA[pfelix68]]></name>
				<uri>https://quik2dde.ru/profile.php?id=3324</uri>
			</author>
			<updated>2021-11-17T15:43:41Z</updated>
			<id>https://quik2dde.ru/viewtopic.php?pid=3367#p3367</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)]]></title>
			<link rel="alternate" href="https://quik2dde.ru/viewtopic.php?pid=3366#p3366" />
			<content type="html"><![CDATA[<p>Спасибо огромное.<br />Знание -- сила.<br />В программировании -- не новичок, но . . .<br />Секреты тоже как-бы не новость, но, когда знание не на уровне рассуждений/домыслов - совсем другое дело.<br />Мой секрет, как понимаю (еще перепроверю), прятался в том (delphi писал Session disconnected, а еще &quot;в непонятном месте&quot; вываливался в окно с ассемблером), что код &quot;стряпал&quot; как из пулемета (заработало, -- и ладно, ДЛЛ вызывается - надо код писать, типа не до осмысливания), короче используя куски стороннего кода, остались конструкции, типа:\<br />try<br />&nbsp; ...<br />finally<br />&nbsp; ...<br />end;<br />, ну и внутри нее точку останова пытался установить.<br />Все ДЛЛ запустились, в обоих вариантах (основной код в одной,&nbsp; либо вызов через интерфейсную/промежуточную).<br />Оказалось, код основной либы &quot;не понравился&quot;.<br />Хоть истина и дороже, но не представляю как постепенно выхолащивать 300 кБ кода (строк, примерно 9К), чтоб найти причину. А там еще и системного кода много (х32 ориентированного)<br />Решил наполнять постепенно, сообразно новым задачам, тем более, что года 2 проектом не занимался, уже и подзабылось, что - где. Думаю, по-восстребованности оно и лучше будет.<br />Все основные (экспортируемые в ЛУА) функции &quot;система съела&quot;.&nbsp; . . . ???<br />Интересно, есть ли способ, узнать КОНКРЕТНО, какую процедуру квик/система/qlua/. . . не находит, когда пишет: &quot;...&nbsp; &nbsp;Не найдена указанная процедура.&quot; . . . ???</p>]]></content>
			<author>
				<name><![CDATA[pfelix68]]></name>
				<uri>https://quik2dde.ru/profile.php?id=3324</uri>
			</author>
			<updated>2021-11-17T15:41:20Z</updated>
			<id>https://quik2dde.ru/viewtopic.php?pid=3366#p3366</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)]]></title>
			<link rel="alternate" href="https://quik2dde.ru/viewtopic.php?pid=3365#p3365" />
			<content type="html"><![CDATA[<div class="quotebox"><cite>pfelix68 пишет:</cite><blockquote><p>Знает ли кто-то вот эти тонкости отличия платформ 32 и х64 (или это связано с компилятором xe5)?</p></blockquote></div><p>Вспомнил еще нюанс. <br />Начиная с какой-то версии (xe5 туда уже попадает) Embarcadero заменили внутренний формат типа <strong>String</strong>: теперь он хранит <strong>юникодные строки</strong>.<br />Соответственно при использовании Lua следует в pas-коде использовать только типы <strong>AnsiString</strong> и <strong>PAnsiChar</strong> ! Иначе будет фигня.</p><p>И еще. Embarcadero теперь предоставляет честно бесплатную [url=https://www.embarcadero.com/ru/products/delphi/starter]Delphi Community Edition[/url]. Так что не вижу особого смысла возиться с наверняка ломанной xe5. Можно взять сразу честно бесплатную самую свежую версию Delphi в редакции Community Edition и с удовольствием пользоваться <img src="https://quik2dde.ru/img/smilies/smile.png" width="15" height="15" alt="smile" /></p>]]></content>
			<author>
				<name><![CDATA[swerg]]></name>
				<uri>https://quik2dde.ru/profile.php?id=78</uri>
			</author>
			<updated>2021-11-17T04:49:37Z</updated>
			<id>https://quik2dde.ru/viewtopic.php?pid=3365#p3365</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)]]></title>
			<link rel="alternate" href="https://quik2dde.ru/viewtopic.php?pid=3364#p3364" />
			<content type="html"><![CDATA[<div class="quotebox"><cite>pfelix68 пишет:</cite><blockquote><p>Ну и по пути вопрос, если кто под xe5 (либо др. версиями embarcadero) отлаживал dll, как это делается? В нэт-е попадалось, но так у меня не получилось.</p></blockquote></div><p>Две есть стратегии:<br /></p><ol class="decimal"><li><p>В параметрах проекта, в параметрах отладки прописываете запускаемый файл info.exe. Тогда при старте отладки в дельфи у вас запустится QUIK и как запустите в нем скрипт с вашей библиотекой - так дельфи подхватит dll для отладки.</p></li><li><p>Просто запускаете QUIK, потом в дальфи в идете в Run -&gt; Attach to process, в списке процессов выбираете QUIK, дельфи подключается к нему как отладчик и далее тоже самое - как запустите в нем скрипт с вашей библиотекой.....</p></li></ol><p>Не важно каким вариантом идти. Как удобнее, хотя мне нравится второй.</p><p>А &quot;секрет&quot; тут скорее вот в чем: Delphi должна собирать dll сразу в ту папку, где ее подхватывает QUIK. Вернее сказать сразу в папку с QUIK. (dll при этом не должна быть подгружена скриптом или QUIK должен быть закрыт на время пересборки). В этом случае отладка точно пойдет нормально.<br />А если собрать в одну папку, потом перекопировать dll в QUIK и пытаться отлаживать - то тут бывают нюансы, бывает не работает отладка. Ну и режим debug сборки проекта выбирать надо, понятно.</p>]]></content>
			<author>
				<name><![CDATA[swerg]]></name>
				<uri>https://quik2dde.ru/profile.php?id=78</uri>
			</author>
			<updated>2021-11-16T13:22:30Z</updated>
			<id>https://quik2dde.ru/viewtopic.php?pid=3364#p3364</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)]]></title>
			<link rel="alternate" href="https://quik2dde.ru/viewtopic.php?pid=3363#p3363" />
			<content type="html"><![CDATA[<p><strong>pfelix68</strong>, приветствую вас на форуме!</p><p>Как-то много написали, а толком - ничего. Ни кода, ни конкретного примера минимальной библиотеки, где бы воспроизводилась проблема.</p><div class="quotebox"><cite>pfelix68 пишет:</cite><blockquote><p>Кстати, использовал я на х32 неявное связывание, но всё прекрасно работало, здесь же -- нифига.<br />Что посоветует почтенная публика?</p></blockquote></div><p>Раннее связывание - меньше кода. Но это не важно на самом деле. Проблема где-то не тут.</p><div class="quotebox"><cite>pfelix68 пишет:</cite><blockquote><p>Знает ли кто-то вот эти тонкости отличия платформ 32 и х64 (или это связано с компилятором xe5)?</p></blockquote></div><p>Нету разницы.<br />Разница скорее в том, что версия LUA изменилась. Для нее новые заголовочные файлы нужны.<br />И еще надо раздельно собирать для Lua 5.3 и Lua 5.4, с разными заголовочными файлами.<br />Ну или просто остановиться на одной из этих версий и только для нее собирать, не забывая выбирать соотв. версию Lua в терминале для выполнения скрипта.</p><p>Заголовочники можно стырить из QVCLua, например<br />[url]https://quik2dde.ru/viewtopic.php?id=111[/url]</p><p>В этой теме, увы, пример я пока не обновил с готовыми параметрами сборки.</p><p>Еще в Lua 5.3 / 5.4 поменялось API для инициализации библиотеки в luaopen_ХХХ<br />Вот в этой теме есть подробности<br />[url]https://quik2dde.ru/viewtopic.php?id=18[/url]</p>]]></content>
			<author>
				<name><![CDATA[swerg]]></name>
				<uri>https://quik2dde.ru/profile.php?id=78</uri>
			</author>
			<updated>2021-11-16T13:12:10Z</updated>
			<id>https://quik2dde.ru/viewtopic.php?pid=3363#p3363</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)]]></title>
			<link rel="alternate" href="https://quik2dde.ru/viewtopic.php?pid=3362#p3362" />
			<content type="html"><![CDATA[<p>Здравствуйте. Огромный привет всей почтенной публике и в особенности ее отдельным членам, а также организатору сего пространства.<br />Поделюсь своей проблемой.<br />жил-был, не тужил на платформе x32, но вот стали &quot;выживать&quot;, пришлось переходить на х64.<br />а наработок -- куча.<br />Короче, с ходу всё не запустилось. Платформа другая, компилятор вместо D7 - XE5, в luа кое-что поменялось.<br />Куда смотреть, - мозги в разнос. А хочется быстрей, не то, чтобы по-халявному, но . . .&nbsp; я думаю, меня поймут.<br />неделю бился, -- после смены вызовов (не без помощи, разумеется, и настоящего форума) выяснил . . .<br />библиотеку вызываю правильно, она подключается, но если я вызываю функцию, определенную в другой dll,<br />quik пишет что процедура не найдена.<br />Было время, когда я активно разрабатывал код, а ddl-ки под D7 отлаживать не умел (скорее не знал, что так можно), кроме того, незнание определенных тонкостей часто приводило к падению квика, в общем, не нашел я тогда лучшего способа перегружать либу (останавливать скрипт) иначе, чем связывая основной код через промежуточную dll.<br />Кстати, использовал я на х32 неявное связывание, но всё прекрасно работало, здесь же -- нифига.<br />Что посоветует почтенная публика?<br />Понятно, что можно в сторону написания единой dll.<br />Но, может, явное связывание поможет или какие-то дополнительные объявления в коде.<br />Была ли у кого-то аналогичная проблема?<br />Знает ли кто-то вот эти тонкости отличия платформ 32 и х64 (или это связано с компилятором xe5)?<br />Работы, по-ходу, впереди немало, хочется путь пооптимальней выбрать.<br />Ну и по пути вопрос, если кто под xe5 (либо др. версиями embarcadero) отлаживал dll, как это делается? В нэт-е попадалось, но так у меня не получилось.</p>]]></content>
			<author>
				<name><![CDATA[pfelix68]]></name>
				<uri>https://quik2dde.ru/profile.php?id=3324</uri>
			</author>
			<updated>2021-11-16T07:58:58Z</updated>
			<id>https://quik2dde.ru/viewtopic.php?pid=3362#p3362</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)]]></title>
			<link rel="alternate" href="https://quik2dde.ru/viewtopic.php?pid=2926#p2926" />
			<content type="html"><![CDATA[<div class="quotebox"><cite>Cave Cat пишет:</cite><blockquote><p>После этого пример заработал, но, возможно, для других проектов понадобится обновить также lualib.pas и lauxlib.pas, но где их взять, пока не знаю...</p></blockquote></div><p>Я вам советую воспользоваться моими хелперами: lualib53.pas и LuaHelpers.pas, которые можно взять тут: [url]https://github.com/untoxa/lua_share/tree/master/common[/url]</p><p>это части проекта lua_share: [url]https://github.com/untoxa/lua_share[/url] он прекрасно собирается fpc/lazarus.</p>]]></content>
			<author>
				<name><![CDATA[toxa]]></name>
				<uri>https://quik2dde.ru/profile.php?id=3172</uri>
			</author>
			<updated>2020-12-24T14:09:14Z</updated>
			<id>https://quik2dde.ru/viewtopic.php?pid=2926#p2926</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)]]></title>
			<link rel="alternate" href="https://quik2dde.ru/viewtopic.php?pid=2916#p2916" />
			<content type="html"><![CDATA[<p>Надо будет дополнить сборки и инструкции, да.</p><div class="quotebox"><cite>Cave Cat пишет:</cite><blockquote><p>возможно, для других проектов понадобится обновить также lualib.pas и lauxlib.pas, но где их взять, пока не знаю...</p></blockquote></div><p>Таких файлов нет.<br />В портированных в паскаль заголовках для Lua как-то принято все складывать один файл LuaXX.pas, без разбивки на несколько. Ну т.е. Lua53.pas содержит в себе все, что есть в lauxlib.h, lua.h, luaconf.h и lualib.h.</p>]]></content>
			<author>
				<name><![CDATA[admin]]></name>
				<uri>https://quik2dde.ru/profile.php?id=2</uri>
			</author>
			<updated>2020-12-21T04:24:09Z</updated>
			<id>https://quik2dde.ru/viewtopic.php?pid=2916#p2916</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)]]></title>
			<link rel="alternate" href="https://quik2dde.ru/viewtopic.php?pid=2915#p2915" />
			<content type="html"><![CDATA[<p>Здравствуйте!<br />Можно ли обновить инструкцию и архив с примером проекта dll в Lazarus для Quik 8.7 и старше?</p><p>P.S. Погуглив, разобрался сам.<br />Нужно добыть файл lua53.pas, например, здесь: [url]https://github.com/malcome/Lua4Lazarus/archive/R150205.zip[/url],<br />и положить его в папку проекта<br />Соответственно, в секции uses нужно заменить везде lua на lua53.<br />В коде регистрации функций нужно заменить<br /></p><div class="codebox"><pre><code>luaL_openlib(L, PChar(&#039;SimpleDelphiLua&#039;), @ls_lib, 0);
lua_pop(L, 1);</code></pre></div><p>на <br /></p><div class="codebox"><pre><code>lua_newtable(L);
luaL_setfuncs(L, @ls_lib, 0);
lua_pushvalue(L,-1);
lua_setglobal(L, &#039;SimpleDelphiLua&#039;);</code></pre></div><p>После этого пример заработал, но, возможно, для других проектов понадобится обновить также lualib.pas и lauxlib.pas, но где их взять, пока не знаю...</p>]]></content>
			<author>
				<name><![CDATA[Cave Cat]]></name>
				<uri>https://quik2dde.ru/profile.php?id=3253</uri>
			</author>
			<updated>2020-12-18T21:26:23Z</updated>
			<id>https://quik2dde.ru/viewtopic.php?pid=2915#p2915</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)]]></title>
			<link rel="alternate" href="https://quik2dde.ru/viewtopic.php?pid=2733#p2733" />
			<content type="html"><![CDATA[<p>Здравствуйте.<br />По Вашему описанию создания dll на lazarus сделал библиотеку. Все прекрасно работало. Под quik8.5.2(lua53) пытался изменить сам не получается. Спотыкается на luaL_openlib. По результатам поиска в инете пробовал заменить на<br />&nbsp; &nbsp; luaL_setfuncs(L, @ls_lib, 0);<br />&nbsp; &nbsp; lua_setglobal(L, PChar(&#039;MySoundLib&#039;)); <br />то же не правильно.<br />Что посоветуете?<br />(вместо 3-х файлов *.pas использовал lua53.pas)</p><p>Спасибо.</p>]]></content>
			<author>
				<name><![CDATA[fin]]></name>
				<uri>https://quik2dde.ru/profile.php?id=3213</uri>
			</author>
			<updated>2020-05-19T07:39:09Z</updated>
			<id>https://quik2dde.ru/viewtopic.php?pid=2733#p2733</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)]]></title>
			<link rel="alternate" href="https://quik2dde.ru/viewtopic.php?pid=2471#p2471" />
			<content type="html"><![CDATA[<p>наваял, вот, для delphi/fpc хелперы, может кому пригодится. код раз в 10 более читаемый и безопасный.<br /></p><div class="codebox"><pre><code>unit LuaHelpers;

interface

uses 
  Classes, SysUtils,
  LuaLib;

type
  TLuaState     = LuaLib.lua_State;

  TLuaContext   = class;
  TLuaTable     = class;

  TLuaField     = class(tObject)
  private
    fContext    : TLuaContext;
    fFieldType  : integer;
    fNumber     : double;
    fBool       : boolean;
    fString     : ansistring;
    fTable      : TLuaTable;
    fIndex      : integer;

    function    getabsindex(AIndex: integer): integer;
    function    fExtractField(AIndex: integer): TLuaField;
    function    fGetField(AIndex: integer; const AName: ansistring): TLuaField;
  public
    constructor create(AContext: TLuaContext);
    destructor  destroy; override;
    function    AsBoolean(adefault: boolean = false): boolean;
    function    AsInteger(adefault: integer = 0): integer;
    function    AsNumber(adefault: double = 0.0): double;
    function    AsString(const adefault: ansistring = &#039;&#039;): ansistring;
    function    AsTable: TLuaTable;

    property    FieldType: integer read fFieldType;
    property    FieldByName[AIndex: integer; const AName: ansistring]: TLuaField read fGetField; default;
  end;

  TLuaTable     = class(tObject)
  private
    fContext    : TLuaContext;
    fField      : TLuaField;
    fIndex      : integer;
    fPopSize    : integer;
    fCurField   : TLuaField;
    fStackAlloc : boolean;

    function    getabsindex(AIndex: integer): integer;
    procedure   fSetIndex(AIndex: integer);
    function    fGetFieldByName(const AName: ansistring): TLuaField;
    function    fGetField: TLuaField;
    function    fGetSelf: TLuaTable;
  protected
    property    Field: TLuaField read fGetField;
  public
    constructor create(AContext: TLuaContext); overload;
    constructor create(AContext: TLuaContext; AIndex: integer); overload;
    constructor create(AContext: TLuaContext; ALuaTable: TLuaTable; const AName: ansistring); overload;
    constructor create(AContext: TLuaContext; const AGlobalName: ansistring); overload;
    destructor  destroy; override;

    function    FindFirst: boolean;
    function    FindNext: boolean;
    procedure   FindClose;

    function    FindField(const AName: ansistring): boolean;

    function    CallMethodSafe(const AName: ansistring; const AArgs: array of const; AResCount: integer; var error: ansistring; AResType: integer = LUA_TNONE): boolean;

    property    CurrentTable: TLuaTable read fGetSelf;
    property    Index: integer read fIndex write fSetIndex;
    property    FieldByName[const AName: ansistring]: TLuaField read fGetFieldByName; default;
    property    CurrentField: TLuaField read fCurField;
    property    Context: TLuaContext read fContext;
  end;

  TLuaContext   = class(tObject)
  private
    fLuaState   : TLuaState;
    fField      : TLuaField;
    function    fGetStackByIndex(AIndex: integer): TLuaField;
    function    fGetGlobalByName(const AName: ansistring): TLuaField;
    function    fGetSelf: TLuaContext;
  public
    constructor create(ALuaState: TLuaState);
    destructor  destroy; override;

    function    PushArgs(const aargs: array of const): integer;

    function    PushTable(aKVTable: tStringList): integer; overload;
    function    PushTable(const aargs: array of const): integer; overload;  // aargs must look like: [&#039;name1&#039;, value1, &#039;name2&#039;, value2]

    function    Call(const AName: ansistring; const AArgs: array of const; AResCount: integer; AResType: integer = LUA_TNONE): boolean;
    function    CallSafe(const AName: ansistring; const AArgs: array of const; AResCount: integer; var error: ansistring; AResType: integer = LUA_TNONE): boolean;

    function    ExecuteSafe(const AScript: ansistring; AResCount: integer; var error: ansistring): boolean;

    procedure   CleanUp(ACount: integer);

    procedure   SetGlobal(AIndex: integer; const AName: ansistring);
    procedure   ResetGlobal(const AName: ansistring);

    property    CurrentContext: TLuaContext read fGetSelf;
    property    CurrentState: TLuaState read fLuaState;
    property    Stack[AIndex: integer]: TLuaField read fGetStackByIndex; default;
    property    Globals[const AName: ansistring]: TLuaField read fGetGlobalByName;
  end;

  TOnTableItemEx = function(ATable: TLuaTable): boolean of object;

implementation

function  StrToFloatDef(const astr: ansistring; adef: extended): extended;
begin if not TextToFloat(pAnsiChar(astr), result, fvExtended) then result:= adef; end;

{ TLuaField }

constructor TLuaField.create(AContext: TLuaContext);
begin
  inherited create;
  fContext:= AContext;
  fTable:= nil;
  fFieldType:= LUA_TNONE;
  fNumber:= 0;
  fBool:= false;
  setlength(fString, 0);
end;

destructor TLuaField.destroy;
begin
  if assigned(fTable) then freeandnil(fTable);
  inherited destroy;
end;

function TLuaField.getabsindex(AIndex: integer): integer;
begin
  if ((AIndex = LUA_GLOBALSINDEX) or (AIndex = LUA_REGISTRYINDEX)) then result := AIndex
  else if (AIndex &lt; 0) then result := AIndex + lua_gettop(fContext.CurrentState) + 1
  else result := AIndex;
end;

function TLuaField.fExtractField(AIndex: integer): TLuaField;
var len : cardinal;
begin
  fFieldType:= lua_type(fContext.CurrentState, AIndex);
  case fFieldType of
    LUA_TNUMBER   : fNumber := lua_tonumber(fContext.CurrentState, AIndex);
    LUA_TBOOLEAN  : fBool := lua_toboolean(fContext.CurrentState, AIndex);
    LUA_TSTRING   : begin
                      len:= 0;
                      SetString(fString, lua_tolstring(fContext.CurrentState, AIndex, len), len);
                    end;
    LUA_TTABLE    : begin
                      if not assigned(fTable) then fTable:= TLuaTable.create(fContext, AIndex)
                                              else fTable.Index:= AIndex;
                    end;
    LUA_TFUNCTION : fIndex:= getabsindex(aindex);
    else            fFieldType:= LUA_TNONE;
  end;
  result:= Self;
end;

function TLuaField.fGetField(AIndex: integer; const AName: ansistring): TLuaField;
begin
  result:= Self;
  lua_pushstring(fContext.CurrentState, pAnsiChar(AName));
  lua_gettable(fContext.CurrentState, AIndex);
  try
    case lua_type(fContext.CurrentState, -1) of
      LUA_TTABLE : fFieldType:= LUA_TNONE;
      else         result:= fExtractField(-1) // only simple types allowed
    end;
  finally lua_pop(fContext.CurrentState, 1); end;
end;

function TLuaField.AsBoolean(adefault: boolean): boolean;
begin
  case fFieldType of
    LUA_TBOOLEAN : result:= fBool;
    LUA_TNUMBER  : result:= (fNumber &lt;&gt; 0);
    LUA_TSTRING  : result:= (AnsiCompareText(fString, &#039;TRUE&#039;) = 0);
    else           result:= adefault;
  end;
end;

function TLuaField.AsInteger(adefault: integer): integer;
begin result:= round(AsNumber(adefault)); end;

function TLuaField.AsNumber(adefault: double): double;
begin
  case fFieldType of
    LUA_TBOOLEAN : result:= integer(fBool);
    LUA_TNUMBER  : result:= fNumber;
    LUA_TSTRING  : result:= StrToFloatDef(fString, adefault);
    else           result:= adefault;
  end;
end;

function TLuaField.AsString(const adefault: ansistring): ansistring;
const boolval : array[boolean] of ansistring = (&#039;FALSE&#039;, &#039;TRUE&#039;);
begin
  case fFieldType of
    LUA_TBOOLEAN : result:= boolval[fBool];
    LUA_TNUMBER  : result:= FloatToStr(fNumber);
    LUA_TSTRING  : result:= fString;
    else           result:= &#039;&#039;;
  end;
end;

function TLuaField.AsTable: TLuaTable;
begin
  if (fFieldType = LUA_TTABLE) then result:= fTable
                               else result:= nil;
end;

{ TLuaTable }

constructor TLuaTable.create(AContext: TLuaContext);
begin
  inherited create;
  fContext:= AContext;
  fField:= nil;
  fCurField:= nil;
  fIndex:= 0;
  fStackAlloc:= false;
  fPopSize:= 0;
end;

constructor TLuaTable.create(AContext: TLuaContext; AIndex: integer);
begin
  inherited create;
  fContext:= AContext;
  fField:= nil;
  fCurField:= nil;
  fIndex:= getabsindex(AIndex);
  fStackAlloc:= false;
  fPopSize:= 0;
end;

constructor TLuaTable.create(AContext: TLuaContext; ALuaTable: TLuaTable; const AName: ansistring);
begin
  inherited create;
  fContext:= AContext;
  fField:= nil;
  fCurField:= nil;
  fIndex:= 0;
  fStackAlloc:= false;
  fPopSize:= 0;

  lua_pushstring(fContext.CurrentState, pAnsiChar(AName));
  lua_gettable(fContext.CurrentState, ALuaTable.Index);
  if lua_istable(fContext.CurrentState, -1) then begin
    fIndex:= getabsindex(-1);
    fStackAlloc:= true;
  end else begin
    lua_pop(fContext.CurrentState, 1);
    raise Exception.CreateFmt(&#039;Field %s is not a table&#039;, [AName]);
  end;
end;

constructor TLuaTable.create(AContext: TLuaContext; const AGlobalName: ansistring);
begin
  inherited create;
  fContext:= AContext;
  fField:= nil;
  fCurField:= nil;
  fIndex:= 0;
  fStackAlloc:= false;
  fPopSize:= 0;

  lua_getglobal(fContext.CurrentState, pAnsiChar(AGlobalName));
  if lua_istable(fContext.CurrentState, -1) then begin
    fIndex:= getabsindex(-1);
    fStackAlloc:= true;
  end else begin
    lua_pop(fContext.CurrentState, 1);
    raise Exception.CreateFmt(&#039;Global %s is not a table&#039;, [AGlobalName]);
  end;
end;

destructor TLuaTable.destroy;
begin
  if fStackAlloc then lua_pop(fContext.CurrentState, 1);
  fCurField:= nil;
  if assigned(fField) then freeandnil(fField);
  inherited destroy;
end;

function TLuaTable.getabsindex(AIndex: integer): integer;
begin
  if ((AIndex = LUA_GLOBALSINDEX) or (AIndex = LUA_REGISTRYINDEX)) then result := AIndex
  else if (AIndex &lt; 0) then result := AIndex + lua_gettop(fContext.CurrentState) + 1
  else result := AIndex;
end;

procedure TLuaTable.fSetIndex(AIndex: integer);
begin fIndex:= getabsindex(AIndex); end;

function TLuaTable.fGetField: TLuaField;
begin
  if not assigned(fField) then fField:= TLuaField.create(fContext);
  result:= fField;
end;

function TLuaTable.fGetFieldByName(const AName: ansistring): TLuaField;
begin result:= Field.FieldByName[fIndex, AName]; end;

function TLuaTable.fGetSelf: TLuaTable;
begin result:= Self; end;

function TLuaTable.FindFirst: boolean;
begin
  FindClose;
  lua_pushnil(fContext.CurrentState);
  lua_pushnil(fContext.CurrentState);  // imitate &quot;value&quot;
  result:= FindNext;
end;

function TLuaTable.FindNext: boolean;
begin
  lua_pop(fContext.CurrentState, 1);   // pop previous &quot;value&quot;
  result:= (lua_next(fContext.CurrentState, Index) &lt;&gt; 0);
  if result then begin
    fCurField:= Field.fExtractField(-1);
    fPopSize:= 2;                      // leave &quot;key&quot; on stack, need to cleanup if findclose()
  end else begin
    fCurField:= nil;
    fPopSize:= 0;                      // no need to cleanup, stack is empty
  end;
end;

procedure TLuaTable.FindClose;
begin
  if (fPopSize &gt; 0) then lua_pop(fContext.CurrentState, fPopSize);
  fPopSize:= 0;
end;

function TLuaTable.FindField(const AName: ansistring): boolean;
begin
  lua_pushstring(fContext.CurrentState, pAnsiChar(AName));
  lua_gettable(fContext.CurrentState, Index);
  fCurField:= Field.fExtractField(-1);
  fPopSize:= 1;
  result:= true;
end;

function TLuaTable.CallMethodSafe(const AName: ansistring; const AArgs: array of const; AResCount: integer; var error: ansistring; AResType: integer): boolean;
var len: cardinal;
begin
  if (AResCount &lt; 0) then AResCount:= LUA_MULTRET;
  lua_getfield(fContext.CurrentState, Index, pAnsiChar(AName));
  lua_pushvalue(fContext.CurrentState, Index);
  fContext.PushArgs(AArgs);
  if (lua_pcall(fContext.CurrentState, length(aargs) + 1, AResCount, 0) = 0) then begin
    if (AResType &lt;&gt; LUA_TNONE) then begin
      result:= (lua_type(fContext.CurrentState, -1) = AResType);
      if not result and (AResCount &gt; 0) then lua_pop(fContext.CurrentState, AResCount);
    end else result:= true;
  end else begin
    len:= 0;
    SetString(error, lua_tolstring(fContext.CurrentState, -1, len), len);
    lua_pop(fContext.CurrentState, 1);
    result:= false;
  end;
end;

{ TLuaContext }

constructor TLuaContext.create(ALuaState: TLuaState);
begin
  inherited create;
  fLuaState:= ALuaState;
  fField:= nil;
end;

destructor TLuaContext.destroy;
begin
  if assigned(fField) then freeandnil(fField);
  inherited destroy;
end;

function TLuaContext.fGetStackByIndex(AIndex: integer): TLuaField;
begin
  if not assigned(fField) then fField:= TLuaField.create(Self);
  result:= fField.fExtractField(AIndex);
end;

function TLuaContext.fGetGlobalByName(const AName: ansistring): TLuaField;
begin
  if not assigned(fField) then fField:= TLuaField.create(Self);
  lua_getglobal(fLuaState, pAnsiChar(AName));
  result:= fField.fExtractField(-1);  // may be problems with tables?
  lua_pop(fLuaState, 1);
end;

function TLuaContext.fGetSelf: TLuaContext;
begin result:= Self; end;

function TLuaContext.PushArgs(const aargs: array of const): integer;
var i : integer;
begin
  for i:= 0 to length(aargs) - 1 do begin
    with aargs[i] do begin
      case vType of
        vtInteger    : lua_pushinteger(fLuaState, vInteger);
        vtInt64      : lua_pushnumber(fLuaState, vInt64^);
        vtPChar      : lua_pushstring(fLuaState, pAnsiChar(vPChar));
        vtAnsiString : lua_pushstring(fLuaState, pAnsiChar(vAnsiString));
        vtExtended   : lua_pushnumber(fLuaState, vExtended^);
        vtBoolean    : lua_pushboolean(fLuaState, vBoolean);
        vtObject     : if assigned(vObject) then begin
                         if (vObject is tStringList) then PushTable(tStringList(vObject))
                                                     else lua_pushnil(fLuaState);
                       end else lua_pushnil(fLuaState);
        else           lua_pushnil(fLuaState);
      end;
    end;
  end;
  result:= length(aargs);
end;

function TLuaContext.PushTable(aKVTable: tStringList): integer;
var tmp : ansistring;
    p   : pAnsiChar;
    i   : integer;
begin
  result:= 0;
  if assigned(aKVTable) then with aKVTable do begin
    lua_createtable(fLuaState, Count, 0);
    for i := 0 to count - 1 do begin
      tmp:= Names[i];
      lua_pushstring(fLuaState, pAnsiChar(tmp));
      tmp:= Values[tmp];
      if (length(tmp) &gt; 0) and (tmp[1]=&#039;&quot;&#039;) then begin
        p:= pAnsiChar(tmp);
        tmp:= AnsiExtractQuotedStr(p, &#039;&quot;&#039;);
      end;
      lua_pushstring(fLuaState, pAnsiChar(tmp));
      lua_settable(fLuaState, -3);
    end;
    result:= 1;
  end;
end;

function TLuaContext.PushTable(const aargs: array of const): integer;
var i, count : integer;
begin
  count:= (length(aargs) div 2) * 2;                   // must be even, if not - last pair is not pushed!
  lua_createtable(fLuaState, count div 2, 0);
  for i:= 0 to count - 1 do begin
    with aargs[i] do
      case vType of
        vtInteger    : lua_pushinteger(fLuaState, vInteger);
        vtInt64      : lua_pushnumber(fLuaState, vInt64^);
        vtPChar      : lua_pushstring(fLuaState, pAnsiChar(vPChar));
        vtAnsiString : lua_pushstring(fLuaState, pAnsiChar(vAnsiString));
        vtExtended   : lua_pushnumber(fLuaState, vExtended^);
        vtBoolean    : lua_pushboolean(fLuaState, vBoolean);
        else           lua_pushnil(fLuaState);
      end;
    if (i mod 2 = 1) then lua_settable(fLuaState, -3); // set on every odd i
  end;
  result:= 1;
end;

function TLuaContext.Call(const AName: ansistring; const AArgs: array of const; AResCount: integer; AResType: integer): boolean;
begin
  if (AResCount &lt; 0) then AResCount:= LUA_MULTRET;
  lua_getglobal(fLuaState, pAnsiChar(AName));                              // get function index
  PushArgs(aargs);                                                         // push parameters
  lua_call(fLuaState, length(aargs), AResCount);                           // call function
  if (AResType &lt;&gt; LUA_TNONE) then begin
    result:= (lua_type(fLuaState, -1) = AResType);
    if not result and (AResCount &gt; 0) then lua_pop(fLuaState, AResCount);  // cleanup stack if unexpected type returned
  end else result:= true;
end;

function TLuaContext.CallSafe(const AName: ansistring; const AArgs: array of const; AResCount: integer; var error: ansistring; AResType: integer): boolean;
var len: cardinal;
begin
  if (AResCount &lt; 0) then AResCount:= LUA_MULTRET;
  lua_getglobal(fLuaState, pAnsiChar(AName));                              // get function index
  PushArgs(aargs);                                                         // push parameters
  if (lua_pcall(fLuaState, length(aargs), AResCount, 0) = 0) then begin    // call function in &quot;protected mode&quot;
    if (AResType &lt;&gt; LUA_TNONE) then begin
      result:= (lua_type(fLuaState, -1) = AResType);
      if not result and (AResCount &gt; 0) then lua_pop(fLuaState, AResCount);// cleanup stack if unexpected type returned
    end else result:= true;
  end else begin
    len:= 0;
    SetString(error, lua_tolstring(fLuaState, -1, len), len);
    lua_pop(fLuaState, 1);
    result:= false;
  end;
end;

function TLuaContext.ExecuteSafe(const AScript: ansistring; AResCount: integer; var error: ansistring): boolean;
var len: cardinal;
begin
  result:= (luaL_loadstring(fLuaState, pAnsiChar(AScript)) = 0);
  if result then begin
    result:= (lua_pcall(fLuaState, 0, AResCount, 0) = 0);
    if not result then begin
      len:= 0;
      SetString(error, lua_tolstring(fLuaState, -1, len), len);
      lua_pop(fLuaState, 1);
      result:= false;
    end;
  end else error:= &#039;Script loading failed&#039;;
end;

procedure TLuaContext.CleanUp(ACount: integer);
begin lua_pop(fLuaState, ACount); end;

procedure TLuaContext.SetGlobal(AIndex: integer; const AName: ansistring);
begin
  lua_pushvalue(fLuaState, AIndex);
  lua_setglobal(fLuaState, pAnsiChar(AName));
end;

procedure TLuaContext.ResetGlobal(const AName: ansistring);
begin
  lua_pushnil(fLuaState);
  lua_setglobal(fLuaState, pAnsiChar(AName));
end;

end.</code></pre></div><p>примерно так может выглядеть обработчик колбэка OnQuote, при использовании хелперов, все потроха LUA скрываются:<br /></p><div class="codebox"><pre><code>function tSomeLuaClass.OnQuote(LuaState: TLuaState): Integer;
var classcode, seccode : ansistring;
  procedure dumptable(acontext: tLuaContext; atable: tLuaTable; const aparamname: ansistring);
  var rowtbl : tLuaTable;
  begin
    with TLuaTable.create(acontext, atable, aparamname) do try
      if FindFirst then try
        repeat
          if assigned(CurrentField) then begin
            rowtbl:= CurrentField.AsTable;
            if assigned(rowtbl) then 
              log(&#039;%s  price: %s qty: %s&#039;, [aparamname, rowtbl[&#039;price&#039;].AsString, rowtbl[&#039;quantity&#039;].AsString]);
          end;
        until not FindNext;
      finally FindClose; end;
    finally free; end;
  end;
begin
  with tLuaContext.create(LuaState) do try
    classcode := Stack[1].AsString;
    seccode   := Stack[2].AsString;
    log(&#039;OnQuote: Class: %s Code: %s&#039;, [classcode, seccode]);
    if Call(&#039;getQuoteLevel2&#039;, [classcode, seccode], 1, LUA_TTABLE) then try
      with Stack[-1].AsTable do begin
        if (FieldByName[&#039;bid_count&#039;].AsInteger &gt; 0) then
          dumptable(CurrentContext, CurrentTable, &#039;bid&#039;);
        if (FieldByName[&#039;offer_count&#039;].AsInteger &gt; 0) then
          dumptable(CurrentContext, CurrentTable, &#039;offer&#039;);
      end;
    finally CleanUp(1); end;
  finally free; end;
  result:= 0;
end;</code></pre></div>]]></content>
			<author>
				<name><![CDATA[toxa]]></name>
				<uri>https://quik2dde.ru/profile.php?id=3172</uri>
			</author>
			<updated>2019-11-01T15:50:23Z</updated>
			<id>https://quik2dde.ru/viewtopic.php?pid=2471#p2471</id>
		</entry>
</feed>
