26

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

я это пробовал. и это не мое творение smile

27

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

sam063rus пишет:
ls_lib: array[0..2] of luaL_reg =

Кстати, выложенная dll с этим и скомпилирована.

28 (2016-09-29 11:31:27 отредактировано sam063rus)

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

-

29 (2015-04-06 12:23:05 отредактировано merabn)

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

sam063rus пишет:

увы, но код говорит другое. у вас там переделана и ещё с ошибками главная функция: luaopen_

Вы правы, наименования dll и функций я менял, как впрочем пытался менять в процессе еще много чего.
Не могу понять как вы увидели другое наименование экспортной функции, я смотрел несколькими просмотрщиками DLL, не нашел этого наименования, тем более в самом проекте стояло другое.
Но это не так важно, а важно что вы помогли разобраться в проблеме и я благодарю вас за это.
Delphi старших версий по-умолчанию используют Unicode. Теперь string и char в Unicode. В компиляторе нет опций для отключения Unicode и погуглив я нашел, что это нельзя сделать, если доверять специалистам, утверждающим это. Выход в переопределении всех строковых типов и переменных в функциях всех модулей: PChar в PAnsiChar, а string в ansistring. Я переопределил только используемые и все заработало.

sam063rus, не подскажете чем смотрели dll?
Еще раз спасибо.

30 (2016-09-29 11:31:36 отредактировано sam063rus)

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

-

31

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

sam063rus пишет:

дизассемблером вестимо:))

Спасибо

32

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

А ведь sam063rus абсолютно прав, я совсем забыл про эту юникодную особенность новых дельфей, чем всё заметно осложняется.

Сделал проект на Delphi XE7. Перехачил все заголовочные файлы Lua под него.
Теперь собирается и работает как надо.

Пока можно скачать отдельным архивом, потом буду смотреть как это правильнее сделать в общую кучу.

[url=https://quik2dde.ru/static-img/40/delphi_xe7.zip]Скачать пример исходников DLL для Delphi XE7[/url]

33

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

Это всё замечательно, но как я могу из своей либы обратиться к методам в lua?

34 (2016-09-29 11:42:42 отредактировано sam063rus)

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

-

35

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

Тогда еще вопрос, как я могу передать из DLL в LUA  строку?

36 (2016-09-29 11:42:32 отредактировано sam063rus)

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

-

37

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

Да, действительно это так и работает) спасибо за помощь, предлагаю посмотреть, что получилось...
Теперь с помощью моей либы можно экспортировать данные по НТТР.
[url]http://quik2dde.ru/viewtopic.php?id=160[/url]

Т.е. через нттр вызывать методы в LUA и получать результат

38 (2019-11-01 20:19:32 отредактировано toxa)

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

наваял, вот, для 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;

39

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

Здравствуйте.
По Вашему описанию создания dll на lazarus сделал библиотеку. Все прекрасно работало. Под quik8.5.2(lua53) пытался изменить сам не получается. Спотыкается на luaL_openlib. По результатам поиска в инете пробовал заменить на
    luaL_setfuncs(L, @ls_lib, 0);
    lua_setglobal(L, PChar('MySoundLib'));
то же не правильно.
Что посоветуете?
(вместо 3-х файлов *.pas использовал lua53.pas)

Спасибо.

40 (2020-12-19 11:52:50 отредактировано Cave Cat)

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

Здравствуйте!
Можно ли обновить инструкцию и архив с примером проекта 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, но где их взять, пока не знаю...

41

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

Надо будет дополнить сборки и инструкции, да.

Cave Cat пишет:

возможно, для других проектов понадобится обновить также lualib.pas и lauxlib.pas, но где их взять, пока не знаю...

Таких файлов нет.
В портированных в паскаль заголовках для Lua как-то принято все складывать один файл LuaXX.pas, без разбивки на несколько. Ну т.е. Lua53.pas содержит в себе все, что есть в lauxlib.h, lua.h, luaconf.h и lualib.h.

42

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

Cave Cat пишет:

После этого пример заработал, но, возможно, для других проектов понадобится обновить также 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.

43

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

Здравствуйте. Огромный привет всей почтенной публике и в особенности ее отдельным членам, а также организатору сего пространства.
Поделюсь своей проблемой.
жил-был, не тужил на платформе x32, но вот стали "выживать", пришлось переходить на х64.
а наработок -- куча.
Короче, с ходу всё не запустилось. Платформа другая, компилятор вместо D7 - XE5, в luа кое-что поменялось.
Куда смотреть, - мозги в разнос. А хочется быстрей, не то, чтобы по-халявному, но . . .  я думаю, меня поймут.
неделю бился, -- после смены вызовов (не без помощи, разумеется, и настоящего форума) выяснил . . .
библиотеку вызываю правильно, она подключается, но если я вызываю функцию, определенную в другой dll,
quik пишет что процедура не найдена.
Было время, когда я активно разрабатывал код, а ddl-ки под D7 отлаживать не умел (скорее не знал, что так можно), кроме того, незнание определенных тонкостей часто приводило к падению квика, в общем, не нашел я тогда лучшего способа перегружать либу (останавливать скрипт) иначе, чем связывая основной код через промежуточную dll.
Кстати, использовал я на х32 неявное связывание, но всё прекрасно работало, здесь же -- нифига.
Что посоветует почтенная публика?
Понятно, что можно в сторону написания единой dll.
Но, может, явное связывание поможет или какие-то дополнительные объявления в коде.
Была ли у кого-то аналогичная проблема?
Знает ли кто-то вот эти тонкости отличия платформ 32 и х64 (или это связано с компилятором xe5)?
Работы, по-ходу, впереди немало, хочется путь пооптимальней выбрать.
Ну и по пути вопрос, если кто под xe5 (либо др. версиями embarcadero) отлаживал dll, как это делается? В нэт-е попадалось, но так у меня не получилось.

