一、创建一个exe程序
创建一个exe程序,引用LuaRedis.pas单元(此单元自己封装的代码,目前主要封装了获取key和设置key/value功能),代码如下:
unit Unit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls;typeTForm1 = class(TForm)btn2: TButton;Memo1: TMemo;edt1: TEdit;edt2: TEdit;edt3: TEdit;btn3: TButton;edt4: TEdit;procedure btn2Click(Sender: TObject);procedure btn3Click(Sender: TObject);private{ Private declarations }public{ Public declarations }end;varForm1: TForm1;implementation
usesLuaRedis;{$R *.dfm}procedure TForm1.btn2Click(Sender: TObject);
varsTmp, sErrorMsg: string;
beginMemo1.Text := '';trysTmp := getValue(Trim(edt1.Text), sErrorMsg); // value111Memo1.Text := sTmp + '->' + sErrorMsg;excepton e:Exception do beginShowMessage('【异常】' + e.Message);Exit;end;end;
end;procedure TForm1.btn3Click(Sender: TObject);
varsKey, sValue, sErrorMsg: string;
beginMemo1.Text := '';trysKey := Trim(edt2.Text);if setKeyValue(sKey, Trim(edt3.Text), StrToIntDef(Trim(edt4.Text), 0), sErrorMsg) then begin // key111 value111sValue := getValue(Trim(edt2.Text), sErrorMsg);end;Memo1.Text := sKey + ':' + sValue + '->' + sErrorMsg;excepton e:Exception do beginShowMessage('【异常】' + e.Message);Exit;end;end;
end;end.
二、封装LuaRedis.pas单元代码
上面说的封装LuaRedis.pas单元(通过registerLuaState()和destroyLuaState()来加载和销毁lua的状态机),同时引用Lua.pas, LuaLib.pas单元,代码如下:
unit LuaRedis;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Lua, LuaLib;constC_LuaPathFileName = './luaScript/mytest.lua';function getValue(myKey: string; var sErrorMsg: string): string;function setKeyValue(myKey, myValue: string; myExpire: Integer; var sErrorMsg: string): Boolean;varLuaObj: TLua;L: TLuaState;implementationfunction loadLuaScript(sLuaPathFileName: String; var sErrorMsg: string): Boolean;
varnTmp: Integer;
beginResult := False;trysErrorMsg := '默认提示消息(loadLuaScript)!';if not FileExists(sLuaPathFileName) then beginsErrorMsg := '未查到路径中此Lua脚本文件(' + sLuaPathFileName + ')';Exit;end;nTmp := LuaObj.DoFile(sLuaPathFileName);case nTmp ofLUA_OK : beginsErrorMsg := '成功加载路径中此Lua脚本文件!';Result := True;end;LUA_ERRSYNTAX : sErrorMsg := '在预编译Lua文件时发现了语法错误!';LUA_ERRMEM : sErrorMsg := '在执行Lua文件时内存分配错误!';LUA_ERRRUN : sErrorMsg := '在执行Lua文件中在调用函数时发生了运行时错误!';elsesErrorMsg := '加载失败路径中此Lua脚本文件!';end;excepton e:Exception do beginResult := False;sErrorMsg := '【异常】方法(loadLuaScript):' + e.Message;Exit;end;end;
end;function getValue(myKey: string; var sErrorMsg: string): string;
varnRet: Integer;
begintrysErrorMsg := '默认提示消息(getValue)!';if not loadLuaScript(C_LuaPathFileName, sErrorMsg) then beginExit;end;lua_getglobal(L, 'getValue');lua_pushstring(L, PAnsiChar(myKey));nRet := lua_pcall(L, 1, 1, 0);if nRet = 0 then beginResult := lua_toString(L, -1);sErrorMsg := 'Lua脚本正常执行';Exit;end elsesErrorMsg := 'Lua脚本执行失败!';excepton e:Exception do beginResult := '';sErrorMsg := '【异常】方法(getValue):' + e.Message;Exit;end;end;
end;function setKeyValue(myKey, myValue: string; myExpire: Integer; var sErrorMsg: string): Boolean;
varnRet: Integer;
beginResult := False;trysErrorMsg := '默认提示消息(setKeyValue)!';if not loadLuaScript(C_LuaPathFileName, sErrorMsg) then beginExit;end;lua_getglobal(L, 'setKeyValue');lua_pushstring(L, PAnsiChar(myKey));lua_pushstring(L, PAnsiChar(myValue));lua_pushinteger(L, myExpire);nRet := lua_pcall(L, 3, 1, 0);if nRet = 0 then beginResult := (lua_toInteger(L, -1) = 1);sErrorMsg := 'Lua脚本正常执行';Exit;end elsesErrorMsg := 'Lua脚本执行失败!';excepton e:Exception do beginResult := False;sErrorMsg := '【异常】方法(setKeyValue):' + e.Message;Exit;end;end;
end;procedure registerLuaState();
beginif LuaObj = nil then beginLuaObj := TLua.Create;if L = nil then beginL := LuaObj.LuaInstance;end;// luaL_openlibs 是一个由 luaL(Lua 实用程序库)提供的函数,它用于打开一组标准的Lua库。// 这些库通常包括基础库(base)、字符串处理库(string)、表操作库(table)、数学函数库(math)、I/O库(io)、操作系统库(os)等。// 这个函数通常在你的C/C++程序中与Lua交互时使用,以提供完整的Lua标准库功能。luaL_openlibs(L);end;
end;procedure destroyLuaState();
beginif LuaObj <> nil then beginif L <> nil then beginL := nil;end;LuaObj.Free;end;
end;initializationregisterLuaState();finalizationdestroyLuaState();end.
三、封装的Lua, LuaLib单元
封装的Lua, LuaLib单元,代码如下:
{
/** * @package Delphi Lua * @copyright Copyright (c) 2009 Dennis D. Spreen (http://www.spreendigital.de/blog) * @license http://opensource.org/licenses/gpl-license.php GNU Public License * @author Dennis D. Spreen <dennis@spreendigital.de> * @version 1.3 * @revision $Id: Lua.pas 102 2009-09-30 11:39:41Z dennis.spreen $ */ History
1.3 DS Improved Callback, now uses pointer instead of object index Modified RegisterFunctions to allow methods from other class to be registered, moved object table into TLua class
1.2 DS Added example on how to extend lua with a delphi dll
1.1 DS Improved global object table, this optimizes the delphi function calls
1.0 DS Initial Release Copyright 2009 Dennis D. Spreen (email : dennis@spreendigital.de) This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
} unit Lua; interface uses Classes, LuaLib; type TLuaState = Lua_State; TLua = class(TObject) private fAutoRegister: Boolean; CallbackList: TList; // internal callback list public LuaInstance: TLuaState; // Lua instance constructor Create(AutoRegister: Boolean = True); overload; virtual; destructor Destroy; override; function DoFile(Filename: String): Integer; virtual;// load file and execute procedure RegisterFunction(FuncName: AnsiString; MethodName: AnsiString = ''; Obj: TObject = NIL); virtual; //register function procedure AutoRegisterFunctions(Obj: TObject); // register all published functions procedure UnregisterFunctions(Obj: TObject); // unregister all object functions end; implementation type TProc = function(L: TLuaState): Integer of object; // Lua Function TCallback = class Routine: TMethod; // Code and Data for the method Exec: TProc; // Resulting execution function end; //
// This function is called by Lua, it extracts the object by
// pointer to the objects method by name, which is then called.
//
// @param Lua_State L Pointer to Lua instance
// @return Integer Number of result arguments on stack
//
function LuaCallBack(L: Lua_State): Integer; cdecl;
var CallBack: TCallBack; // The Object stored in the Object Table
begin // Retrieve first Closure Value (=Object Pointer) CallBack := lua_topointer(L, lua_upvalueindex(1)); // Execute only if Object is valid if (assigned(CallBack) and assigned(CallBack.Exec)) then Result := CallBack.Exec(L) else Result := 0;
end; { TLua } //
// Create a new Lua instance and optionally create Lua functions
//
// @param Boolean AutoRegister (optional)
// @return TLua Lua Instance
//
constructor TLua.Create(AutoRegister: Boolean = True);
begin inherited Create; // Load Lua Lib if not already done if (not LuaLibLoaded) then LoadLuaLib(); // Open Library LuaInstance := Lua_Open(); luaopen_base(LuaInstance); fAutoRegister := AutoRegister; // Create Object List on initialization CallBackList := TList.Create; // if set then register published functions if (AutoRegister) then AutoRegisterFunctions(self);
end; //
// Dispose Lua instance
//
destructor TLua.Destroy;
begin // Unregister all functions if previously autoregistered if (fAutoRegister) then UnregisterFunctions(Self); // dispose Object List on finalization CallBackList.Free; // Close instance Lua_Close(LuaInstance); inherited;
end; //
// Wrapper for Lua File load and Execution
//
// @param String Filename Lua Script file name
// @return Integer
//
function TLua.DoFile(Filename: String): Integer;
begin Result := lual_dofile(LuaInstance, PAnsiChar(AnsiString(Filename)));
end; //
// Register a new Lua Function and map it to the Objects method name
//
// @param AnsiString FuncName Lua Function Name
// @param AnsiString MethodName (optional) Objects Method name
//
procedure TLua.RegisterFunction(FuncName: AnsiString; MethodName: AnsiString = ''; Obj: TObject = NIL);
var CallBack: TCallBack; // Callback Object
begin // if method name not specified use Lua function name if (MethodName = '') then MethodName := FuncName; // if not object specified use this object if (Obj = NIL) then Obj := Self; // Add Callback Object to the Object Index CallBack := TCallBack.Create; CallBack.Routine.Data := Obj; CallBack.Routine.Code := Obj.MethodAddress(String(MethodName)); CallBack.Exec := TProc(CallBack.Routine); CallbackList.Add(CallBack); // prepare Closure value (Method Name) lua_pushstring(LuaInstance, PAnsiChar(FuncName)); // prepare Closure value (CallBack Object Pointer) lua_pushlightuserdata(LuaInstance, CallBack); // set new Lua function with Closure value lua_pushcclosure(LuaInstance, LuaCallBack, 1); lua_settable(LuaInstance, LUA_GLOBALSINDEX);
end; //
// UnRegister all new Lua Function
//
// @param TObject Object Object with prev registered lua functions
//
procedure TLua.UnregisterFunctions(Obj: TObject);
var I: Integer; CallBack: TCallBack;
begin // remove obj from object list for I := CallBackList.Count downto 1 do begin CallBack := CallBackList[I-1]; if (assigned(CallBack)) and (CallBack.Routine.Data = Obj) then begin CallBack.Free; CallBackList.Items[I-1] := NIL; CallBackList.Delete(I-1); end; end;
end; //
// Registe