lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Here is how I call lua methods from Delphi, and so far I've never had a
problem.

type
  TVariantArray =array of Variant;
  PVariantArray =^TVariantArray;

function LuaPCallFunction(L: Plua_State; FunctionName :String;
                          const Args: array of Variant;
                          Results : PVariantArray;
                          ErrFunc: Integer=0;
                          NResults :Integer=LUA_MULTRET):Integer;
var
   NArgs,
   i :Integer;
begin
     //Put Function To Call on the Stack
     luaPushString(L, FunctionName);
     lua_gettable(L, LUA_GLOBALSINDEX);

     //Put Parameters on the Stack
     NArgs := High(Args)+1;
     for i:=0 to (NArgs-1) do
       LuaPushVariant(L, Args[i]);

     //Call the Function
     LuaPcall(L, NArgs, NResults, ErrFunc);
     Result :=lua_gettop(L);   //Get Number of Results

     if (Results<>Nil)
     then begin 
               //Get Results in the right order
               SetLength(Results^, Result);
               for i:=0 to Result-1 do
               begin
                    Results^[Result-(i+1)] :=LuaToVariant(L, -(i+1));
               end;
          end;
end;

function TLUA.FunctionExists(MethodName: String): Boolean;
begin
  lua_pushstring(L, PChar(MethodName));
  lua_rawget(L, LUA_GLOBALSINDEX);
  result := lua_isfunction(L, -1);
  lua_pop(L, 1);
end;

function TLUA.CallFunction(FunctionName: String;
  const Args: array of Variant; Results: PVariantArray = nil): Integer;
begin
  if FunctionExists(FunctionName) then
    result := LuaPCallFunction(L, FunctionName, Args, Results)
  else
    result := -1;
end;

Usage:
  LuaInstance.CallFunction('MyFunc', [Param1, Param2], ResultVarArray);

Actually I've also attached my Delphi wrapper unit for lua, its built
around the lua 5.0.2 distro that ships with LuaEdit, but it should be
easily modifiable to 5.1.x

 - Jeremy

"Help I suffer from the oxymoron Corporate Security."


> -------- Original Message --------
> Subject: Re: Lua Tutor (Delphi + Lua)
> From: Jilani Khaldi <jilani.khaldi1@virgilio.it>
> Date: Wed, June 28, 2006 5:37 pm
> To: Lua list <lua@bazar2.conectiva.com.br>
> 
> // Call add_xy() from Delphi:
> function call_add_xy(L: Plua_State; x, y: Double): Double;
> begin
>    // Push functions and arguments:
>    lua_getglobal(L, 'add_xy');  // Function to be called.
>    lua_pushnumber(L ,x);        // Push 1st argument.
>    lua_pushnumber(L, y);        // push 2nd argument.
> 
>    // Do the call (2 arguments, 1 result):
>    if lua_pcall(L, 2, 1, 0) <> 0 then
>    begin
>      // Handle error here.
>    end;
> 
>    // Retrieve result:
>    if not lua_isnumber(L, -1) then
>    begin
>      // Handle error here.
>    end;
>    Result := lua_tonumber(L, -1);
> 
>    // pop returned value:
>    lua_pop(L, 1);
> end;
> 
> procedure TForm1.Button1Click(Sender: TObject);
> var
>   L: Plua_State;
>   FName: PChar;
>   x, y, R: double;
>   st: string;
>   pc: PChar;
> begin
>   FName := 'exp1.lua';
>   L := lua_open();
>   luaopen_base(L);
> //  luaopen_io(L); (*)
>   luaL_loadfile(L, FName);
>   lua_call(L, 0, 0);
>   x := 3.14159;
>   y := 2.71828;
>   R := call_add_xy(L,x,y);
>   st := Format('pi + e = %1.5f', [R]);
>   memo1.Lines.Add(st);
>   lua_close(L);
> end;
> 
> exp1.lua file contains:
> 
> function add_xy(x, y)
>   return (x + y)
> end
> 
> (*): this line gives an "access violation" if the program is run from 
> Delphi IDE with lua5.1.dll, but not with lua5.0.dll
> 
> jk
unit LuaWrapper;