44

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

pfelix68, приветствую вас на форуме!

Как-то много написали, а толком - ничего. Ни кода, ни конкретного примера минимальной библиотеки, где бы воспроизводилась проблема.

pfelix68 пишет:

Кстати, использовал я на х32 неявное связывание, но всё прекрасно работало, здесь же -- нифига.
Что посоветует почтенная публика?

Раннее связывание - меньше кода. Но это не важно на самом деле. Проблема где-то не тут.

pfelix68 пишет:

Знает ли кто-то вот эти тонкости отличия платформ 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]

45

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

pfelix68 пишет:

Ну и по пути вопрос, если кто под xe5 (либо др. версиями embarcadero) отлаживал dll, как это делается? В нэт-е попадалось, но так у меня не получилось.

Две есть стратегии:

  1. В параметрах проекта, в параметрах отладки прописываете запускаемый файл info.exe. Тогда при старте отладки в дельфи у вас запустится QUIK и как запустите в нем скрипт с вашей библиотекой - так дельфи подхватит dll для отладки.

  2. Просто запускаете QUIK, потом в дальфи в идете в Run -> Attach to process, в списке процессов выбираете QUIK, дельфи подключается к нему как отладчик и далее тоже самое - как запустите в нем скрипт с вашей библиотекой.....

Не важно каким вариантом идти. Как удобнее, хотя мне нравится второй.

А "секрет" тут скорее вот в чем: Delphi должна собирать dll сразу в ту папку, где ее подхватывает QUIK. Вернее сказать сразу в папку с QUIK. (dll при этом не должна быть подгружена скриптом или QUIK должен быть закрыт на время пересборки). В этом случае отладка точно пойдет нормально.
А если собрать в одну папку, потом перекопировать dll в QUIK и пытаться отлаживать - то тут бывают нюансы, бывает не работает отладка. Ну и режим debug сборки проекта выбирать надо, понятно.

46 (2021-11-17 09:45:45 отредактировано swerg)

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

pfelix68 пишет:

Знает ли кто-то вот эти тонкости отличия платформ 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 и с удовольствием пользоваться smile

47

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

Спасибо огромное.
Знание -- сила.
В программировании -- не новичок, но . . .
Секреты тоже как-бы не новость, но, когда знание не на уровне рассуждений/домыслов - совсем другое дело.
Мой секрет, как понимаю (еще перепроверю), прятался в том (delphi писал Session disconnected, а еще "в непонятном месте" вываливался в окно с ассемблером), что код "стряпал" как из пулемета (заработало, -- и ладно, ДЛЛ вызывается - надо код писать, типа не до осмысливания), короче используя куски стороннего кода, остались конструкции, типа:\
try
  ...
finally
  ...
end;
, ну и внутри нее точку останова пытался установить.
Все ДЛЛ запустились, в обоих вариантах (основной код в одной,  либо вызов через интерфейсную/промежуточную).
Оказалось, код основной либы "не понравился".
Хоть истина и дороже, но не представляю как постепенно выхолащивать 300 кБ кода (строк, примерно 9К), чтоб найти причину. А там еще и системного кода много (х32 ориентированного)
Решил наполнять постепенно, сообразно новым задачам, тем более, что года 2 проектом не занимался, уже и подзабылось, что - где. Думаю, по-восстребованности оно и лучше будет.
Все основные (экспортируемые в ЛУА) функции "система съела".  . . . ???
Интересно, есть ли способ, узнать КОНКРЕТНО, какую процедуру квик/система/qlua/. . . не находит, когда пишет: "...   Не найдена указанная процедура." . . . ???

48

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

swerg пишет:
pfelix68 пишет:

Знает ли кто-то вот эти тонкости отличия платформ 32 и х64 (или это связано с компилятором xe5)?

И еще. Embarcadero теперь предоставляет честно бесплатную [url=https://www.embarcadero.com/ru/products/delphi/starter]Delphi Community Edition[/url].

Обязательно присмотрюсь.

49

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

Еще нюанс. . . . ))
Меня вообще-то потряхивает больше не от наличия/отсутствия нужного (свободного) компилятора, а от того, найду ли я к нему графические либы, под которые наработок - страшно потерять.

50 (2021-11-18 16:44:57 отредактировано swerg)

Re: Создание своей DLL на Delphi или Lazarus для Lua (в QUIK)

pfelix68 пишет:

остались конструкции, типа:\
try
  ...
finally
  ...
end;
, ну и внутри нее точку останова пытался установить.

Точки останова в таких фрагментах отлично устанавливаются и работают (возможно не на буквально try/finally, а на строки внутри).

pfelix68 пишет:

Интересно, есть ли способ, узнать КОНКРЕТНО, какую процедуру квик/система/qlua/. . . не находит, когда пишет: "...   Не найдена указанная процедура." . . . ???

Есть. Но надо бы определиться кто ж выдает это сообщение и при выполнении какого кода.