Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)
я это пробовал. и это не мое творение
Вы не вошли. Пожалуйста, войдите или зарегистрируйтесь.
QUIK -> DDE → Написание внешних библиотек на C++/Delphi/C# для Lua → Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)
я это пробовал. и это не мое творение
ls_lib: array[0..2] of luaL_reg =
Кстати, выложенная dll с этим и скомпилирована.
-
увы, но код говорит другое. у вас там переделана и ещё с ошибками главная функция: luaopen_
Вы правы, наименования dll и функций я менял, как впрочем пытался менять в процессе еще много чего.
Не могу понять как вы увидели другое наименование экспортной функции, я смотрел несколькими просмотрщиками DLL, не нашел этого наименования, тем более в самом проекте стояло другое.
Но это не так важно, а важно что вы помогли разобраться в проблеме и я благодарю вас за это.
Delphi старших версий по-умолчанию используют Unicode. Теперь string и char в Unicode. В компиляторе нет опций для отключения Unicode и погуглив я нашел, что это нельзя сделать, если доверять специалистам, утверждающим это. Выход в переопределении всех строковых типов и переменных в функциях всех модулей: PChar в PAnsiChar, а string в ansistring. Я переопределил только используемые и все заработало.
sam063rus, не подскажете чем смотрели dll?
Еще раз спасибо.
-
дизассемблером вестимо:))
Спасибо
А ведь sam063rus абсолютно прав, я совсем забыл про эту юникодную особенность новых дельфей, чем всё заметно осложняется.
Сделал проект на Delphi XE7. Перехачил все заголовочные файлы Lua под него.
Теперь собирается и работает как надо.
Пока можно скачать отдельным архивом, потом буду смотреть как это правильнее сделать в общую кучу.
[url=https://quik2dde.ru/static-img/40/delphi_xe7.zip]Скачать пример исходников DLL для Delphi XE7[/url]
Это всё замечательно, но как я могу из своей либы обратиться к методам в lua?
-
Тогда еще вопрос, как я могу передать из DLL в LUA строку?
-
Да, действительно это так и работает) спасибо за помощь, предлагаю посмотреть, что получилось...
Теперь с помощью моей либы можно экспортировать данные по НТТР.
[url]http://quik2dde.ru/viewtopic.php?id=160[/url]
Т.е. через нттр вызывать методы в LUA и получать результат
наваял, вот, для delphi/fpc хелперы, может кому пригодится. код раз в 10 более читаемый и безопасный.
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 = ''): 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: ['name1', value1, 'name2', 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 < 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 <> 0);
LUA_TSTRING : result:= (AnsiCompareText(fString, 'TRUE') = 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 = ('FALSE', 'TRUE');
begin
case fFieldType of
LUA_TBOOLEAN : result:= boolval[fBool];
LUA_TNUMBER : result:= FloatToStr(fNumber);
LUA_TSTRING : result:= fString;
else result:= '';
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('Field %s is not a table', [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('Global %s is not a table', [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 < 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 "value"
result:= FindNext;
end;
function TLuaTable.FindNext: boolean;
begin
lua_pop(fContext.CurrentState, 1); // pop previous "value"
result:= (lua_next(fContext.CurrentState, Index) <> 0);
if result then begin
fCurField:= Field.fExtractField(-1);
fPopSize:= 2; // leave "key" 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 > 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 < 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 <> LUA_TNONE) then begin
result:= (lua_type(fContext.CurrentState, -1) = AResType);
if not result and (AResCount > 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) > 0) and (tmp[1]='"') then begin
p:= pAnsiChar(tmp);
tmp:= AnsiExtractQuotedStr(p, '"');
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 < 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 <> LUA_TNONE) then begin
result:= (lua_type(fLuaState, -1) = AResType);
if not result and (AResCount > 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 < 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 "protected mode"
if (AResType <> LUA_TNONE) then begin
result:= (lua_type(fLuaState, -1) = AResType);
if not result and (AResCount > 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:= 'Script loading failed';
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.
примерно так может выглядеть обработчик колбэка OnQuote, при использовании хелперов, все потроха LUA скрываются:
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('%s price: %s qty: %s', [aparamname, rowtbl['price'].AsString, rowtbl['quantity'].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('OnQuote: Class: %s Code: %s', [classcode, seccode]);
if Call('getQuoteLevel2', [classcode, seccode], 1, LUA_TTABLE) then try
with Stack[-1].AsTable do begin
if (FieldByName['bid_count'].AsInteger > 0) then
dumptable(CurrentContext, CurrentTable, 'bid');
if (FieldByName['offer_count'].AsInteger > 0) then
dumptable(CurrentContext, CurrentTable, 'offer');
end;
finally CleanUp(1); end;
finally free; end;
result:= 0;
end;
Здравствуйте.
По Вашему описанию создания dll на lazarus сделал библиотеку. Все прекрасно работало. Под quik8.5.2(lua53) пытался изменить сам не получается. Спотыкается на luaL_openlib. По результатам поиска в инете пробовал заменить на
luaL_setfuncs(L, @ls_lib, 0);
lua_setglobal(L, PChar('MySoundLib'));
то же не правильно.
Что посоветуете?
(вместо 3-х файлов *.pas использовал lua53.pas)
Спасибо.
Здравствуйте!
Можно ли обновить инструкцию и архив с примером проекта dll в Lazarus для Quik 8.7 и старше?
P.S. Погуглив, разобрался сам.
Нужно добыть файл lua53.pas, например, здесь: [url]https://github.com/malcome/Lua4Lazarus/archive/R150205.zip[/url],
и положить его в папку проекта
Соответственно, в секции uses нужно заменить везде lua на lua53.
В коде регистрации функций нужно заменить
luaL_openlib(L, PChar('SimpleDelphiLua'), @ls_lib, 0);
lua_pop(L, 1);
на
lua_newtable(L);
luaL_setfuncs(L, @ls_lib, 0);
lua_pushvalue(L,-1);
lua_setglobal(L, 'SimpleDelphiLua');
После этого пример заработал, но, возможно, для других проектов понадобится обновить также lualib.pas и lauxlib.pas, но где их взять, пока не знаю...
Надо будет дополнить сборки и инструкции, да.
возможно, для других проектов понадобится обновить также lualib.pas и lauxlib.pas, но где их взять, пока не знаю...
Таких файлов нет.
В портированных в паскаль заголовках для Lua как-то принято все складывать один файл LuaXX.pas, без разбивки на несколько. Ну т.е. Lua53.pas содержит в себе все, что есть в lauxlib.h, lua.h, luaconf.h и lualib.h.
После этого пример заработал, но, возможно, для других проектов понадобится обновить также lualib.pas и lauxlib.pas, но где их взять, пока не знаю...
Я вам советую воспользоваться моими хелперами: lualib53.pas и LuaHelpers.pas, которые можно взять тут: [url]https://github.com/untoxa/lua_share/tree/master/common[/url]
это части проекта lua_share: [url]https://github.com/untoxa/lua_share[/url] он прекрасно собирается fpc/lazarus.
Здравствуйте. Огромный привет всей почтенной публике и в особенности ее отдельным членам, а также организатору сего пространства.
Поделюсь своей проблемой.
жил-был, не тужил на платформе x32, но вот стали "выживать", пришлось переходить на х64.
а наработок -- куча.
Короче, с ходу всё не запустилось. Платформа другая, компилятор вместо D7 - XE5, в luа кое-что поменялось.
Куда смотреть, - мозги в разнос. А хочется быстрей, не то, чтобы по-халявному, но . . . я думаю, меня поймут.
неделю бился, -- после смены вызовов (не без помощи, разумеется, и настоящего форума) выяснил . . .
библиотеку вызываю правильно, она подключается, но если я вызываю функцию, определенную в другой dll,
quik пишет что процедура не найдена.
Было время, когда я активно разрабатывал код, а ddl-ки под D7 отлаживать не умел (скорее не знал, что так можно), кроме того, незнание определенных тонкостей часто приводило к падению квика, в общем, не нашел я тогда лучшего способа перегружать либу (останавливать скрипт) иначе, чем связывая основной код через промежуточную dll.
Кстати, использовал я на х32 неявное связывание, но всё прекрасно работало, здесь же -- нифига.
Что посоветует почтенная публика?
Понятно, что можно в сторону написания единой dll.
Но, может, явное связывание поможет или какие-то дополнительные объявления в коде.
Была ли у кого-то аналогичная проблема?
Знает ли кто-то вот эти тонкости отличия платформ 32 и х64 (или это связано с компилятором xe5)?
Работы, по-ходу, впереди немало, хочется путь пооптимальней выбрать.
Ну и по пути вопрос, если кто под xe5 (либо др. версиями embarcadero) отлаживал dll, как это делается? В нэт-е попадалось, но так у меня не получилось.
pfelix68, приветствую вас на форуме!
Как-то много написали, а толком - ничего. Ни кода, ни конкретного примера минимальной библиотеки, где бы воспроизводилась проблема.
Кстати, использовал я на х32 неявное связывание, но всё прекрасно работало, здесь же -- нифига.
Что посоветует почтенная публика?
Раннее связывание - меньше кода. Но это не важно на самом деле. Проблема где-то не тут.
Знает ли кто-то вот эти тонкости отличия платформ 32 и х64 (или это связано с компилятором xe5)?
Нету разницы.
Разница скорее в том, что версия LUA изменилась. Для нее новые заголовочные файлы нужны.
И еще надо раздельно собирать для Lua 5.3 и Lua 5.4, с разными заголовочными файлами.
Ну или просто остановиться на одной из этих версий и только для нее собирать, не забывая выбирать соотв. версию Lua в терминале для выполнения скрипта.
Заголовочники можно стырить из QVCLua, например
[url]https://quik2dde.ru/viewtopic.php?id=111[/url]
В этой теме, увы, пример я пока не обновил с готовыми параметрами сборки.
Еще в Lua 5.3 / 5.4 поменялось API для инициализации библиотеки в luaopen_ХХХ
Вот в этой теме есть подробности
[url]https://quik2dde.ru/viewtopic.php?id=18[/url]
Ну и по пути вопрос, если кто под xe5 (либо др. версиями embarcadero) отлаживал dll, как это делается? В нэт-е попадалось, но так у меня не получилось.
Две есть стратегии:
В параметрах проекта, в параметрах отладки прописываете запускаемый файл info.exe. Тогда при старте отладки в дельфи у вас запустится QUIK и как запустите в нем скрипт с вашей библиотекой - так дельфи подхватит dll для отладки.
Просто запускаете QUIK, потом в дальфи в идете в Run -> Attach to process, в списке процессов выбираете QUIK, дельфи подключается к нему как отладчик и далее тоже самое - как запустите в нем скрипт с вашей библиотекой.....
Не важно каким вариантом идти. Как удобнее, хотя мне нравится второй.
А "секрет" тут скорее вот в чем: Delphi должна собирать dll сразу в ту папку, где ее подхватывает QUIK. Вернее сказать сразу в папку с QUIK. (dll при этом не должна быть подгружена скриптом или QUIK должен быть закрыт на время пересборки). В этом случае отладка точно пойдет нормально.
А если собрать в одну папку, потом перекопировать dll в QUIK и пытаться отлаживать - то тут бывают нюансы, бывает не работает отладка. Ну и режим debug сборки проекта выбирать надо, понятно.
Знает ли кто-то вот эти тонкости отличия платформ 32 и х64 (или это связано с компилятором xe5)?
Вспомнил еще нюанс.
Начиная с какой-то версии (xe5 туда уже попадает) Embarcadero заменили внутренний формат типа String: теперь он хранит юникодные строки.
Соответственно при использовании Lua следует в pas-коде использовать только типы AnsiString и PAnsiChar ! Иначе будет фигня.
И еще. Embarcadero теперь предоставляет честно бесплатную [url=https://www.embarcadero.com/ru/products/delphi/starter]Delphi Community Edition[/url]. Так что не вижу особого смысла возиться с наверняка ломанной xe5. Можно взять сразу честно бесплатную самую свежую версию Delphi в редакции Community Edition и с удовольствием пользоваться
Спасибо огромное.
Знание -- сила.
В программировании -- не новичок, но . . .
Секреты тоже как-бы не новость, но, когда знание не на уровне рассуждений/домыслов - совсем другое дело.
Мой секрет, как понимаю (еще перепроверю), прятался в том (delphi писал Session disconnected, а еще "в непонятном месте" вываливался в окно с ассемблером), что код "стряпал" как из пулемета (заработало, -- и ладно, ДЛЛ вызывается - надо код писать, типа не до осмысливания), короче используя куски стороннего кода, остались конструкции, типа:\
try
...
finally
...
end;
, ну и внутри нее точку останова пытался установить.
Все ДЛЛ запустились, в обоих вариантах (основной код в одной, либо вызов через интерфейсную/промежуточную).
Оказалось, код основной либы "не понравился".
Хоть истина и дороже, но не представляю как постепенно выхолащивать 300 кБ кода (строк, примерно 9К), чтоб найти причину. А там еще и системного кода много (х32 ориентированного)
Решил наполнять постепенно, сообразно новым задачам, тем более, что года 2 проектом не занимался, уже и подзабылось, что - где. Думаю, по-восстребованности оно и лучше будет.
Все основные (экспортируемые в ЛУА) функции "система съела". . . . ???
Интересно, есть ли способ, узнать КОНКРЕТНО, какую процедуру квик/система/qlua/. . . не находит, когда пишет: "... Не найдена указанная процедура." . . . ???
pfelix68 пишет:Знает ли кто-то вот эти тонкости отличия платформ 32 и х64 (или это связано с компилятором xe5)?
И еще. Embarcadero теперь предоставляет честно бесплатную [url=https://www.embarcadero.com/ru/products/delphi/starter]Delphi Community Edition[/url].
Обязательно присмотрюсь.
Еще нюанс. . . . ))
Меня вообще-то потряхивает больше не от наличия/отсутствия нужного (свободного) компилятора, а от того, найду ли я к нему графические либы, под которые наработок - страшно потерять.
остались конструкции, типа:\
try
...
finally
...
end;
, ну и внутри нее точку останова пытался установить.
Точки останова в таких фрагментах отлично устанавливаются и работают (возможно не на буквально try/finally, а на строки внутри).
Интересно, есть ли способ, узнать КОНКРЕТНО, какую процедуру квик/система/qlua/. . . не находит, когда пишет: "... Не найдена указанная процедура." . . . ???
Есть. Но надо бы определиться кто ж выдает это сообщение и при выполнении какого кода.
QUIK -> DDE → Написание внешних библиотек на C++/Delphi/C# для Lua → Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)
Форум работает на PunBB, при поддержке Informer Technologies, Inc