<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<title type="html"><![CDATA[QUIK -> DDE &mdash; Ошибка ACCESS VIOLATION при подключении внешней dll в lua]]></title>
	<link rel="self" href="https://quik2dde.ru/extern.php?action=feed&amp;tid=417&amp;type=atom" />
	<updated>2022-10-19T19:14:19Z</updated>
	<generator>PunBB</generator>
	<id>https://quik2dde.ru/viewtopic.php?id=417</id>
		<entry>
			<title type="html"><![CDATA[Re: Ошибка ACCESS VIOLATION при подключении внешней dll в lua]]></title>
			<link rel="alternate" href="https://quik2dde.ru/viewtopic.php?pid=3858#p3858" />
			<content type="html"><![CDATA[<p>Для удобства выложу исправленный код dll и исправленный lua-скрипт, надеюсь кому нибудь пригодится</p><p>Библиотека написана под lua версии 5.4</p><p>UDP 20.10.2022: обновлён lua-скрипт </p><div class="codebox"><pre><code>#include &lt;windows.h&gt;
#include &lt;process.h&gt;

// необходимые для Lua константы
#define LUA_LIB
#define LUA_BUILD_AS_DLL

// заголовочные файлы LUA
extern &quot;C&quot; {
#include &quot;Lua\lua.h&quot;
#include &quot;Lua\lualib.h&quot;
#include &quot;Lua\lauxlib.h&quot;
}

TCHAR CommandMemory[] = TEXT(&quot;Memory4CommandGetCandles&quot;);
TCHAR CandlesMemory[] = TEXT(&quot;Memory4GetCandles&quot;);

HANDLE CommandFileMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 64, CommandMemory);
HANDLE CandlesFileMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 128, CandlesMemory);

// точка входа DLL
BOOL APIENTRY DllMain(HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    return TRUE;
}

// функция отправки команд из программы в Lua скрипт
static int forLua_GetCommand(lua_State* L)
{
    if (CommandFileMap) // если память существует
    {
        // считываем данные из памяти и переводим в набор байтов
        PBYTE pb = (PBYTE)(MapViewOfFile(CommandFileMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 64));
        if (pb != NULL) // если есть данные
        {
            if (pb[0] == 0) // если первый байт нулевой
            {
                lua_pushstring(L, &quot;&quot;); // отправляем пустую строку в Lua скрипт
            }
            else
            {
                lua_pushstring(L, (char*)(pb));//иначе отправляем набор байтов в Lua скрипт
            }


            UnmapViewOfFile(pb); // закрываем доступ к данным
        }
        else
        {
            lua_pushstring(L, &quot;&quot;); // иначе отправляем пустую строку в Lua скрипт
        }
    }
    else
    {
        lua_pushstring(L, &quot;&quot;); // иначе отправляем пустую строку в Lua скрипт
    }

    return(1);
}

// функция очистки памяти для отправки команд
static int forLua_ClearCommand(lua_State* L)
{
    if (CommandFileMap)//если память существует
    {
        // считываем данные из памяти и переводим в набор байтов
        PBYTE pb = (PBYTE)(MapViewOfFile(CommandFileMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 64));

        if (pb != NULL) // если есть данные
        {
            // заполняем нулевыми байтами
            for (int i = 0; i &lt; 64; i++)
            {
                pb[i] = &#039;\0&#039;;
            }

            UnmapViewOfFile(pb); // закрываем доступ
        }
    }

    return(0);
}

// функция отправки свечек из lua в программу
static int forLua_SendCandle(lua_State* L)
{
    if (CandlesFileMap) // если память существует
    {
        // считываем данные из памяти и переводим в набор байтов
        PBYTE pb = (PBYTE)(MapViewOfFile(CandlesFileMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 128));
        if (pb != NULL) // если есть данные
        {
            const char* Candle = lua_tostring(L, 1); // переменная для хранения данных
            int Size = 0;

            for (int i = 0; i &lt; 128; i++)
            {
                if (Candle[i] == 0)
                {
                    break;
                }
                else
                {
                    Size++;
                }
            }

            memcpy(pb + 1, Candle, Size); // копируем 
            UnmapViewOfFile(pb); // закрываем доступ
        }
    }

    return(0);
}

