Тема: Ошибка ACCESS VIOLATION при подключении внешней dll в lua
Приветствую форумчане.
Имеется сторонняя dll написанная на c++ для получения из quik9.5 свечек по команде, собрана под lua5.3, а также имеется lua скрипт, который должен эти самые свечки отправлять в dll, а затем в приложение написанное на c#.
Для сборки dll используется VS 2019 в release x64.
Dll помещается в корень quik`а.
Суть проблемы - при запуске в quik lua-скрипта, терминал выплёвывает ошибку ACCESS VIOLATION at address SOME_ADDRESS.
Код dll
#include <windows.h>
#include <process.h>
// необходимые для Lua константы
#define LUA_LIB
#define LUA_BUILD_AS_DLL
// заголовочные файлы LUA
extern "C" {
#include "Lua\lauxlib.h"
#include "Lua\lua.h"
}
TCHAR CommandMemory[] = TEXT("Memory4CommandGetCandles");
TCHAR CandlesMemory[] = TEXT("Memory4GetCandles");
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, ""); // отправляем пустую строку в Lua скрипт
}
else
{
lua_pushstring(L, (char*)(pb));//иначе отправляем набор байтов в Lua скрипт
}
UnmapViewOfFile(pb); // закрываем доступ к данным
}
else
{
lua_pushstring(L, ""); // иначе отправляем пустую строку в Lua скрипт
}
}
else
{
lua_pushstring(L, ""); // иначе отправляем пустую строку в 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 < 64; i++)
{
pb[i] = '\0';
}
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 < 128; i++)
{
if (Candle[i] == 0)
{
break;
}
else
{
Size++;
}
}
memcpy(pb + 1, Candle, Size); // копируем
memcpy(pb, "1", 1);
UnmapViewOfFile(pb); // закрываем доступ
}
}
return(0);
}
// регистрация реализованных в dll функций, чтобы они стали "видимы" для Lua
static const struct luaL_Reg ls_lib[] = {
{ "GetCommand", forLua_GetCommand },
{ "ClearCommand", forLua_ClearCommand },
{ "SendCandle", forLua_SendCandle },
{ NULL, NULL }
};
// регистрация названия библиотеки, видимого в скрипте Lua
extern "C" LUALIB_API int luaopen_GetCandlesDll(lua_State * L) {
lua_newtable(L);
luaL_setfuncs(L, ls_lib, 0);
lua_setglobal(L, "GetCandlesDll");
return 1;
}
Код lua-скрипта
require("GetCandlesDll");
local Candle = "";
local LastQty = 1;
local CurrentQty = 1;
local DataSet;
local IsOnline = false;
local IsRun = true;
local Minute = "";
local Hour = "";
local Day = "";
local Month = "";
local Year = "";
local High = "";
local Low = "";
local Open = "";
local Close = "";
local ClassName = "TQBR";
local ToolName = "YNDX";
function OnInit()
DataSet = CreateDataSource(ClassName, ToolName, INTERVAL_M1);
end;
function OnStop()
IsRun = false;
end;
function main()
while IsRun do
if tostring(GetCandlesDll.GetCommand()) == "run" then
IsOnline = true;
DataSet = CreateDataSource(ClassName, ToolName, INTERVAL_M1);
GetCandlesDll.ClearCommand();
end;
if tostring(GetCandlesDll.GetCommand()) == "stop" then
StopScript();
end;
if IsOnline == true then
CurrentQty = DataSet:Size() - 1;
if CurrentQty ~= nil and CurrentQty > LastQty then
for i = LastQty, CurrentQty do
if (i == CurrentQty) then
LastQty = CurrentQty;
end;
if tostring(GetCandlesDll.GetCommand()) == "stop" then
StopScript();
break;
end;
Minute = tonumber(DataSet:T(i).min) < 10 and "0"..tostring(DataSet:T(i).min) : tostring(DataSet:T(i).min);
Hour = tonumber(DataSet:T(i).hour) < 10 and "0"..tostring(DataSetDataSetT(i).hour) : tostring(DataSet:T(i).hour);
Day = tonumber(DataSet:T(i).day) < 10 and "0"..tostring(DataSet:T(i).day) : tostring(DataSet:T(i).day);
Month = tonumber(DataSet:T(i).month) < 10 and "0"..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.."."..Month.."."..Year.." "..Hour..":"..Minute..":".."00"..";"..High..";"..Low..";"..Open..";"..Close..";";
sleep(1);
end;
end;
end;
sleep(1000);
end;
end;
function StopScript()
GetCandlesDll.ClearCommand()
IsOnline = false;
LastQty = 1;
Candle = "";
if DataSet:Size() ~= nil then
DataSet:Close();
end;
end;