一、创建一个exe程序
创建一个exe程序,引用LuaRedis.pas单元(此单元自己封装的代码,目前主要封装了获取key和设置key/value功能),代码如下:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = 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;
var
Form1: TForm1;
implementation
uses
LuaRedis;
{$R *.dfm}
procedure TForm1.btn2Click(Sender: TObject);
var
sTmp, sErrorMsg: string;
begin
Memo1.Text := '';
try
sTmp := getValue(Trim(edt1.Text), sErrorMsg); // value111
Memo1.Text := sTmp + '->' + sErrorMsg;
except
on e:Exception do begin
ShowMessage('【异常】' + e.Message);
Exit;
end;
end;
end;
procedure TForm1.btn3Click(Sender: TObject);
var
sKey, sValue, sErrorMsg: string;
begin
Memo1.Text := '';
try
sKey := Trim(edt2.Text);
if setKeyValue(sKey, Trim(edt3.Text), StrToIntDef(Trim(edt4.Text), 0), sErrorMsg) then begin // key111 value111
sValue := getValue(Trim(edt2.Text), sErrorMsg);
end;
Memo1.Text := sKey + ':' + sValue + '->' + sErrorMsg;
except
on e:Exception do begin
ShowMessage('【异常】' + e.Message);
Exit;
end;
end;
end;
end.
二、封装LuaRedis.pas单元代码
上面说的封装LuaRedis.pas单元(通过registerLuaState()和destroyLuaState()来加载和销毁lua的状态机),同时引用Lua.pas, LuaLib.pas单元,代码如下:
unit LuaRedis;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Lua, LuaLib;
const
C_LuaPathFileName = './luaScript/mytest.lua';
function getValue(myKey: string; var sErrorMsg: string): string;
function setKeyValue(myKey, myValue: string; myExpire: Integer; var sErrorMsg: string): Boolean;
var
LuaObj: TLua;
L: TLuaState;
implementation
function loadLuaScript(sLuaPathFileName: String; var sErrorMsg: string): Boolean;
var
nTmp: Integer;
begin
Result := False;
try
sErrorMsg := '默认提示消息(loadLuaScript)!';
if not FileExists(sLuaPathFileName) then begin
sErrorMsg := '未查到路径中此Lua脚本文件(' + sLuaPathFileName + ')';
Exit;
end;
nTmp := LuaObj.DoFile(sLuaPathFileName);
case nTmp of
LUA_OK : begin
sErrorMsg := '成功加载路径中此Lua脚本文件!';
Result := True;
end;
LUA_ERRSYNTAX : sErrorMsg := '在预编译Lua文件时发现了语法错误!';
LUA_ERRMEM : sErrorMsg := '在执行Lua文件时内存分配错误!';
LUA_ERRRUN : sErrorMsg := '在执行Lua文件中在调用函数时发生了运行时错误!';
else
sErrorMsg := '加载失败路径中此Lua脚本文件!';
end;
except
on e:Exception do begin
Result := False;
sErrorMsg := '【异常】方法(loadLuaScript):' + e.Message;
Exit;
end;
end;
end;
function getValue(myKey: string; var sErrorMsg: string): string;
var
nRet: Integer;
begin
try
sErrorMsg := '默认提示消息(getValue)!';
if not loadLuaScript(C_LuaPathFileName, sErrorMsg) then begin
Exit;
end;
lua_getglobal(L, 'getValue');
lua_pushstring(L, PAnsiChar(myKey));
nRet := lua_pcall(L, 1, 1, 0);
if nRet = 0 then begin
Result := lua_toString(L, -1);
sErrorMsg := 'Lua脚本正常执行';
Exit;
end else
sErrorMsg := 'Lua脚本执行失败!';
except
on e:Exception do begin
Result := '';
sErrorMsg := '【异常】方法(getValue):' + e.Message;
Exit;
end;
end;
end;
function setKeyValue(myKey, myValue: string; myExpire: Integer; var sErrorMsg: string): Boolean;
var
nRet: Integer;
begin
Result := False;
try
sErrorMsg := '默认提示消息(setKeyValue)!';
if not loadLuaScript(C_LuaPathFileName, sErrorMsg) then begin
Exit;
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 begin
Result := (lua_toInteger(L, -1) = 1);
sErrorMsg := 'Lua脚本正常执行';
Exit;
end else
sErrorMsg := 'Lua脚本执行失败!';
except
on e:Exception do begin
Result := False;
sErrorMsg := '【异常】方法(setKeyValue):' + e.Message;
Exit;
end;
end;
end;
procedure registerLuaState();
begin
if LuaObj = nil then begin
LuaObj := TLua.Create;
if L = nil then begin
L := 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();
begin
if LuaObj <> nil then begin
if L <> nil then begin
L := nil;
end;
LuaObj.Free;
end;
end;
initialization
registerLuaState();
finalization
destroyLuaState();
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