// регистрация реализованных в dll функций, чтобы они стали &quot;видимы&quot; для Lua
static const struct luaL_Reg ls_lib[] = {
    { &quot;GetCommand&quot;, forLua_GetCommand },
    { &quot;ClearCommand&quot;, forLua_ClearCommand },
    { &quot;SendCandle&quot;, forLua_SendCandle },
    { nullptr, nullptr }
};

// регистрация названия библиотеки, видимого в скрипте Lua
extern &quot;C&quot; LUALIB_API int luaopen_GetCandlesDll(lua_State * L) {
    lua_newtable(L);
    luaL_setfuncs(L, ls_lib, 0);
    lua_pushvalue(L, -1);
    lua_setglobal(L, &quot;GetCandlesDll&quot;);
    return 1;
}</code></pre></div><div class="codebox"><pre><code>require(&quot;GetCandlesDll&quot;);

Candle = &quot;&quot;;
LastQty = 1;
CurrentQty = 1;
DataSet = nil;
IsOnline = false;
IsRun = true;

Minute = &quot;&quot;;
Hour = &quot;&quot;;

Day = &quot;&quot;;
Month = &quot;&quot;;
Year = &quot;&quot;;

High = &quot;&quot;;
Low = &quot;&quot;;
Open = &quot;&quot;;
Close = &quot;&quot;;

ClassName = &quot;TQBR&quot;;
ToolName = &quot;YNDX&quot;;

function main()
    while IsRun do    
        if tostring(GetCandlesDll.GetCommand()) == &quot;run&quot; then
            message(&quot;bot is started&quot;);
            IsOnline = true;
            DataSet = CreateDataSource(ClassName, ToolName, INTERVAL_M1);
            GetCandlesDll.ClearCommand();
        end;
        
        if BotStopCheck() then 
            StopScript();
        end;
        
        if IsOnline == true then
            CurrentQty = DataSet:Size() - 1;

            if CurrentQty ~= nil and CurrentQty &gt; LastQty then
                for i = LastQty, CurrentQty do
                    while tostring(GetCandlesDll.GetCommand()) ~= &quot;send&quot; do
                        if i == 1 or BotStopCheck() then 
                            break;
                        end;

                        sleep(1);
                    end;

                    if BotStopCheck() then 
                        StopScript();
                        break;
                    end;
                    
                    GetCandlesDll.ClearCommand();

                    LastQty = i == CurrentQty and CurrentQty | LastQty;        

                    Minute = CheckNumber(DataSet:T(i).min);
                    Hour = CheckNumber(DataSet:T(i).hour);

                    Day = CheckNumber(DataSet:T(i).day);
                    Month = CheckNumber(DataSet:T(i).month);
                    Year = tostring(DataSet:T(i).year);
                    
                    High = tostring(DataSet:H(i));
                    Low = tostring(DataSet:L(i));
                    Open = tostring(DataSet:O(i));
                    Close = tostring(DataSet:C(i));
                    
                    Candle = Day..&quot;.&quot;..Month..&quot;.&quot;..Year..&quot; &quot;..Hour..&quot;:&quot;..Minute..&quot;:&quot;..&quot;00&quot;..&quot;;&quot;..High..&quot;;&quot;..Low..&quot;;&quot;..Open..&quot;;&quot;..Close;

                    GetCandlesDll.SendCandle(Candle);

                    sleep(1);
                end;
            end;
        end;

        sleep(1);
    end;
end;

function OnInit()
    GetCandlesDll.ClearCommand();
end

function OnStop()
    IsRun = false;
end;

function CheckNumber(Number)
    if (tonumber(Number) &lt; 10) then    
        return &quot;0&quot; .. tostring(Number);
    else
        return tostring(Number);
    end;
end;