{$IFDEF FPC}
  {$MODE Delphi}
{$ENDIF}

interface

uses
  Classes,
  LUA,
  LuaUtils,
  Lauxlib,
  LuaLib;

type

  { TLUA }

  TLUA=class(TComponent)
  private
    L : Plua_State;
    FScript,
    FLibFile,
    FLibName: String;
    FUseDebugDLL: Boolean;
    FMethods : TStringList;
    procedure SetLibName(const Value: String);
    function GetValue(ValueName: String): Variant;
    procedure SetValue(ValueName: String; const Value: Variant);
    procedure OpenLibs;
    procedure SetUseDebugDLL(const Value: Boolean);
    function GetUseDebugDLL: Boolean;
  public
    constructor Create(Owner : TComponent); override;
    destructor Destroy; override;

    procedure Close;
    procedure Open;

    procedure LoadScript(Script : String);
    procedure LoadFile(FileName:String);
    procedure Execute;
    procedure ExecuteCmd(Script:String);
    procedure RegisterLUAMethod(MethodName: String; Func: lua_CFunction);
    function  FunctionExists(MethodName:String) : Boolean;
    function  CallFunction( FunctionName :String; const Args: array of Variant;
                            Results : PVariantArray = nil):Integer;
    function  TableFunctionExists(TableName, FunctionName : String) : Boolean;
    function  CallTableFunction( TableName, FunctionName :String;
                               const Args: array of Variant;
                               Results : PVariantArray = nil):Integer;

    property LibName : String read FLibName write SetLibName;
    property Value[ValueName:String]:Variant read GetValue write SetValue;
    property LuaState : Plua_State read L;
    property UseDebugDLL : Boolean read GetUseDebugDLL write SetUseDebugDLL;
  end;

implementation

uses
  Variants,
  SysUtils;

constructor TLUA.Create(Owner: TComponent);
begin
  inherited;
  FMethods := TStringList.Create;
  Open;
end;

destructor TLUA.Destroy;
begin
  lua_close(L);
  FMethods.Free;
  inherited;
end;

procedure TLUA.Execute;
begin
  if L = nil then
    Open;
  if FScript <> '' then
    LuaLoadBuffer(L, FScript, LibName)
  else
    if FLibFile <> '' then
      luaL_loadfile(L, PChar(FLibFile))
    else
      exit;
  LuaPCall(L, 0, 0, 0);
end;

procedure TLUA.ExecuteCmd(Script: String);
begin
  luaL_loadbuffer(L, PChar(Script), Length(Script), PChar(LibName));
  lua_pcall(L, 0, 0, 0);
end;

function TLUA.GetValue(ValueName: String): Variant;
begin
  lua_pushstring(L, PChar(ValueName));
  lua_rawget(L, LUA_GLOBALSINDEX);
  result := LuaToVariant(L, -1);
  lua_pop(L, 1);
end;

procedure TLUA.LoadFile(FileName: String);
begin
  if L = nil then
    Open;
  FLibFile := FileName;
  FScript := '';
  luaL_loadfile(L, PChar(FileName));
end;

procedure TLUA.LoadScript(Script: String);
begin
  if FScript <> Script then
    Close;
  if L = nil then
    Open;
  FScript := Trim(Script);
  FLibFile := '';
  if FScript <> '' then
    LuaLoadBuffer(L, Script, LibName);
end;

function TLUA.FunctionExists(MethodName: String): Boolean;
begin
  lua_pushstring(L, PChar(MethodName));
  lua_rawget(L, LUA_GLOBALSINDEX);
  result := lua_isfunction(L, -1);
  lua_pop(L, 1);
end;

procedure TLUA.RegisterLUAMethod(MethodName: String; Func: lua_CFunction);
begin
  if L = nil then
    Open;
  lua_register(L, PChar(MethodName), Func);
  if FMethods.IndexOf(MethodName) = -1 then
    FMethods.AddObject(MethodName, @Func)
  else
    FMethods.Objects[FMethods.IndexOf(MethodName)] := @Func;
end;

procedure TLUA.SetLibName(const Value: String);
begin
  FLibName := Value;
end;

procedure TLUA.SetValue(ValueName: String; const Value: Variant);
begin
  if VarIsType(Value, varString) then
    LuaSetIdentValue(L, ValueName, quote(Value))
  else
    LuaSetIdentValue(L, ValueName, Value);
end;

function TLUA.CallFunction(FunctionName: String;
  const Args: array of Variant; Results: PVariantArray = nil): Integer;
begin
  if FunctionExists(FunctionName) then
    result := LuaPCallFunction(L, FunctionName, Args, Results)
  else
    result := -1;
end;

procedure TLUA.Close;
begin
  if L <> nil then
    lua_close(L);
  L := nil;
end;

procedure TLUA.Open;
begin
  if L <> nil then
    Close;
  L := lua_open;
  OpenLibs;
end;

procedure TLUA.OpenLibs;
var
  I : Integer;
begin
  luaopen_base(L);
  luaopen_table(L);
  luaopen_io(L);
  luaopen_string(L);
  luaopen_math(L);
  if UseDebugDLL then
    luaopen_debug(L);
  luaopen_loadlib(L);
  lua_settop(L, 0);

  for I := 0 to FMethods.Count -1 do
    begin
      RegisterLUAMethod(FMethods[I], Pointer(FMethods.Objects[I]));
    end;
end;

procedure TLUA.SetUseDebugDLL(const Value: Boolean);
begin
  FUseDebugDLL := Value;
end;

function TLUA.GetUseDebugDLL: Boolean;
begin
  result := FUseDebugDLL and (FileExists(ExtractFilePath(ParamStr(0))+'LuaEditDebug.dll'));
end;

function TLUA.CallTableFunction(TableName, FunctionName: String;
  const Args: array of Variant; Results: PVariantArray): Integer;
var
   NArgs,
   NResults,
   i :Integer;
begin
  if TableFunctionExists(TableName, FunctionName) then
    begin
     //Put Function To Call on the Stack
     luaPushString(L, TableName);
     lua_gettable(L, LUA_GLOBALSINDEX);
     luaPushString(L, FunctionName);
     lua_rawget(L, -2);

     //Put Parameters on the Stack
     NArgs := High(Args)+1;
     for i:=0 to (NArgs-1) do
       LuaPushVariant(L, Args[i]);

     NResults := LUA_MULTRET;
     //Call the Function
     LuaPcall(L, NArgs, NResults, 0);
     Result :=lua_gettop(L);   //Get Number of Results

     if (Results<>Nil) then
       begin
         //Get Results in the right order
         SetLength(Results^, Result);
         for i:=0 to Result-1 do
           Results^[Result-(i+1)] :=LuaToVariant(L, -(i+1));
       end;
    end
  else
    result := -1;
end;

function TLUA.TableFunctionExists(TableName,
  FunctionName: String): Boolean;
begin
//  LuaGetTable(L, 1, TableName);
  lua_pushstring(L, PChar(TableName));
  lua_rawget(L, LUA_GLOBALSINDEX);
  result := lua_istable(L, -1);
{  lua_pop(L, 1);

  lua_pushstring(L, PChar(TableName));
  lua_rawget(L, LUA_GLOBALSINDEX);
  result := lua_istable(L, -1);}
  if result then
    begin
      lua_pushstring(L, PChar(FunctionName));
      lua_rawget(L, -2);
      result := lua_isfunction(L, -1);
      lua_pop(L, 1);
      lua_pop(L, 1);
    end
  else
    begin
      lua_pop(L, 1);
    end;
end;

end.