function StopScript()
    message(&quot;bot is stopped&quot;);
    GetCandlesDll.ClearCommand()
    IsOnline = false;
    LastQty = 1;
    Candle = &quot;&quot;;

    if DataSet ~= nil then 
        DataSet:Close(); 
    end;
end;


function BotStopCheck()
    return tostring(GetCandlesDll.GetCommand()) == &quot;stop&quot;;
end;</code></pre></div>]]></content>
			<author>
				<name><![CDATA[infinitywaytrader]]></name>
				<uri>https://quik2dde.ru/profile.php?id=3376</uri>
			</author>
			<updated>2022-10-19T19:14:19Z</updated>
			<id>https://quik2dde.ru/viewtopic.php?pid=3858#p3858</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Ошибка ACCESS VIOLATION при подключении внешней dll в lua]]></title>
			<link rel="alternate" href="https://quik2dde.ru/viewtopic.php?pid=3857#p3857" />
			<content type="html"><![CDATA[<div class="quotebox"><cite>infinitywaytrader пишет:</cite><blockquote><p>надо было использовать lua54.lib</p></blockquote></div><p>Либо переключиться в терминале QUIK на выполнение скрипта на Lua 5.3.</p><p>Спасибо что поделились на форуме результатами и решением.</p>]]></content>
			<author>
				<name><![CDATA[swerg]]></name>
				<uri>https://quik2dde.ru/profile.php?id=78</uri>
			</author>
			<updated>2022-10-19T18:43:04Z</updated>
			<id>https://quik2dde.ru/viewtopic.php?pid=3857#p3857</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Ошибка ACCESS VIOLATION при подключении внешней dll в lua]]></title>
			<link rel="alternate" href="https://quik2dde.ru/viewtopic.php?pid=3856#p3856" />
			<content type="html"><![CDATA[<p>Нашёл решение своей проблемы, для корректного подключения dll в lua-скрипте надо было использовать lua54.lib, это раз.<br />Два - немного подредактировать регистрацию в коде самой&nbsp; dll, то есть на выходе получается такой код</p><div class="codebox"><pre><code>// регистрация названия библиотеки, видимого в скрипте Lua
extern &quot;C&quot; LUALIB_API int luaopen_GetCandlesDll(lua_State * L) {
    lua_newtable(L);
    luaL_setfuncs(L, ls_lib, 0);
    lua_pushvalue(L, -1);
    lua_setglobal(L, &quot;GetCandlesDll&quot;);
    return 1;
}</code></pre></div>]]></content>
			<author>
				<name><![CDATA[infinitywaytrader]]></name>
				<uri>https://quik2dde.ru/profile.php?id=3376</uri>
			</author>
			<updated>2022-10-19T18:21:28Z</updated>
			<id>https://quik2dde.ru/viewtopic.php?pid=3856#p3856</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: Ошибка ACCESS VIOLATION при подключении внешней dll в lua]]></title>
			<link rel="alternate" href="https://quik2dde.ru/viewtopic.php?pid=3853#p3853" />
			<content type="html"><![CDATA[<p>Ссылка на GoogleDrive проекта</p><p>[url]https://drive.google.com/file/d/1z0BY-pwdQ-ZRkjG7k06GB6odp6gdc2lB/view?usp=sharing[/url]</p>]]></content>
			<author>
				<name><![CDATA[infinitywaytrader]]></name>
				<uri>https://quik2dde.ru/profile.php?id=3376</uri>
			</author>
			<updated>2022-10-18T10:54:47Z</updated>
			<id>https://quik2dde.ru/viewtopic.php?pid=3853#p3853</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Ошибка ACCESS VIOLATION при подключении внешней dll в lua]]></title>
			<link rel="alternate" href="https://quik2dde.ru/viewtopic.php?pid=3852#p3852" />
			<content type="html"><![CDATA[<p>Приветствую форумчане.</p><p>Имеется сторонняя dll написанная на c++ для получения из quik9.5 свечек по команде, собрана под lua5.3, а также имеется lua скрипт, который должен эти самые свечки отправлять в dll, а затем в приложение написанное на c#.</p><p>Для сборки dll используется VS 2019 в release x64.</p><p>Dll помещается в корень quik`а.</p><p>Суть проблемы - при запуске в quik lua-скрипта, терминал выплёвывает ошибку ACCESS VIOLATION at address SOME_ADDRESS.</p><p>Код dll<br /></p><div class="codebox"><pre><code>#include &lt;windows.h&gt;
#include &lt;process.h&gt;

// необходимые для Lua константы
#define LUA_LIB
#define LUA_BUILD_AS_DLL

// заголовочные файлы LUA
extern &quot;C&quot; {
#include &quot;Lua\lauxlib.h&quot;
#include &quot;Lua\lua.h&quot;
}

TCHAR CommandMemory[] = TEXT(&quot;Memory4CommandGetCandles&quot;);
TCHAR CandlesMemory[] = TEXT(&quot;Memory4GetCandles&quot;);

HANDLE CommandFileMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 64, CommandMemory);
HANDLE CandlesFileMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 128, CandlesMemory);

// точка входа DLL
BOOL APIENTRY DllMain(HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    return TRUE;
}

// функция отправки команд из программы в Lua скрипт
static int forLua_GetCommand(lua_State* L)
{
    if (CommandFileMap) // если память существует
    {
        // считываем данные из памяти и переводим в набор байтов
        PBYTE pb = (PBYTE)(MapViewOfFile(CommandFileMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 64));
        if (pb != NULL) // если есть данные
        {
            if (pb[0] == 0) // если первый байт нулевой
            {
                lua_pushstring(L, &quot;&quot;); // отправляем пустую строку в Lua скрипт
            }
            else
            {
                lua_pushstring(L, (char*)(pb));//иначе отправляем набор байтов в Lua скрипт
            }


            UnmapViewOfFile(pb); // закрываем доступ к данным
        }
        else
        {
            lua_pushstring(L, &quot;&quot;); // иначе отправляем пустую строку в Lua скрипт
        }
    }
    else
    {
        lua_pushstring(L, &quot;&quot;); // иначе отправляем пустую строку в Lua скрипт
    }

    return(1);
}

// функция очистки памяти для отправки команд
static int forLua_ClearCommand(lua_State* L)
{
    if (CommandFileMap)//если память существует
    {
        // считываем данные из памяти и переводим в набор байтов
        PBYTE pb = (PBYTE)(MapViewOfFile(CommandFileMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 64));

        if (pb != NULL) // если есть данные
        {
            // заполняем нулевыми байтами
            for (int i = 0; i &lt; 64; i++)
            {
                pb[i] = &#039;\0&#039;;
            }

            UnmapViewOfFile(pb); // закрываем доступ
        }
    }

    return(0);
}

// функция отправки свечек из lua в программу
static int forLua_SendCandle(lua_State* L)
{
    if (CandlesFileMap) // если память существует
    {
        // считываем данные из памяти и переводим в набор байтов
        PBYTE pb = (PBYTE)(MapViewOfFile(CandlesFileMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 128));
        if (pb != NULL) // если есть данные
        {
            const char* Candle = lua_tostring(L, 1); // переменная для хранения данных
            int Size = 0;

            for (int i = 0; i &lt; 128; i++)
            {
                if (Candle[i] == 0)
                {
                    break;
                }
                else
                {
                    Size++;
                }
            }

            memcpy(pb + 1, Candle, Size); // копируем 
            memcpy(pb, &quot;1&quot;, 1);
            UnmapViewOfFile(pb); // закрываем доступ
        }
    }

    return(0);
}

// регистрация реализованных в dll функций, чтобы они стали &quot;видимы&quot; для Lua
static const struct luaL_Reg ls_lib[] = {
    { &quot;GetCommand&quot;, forLua_GetCommand },
    { &quot;ClearCommand&quot;, forLua_ClearCommand },
    { &quot;SendCandle&quot;, forLua_SendCandle },
    { NULL, NULL }
};

// регистрация названия библиотеки, видимого в скрипте Lua
extern &quot;C&quot; LUALIB_API int luaopen_GetCandlesDll(lua_State * L) {
    lua_newtable(L);
    luaL_setfuncs(L, ls_lib, 0);
    lua_setglobal(L, &quot;GetCandlesDll&quot;);
    return 1;
}</code></pre></div><p>Код lua-скрипта<br /></p><div class="codebox"><pre><code>require(&quot;GetCandlesDll&quot;);

local Candle = &quot;&quot;;
local LastQty = 1;
local CurrentQty = 1;
local DataSet;
local IsOnline = false;
local IsRun = true;

local Minute = &quot;&quot;;
local Hour = &quot;&quot;;

local Day = &quot;&quot;;
local Month = &quot;&quot;;
local Year = &quot;&quot;;

local High = &quot;&quot;;
local Low = &quot;&quot;;
local Open = &quot;&quot;;
local Close = &quot;&quot;;

local ClassName = &quot;TQBR&quot;;
local ToolName = &quot;YNDX&quot;;

function OnInit()
    DataSet = CreateDataSource(ClassName, ToolName, INTERVAL_M1);
end;

function OnStop()
    IsRun = false;
end;

function main()
    while IsRun do
        if tostring(GetCandlesDll.GetCommand()) == &quot;run&quot; then
            IsOnline = true;
            DataSet = CreateDataSource(ClassName, ToolName, INTERVAL_M1);
            GetCandlesDll.ClearCommand();
        end;
        
        if tostring(GetCandlesDll.GetCommand()) == &quot;stop&quot; then
            StopScript();
        end;

        if IsOnline == true then
            CurrentQty = DataSet:Size() - 1;

            if CurrentQty ~= nil and CurrentQty &gt; LastQty then
                for i = LastQty, CurrentQty do
                    if (i == CurrentQty) then
                        LastQty = CurrentQty;
                    end;

                    if tostring(GetCandlesDll.GetCommand()) == &quot;stop&quot; then
                        StopScript();

                        break;
                    end;

                    Minute = tonumber(DataSet:T(i).min) &lt; 10 and &quot;0&quot;..tostring(DataSet:T(i).min) : tostring(DataSet:T(i).min);
                    Hour = tonumber(DataSet:T(i).hour) &lt; 10 and &quot;0&quot;..tostring(DataSetDataSetT(i).hour) : tostring(DataSet:T(i).hour);

                    Day = tonumber(DataSet:T(i).day) &lt; 10 and &quot;0&quot;..tostring(DataSet:T(i).day) : tostring(DataSet:T(i).day);
                    Month = tonumber(DataSet:T(i).month) &lt; 10 and &quot;0&quot;..tostring(DataSet:T(i).month) : tostring(DataSet:T(i).month);
                    Year = tostring(DataSet:T(i).year);
                    
                    High = tostring(DataSet:H(i));
                    Low = tostring(DataSet:L(i));
                    Open = tostring(DataSet:O(i));
                    Close = tostring(DataSet:C(i));
                    
                    Candle = Day..&quot;.&quot;..Month..&quot;.&quot;..Year..&quot; &quot;..Hour..&quot;:&quot;..Minute..&quot;:&quot;..&quot;00&quot;..&quot;;&quot;..High..&quot;;&quot;..Low..&quot;;&quot;..Open..&quot;;&quot;..Close..&quot;;&quot;;

                    sleep(1);
                end;
            end;
        end;

        sleep(1000);
    end;
end;

function StopScript()
    GetCandlesDll.ClearCommand()
    IsOnline = false;
    LastQty = 1;
    Candle = &quot;&quot;;

    if DataSet:Size() ~= nil then 
        DataSet:Close(); 
    end;
end;</code></pre></div>]]></content>
			<author>
				<name><![CDATA[infinitywaytrader]]></name>
				<uri>https://quik2dde.ru/profile.php?id=3376</uri>
			</author>
			<updated>2022-10-18T10:30:26Z</updated>
			<id>https://quik2dde.ru/viewtopic.php?pid=3852#p3852</id>
		</entry>
</feed>
