unit LuaHandler;



{todo: Split up into smaller units. 9255 lines is becomming too big}
{todo2: dll injecting lua into a target process}


{Note:
Assume all strings passed between lua are in UTF8 format
}

{$mode delphi}

interface

uses
  {$ifdef darwin}
  mactypes, macport, LCLIntf, LCLType, macCreateRemoteThread, dynlibs,
  {$endif}
  {$ifdef windows}
  jwawindows, windows, ShellApi,
  {$endif}
  vmxfunctions, Classes, dialogs, SysUtils, lua, lualib,
  lauxlib, syncobjs, CEFuncProc, NewKernelHandler, Graphics,
  controls, LuaCaller, forms, ExtCtrls, StdCtrls, comctrls, ceguicomponents,
  genericHotkey, luafile, xmplayer_server, ExtraTrainerComponents, customtimer,
  menus, XMLRead, XMLWrite, DOM, Clipbrd, typinfo, PEInfoFunctions,
  LCLProc, strutils, registry, md5, commonTypeDefs, LResources, Translations,
  variants, LazUTF8, zstream, MemoryQuery, LCLVersion
  {$ifdef darwin}
  ,macportdefines
  {$endif};


const MAXTABLERECURSIONLOOKUP=2;

var
  _LuaVM: Plua_State;  //Global lua state (generally not used by anything except creating threads)
  _LuaCS: Tcriticalsection; //critical section for the _LuaVM state

threadvar
  Thread_LuaVM: PLua_State;
  Thread_LuaRef: integer;

function lua_strtofloat(s: string): double;
function lua_strtoint(s: string): integer;

procedure lua_register(L: Plua_State; const n: PChar; f: lua_CFunction);
function lua_pcall(L: Plua_State; nargs, nresults, errf: Integer): Integer; cdecl;
function lua_dostring(L: Plua_State; const str: PChar): Integer;

function luaL_ref(L: Plua_State; t: Integer): Integer; cdecl;
procedure luaL_unref(L: Plua_State; t, ref: Integer); cdecl;


procedure Lua_RegisterObject(name: string; o: TObject);
function CheckIfConditionIsMetContext(threadid: dword; context: PContext; script: string): boolean;
procedure LUA_DoScript(s: string);
function LUA_functioncall(routinetocall: string; parameters: array of const): integer;
procedure LUA_memrec_callback(memrec: pointer; routine: string);
procedure LUA_SetCurrentContextState(tid: dword; context: PContext; extraregs: boolean=false);
procedure LUa_GetNewContextState(context: PContext; extraregs: boolean=false);

function LUA_onBreakpoint(threadid: dword; context: PContext; functionAlreadyPushed: boolean=false): boolean;
procedure LUA_onNotify(functionid: integer; sender: tobject);
function Lua_ToString(L: Plua_State; i: Integer): string;
function lua_ToCEUserData(L: PLua_state; i: integer): pointer;
function lua_tovariant(L: PLua_state; i: integer): variant;
procedure lua_pushvariant(L: PLua_state; v: variant);
procedure lua_pushrect(L: PLua_state; r: TRect);
procedure lua_pushpoint(L: PLua_state; r: TPoint);
function lua_toRect(L: PLua_State; index: integer): TRect;
function lua_toPoint(L: PLua_State; index: integer): TPoint;
function lua_toaddress(L: PLua_state; i: integer; self: boolean=false): ptruint;
procedure lua_pushcontext(L: PLua_state; context: PContext);
procedure InitializeLuaScripts(noautorun: boolean=false);
procedure InitializeLua;


function LuaValueToDescription(L: PLua_state; i: integer; recursivetablecount: integer=0): string;

function GetLuaState: PLUA_State; inline;
function LuaVM: PLUA_State; inline;



function lua_oldprintoutput:TStrings;
procedure lua_setPrintOutput(output: TStrings);

function lua_synchronize(L: Plua_State): integer; cdecl;

resourcestring
  rsPluginAddress = 'Plugin Address';
  rsThisTypeIsNotSupportedHere='This type is not supported here';
  rsIncorrectNumberOfParameters='Incorrect number of parameters';

implementation

uses autoassembler, mainunit, MainUnit2, LuaClass, frmluaengineunit, plugin, pluginexports,
  formsettingsunit, MemoryRecordUnit, debuggertypedefinitions, symbolhandler,
  symbolhandlerstructs,
  frmautoinjectunit, simpleaobscanner, addresslist, memscan, foundlisthelper,
  cesupport, DBK32functions, sharedMemory, disassemblerComments, disassembler,
  LuaCanvas, LuaPen, LuaFont, LuaBrush, LuaPicture, LuaMenu, LuaDebug, LuaThread,
  LuaGraphic, LuaProgressBar, LuaOldD3DHook, LuaWinControl, LuaMemoryRecord,
  LuaForm, MemoryBrowserFormUnit, disassemblerviewunit, hexviewunit,
  CustomTypeHandler, LuaStructure, LuaRegion, LuaXMPlayer, LuaMemscan, LuaFoundlist,
  LuaRadioGroup, LuaRasterImage, LuaCheatComponent, LuaAddresslist, byteinterpreter,
  OpenSave, CEDebugger, DebugHelper, StructuresFrm2, Assemblerunit, LuaObject,
  LuaComponent, LuaControl, LuaStrings, LuaStringlist, LuaCustomControl,
  LuaGraphicControl, LuaPanel, LuaImage, LuaButton, LuaCheckbox, LuaGroupbox,
  LuaListbox, LuaCombobox, LuaTrackbar, LuaListcolumn, LuaEdit, LuaMemo, LuaCollection,
  LuaListColumns, LuaListItem, LuaListItems, LuaTimer, LuaListview, LuaGenericHotkey,
  LuaTableFile, LuaMemoryRecordHotkey, LuaMemoryView, LuaD3DHook, LuaDisassembler,
  LuaDissectCode, LuaByteTable, LuaBinary, lua_server, HotkeyHandler, LuaPipeClient,
  LuaPipeServer, LuaTreeview, LuaTreeNodes, LuaTreeNode, LuaCalendar, LuaSymbolListHandler,
  LuaCommonDialog, LuaFindDialog, LuaSettings, LuaPageControl, LuaStructureFrm,
  LuaInternet, SymbolListHandler, ProcessHandlerUnit, processlist,
  DebuggerInterface, WindowsDebugger, VEHDebugger, KernelDebuggerInterface,
  DebuggerInterfaceAPIWrapper, Globals, math, speedhack2, CETranslator, binutils,
  xinput, winsapi, frmExeTrainerGeneratorUnit, CustomBase85, FileUtil, networkConfig,
  LuaCustomType, Filehandler, LuaSQL, frmSelectionlistunit, cpuidUnit, LuaRemoteThread,
  LuaManualModuleLoader, pointervaluelist, frmEditHistoryUnit, LuaCheckListBox,
  LuaDiagram, frmUltimap2Unit, frmcodefilterunit, BreakpointTypeDef, LuaSyntax,
  LazLogger, LuaSynedit, LuaRIPRelativeScanner, LuaCustomImageList ,ColorBox,
  rttihelper;

  {$warn 5044 off}

resourcestring
  rsLUA_DoScriptWasNotCalledRomTheMainThread = 'LUA_DoScript was not called '
    +'from the main thread';
  rsUndefinedLuaError = 'Undefined lua error';
  rsCheatengineIsBeingAFag = 'Cheatengine is being a fag';

  rsInvalidFloat = 'Invalid floating point string:%s';
  rsInvalidInt = 'Invalid integer:%s';
  rsError = 'Error:';
  rsConditionalBreakpointError = 'Conditional breakpoint error';
  rsNonMainthreadLuaError = 'Lua error in a secondary thread';
  rsMainLuaError = 'main.lua error:';
  rsMainLuaError2 = 'main.lua error';
  rsError2 = ' error:';
  rsError3 = ' error';
  rsLUAPanic = 'LUA panic!';
  rsDebugsetBreakpointNeedsAtLeastAnAddress = 'debug_setBreakpoint needs at least an address';
  rsCreateMemScanNeedsAProgressbarOrNil = 'createMemScan needs a progressbar or nil. ';
  rsIsNotAProgressbar = ' is not a progressbar';
  rsDeallocateSharedMemoryIsNotImplemented = 'deallocateSharedMemory is not implemented (It''s not even in the list of available functions)';
  rsGetProcessListTheProvidedListObjectIsNotValid = 'getProcessList: the provided List object is not valid';
  rsGetThreadlistTheProvidedListObjectIsNotValid = 'getThreadlist: the provided List object is not valid';
  rsPlaySoundTheParameterMustBeATableFileOrAMemoryStream = 'playSound: The parameter must be a table file or a memory stream. Nothing else';
  rsNumberRequired = 'Number required';
  rsScriptCorruptedVar = '%s has corrupted the global %s variable. Many scripts will fail to load now';

var
  printoutput: TStrings;

  waitforsymbols: boolean=true;

  autorunpath: string;


function lua_oldprintoutput:TStrings;
begin
  result:=printoutput;
end;

procedure lua_setPrintOutput(output: TStrings);
begin
  printoutput:=output;
end;


function GetLuaState: PLUA_State; inline;
begin
  if Thread_LuaVM=nil then
  begin
    _luacs.Enter;
    try
      Thread_LuaVM:=lua_newthread(_luavm);
      Thread_LuaRef:=luaL_ref(_luavm, LUA_REGISTRYINDEX);
    finally
      _luacs.leave;
    end;
  end;

  result:=Thread_LuaVM;
end;

function LuaVM: PLUA_State; inline;
begin
  result:=GetLuaState;
end;



procedure lua_register(L: Plua_State; const n: PChar; f: lua_CFunction);
//overriding the original lua_register to add both a lower and uppercase start
var s: string;
begin
  if luasyntaxStringHashList<>nil then
    luasyntaxStringHashList.Add(n);

  lua.lua_register(L, n, f);
  s:=n;
  s[1]:=chr(ord(s[1]) xor $20); //switch from uppercase to lowercase and lowercase to uppercase

  lua.lua_register(L, pchar(s), f);

  if luasyntaxStringHashList<>nil then
    luasyntaxStringHashList.Add(s);
end;

var luarefcs: TCriticalSection;
function luaL_ref(L: Plua_State; t: Integer): Integer; cdecl;
begin
  luarefcs.Enter;
  result:=lauxlib.luaL_ref(l, t);
  luarefcs.leave;
end;

procedure luaL_unref(L: Plua_State; t, ref: Integer); cdecl;
begin
  luarefcs.enter;
  lauxlib.luaL_unref(l, t, ref);
  luarefcs.leave;
end;

//todo: let the user define a default error function
function lua_pcall(L: Plua_State; nargs, nresults, errf: Integer): Integer; cdecl;
var
  error: string;
  usesluaengineform: boolean;
begin
  try
    if lua_isfunction(L, (-nargs)-1)=false then
    begin
      lua_pop(L,nargs+1);

      outputdebugstring(pchar('lua_pcall with invalid parameter'));
      //MessageBoxA(0, pchar('lua_pcall with invalid parameter'), pchar('Lua: Not a function'), MB_OK);
      exit(LUA_ERRRUN);
    end;

    result:=lua.lua_pcall(L, nargs, nresults, errf);
  except
    on e: exception do
    begin
      lua_pop(L, lua_gettop(L));
      result:=LUA_ERRRUN;
      lua_pushstring(l, e.Message);

      if (GetCurrentThreadId=MainThreadID) and (e.Message='Access violation') and mainform.miEnableLCLDebug.checked then
      begin
        DebugLn('Lua Exception: '+e.Message);
        lazlogger.DumpExceptionBackTrace;
      end;
    end;
  end;

  if (result=LUA_ERRRUN) and (errf=0) then //an error occured and no error handler was specified
  begin
    if GetCurrentThreadId=MainThreadID then
    begin


      //lua_Debug
      error:=Lua_ToString(l, -1);
      if (error<>'') then
      begin
        usesluaengineform:=false;
        if printoutput=nil then
        begin
          if frmLuaEngine=nil then
            frmLuaEngine:=TfrmLuaEngine.Create(application);

          printoutput:=frmLuaEngine.mOutput.Lines;
          usesluaengineform:=true;
        end;

        printoutput.add(rsError+error);

        if (frmLuaEngine<>nil) and usesluaengineform and (frmLuaEngine.cbShowOnPrint.checked) then
          frmLuaEngine.show;

        if usesluaengineform then
          printoutput:=nil;

        lua_pop(L, lua_gettop(L));
      end;
    end
    else
    begin
      //MessageBoxA(0, pchar(Lua_ToString(l, -1)), pchar(rsNonMainthreadLuaError), MB_OK);
    end;
  end;
end;

function lua_dostring(L: Plua_State; const str: PChar): Integer;
begin
  Result := luaL_loadstring(L, str);
  if Result = 0 then
    Result := lua_pcall(L, 0, LUA_MULTRET, 0);
end;

function lua_isstring(L: PLua_state; i: integer): boolean;
begin
  result := lua_type(L,i)=LUA_TSTRING;
end;

function Lua_ToString(L: Plua_State; i: Integer): string;
var r: pchar;
begin
  if lua_islightuserdata(L, i) then
    Result := inttohex(ptruint(lua_touserdata(L, i)),1)
  else
  begin
    r := lua.lua_tostring(l,i);
    if r<>nil then
      result:=r
    else
      result:='';
  end;


//unclear should there be a result:=Utf8ToAnsi(s); ?
end;

function lua_toRect(L: PLua_State; index: integer): TRect;
var i: integer;
begin
  ZeroMemory(@result,sizeof(trect));

  i:=lua_absindex(L,index);

  if lua_istable(L, i) then
  begin
    lua_pushstring(L,'Left');
    lua_gettable(L, i);
    result.Left:=lua_tointeger(L,-1);
    lua_pop(L,1);

    lua_pushstring(L,'Top');
    lua_gettable(L, i);
    result.Top:=lua_tointeger(L,-1);
    lua_pop(L,1);

    lua_pushstring(L,'Right');
    lua_gettable(L, i);
    result.Right:=lua_tointeger(L,-1);
    lua_pop(L,1);

    lua_pushstring(L,'Bottom');
    lua_gettable(L, i);
    result.Bottom:=lua_tointeger(L,-1);
    lua_pop(L,1);
  end;

end;

procedure lua_pushrect(L: PLua_state; r: TRect);
begin
  lua_createtable(L, 0,4);
  lua_pushstring(L, 'Left');
  lua_pushinteger(L, r.left);
  lua_settable(L, -3);

  lua_pushstring(L, 'Top');
  lua_pushinteger(L, r.top);
  lua_settable(L, -3);

  lua_pushstring(L, 'Right');
  lua_pushinteger(L, r.right);
  lua_settable(L, -3);

  lua_pushstring(L, 'Bottom');
  lua_pushinteger(L, r.bottom);
  lua_settable(L, -3);
end;


function lua_toPoint(L: PLua_State; index: integer): TPoint;
var i: integer;
begin
  result.x:=0;
  result.y:=0;

  i:=lua_absindex(L,index);
  if lua_istable(L, i) then
  begin
    lua_pushstring(L,'x');
    lua_gettable(L,i);

    if lua_isnil(L,-1) then
    begin
      lua_pop(L,1);
      lua_pushinteger(L,1);
      lua_gettable(L,i);
    end;

    result.x:=lua_tointeger(L,-1);
    lua_pop(L,1);

    lua_pushstring(L,'y');
    lua_gettable(L,i);
    if lua_isnil(L,-1) then
    begin
      lua_pop(L,1);
      lua_pushinteger(L,1);
      lua_gettable(L,i);
    end;

    result.y:=lua_tointeger(L,-1);
    lua_pop(L,1);
  end;
end;

procedure lua_pushpoint(L: PLua_state; r: TPoint);
begin
  lua_createtable(L, 0,2);
  lua_pushstring(L,'x');
  lua_pushinteger(L,r.x);
  lua_settable(L, -3);

  lua_pushstring(L,'y');
  lua_pushinteger(L,r.y);
  lua_settable(L, -3);
end;

procedure lua_pushvariant(L: PLua_state; v: variant);
begin
  case (tvardata(v).vtype and vartypemask) of
    varempty: lua_pushnil(L);
    varnull: lua_pushnil(L);
    varsmallint, varinteger, vardecimal, varshortint, varbyte, varword, varlongword, varint64, varqword: lua_pushinteger(L, v);
    varsingle, vardouble: lua_pushnumber(L, v);
    varboolean: lua_pushboolean(L, v);
    varstring, varustring: lua_pushstring(L, v);
    else
      lua_pushstring(L, v);
  end;
end;

function lua_tovariant(L: PLua_state; i: integer): variant;
begin
  case lua_type(L, i) of
    LUA_TNONE          : result:=nil;
    LUA_TNIL           : result:=nil;
    LUA_TBOOLEAN       : result:=lua_toboolean(L, i);
    LUA_TNUMBER        : result:=lua_tonumber(L, i);
    LUA_TSTRING        : result:=Lua_ToString(L, i);
    else
      raise exception.create(rsThisTypeIsNotSupportedHere);

  end;
end;

function lua_ToCEUserData(L: PLua_state; i: integer): pointer;
//Cheat Engine implements two types of userdata. the legacy LightUserData used in 6.2- and the Heavy UserData in 6.3+
//Heavy UserData is a pointer with a pointer to the real object, while lightuserdata is just a pointer to the object
begin
  result:=lua_touserdata(L,i);

  if (result<>nil) and (lua_isheavyuserdata(L, i)) then   //once the conversion is done this if check if it's userdata can go as it will always be userdata
    result:=ppointer(result)^;
end;


function lua_toaddress(L: PLua_state; i: integer; self: boolean=false): ptruint; inline;
begin
  if lua_type(L,i)=LUA_TSTRING then
  begin
    if self then
      result:=selfsymhandler.getAddressFromNameL(lua_tostring(L,i),waitforsymbols)
    else
      result:=symhandler.getAddressFromNameL(lua_tostring(L,i),waitforsymbols)
  end
  else
    result:=lua_tointeger(L,i);
end;

function LuaValueToDescription(L: PLua_state; i: integer; recursivetablecount: integer=0): string;
var index, count: integer;
  fieldname: string;
  valuedesc: string;
  o: tobject;

  tablepad: string;

  stackstart: integer;
begin
  result:='';


  if not lua_isnil(L, i) then
  begin
    if lua_isuserdata(L, i) then
    begin
      stackstart:=lua_gettop(L);

      o:=lua_ToCEUserData(L, i);

      try
        if o is TObject then
        begin
          result:='Object of type '+o.ClassName;
          if o is TControl then
            result:=result+#13#10+tcontrol(o).Name;
        end;
      except
      end;

      index:=lua_gettop(l);
      lua_settop(l, stackstart);
    end
    else
    if lua_iscfunction(L, i) then
      result:='native function'
    else
    if lua_isfunction(L, i) then
      result:='function'
    else
    if lua_istable(L, i) then
    begin
      result:='table';

      if recursivetablecount<MAXTABLERECURSIONLOOKUP then
      begin
        tablepad:=DupeString('   ',recursivetablecount);

        stackstart:=lua_gettop(l);


        result:=result+#13#10+tablepad+'['+#13#10;;
        count:=10;
        lua_pushvalue(L, i);
        index:=lua_gettop(L);
        lua_pushnil(L);  //first key (nil)
        while lua_next(L, index)<>0 do
        begin
          count:=count-1;
          if count<0 then
          begin

            result:=result+tablepad+'...'+#13#10;;
            break;
          end;

          if lua_type(L,-2)=LUA_TSTRING then
            fieldname:=Lua_ToString(L, -2)
          else
            fieldname:=inttostr(lua_tointeger(L, -2));


          valuedesc:=LuaValueToDescription(L, -1, recursivetablecount+1);

          result:=result+tablepad+'   '+fieldname+' = '+valuedesc+#13#10;


          lua_pop(L, 1); //pop the value, keep the key
        end;

//        lua_pop(L,1); //pop the pushvalue from before



        lua_settop(l, stackstart);

        result:=result+tablepad+']';
      end;
    end
    else
    if lua_isboolean(L, i) then
      result:=BoolToStr(lua_toboolean(L,i),'true','false')
    else
      result:=Lua_ToString(L, i);
  end
  else
    result:='nil';
end;

procedure InitializeLuaScripts(noautorun: boolean=false);
var f: string;
  i,r: integer;
  pc: pchar;
  DirInfo: TSearchRec;
  mainformwasset: boolean=true;
  addresslistwasset: boolean=true;


begin
  lua_getglobal(LuaVM,'MainForm');
  if lua_isnil(LuaVM,-1) then
  begin
    MessageDlg('MainForm is undefined. Invalid CE Build', mtError, [mbok],0);
    mainformwasset:=false;
  end;
  lua_pop(LuaVM,1);

  lua_getglobal(LuaVM,'AddressList');
  if lua_isnil(LuaVM,-1) then
  begin
    MessageDlg('AddressList is undefined. Invalid CE Build', mtError, [mbok],0);
    addresslistwasset:=false;
  end;
  lua_pop(LuaVM,1);


  f:='main.lua';
  {$ifdef darwin}
  f:=extractfiledir(extractfiledir(Application.ExeName))+'/Lua/main.lua';
  {$endif}
  if not FileExists(f) then //perhaps in the cedir
  begin
    f:=CheatEngineDir+'main.lua';
    if not FileExists(f) then
    begin
      //try the defines only then
      f:='defines.lua';
      if not FileExists(f) then
      begin
        f:=CheatEngineDir+'defines.lua';
        if not FileExists(f) then
          exit;
      end;
    end;
  end;

  //file exists


  try
    if lua_dofile(luavm, pchar(f))<>0 then
    begin
      i:=lua_gettop(luavm);
      if i>0 then
      begin
        pc:=lua_tolstring(luavm, -1,nil);
        if pc<>nil then
          showmessage(rsMainLuaError+pc)
        else
          showmessage(rsMainLuaError2);
      end
      else showmessage(rsMainLuaError2);

    end;


  finally
    lua_pop(LuaVM, lua_gettop(luavm)); //reset stack
  end;

  //autorun folder

  if noautorun=false then
  begin


    ZeroMemory(@DirInfo,sizeof(TSearchRec));
    r := FindFirst(autorunpath+'*.lua', FaAnyfile, DirInfo);

    while (r = 0) do
    begin
      if (DirInfo.Attr and FaVolumeId <> FaVolumeID) then
      begin
        if ((DirInfo.Attr and FaDirectory) <> FaDirectory) then
        begin
          i:=lua_dofile(luavm, pchar( UTF8ToWinCP(autorunpath+DirInfo.name)));
          if i<>0 then //error
          begin
            i:=lua_gettop(luavm);
            if i>0 then
            begin
              pc:=lua_tolstring(luavm, -1,nil);
              if pc<>nil then
                showmessage(DirInfo.name+rsError2+pc)
              else
                showmessage(DirInfo.name+rsError3);
            end
            else showmessage(DirInfo.name+rsError3);
          end;

          //reset stack
          lua_pop(LuaVM, lua_gettop(luavm));

          if mainformwasset then
          begin
            lua_getglobal(LuaVM,'MainForm');
            if lua_isnil(LuaVM,-1) then
            begin
              MessageDlg(format(rsScriptCorruptedVar, [autorunpath+DirInfo.name, 'MainForm']), mtError,[mbOK],0);
              mainformwasset:=false;
            end;
            lua_pop(LuaVM,1);
          end;

          if addresslistwasset then
          begin
            lua_getglobal(LuaVM,'AddressList');
            if lua_isnil(LuaVM,-1) then
            begin
              MessageDlg(format(rsScriptCorruptedVar, [autorunpath+DirInfo.name, 'AddressList']), mtError,[mbOK],0);
              addresslistwasset:=false;
            end;
            lua_pop(LuaVM,1);
          end;

        end;
      end;
      r := FindNext(DirInfo);
    end;
    FindClose(DirInfo);
  end;



  if translationfilepath<>'' then
  begin
    if FileExists(translationfilepath+'init.lua') then
    begin
      lua_dofile(luavm, pchar(translationfilepath+'init.lua'));
      lua_pop(LuaVM, lua_gettop(luavm));

      if mainformwasset then
      begin
        lua_getglobal(LuaVM,'MainForm');
        if lua_isnil(LuaVM,-1) then
        begin
          MessageDlg(format(rsScriptCorruptedVar, [translationfilepath+'init.lua', 'MainForm']), mtError,[mbOK],0);
          mainformwasset:=false;
        end;
        lua_pop(LuaVM,1);
      end;

      if addresslistwasset then
      begin
        lua_getglobal(LuaVM,'AddressList');
        if lua_isnil(LuaVM,-1) then
        begin
          MessageDlg(format(rsScriptCorruptedVar, [translationfilepath+'init.lua', 'AddressList']), mtError,[mbOK],0);
          addresslistwasset:=false;
        end;
        lua_pop(LuaVM,1);
      end;
    end;
  end;

  lua_settop(LuaVM,0);
end;

function lua_strtofloat(s: string): double;
var stackpos: integer;
  s2: integer;
begin

  try
    stackpos:=lua_gettop(luavm);
    if lua_dostring(luavm, pchar('return '+s) )=0 then
    begin
      s2:=lua_gettop(luavm);
      if (s2-stackpos)>0 then
        result:=lua_tonumber(luavm, stackpos-s2)
      else
        raise exception.create(Format(rsInvalidFloat, [s]));
    end
    else
      raise exception.create(Format(rsInvalidFloat, [s]));

  finally
    lua_settop(luavm, stackpos);
  end;
end;

function lua_strtoint(s: string): integer;
var stackpos: integer;
  s2: integer;
begin
  try
    stackpos:=lua_gettop(luavm);
    if lua_dostring(luavm, pchar('return '+s) )=0 then
    begin
      s2:=lua_gettop(luavm);
      if (s2-stackpos)>0 then
      begin
        if lua_isnil(luavm,-1)=false then
          result:=lua_tointeger(luavm, stackpos-s2)
        else
          raise exception.create(rsInvalidInt);
      end
      else
        raise exception.create(Format(rsInvalidInt, [s]));
    end
    else
      raise exception.create(Format(rsInvalidInt, [s]));

  finally
    lua_settop(luavm, stackpos);
  end;

end;

procedure Lua_RegisterObject(name: string; o: TObject);
var s: integer;
begin
  s:=lua_gettop(LuaVM);
  luaclass_newClass(LuaVM, o);
  lua_setglobal(LuaVM, pchar(name));

  lua_settop(LuaVM, s);
end;

function LUA_onBreakpoint(threadid: dword; context: PContext; functionAlreadyPushed: boolean=false): boolean;
var p: integer;
begin
  result:=false;
  try
    LUA_SetCurrentContextState(threadid, context);


    if not functionAlreadyPushed then
    begin
      lua_pop(LuaVM, lua_gettop(luavm)); //clear it just to be sure

      lua_getglobal(luavm, pchar('debugger_onBreakpoint'));
      p:=lua_gettop(luavm);
      if p=0 then exit;
    end;

    if lua_isfunction(luavm, -1) then //extra check
    begin
      if lua_pcall(LuaVM, 0, 1, 0)=0 then
      begin
        p:=lua_gettop(luavm);

        if (p=1) then //only 1 parameter returned
          result:=lua_tointeger(luavm, -1)<>0;  //return the result is not 0


        lua_pop(LuaVM, lua_gettop(luavm)); //clear stack

        //set new state if changes where made
        LUA_GetNewContextState(context);
      end;
    end;

  finally
    lua_pop(LuaVM, lua_gettop(luavm));
  end;
end;

procedure lua_pushcontext(L: PLua_state; context: PContext);
var
  t: integer;
  i: integer;
begin
  lua_newtable(L);
  t:=lua_gettop(L);

  lua_pushstring(L, 'ContextFlags');
  lua_pushinteger(L,context^.ContextFlags);
  lua_settable(L,t);

  lua_pushstring(L, 'CS');
  lua_pushinteger(L,context^.SegCs);
  lua_settable(L,t);

  lua_pushstring(L, 'DS');
  lua_pushinteger(L,context^.SegDs);
  lua_settable(L,t);

  lua_pushstring(L, 'ES');
  lua_pushinteger(L,context^.SegEs);
  lua_settable(L,t);

  lua_pushstring(L, 'FS');
  lua_pushinteger(L,context^.SegFs);
  lua_settable(L,t);

  lua_pushstring(L, 'GS');
  lua_pushinteger(L,context^.SegGs);
  lua_settable(L,t);

  lua_pushstring(L, 'SS');
  lua_pushinteger(L,context^.SegSs);
  lua_settable(L,t);

  lua_pushstring(L, 'EFlags');
  lua_pushinteger(L,context^.EFlags);
  lua_settable(L,t);

  {$ifdef cpu64}
  lua_pushstring(L, 'RAX');
  lua_pushinteger(L,context^.Rax);
  lua_settable(L,t);

  lua_pushstring(L, 'RBX');
  lua_pushinteger(L,context^.Rbx);
  lua_settable(L,t);

  lua_pushstring(L, 'RCX');
  lua_pushinteger(L,context^.Rcx);
  lua_settable(L,t);

  lua_pushstring(L, 'RDX');
  lua_pushinteger(L,context^.Rdx);
  lua_settable(L,t);

  lua_pushstring(L, 'RSI');
  lua_pushinteger(L,context^.Rsi);
  lua_settable(L,t);

  lua_pushstring(L, 'RDI');
  lua_pushinteger(L,context^.Rdi);
  lua_settable(L,t);

  lua_pushstring(L, 'RBP');
  lua_pushinteger(L,context^.Rbp);
  lua_settable(L,t);

  lua_pushstring(L, 'RSP');
  lua_pushinteger(L,context^.Rsp);
  lua_settable(L,t);

  lua_pushstring(L, 'RIP');
  lua_pushinteger(L,context^.Rip);
  lua_settable(L,t);

  lua_pushstring(L, 'R8');
  lua_pushinteger(L,context^.R8);
  lua_settable(L,t);

  lua_pushstring(L, 'R9');
  lua_pushinteger(L,context^.R9);
  lua_settable(L,t);

  lua_pushstring(L, 'R10');
  lua_pushinteger(L,context^.R10);
  lua_settable(L,t);

  lua_pushstring(L, 'R11');
  lua_pushinteger(L,context^.R11);
  lua_settable(L,t);

  lua_pushstring(L, 'R12');
  lua_pushinteger(L,context^.R12);
  lua_settable(L,t);

  lua_pushstring(L, 'R13');
  lua_pushinteger(L,context^.R13);
  lua_settable(L,t);

  lua_pushstring(L, 'R14');
  lua_pushinteger(L,context^.R14);
  lua_settable(L,t);

  lua_pushstring(L, 'R15');
  lua_pushinteger(L,context^.R15);
  lua_settable(L,t);
  {$endif}

  if processhandler.is64Bit=false then
  begin
    lua_pushstring(L, 'EAX');
    lua_pushinteger(L,context^.{$ifdef cpu64}Rax{$else}eax{$endif} and $ffffffff);
    lua_settable(L,t);

    lua_pushstring(L, 'EBX');
    lua_pushinteger(L,context^.{$ifdef cpu64}Rbx{$else}ebx{$endif} and $ffffffff);
    lua_settable(L,t);

    lua_pushstring(L, 'ECX');
    lua_pushinteger(L,context^.{$ifdef cpu64}Rcx{$else}ecx{$endif} and $ffffffff);
    lua_settable(L,t);

    lua_pushstring(L, 'EDX');
    lua_pushinteger(L,context^.{$ifdef cpu64}Rdx{$else}edx{$endif} and $ffffffff);
    lua_settable(L,t);

    lua_pushstring(L, 'ESI');
    lua_pushinteger(L,context^.{$ifdef cpu64}Rsi{$else}esi{$endif} and $ffffffff);
    lua_settable(L,t);

    lua_pushstring(L, 'EDI');
    lua_pushinteger(L,context^.{$ifdef cpu64}Rdi{$else}edi{$endif} and $ffffffff);
    lua_settable(L,t);

    lua_pushstring(L, 'EBP');
    lua_pushinteger(L,context^.{$ifdef cpu64}Rbp{$else}ebp{$endif} and $ffffffff);
    lua_settable(L,t);

    lua_pushstring(L, 'ESP');
    lua_pushinteger(L,context^.{$ifdef cpu64}Rsp{$else}esp{$endif} and $ffffffff);
    lua_settable(L,t);

    lua_pushstring(L, 'EIP');
    lua_pushinteger(L,context^.{$ifdef cpu64}Rip{$else}eip{$endif} and $ffffffff);
    lua_settable(L,t);
  end;

  lua_pushstring(L, 'DR0');
  lua_pushinteger(L,context^.DR0);
  lua_settable(L,t);

  lua_pushstring(L, 'DR1');
  lua_pushinteger(L,context^.DR1);
  lua_settable(L,t);

  lua_pushstring(L, 'DR2');
  lua_pushinteger(L,context^.DR2);
  lua_settable(L,t);

  lua_pushstring(L, 'DR3');
  lua_pushinteger(L,context^.DR3);
  lua_settable(L,t);

  lua_pushstring(L, 'DR6');
  lua_pushinteger(L,context^.DR6);
  lua_settable(L,t);

  lua_pushstring(L, 'DR7');
  lua_pushinteger(L,context^.DR7);
  lua_settable(L,t);


  for i:=0 to 7 do
  begin
    lua_pushstring(L,'FP'+inttostr(i));
    {$ifdef cpu32}
    CreateByteTableFromPointer(L, @context^.FloatSave.RegisterArea[10*i], 10);
    {$else}
    CreateByteTableFromPointer(L, @context^.FltSave.FloatRegisters[i], 10);
    {$endif}
    lua_settable(L,t);
  end;

  //xmm regs

  for i:=0 to 15 do
  begin
    if (i>=8) and (not processhandler.is64Bit) then break;

    lua_pushstring(L,'XMM'+inttostr(i));

    {$ifdef cpu32}
    CreateByteTableFromPointer(luavm, @context^.ext.XMMRegisters.LegacyXMM[i], 16);
    {$else}
    CreateByteTableFromPointer(luavm, @context^.FltSave.XmmRegisters[i], 16);
    {$endif}
    lua_settable(L,t);
  end;

end;

procedure LUA_SetCurrentContextState(tid: dword; context: PContext; extraregs: boolean=false);
var i: integer;
begin
  lua_pushinteger(luavm, tid);
  lua_setglobal(luavm, 'THREADID');

  {$ifdef cpu64}
  lua_pushinteger(luavm, context^.{$ifdef cpu64}Rax{$else}eax{$endif});
  lua_setglobal(luavm, 'RAX');
  {$endif}
  lua_pushinteger(luavm, context^.{$ifdef cpu64}Rax{$else}eax{$endif} and $ffffffff);
  lua_setglobal(luavm, 'EAX');

  {$ifdef cpu64}
  lua_pushinteger(luavm, context^.{$ifdef cpu64}Rbx{$else}ebx{$endif});
  lua_setglobal(luavm, 'RBX');
  {$endif}
  lua_pushinteger(luavm, context^.{$ifdef cpu64}Rbx{$else}ebx{$endif} and $ffffffff);
  lua_setglobal(luavm, 'EBX');


  {$ifdef cpu64}
  lua_pushinteger(luavm, context^.{$ifdef cpu64}Rcx{$else}ecx{$endif});
  lua_setglobal(luavm, 'RCX');
  {$endif}
  lua_pushinteger(luavm, context^.{$ifdef cpu64}Rcx{$else}ecx{$endif} and $ffffffff);
  lua_setglobal(luavm, 'ECX');

  {$ifdef cpu64}
  lua_pushinteger(luavm, context^.{$ifdef cpu64}Rdx{$else}edx{$endif});
  lua_setglobal(luavm, 'RDX');
  {$endif}
  lua_pushinteger(luavm, context^.{$ifdef cpu64}Rdx{$else}edx{$endif} and $ffffffff);
  lua_setglobal(luavm, 'EDX');


  {$ifdef cpu64}
  lua_pushinteger(luavm, context^.{$ifdef cpu64}Rsi{$else}esi{$endif});
  lua_setglobal(luavm, 'RSI');
  {$endif}
  lua_pushinteger(luavm, context^.{$ifdef cpu64}Rsi{$else}esi{$endif} and $ffffffff);
  lua_setglobal(luavm, 'ESI');


  {$ifdef cpu64}
  lua_pushinteger(luavm, context^.{$ifdef cpu64}Rdi{$else}edi{$endif});
  lua_setglobal(luavm, 'RDI');
  {$endif}
  lua_pushinteger(luavm, context^.{$ifdef cpu64}Rdi{$else}edi{$endif} and $ffffffff);
  lua_setglobal(luavm, 'EDI');


  {$ifdef cpu64}
  lua_pushinteger(luavm, context^.{$ifdef cpu64}Rbp{$else}ebp{$endif});
  lua_setglobal(luavm, 'RBP');
  {$endif}
  lua_pushinteger(luavm, context^.{$ifdef cpu64}RBP{$else}eBP{$endif} and $ffffffff);
  lua_setglobal(luavm, 'EBP');


  {$ifdef cpu64}
  lua_pushinteger(luavm, context^.{$ifdef cpu64}RSP{$else}eSP{$endif});
  lua_setglobal(luavm, 'RSP');
  {$endif}
  lua_pushinteger(luavm, context^.{$ifdef cpu64}RSP{$else}eSP{$endif} and $ffffffff);
  lua_setglobal(luavm, 'ESP');

  {$ifdef cpu64}
  lua_pushinteger(luavm, context^.{$ifdef cpu64}RIP{$else}eIP{$endif});
  lua_setglobal(luavm, 'RIP');
  {$endif}
  lua_pushinteger(luavm, context^.{$ifdef cpu64}RIP{$else}eIP{$endif} and $ffffffff);
  lua_setglobal(luavm, 'EIP');

  lua_pushinteger(luavm, context^.EFlags);
  lua_setglobal(luavm, 'EFLAGS');



  {$ifdef cpu64}
  lua_pushinteger(luavm, context^.r8);
  lua_setglobal(luavm, 'R8');

  lua_pushinteger(luavm, context^.r9);
  lua_setglobal(luavm, 'R9');

  lua_pushinteger(luavm, context^.r10);
  lua_setglobal(luavm, 'R10');

  lua_pushinteger(luavm, context^.r11);
  lua_setglobal(luavm, 'R11');

  lua_pushinteger(luavm, context^.r12);
  lua_setglobal(luavm, 'R12');

  lua_pushinteger(luavm, context^.r13);
  lua_setglobal(luavm, 'R13');

  lua_pushinteger(luavm, context^.r14);
  lua_setglobal(luavm, 'R14');

  lua_pushinteger(luavm, context^.r15);
  lua_setglobal(luavm, 'R15');
  {$endif}

  if extraregs then //default off as it's a bit slow
  begin
    for i:=0 to 7 do
    begin
      {$ifdef cpu32}
      CreateByteTableFromPointer(luavm, @context^.FloatSave.RegisterArea[10*i], 10);
      {$else}
      CreateByteTableFromPointer(luavm, @context^.FltSave.FloatRegisters[i], 10);
      {$endif}
      lua_setglobal(luavm, pchar('FP'+inttostr(i)));
    end;

    //xmm regs

    for i:=0 to 15 do
    begin
      if (i>=8) and (not processhandler.is64Bit) then break;

      {$ifdef cpu32}
      CreateByteTableFromPointer(luavm, @context^.ext.XMMRegisters.LegacyXMM[i], 16);
      {$else}
      CreateByteTableFromPointer(luavm, @context^.FltSave.XmmRegisters[i], 16);
      {$endif}
      lua_setglobal(luavm, pchar('XMM'+inttostr(i)));
    end;
  end;

end;

procedure LUA_GetNewContextState(context: PContext; extraregs: boolean=false);
var
  i: integer;
  t: integer;
begin
  lua_getglobal(luavm, 'EFLAGS');
  context.EFLAGS:=lua_tointeger(luavm, -1);
  lua_pop(luavm,1);

  if not processhandler.is64bit then
  begin
    lua_getglobal(luavm, 'EAX');
    context.{$ifdef cpu64}rax{$else}eax{$endif}:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'EBX');
    context.{$ifdef cpu64}rbx{$else}ebx{$endif}:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'ECX');
    context.{$ifdef cpu64}rcx{$else}ecx{$endif}:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'EDX');
    context.{$ifdef cpu64}rdx{$else}edx{$endif}:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'ESI');
    context.{$ifdef cpu64}rsi{$else}esi{$endif}:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'EDI');
    context.{$ifdef cpu64}rdi{$else}edi{$endif}:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'EBP');
    context.{$ifdef cpu64}rbp{$else}ebp{$endif}:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'ESP');
    context.{$ifdef cpu64}rsp{$else}esp{$endif}:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);


    lua_getglobal(luavm, 'EIP');
    context.{$ifdef cpu64}rip{$else}eip{$endif}:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

  end
  else
  begin
  {$ifdef cpu64}
    lua_getglobal(luavm, 'RAX');
    context.RAX:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'RBX');
    context.RBX:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'RCX');
    context.RCX:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'RDX');
    context.RDX:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'RSI');
    context.RSI:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'RDI');
    context.RDI:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'RBP');
    context.RBP:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'RSP');
    context.RSP:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'RIP');
    context.RIP:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'R8');
    context.R8:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'R9');
    context.R9:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'R10');
    context.R10:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'R11');
    context.R11:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'R12');
    context.R12:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'R13');
    context.R13:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'R14');
    context.R14:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);

    lua_getglobal(luavm, 'R15');
    context.R15:=lua_tointeger(luavm, -1);
    lua_pop(luavm,1);
  {$endif}
  end;

  if extraregs then
  begin
    for i:=0 to 7 do
    begin
      lua_getglobal(luavm, pchar('FP'+inttostr(i)));
      if not lua_isnil(luavm, -1) then
      begin
        t:=lua_gettop(LuaVM);
        {$ifdef cpu32}
        readBytesFromTable(luavm, t, @context.FloatSave.RegisterArea[10*i], 10);
        {$else}
        readBytesFromTable(luavm, t, @context.FltSave.FloatRegisters[i], 10);
        {$endif}
      end;
      lua_pop(luavm,1);
    end;

    for i:=0 to 15 do
    begin
      if (i>=8) and (not processhandler.is64Bit) then break;

      lua_getglobal(luavm, pchar('XMM'+inttostr(i)));
      if not lua_isnil(luavm, -1) then
      begin
        t:=lua_gettop(LuaVM);
        {$ifdef cpu32}
        readBytesFromTable(luavm, t, @context.ext.XMMRegisters.LegacyXMM[i], 16);
        {$else}
        readBytesFromTable(luavm, t, @context.FltSave.XmmRegisters[i], 16);
        {$endif}
      end;

    end;
  end;
end;

procedure LUA_DoScript(s: string);
var i: integer;
  pc: pchar;

  stack: integer;
begin
  //if GetCurrentThreadId<>MainThreadID then raise exception.create(rsLUA_DoScriptWasNotCalledRomTheMainThread);

  stack:=lua_gettop(luavm);
  try

    i:=lua_dostring(luavm, pchar(s));
    if i<>0 then
    begin
      pc:=lua.lua_tostring(luavm, -1);
      if pc<>nil then
        raise Exception.Create(pc)
      else
        raise exception.create(rsUndefinedLuaError);

    end;
  finally
    lua_settop(luavm, stack);
  end;
end;

procedure LUA_onNotify(functionid: integer; sender: tobject);
begin
  try
    lua_rawgeti(Luavm, LUA_REGISTRYINDEX, functionid);

    lua_pushlightuserdata(Luavm, sender);
    lua_pcall(Luavm, 1, 0, 0);
  finally
    lua_pop(luavm, lua_gettop(luavm)); //clear the stack
  end;
end;

procedure LUA_memrec_callback(memrec: pointer; routine: string);
var m: TMemoryrecord;
  p: integer;
begin
  try
    m:=memrec;

    lua_getglobal(luavm, pchar(routine));

    p:=lua_gettop(luavm);
    if p<>0 then
    begin
      if lua_isfunction(luavm, -1) then
      begin
        lua_pushlightuserdata(luavm, memrec);
        lua_pcall(luavm, 1, 0, 0);
      end;


    end;
  finally
    lua_pop(luavm,lua_gettop(luavm));
  end;
end;

procedure lua_setbasictableentry(L: Plua_State; tableindex: integer; entryname: string; data: Variant);
var x: integer;
begin
  lua_pushstring(L, entryname);

  x:=vartype(data) and vartypemask;
  case x of
    varsmallint, varinteger, varint64, varqword, varlongword, varword, varbyte, varshortint: lua_pushinteger(L, data);
    varsingle, vardouble: lua_pushnumber(L, data);
    varboolean: lua_pushboolean(L, data);
    varstring,varustring,varolestr: lua_pushstring(L, data);

  end;

  lua_settable(L, tableindex);
end;

function LUA_functioncall(routinetocall: string; parameters: array of const): integer;
var i,e: integer;
  c: string;
  p: integer;
  oldstack: integer;
  l: Plua_State;
begin
 // OutputDebugString(inttohex(qword(GetCurrentThreadId),1)+':LUA_functioncall calling '+routinetocall);
 { if GetCurrentThreadId<>MainThreadID then
  begin
    OutputDebugString('Not main thread');
    l:=lua_newthread(luavm);
  end
  else  }
    l:=luavm;


  result:=-1;
  oldstack:=lua_gettop(l);

 // OutputDebugString('LUA_functioncall: oldstack='+inttostr(oldstack));

 // if luacs.TryEnter then
  begin
    try
      //check if the routine exists
    //  OutputDebugString('LUA_functioncall: calling getglobal');

      lua_getglobal(l, pchar(routinetocall));

     // OutputDebugString('LUA_functioncall: after getglobal');

      p:=lua_gettop(l);
     // OutputDebugString('LUA_functioncall: newstack='+inttostr(p));

      if p<>oldstack then
      begin
        if lua_isfunction(l, -1) then
        begin
          //OutputDebugString('LUA_functioncall: function exists');
          //OutputDebugString('LUA_functioncall: length(parameters)='+inttostr(length(parameters)));

          //routine exists, fill in the parameters
          for i:=0 to length(parameters)-1 do
          begin
            case parameters[i].VType of
              system.vtInteger : lua_pushinteger(L, parameters[i].VInteger);
              system.vtBoolean: lua_pushboolean(L, parameters[i].VBoolean);
              system.vtChar:
              begin
                c:=parameters[i].VChar;
                lua_pushstring(L, c);
              end;
              system.vtExtended: lua_pushnumber(L, parameters[i].VExtended^);
              system.vtString: lua_pushstring(L, pchar(parameters[i].VString));
              system.vtPointer: lua_pushlightuserdata(L, parameters[i].VPointer);
              system.vtPChar: lua_pushstring(L, parameters[i].VPChar);
              system.vtObject: luaclass_newClass(L, parameters[i].VObject); //lua_pushlightuserdata(L, pointer(parameters[i].VObject));
              system.vtClass: lua_pushlightuserdata(L, pointer(parameters[i].VClass));
              system.vtWideChar, vtPWideChar, vtVariant, vtInterface,
                vtWideString: lua_pushstring(L, rsCheatengineIsBeingAFag);
              system.vtAnsiString: lua_pushstring(L, pchar(parameters[i].VAnsiString));
              system.vtCurrency: lua_pushnumber(L, parameters[i].VCurrency^);
              system.vtInt64:
              begin
                if (parameters[i].VInt64^<=$ffffffff) then
                  lua_pushinteger(L, parameters[i].VInt64^)
                else
                  lua_pushlightuserdata(L, pointer(parameters[i].VInt64^));
              end;
              system.vtQWord:
              begin
                if (parameters[i].VQWord^<=$ffffffff) then
                  lua_pushinteger(L, parameters[i].VQWord^)
                else
                  lua_pushlightuserdata(L, pointer(parameters[i].VQWord^));
              end;
            end;

          end;

         // OutputDebugString('Lua_functioncall: Calling lua_pcall');
          lua_pcall(L, length(parameters), 1, 0);
         // OutputDebugString('Lua_functioncall: returned from lua_pcall');
          i:=lua_gettop(L);
          if i>0 then //it has a parameter
            result:=lua_tointeger(L, -1);
        end;


      end;


    finally
     // OutputDebugString('Lua_functioncall exit');
      lua_settop(L, oldstack);
 //     luacs.leave;
    end;

  end;
end;

 {
procedure LUA_callback(routine: string; parameters: tvararray);
var m: TMemoryrecord;
  p: integer;
begin
  LuaCS.Enter;
  try
    m:=memrec;

    lua_getfield(luavm, LUA_GLOBALSINDEX, pchar(routine));

    p:=lua_gettop(luavm);
    if p<>0 then
    begin
      if lua_isfunction(luavm, -1) then
      begin
        lua_pushlightuserdata(luavm, memrec);
        lua_pcall(luavm, 1, 0, 0);
      end;


    end;
  finally
    lua_pop(luavm,lua_gettop(luavm));
    luacs.Leave;
  end;
end; }

function CheckIfConditionIsMetContext(threadid: dword; context: PContext; script: string): boolean;
{
precondition: script returns a value (so already has the 'return ' part appended for single line scripts)
}
var i: integer;
begin
  result:=false;
  try
    LUA_SetCurrentContextState(threadid, context);

    if lua_dostring(luavm, pchar(script))=0 then
    begin
      i:=lua_gettop(LuaVM);
      if i=1 then //valid return
        result:=lua_toboolean(LuaVM, -1);
    end;
  finally
    lua_pop(LuaVM, lua_gettop(luavm));
  end;
end;

function LuaPanic(L: Plua_State): Integer; cdecl;
begin
  result:=0;
  lua_pop(L, lua_gettop(L));
  raise exception.create(rsLUAPanic);
end;


function lua_sleep(L: PLua_State): integer; cdecl;
var
  parameters: integer;
begin
  parameters:=lua_gettop(L);

  result:=0;


  if parameters=1 then
    sleep(lua_tointeger(L, -1));

  lua_pop(L, parameters);
end;

function print2(param: pointer): pointer;
var
  usesluaengineform: boolean;
  l: tstringlist;
  i: integer;
begin
  usesluaengineform:=false;

  if printoutput=nil then
  begin
    if frmLuaEngine=nil then
      frmLuaEngine:=TfrmLuaEngine.Create(MemoryBrowser);

    printoutput:=frmLuaEngine.mOutput.Lines;
    usesluaengineform:=true;
  end;

  l:=tstringlist.create;
  l.text:=pchar(param);
  for i:=0 to l.Count-1 do
    printoutput.add(l[i]);

  l.free;

  if (frmLuaEngine<>nil) and usesluaengineform and (frmLuaEngine.cbShowOnPrint.checked) then
    frmLuaEngine.show;

  if usesluaengineform then
    printoutput:=nil;

  result:=nil;
end;

function print(L: PLua_State): integer; cdecl;
var
  parameters: integer;
  s: string;

  str: string;
  i: integer;
begin
  if MainThreadID<>GetCurrentThreadId then
  begin
    //print is threadsafe because it always syncs
    lua_pushcfunction(L,@print);
    lua_insert(L,1);
    exit(lua_synchronize(L));
  end;


  parameters:=lua_gettop(L);
  if parameters=0 then exit(0);

  str:='';
  for i:=-parameters to -1 do
  begin
    if lua_isuserdata(L,i) then
      s:=inttohex(ptruint(lua_ToCEUserData(L, i)),8)
    else
      s:=lua_tostring(L, i);

    str:=str+s+' ';
  end;

  if str<>'' then
  begin
    print2(@str[1]);
    //pluginsync(print2, @str[1]);
  end;

  lua_pop(L, parameters);
  lua_pushstring(L, str);
  result:=1;
end;

function inputQuery_lua(L: PLua_State): integer; cdecl;
var
  caption, prompt, value: string;
  parameters: integer;
begin
  result:=0;
  parameters:=lua_gettop(l);
  if parameters=3 then
  begin
    caption:=Lua_ToString(L, 1);
    prompt:=Lua_ToString(L, 2);
    value:=Lua_ToString(L, 3);
    if InputQuery(caption, prompt, value) then
    begin
      result:=1;
      lua_pushstring(L, value);
    end;
  end;

end;

function showMessage_lua(L: PLua_State): integer; cdecl;
var
  parameters: integer;
  s: string;
begin
  parameters:=lua_gettop(L);
  if parameters=0 then exit(0);

  if lua_islightuserdata(l,-1) then
    s:=inttohex(ptruint(lua_touserdata(L, -1)),8)
  else
    s:=lua_tostring(L, -1);

  ShowMessage(s);

//  ce_showmessage(pchar(s));

  lua_pop(L, parameters);
  result:=0;
end;

function readSmallIntegerEx(L: PLua_State; processhandle: thandle): integer; cdecl;
var
  parameters: integer;
  address: ptruint;
  signed: boolean;

  v: smallInt;
  r: PtrUInt;
begin
  result:=0;
  try
    parameters:=lua_gettop(L);
    if parameters>=1 then
    begin
      //ShowMessage(inttostr(lua_type(L, 1)));

      address:=lua_toaddress(L,1, processhandle=GetCurrentProcess);

      if parameters>=2 then
        signed:=lua_toboolean(L,2)
      else
        signed:=false;

      lua_pop(L, parameters);

      v:=0;
      if ReadProcessMemory(processhandle, pointer(address), @v, sizeof(v), r) then
      begin
        if signed then 
          lua_pushinteger(L, v)
        else
          lua_pushinteger(L, word(v));

        result:=1;
      end;

    end;
  except
    result:=0;
    lua_pop(L, lua_gettop(L));
  end;
end;

function readSmallIntegerLocal(L: PLua_State): integer; cdecl;
begin
  result:=readSmallIntegerEx(L, GetCurrentProcess);
end;

function readSmallInteger(L: PLua_State): integer; cdecl;
begin
  result:=readSmallIntegerEx(L, ProcessHandle);
end;

function readIntegerEx(L: PLua_State; processhandle: thandle): integer; cdecl;
var
  parameters: integer;
  address: ptruint;
  signed: boolean;

  v: integer;
  r: PtrUInt;
begin
  result:=0;
  try
    parameters:=lua_gettop(L);
    if parameters>=1 then
    begin
      //ShowMessage(inttostr(lua_type(L, 1)));
      address:=lua_toaddress(L,1, processhandle=GetCurrentProcess);


      if parameters>=2 then
        signed:=lua_toboolean(L,2)
      else
        signed:=false;

      lua_pop(L, parameters);

      v:=0;
      if ReadProcessMemory(processhandle, pointer(address), @v, sizeof(v), r) then
      begin
        if signed then 
          lua_pushinteger(L, v)
        else
          lua_pushinteger(L, dword(v));

        result:=1;
      end;

    end;
  except
    result:=0;
    lua_pop(L, lua_gettop(L));
  end;
end;

function readIntegerLocal(L: PLua_State): integer; cdecl;
begin
  result:=readIntegerEx(L, GetCurrentProcess);
end;

function readInteger(L: PLua_State): integer; cdecl;
begin
  result:=readIntegerEx(L, ProcessHandle);
end;

function readQwordEx(L: PLua_State; processhandle: thandle): integer; cdecl;
var
  parameters: Qword;
  address: ptruint;

  v: Qword;
  r: PtrUInt;
begin
  result:=0;
  try
    parameters:=lua_gettop(L);
    if parameters=1 then
    begin
      //ShowMessage(inttostr(lua_type(L, -1)));

      address:=lua_toaddress(L,-1,processhandle=GetCurrentProcess);


      lua_pop(L, parameters);

      v:=0;
      if ReadProcessMemory(processhandle, pointer(address), @v, sizeof(v), r) then
      begin
        lua_pushinteger(L, v);
        result:=1;
      end;

    end;
  except
    result:=0;
    lua_pop(L, lua_gettop(L));
  end;
end;

function readQwordLocal(L: PLua_State): integer; cdecl;
begin
  result:=readQwordEx(L, GetCurrentProcess);
end;

function readQword(L: PLua_State): integer; cdecl;
begin
  result:=readQwordEx(L, ProcessHandle);
end;

function readPointerLocal(L: PLua_State): integer; cdecl;
begin
{$ifdef cpu64}
  result:=readQwordLocal(L);
{$else}
  result:=readIntegerLocal(L);
{$endif}
end;

function readPointer(L: PLua_State): integer; cdecl;
begin
  if processhandler.is64Bit then
    result:=readQword(L)
  else
    result:=readInteger(L);
end;

function readFloatEx(L: PLua_State; ProcessHandle: THandle): integer; cdecl;
var
  parameters: integer;
  address: ptruint;

  v: single;
  r: PtrUInt;
begin
  result:=0;
  try
    parameters:=lua_gettop(L);
    if parameters=1 then
    begin
      address:=lua_toaddress(L,-1,processhandle=GetCurrentProcess);

      lua_pop(L, parameters);

      v:=0;
      if ReadProcessMemory(processhandle, pointer(address), @v, sizeof(v), r) then
      begin
        lua_pushnumber(L, v);
        result:=1;
      end;

    end;
  except
    result:=0;
    lua_pop(L, lua_gettop(L));
  end;
end;

function readFloatLocal(L: PLua_State): integer; cdecl;
begin
  result:=readFloatEx(L, GetCurrentProcess);
end;

function readFloat(L: PLua_State): integer; cdecl;
begin
  result:=readFloatEx(L, ProcessHandle);
end;

function readDoubleEx(L: PLua_State; ProcessHandle: THandle): integer; cdecl;
var
  parameters: integer;
  address: ptruint;

  v: double;
  r: PtrUInt;
begin
  result:=0;
  try
    parameters:=lua_gettop(L);
    if parameters=1 then
    begin
      address:=lua_toaddress(L,-1,processhandle=GetCurrentProcess);

      lua_pop(L, parameters);

      v:=0;
      if ReadProcessMemory(processhandle, pointer(address), @v, sizeof(v), r) then
      begin
        lua_pushnumber(L, v);
        result:=1;
      end;

    end;
  except
    result:=0;
    lua_pop(L, lua_gettop(L));
  end;
end;

function readDoubleLocal(L: PLua_State): integer; cdecl;
begin
  result:=readDoubleEx(L, GetCurrentProcess);
end;

function readDouble(L: PLua_State): integer; cdecl;
begin
  result:=readDoubleEx(L, processhandle);
end;

function readStringEx(L: PLua_State; ProcessHandle: THandle): integer; cdecl;
var
  parameters: integer;
  address: ptruint;

  v: pchar;
  w: pwidechar absolute v;
  s: string;
  r: PtrUInt;
  maxsize: integer;

  usewidechar: boolean;
begin
  result:=0;
  try
    parameters:=lua_gettop(L);
    if parameters>=1 then
    begin
      address:=lua_toaddress(L,1,processhandle=GetCurrentProcess);

      if parameters>=2 then
        maxsize:=lua_tointeger(L,2)
      else
        maxsize:=50;

      if parameters>=3 then
      begin
        usewidechar:=lua_toboolean(L,3);
        maxsize:=maxsize+1;
      end
      else
        usewidechar:=false;

      lua_pop(L, parameters);

      getmem(v,maxsize+1);
      try
        r:=0;
        ReadProcessMemory(processhandle, pointer(address), v, maxsize, r);

        if (r>0) and (r<=maxsize) then
        begin
          v[maxsize]:=#0;

          if (r+1)<=maxsize then
            v[r+1]:=#0;

          if usewidechar then
          begin
            v[maxsize-1]:=#0;
            if (r+2)<=maxsize then
              v[r+2]:=#0;

            s:=w;
          end
          else
            s:=v;


          lua_pushstring(L, s);
          result:=1;
        end;


      finally
        freememandnil(v);
      end;

    end;
  except
    result:=0;
    lua_pop(L, lua_gettop(L));
  end;
end;

function readStringLocal(L: PLua_State): integer; cdecl;
begin
  result:=readStringEx(L, GetCurrentProcess);
end;

function readString(L: PLua_State): integer; cdecl;
begin
  result:=readStringEx(L, processhandle);
end;

function writeSmallIntegerEx(L: PLua_State; processhandle: THandle): integer; cdecl;
var
  parameters: integer;
  address: ptruint;

  v: smallInt;
  r: PtrUInt;
begin
  result:=0;
  try
    parameters:=lua_gettop(L);
    if parameters=2 then
    begin
      address:=lua_toaddress(L,-2,processhandle=GetCurrentProcess);

      v:=lua_tointeger(L, -1);

      lua_pop(L, parameters);
      lua_pushboolean(L, WriteProcessMemory(processhandle, pointer(address), @v, sizeof(v), r));
      result:=1;
    end;
  except
    result:=0;
    lua_pop(L, lua_gettop(L));
  end;
end;

function writeSmallIntegerLocal(L: PLua_State): integer; cdecl;
begin
  result:=writeSmallIntegerEx(L, GetCurrentProcess);
end;

function writeSmallInteger(L: PLua_State): integer; cdecl;
begin
  result:=writeSmallIntegerEx(L, processhandle);
end;

function writeIntegerEx(L: PLua_State; processhandle: THandle): integer; cdecl;
var
  parameters: integer;
  address: ptruint;

  v: integer;
  r: PtrUInt;
begin
  result:=0;
  try
    parameters:=lua_gettop(L);
    if parameters=2 then
    begin
      address:=lua_toaddress(L,-2,processhandle=GetCurrentProcess);

      v:=lua_tointeger(L, -1);

      lua_pop(L, parameters);
      lua_pushboolean(L, WriteProcessMemory(processhandle, pointer(address), @v, sizeof(v), r));
      result:=1;
    end;
  except
    result:=0;
    lua_pop(L, lua_gettop(L));
  end;
end;

function writeIntegerLocal(L: PLua_State): integer; cdecl;
begin
  result:=writeIntegerEx(L, GetCurrentProcess);
end;

function writeInteger(L: PLua_State): integer; cdecl;
begin
  result:=writeIntegerEx(L, processhandle);
end;

function writeQwordEx(L: PLua_State; processhandle: THandle): integer; cdecl;
var
  parameters: Qword;
  address: ptruint;

  v: Qword;
  r: PtrUInt;
begin
  result:=0;
  try
    parameters:=lua_gettop(L);
    if parameters=2 then
    begin
      address:=lua_toaddress(L,-2,processhandle=GetCurrentProcess);

      v:=lua_tointeger(L, -1);

      lua_pop(L, parameters);
      lua_pushboolean(L, WriteProcessMemory(processhandle, pointer(address), @v, sizeof(v), r));
      result:=1;
    end;
  except
    result:=0;
    lua_pop(L, lua_gettop(L));
  end;
end;

function writeQwordLocal(L: PLua_State): integer; cdecl;
begin
  result:=writeQwordEx(L, GetCurrentProcess);
end;

function writeQword(L: PLua_State): integer; cdecl;
begin
  result:=writeQwordEx(L, processhandle);
end;

function writePointerLocal(L: PLua_State): integer; cdecl;
begin
{$ifdef cpu64}
  result:=writeQwordLocal(L);
{$else}
  result:=writeIntegerLocal(L);
{$endif}
end;

function writePointer(L: PLua_State): integer; cdecl;
begin
  if processhandler.is64bit then
    result:=writeQword(L)
  else
    result:=writeInteger(L);
end;

function writeFloatEx(L: PLua_State; processhandle: THandle): integer; cdecl;
var
  parameters: integer;
  address: ptruint;

  v: single;
  r: PtrUInt;
begin
  result:=0;
  try
    parameters:=lua_gettop(L);
    if parameters=2 then
    begin
      address:=lua_toaddress(L,-2,processhandle=GetCurrentProcess);

      v:=lua_tonumber(L, -1);

      lua_pop(L, parameters);


      lua_pushboolean(L, WriteProcessMemory(processhandle, pointer(address), @v, sizeof(v), r));
      result:=1;
    end;
  except
    result:=0;
    lua_pop(L, lua_gettop(L));
  end;
end;

function writeFloatLocal(L: PLua_State): integer; cdecl;
begin
  result:=writeFloatEx(L, GetCurrentProcess);
end;

function writeFloat(L: PLua_State): integer; cdecl;
begin
  result:=writeFloatEx(L, processhandle);
end;


function writeDoubleEx(L: PLua_State; processhandle: THandle): integer; cdecl;
var
  parameters: integer;
  address: ptruint;

  v: double;
  r: PtrUInt;
begin
  result:=0;
  try
    parameters:=lua_gettop(L);
    if parameters=2 then
    begin
      address:=lua_toaddress(L,-2,processhandle=GetCurrentProcess);

      v:=lua_tonumber(L, -1);

      lua_pop(L, parameters);

      lua_pushboolean(L, WriteProcessMemory(processhandle, pointer(address), @v, sizeof(v), r));
      result:=1;
    end;
  except
    result:=0;
    lua_pop(L, lua_gettop(L));
  end;
end;

function writeDoubleLocal(L: PLua_State): integer; cdecl;
begin
  result:=writeDoubleEx(L, GetCurrentProcess);
end;

function writeDouble(L: PLua_State): integer; cdecl;
begin
  result:=writeDoubleEx(L, processhandle);
end;

function writeStringEx(L: PLua_State; processhandle: THandle): integer; cdecl;
var
  parameters: integer;
  address: ptruint;

  v: pchar;
  usewidechar: boolean;

  w: widestring;
  r: PtrUInt;
begin
  result:=0;
  try
    parameters:=lua_gettop(L);
    if parameters>=2 then
    begin
      address:=lua_toaddress(L,1,processhandle=GetCurrentProcess);

      v:=lua.lua_tostring(L, 2);

      if parameters>=3 then
        usewidechar:=lua.lua_toboolean(L, 3)
      else
        usewidechar:=false;

      lua_pop(L, parameters);

      if usewidechar then
      begin
        //convert the ansi sring to a widestring
        w:=v;
        lua_pushboolean(L, WriteProcessMemory(processhandle, pointer(address), @w[1], length(w)*2, r));
      end
      else
        lua_pushboolean(L, WriteProcessMemory(processhandle, pointer(address), v, length(v), r));

      result:=1;
    end;
  except
    result:=0;
    lua_pop(L, lua_gettop(L));
  end;
end;

function writeStringLocal(L: PLua_State): integer; cdecl;
begin
  result:=writeStringEx(L, GetCurrentProcess);
end;

function writeString(L: PLua_State): integer; cdecl;
begin
  result:=writeStringEx(L, processhandle);
end;

function readBytesEx(processhandle: THandle; L: PLua_State): integer; cdecl;
var parameters: integer;
  addresstoread: ptruint;
  bytestoread: integer;
  i: integer;
  bytes: array of byte;
  x: PtrUInt;
  tableversion: boolean;
begin
  tableversion:=false;
  result:=0;
  parameters:=lua_gettop(L);

  if lua_isstring(L, 1) then
  begin
    if processhandle=GetCurrentProcess then
      addresstoread:=selfsymhandler.getAddressFromNameL(lua_tostring(L,1), waitforsymbols)
    else
      addresstoread:=symhandler.getAddressFromNameL(lua_tostring(L,1), waitforsymbols);
  end
  else
    addresstoread:=lua_tointeger(L,1);

  if parameters>1 then
  begin
    bytestoread:=lua_tointeger(L,2);

    if parameters>2 then
      tableversion:=lua_toboolean(L, 3);
  end
  else
    bytestoread:=1;

  lua_pop(L, parameters);

  setlength(bytes,bytestoread);
  ZeroMemory(@bytes[0], bytestoread);
  x:=0;
  ReadProcessMemory(processhandle, pointer(addresstoread), @bytes[0], bytestoread, x);

  if (x>0) and (x<=bytestoread) then
  begin
    if tableversion then
    begin
      lua_createtable(L, x,0);
      for i:=0 to x-1 do
      begin
        lua_pushinteger(L, i+1);
        lua_pushinteger(L, bytes[i]);
        lua_settable(L, -3);
      end;
      result:=1;
    end
    else
    begin
      for i:=0 to x-1 do
        lua_pushinteger(L,bytes[i]);
      result:=x;
    end;
  end;
end;


function writeBytesEx(processhandle: THandle; L: PLua_State): integer;
var
  parameters, parameters2: integer;
  bytes: array of byte;
  i,j: integer;
  bytecount: integer;
  address: ptruint;
  x: PtrUInt;
  oldprotect: dword;
  b: byte;
  vpe: boolean;
begin
  parameters:=lua_gettop(L);
  if parameters=0 then exit(0);



  address:=lua_toaddress(L,1,processhandle=GetCurrentProcess);

  bytecount:=0;
  if lua_istable(L, 2) then
  begin
    parameters2:=lua_objlen(L, 2);
    setlength(bytes, parameters2);



    for i:=1 to parameters2 do
    begin
      lua_pushinteger(L,i);
      lua_gettable(L, 2);

      if lua_isnumber(L,-1) then
      begin
        j:=lua_tointeger(L,-1);
        bytes[bytecount]:=j;
        inc(bytecount);
      end;
      lua_pop(L,1);
    end;


  end
  else
  begin
    setlength(bytes,parameters-1);

    bytecount:=0;
    for i:=(-parameters)+1 to -1 do
    begin
      b:=lua_tointeger(L,i);
      bytes[bytecount]:=b;
      inc(bytecount);
    end;

  end;

  x:=0;
  vpe:=(SkipVirtualProtectEx=false) and VirtualProtectEx(processhandle, pointer(address), bytecount, PAGE_EXECUTE_READWRITE, oldprotect);
  WriteProcessMemory(processhandle, pointer(address), @bytes[0], bytecount, x);
  if vpe then VirtualProtectEx(processhandle, pointer(address), bytecount, oldprotect, oldprotect);


  lua_pop(L, parameters);
  lua_pushinteger(L, x);    //return the number of bytes written

  result:=1;  //return 1 value
end;

function writeBytes(L: PLua_state): integer; cdecl;
begin
  result:=writeBytesEx(processhandle, L);
end;

function readBytes(L: PLua_State): integer; cdecl;
begin
  result:=readBytesEx(processhandle, L);
end;

function writeBytesLocal(L: PLua_state): integer; cdecl;
begin
  result:=writebytesEx(getcurrentprocess, L);
end;

function readBytesLocal(L: PLua_State): integer; cdecl;
begin
  result:=readbytesEx(getcurrentprocess, L);
end;


function lua_createSection(L: PLua_State): integer; cdecl;
{$IFDEF windows}
var
  n: NTSTATUS;
  s: THandle;
  size: LARGE_INTEGER;
{$ENDIF}
begin
  result:=0;
  {$IFDEF windows}
  if lua_gettop(L)>=1 then
  begin
    size.QuadPart:=lua_tointeger(L,1);
    s:=0;
    n:=ZwCreateSection(@s,SECTION_ALL_ACCESS,nil, @size, PAGE_EXECUTE_READWRITE,SEC_COMMIT,0);

   // STATUS_MAPPED_FILE_SIZE_ZERO
    if Succeeded(n) then
    begin
      lua_pushinteger(L,s);
      result:=1;
    end
    else
    begin
      lua_pushnil(L);
      lua_pushinteger(L,n);
      result:=2;
    end;
  end;
  {$ENDIF}
end;

function lua_MapViewOfSection(L: PLua_State): integer; cdecl;
{$IFDEF windows}
var
  sh: thandle;
  base: pointer;
  basep: pointer;
  offset: LARGE_INTEGER;
  n: NTSTATUS;
  si: SECTION_INHERIT;
  viewsize: LARGE_INTEGER;
{$ENDIF}
begin
  result:=0;
  {$IFDEF windows}
  if lua_gettop(L)>=1 then
  begin
    sh:=lua_tointeger(L,1);

    if lua_Gettop(L)>=2 then
    begin
      if lua_isstring(L, 2) then
        base:=pointer(symhandler.getAddressFromNameL(lua_tostring(L,2), waitforsymbols))
      else
        base:=pointer(lua_tointeger(L,2));
    end
    else
      base:=nil;


    basep:=@base;



    offset.QuadPart:=0;
    viewsize.QuadPart:=0;


    n:=ZwMapViewOfSection(sh,processhandle, @base,0,0,nil,@viewsize,2,0,PAGE_EXECUTE_READWRITE);
    if succeeded(n) then
    begin
      lua_pushinteger(L,ptruint(base));
      result:=1;
    end
    else
    begin
      lua_pushnil(L);
      lua_pushinteger(L, n);
      result:=2;
    end;
  end;
  {$ENDIF}




end;

function lua_unMapViewOfSection(L: PLua_State): integer; cdecl;
var parameters: integer;
    address: ptruint;
begin
  {$IFDEF windows}
  result:=1;
  parameters:=lua_gettop(L);
  if parameters=0 then begin lua_pushboolean(L, false); exit; end;

  address:=lua_toaddress(L,1);

  lua_pop(L, parameters);
  lua_pushinteger(L, ZwUnmapViewOfSection(processhandle, pointer(address)));
  {$ELSE}
  result:=0;
  {$ENDIF}
end;



function deAllocEx(processhandle: THandle; L: PLua_State): integer; cdecl;
var parameters: integer;
    address: ptruint;
begin
  result:=1;
  parameters:=lua_gettop(L);
  if parameters=0 then begin lua_pushboolean(L, false); exit; end;

  address:=lua_toaddress(L,1, processhandle=GetCurrentProcess);

  lua_pop(L, parameters);
  lua_pushboolean(L, virtualfreeex(processhandle,pointer(address),0,MEM_RELEASE));
end;

function deAlloc_lua(L: PLua_State): integer; cdecl;
begin
  result:=deAllocEx(processhandle, L);
end;

function deAllocLocal_lua(L: PLua_State): integer; cdecl;
begin
  result:=deAllocEx(getcurrentprocess, L);
end;

function AutoAssembleCheck_lua(L: PLua_State): integer; cdecl;
var
  script: tstringlist;
  enable: boolean;
  targetself: boolean;
begin
  if lua_gettop(L)=0 then
  begin
    lua_pushboolean(L,false);
    lua_pushstring(L,'No parameters given');
    exit(2);
  end;

  script:=tstringlist.create;
  try
    script.text:=Lua_ToString(L,1);
    if lua_gettop(L)>=2 then
      enable:=lua_toboolean(L,2)
    else
      enable:=true;

    if lua_gettop(L)>=3 then
      targetself:=lua_toboolean(L,3)
    else
      targetself:=false;

    try
      lua_pushboolean(L,autoassemble(script,false,enable,true,targetself));
      exit(1);
    except
      on e:exception do
      begin
        lua_pushboolean(L,false);
        lua_pushstring(L,e.message);
        exit(2);
      end;
    end;

  finally
    script.free;
  end;
end;

function autoAssemble_lua(L: PLua_State): integer; cdecl;
var
  parameters: integer;
  code: TStringlist=nil;
  registeredsymbols: TStringlist=nil;

  r: boolean;
  targetself: boolean;
  CEAllocArray: TCEAllocArray;

  exceptionlist: TCEExceptionListArray;

  i: integer;

  secondaryResultTable: integer;
  tableIndex, tableIndex2: integer;
  disableInfoIndex: integer;
  enable: boolean;
begin
  result:=1;
  enable:=true;


  parameters:=lua_gettop(L);
  if parameters=0 then
  begin
    lua_pushboolean(L, false);
    exit;
  end;

  setlength(CEAllocArray,0);

  code:=tstringlist.create;
  registeredsymbols:=tstringlist.create;

  try
    code.text:=lua_tostring(L, 1);
    if (parameters>1) and lua_isboolean(L,2) then
      targetself:=lua_toboolean(L, 2)
    else
      targetself:=false;

    disableInfoIndex:=0;
    if (parameters>1) and lua_istable(L,2) then
      disableInfoIndex:=2
    else
    if (parameters>2) and lua_istable(L,3) then
      disableInfoIndex:=3;



    if disableInfoIndex>0 then
    begin
      try
        if lua_istable(L, disableInfoIndex) then
        begin
          enable:=false;
          lua_pushstring(L,'allocs');
          lua_gettable(L,disableInfoIndex);
          if lua_isnil(L,disableInfoIndex+1)=false then
          begin
            if lua_istable(L,disableInfoIndex+1)=false then raise exception.create('Corrupt disableInfo section at the allocs side');
            //enum all the entries

            lua_pushnil(L);
            while lua_next(L, disableInfoIndex+1)<>0 do
            begin
              i:=length(CEAllocArray);
              setlength(ceallocarray,i+1);

              CEAllocArray[i].varname:=Lua_ToString(L,-2);

              tableindex:=lua_gettop(L);

              lua_pushstring(L,'address');
              lua_gettable(L,tableindex);
              if lua_isnumber(L,-1)=false then raise exception.create('Corrupt disableInfo section at '+CEAllocArray[i].varname+'.address');
              CEAllocArray[i].address:=lua_tointeger(L,-1);
              lua_pop(L,1);

              lua_pushstring(L,'size');
              lua_gettable(L,tableindex);
              if lua_isnumber(L,-1)=false then raise exception.create('Corrupt disableInfo section at '+CEAllocArray[i].varname+'.size');
              CEAllocArray[i].size:=lua_tointeger(L,-1);
              lua_pop(L,1);

              lua_pushstring(L,'prefered');
              lua_gettable(L,tableindex);
              if lua_isnil(L,-1)=false then
              begin
                if lua_isnumber(L,-1)=false then raise exception.create('Corrupt disableInfo section at '+CEAllocArray[i].varname+'.prefered');
                CEAllocArray[i].size:=lua_tointeger(L,-1);
              end;
              lua_pop(L,1);

              lua_pop(L,1);
            end;
          end;
          lua_pop(L,1);

          lua_pushstring(L,'registeredsymbols');
          lua_gettable(L,disableInfoIndex);
          if not lua_isnil(L,-1) then
          begin
            if lua_istable(L,-1)=false then raise exception.create('Corrupt disableInfo section at the registeredsymbols side');
            lua_pushnil(L);
            while lua_next(L, disableInfoIndex+1)<>0 do
            begin
              registeredsymbols.Add(Lua_ToString(L,-1));
              lua_pop(L,1);
            end;
          end;
          lua_pop(L,1);

          lua_pushstring(L,'exceptionlist');
          lua_gettable(L,disableInfoIndex);
          if not lua_isnil(L,-1) then
          begin
            if lua_istable(L,-1)=false then raise exception.create('Corrupt disableInfo section at the exceptionlist side');

            setlength(exceptionlist, lua_objlen(L,-1));

            for i:=1 to length(exceptionlist) do
            begin
              lua_pushinteger(L,i);
              lua_gettable(L,-2);
              exceptionlist[i-1]:=lua_tointeger(L,-1);
              lua_pop(L,1);
            end;
          end;
        end
        else raise exception.create('Not a valid disableInfo variable');

      except
        on e:exception do
        begin
          lua_pushboolean(L,false);
          lua_pushstring(L,e.Message);
          exit(2);
        end;
      end;
    end;


    try
      r:=autoassemble(code, false, enable, false, targetself, CEAllocArray, exceptionlist, registeredsymbols, nil);
    except
      on e:exception do
      begin
        lua_pushboolean(L,false);
        lua_pushstring(L,e.Message);
        exit(2);
      end;
    end;

    lua_pop(L, parameters);
    lua_pushboolean(L, r);

    if r and enable then
    begin
      result:=2;
      lua_newtable(L);
      secondaryResultTable:=lua_gettop(L); //should be 2

      lua_pushstring(L,'allocs');
      lua_newtable(L);
      tableIndex:=lua_gettop(L);

      for i:=0 to length(CEAllocArray)-1 do
      begin
        lua_pushstring(L, CEAllocArray[i].varname);
        lua_newtable(L);
        tableindex2:=lua_gettop(L);

        lua_setbasictableentry(L, tableindex2, 'address',CEAllocArray[i].address);
        lua_setbasictableentry(L, tableindex2, 'size',CEAllocArray[i].size);
        if CEAllocArray[i].prefered<>0 then
          lua_setbasictableentry(L, tableindex2, 'prefered',CEAllocArray[i].prefered);

        lua_settable(L, tableindex);
      end;
      lua_settable(l,secondaryResultTable);

      lua_pushstring(L,'registeredsymbols');
      lua_newtable(L);
      tableIndex:=lua_gettop(L);

      for i:=0 to registeredsymbols.Count-1 do
      begin
        lua_pushinteger(L,i+1);
        lua_pushstring(L, registeredsymbols[i]);
        lua_settable(L, tableIndex);
      end;

      lua_settable(L, secondaryResultTable);

      lua_pushstring(L,'exceptionlist');
      lua_newtable(L);
      tableIndex:=lua_gettop(L);

      for i:=0 to length(exceptionlist)-1 do
      begin
        lua_pushinteger(L,i+1);
        lua_pushinteger(L, exceptionlist[i]);
        lua_settable(L, tableIndex);
      end;

      lua_settable(L, secondaryResultTable);

    end;
  finally
    if code<>nil then
      code.free;

    if registeredsymbols<>nil then
      registeredsymbols.free;
  end;

end;

function getPixel(L: PLua_State): integer; cdecl;
var t:TCanvas;
  parameters: integer;
  r: dword;
  x,y: integer;
begin
  result:=0; //return 0 paramaters
  parameters:=lua_gettop(L);
  if parameters=2 then
  begin
    x:=lua_tointeger(L, -2); //x
    y:=lua_tointeger(L, -1); //y
    lua_pop(L, 2);

    try
      t:=TCanvas.create;
      try
        t.Handle:=getdc(0);
        r:=t.Pixels[x,y];

        lua_pushinteger(L,r); //push the color on the stack
        result:=1; //tell lue I put 1 parameter on the stack

        ReleaseDC(0,t.handle);
      finally
        t.free;
      end;
    except
    end;
  end else lua_pop(L, parameters);
end;

function getMousePos(L: PLua_State): integer; cdecl;
var t:TCanvas;
  parameters: integer;
  cp: Tpoint;
begin
  result:=0; //return 0 parameters
  parameters:=lua_gettop(L);
  if parameters=0 then
  begin
    cp:=mouse.CursorPos;
    lua_pushinteger(L, cp.x);
    lua_pushinteger(L, cp.y);
    result:=2;   //return 2 parameters
  end else lua_pop(L, parameters);
end;

function setMousePos(L: PLua_State): integer; cdecl;
var t:TCanvas;
  parameters: integer;
  cp: Tpoint;
begin
  result:=0; //return 0 parameters
  parameters:=lua_gettop(L);
  if parameters=2 then
  begin
    cp.x:=lua_tointeger(L, -2); //x
    cp.y:=lua_tointeger(L, -1); //y
    lua_pop(L, 2);

    mouse.CursorPos:=cp;
  end else lua_pop(L, parameters);
end;

function createTableEntry(L: PLua_State): integer; cdecl;
var parameters: integer;
  r: pointer;
begin
  lua_pop(L, lua_gettop(L)); //clear the stack

  r:=ce_createTableEntry;
  luaclass_newClass(L, r);
  result:=1;
end;

function getTableEntry(L: PLua_State): integer; cdecl;
var parameters: integer;
  description: pchar;
  r: pointer;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    description:=lua.lua_tostring(L,-1); //description

    lua_pop(L, parameters);  //clear stack

    r:=ce_getTableEntry(description);
    if r<>nil then
    begin
      luaclass_newClass(L, r);
      result:=1;
    end;
  end else lua_pop(L, parameters);
end;



function isKeyPressed(L: PLua_State): integer; cdecl;
var parameters: integer;
  keyinput: pchar;
  key: integer;
  w: word;
  r: boolean;
begin
  result:=0;
  r:=false;
  key:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    if lua_isstring(L,-1) then  //char given instead of keycode
    begin
      keyinput:=lua.lua_tostring(L,-1);
      if keyinput<>nil then
        key:=ord(keyinput[0]);
    end
    else

    if lua_isnumber(L,-1) then //keycode
      key:=lua_tointeger(L,-1);

    lua_pop(L, parameters); //parameters have been fetched, clear stack

    if key<>0 then
    begin
      {$IFDEF windows}
      if key>=VK_PAD_A then
      begin
        lua_pushboolean(L, HotkeyHandler.IsKeyPressed(key));
        exit(1);
      end;
      {$ENDIF}


      w:=GetAsyncKeyState(key);
      r:=(w and 1)=1;

      if not r then
        r:=((w shr 15) and 1)=1;

      lua_pushboolean(L, r);
      result:=1;
    end;

  end else lua_pop(L, parameters);

end;


function lua_mouse_event(L: PLua_State): integer; cdecl;
var
  flags, x,y,data: dword;
  extrainfo: ptruint;
  c: integer;
begin
  result:=0;

  {$IFDEF windows}
  c:=lua_gettop(L);
  if c=0 then exit(0); //flags is important, the rest can be ignored

  flags:=lua_tointeger(L, 1);
  x:=lua_tointeger(L, 2);
  y:=lua_tointeger(L, 3);
  data:=lua_tointeger(L, 4);
  extrainfo:=lua_tointeger(L, 5);

  mouse_event(flags, x, y, data, extrainfo);
  {$ENDIF}

end;

function keyDown(L: PLua_State): integer; cdecl;
var parameters: integer;
  keyinput: pchar;
  key: integer;
  w: word;
  r: boolean;
begin
  result:=0;
  {$IFDEF windows}
  r:=false;
  key:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    if lua_isstring(L,-1) then  //char given isntead of keycode
    begin
      keyinput:=lua.lua_tostring(L,-1);
      if keyinput<>nil then
        key:=ord(keyinput[0]);
    end
    else
    if lua_isnumber(L,-1) then //keycode
      key:=lua_tointeger(L,-1);


    if key<>0 then
      keybd_event(key, 0,0,0);

  end;
  lua_pop(L, parameters);
  {$ENDIF}
end;


function keyUp(L: PLua_State): integer; cdecl;
var parameters: integer;
  keyinput: pchar;
  key: integer;
  w: word;
  r: boolean;
begin
  result:=0;
  {$IFDEF windows}
  r:=false;
  key:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    if lua_isstring(L,-1) then  //char given isntead of keycode
    begin
      keyinput:=lua.lua_tostring(L,-1);
      if keyinput<>nil then
        key:=ord(keyinput[0]);
    end
    else
    if lua_isnumber(L,-1) then //keycode
      key:=lua_tointeger(L,-1);


    if key<>0 then
      keybd_event(key, 0,KEYEVENTF_KEYUP,0);

  end;
  lua_pop(L, parameters);
  {$ENDIF}
end;

function doKeyPress(L: PLua_State): integer; cdecl;
var parameters: integer;
  keyinput: pchar;
  key: integer;
  w: word;
  r: boolean;
begin
  result:=0;
  {$IFDEF windows}
  r:=false;
  key:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    if lua_isstring(L,1) then  //char given instead of keycode
    begin
      keyinput:=lua.lua_tostring(L,1);
      if keyinput<>nil then
        key:=ord(keyinput[0]);
    end
    else
    if lua_isnumber(L,1) then //keycode
      key:=lua_tointeger(L,1);


    if key<>0 then
    begin
      keybd_event(key, 0, 0, 0);
      windows.sleep(110);
      keybd_event(key, 0, KEYEVENTF_KEYUP, 0);
    end;

  end;
  lua_pop(L, parameters);
{$ENDIF}
end;

function getProcessIDFromProcessName(L: PLua_state): integer; cdecl;
var parameters: integer;
  pname: pchar;
  pid: dword;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    pname:=lua.lua_tostring(L, -1);
    lua_pop(L, parameters);

    pid:=ce_getProcessIDFromProcessName(pname);
    if pid<>0 then
    begin
      lua_pushinteger(L, pid);
      result:=1;
    end;


  end else lua_pop(L, parameters);
end;

function openProcess(L: PLua_state): integer; cdecl;
var parameters: integer;
  pname: pchar;
  pid: dword;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters>=1 then
  begin
    if lua_isstring(L,1) then
    begin
      pname:=lua.lua_tostring(L,1);
      pid:=ce_getProcessIDFromProcessName(pname);
    end
    else
      pid:=lua_tointeger(L,1);

    lua_pop(L, parameters);

    if pid<>0 then
      ce_openProcess(pid);

    if (ProcessHandle<>0) and (processid=pid) then
    begin
      lua_pushboolean(L, true);
      result:=1;
    end;

  end else lua_pop(L, parameters);
end;

function beep(L: PLua_state): integer; cdecl;
begin
  lua_pop(L, lua_gettop(L)); //clear the stack
  SysUtils.Beep;
  result:=0;
end;

function pause(L: PLua_state): integer; cdecl;
begin
  lua_pop(L, lua_gettop(L)); //clear the stack
  ce_pause;
  result:=0;
end;

function unpause(L: PLua_state): integer; cdecl;
begin
  lua_pop(L, lua_gettop(L)); //clear the stack
  ce_unpause;
  result:=0;
end;


function debugProcess(L: PLua_state): integer; cdecl;
var parameters: integer;
  debuggerinterface: integer;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
    debuggerinterface:=lua_tointeger(L, -1)
  else
    debuggerinterface:=0;

  lua_pop(L, lua_gettop(L)); //clear the stack

  ce_debugProcess(debuggerinterface);
end;

function debug_getCurrentDebuggerInterface(L:PLua_State): integer; cdecl;
begin

  if debuggerthread<>nil then
  begin
    {$IFDEF windows}
    if (CurrentDebuggerInterface is TWindowsDebuggerInterface) then
      lua_pushinteger(L, 1);

    if (CurrentDebuggerInterface is TVEHDebugInterface) then
      lua_pushinteger(L, 2);

    if (CurrentDebuggerInterface is TKernelDebugInterface) then
      lua_pushinteger(L, 3);
    {$ENDIF}

    {$ifdef darwin}
    lua_pushinteger(L, 4);
    {$endif}

    result:=1;
  end
  else
    result:=0;
end;

function debug_getBreakpointList(L: Plua_State): integer; cdecl;
var
  al: TAddressArray;
  t: integer;
  i: integer;
begin
  result:=0;
  if debuggerthread<>nil then
  begin
    debuggerthread.getBreakpointAddresses(al);
    lua_newtable(L);
    t:=lua_gettop(L);


    for i:=0 to length(al)-1 do
    begin
      lua_pushinteger(L, i+1);
      lua_pushinteger(L, al[i]);
      lua_settable(L, t);
    end;

    result:=1;
  end;

end;

function lua_checkSynchronize(L: Plua_State): integer; cdecl;
var timeout: integer=0;
begin
  result:=0;
  if lua_Gettop(L)>0 then
    timeout:=lua_tointeger(L,1);

  CheckSynchronize(timeout);
end;

function lua_queue(L: Plua_State): integer; cdecl;
var lc: TLuaCaller;
  f: integer;
  routine: string;
begin
  result:=0;
  lc:=nil;
  if lua_isfunction(L,1) then
  begin
    lua_pushvalue(L, 1);
    f:=luaL_ref(L,LUA_REGISTRYINDEX);

    lc:=TLuaCaller.create;
    lc.luaroutineIndex:=f;
  end
  else
  if lua_isstring(L,1) then
  begin
    routine:=lua_tostring(L,1);
    lc:=TLuaCaller.create;
    lc.luaroutine:=routine;
  end;

  if lc<>nil then
  begin
    lc.syncvm:=l;
    if lua_gettop(L)>=2 then
    begin
      lc.synchronizeparam:=2;
      lc.synchronizeparamcount:=lua_gettop(l)-1;
    end
    else
      lc.synchronizeparam:=0;

    tthread.Queue(nil, lc.synchronize);


    result:=0;
  end;
end;

function lua_synchronize(L: Plua_State): integer; cdecl;
var lc: TLuaCaller;
  f: integer;
  routine: string;
begin
  result:=0;
  lc:=nil;
  if lua_isfunction(L,1) then
  begin
    lua_pushvalue(L, 1);
    f:=luaL_ref(L,LUA_REGISTRYINDEX);

    lc:=TLuaCaller.create;
    lc.luaroutineIndex:=f;
  end
  else
  if lua_isstring(L,1) then
  begin
    routine:=lua_tostring(L,1);
    lc:=TLuaCaller.create;
    lc.luaroutine:=routine;
  end;

  if lc<>nil then
  begin
    lc.syncvm:=l;
    if lua_gettop(L)>=2 then
    begin
      lc.synchronizeparam:=2;
      lc.synchronizeparamcount:=lua_gettop(l)-1;
    end
    else
      lc.synchronizeparam:=0;

    tthread.Synchronize(nil, lc.synchronize);

    result:=1;
  end;
end;

function inMainThread(L: Plua_State): integer; cdecl;
begin
  lua_pushboolean(L, MainThreadID=GetCurrentThreadId);
  result:=1;
end;

function debug_isDebugging(L: Plua_State): integer; cdecl;
begin
  lua_pushboolean(L, debuggerthread<>nil);
  result:=1;
end;



function debug_canBreak(L: Plua_State): integer; cdecl;
var list: TAddressArray;
begin
  if debuggerthread<>nil then
  begin
    debuggerthread.getBreakpointAddresses(list);

    lua_pushboolean(L, (length(list)>0) or ((debuggerthread.CurrentThread<>nil) and (debuggerthread.CurrentThread.isHandled)) );
  end
  else
    lua_pushboolean(L, false);

  result:=1;
end;

function debug_isBroken(L: PLua_state): integer; cdecl;
var r: boolean;
begin
  r:=(debuggerthread<>nil) and (debuggerthread.CurrentThread<>nil) and (debuggerthread.CurrentThread.isHandled);
  lua_pushboolean(L, r);
  result:=1;
end;

function debug_setBreakpoint(L: Plua_State): integer; cdecl;
var parameters: integer;
  address: ptruint;
  size: integer;
  trigger: TBreakpointTrigger;
  method: TBreakpointMethod;

  lc: TLuaCaller;

  bpe: TBreakpointEvent;
begin
  lc:=nil;

  trigger:=bptExecute;
  result:=0;
  size:=1;
  parameters:=lua_gettop(L);
  if parameters=0 then
    raise exception.create(rsDebugsetBreakpointNeedsAtLeastAnAddress);

  address:=lua_toaddress(L,1);

  if parameters>=2 then
  begin
    if lua_isfunction(L,2) then //address, function type
    begin
      lua_pushvalue(L,2);
      lc:=TLuaCaller.create;
      lc.luaroutineIndex:=luaL_ref(L,LUA_REGISTRYINDEX);
    end
    else
    begin
      if lua_isnumber(L, 2) then
        size:=lua_tointeger(L, 2)
      else
      begin //function name as string
        lc:=TLuaCaller.create;
        lc.luaroutine:=Lua_ToString(L,2);
      end;
    end;
  end;

  method:=preferedBreakpointMethod;

  if lc=nil then  //address, size OPTIONAL, trigger OPTIONAL, method, functiontocall OPTIONAL
  begin
    if parameters>=3 then
      trigger:=TBreakpointTrigger(lua_tointeger(L,3))
    else
      trigger:=bptExecute;

    if parameters>=4 then
    begin
      if lua_isnumber(L, 4) then //address, size OPTIONAL, trigger OPTIONAL, method
      begin
        method:=TBreakpointMethod(lua_tointeger(L,4));
      end
      else
      begin
        //addresss, size, trigger, function
        if lua_isfunction(L,4) then //address, function type
        begin
          lua_pushvalue(L,4);
          lc:=TLuaCaller.create;
          lc.luaroutineIndex:=luaL_ref(L,LUA_REGISTRYINDEX);
        end
        else
        begin
          lc:=TLuaCaller.create;
          lc.luaroutine:=Lua_ToString(L,4);
        end;
      end;
    end;


    if lc=nil then
    begin
      if parameters>=5 then
      begin
        if lua_isfunction(L,5) then //address, function type
        begin
          lua_pushvalue(L,5);
          lc:=TLuaCaller.create;
          lc.luaroutineIndex:=luaL_ref(L,LUA_REGISTRYINDEX);
        end
        else
        begin
          lc:=TLuaCaller.create;
          lc.luaroutine:=Lua_ToString(L,5);
        end;

      end;
    end;
  end;

  try
    if lc<>nil then
      bpe:=TBreakpointEvent(lc.BreakpointEvent)
    else
      bpe:=nil;

    if startdebuggerifneeded(false) then
    begin
      case trigger of
        bptAccess: debuggerthread.SetOnAccessBreakpoint(address, size, method, 0, bpe);
        bptWrite: debuggerthread.SetOnWriteBreakpoint(address, size, method, 0, bpe);
        bptExecute: debuggerthread.SetOnExecuteBreakpoint(address, method,false, 0, bpe);
      end;

      MemoryBrowser.hexview.update;
      Memorybrowser.disassemblerview.Update;
    end;

  except
  end;


  lua_pop(L, lua_gettop(L)); //clear the stack
end;

function debug_removeBreakpoint(L: Plua_State): integer; cdecl;
var parameters: integer;
  address: ptruint;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    address:=lua_toaddress(L,1);

    lua_pushboolean(L, ce_debug_removeBreakpoint(address));
    result:=1;
  end;

  lua_pop(L, lua_gettop(L)); //clear the stack
end;

function debug_continueFromBreakpoint(L: Plua_State): integer; cdecl;
var parameters: integer;
  method: TContinueOption;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    method:=TContinueOption(lua_tointeger(L, -1));
    ce_debug_continuefrombreakpoint(method);
  end;

  lua_pop(L, lua_gettop(L)); //clear the stack
end;

function debug_addThreadToNoBreakList(L: Plua_State): integer; cdecl;
begin
  result:=1;
  if debuggerthread<>nil then
  begin
    CurrentDebuggerInterface.AddToNoBreakList(lua_tointeger(L,1));
    lua_pushboolean(L, true);
  end
  else
    lua_pushboolean(L, false);
end;

function debug_removeThreadFromNoBreakList(L: Plua_State): integer; cdecl;
begin
  result:=1;
  if debuggerthread<>nil then
  begin
    CurrentDebuggerInterface.RemoveFromNoBreakList(lua_tointeger(L,1));
    lua_pushboolean(L, true);
  end
  else
    lua_pushboolean(L, false);
end;

var isclosing: boolean;
function closeCE(L: Plua_state): integer; cdecl;
var th: thandle;
  b: boolean;
begin
  if isclosing=false then
  begin
    isclosing:=true;

    ce_closeCE; //cleanup

    {$ifdef windows}
    ExitProcess(0);
    {$else}
    application.Terminate;
    {$endif}

  end;
  result:=0;
end;

function hideAllCEWindows(L: Plua_State): integer; cdecl;
begin
  result:=0;
  lua_pop(L, lua_gettop(L)); //clear the stack

  ce_hideAllCEWindows;
end;

function unhideMainCEwindow(L: Plua_State): integer; cdecl;
begin
  result:=0;
  lua_pop(L, lua_gettop(L)); //clear the stack

  ce_unhideMainCEwindow;
end;




function createLabel(L: Plua_State): integer; cdecl;
var parameters: integer;
  f,p: pointer;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    f:=lua_toceuserdata(L, -1);
    p:=ce_createLabel(f);

    lua_pop(L, lua_gettop(L));

    luaclass_newClass(L, p);
    result:=1;
  end else lua_pop(L, lua_gettop(L));
end;

function messageDialog(L: PLua_State): integer; cdecl;
var
  parameters: integer;
  message: pchar;
  dialogtype: integer;
  buttontype: integer;

  r: integer;

  i: integer;
  b: TMsgDlgButtons;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters>=3 then
  begin
    message:=lua.lua_tostring(L,-parameters);
    dialogtype:=lua_tointeger(L,-parameters+1);
    b:=[];
    for i:=-parameters+2 to -1 do
    begin
      buttontype:=lua_tointeger(L,i);
      case buttontype of
        0:  b:=b+[mbYes];
        1:  b:=b+[mbNo];
        2:  b:=b+[mbOK];
        3:  b:=b+[mbCancel];
        4:  b:=b+[mbAbort];
        5:  b:=b+[mbRetry];
        6:  b:=b+[mbIgnore];
        7:  b:=b+[mbAll];
        8:  b:=b+[mbNoToAll];
        9:  b:=b+[mbYesToAll];
        10: b:=b+[mbHelp];
        11: b:=b+[mbClose];
        else b:=b+[mbyes];
      end;
    end;
    lua_pop(L, parameters);

    r:=ce_messageDialog_lua(message, dialogtype, b);
    lua_pushinteger(L,r);
    result:=1;

  end else lua_pop(L, parameters);
end;

function speedhack_getSpeed(L: PLua_State): integer; cdecl;
begin
  lua_pushnumber(L, speedhack.getSpeed);
  result:=1;
end;

function speedhack_setSpeed(L: PLua_State): integer; cdecl;
var
  parameters: integer;
  speed: single;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    speed:=lua_tonumber(L,-1);
    ce_speedhack_setSpeed(speed);
  end;
  lua_pop(L, parameters);
end;

function injectDLL(L: PLua_State): integer; cdecl;
var
  parameters: integer;
  filename: pchar;
  r: boolean;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    filename:=lua.lua_tostring(L,-1);
    r:=false;
    try
      r:=ce_InjectDLL(filename,pchar(''));
    except
    end;

    result:=1;
    lua_pushboolean(L, r);
  end;
end;




function getAutoAttachList(L: Plua_State): integer; cdecl;
var f: pointer;
  parameters: integer;
  visible: boolean;
begin
  result:=1;
  lua_pop(L, lua_gettop(L));

  f:=ce_getAutoAttachList();
  luaclass_newClass(L, f);
  result:=1;
end;



function generateAPIHookScript_lua(L: PLua_state): integer; cdecl;
var
  parameters: integer;
  address: string;
  addressTo: string;
  addresstogetnewcalladdress: string;
  ext: string='';
  self: boolean=false;
  script: tstringlist;
begin
  address:='';
  addressTo:='';
  addresstogetnewcalladdress:='';

  result:=0;
  parameters:=lua_gettop(L);
  if parameters>=2 then
  begin
    address:=lua_tostring(L, 1);
    addressTo:=lua_tostring(L, 2);

    if parameters>=3 then
      addresstogetnewcalladdress:=lua_tostring(L, 3);

    if parameters>=4 then
      ext:=lua_tostring(L, 4);

    if parameters>=5 then
      self:=lua_toboolean(L,5);

    lua_pop(L, lua_gettop(L));

    script:=tstringlist.create;
    try
      generateAPIHookScript(script, address, addressto, addresstogetnewcalladdress,ext,self);
      lua_pushstring(L, pchar(script.text));
      result:=1;
    finally
      script.free;
    end;
  end;

end;

function createProcess(L: PLua_state): integer; cdecl;
var parameters: integer;
  path,params: string;
  debug: boolean;
  breakonentrypoint: boolean;
begin
  result:=0;
  parameters:=lua_gettop(L);
  path:='';
  params:='';
  debug:=false;
  breakonentrypoint:=false;

  if parameters>0 then
    path:=lua_tostring(L, 1);

  if parameters>1 then
    params:=lua_tostring(L, 2);

  if parameters>2 then
    debug:=lua_toboolean(L, 3);

  if parameters>3 then
    breakonentrypoint:=lua_toboolean(L, 4);

  if path<>'' then
    ce_createProcess(pchar(path), pchar(params), debug, breakonentrypoint);

  lua_pop(L, lua_gettop(L));
end;

function AOBScanUnique(L: PLua_state): integer; cdecl;
var
  scanstring: string;
  protectionflags: string;
  alignmentparam: string;
  alignmenttype: TFastScanMethod;
  list: tstringlist;
  r: ptruint;
  parameters: integer;
begin
  parameters:=lua_gettop(L);

  if parameters=1 then
  begin
    scanstring:=Lua_ToString(L,1);
    if parameters>=2 then
      protectionflags:=Lua_ToString(L, 2)
    else
      protectionflags:='*X*W*C';

    if parameters>=3 then
      alignmenttype:=TFastScanMethod(lua_tointeger(L, 3))
    else
      alignmenttype:=fsmNotAligned;

    if parameters>=4 then
      alignmentparam:=Lua_ToString(L, 4)
    else
      alignmentparam:='1';

    if scanstring='' then
    begin
      lua_pushstring(L,'Invalid parameter. Must be a string');
      lua_pushnil(L);
      result:=2;
    end;

    r:=findaob(scanstring, protectionflags, alignmenttype,alignmentparam,true);
    if r=0 then
      lua_pushnil(L)
    else
      lua_pushinteger(L,r);

    result:=1;
  end
  else
  begin
    lua_pushstring(L,'Not enough parameters');
    lua_pushnil(L);
    result:=2;
  end;

end;

function AOBScan(L: PLua_state): integer; cdecl;
var
  parameters: integer;
  i,b: integer;
  scanstring: string;
  protectionflags: string;
  alignmentparam: string;
  alignmenttype: TFastScanMethod;
  list: tstringlist;
begin
  result:=0;

  parameters:=lua_gettop(L);
  if parameters=0 then exit;

  protectionflags:='';
  alignmenttype:=fsmNotAligned;
  alignmentparam:='1';

  if (parameters>=1) and (lua_isstring(L,1)) then
  begin
    //it's a scanstring, optional call
    scanstring:=Lua_ToString(L, 1);
    if parameters>=2 then
      protectionflags:=Lua_ToString(L, 2);

    if parameters>=3 then
      alignmenttype:=TFastScanMethod(lua_tointeger(L, 3));

    if parameters>=4 then
      alignmentparam:=Lua_ToString(L, 4);


  end
  else
  begin
    //buildup the scanstring
    scanstring:='';
    for i:=-parameters to -1 do
    begin
      b:=lua_tointeger(L,i);

      if (b>255) then scanstring:=scanstring+'* '
      else
      if b=0 then
      begin
        if not lua_isnumber(L,i) then
          scanstring:=scanstring+'* '
        else
          scanstring:=scanstring+'00 '
      end
      else scanstring:=scanstring+inttohex(b,2)+' ';
    end;
  end;
  lua_pop(L, lua_gettop(L));


  list:=tstringlist.create;
  if getaoblist(scanstring, list, protectionflags, alignmenttype, alignmentparam) then
  begin
    result:=1;
    luaclass_newClass(L, list);
  end
  else
  begin
    list.free;
  end;

end;




function getOpenedProcessID(L: PLua_state): integer; cdecl;
begin
  lua_pushinteger(L, processid);
  result:=1;
end;

function getOpenedProcessHandle(L: PLua_state): integer; cdecl;
begin
  lua_pushinteger(L, processhandle);
  result:=1;
end;

function getSymbolInfo(L: PLua_state): integer; cdecl;
var
  parameters: integer;
  symbolname: string;
  mi: TModuleInfo;

  si: TCESymbolInfo;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    symbolname:=Lua_ToString(L, 1);
    lua_pop(L, lua_gettop(l));

    if symhandler.GetSymbolInfo(symbolname, si) then
    begin
      pushSymbol(L, @si);
      result:=1;
    end;
  end;
end;

function getModuleSize(L: PLua_state): integer; cdecl;
var
  parameters: integer;
  modulename: string;
  mi: TModuleInfo;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    modulename:=Lua_ToString(L, 1);
    lua_pop(L, lua_gettop(l));

    if symhandler.getmodulebyname(modulename, mi) then
    begin
      lua_pushinteger(L, mi.basesize);
      result:=1;
    end;
  end;
end;

function getAddressSafe(L: PLua_state): integer; cdecl;
var parameters: integer;
  s: string;

  local,shallow,e: boolean;

begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters>=1 then
  begin
    if lua_type(L,1)=LUA_TNUMBER then
    begin
      lua_pushinteger(L,lua_tointeger(L,1));
      exit(1);
    end;

    s:=Lua_ToString(L, 1);

    if parameters>=2 then
      local:=lua_toboolean(L, 2)
    else
      local:=false;

    if parameters>=3 then
      shallow:=lua_toboolean(L, 3)
    else
      shallow:=false;

    lua_pop(L, lua_gettop(l));

    try
      if not local then
        lua_pushinteger(L,symhandler.getAddressFromName(s, waitforsymbols, e, nil, shallow))
      else
        lua_pushinteger(L,selfsymhandler.getAddressFromName(s, waitforsymbols, e, nil, shallow));

      if e then
        result:=0
      else
        result:=1;
    except
      exit(0);
    end;


  end;
end;


function getAddress(L: PLua_state): integer; cdecl;
var parameters: integer;
  s: string;

  local: boolean;

begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters>=1 then
  begin
    if lua_type(L,1)=LUA_TNUMBER then
    begin
      lua_pushinteger(L,lua_tointeger(L,1));
      exit(1);
    end;

    s:=Lua_ToString(L, 1);

    if parameters>=2 then
      local:=lua_toboolean(L, 2)
    else
      local:=false;


    lua_pop(L, lua_gettop(l));

    try
      if not local then
        lua_pushinteger(L,symhandler.getAddressFromNameL(s, waitforsymbols))
      else
        lua_pushinteger(L,selfsymhandler.getAddressFromNameL(s, waitforsymbols));
    except
      on e:exception do
      begin
        {$ifdef cpu64}
        lua_pushstring(L,e.Message);
        lua_error(L);
        {$else}
        raise;
        {$endif}
      end;
    end;

    result:=1;
  end
  else
  lua_pop(L, lua_gettop(l));
end;

function getNameFromAddress(L: PLua_state): integer; cdecl;
var parameters: integer;
  s: string;
  address: ptruint;
  modulenames: boolean=true;
  symbols: boolean=true;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters>=1 then
  begin
    address:=lua_toaddress(L,1);

    if (parameters>=2) and (not lua_isnil(L,2)) then modulenames:=lua_toboolean(L,2);
    if (parameters>=3) and (not lua_isnil(L,3)) then symbols:=lua_toboolean(L,3);

    lua_pop(L, lua_gettop(l));

    lua_pushstring(L,symhandler.getNameFromAddress(address, symbols, modulenames));
    result:=1;
  end
  else lua_pop(L, lua_gettop(l));
end;

function inModule(L: PLua_state): integer; cdecl;
var parameters: integer;
  s: string;
  address: ptruint;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    address:=lua_toaddress(L,1);

    lua_pop(L, lua_gettop(l));

    lua_pushboolean(L,symhandler.inModule(address));
    result:=1;
  end
  else lua_pop(L, lua_gettop(l));
end;

function inSystemModule(L: PLua_state): integer; cdecl;
var parameters: integer;
  s: string;
  address: ptruint;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    address:=lua_toaddress(L,1);

    lua_pop(L, lua_gettop(l));

    lua_pushboolean(L,symhandler.inSystemModule(address));
    result:=1;
  end;
end;

function getCommonModuleList(L: PLua_state): integer; cdecl;
begin
  result:=0;
  lua_pop(L, lua_gettop(l));

  luaclass_newClass(L,symhandler.getCommonModuleList);
  result:=1;
end;

function reinitializeDotNetSymbolhandler(L:PLua_state): integer; cdecl;
var modulename: string;
begin
  result:=0;
  if lua_gettop(L)>=1 then
    modulename:=Lua_ToString(L, 1)
  else
    modulename:='';

  symhandler.reinitializeDotNetSymbols(modulename);
end;

function reinitializeSymbolhandler(L: PLua_state): integer; cdecl;
var waittilldone: boolean;
begin
  if lua_gettop(L)>=1 then
    waittilldone:=lua_toboolean(L,1)
  else
    waittilldone:=true;

  lua_pop(L, lua_gettop(L));
  result:=0;


  symhandler.reinitialize(true);

  if waitTillDone then
    symhandler.waitforsymbolsloaded;
end;

function waitForExports(L: PLua_state): integer; cdecl;
begin
  symhandler.waitforExports;
  result:=0;
end;


function waitForDotNet(L: PLua_state): integer; cdecl;
begin
  symhandler.waitforDotNet;
  result:=0;
end;

function waitForPDB(L: PLua_state): integer; cdecl;
begin
  symhandler.waitforpdb;
  result:=0;
end;

function searchPDBWhileLoading(L: PLua_state): integer; cdecl;
begin
  if lua_gettop(L)>=1 then
    symhandler.searchPDBWhileLoading(lua_toboolean(L,1));

  result:=0;
end;

function reinitializeSelfSymbolhandler(L: PLua_state): integer; cdecl;
var waittilldone: boolean;
begin
  if lua_gettop(L)>=1 then
    waittilldone:=lua_toboolean(L,1)
  else
    waittilldone:=true;

  lua_pop(L, lua_gettop(L));
  result:=0;


  selfsymhandler.reinitialize(true);

  if waitTillDone then
    selfsymhandler.waitforsymbolsloaded;
end;

function enumModules(L:PLua_state): integer; cdecl;
var
  i: integer;
  ml: tstringlist;
  tableindex: integer;
  entryindex: integer;

  ths: THandle;
  me32: TModuleEntry32;

  is64bitmodule: boolean;

  pid: integer;
begin
  result:=0;

  if lua_gettop(L)=1 then
    pid:=lua_tointeger(L,1)
  else
    pid:=processid;

  ths:=CreateToolhelp32Snapshot(TH32CS_SNAPMODULE or TH32CS_SNAPMODULE32, pid);
  if ths<>0 then
  begin
    lua_newtable(L);
    tableindex:=lua_gettop(L);

    me32.dwSize:=sizeof(MODULEENTRY32);

    i:=1;
    if module32first(ths,me32) then
    repeat
      lua_newtable(L);
      entryindex:=lua_gettop(L);

      lua_pushstring(L, 'Name');
      lua_pushstring(L, extractfilename(me32.szExePath));
      lua_settable(L, entryindex);

      lua_pushstring(L, 'Address');
      lua_pushinteger(L, ptruint(me32.modBaseAddr));
      lua_settable(L, entryindex);

      is64bitmodule:=processhandler.is64Bit;

      {$ifdef windows}
      if (processhandler.isNetwork) or (peinfo_is64bitfile(me32.szExePath, is64bitmodule)=false) then
        is64bitmodule:=processhandler.is64Bit; //fallback on an assumption
      {$endif}

      lua_pushstring(L, 'Is64Bit');
      lua_pushboolean(L, is64bitmodule);
      lua_settable(L, entryindex);

      lua_pushstring(L, 'PathToFile');
      lua_pushstring(L, me32.szExePath);
      lua_settable(L, entryindex);


      lua_pushinteger(L, i);
      lua_pushvalue(L, entryindex);
      lua_settable(L, tableindex);

      lua_pop(L, 1); //remove the current entry table

      inc(i);
    until Module32Next(ths, me32)=false;

    lua_pushvalue(L, tableindex); //shouldn't be needed, but let's make sure
    result:=1;

    closehandle(ths);

  end;
end;




function getSettingsForm(L: PLua_state): integer; cdecl;
begin
  result:=1;
  lua_pop(L, lua_gettop(l));
  luaclass_newClass(l, formSettings);
end;

function getMemoryViewForm(L: PLua_state): integer; cdecl;
begin
  result:=1;
  lua_pop(L, lua_gettop(l));
  luaclass_newClass(l, MemoryBrowser);
end;


function getMainForm(L: PLua_state): integer; cdecl;
begin
  result:=1;
  lua_pop(L, lua_gettop(l));
  luaclass_newClass(l, mainform);
end;




function getAddressList(L: PLua_state): integer; cdecl;
begin
  result:=1;
  lua_pop(L, lua_gettop(l));
  luaclass_newClass(l, mainform.addresslist);
end;

function getFreezeTimer(L: PLua_state): integer; cdecl;
begin
  result:=1;
  lua_pop(L, lua_gettop(l));
  luaclass_newClass(l, mainform.FreezeTimer);
end;

function getUpdateTimer(L: PLua_state): integer; cdecl;
begin
  result:=1;
  lua_pop(L, lua_gettop(l));
  luaclass_newClass(l, mainform.UpdateTimer);
end;

function setGlobalKeyPollInterval(L: PLua_state): integer; cdecl;
begin
  if lua_gettop(L)=1 then
    hotkeyPollInterval:=lua_tointeger(L, -1);

  result:=0;
end;

function setGlobalDelayBetweenHotkeyActivation(L: PLua_state): integer; cdecl;
begin
  if lua_gettop(L)=1 then
    hotkeyIdletime:=lua_tointeger(L, -1);

  result:=0;
end;



function inheritsFromObject(L: PLua_state): integer; cdecl;
var x: TObject;
begin
  result:=0;
  if lua_gettop(L)>=1 then
  begin
    x:=lua_toceuserdata(L, 1);
    lua_pop(L, lua_gettop(l));

    if x<>nil then
    begin
      result:=1;
      lua_pushboolean(l, (x is TObject));
    end;

  end;
end;

function inheritsFromComponent(L: PLua_state): integer; cdecl;
var x: TObject;
begin
  result:=0;
  if lua_gettop(L)>=1 then
  begin
    x:=lua_toceuserdata(L, 1);
    lua_pop(L, lua_gettop(l));

    if x<>nil then
    begin
      result:=1;
      lua_pushboolean(l, (x is TComponent));
    end;

  end;
end;

function inheritsFromControl(L: PLua_state): integer; cdecl;
var x: TObject;
  r: boolean;
begin
  result:=0;
  if lua_gettop(L)>=1 then
  begin
    x:=lua_toceuserdata(L, 1);
    lua_pop(L, lua_gettop(l));

    if x<>nil then
    begin
      result:=1;
      r:=x is TControl;
      lua_pushboolean(l, r);
    end;

  end;
end;

function inheritsFromWinControl(L: PLua_state): integer; cdecl;
var x: TObject;
begin
  result:=0;
  if lua_gettop(L)>=1 then
  begin
    x:=lua_toceuserdata(L, 1);
    lua_pop(L, lua_gettop(l));

    if x<>nil then
    begin
      result:=1;
      lua_pushboolean(l, (x is TWinControl));
    end;

  end;
end;


function createToggleBox(L: Plua_State): integer; cdecl;
var
  ToggleBox: TCEToggleBox;
  parameters: integer;
  owner: TWincontrol;
begin
  result:=0;

  parameters:=lua_gettop(L);
  if parameters>=1 then
    owner:=lua_toceuserdata(L, -parameters)
  else
    owner:=nil;

  lua_pop(L, lua_gettop(L));


  ToggleBox:=TCEToggleBox.Create(owner);
  if owner<>nil then
    ToggleBox.Parent:=owner;

  luaclass_newClass(L, ToggleBox);
  result:=1;
end;


function opendialog_execute(L: Plua_State): integer; cdecl; //6.2- version only
var
  opendialog: TOpenDialog;
begin
  opendialog:=luaclass_getClassObject(L);
  if opendialog.execute then
    lua_pushnil(L)
  else
    lua_pushstring(L, opendialog.FileName);

  result:=1;
end;

function createOpenDialog(L: Plua_State): integer; cdecl;
var
  o: TOpenDialog;
begin
  result:=0;

  if lua_gettop(L)>=1 then
    luaclass_newClass(L, TOpenDialog.create(lua_toceuserdata(L, 1)))
  else
    luaclass_newClass(L, TOpenDialog.create(nil));

  result:=1;
end;

function createSaveDialog(L: Plua_State): integer; cdecl;
var
  o: TSaveDialog;
begin
  result:=0;

  if lua_gettop(L)>=1 then
    luaclass_newClass(L, TSaveDialog.create(lua_toceuserdata(L, 1)))
  else
    luaclass_newClass(L, TSaveDialog.create(nil));

  result:=1;
end;

function CreateSelectDirectoryDialog(L: Plua_State): integer; cdecl;
var
  o: TSaveDialog;
begin
  result:=0;

  if lua_gettop(L)>=1 then
    luaclass_newClass(L, TSelectDirectoryDialog.create(lua_toceuserdata(L, 1)))
  else
    luaclass_newClass(L, TSelectDirectoryDialog.create(nil));

  result:=1;
end;


function createMemoryStream(L: Plua_State): integer; cdecl;
begin
  luaclass_newClass(L, TMemoryStream.create);
  result:=1;
end;

function createFileStream(L: Plua_State): integer; cdecl;
var
  filename: string;
  mode: word;
begin
  result:=0;
  if lua_gettop(L)>=1 then
  begin
    filename:=lua_tostring(L, 1);
    if lua_gettop(L)>=2 then
      mode:=lua_tointeger(L, 2)
    else
    begin
      //in case the user forgets or doesn't care
      if FileExists(filename) then
        mode:=fmOpenReadWrite or fmShareDenyNone
      else
        mode:=fmCreate;
    end;

    luaclass_newClass(L, TFileStream.create(filename, mode));
    result:=1;
  end;
end;

{
function createStringStream(L: Plua_State): integer; cdecl;
var s: pchar;
  //sl: size_t;
  ss: TStringStream;
  b: TBytes;

  stringlength: psize_t;
begin
  getmem(stringlength,16);



  if lua_gettop(L)>0 then
    s:=lua_tolstring(L, 1, stringlength)
  else
    s:=nil;

  setlength(b,0);
  ss:=TStringStream.create('',TEncoding.Default,false); //(s);
  if (s<>nil) and (stringlength^>0) then
  begin
    ss.WriteBuffer(s^, stringlength^);
    ss.position:=0;
  end;

  freemem(stringlength);

  luaclass_newClass(L, ss);
  result:=1;
end;
}

function createStringStream(L: Plua_State): integer; cdecl;
var s: pchar;
  sl: size_t=0;
  ss: TStringStream;
begin
  if lua_gettop(L)>0 then
    s:=lua_tolstring(L, 1, @sl)
  else
    s:=nil;

  ss:=TStringStream.create(''{$if FPC_FULLVERSION>=030200},TEncoding.Default,false{$endif});
  if (s<>nil) and (sl>0) then
  begin
    ss.WriteBuffer(s^, sl);
    ss.position:=0;
  end;

  luaclass_newClass(L, ss);       //lua_pushinteger(L,ptruint(ss));

  result:=1;
end;



function readRegionFromFile(L: Plua_State): integer; cdecl;
var parameters: integer;
  filename: string;
  address: ptruint;
  size: integer;
  x: PtrUInt;
  buf: pointer;
  f: tmemorystream;
begin
  result:=0;
  x:=0;
  f:=nil;

  parameters:=lua_gettop(L);
  if (parameters=2) then
  begin
    filename:=Lua_ToString(L, 1);
    address:=lua_toaddress(L,2);

    lua_pop(L, lua_gettop(L));

    f:=tmemorystream.create;
    try
      f.LoadFromFile(filename);
      writeprocessmemory(processhandle, pointer(address), f.memory, f.size, x);

    finally
      freeandnil(f);
    end;


    result:=1;
    lua_pushinteger(L,x);
  end else lua_pop(L, lua_gettop(L));
end;


function writeRegionToFile(L: Plua_State): integer; cdecl;
var parameters: integer;
  filename: string;
  address: ptruint;
  size: integer;
  x: PtrUInt;
  buf: pointer;
  f: tfilestream;
begin
  result:=0;
  x:=0;
  f:=nil;

  parameters:=lua_gettop(L);
  if (parameters=3) then
  begin
    filename:=Lua_ToString(L, -3);
    address:=lua_toaddress(L,-2);

    size:=lua_tointeger(L,-1);
    lua_pop(L, lua_gettop(L));

    getmem(buf,size);
    try

      readprocessmemory(processhandle, pointer(address), buf, size, x);

      f:=tfilestream.create(filename, fmCreate);
      f.WriteBuffer(buf^, x);

    finally
      if f<>nil then
        FreeAndNil(f);

      freememandnil(buf);
    end;


    result:=1;
    lua_pushinteger(L,x);
  end else lua_pop(L, lua_gettop(L));
end;


function registerSymbol(L: Plua_State): integer; cdecl;
var parameters: integer;
  symbolname: string;
  address: string;
  donotsave: boolean;
begin
  result:=0;

  parameters:=lua_gettop(L);
  if (parameters>=2) then
  begin
    symbolname:=Lua_ToString(L, -parameters);
    if lua_isstring(L, -parameters+1) then
      address:=lua_tostring(L,-parameters+1)
    else
      address:=IntToHex(lua_tointeger(L,-parameters+1),1);


    donotsave:=(parameters>=3) and (lua_toboolean(L, -parameters+2));


    symhandler.AddUserdefinedSymbol(address, symbolname, donotsave);
  end;

  lua_pop(L, lua_gettop(L));
end;

function unregisterSymbol(L: Plua_State): integer; cdecl;
var parameters: integer;
  symbolname: string;
begin
  result:=0;

  parameters:=lua_gettop(L);
  if (parameters=1) then
  begin
    symbolname:=Lua_ToString(L, -1);
    symhandler.DeleteUserdefinedSymbol(symbolname);
  end;

  lua_pop(L, lua_gettop(L));
end;

function resetLuaState(L: Plua_State): integer; cdecl;
begin
  result:=0;
  lua_pop(L, lua_gettop(L));
  InitializeLua; //this creates a NEW lua state (cut doesn't destroy the current one)
end;

function reloadSettingsFromRegistry(L: Plua_State): integer; cdecl;
begin
  result:=0;
  LoadSettingsFromRegistry;
end;

function createMemScan(L: Plua_State): integer; cdecl;
var
  progressbar: TCustomProgressbar;
  memscan: TMemScan;
  parameters: integer;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
    progressbar:=lua_toceuserdata(L, -1)
  else
    progressbar:=nil;

  lua_pop(L, lua_gettop(L));

  if (progressbar<>nil) and (progressbar is TCustomProgressBar=false) then
    raise exception.create(rsCreateMemScanNeedsAProgressbarOrNil+progressbar.ClassName+rsIsNotAProgressbar);

  memscan:=TMemscan.create(progressbar);

  luaclass_newClass(L, memscan);
  result:=1;
end;

function getCurrentMemscan(L: Plua_State): integer; cdecl;
begin
  lua_pop(L, lua_gettop(L));

  luaclass_newClass(L, mainform.memscan);
  result:=1;
end;





function supportCheatEngine(L: Plua_State): integer; cdecl;
var
  parameters: integer;
  //attachwindow, hasclosebutton, width, height, position ,yoururl OPTIONAL, extraparameters OPTIONAL, percentageshown OPTIONAL
  attachwindow: TCustomForm;
  hasCloseButton: boolean;
  width: integer;
  height: integer;
  position: integer;
  yoururl: string;
  extraparameters: string;
  percentageshown: integer;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters>=5 then
  begin
    attachwindow:=lua_toceuserdata(L, 1);
    hasCloseButton:=lua_toboolean(L, 2);
    width:=lua_tointeger(L, 3);
    height:=lua_tointeger(L, 4);
    position:=lua_tointeger(L, 5);

    if parameters>=6 then
      yoururl:=Lua_ToString(L, 6)
    else
      yoururl:='';

    if parameters>=7 then
      extraparameters:=Lua_ToString(L, 7)
    else
      extraparameters:='';

    if parameters>=8 then
      percentageshown:=lua_tointeger(L, 8)
    else
      percentageshown:=0;

    lua_pop(L, lua_gettop(L));

    if adwindow=nil then
      adwindow:=TADWindow.Create2(Application, hasclosebutton);

    adwindow.clientWidth:=width;
    adwindow.clientheight:=height;
    adwindow.show;
    adwindow.AttachToForm(attachwindow);
    case position of
      0: adwindow.setPosition(akTop);
      1: adwindow.setPosition(akRight);
      2: adwindow.setPosition(akBottom);
      3: adwindow.setPosition(akLeft);
    end;

    adwindow.setUserUrl(yoururl);
    adwindow.setUserPercentage(percentageshown);
    adwindow.optional:=extraparameters;

    adwindow.LoadAdNow;


  end else lua_pop(L, lua_gettop(L));
end;

function fuckCheatEngine(L: Plua_State): integer; cdecl;
begin
  lua_pop(L, lua_gettop(L));
  if adwindow<>nil then
    adWindow.visible:=false;

  result:=0;
end;


function dbk_initialize(L: Plua_State): integer; cdecl;
var
  state,x: BOOL;
  reason: string;
begin
  result:=0;
  {$IFDEF windows}
  if isDriverLoaded(nil)=false then
  begin
    reason:='A lua script wants to load the driver. Reason:';
    if lua_gettop(L)>=1 then
      reason:=Lua_ToString(L,1)
    else
      reason:='No reason';

    LoadDBK32;
    state:=isDriverLoaded(@x);
    lua_pushboolean(L, state);
    if state then
      lua_pushinteger(L, hdevice);

    result:=2;
  end
  else
  begin
    lua_pushboolean(L,true);
    result:=1;
  end;
  {$ENDIF}

end;

function dbk_useKernelmodeOpenProcess(L: Plua_State): integer; cdecl;
begin
  {$IFDEF windows}
  UseDBKOpenProcess;
  {$ENDIF}
  result:=0;
end;

function dbk_useKernelmodeProcessMemoryAccess(L: Plua_State): integer; cdecl;
begin
  {$IFDEF windows}
  UseDBKReadWriteMemory;
  {$ENDIF}
  result:=0;
end;

function dbk_useKernelmodeQueryMemoryRegions(L: Plua_State): integer; cdecl;
begin
  {$IFDEF windows}
  UseDBKQueryMemoryRegion;
  {$ENDIF}
  result:=0;
end;

function dbk_usePhysicalMemoryAccess(L: Plua_State): integer; cdecl;
begin
  {$IFDEF windows}
  if dbvm_version<>0 then
    DBKPhysicalMemoryDBVM
  else
    DBKPhysicalMemory;

  MainForm.ProcessLabel.Caption:=strPhysicalMemory;
  {$ENDIF}
  result:=0;
end;

function dbk_setSaferPhysicalMemoryScanning(L: Plua_State): integer; cdecl;
begin
  {$IFDEF windows}
  saferQueryPhysicalMemory:=lua_toboolean(L,1);
  {$ENDIF}
  result:=0;
end;


function lua_dbk_readphysicalmemory(L: PLua_state): integer; cdecl;
var
  PhysicalAddress: qword;
  buffer:pointer;
  size:integer;
  i: integer;
  br: ptruint;
begin
  result:=0;

  {$IFDEF windows}
  if lua_gettop(L)<2 then raise exception.create('not all parameters given');
  PhysicalAddress:=lua_tointeger(L,1);
  size:=lua_tointeger(L,2);
  getmem(buffer,size);

  br:=0;
  ReadPhysicalMemory(qword(-1),pointer(PhysicalAddress), buffer, size, br);
  if size=br then
  begin
    CreateByteTableFromPointer(L, buffer,size);
    freemem(buffer);
    exit(1);
  end
  else
  begin
    freemem(buffer);
    exit(0);
  end;
  {$ENDIF}
end;

function lua_dbk_writephysicalmemory(L: PLua_state): integer; cdecl;
var
  PhysicalAddress: qword;
  buffer:pointer;
  size:integer;
  i: integer;
  bw: ptruint;
begin
  result:=0;

  {$IFDEF windows}
  if lua_gettop(L)<2 then raise exception.create('not all parameters given');
  PhysicalAddress:=lua_tointeger(L,1);
  if lua_istable(L,2)=false then raise exception.create('2nd parameter needs to be a bytetable');
  size:=lua_objlen(L, 2);
  getmem(buffer,size);
  readBytesFromTable(L,2,buffer,size);

  bw:=0;
  WritePhysicalMemory(qword(-1),pointer(PhysicalAddress), buffer, size, bw);
  if size=bw then
    lua_pushboolean(L,true)
  else
    lua_pushboolean(L,false);

  freemem(buffer);

  exit(1);
  {$ENDIF}

end;


function dbk_getPEProcess(L: PLua_State): integer; cdecl;
var
  parameters: integer;
  pid: dword;
begin
  result:=0;
  {$IFDEF windows}
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    pid:=lua_tointeger(L,-1);

    lua_pushinteger(L, GetPEProcess(pid));
    result:=1;
  end else lua_pop(L, parameters);
  {$ENDIF}
end;

function dbk_getPEThread(L: PLua_State): integer; cdecl;
var
  parameters: integer;
  pid: dword;
begin
  result:=0;
  {$IFDEF windows}
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    pid:=lua_tointeger(L,-1);

    lua_pushinteger(L, GetPEThread(pid));
    result:=1;
  end else lua_pop(L, parameters);
  {$ENDIF}
end;

function dbk_executeKernelMemory(L: PLua_State): integer; cdecl;
var
  parameters: integer;
  address: ptruint;
  parameter: ptruint;
begin
  result:=0;
  {$IFDEF windows}
  parameters:=lua_gettop(L);
  if parameters>=1 then
  begin
    address:=lua_toaddress(L,-parameters);

    if parameters>=2 then
    begin
      if lua_isstring(L, -parameters+1) then
        parameter:=symhandler.getAddressFromNameL(Lua_ToString(L,-parameters+1), waitforsymbols)
      else
        parameter:=lua_tointeger(L, -parameters+1);
    end
    else
      parameter:=0;

    lua_pop(L, parameters);


    executeKernelCode(address,parameter);

    result:=0;
  end else lua_pop(L, parameters);
  {$ENDIF}
end;

function dbk_writesIgnoreWriteProtection(L: PLua_State): integer; cdecl;
var state: boolean;
begin
  result:=0;
  {$IFDEF windows}
  if lua_gettop(L)=1 then
  begin
    state:=lua_toboolean(L, 1);
    lua_pushboolean(L, KernelWritesIgnoreWriteProtection(state));
    result:=1;
  end;
  {$ENDIF}
end;

function lua_getPhysicalAddressCR3(L: PLua_State): integer; cdecl;
var
  CR3: QWORD;
  VirtualAddress: QWORD;
  PhysicalAddress: QWORD;
begin
  result:=0;
  {$IFDEF windows}
  if lua_gettop(L)>=2 then
  begin
    CR3:=lua_tointeger(L,1);
    VirtualAddress:=lua_tointeger(L,2);
    if VirtualToPhysicalCR3(CR3, VirtualAddress, PhysicalAddress) then
    begin
      lua_pushinteger(L, PhysicalAddress);
      result:=1;
    end;
  end;
  {$ENDIF}
end;

function lua_readProcessMemoryCR3(L: PLua_State): integer; cdecl;
var
  CR3: QWORD;
  Address: QWORD;
  Size: integer;
  x: ptruint;
  buf: pointer;

begin
  result:=0;
  {$IFDEF windows}
  if lua_gettop(L)>=3 then
  begin
    CR3:=lua_tointeger(L,1);
    Address:=lua_tointeger(L,2);
    Size:=lua_tointeger(L,3);

    getmem(buf, size);
    x:=0;
    ReadProcessMemoryCR3(cr3, pointer(address), buf, size, x);
    if x>0 then
    begin
      CreateByteTableFromPointer(L, buf, x);
      result:=1;
      freememandnil(buf);
    end;
  end;
  {$ENDIF}
end;

function lua_writeProcessMemoryCR3(L: PLua_State): integer; cdecl;
var
  CR3: QWORD;
  Address: QWORD;
  size: integer;
  buf: pointer;
  x: ptruint;
begin
  result:=0;
  {$IFDEF windows}
  if lua_gettop(L)>=3 then
  begin
    CR3:=lua_tointeger(L,1);
    Address:=lua_tointeger(L,2);
    if lua_istable(L,3) then
    begin
      size:=lua_objlen(L, 3);
      getmem(buf,size);
      readBytesFromTable(L, 3, buf, size);

      x:=0;
      WriteProcessMemoryCR3(cr3, pointer(Address), buf, size, x);
      freememandnil(buf);

      if (x>0) then
      begin
        lua_pushboolean(L,true);
        exit(1);
      end;
    end;
  end;

  lua_pushboolean(L, false);
  result:=1;
  {$ENDIF}
end;

function dbk_getPhysicalAddress(L: PLua_State): integer; cdecl;
var
  address: ptruint;
  pa: int64;
begin
  result:=0;
  {$IFDEF windows}
  if lua_gettop(L)=1 then
  begin
    address:=lua_toaddress(L,1);

    if GetPhysicalAddress(processhandle, pointer(address), pa) then
    begin
      lua_pushinteger(L, pa);
      result:=1;
    end;
  end;
  {$ENDIF}
end;

function dbk_getCR0(L: PLua_state): integer; cdecl;
begin
  result:=0;
  {$IFDEF windows}
  lua_pushinteger(L, getcr0);
  result:=1;
  {$ENDIF}
end;

function dbk_getCR3(L: PLua_state): integer; cdecl;
var cr3: qword;
begin
  result:=0;
  {$IFDEF windows}
  if GetCR3(processhandle, cr3) then
    lua_pushinteger(L, cr3)
  else
    lua_pushnil(L);

  result:=1;
  {$ENDIF}
end;

function dbk_getCR4(L: PLua_state): integer; cdecl;
begin
  result:=0;
  {$IFDEF windows}
  lua_pushinteger(L, getcr4);
  result:=1;
  {$ENDIF}
end;

function dbvm_getCR0(L: PLua_state): integer; cdecl;
begin
  result:=0;
  {$IFDEF windows}
  lua_pushinteger(L, dbvm_getRealCR0);
  result:=1;
  {$ENDIF}
end;

function dbvm_getCR3(L: PLua_state): integer; cdecl;
begin
  result:=0;
  {$IFDEF windows}
  lua_pushinteger(L, dbvm_getRealCR3);
  result:=1;
  {$ENDIF}
end;

function dbvm_getCR4(L: PLua_state): integer; cdecl;
begin
  lua_pushinteger(L, dbvm_getRealCR4);
  result:=1;
end;

function lua_dbk_test(L: PLua_state): integer; cdecl;
begin
  result:=0;
  {$IFDEF windows}
  dbk_test;
  {$ENDIF}
end;


function lua_dbvm_jtagbp(L: PLua_state): integer; cdecl;
begin
  lua_pushboolean(L, dbvm_jtagbp);
  result:=1;
end;

function lua_dbvm_readMSR(L: PLua_State): integer; cdecl;
var
  parameters: integer;
  msr: dword;
begin
  result:=0;
  if lua_gettop(L)>=1 then
  begin
    msr:=lua_tointeger(L,1);
    lua_pushinteger(L, dbvm_readMSR(msr));
    result:=1;
  end;
end;

function lua_dbvm_writeMSR(L: PLua_State): integer; cdecl;
var
  parameters: integer;
  msr: dword;
  msrvalue: qword;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=2 then
  begin
    msr:=lua_tointeger(L,1);
    msrvalue:=lua_tointeger(L,2);
    dbvm_writeMSR(msr, msrvalue);
  end;

  lua_pop(L, parameters);
end;

function lua_dbvm_writephysicalmemory(L: PLua_state): integer; cdecl;
var
  PhysicalAddress: qword;
  buffer:pointer;
  size:integer;
  i: integer;
begin
  if lua_gettop(L)<2 then raise exception.create('not all parameters given');
  PhysicalAddress:=lua_tointeger(L,1);
  if lua_istable(L,2)=false then raise exception.create('2nd parameter needs to be a bytetable');
  size:=lua_objlen(L, 2);
  getmem(buffer,size);
  readBytesFromTable(L,2,buffer,size);

  i:=dbvm_write_physical_memory(PhysicalAddress, buffer, size);
  if size=i then
    lua_pushboolean(L,true)
  else
    lua_pushboolean(L,false);

  freemem(buffer);

  exit(1);

end;

function lua_dbvm_readphysicalmemory(L: PLua_state): integer; cdecl;
var
  PhysicalAddress: qword;
  buffer:pointer;
  size:integer;
  i: integer;
begin
  if lua_gettop(L)<2 then raise exception.create('not all parameters given');
  PhysicalAddress:=lua_tointeger(L,1);
  size:=lua_tointeger(L,2);
  getmem(buffer,size);

  i:=dbvm_read_physical_memory(PhysicalAddress, buffer, size);
  if size=i then
  begin
    CreateByteTableFromPointer(L, buffer,size);
    freemem(buffer);
    exit(1);
  end
  else
  begin
    freemem(buffer);
    raise exception.create('not all memory read');
  end;
end;

function lua_dbvm_psod(L: PLua_state): integer; cdecl;
begin
  dbvm_psod;
  result:=1;
  lua_pushstring(L,'WTF');
end;

function lua_dbvm_getNMIcount(L: PLua_state): integer; cdecl;
begin
  lua_pushinteger(L, dbvm_getNMIcount);
  result:=1;
end;

function lua_dbvm_get_statistics(L: PLua_state): integer; cdecl;
var
  stats: TDBVMStatistics;
  i: integer;
  count: qword;
begin
  result:=0;
  count:=dbvm_get_statistics(stats);

  lua_newtable(L);
  //
  lua_pushstring(L,'Local');
  lua_newtable(L);
  for i:=0 to 55 do
  begin
    lua_pushinteger(L,i);
    lua_pushinteger(L,stats.eventCountersCurrentCPU[i]);
    lua_settable(L,-3);
  end;
  lua_settable(L,-3);

  lua_pushstring(L,'Global');
  lua_newtable(L);
  for i:=0 to 55 do
  begin
    lua_pushinteger(L,i);
    lua_pushinteger(L,stats.eventCountersAllCPUS[i]);
    lua_settable(L,-3);
  end;
  lua_settable(L,-3);


  lua_pushinteger(L,count);
  result:=2;

end;

function lua_dbvm_watch_writes(L: PLua_state): integer; cdecl;
var
  physicalAddress: qword=0;
  size: integer;
  options: DWORD;
  MaxEntryCount: integer;

  top: integer;
begin
  top:=lua_gettop(L);
  if top>=1 then
    physicalAddress:=lua_tointeger(L,1)
  else
  begin
    lua_pushstring(L, 'dbvm_watch_writes needs a physical address');
    lua_error(L);
  end;

  if top>=2 then
    size:=lua_tointeger(L,2)
  else
    size:=4;

  if top>=3 then
    options:=lua_tointeger(L,3)
  else
    options:=0;

  if top>=4 then
    MaxEntryCount:=lua_tointeger(L,4)
  else
    MaxEntryCount:=16;

  lua_pushinteger(L, dbvm_watch_writes(physicalAddress, Size, Options, MaxEntryCount));
  result:=1;
end;

function lua_dbvm_watch_reads(L: PLua_state): integer; cdecl;
var
  physicalAddress: qword=0;
  size: integer;
  options: DWORD;
  MaxEntryCount: integer;

  top: integer;
begin
  top:=lua_gettop(L);
  if top>=1 then
    physicalAddress:=lua_tointeger(L,1)
  else
  begin
    lua_pushstring(L, 'dbvm_watch_reads needs a physical address');
    lua_error(L);
  end;

  if top>=2 then
    size:=lua_tointeger(L,2)
  else
    size:=4;

  if top>=3 then
    options:=lua_tointeger(L,3)
  else
    options:=0;

  if top>=4 then
    MaxEntryCount:=lua_tointeger(L,4)
  else
    MaxEntryCount:=16;

  lua_pushinteger(L, dbvm_watch_reads(physicalAddress, Size, Options, MaxEntryCount));
  result:=1;
end;

function lua_dbvm_watch_executes(L: PLua_state): integer; cdecl;
var
  physicalAddress: qword=0;
  size: integer;
  options: DWORD;
  MaxEntryCount: integer;

  top: integer;
begin
  top:=lua_gettop(L);
  if top>=1 then
    physicalAddress:=lua_tointeger(L,1)
  else
  begin
    lua_pushstring(L, 'dbvm_watch_reads needs a physical address');
    lua_error(L);
  end;

  if top>=2 then
    size:=lua_tointeger(L,2)
  else
    size:=4;

  if top>=3 then
    options:=lua_tointeger(L,3)
  else
    options:=0;

  if top>=4 then
    MaxEntryCount:=lua_tointeger(L,4)
  else
    MaxEntryCount:=16;

  lua_pushinteger(L, dbvm_watch_executes(physicalAddress, Size, Options, MaxEntryCount));
  result:=1;
end;

function lua_dbvm_watch_retrievelog(L: PLua_state): integer; cdecl;
  procedure lua_push_watch_basic_fields(pbasic: PPageEventBasic; index: integer);
  begin
    lua_pushstring(L,'VirtualAddress');
    lua_pushinteger(L,pbasic^.VirtualAddress);
    lua_settable(L,index);

    lua_pushstring(L,'PhysicalAddress');
    lua_pushinteger(L,pbasic^.PhysicalAddress);
    lua_settable(L,index);

    lua_pushstring(L,'CR3');
    lua_pushinteger(L,pbasic^.CR3);
    lua_settable(L,index);

    lua_pushstring(L,'FSBASE');
    lua_pushinteger(L,pbasic^.FSBASE);
    lua_settable(L,index);

    lua_pushstring(L,'GSBASE');
    lua_pushinteger(L,pbasic^.GSBASE);
    lua_settable(L,index);

    lua_pushstring(L,'FLAGS');
    lua_pushinteger(L,pbasic^.FLAGS);
    lua_settable(L,index);

    lua_pushstring(L,'RAX');
    lua_pushinteger(L,pbasic^.RAX);
    lua_settable(L,index);

    lua_pushstring(L,'RBX');
    lua_pushinteger(L,pbasic^.RBX);
    lua_settable(L,index);

    lua_pushstring(L,'RCX');
    lua_pushinteger(L,pbasic^.RCX);
    lua_settable(L,index);

    lua_pushstring(L,'RDX');
    lua_pushinteger(L,pbasic^.RDX);
    lua_settable(L,index);

    lua_pushstring(L,'RSI');
    lua_pushinteger(L,pbasic^.RSI);
    lua_settable(L,index);

    lua_pushstring(L,'RDI');
    lua_pushinteger(L,pbasic^.RDI);
    lua_settable(L,index);

    lua_pushstring(L,'R8');
    lua_pushinteger(L,pbasic^.R8);
    lua_settable(L,index);

    lua_pushstring(L,'R9');
    lua_pushinteger(L,pbasic^.R9);
    lua_settable(L,index);

    lua_pushstring(L,'R10');
    lua_pushinteger(L,pbasic^.R10);
    lua_settable(L,index);

    lua_pushstring(L,'R11');
    lua_pushinteger(L,pbasic^.R11);
    lua_settable(L,index);

    lua_pushstring(L,'R12');
    lua_pushinteger(L,pbasic^.R12);
    lua_settable(L,index);

    lua_pushstring(L,'R13');
    lua_pushinteger(L,pbasic^.R13);
    lua_settable(L,index);

    lua_pushstring(L,'R14');
    lua_pushinteger(L,pbasic^.R14);
    lua_settable(L,index);

    lua_pushstring(L,'R15');
    lua_pushinteger(L,pbasic^.R15);
    lua_settable(L,index);

    lua_pushstring(L,'RBP');
    lua_pushinteger(L,pbasic^.RBP);
    lua_settable(L,index);

    lua_pushstring(L,'RSP');
    lua_pushinteger(L,pbasic^.RSP);
    lua_settable(L,index);

    lua_pushstring(L,'RIP');
    lua_pushinteger(L,pbasic^.RIP);
    lua_settable(L,index);

    lua_pushstring(L,'CS');
    lua_pushinteger(L,pbasic^.CS);
    lua_settable(L,index);

    lua_pushstring(L,'DS');
    lua_pushinteger(L,pbasic^.DS);
    lua_settable(L,index);

    lua_pushstring(L,'ES');
    lua_pushinteger(L,pbasic^.ES);
    lua_settable(L,index);

    lua_pushstring(L,'SS');
    lua_pushinteger(L,pbasic^.SS);
    lua_settable(L,index);

    lua_pushstring(L,'FS');
    lua_pushinteger(L,pbasic^.FS);
    lua_settable(L,index);

    lua_pushstring(L,'GS');
    lua_pushinteger(L,pbasic^.GS);
    lua_settable(L,index);

    lua_pushstring(L,'Count');
    lua_pushinteger(L,pbasic^.Count);
    lua_settable(L,index);
  end;

  procedure lua_push_watch_fxsave_fields(fpudata: PFXSAVE64; index: integer);
  var index2: integer;
  begin
    lua_pushstring(L,'FXSAVE64');
    lua_createtable(L,0,32);
    index2:=lua_gettop(L); //should be index+2

    lua_pushstring(L,'FCW');
    lua_pushinteger(L,fpudata^.FCW);
    lua_settable(L,index2);

    lua_pushstring(L,'FSW');
    lua_pushinteger(L,fpudata^.FSW);
    lua_settable(L,index2);

    lua_pushstring(L,'FTW');
    lua_pushinteger(L,fpudata^.FTW);
    lua_settable(L,index2);

    lua_pushstring(L,'FOP');
    lua_pushinteger(L,fpudata^.FOP);
    lua_settable(L,index2);

    lua_pushstring(L,'IP');
    lua_pushinteger(L,fpudata^.FPU_IP);
    lua_settable(L,index2);

    lua_pushstring(L,'DP');
    lua_pushinteger(L,fpudata^.FPU_DP);
    lua_settable(L,index2);

    lua_pushstring(L,'MXCSR');
    lua_pushinteger(L,fpudata^.MXCSR);
    lua_settable(L,index2);

    lua_pushstring(L,'MXCSR_MASK');
    lua_pushinteger(L,fpudata^.MXCSR_MASK);
    lua_settable(L,index2);

    lua_pushstring(L,'FP_MM0');
    CreateByteTableFromPointer(L, @fpudata.FP_MM0,16);
    lua_settable(L,index2);

    lua_pushstring(L,'FP_MM1');
    CreateByteTableFromPointer(L, @fpudata.FP_MM1,16);
    lua_settable(L,index2);

    lua_pushstring(L,'FP_MM2');
    CreateByteTableFromPointer(L, @fpudata.FP_MM2,16);
    lua_settable(L,index2);

    lua_pushstring(L,'FP_MM3');
    CreateByteTableFromPointer(L, @fpudata.FP_MM3,16);
    lua_settable(L,index2);

    lua_pushstring(L,'FP_MM4');
    CreateByteTableFromPointer(L, @fpudata.FP_MM4,16);
    lua_settable(L,index2);

    lua_pushstring(L,'FP_MM5');
    CreateByteTableFromPointer(L, @fpudata.FP_MM5,16);
    lua_settable(L,index2);

    lua_pushstring(L,'FP_MM6');
    CreateByteTableFromPointer(L, @fpudata.FP_MM6,16);
    lua_settable(L,index2);

    lua_pushstring(L,'FP_MM7');
    CreateByteTableFromPointer(L, @fpudata.FP_MM7,16);
    lua_settable(L,index2);

    lua_pushstring(L,'XMM0');
    CreateByteTableFromPointer(L, @fpudata.XMM0,16);
    lua_settable(L,index2);

    lua_pushstring(L,'XMM1');
    CreateByteTableFromPointer(L, @fpudata.XMM1,16);
    lua_settable(L,index2);

    lua_pushstring(L,'XMM2');
    CreateByteTableFromPointer(L, @fpudata.XMM2,16);
    lua_settable(L,index2);

    lua_pushstring(L,'XMM3');
    CreateByteTableFromPointer(L, @fpudata.XMM3,16);
    lua_settable(L,index2);

    lua_pushstring(L,'XMM4');
    CreateByteTableFromPointer(L, @fpudata.XMM4,16);
    lua_settable(L,index2);

    lua_pushstring(L,'XMM5');
    CreateByteTableFromPointer(L, @fpudata.XMM5,16);
    lua_settable(L,index2);

    lua_pushstring(L,'XMM6');
    CreateByteTableFromPointer(L, @fpudata.XMM6,16);
    lua_settable(L,index2);

    lua_pushstring(L,'XMM7');
    CreateByteTableFromPointer(L, @fpudata.XMM7,16);
    lua_settable(L,index2);

    lua_pushstring(L,'XMM8');
    CreateByteTableFromPointer(L, @fpudata.XMM8,16);
    lua_settable(L,index2);

    lua_pushstring(L,'XMM9');
    CreateByteTableFromPointer(L, @fpudata.XMM9,16);
    lua_settable(L,index2);

    lua_pushstring(L,'XMM10');
    CreateByteTableFromPointer(L, @fpudata.XMM10,16);
    lua_settable(L,index2);

    lua_pushstring(L,'XMM11');
    CreateByteTableFromPointer(L, @fpudata.XMM11,16);
    lua_settable(L,index2);

    lua_pushstring(L,'XMM12');
    CreateByteTableFromPointer(L, @fpudata.XMM12,16);
    lua_settable(L,index2);

    lua_pushstring(L,'XMM13');
    CreateByteTableFromPointer(L, @fpudata.XMM13,16);
    lua_settable(L,index2);

    lua_pushstring(L,'XMM14');
    CreateByteTableFromPointer(L, @fpudata.XMM14,16);
    lua_settable(L,index2);

    lua_pushstring(L,'XMM15');
    CreateByteTableFromPointer(L, @fpudata.XMM15,16);
    lua_settable(L,index2);


    lua_settable(L,index);
  end;

  procedure lua_push_watch_stack(stack: pointer; index: integer);
  begin
    lua_pushstring(L,'Stack');
    CreateByteTableFromPointer(L, stack, 4096);
    lua_settable(L,index);
  end;

var
  id: integer;
  size: integer;
  buf: PPageEventListDescriptor;
  i: integer;

  basic: PPageEventBasicArray;
  extended: PPageEventExtendedArray absolute basic;
  basics: PPageEventBasicWithStackArray absolute basic;
  extendeds: PPageEventExtendedWithStackArray absolute basic;
begin

  OutputDebugString('lua_dbvm_watch_retrievelog');
  result:=0;
  if lua_gettop(L)=0 then exit;
  ID:=lua_tointeger(L,1);

  OutputDebugString('id='+inttostr(id));

  lua_pop(L,lua_gettop(L));

  buf:=nil;
  size:=0;
  i:=dbvm_watch_retrievelog(ID, buf,size);
  while i=2 do
  begin
    //must be 2
    OutputDebugString('reallocating buffer for watchlog');

    if (buf<>nil) then
    begin
      freememandnil(buf);

    end;

    size:=size*2;
    getmem(buf, size);
    if (buf=nil) then exit;

    FillMemory(buf, size,$ce);
    i:=dbvm_watch_retrievelog(ID, buf,size);
  end;

  if i<>0 then
  begin
    lua_pushnil(L);
    case i of
      1: lua_pushstring(L,'invalid id');
      3: lua_pushstring(L,'inactive id');
      4: lua_pushstring(L,'invalid address for buffer');
      else lua_pushstring(L,'unknown error '+inttostr(i));
    end;

    exit(2);
  end;

  outputdebugstring('Buf allocated at '+inttohex(QWORD(buf),8));

  basic:=PPageEventBasicArray(qword(buf)+sizeof(TPageEventListDescriptor));

  outputdebugstring('sizeof(TPageEventBasic)='+inttostr(sizeof(TPageEventBasic)));
  outputdebugstring('sizeof(TPageEventExtended)='+inttostr(sizeof(TPageEventExtended)));
  outputdebugstring('sizeof(TPageEventBasicWithStack)='+inttostr(sizeof(TPageEventBasicWithStack)));
  outputdebugstring('sizeof(TPageEventExtendedWithStack)='+inttostr(sizeof(TPageEventExtendedWithStack)));


  outputdebugstring('sizeof(TPageEventListDescriptor)='+inttostr(sizeof(TPageEventListDescriptor)));
  outputdebugstring('  buf^.ID='+inttostr(buf^.ID));
  outputdebugstring('  buf^.maxSize='+inttostr(buf^.maxSize));
  outputdebugstring('  buf^.numberOfEntries='+inttostr(buf^.numberOfEntries));
  outputdebugstring('  buf^.entryType='+inttostr(buf^.entryType));

  lua_createtable(L, buf^.numberOfEntries, 0); //index 1

  for i:=0 to buf^.numberOfEntries-1 do
  begin
    lua_pushinteger(L,i+1); //2
    lua_createtable(L, 0, 32); //3

    case buf^.entryType of
      0:
      begin
        //basic
        lua_push_watch_basic_fields(@basic[i], 3);
      end;

      1:
      begin
        //extended
        lua_push_watch_basic_fields(@extended^[i].basic, 3);
        lua_push_watch_fxsave_fields(@extended^[i].fpudata, 3);
      end;

      2:
      begin
        //basics
        lua_push_watch_basic_fields(@basics^[i].basic, 3);
        lua_push_watch_stack(@basics^[i].stack[0], 3);
      end;

      3:
      begin
        //extendeds
        lua_push_watch_basic_fields(@extendeds^[i].basic, 3);
        lua_push_watch_fxsave_fields(@extendeds^[i].fpudata, 3);
        lua_push_watch_stack(@extendeds^[i].stack[0], 3);
      end;
    end;

    lua_settable(L,1);

  end;

  result:=1;
end;

function lua_dbvm_watch_disable(L: PLua_State): integer; cdecl;
var
  id: integer;
begin
  if lua_gettop(L)=0 then exit(0);

  id:=lua_tointeger(L,1);
  dbvm_watch_delete(id);

  result:=0;
end;

function lua_dbvm_cloak_activate(L: PLua_State): integer; cdecl;
var PA, VA: QWORD;
begin
  result:=0;
  if lua_gettop(L)>=1 then
  begin
    pa:=lua_tointeger(L,1);
    if lua_gettop(L)>=2 then
      VA:=lua_tointeger(L,2)
    else
      VA:=0;

    lua_pushinteger(L, dbvm_cloak_activate(PA, VA));
    result:=1;
  end;
end;

function lua_dbvm_cloak_deactivate(L: PLua_State): integer; cdecl;
var PA: QWORD;
begin
  result:=0;
  if lua_gettop(L)>=1 then
  begin
    pa:=lua_tointeger(L,1);
    lua_pushboolean(L, dbvm_cloak_deactivate(PA));
    result:=1;
  end;
end;

function lua_dbvm_cloak_readOriginal(L: PLua_State): integer; cdecl;
var
  PA: QWORD;
  buf: pointer;
begin
  result:=0;
  if lua_gettop(L)>=1 then
  begin
    pa:=lua_tointeger(L,1);
    getmem(buf,4096);
    dbvm_cloak_readoriginal(PA, buf);

    CreateByteTableFromPointer(L, buf, 4096);
    FreeMemAndNil(buf);
    result:=1;
  end;
end;

function lua_dbvm_cloak_writeOriginal(L: PLua_State): integer; cdecl;
var
  PA: QWORD;
  buf: pointer;
  r: integer;
begin
  result:=0;
  if lua_gettop(L)>=2 then
  begin
    pa:=lua_tointeger(L,1);
    if lua_istable(L,2) then
    begin
      getmem(buf,4096);
      readBytesFromTable(L, 2,buf,4096);
      r:=dbvm_cloak_writeoriginal(PA, buf);
      lua_pushinteger(L, r);

      FreeMemAndNil(buf);
      result:=1;
    end;
  end;
end;

function lua_dbvm_changeregonbp(L: PLua_State): integer; cdecl;
var
  pa,va: qword;
  changeregonbpinfo: TChangeRegOnBPInfo;
  r: boolean;

begin
  result:=0;
  if lua_gettop(L)>=2 then
  begin
    pa:=lua_tointeger(L,1);
    if lua_istable(L,2) then
    begin
      lua_pushstring(L,'newCF');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.Flags.newCF:=lua_tointeger(L,-1);
      changeregonbpinfo.Flags.changeCF:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);


      lua_pushstring(L,'newPF');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.Flags.newPF:=lua_tointeger(L,-1);
      changeregonbpinfo.Flags.changePF:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);

      lua_pushstring(L,'newAF');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.Flags.newAF:=lua_tointeger(L,-1);
      changeregonbpinfo.Flags.changeAF:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);

      lua_pushstring(L,'newZF');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.Flags.newZF:=lua_tointeger(L,-1);
      changeregonbpinfo.Flags.changeZF:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);

      lua_pushstring(L,'newSF');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.Flags.newSF:=lua_tointeger(L,-1);
      changeregonbpinfo.Flags.changeSF:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);

      lua_pushstring(L,'newOF');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.Flags.newOF:=lua_tointeger(L,-1);
      changeregonbpinfo.Flags.changeOF:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);

      lua_pushstring(L,'newRAX');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.newRAX:=lua_tointeger(L,-1);
      changeregonbpinfo.flags.changeRAX:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);

      lua_pushstring(L,'newRBX');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.newRBX:=lua_tointeger(L,-1);
      changeregonbpinfo.Flags.changeRBX:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);

      lua_pushstring(L,'newRCX');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.newRCX:=lua_tointeger(L,-1);
      changeregonbpinfo.Flags.changeRCX:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);

      lua_pushstring(L,'newRDX');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.newRDX:=lua_tointeger(L,-1);
      changeregonbpinfo.Flags.changeRDX:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);

      lua_pushstring(L,'newRSI');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.newRSI:=lua_tointeger(L,-1);
      changeregonbpinfo.Flags.changeRSI:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);

      lua_pushstring(L,'newRDI');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.newRDI:=lua_tointeger(L,-1);
      changeregonbpinfo.Flags.changeRDI:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);

      lua_pushstring(L,'newRBP');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.newRBP:=lua_tointeger(L,-1);
      changeregonbpinfo.Flags.changeRBP:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);

      lua_pushstring(L,'newRSP');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.newRSP:=lua_tointeger(L,-1);
      changeregonbpinfo.Flags.changeRSP:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);

      lua_pushstring(L,'newRIP');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.newRIP:=lua_tointeger(L,-1);
      changeregonbpinfo.Flags.changeRIP:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);

      lua_pushstring(L,'newR8');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.newR8:=lua_tointeger(L,-1);
      changeregonbpinfo.Flags.changeR8:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);

      lua_pushstring(L,'newR9');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.newR9:=lua_tointeger(L,-1);
      changeregonbpinfo.Flags.changeR9:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);

      lua_pushstring(L,'newR10');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.newR10:=lua_tointeger(L,-1);
      changeregonbpinfo.Flags.changeR10:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);

      lua_pushstring(L,'newR11');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.newR11:=lua_tointeger(L,-1);
      changeregonbpinfo.Flags.changeR11:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);

      lua_pushstring(L,'newR12');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.newR12:=lua_tointeger(L,-1);
      changeregonbpinfo.Flags.changeR12:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);

      lua_pushstring(L,'newR13');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.newR13:=lua_tointeger(L,-1);
      changeregonbpinfo.Flags.changeR13:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);

      lua_pushstring(L,'newR14');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.newR14:=lua_tointeger(L,-1);
      changeregonbpinfo.Flags.changeR14:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);

      lua_pushstring(L,'newR15');
      lua_gettable(L,2);

      if not lua_isnil(L,-1) then
        changeregonbpinfo.newR15:=lua_tointeger(L,-1);
      changeregonbpinfo.Flags.changeR15:=ifthen(lua_isnil(L,-1), 0, 1);
      lua_pop(L,1);

      if lua_gettop(L)>=3 then
        VA:=lua_tointeger(L,3)
      else
        VA:=0;


      r:=dbvm_cloak_changeregonbp(PA, changeregonbpinfo, VA)=0;
      lua_pushboolean(l,r);
      result:=1;
    end;

  end;
end;

function lua_dbvm_removechangeregonbp(L: PLua_State): integer; cdecl;
var PA: qword;
begin
  result:=0;
  if lua_gettop(L)>=1 then
  begin
    PA:=lua_tointeger(L,1);
    lua_pushboolean(L, dbvm_cloak_removechangeregonbp(PA)=0);
    result:=1;
  end;
end;

function lua_dbvm_ept_reset(L: PLua_State): integer; cdecl;
begin
  dbvm_ept_reset;
  result:=0;
end;



function lua_dbvm_log_cr3_start(L: PLua_State): integer; cdecl;
begin
  lua_pushboolean(L, dbvm_log_cr3values_start);
  result:=1;
end;

function lua_dbvm_log_cr3_stop(L: PLua_State): integer; cdecl;
var
  r: boolean;
  log: array [0..511] of QWORD;
  i,j: integer;
begin
  result:=0;
  r:=dbvm_log_cr3values_stop(@log[0]);
  if r then
  begin
    lua_newtable(L);
    j:=1;
    for i:=0 to 511 do
    begin
      if log[i]<>0 then
      begin
        lua_pushinteger(L, j);
        lua_pushinteger(L,log[i]);
        lua_settable(L, -3);
        inc(j);
      end;
    end;
    result:=1;
  end;
end;


function lua_dbvm_registerPlugin(L: PLua_State): integer; cdecl;
var
  pluginAddress: ptruint;
  pluginSize: integer;
  plugintype: integer;
  r: integer;
begin
  if lua_gettop(L)>=3 then
  begin
    pluginAddress:=lua_tointeger(L,1);
    pluginSize:=lua_tointeger(L,2);
    plugintype:=lua_tointeger(L,2);
    r:=dbvm_registerPlugin(pointer(pluginAddress), pluginSize, pluginType);
    lua_pushinteger(L,r);
    result:=1;
  end
  else
    result:=0;
end;

function lua_dbvm_raisePMI(L: PLua_State): integer; cdecl;
begin
  result:=0;
  dbvm_raisePMI;
end;

function lua_dbvm_ultimap2_hideRangeUsage(L: PLua_State): integer; cdecl;
begin
  result:=0;
  dbvm_ultimap2_hideRangeUsage;
end;

function lua_dbvm_ultimap_getDebugInfo(L: PLua_State): integer; cdecl;
var
  di: TULTIMAPDEBUGINFO;
  r: integer;
begin
  r:=dbvm_ultimap_debuginfo(@di);
  result:=2;
  lua_pushinteger(L,r);
  lua_newtable(L);


  lua_pushstring(L,'Active');
  lua_pushinteger(L,di.Active);
  lua_settable(L,2);

  lua_pushstring(L,'CR3');
  lua_pushinteger(L,di.CR3);
  lua_settable(L,2);

  lua_pushstring(L,'DEBUGCTL');
  lua_pushinteger(L,di.DEBUGCTL);
  lua_settable(L,2);

  lua_pushstring(L,'DS_AREA');
  lua_pushinteger(L,di.DS_AREA);
  lua_settable(L,2);

  lua_pushstring(L,'OriginalDebugCTL');
  lua_pushinteger(L,di.OriginalDebugCTL);
  lua_settable(L,2);

  lua_pushstring(L,'OriginalDS_AREA');
  lua_pushinteger(L,di.OriginalDS_AREA);
  lua_settable(L,2);

  lua_pushstring(L,'CR3_switchcount');
  lua_pushinteger(L,di.CR3_switchcount);
  lua_settable(L,2);

  lua_pushstring(L,'CR3_switchcount2');
  lua_pushinteger(L,di.CR3_switchcount2);
  lua_settable(L,2);

  lua_pushstring(L,'LastOldCR3');
  lua_pushinteger(L,di.LastOldCR3);
  lua_settable(L,2);

  lua_pushstring(L,'LastNewCR3');
  lua_pushinteger(L,di.LastNewCR3);
  lua_settable(L,2);

  lua_pushstring(L,'cpunr');
  lua_pushinteger(L,di.cpunr);
  lua_settable(L,2);

  result:=2;
end;

function lua_dbvm_setTSCAdjust(L: PLua_State): integer; cdecl;
var
  enabled:boolean;
  timeout: integer;
begin
  result:=0;
  if lua_gettop(L)>=1 then
  begin
    enabled:=lua_toboolean(L,1);
    if enabled and (lua_gettop(L)>=2) then
      timeout:=lua_tointeger(L,2)
    else
      timeout:=2000;

    dbvm_setTSCAdjust(enabled, timeout);
  end;
end;

function lua_dbvm_speedhack_setSpeed(L: PLua_State): integer; cdecl;
var speed: double;
begin
  result:=0;
  if lua_gettop(L)>=1 then
  begin
    speed:=lua_tonumber(L,1);
    dbvm_speedhack_setSpeed(speed);
  end;

end;

function lua_dbvm_enableTSCHook(L: PLua_State): integer; cdecl;
begin
  dbvm_enableTSCHook;
  result:=0;
end;

function lua_dbvm_disableTSCHook(L: PLua_State): integer; cdecl;
begin
  lua_pushboolean(L, dbvm_disableTSCHook);
  result:=1;
end;

function lua_dbvm_findCR3(L: PLua_State): integer; cdecl;
begin
  lua_pushinteger(L, dbvm_findCR3(processhandle));
  result:=1;
end;

function dbk_readMSR(L: PLua_State): integer; cdecl;
var
  parameters: integer;
  msr: dword;
begin
  result:=0;
  {$IFDEF windows}
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    msr:=lua_tointeger(L,-1);
    lua_pushinteger(L, readMSR(msr));
    result:=1;
  end else lua_pop(L, parameters);
  {$ENDIF}
end;

function dbk_writeMSR(L: PLua_State): integer; cdecl;
var
  parameters: integer;
  msr: dword;
  msrvalue: qword;
begin
  result:=0;
  {$IFDEF windows}
  parameters:=lua_gettop(L);
  if parameters=2 then
  begin
    msr:=lua_tointeger(L,1);
    msrvalue:=lua_tointeger(L,2);
    writemsr(msr, msrvalue);
  end;

  lua_pop(L, parameters);
  {$ENDIF}
end;

function createSplitter(L: Plua_State): integer; cdecl;
var
  Splitter: TCESplitter;
  parameters: integer;
  owner: TWincontrol;
begin
  result:=0;

  parameters:=lua_gettop(L);
  if parameters>=1 then
    owner:=lua_toceuserdata(L, -parameters)
  else
    owner:=nil;

  lua_pop(L, lua_gettop(L));


  Splitter:=TCESplitter.Create(owner);
  if owner<>nil then
    Splitter.Parent:=owner;

  luaclass_newClass(L, splitter);
  result:=1;
end;

function createPaintBox(L: Plua_State): integer; cdecl;
var
  paintbox: TPaintbox;
  parameters: integer;
  owner: TWincontrol;
begin
  result:=0;

  parameters:=lua_gettop(L);
  if parameters>=1 then
    owner:=lua_toceuserdata(L, 1)
  else
    owner:=nil;

  lua_pop(L, lua_gettop(L));


  paintbox:=TPaintBox.Create(owner);
  if owner<>nil then
    paintbox.Parent:=owner;

  luaclass_newClass(L, paintbox);
  result:=1;
end;

function allocateSharedMemoryLocal(L: PLua_State): integer; cdecl;
var
  parameters: integer;
  sharedmemoryname: string;
  size: ptruint;
  address: pointer;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters>=1 then
  begin
    sharedmemoryname:=Lua_ToString(L,1);

    if parameters>=2 then
      size:=lua_tointeger(L, 2)
    else
      size:=4096;

    lua_pop(L, parameters);

    address:=allocateSharedMemory(sharedmemoryname, size);
    if address<>nil then
    begin
      lua_pushinteger(L, ptruint(address));
      result:=1;
    end;
  end else lua_pop(L, parameters);
end;

function deallocateSharedMemoryLocal(L: PLua_State): integer; cdecl;
var address: ptruint;
begin
  result:=0;
  if lua_gettop(L)>=1 then
  begin
    address:=lua_tointeger(L,1);

    UnmapViewOfFile(pointer(address));
  end;
end;

function allocateSharedMemory(L: PLua_State): integer; cdecl;
var
  parameters: integer;
  sharedmemoryname: string;
  size: ptruint;
  address: pointer;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters>=1 then
  begin
    sharedmemoryname:=Lua_ToString(L,-parameters);

    if parameters>=2 then
      size:=lua_tointeger(L, -parameters+1)
    else
      size:=4096;

    lua_pop(L, parameters);

    address:=allocateSharedMemoryIntoTargetProcess(sharedmemoryname, size);
    if address<>nil then
    begin
      lua_pushinteger(L, ptruint(address));
      result:=1;
    end;
  end else lua_pop(L, parameters);
end;

function deallocateSharedMemory(L: PLua_State): integer; cdecl;
var parameters: integer;
  address: ptruint;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters>=1 then
    lua_pop(L, parameters);

  lua_pushstring(L, rsDeallocateSharedMemoryIsNotImplemented);
  lua_error(L);
end;

function getCheatEngineDir(L: PLua_State): integer; cdecl;
begin
  lua_pop(L, lua_gettop(l));
  lua_pushstring(L, CheatEngineDir);
  result:=1;
end;

function lua_getCheatEngineProcessID(L: PLua_State): integer; cdecl;
begin
  lua_pop(L, lua_gettop(l));
  lua_pushinteger(L, GetCurrentProcessId);
  result:=1;
end;



function getInstructionSize(L: PLua_State): integer; cdecl;
var parameters: integer;
  address, address2: ptruint;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    address:=lua_toaddress(L,1);

    lua_pop(L, parameters);

    address2:=address;
    disassemble(address);
    lua_pushinteger(L, address-address2);
    result:=1;
  end
  else
    lua_pop(L, parameters);
end;

function getPreviousOpcode(L: PLua_State): integer; cdecl;
var parameters: integer;
  address, address2: ptruint;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    address:=lua_toaddress(L,1);

    lua_pop(L, parameters);

    lua_pushinteger(L, previousopcode(address));
    result:=1;
  end
  else
    lua_pop(L, parameters);
end;

function disassemble_lua(L: PLua_State): integer; cdecl;
var parameters: integer;
  address: ptruint;
  d: TDisassembler;
  x: string;
  s: string;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    address:=lua_toaddress(L,1);

    lua_pop(L, parameters);

    d:=TDisassembler.Create;
    try
      d.showmodules:=false;
      d.showsymbols:=false;
      s:=d.disassemble(address, x);
    finally
      d.free;
    end;


    result:=1;
    lua_pushstring(L, s);
  end else lua_pop(L, parameters);
end;

function splitDisassembledString(L: PLua_State): integer; cdecl;
var parameters: integer;
  disassembledstring: string;

  address, bytes, opcode, special: string;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    disassembledstring:=lua_tostring(L,-parameters);
    lua_pop(L, parameters);

    disassembler.splitDisassembledString(disassembledstring, true, address, bytes, opcode, special);

    result:=4;
    lua_pushstring(L, special);
    lua_pushstring(L, opcode);
    lua_pushstring(L, bytes);
    lua_pushstring(L, address);
  end
  else
    lua_pop(L, parameters);
end;

function hexadecimalview_getTopAddress(L: PLua_State): integer; cdecl;
var
  hv: THexView;
begin
  hv:=luaclass_getClassObject(L);
  lua_pushinteger(L, hv.address);
  result:=1;
end;

function hexadecimalview_setTopAddress(L: PLua_State): integer; cdecl;
var
  hv: THexView;
  address: ptruint;
begin
  result:=0;
  hv:=luaclass_getClassObject(L);
  if lua_gettop(L)>=1 then
  begin
    address:=lua_toaddress(L,1);

    hv.address:=address;
  end
end;

function hexadecimalview_onAddressChange(L: PLua_State): integer; cdecl;
var
  parameters: integer;
  hexadecimalview: THexView;
  f: integer;
  routine: string;

  lc: TLuaCaller;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=2 then
  begin
    hexadecimalview:=lua_toceuserdata(L,-2);

    CleanupLuaCall(tmethod(hexadecimalview.onAddressChange));
    hexadecimalview.onAddressChange:=nil;

    if lua_isfunction(L,-1) then
    begin
      f:=luaL_ref(L,LUA_REGISTRYINDEX);

      lc:=TLuaCaller.create;
      lc.luaroutineIndex:=f;
      hexadecimalview.onAddressChange:=lc.AddressChangeEvent;
    end
    else
    if lua_isstring(L,-1) then
    begin
      routine:=lua_tostring(L,-1);
      lc:=TLuaCaller.create;
      lc.luaroutine:=routine;
      hexadecimalview.onAddressChange:=lc.AddressChangeEvent;
    end;

  end;

  lua_pop(L, parameters);
end;

function hexadecimalview_onByteSelect(L: PLua_State): integer; cdecl;
var
  parameters: integer;
  hexadecimalview: THexView;
  f: integer;
  routine: string;

  lc: TLuaCaller;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=2 then
  begin
    hexadecimalview:=lua_toceuserdata(L,-2);

    CleanupLuaCall(tmethod(hexadecimalview.onByteSelect));
    hexadecimalview.onByteSelect:=nil;

    if lua_isfunction(L,-1) then
    begin
      routine:=Lua_ToString(L,-1);
      f:=luaL_ref(L,LUA_REGISTRYINDEX);

      lc:=TLuaCaller.create;
      lc.luaroutineIndex:=f;
      hexadecimalview.onByteSelect:=lc.ByteSelectEvent;
    end
    else
    if lua_isstring(L,-1) then
    begin
      routine:=lua_tostring(L,-1);
      lc:=TLuaCaller.create;
      lc.luaroutine:=routine;
      hexadecimalview.onByteSelect:=lc.ByteSelectEvent;
    end;

  end;

  lua_pop(L, parameters);
end;


function disassemblerview_getSelectedAddress(L: PLua_State): integer; cdecl;    //6.2-
var
  dv: TDisassemblerview;
begin
  dv:=luaclass_getClassObject(L);
  result:=2;
  lua_pushinteger(L, dv.SelectedAddress);
  lua_pushinteger(L, dv.SelectedAddress2); //6.2: Returns both addresses
end;

function disassemblerview_setSelectedAddress(L: PLua_State): integer; cdecl;  //6.2-
var
  dv: TDisassemblerview;
  address: ptruint;
begin
  result:=0;
  dv:=luaclass_getClassObject(L);
  if lua_gettop(L)>=1 then
  begin
    address:=lua_toaddress(L,1);

    dv.SelectedAddress:=address;
  end;
end;

function disassemblerview_onSelectionChange(L: PLua_State): integer; cdecl;
var
  parameters: integer;
  disassemblerview: TDisassemblerview;
  f: integer;
  routine: string;

  lc: TLuaCaller;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=2 then
  begin
    disassemblerview:=lua_toceuserdata(L,-2);

    CleanupLuaCall(tmethod(disassemblerview.onselectionchange));
    disassemblerview.onselectionchange:=nil;

    if lua_isfunction(L,-1) then
    begin

      f:=luaL_ref(L,LUA_REGISTRYINDEX);

      lc:=TLuaCaller.create;
      lc.luaroutineIndex:=f;
      disassemblerview.onselectionchange:=lc.DisassemblerSelectionChangeEvent;
    end
    else
    if lua_isstring(L,-1) then
    begin
      routine:=lua_tostring(L,-1);
      lc:=TLuaCaller.create;
      lc.luaroutine:=routine;
      disassemblerview.onselectionchange:=lc.DisassemblerSelectionChangeEvent;
    end;
    lua_pop(L, lua_gettop(L));
  end;

  lua_pop(L, parameters);
end;

function getForegroundProcess(L: PLua_State): integer; cdecl;
var h: thandle;
  pid: dword;
begin
  result:=0;
  {$IFDEF windows}
  lua_pop(L, lua_gettop(L));

  h:=GetForegroundWindow;

  GetWindowThreadProcessId(h, pid);
  lua_pushinteger(L, pid);
  result:=1;
  {$ENDIF}
end;

function cheatEngineIs64Bit(L: PLua_State): integer; cdecl;
begin
  lua_pop(L, lua_gettop(L));
  lua_pushboolean(L, {$ifdef cpu64}true{$else}false{$endif});
  result:=1;
end;

function targetIs64Bit(L: PLua_State): integer; cdecl;
begin
  lua_pop(L, lua_gettop(L));
  lua_pushboolean(L, processhandler.is64Bit);
  result:=1;
end;

function unregisterFormAddNotification(L: PLua_State): integer; cdecl;
var lc: TLuacaller;
begin
  result:=0;
  if lua_gettop(L)=1 then
  begin
    lc:=lua_ToCEUserData(L, -1);
    if lc<>nil then
      screen.RemoveHandlerFormAdded(lc.ScreenFormEvent);

    lc.Free;
  end;
end;

function registerFormAddNotification(L: PLua_State): integer; cdecl;
var lc: TLuaCaller;
  f: integer;
  routine: string;
begin
  result:=0;
  if lua_gettop(L)=1 then
  begin
    lc:=nil;

    if lua_isfunction(L,-1) then
    begin
      f:=luaL_ref(L,LUA_REGISTRYINDEX);

      lc:=TLuaCaller.create;
      lc.luaroutineIndex:=f;
      screen.AddHandlerFormAdded(lc.ScreenFormEvent);
    end
    else
    if lua_isstring(L,-1) then
    begin
      routine:=lua_tostring(L,-1);
      lc:=TLuaCaller.create;
      lc.luaroutine:=routine;
      screen.AddHandlerFormAdded(lc.ScreenFormEvent);
    end;


    luaclass_newClass(L, lc);
    result:=1;
  end;
end;

function getFormCount(L: PLua_State): integer; cdecl;
begin
  lua_pop(L, lua_gettop(L));
  lua_pushinteger(L, screen.FormCount);
  result:=1;
end;

function getForm(L: PLua_State): integer; cdecl;
var
  parameters: integer;
  f: TCustomForm;
  index: integer;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    index:=lua_tointeger(L, -1);
    lua_pop(L, lua_gettop(L));

    if index<screen.formcount then
    begin
      luaclass_newClass(L, screen.Forms[index]);
      result:=1;
    end;
  end
  else
    lua_pop(L, lua_gettop(L));
end;

function onAutoGuess(L: PLua_State): integer; cdecl;
var
  parameters: integer;
  lc: TLuaCaller;
  routine: string;
  f: integer;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    CleanupLuaCall(tmethod(onAutoGuessRoutine));
    onAutoGuessRoutine:=nil;

    if lua_isfunction(L,-1) then
    begin
      f:=luaL_ref(L,LUA_REGISTRYINDEX); //pop the last item of the stack, which is what I need

      lc:=TLuaCaller.create;
      lc.luaroutineIndex:=f;
      onAutoGuessRoutine:=lc.AutoGuessEvent;
    end
    else
    if lua_isstring(L,-1) then
    begin
      routine:=Lua_ToString(L, -1);
      lc:=TLuaCaller.create;
      lc.luaroutine:=routine;
      onAutoGuessRoutine:=lc.AutoGuessEvent;
    end;


  end;

  lua_pop(L, lua_gettop(L));
end;

function onAPIPointerChange(L: PLua_State): integer; cdecl;
var
  parameters: integer;
  lc: TLuaCaller;
  routine: string;
  f: integer;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    CleanupLuaCall(tmethod(plugin.onAPIPointerChange));
    plugin.onAPIPointerChange:=nil;

    if lua_isfunction(L,-1) then
    begin
      f:=luaL_ref(L,LUA_REGISTRYINDEX); //pop the last item of the stack, which is what I need

      lc:=TLuaCaller.create;
      lc.luaroutineIndex:=f;
      plugin.onAPIPointerChange:=lc.NotifyEvent;
    end
    else
    if lua_isstring(L,-1) then
    begin
      routine:=Lua_ToString(L, -1);
      lc:=TLuaCaller.create;
      lc.luaroutine:=routine;
      plugin.onAPIPointerChange:=lc.NotifyEvent;
    end;


  end;

  lua_pop(L, lua_gettop(L));
end;

function setAPIPointer(L: PLua_State): integer; cdecl;
var parameters: integer;
  apiID: integer;
  address: ptruint;
begin
  result:=0;
  {$IFDEF windows}
  parameters:=lua_gettop(L);
  if parameters=2 then
  begin
    apiID:=lua_tointeger(L, -2);
    address:=lua_toaddress(L,-1);


    lua_pop(L, parameters);

    case apiid of
      0: newkernelhandler.OpenProcess:=pointer(address);
      1: newkernelhandler.ReadProcessMemory:=pointer(address);
      2: newkernelhandler.WriteProcessMemoryActual:=pointer(address);
      3: newkernelhandler.VirtualQueryEx:=pointer(address);
    end;

  end
  else
    lua_pop(L, parameters);
  {$ENDIF}
end;


function dbvm_initialize(L: PLua_State): integer; cdecl;
var
  parameters: integer;
  offload: boolean;
  r: boolean;
  reason: string;
begin
  result:=0;

  {$IFDEF windows}
  //for now use the default
  if (dbvm_version>0) then
  begin
    //already loaded and initialized
    lua_pop(L, lua_gettop(L));
    lua_pushboolean(L, true);
    result:=1;
    exit;
  end;

  //not yet loaded/initialized
  if (vmx_password1=0) and (vmx_password2=0) then
  begin
    vmx_password1:=$76543210;
    vmx_password2:=$fedcba98;
  end;



  result:=0;
  parameters:=lua_gettop(L);
  if parameters>=1 then
  begin
    offload:=lua_toboolean(L, 1);

    if offload then
    begin
      if isRunningDBVM=false then
      begin
        reason:='A lua script wants to launch the DBVM hypervisor. Reason:';

        if parameters>=2 then
          reason:=Lua_ToString(L,2)
        else
          reason:='No reason given';

        //not yet loaded.
        if isDBVMCapable then
          r:=loaddbvmifneeded(reason);
      end;
    end;
  end
  else
    lua_pop(L, lua_gettop(L));

  result:=1;
  lua_pushboolean(L, dbvm_version>0);
  {$ENDIF}
end;

function dbvm_addMemory(L: PLua_State): integer; cdecl;
var pagecount: qword;
begin
  {$IFDEF windows}
  LoadDBK32;
  if lua_gettop(L)>=1 then
  begin
    pagecount:=lua_tointeger(L,1);
    allocateMemoryForDBVM(pagecount);

    dbvm_getMemory(pagecount);  //get the new count
    lua_pushinteger(L, pagecount);
    result:=1;
  end
  else
  {$ENDIF}
    result:=0;
end;

function lua_shellExecute(L: PLua_State): integer; cdecl;
var
  pcount: integer;
  command: string;
  parameters: string;
  folder: string;
  showcommand: integer;
begin
  pcount:=lua_gettop(L);
  if pcount>=1 then
  begin
    command:=utf8toansi(lua_tostring(L, -pcount));

    if pcount>=2 then
      parameters:=utf8toansi(lua_tostring(L, -pcount+1))
    else
      parameters:='';


    if pcount>=3 then
      folder:=utf8toansi(lua_tostring(L, -pcount+2))
    else
      folder:='';

    if pcount>=4 then
      showcommand:=lua_tointeger(L, -pcount+3)
    else
      showcommand:=SW_NORMAL;

    shellexecute(0,'open',pchar(command),pchar(parameters),pchar(folder),showcommand);
  end;

  lua_pop(L, lua_gettop(L));

  result:=0;

end;

function getTickCount_lua(L: PLua_State): integer; cdecl;
begin
  lua_pop(L, lua_gettop(L));
  result:=1;
  lua_pushinteger(L, GetTickCount64);
end;

function processMessages(L: PLua_State): integer; cdecl;
begin
  lua_pop(L, lua_gettop(L));
  result:=0;
  application.ProcessMessages;
end;

function integerToUserData(L: PLua_State): integer; cdecl;
var
  i: integer;
  parameters: integer;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    i:=lua_tointeger(L,-1);
    lua_pop(L, parameters);

    luaclass_newClass(L, pointer(ptruint(i)));
    result:=1;

  end else lua_pop(L, parameters);
end;

function userDataToInteger(L: PLua_State): integer; cdecl;
var
  u: pointer;
  parameters: integer;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    u:=lua_toceuserdata(L,-1);
    lua_pop(L, parameters);

    lua_pushinteger(L, ptruint(u));
    result:=1;

  end else lua_pop(L, parameters);
end;

function writeToClipboard(L: PLua_State): integer; cdecl;
var
  parameters: integer;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
    Clipboard.AsText:=Lua_ToString(L, -1);


  lua_pop(L, parameters);
end;

function readFromClipboard(L: PLua_State): integer; cdecl;
var s: string;
begin
  lua_pop(L, lua_gettop(L));

  lua_pushstring(L, Clipboard.AsText);
  result:=1;
end;




function createBitmap(L: Plua_State): integer; cdecl;
var
  Bitmap: TBitmap;
  parameters: integer;
  width, height: integer;
begin
  result:=0;

  parameters:=lua_gettop(L);
  if parameters>=1 then
    width:=lua_tointeger(L, 1)
  else
    width:=screen.width;

  if parameters>=2 then
    height:=lua_tointeger(L, 2)
  else
    height:=screen.height;


  lua_pop(L, parameters);

  Bitmap:=TBitmap.Create;
  bitmap.Width:=width;
  bitmap.Height:=height;


  luaclass_newClass(L, Bitmap);
  result:=1;
end;

function createPNG(L: Plua_State): integer; cdecl;
var
  png: TPortableNetworkGraphic;
  parameters: integer;
  width, height: integer;
begin
  result:=0;

  parameters:=lua_gettop(L);
  if parameters>=1 then
    width:=lua_tointeger(L, 1)
  else
    width:=screen.width;

  if parameters>=2 then
    height:=lua_tointeger(L, 2)
  else
    height:=screen.height;


  lua_pop(L, parameters);

  png:=TPortableNetworkGraphic.Create;
  png.Width:=width;
  png.Height:=height;


  luaclass_newClass(L, Png);
  result:=1;
end;

function createJpeg(L: Plua_State): integer; cdecl;
var
  jpeg: TJPEGImage;
  parameters: integer;
  width, height: integer;
begin
  result:=0;

  parameters:=lua_gettop(L);
  if parameters>=1 then
    width:=lua_tointeger(L, 1)
  else
    width:=screen.width;

  if parameters>=2 then
    height:=lua_tointeger(L, 2)
  else
    height:=screen.height;


  lua_pop(L, parameters);

  jpeg:=TJPEGImage.Create;
  jpeg.Width:=width;
  jpeg.Height:=height;


  luaclass_newClass(L, jpeg);
  result:=1;
end;

function createIcon(L: Plua_State): integer; cdecl;
var
  Icon: TIcon;
  parameters: integer;
  width, height: integer;
begin
  result:=0;

  parameters:=lua_gettop(L);
  if parameters>=1 then
    width:=lua_tointeger(L, 1)
  else
    width:=64;

  if parameters>=2 then
    height:=lua_tointeger(L, 2)
  else
    height:=64;


  lua_pop(L, parameters);

  icon:=TIcon.Create;
  icon.Width:=width;
  icon.Height:=height;


  luaclass_newClass(L, icon);
  result:=1;
end;

function lua_waitforsymbols(L: Plua_State): integer; cdecl;
begin
  result:=1;
  lua_pushboolean(L,waitforsymbols);

  if lua_gettop(L)>0 then
    waitforsymbols:=lua_toboolean(L,1);


end;

function errorOnLookupFailure(L: Plua_State): integer; cdecl;
var
  parameters: integer;

  oldvalue: boolean;
begin
  result:=0;
  parameters:=lua_gettop(L);
  oldvalue:=symhandler.ExceptionOnLuaLookup;

  if parameters=1 then
  begin
    symhandler.ExceptionOnLuaLookup:=lua_toboolean(L, -1);
    lua_pop(L, parameters);
    lua_pushboolean(L, oldvalue);
    result:=1;
  end
  else
    lua_pop(L, parameters);
end;

function loadPlugin(L: PLua_State): integer; cdecl;
var
  p: string;
  parameters: integer;
  pluginid: integer;
begin
  result:=1;
  pluginid:=0;

  parameters:=lua_gettop(L);

  if parameters=1 then
  begin
    p:=Lua_ToString(L, -1);
    try

      pluginid:=pluginhandler.LoadPlugin(p);
      if pluginid<>-1 then
        pluginhandler.EnablePlugin(pluginid);
    except
      pluginid:=-1;
    end;

  end;

  lua_pop(L, parameters);

  if pluginid=-1 then
    lua_pushnil(L)
  else
    lua_pushinteger(L, pluginid);
end;

function getCEVersion(L: PLua_State): integer; cdecl;
var
  p: string;
  parameters: integer;
  pluginid: integer;
begin
  lua_pop(L, lua_gettop(L));

  result:=1;
  lua_pushnumber(L, ceversion);
end;

function lua_Utf8ToAnsi(L: Plua_State): integer; cdecl;
var
  s: string;
  parameters: integer;
begin
  result:=0;
  parameters:=lua_gettop(L);

  if parameters=1 then
  begin
    s:=Lua_ToString(L, -1);
    lua_pop(L, parameters);

    lua_pushstring(L, UTF8ToWinCP(s));
    result:=1;
  end
  else
    lua_pop(L, parameters);
end;

function lua_AnsitoUTF8(L: Plua_State): integer; cdecl;
var
  s: string;
  parameters: integer;
begin
  result:=0;
  parameters:=lua_gettop(L);

  if parameters=1 then
  begin
    s:=Lua_ToString(L, -1);
    lua_pop(L, parameters);

    lua_pushstring(L, WinCPToUTF8(s));
    result:=1;
  end
  else
    lua_pop(L, parameters);
end;


function fullAccess(L: PLua_state): integer; cdecl;
var parameters: integer;
  address: ptruint;
  size: integer;
  op: dword;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=2 then
  begin
    address:=lua_toaddress(L,1);

    size:=lua_tointeger(L,2);

    lua_pop(L, lua_gettop(l));

    if virtualprotectex(processhandle,pointer(address),size,PAGE_EXECUTE_READWRITE,op) then
      lua_pushboolean(L,true)
    else
      lua_pushboolean(L,false);

    result:=1;
  end;
end;

function getWindowList_lua(L: PLua_state): integer; cdecl;
var
  parameters: integer;
  s: tstrings;
  i,j: integer;
  pid: integer;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters>=1 then
  begin
    s:=lua_toceuserdata(L,1);
    lua_pop(L, lua_gettop(l));
    if (s<>nil) and (s is TStrings) then
    begin
      GetWindowList(s);
      sanitizeProcessList(s);

    end
    else
    begin
      lua_pushstring(L,rsGetProcessListTheProvidedListObjectIsNotValid);
      lua_error(L);
    end;
  end
  else
  begin
    //table version
    s:=tstringlist.create;
    GetWindowList(s);
    sanitizeProcessList(s);



    lua_newtable(L);

    for i:=0 to s.Count-1 do
    begin
      if TryStrToInt('0x'+copy(s[i],1,8), pid) then
      begin
        lua_pushinteger(L, pid);
        lua_gettable(L,1);

        if lua_isnil(L,-1) then
        begin
          //not yet in the list
          j:=lua_gettop(L);

          lua_pop(L,1);
          lua_pushinteger(L, pid);
          lua_newtable(L);
          lua_settable(L,1);

          lua_pushinteger(L, pid);
          lua_gettable(L,1);
        end;

        j:=lua_objlen(L,-1);
        lua_pushinteger(L, j+1);
        lua_pushstring(L, copy(s[i], 10, length(s[i])));
        lua_settable(L, -3);

        lua_pop(L,1); //pop the current processid table
      end;
    end;

    s.free;

    result:=1; //table
  end;
end;

function getProcesslist_lua(L: PLua_state): integer; cdecl;
var
  parameters: integer;
  s: tstrings;
  i: integer;
  pid: integer;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters>=1 then
  begin
    s:=lua_toceuserdata(L,1);
    lua_pop(L, lua_gettop(l));
    if (s<>nil) and (s is TStrings) then
      GetProcessList(s, false, true)
    else
    begin
      lua_pushstring(L,rsGetProcessListTheProvidedListObjectIsNotValid);
      lua_error(L);
    end;
  end
  else
  begin
    //table version
    s:=tstringlist.create;
    GetProcessList(s, false, true);

    lua_newtable(L);

    for i:=0 to s.Count-1 do
    begin
      if TryStrToInt('0x'+copy(s[i],1,8), pid) then
      begin
        lua_pushinteger(L, pid);
        lua_pushstring(L, copy(s[i], 10, length(s[i])));
        lua_settable(L, 1);
      end;
    end;
    s.free;

    result:=1; //table
  end;
end;

function getThreadlist_lua(L: PLua_state): integer; cdecl;
var parameters: integer;
  s: tstrings;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters>=1 then
  begin
    s:=lua_toceuserdata(L,1);
    lua_pop(L, lua_gettop(l));
    if (s<>nil) and (s is TStrings) then
      GetThreadList(s)
    else
    begin
      lua_pushstring(L,rsGetThreadlistTheProvidedListObjectIsNotValid);
      lua_error(L);
    end;
  end
  else
    lua_pop(L, lua_gettop(l));
end;

function lua_loadTable(L: Plua_State): integer; cdecl;
var
  filename: string='';
  parameters: integer;
  merge: boolean;
  doc: TXMLDocument;
  s: Tstream;
  ignoreluascriptdialog: boolean;
begin
  result:=0;
  s:=nil;
  parameters:=lua_gettop(L);
  if parameters>=1 then
  begin
    if lua_isstring(L, 1) then
    begin
      filename:=Lua_ToString(L, 1);
      if (not fileexists(filename)) and (fileexists(wincptoutf8(filename))) then
        filename:=wincptoutf8(filename);
    end
    else
    begin
      s:=lua_toceuserdata(L, 1);
      if s=nil then
        exit;
    end;

    if parameters>=2 then
      merge:=lua_toboolean(L,2)
    else
      merge:=false;


    if s<>nil then //read a stream
    begin
      ignoreluascriptdialog:=false;
      if parameters>=3 then
        ignoreluascriptdialog:=lua_toboolean(L,3);

      ReadXMLFile(doc, s);
      loadxml(doc, merge, ignoreluascriptdialog);
    end
    else
      loadtable(filename,merge);
  end;

  lua_pop(L, lua_gettop(L));
end;

function lua_saveTable(L: Plua_State): integer; cdecl;
var
  filename: string;
  parameters: integer;
  protect: boolean;
  dontDeactivateDesignerForms: boolean;
begin
  result:=0;

  parameters:=lua_gettop(L);
  if parameters>=1 then
  begin
    filename:=Lua_ToString(L, 1);
    if parameters>=2 then
      protect:=lua_toboolean(L,2)
    else
      protect:=false;

    if parameters>=3 then
      dontDeactivateDesignerForms:=lua_toboolean(L,3)
    else
      dontDeactivateDesignerForms:=true;

    savetable(filename, protect, dontDeactivateDesignerForms);
  end;

  lua_pop(L, lua_gettop(L));
end;

function lua_detachIfPossible(L: Plua_State): integer; cdecl;
begin
  result:=0;
  DetachIfPossible;
  lua_pop(L, lua_gettop(L));
end;

function getComment(L: PLua_state): integer; cdecl;
var address: ptruint;
begin
  result:=0;
  if lua_gettop(L)=1 then
  begin
    address:=lua_toaddress(L,1);

    lua_pushstring(L, dassemblercomments.comments[address]);
    result:=1;
  end;
end;

function setComment(L: PLua_state): integer; cdecl;
var address: ptruint;
  comment: string;
begin
  result:=0;
  if lua_gettop(L)=2 then
  begin
    address:=lua_toaddress(L,1);

    comment:=Lua_ToString(L, 2);

    dassemblercomments.comments[address]:=comment;
  end;
end;

function getHeader(L: PLua_state): integer; cdecl;
var address: ptruint;
begin
  result:=0;
  if lua_gettop(L)=1 then
  begin
    address:=lua_toaddress(L,1);

    lua_pushstring(L, dassemblercomments.commentHeader[address]);
    result:=1;
  end;
end;

function setHeader(L: PLua_state): integer; cdecl;
var address: ptruint;
  Header: string;
begin
  result:=0;
  if lua_gettop(L)=2 then
  begin
    address:=lua_toaddress(L,1);

    Header:=Lua_ToString(L, 2);

    dassemblercomments.commentHeader[address]:=Header;
  end;
end;

function lua_createClass(L: PLua_State): integer; cdecl;
var classname: string;
begin
  result:=0;
  if lua_gettop(L)=1 then
  begin
    classname:=Lua_ToString(L,1);
    luaclass_newClass(L, GetClass(classname).Create);
    result:=1;
  end;
end;

function lua_createComponentClass(L: PLua_State): integer; cdecl;
var
  classname: string;
  owner: TComponent;
begin
  result:=0;
  if lua_gettop(L)=2 then
  begin
    classname:=Lua_ToString(L,1);
    owner:=lua_ToCEUserData(L,2);
    luaclass_newClass(L, TComponentClass(GetClass(classname)).Create(owner));
    result:=1;
  end;
end;

function openLuaServer(L: PLua_State): integer; cdecl;
var name: string;
begin
  result:=0;
  {$IFDEF windows}
  if lua_gettop(L)=1 then
    name:=Lua_ToString(L, 1)
  else
    name:='cheatenginebla';

  if luaserverExists(name)=false then
    tluaserver.create(name);
  {$ENDIF}
end;

function lua_registerAutoAssemblerCommand(L: PLua_State): integer; cdecl;
var command: string;
  f: integer;
  routine: string;
  lc: tluacaller;
begin
  result:=0;

  if lua_gettop(L)=2 then
  begin
    if lua_isstring(L, 1) then
    begin
      command:=Lua_ToString(L, 1);

      if lua_isfunction(L,2) then
      begin
        f:=luaL_ref(L,LUA_REGISTRYINDEX);

        lc:=TLuaCaller.create;
        lc.luaroutineIndex:=f;
      end
      else
      if lua_isstring(L,2) then
      begin
        routine:=lua_tostring(L,2);
        lc:=TLuaCaller.create;
        lc.luaroutine:=routine;
      end
      else exit;

      RegisterAutoAssemblerCommand(command, lc.AutoAssemblerCallback);
    end;

  end;

end;

function lua_unregisterAutoAssemblerCommand(L: PLua_State): integer; cdecl;
var command: string;
begin
  result:=0;
  if lua_gettop(L)=1 then
  begin
    command:=Lua_ToString(L, 1);
    UnregisterAutoAssemblerCommand(command);
  end;
end;

function lua_registerSymbolLookupCallback(L: PLua_State): integer; cdecl;
var
  f: integer;
  sltype: TSymbolLookupCallbackPoint;
  routine: string;
  lc: tluacaller;
  i: integer;
begin
  result:=0;

  if lua_gettop(L)=2 then
  begin
    if lua_isnumber(L, 2) then sltype:=TSymbolLookupCallbackPoint(lua_tointeger(L, 2)) else exit;
    if lua_isfunction(L, 1) then
    begin
      lua_pushvalue(L, 1);
      f:=luaL_ref(L,LUA_REGISTRYINDEX);

      lc:=TLuaCaller.create;
      lc.luaroutineIndex:=f;
    end
    else
    if lua_isstring(L,1) then
    begin
      routine:=lua_tostring(L,1);
      lc:=TLuaCaller.create;
      lc.luaroutine:=routine;
    end
    else exit;

    i:=registerSymbolLookupCallback(lc.SymbolLookupCallback, sltype);

    lua_pushinteger(L, lua_integer(i));
    result:=1;
  end;

end;

function lua_unregisterSymbolLookupCallback(L: PLua_State): integer; cdecl;
var id: integer;
begin
  result:=0;
  if lua_gettop(L)>0 then
    unregisterSymbolLookupCallback(lua_tointeger(L, 1));
end;

function lua_registerAddressLookupCallback(L: PLua_State): integer; cdecl;
var
  f: integer;
  routine: string;
  lc: tluacaller;
begin
  result:=0;

  if lua_gettop(L)=1 then
  begin
    if lua_isfunction(L, 1) then
    begin
      lua_pushvalue(L, 1);
      f:=luaL_ref(L,LUA_REGISTRYINDEX);

      lc:=TLuaCaller.create;
      lc.luaroutineIndex:=f;
    end
    else
    if lua_isstring(L,1) then
    begin
      routine:=lua_tostring(L,1);
      lc:=TLuaCaller.create;
      lc.luaroutine:=routine;
    end
    else exit;

    lua_pushinteger(L, registerAddressLookupCallback(lc.AddressLookupCallback));
    result:=1;
  end;

end;

function lua_unregisterAddressLookupCallback(L: PLua_State): integer; cdecl;
begin
  result:=0;
  if lua_gettop(L)>0 then
    unregisterAddressLookupCallback(lua_tointeger(L, 1));
end;

//----
function lua_registerStructureAndElementListCallback(L: PLua_State): integer; cdecl;
var
  f: integer;
  routine: string;
  lc,lc2: tluacaller;
begin
  result:=0;

  if lua_gettop(L)>=2 then
  begin
    if lua_isfunction(L, 1) then
    begin
      lua_pushvalue(L, 1);
      f:=luaL_ref(L,LUA_REGISTRYINDEX);

      lc:=TLuaCaller.create;
      lc.luaroutineIndex:=f;
    end
    else
    if lua_isstring(L,1) then
    begin
      routine:=lua_tostring(L,1);
      lc:=TLuaCaller.create;
      lc.luaroutine:=routine;
    end
    else exit;

    if lua_isfunction(L, 2) then
    begin
      lua_pushvalue(L, 2);
      f:=luaL_ref(L,LUA_REGISTRYINDEX);

      lc2:=TLuaCaller.create;
      lc2.luaroutineIndex:=f;
    end
    else
    if lua_isstring(L,2) then
    begin
      routine:=lua_tostring(L,2);
      lc2:=TLuaCaller.create;
      lc2.luaroutine:=routine;
    end
    else exit;

    lua_pushinteger(L, registerStructureAndElementListCallback(lc.StructureListCallback, lc2.ElementListCallback));
    result:=1;
  end;

end;

function lua_unregisterStructureAndElementListCallback(L: PLua_State): integer; cdecl;
begin
  result:=0;
  if lua_gettop(L)>0 then
    unregisterStructureAndElementListCallback(lua_tointeger(L, 1));
end;
//----

function lua_registerGlobalDisassembleOverride(L: PLua_State): integer; cdecl;
var
  f: integer;
  routine: string;
  lc: tluacaller;
begin
  result:=0;

  if lua_gettop(L)=1 then
  begin
    if lua_isfunction(L, 1) then
    begin
      lua_pushvalue(L, 1);
      f:=luaL_ref(L,LUA_REGISTRYINDEX);

      lc:=TLuaCaller.create;
      lc.luaroutineIndex:=f;
    end
    else
    if lua_isstring(L,1) then
    begin
      routine:=lua_tostring(L,1);
      lc:=TLuaCaller.create;
      lc.luaroutine:=routine;
    end
    else exit;

    lua_pushinteger(L, registerGlobalDisassembleOverride(lc.DisassembleEvent));
    result:=1;
  end;

end;

function lua_unregisterGlobalDisassembleOverride(L: PLua_State): integer; cdecl;
begin
  result:=0;
  if lua_gettop(L)>0 then
    unregisterGlobalDisassembleOverride(lua_tointeger(L, 1));
end;

function lua_registerStructureDissectOverride(L: PLua_State): integer; cdecl;
var
  f: integer;
  routine: string;
  lc: tluacaller;
  m: Tmethod;
begin
  result:=0;

  if lua_gettop(L)=1 then
  begin
    if lua_isfunction(L, 1) then
    begin
      lua_pushvalue(L, 1);
      f:=luaL_ref(L,LUA_REGISTRYINDEX);

      lc:=TLuaCaller.create;
      lc.luaroutineIndex:=f;
    end
    else
    if lua_isstring(L,1) then
    begin
      routine:=lua_tostring(L,1);
      lc:=TLuaCaller.create;
      lc.luaroutine:=routine;
    end
    else exit;

    lua_pushinteger(L, registerStructureDissectOverride(lc.StructureDissectEvent));
    result:=1;
  end;
end;

function lua_unregisterStructureDissectOverride(L: PLua_State): integer; cdecl;
begin
  result:=0;
  if lua_gettop(L)>0 then
    unregisterStructureDissectOverride(lua_tointeger(L, 1));
end;


function lua_registerStructureNameLookup(L: PLua_State): integer; cdecl;
var
  f: integer;
  routine: string;
  lc: tluacaller;
begin
  result:=0;

  if lua_gettop(L)=1 then
  begin
    if lua_isfunction(L, 1) then
    begin
      lua_pushvalue(L, 1);
      f:=luaL_ref(L,LUA_REGISTRYINDEX);

      lc:=TLuaCaller.create;
      lc.luaroutineIndex:=f;
    end
    else
    if lua_isstring(L,1) then
    begin
      routine:=lua_tostring(L,1);
      lc:=TLuaCaller.create;
      lc.luaroutine:=routine;
    end
    else exit;

    lua_pushinteger(L, registerStructureNameLookup(lc.StructureNameLookup));
    result:=1;
  end;
end;

function lua_unregisterStructureNameLookup(L: PLua_State): integer; cdecl;
begin
  result:=0;
  if lua_gettop(L)>0 then
    unregisterStructureNameLookup(lua_tointeger(L, 1));
end;

function lua_registerAssembler(L: PLua_State): integer; cdecl;
var
  f: integer;
  routine: string;
  lc: tluacaller;
begin
  result:=0;

  if lua_gettop(L)=1 then
  begin
    if lua_isfunction(L, 1) then
    begin
      lua_pushvalue(L, 1);
      f:=luaL_ref(L,LUA_REGISTRYINDEX);

      lc:=TLuaCaller.create;
      lc.luaroutineIndex:=f;
    end
    else
    if lua_isstring(L,1) then
    begin
      routine:=lua_tostring(L,1);
      lc:=TLuaCaller.create;
      lc.luaroutine:=routine;
    end
    else exit;

    lua_pushinteger(L, registerAssembler(lc.AssemblerEvent));
    result:=1;
  end;
end;

function lua_unregisterAssembler(L: PLua_State): integer; cdecl;
begin
  result:=0;
  if lua_gettop(L)>0 then
    unregisterAssembler(lua_tointeger(L, 1));
end;


function lua_registerAutoAssemblerPrologue(L: PLua_State): integer; cdecl;
var
  f: integer;
  routine: string;
  lc: tluacaller;
  postaob: boolean;
begin
  result:=0;

  if lua_gettop(L)>=1 then
  begin
    if lua_isfunction(L, 1) then
    begin
      lua_pushvalue(L, 1);
      f:=luaL_ref(L,LUA_REGISTRYINDEX);

      lc:=TLuaCaller.create;
      lc.luaroutineIndex:=f;
    end
    else
    if lua_isstring(L,1) then
    begin
      routine:=lua_tostring(L,-1);
      lc:=TLuaCaller.create;
      lc.luaroutine:=routine;
    end
    else exit;

    if lua_gettop(L)=2 then
      postaob:=lua_toboolean(L,2)
    else
      postaob:=false;

    lua_pushinteger(L, registerAutoAssemblerPrologue(lc.AutoAssemblerPrologueEvent, postaob));
    result:=1;
  end;
end;

function lua_unregisterAutoAssemblerPrologue(L: PLua_State): integer; cdecl;
begin
  result:=0;
  if lua_gettop(L)>0 then
    unregisterAutoAssemblerPrologue(lua_tointeger(L, 1));
end;

function lua_shortCutToText(L: PLua_State): integer; cdecl;
begin
  if lua_gettop(L)>0 then
  begin
    lua_pushstring(L, ShortCutToText(TShortCut(lua_tointeger(L, 1))));
    result:=1;
  end
  else
    result:=0;
end;

function lua_textToShortCut(L: PLua_State): integer; cdecl;
begin
  if lua_gettop(L)>0 then
  begin
    lua_pushinteger(L, TextToShortCut(Lua_ToString(L, 1)));
    result:=1;
  end
  else
    result:=0;
end;

function lua_outputDebugString(L: PLua_State): integer; cdecl;
begin
  if lua_gettop(L)>0 then
    OutputDebugString(pchar(Lua_ToString(L, 1)));

  result:=0;
end;

function getUserRegistryEnvironmentVariable(L: PLua_State): integer; cdecl;
var
  name: string;
  r: Tregistry;
begin
  result:=0;
  if lua_gettop(L)>0 then
  begin
    name:=Lua_ToString(L, 1);

    r:=tregistry.Create;
    try
      r.RootKey:=HKEY_CURRENT_USER;
      if r.OpenKey('\Environment',false) then
      begin
        if r.ValueExists(name) then
        begin
          lua_pushstring(L, r.ReadString(name));
          result:=1;
        end;
      end;
    finally
      r.free;
    end;

  end;
end;

function setUserRegistryEnvironmentVariable(L: PLua_State): integer; cdecl;
var
  name, value: string;
  r: tregistry;
begin
  result:=0;
  if lua_gettop(L)>1 then
  begin
    name:=Lua_ToString(L, 1);
    value:=Lua_ToString(L, 2);

    r:=tregistry.Create;
    try
      r.RootKey:=HKEY_CURRENT_USER;
      if r.OpenKey('\Environment',false) then
        r.WriteString(name, value);
    finally
      r.free;
    end;
  end;
end;

function broadcastEnvironmentUpdate(L: PLua_State): integer; cdecl;
{$if FPC_FULLVERSION<=30002}
var rv: DWORD; //bug in laz 1.6.4 (not the end of the world, as rv is on a 8 byte boundary in the stack and not used)
{$else}
var rv: DWORD_PTR;
{$endif}
begin
  result:=0;

  {$IFDEF windows}
  SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, LPARAM(pchar('Environment')), SMTO_ABORTIFHUNG, 5000, rv);
  {$ENDIF}
end;

{$IFDEF windows}
var winmm: THandle=0;
var PlaySoundA: function (pszSound: LPCSTR; hmod: HModule; fdwSound: DWORD): BOOL; stdcall;
{$ENDIF}

function lua_playSound(L: PLua_State): integer; cdecl;
const
    SND_NODEFAULT = 2;
    SND_MEMORY = 4;
    SND_LOOP = 8;
    SND_NOSTOP = 16;
    SND_SYNC = 0;
    SND_ASYNC = 1;
    SND_PURGE = 64;
    SND_APPLICATION = 128;
var
  o: tobject;
  ms: TMemorystream;
  playparam: dword;
begin
  result:=0;

  {$IFDEF windows}
  if lua_gettop(L)>=1 then
  begin
    if winmm=0 then
      winmm:=LoadLibrary('winmm.dll');

    if (winmm<>0) then
    begin
      if not assigned(PlaySoundA) then
        PlaySoundA:=GetProcAddress(winmm,'PlaySoundA');

      if assigned(PlaySoundA) then
      begin
        if lua_isuserdata(L,1) then
        begin
          o:=lua_ToCEUserData(L, 1);

          if o is TLuafile then
            ms:=TLuaFile(o).stream
          else
          if o is TMemoryStream then
            ms:=TMemoryStream(o)
          else
            raise exception.create(rsPlaySoundTheParameterMustBeATableFileOrAMemoryStream);

          playparam:=SND_MEMORY;
          if (lua_gettop(L)>=2) and lua_toboolean(L,2) then
            playparam:=playparam or SND_SYNC
          else
            playparam:=playparam or SND_ASYNC;

          PlaySoundA(ms.Memory, 0, playparam);
        end;


      end;
    end;
  end;
  {$ENDIF}

end;

function createRef(L: PLua_State): integer; cdecl;
begin
  lua_pushinteger(L, luaL_ref(L, LUA_REGISTRYINDEX));
  result:=1;
end;

function getRef(L: PLua_State): integer; cdecl;
begin
  lua_rawgeti(Luavm, LUA_REGISTRYINDEX, lua_tointeger(L,1));
  result:=1;
end;

function destroyRef(L: PLua_State): integer; cdecl;
begin
  luaL_unref(L, LUA_REGISTRYINDEX, lua_tointeger(L,1));
  result:=0;
end;

function activateProtection(L: PLua_State): integer; cdecl;
begin
  result:=0;
  if lua_gettop(L)=0 then
    protectme
  else
    protectme(lua_tointeger(L,1));
end;

function getLuaEngine(L:PLua_State): integer; cdecl;
begin
  if frmLuaEngine=nil then
    frmLuaEngine:=TfrmLuaEngine.Create(application);

  luaclass_newClass(L, frmLuaEngine);
  result:=1;
end;

function getApplication(L:PLua_State): integer; cdecl;
begin
  luaclass_newClass(L, application);
  result:=1;
end;

function lua_stringToMD5String(L:PLua_State): integer; cdecl;
var msg: pchar;
    size: size_t;
begin
  if lua_gettop(L)=1 then
  begin
    msg:=lua_tolstring(L, 1, @size);
    lua_pushstring(L, MD5Print(MD5Buffer(msg^,size)));
    result:=1;
  end
  else
    result:=0;
end;

function lua_ConvertKeyComboToString(L:PLua_State): integer; cdecl;
var
  keycombo: TKeyCombo;
  keycount: integer;
  i: integer;
begin
  zeromemory(@keycombo, sizeof(keycombo));
  keycount:=min(lua_gettop(L), 5);

  if (keycount=1) and lua_istable(L,1) then
  begin
    for i:=0 to 4 do
    begin
      lua_pushinteger(L, i+1);
      lua_gettable(L, 1);
      if lua_isnil(L, -1) then  //end of the list
      begin
        lua_pop(L,1);
        break;
      end
      else
      begin
        keycombo[i]:=lua_tointeger(L,-1);
        lua_pop(L,1);
      end;
    end;

  end
  else
  begin
    for i:=0 to keycount-1 do
      keycombo[i]:=lua_tointeger(L, i+1);
  end;

  lua_pushstring(L, ConvertKeyComboToString(keycombo));
  result:=1;
end;

function restoreSeDebugPrivilege(L:PLua_State): integer; cdecl;
{$IFDEF windows}
var
  tp: TTokenPrivileges;
  prev: TTokenPrivileges;
  returnlength: dword;
  tokenhandle: thandle;
{$ENDIF}
begin
  result:=0;
  {$IFDEF windows}
  if ownprocesshandle <> 0 then
  begin
    if OpenProcessToken(ownprocesshandle, TOKEN_QUERY or TOKEN_ADJUST_PRIVILEGES, tokenhandle) then
    begin
      ZeroMemory(@tp, sizeof(tp));

      if lookupPrivilegeValue(nil, 'SeDebugPrivilege', tp.Privileges[0].Luid) then
      begin
        tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
        tp.PrivilegeCount := 1; // One privilege to set
        if AdjustTokenPrivileges(tokenhandle, False, tp, sizeof(tp),  prev, returnlength) then
        begin
          lua_pushboolean(L, true);
          result:=1;
        end


      end;

      closehandle(tokenhandle);
    end;

  end;
  {$ENDIF}
end;

function lua_frexp(L:PLua_State): integer; cdecl;
var
  d: float;
  m: float;
  e: integer;
begin
  result:=0;
  if lua_gettop(l)>=1 then
  begin
    d:=lua_tonumber(L, 1);
    Frexp(d, m,e);

    lua_pushnumber(l,m);
    lua_pushnumber(l, e);
    result:=2;
  end
  else
  begin
    lua_pushstring(L, rsNumberRequired);
    lua_error(L);
  end;
end;

function lua_cosh(L:PLua_State): integer; cdecl;
begin
  result:=0;
  if lua_gettop(l)>=1 then
  begin
    lua_pushnumber(L, cosh(lua_tonumber(L,1)));
    result:=1;
  end
  else
  begin
    lua_pushstring(L, rsNumberRequired);
    lua_error(L);
  end;
end;


function lua_sinh(L:PLua_State): integer; cdecl;
begin
  result:=0;
  if lua_gettop(l)>=1 then
  begin
    lua_pushnumber(L, sinh(lua_tonumber(L,1)));
    result:=1;
  end
  else
  begin
    lua_pushstring(L, rsNumberRequired);
    lua_error(L);
  end;
end;

function lua_tanh(L:PLua_State): integer; cdecl;
begin
  result:=0;
  if lua_gettop(l)>=1 then
  begin
    lua_pushnumber(L, tanh(lua_tonumber(L,1)));
    result:=1;
  end
  else
  begin
    lua_pushstring(L, rsNumberRequired);
    lua_error(L);
  end;
end;

function lua_getTranslationFolder(L: PLua_State): integer; cdecl;
begin
  lua_pushstring(L, translationfilepath);
  result:=1;
end;

function lua_loadPOFile(L: PLua_State): integer; cdecl;
var
  POFile: TPOFile;
  filename: string;
  postrings: TStringlist;
begin
  if lua_gettop(L)>=1 then
  begin
    postrings:=Tstringlist.create;
    try
      filename:=Lua_ToString(L, 1);
      postrings.LoadFromFile(filename{$if FPC_FULLVERSION>=030200}, true{$endif});
      if assigned(LRSTranslator) then
      begin
        if (LRSTranslator is TPOTranslator) then
        begin
          pofile:=TPOTranslator(LRSTranslator).POFile;
          pofile.ReadPOText(postrings.text);
        end;
      end;
      lua_pushboolean(L, true);
    except
      lua_pushboolean(L, false);
    end;
    postrings.free;
    result:=1;
  end
  else
    result:=0;
end;

function lua_translateid(L:PLua_state): integer; cdecl;
var
  POFile: TPOFile;
  id, orig: string;
  r: string;
begin
  if lua_gettop(L)>=1 then
  begin
    id:=Lua_ToString(L, 1);

    if lua_gettop(L)>=2 then
      orig:=Lua_ToString(L,2)
    else
      orig:='';

    r:=orig;

    if assigned(LRSTranslator) then
    begin
      if (LRSTranslator is TPOTranslator) then
      begin
        pofile:=TPOTranslator(LRSTranslator).POFile;

        if assigned(pofile) then
          r:=pofile.Translate(id, orig);
      end;
    end;

    lua_pushstring(L, r);
    result:=1;
  end
  else
    result:=0;
end;

function lua_translate(L:PLua_state): integer; cdecl;
var
  s: string;
  POFile: TPOFile;
  r: string;

  z: TStringList;
begin
  if lua_gettop(L)>=1 then
  begin
    r:=Lua_ToString(L, 1);

    if assigned(LRSTranslator) then
    begin
      if (LRSTranslator is TPOTranslator) then
      begin
        pofile:=TPOTranslator(LRSTranslator).POFile;

        if assigned(pofile) then
          r:=pofile.Translate('',r);
      end;
    end;

    lua_pushstring(L, r);
    result:=1;
  end
  else
    result:=1;
end;

function lua_registerBinUtil (L:PLua_state): integer; cdecl;
var
  name, description: string;
  path: string;
  prefix: string;
  ASParam: string;
  LDParam: string;
  OBJDUMPParam: string;
  DisassemblerCommentChar: string;


  bu: TBinUtils;

  miBu: TMenuItem;
  OnDisassemble: integer;
  arch: string;

  i: integer;
begin
  result:=0;
  if (lua_gettop(L)>0) and (lua_istable(L, 1)) then
  begin
    //get the data from the provided table
    lua_pushstring(L, 'Name');
    lua_gettable(L, 1);

    if lua_isnil(L,-1) then
      name:='No name'
    else
      name:=Lua_ToString(L,-1);

    lua_pop(L,1);

    lua_pushstring(L, 'Description');
    lua_gettable(L, 1);

    if lua_isnil(L,-1) then
      description:=''
    else
      description:=Lua_ToString(L,-1);

    lua_pop(L,1);

    lua_pushstring(L, 'Path');
    lua_gettable(L, 1);

    if lua_isnil(L,-1) then
      path:=''
    else
      path:=Lua_ToString(L,-1);

    lua_pop(L,1);

    lua_pushstring(L, 'Prefix');
    lua_gettable(L, 1);

    if lua_isnil(L,-1) then
      prefix:=''
    else
      prefix:=Lua_ToString(L,-1);

    lua_pop(L,1);

    lua_pushstring(L, 'OnDisassemble');
    lua_gettable(L, 1);

    i:=lua_gettop(L);
    if lua_isnil(L,-1) then
    begin
      onDisassemble:=0;
      lua_pop(L,1);
    end
    else
      OnDisassemble:=luaL_ref(L, LUA_REGISTRYINDEX);

    lua_pushstring(L, 'Architecture');
    lua_gettable(L, 1);

    if lua_isnil(L,-1) then
      arch:=''
    else
      arch:=Lua_ToString(L,-1);

    lua_pop(L,1);

    lua_pushstring(L, 'ASParam');
    lua_gettable(L, 1);

    if lua_isnil(L,-1) then
      ASParam:=''
    else
      ASParam:=Lua_ToString(L,-1);

    lua_pop(L,1);

    lua_pushstring(L, 'LDParam');
    lua_gettable(L, 1);

    if lua_isnil(L,-1) then
      LDParam:=''
    else
      LDParam:=Lua_ToString(L,-1);

    lua_pop(L,1);

    lua_pushstring(L, 'OBJDUMPParam');
    lua_gettable(L, 1);

    if lua_isnil(L,-1) then
      OBJDUMPParam:=''
    else
      OBJDUMPParam:=Lua_ToString(L,-1);

    lua_pop(L,1);

    lua_pushstring(L, 'DisassemblerCommentChar');
    lua_gettable(L, 1);

    if lua_isnil(L,-1) then
      DisassemblerCommentChar:=''
    else
      DisassemblerCommentChar:=Lua_ToString(L,-1);

    lua_pop(L,1);




    bu:=TBinUtils.create;

    bu.Name:=name;
    bu.description:=description;
    bu.prefix:=prefix;
    bu.path:=path;
    bu.OnDisassemble:=ondisassemble;
    bu.arch:=Arch;
    bu.ASParam:=ASParam;
    bu.LDParam:=LDParam;
    bu.OBJDUMPParam:=OBJDUMPParam;
    bu.DisassemblerCommentChar:=DisassemblerCommentChar;


    binutilslist.add(bu);

    miBu:=TMenuItem.Create(MemoryBrowser.miBinUtils);
    if bu.description<>'' then
      miBu.caption:=bu.name+' - '+bu.description
    else
      miBu.caption:=bu.name;

    miBu.Tag:=binutilslist.count-1;
    miBu.AutoCheck:=true;
    miBu.RadioItem:=true;
    miBu.OnClick:=MemoryBrowser.miBinutilsSelect.OnClick;

    MemoryBrowser.miBinUtils.Add(miBu);

    if binutilslist.count>0 then //make a menu visible so the user can choose at runtime
    begin
      MemoryBrowser.miBinUtils.visible:=true;
      MemoryBrowser.miGNUAssembler.visible:=true;
    end;
  end;
end;

function setPointerSize(L:PLua_state): integer; cdecl;
begin
  if lua_gettop(L)>=1 then
    processhandler.overridePointerSize(lua_tointeger(L, 1));

  result:=0;
end;


function getDebugContext(L:PLua_state): integer; cdecl;
var extraregs: boolean;
begin
  result:=1;
  if lua_gettop(L)>=1 then
    extraregs:=lua_toboolean(L,1)
  else
    extraregs:=false;

  if (debuggerthread<>nil) and (debuggerthread.isWaitingToContinue) and (debuggerthread.CurrentThread<>nil) then
  begin
    LUA_SetCurrentContextState(debuggerthread.CurrentThread.ThreadId, debuggerthread.CurrentThread.context, extraregs);
    lua_pushboolean(L, true);
  end
  else
    lua_pushboolean(L, false);

end;

function setDebugContext(L:PLua_state): integer; cdecl;
var extraregs: boolean;
begin
  result:=1;
  if lua_gettop(L)>=1 then
    extraregs:=lua_toboolean(L,1)
  else
    extraregs:=false;

  if (debuggerthread<>nil) and (debuggerthread.isWaitingToContinue) and (debuggerthread.CurrentThread<>nil) then
  begin
    LUA_GetNewContextState(debuggerthread.CurrentThread.context, extraregs);
    lua_pushboolean(L, true);
  end
  else
    lua_pushboolean(L, false);
end;

function debug_updateGUI(L:PLua_state): integer; cdecl;
begin
  result:=0;
  if (debuggerthread<>nil) and (debuggerthread.isWaitingToContinue) and (debuggerthread.CurrentThread<>nil) then
  begin
    debuggerthread.CurrentThread.UpdateMemoryBrowserContext;
    MemoryBrowser.UpdateDebugContext(debuggerthread.CurrentThread.handle,debuggerthread.CurrentThread.ThreadID, false);
  end;
end;



function executeMethod(L:PLua_state): integer; cdecl; //executecodeex(callmethod, timeout, address, {instance},{param1},{param2},{param3},{...})
//executeCodeEx(callmethod, timeout, address, {type=x,value=param1} or param1,{type=x,value=param2} or param2,...)

//callmethod:
//0: stdcall
//1: cdecl
//other, not implemented yet
//
//timeout:
//0: don't wait (no return value)
//nil or -1: infinite
//else time in milliseconds
//
//
//paramtypes:
//0: integer/pointer
//1: float
//2: double
//3: asciistring (turns into 0:pointer after writing the string)
//4: widestring
var
  callmethod: integer;
  address: ptruint;
  paramcount: integer;

  i: integer;

  s: tstringlist;
  floatvalues: tstringlist;
  valuetype: integer;

  stackalloc: integer;
  floatvalueallocs: integer;

  instanceValue: ptruint;
  instancereg: integer=1;
  regstr: string;

  stackpointer: integer;

  value: qword;


  f: single;
  floatdword: dword absolute f;
  d: double;
  doubleqword: qword absolute d;
  z: PDwordArray;

  stringsize: integer;
  str: string;
  wstr: widestring;
  stringallocs: array of pointer;
  sai: integer;
  x: ptruint;
  y,wr: dword;

  stubaddress, resultaddress: ptruint;
  allocs: TCEAllocArray;
  exceptionlist: TCEExceptionListArray;

  r: ptruint;
  dontfree: boolean;
  timeout: dword;
  thread:thandle;
begin
  if lua_gettop(L)<4 then
  begin
    lua_pushnil(L);
    lua_pushstring(L,'Not enough parameters. Minimum: callmethod, timeout, address, instance');
    exit(2);
  end;

  paramcount:=lua_gettop(L)-4;


  setlength(stringallocs,0);
  setlength(allocs,0);
  setlength(exceptionlist,0);

  callmethod:=lua_tointeger(L,1);
  if callmethod>=2 then
  begin
    lua_pushnil(L);
    lua_pushstring(L,'Invalid callmethod:'+inttostr(callmethod));
    exit(2);
  end;

  if lua_isnil(L,2) then
    timeout:=INFINITE
  else
    timeout:=lua_tointeger(L,2);

  address:=lua_toaddress(L,3);


  s:=tstringlist.create;
  floatvalues:=tstringlist.create;

  s.Add('allocXO(stub, 4096)');
  if processhandler.is64Bit then
  begin
    floatvalueallocs:=s.add('allocXO(addressToCall, 8)');
    s.add('allocNX(result,8)');
  end
  else
  begin
    floatvalueallocs:=s.add('allocXO(addressToCall, 4)');
    s.add('allocNX(result,4)');
  end;

  s.add('addressToCall:');
  if processhandler.is64Bit then
    s.add('dq '+inttohex(address,8))
  else
    s.add('dd '+inttohex(address,8));


  s.add('stub:');
  if processhandler.is64Bit then
    stackalloc:=s.add('sub rsp,'+inttohex(align(max(4,paramcount)*8,$10)+8,1))
  else
    stackalloc:=s.add('sub esp,'+inttohex(paramcount*4,1));  //save this linenr in case doubles are used


  if lua_isnil(L,4)=false then  //check if instance is nil
  begin
    //instance is provided
    if lua_istable(L,4) then
    begin
      //table
      lua_pushstring(L,'regnr');
      lua_gettable(L,4);
      if lua_isnil(L,-1) then
      begin
        lua_pushinteger(L,1);
        lua_gettable(L,4);
        if not lua_isnil(L,-1) then
          instancereg:=lua_tointeger(L,-1)
        else
          instancereg:=1; //assume the user used a table and left out the instancereg cause he wants ecx/rcx

        lua_pop(L,1);
      end
      else
        instanceReg:=lua_tointeger(L,-1);

      lua_pop(L,1);

      lua_pushstring(L,'classinstance');
      lua_gettable(L,4);
      if lua_isnil(L,-1) then
      begin
        //fu
        lua_pushinteger(L,2);
        lua_gettable(L,4);
        if lua_isnil(L,-1) then
        begin
          lua_pushnil(L);
          lua_pushstring(L,'Invalid instance');
          exit(2);
        end;

        instanceValue:=lua_tointeger(L,-1);
        lua_pop(L,1);
      end
      else
        instanceValue:=lua_tointeger(L,-1);

      lua_pop(L,1);

    end
    else
    begin
      instanceValue:=lua_tointeger(L,4);
      instanceReg:=1; //ECX/RCX
    end;

    case instancereg of
      0: regstr:='rax';
      1: regstr:='rcx';
      2: regstr:='rdx';
      3: regstr:='rbx';
      4: regstr:='rsp';
      5: regstr:='rbp';
      6: regstr:='rsi';
      7: regstr:='rdi';
      8: regstr:='r8';
      9: regstr:='r9';
      10: regstr:='r10';
      11: regstr:='r11';
      12: regstr:='r12';
      13: regstr:='r13';
      14: regstr:='r14';
      15: regstr:='r15';
    end;

    if processhandler.is64Bit=false then
    begin
      if instancereg>=8 then raise exception.create('Invalid instance register');
      regstr[1]:='e';
    end;
    s.add('mov '+regstr+','+inttohex(instanceValue,8));

  end;


  try

    //setup the parameters:
    stackpointer:=0;
    for i:=5 to lua_gettop(L) do
    begin
      valuetype:=0;
      if lua_istable(l,i) then
      begin
        lua_pushstring(L,'type');
        lua_gettable(L,i);
        if lua_isnil(L,-1) then
        begin
          lua_pop(L,1);
          lua_pushinteger(L,1);
          lua_gettable(L,i);
          if lua_isnil(L,-1) then
          begin
            lua_pushnil(L);
            lua_pushstring(L,'Invalid parametertype '+inttostr(i+3));
            exit(2);
          end;
        end;
        valuetype:=lua_tointeger(L,-1);
        lua_pop(L,1);

        lua_pushstring(L,'value');
        lua_gettable(L,i);
        if lua_isnil(L,-1) then
        begin
          lua_pop(L,1);
          lua_pushinteger(L,2);
          lua_gettable(L,i);
          if lua_isnil(L,-1) then
          begin
            lua_pushnil(L);
            lua_pushstring(L,'Invalid parametervalue '+inttostr(i+3));
            exit(2);
          end;
        end;
      end
      else
      begin
        //no specific type is given, guess it based on the parameters (damn those lazy ass users)
        if lua_type(L,i)=LUA_TSTRING then
          valuetype:=3
        else
        begin
          if lua_isnumber(L,i) then
          begin
            if lua_isinteger(L,i) then
              valuetype:=0 //integer/pointer
            else
              valuetype:=1; //float (if you want double then give a proper typespecficiation and FU)
          end
          else
          begin
            lua_pushnil(L);
            lua_pushstring(L,'No idea how to handle the type you provided for parameter '+inttostr(i));
            exit(2);
          end;
        end;
        lua_pushvalue(L,i);  //-1 now contains the value
      end;

      case valuetype of
        0,3,4:
        begin
          if valuetype in [3..4] then
          begin
            sai:=length(stringallocs);
            setlength(stringallocs, sai+1);

            if valuetype=3 then
            begin
              //ascii
              str:=Lua_ToString(L,-1);
              stringallocs[sai]:=virtualallocex(processhandle,nil,length(str)+1,MEM_COMMIT or MEM_RESERVE,PAGE_READWRITE);
              WriteProcessMemory(processhandle, stringallocs[sai],@str[1],length(str)+1,x);
            end
            else
            begin
              //widestring
              wstr:=Lua_ToString(L,-1);
              stringallocs[sai]:=virtualallocex(processhandle,nil,length(wstr)+2,MEM_COMMIT or MEM_RESERVE,PAGE_READWRITE);
              WriteProcessMemory(processhandle, stringallocs[sai],@wstr[1],length(wstr)+2,x);
            end;
            value:=ptruint(stringallocs[sai]);
          end
          else
            value:=lua_tointeger(L,-1);

          if processhandler.is64Bit then
          begin
            case stackpointer of
              0: s.add('mov rcx,'+inttohex(value,8));
              1: s.add('mov rdx,'+inttohex(value,8));
              2: s.add('mov r8,'+inttohex(value,8));
              3: s.add('mov r9,'+inttohex(value,8));
              else
              begin
                s.add('mov rax,'+inttohex(lua_tointeger(L,-1),8));
                s.add('mov qword ptr [rsp+'+inttohex(stackpointer*8,8)+'],rax');
              end;
            end;
          end
          else
          begin
            s.add('mov dword ptr [esp+'+inttohex(stackpointer*4,1)+'],'+inttohex(value,8));
          end;
          inc(stackpointer);
        end;

        1: //float(single)
        begin
          f:=lua_tonumber(L,-1);
          if processhandler.is64Bit then
          begin
            floatvalues.Add('floatvalue'+inttostr(stackpointer)+':');
            floatvalues.add('dd '+inttohex(floatdword,8));
            if stackpointer<4 then
            begin
              s.add('movss xmm'+inttostr(stackpointer)+',[floatvalue'+inttostr(stackpointer)+']')
            end
            else
            begin
              s.add('mov eax,[floatvalue'+inttostr(stackpointer)+']');
              s.add('mov qword ptr [rsp+'+inttohex(stackpointer*8,8)+'],rax');
            end;
          end
          else
            s.add('mov dword ptr [esp+'+inttohex(stackpointer*4,1)+'],'+inttohex(floatdword,8));

          inc(stackpointer);
        end;

        2: //double
        begin
          d:=lua_tonumber(L,-1);
          if processhandler.is64Bit then
          begin
            floatvalues.Add('floatvalue'+inttostr(stackpointer)+':');
            floatvalues.add('dq '+inttohex(doubleqword,16));

            if stackpointer<4 then
              s.add('movsd xmm'+inttostr(stackpointer)+',[floatvalue'+inttostr(stackpointer)+']')
            else
            begin
              s.add('mov rax,[floatvalue'+inttostr(stackpointer)+']');
              s.add('mov qword ptr [rsp+'+inttohex(stackpointer*8,8)+'],rax');
            end;
          end
          else
          begin
            z:=@doubleqword;
            s.add('mov dword ptr [esp+'+inttohex(stackpointer*4,1)+'],'+inttohex(z[0],8));
            inc(stackpointer);
            s.add('mov dword ptr [esp+'+inttohex(stackpointer*4,1)+'],'+inttohex(z[0],8));
          end;
          inc(stackpointer);
        end;

        else
        begin
          lua_pushnil(L);
          lua_pushstring(L,'Invalid parametertype '+inttostr(i+3)+'('+inttostr(valuetype)+')');
          exit(2);
        end;
      end;

      lua_pop(L,1);
    end;

    if processhandler.is64Bit=false then //fix the stackfor the caller
      s[stackalloc]:='sub esp,'+inttohex(stackpointer*4,1);

    s.add('call [addressToCall]');
    if processhandler.is64Bit then
    begin
      s.add('mov [result],rax');
      s.add('add rsp,'+inttohex(align(max(4,paramcount)*8,$10)+8,1));
      s.add('ret');
    end
    else
    begin
      s.add('mov [result],eax');

      if callmethod=1 then
        s.add('add esp,'+inttohex(stackpointer*4,1));

      s.add('ret 4');
    end;

    if floatvalues.count>0 then
      s.add('align 10,0');

    for i:=0 to floatvalues.count-1 do
      s.add(floatvalues[i]);


    dontfree:=false;

    if autoassemble(s,false,true,false,false,allocs,exceptionlist) then
    begin
      for i:=0 to length(allocs)-1 do
      begin
        if allocs[i].varname='stub' then
          stubaddress:=allocs[i].address;

        if allocs[i].varname='result' then
          resultaddress:=allocs[i].address;
      end;

      {
      lua_pop(L,lua_gettop(L));
      lua_pushstring(L,pchar('stub at '+inttohex(stubaddress,8)));
      print(L);
      dontfree:=true;
      exit(0);
                  }


      thread:=CreateRemoteThread(processhandle, nil, 0, pointer(stubaddress), nil, 0, y);

      if (thread<>0) then
      begin
        dontfree:=timeout=0;


        {$ifdef darwin}
        if macWaitForRemoteThread(thread,timeout) then
          wr:=WAIT_OBJECT_0
        else
          wr:=WAIT_TIMEOUT;
        {$endif}
        {$ifdef windows}
        wr:=WaitForSingleObject(thread, timeout);
        {$endif}
        if wr=WAIT_OBJECT_0 then
        begin
          if ReadProcessMemory(processhandle, pointer(resultaddress), @r, sizeof(r), x) then
          begin
            lua_pushinteger(L, r);
            exit(1);
          end
          else
          begin
            lua_pushnil(L);
            lua_pushstring(L,'Failure reading the result address');
            exit(2);
          end;
        end
        else
        if wr=WAIT_TIMEOUT then
        begin
          dontfree:=true;
          lua_pushnil(L);
          lua_pushstring(L,'Execution timeout');
          exit(2);
        end
        else
        begin
          lua_pushnil(L);
          lua_pushstring(L,'Wait failure');
          exit(2);
        end;


        closehandle(thread);
      end
      else
      begin
        lua_pushnil(L);
        lua_pushstring(L,'Failure launching thread');
        exit(2);
      end;
    end;
  finally
    s.free;

    if (dontfree=false) then
    begin
      if stubaddress<>0 then VirtualFreeEx(processhandle, pointer(stubaddress), 0, MEM_RELEASE);
      if resultaddress<>0 then VirtualFreeEx(processhandle, pointer(resultaddress), 0, MEM_RELEASE);
      for i:=0 to length(stringallocs)-1 do
        VirtualFreeEx(processhandle, pointer(stringallocs[i]), 0, MEM_RELEASE);
    end;


    //free allocated strings

  end;

end;

function executeCodeEx(L:PLua_state): integer; cdecl;  //executecodeex(callmethod, timeout, address, {param1},{param2},{param3},{...})
var
  paramcount: integer;
  i: integer;
begin
  //convert to
  //executeMethod(callmethod, timeout, address, nil, param1, param2, param3, ...

  paramcount:=lua_gettop(L);
  if paramcount<3 then
  begin
    lua_pushnil(L);
    lua_pushstring(L,'Not enough parameters. Minimum: callmethod, timeout, address');
    exit(2);
  end;

  lua_pushnil(L);
  lua_insert(L, 4); //instance=nil
  exit(executeMethod(L));
end;

function executeCode(L:PLua_state): integer; cdecl; //executecode(address, parameter)
var
  s: tstringlist;
  allocs: TCEAllocArray;
  exceptionlist: TCEExceptionListArray;
  address: ptruint;
  i: integer;
  stubaddress: ptruint;
  resultaddress: ptruint;

  parameter: ptruint;
  timeout: dword;

  thread: thandle;

  r: ptruint;
  x: dword;
  y: ptruint;

  wr: DWORD;
  dontfree: boolean;
begin
  //creates a thread in the target process.  calls stdcall function(parameter):pointer and wait for it's return
  stubaddress:=0;
  result:=0;
  dontfree:=false;

  if lua_gettop(L)>=1 then
  begin
    if lua_isnil(L,1) then exit(0);
    address:=lua_toaddress(L,1);

    if lua_gettop(L)>=2 then
    begin
      if lua_isnumber(L,2) then
        parameter:=lua_tointeger(L, 2)
      else
        parameter:=symhandler.getAddressFromName(Lua_ToString(L,2), waitforsymbols);
    end
    else
      parameter:=0;

    if lua_gettop(L)>=3 then
      timeout:=lua_tointeger(L,3)
    else
      timeout:=INFINITE;
  end
  else
    exit;

  s:=tstringlist.create;
  try
    s.Add('allocXO(stub, 2048)');

    if processhandler.is64Bit then
    begin
      s.add('allocXO(addressToCall, 8)');
      s.add('allocNX(result,8)');
    end
    else
      s.add('allocNX(result,4)');


    s.add('stub:');
    if processhandler.is64Bit then
    begin
      s.add('sub rsp,28');
      s.add('call [addressToCall]');
      s.add('mov [result],rax');
      s.add('add rsp,28');
      s.add('ret');
    end
    else
    begin
      s.add('push [esp+4]');  //push the parameter again
      s.add('call '+inttohex(address,8));
      s.add('mov [result],eax');
      s.add('ret 4');
    end;

    if processhandler.is64Bit then
    begin
      s.add('addressToCall:');
      s.add('dq '+inttohex(address,8));
    end;

    if autoassemble(s, false, true, false, false, allocs, exceptionlist) then
    begin

      for i:=0 to length(allocs)-1 do
      begin
        if allocs[i].varname='stub' then
          stubaddress:=allocs[i].address;

        if allocs[i].varname='result' then
          resultaddress:=allocs[i].address;
      end;

      if stubaddress<>0 then
      begin
        thread:=CreateRemoteThread(processhandle, nil, 0, pointer(stubaddress), pointer(parameter), 0, x);

        if (thread<>0) then
        begin
          {$ifdef darwin}
          if macWaitForRemoteThread(thread,timeout) then
            wr:=WAIT_OBJECT_0
          else
            wr:=WAIT_TIMEOUT;
          {$endif}
          {$ifdef windows}
          wr:=WaitForSingleObject(thread, timeout);
          {$endif}
          if wr=WAIT_OBJECT_0 then
          begin
            if ReadProcessMemory(processhandle, pointer(resultaddress), @r, sizeof(r), y) then
            begin
              lua_pushinteger(L, r);
              result:=1;
            end
            else
            begin
              lua_pushnil(L);
              lua_pushstring(L,'Failure reading the result address');
              exit(2);
            end;
          end
          else
          if wr=WAIT_TIMEOUT then
          begin
            dontfree:=true;
            lua_pushnil(L);
            lua_pushstring(L,'Execution timeout');
            exit(2);
          end
          else
          begin
            lua_pushnil(L);
            lua_pushstring(L,'Wait failure');
            exit(2);
          end;


          closehandle(thread);
        end
        else
        begin
          lua_pushnil(L);
          lua_pushstring(L,'Failure launching thread');
          exit(2);
        end;
      end;
    end;

  finally
    s.free;

    if (dontfree=false) and (stubaddress<>0) then
      VirtualFreeEx(processhandle, pointer(stubaddress), 0, MEM_RELEASE);

    if (dontfree=false) and (resultaddress<>0) then
      VirtualFreeEx(processhandle, pointer(resultaddress), 0, MEM_RELEASE);
  end;
end;


function test(x: integer): qword;
begin
  result:=x+12;
end;



function executeCodeLocalEx(L:PLua_state): integer; cdecl; //address,{param},{param},{param}
//paramtypes:
//0: integer/pointer
//1: float
//2: double
//3: asciistring (turns into 0:pointer after writing the string)
//4: widestring

label
 p1typeisint, p1typeisfloat, afterp1,
 p2typeisint, p2typeisfloat, afterp2,
 p3typeisint, p3typeisfloat, afterp3,
 p4typeisint, p4typeisfloat, afterp4;
var
  //callstack: pointer;
  oldstack: pointer;
  callstack: array of byte; //stoprage to hold the parameters pushed on the stack (gets copied when needed)
  p1type: byte;
  p2type: byte;
  p3type: byte;
  p4type: byte;

  valuetype: integer;

  AddressToCall: pointer;
  paramcount: integer;
  paramsize: qword;

  paramstart,paramstart2: pointer;

  r: qword;
  i: integer;

  s: string;
  ws: widestring;

  ts: array of string;
  tws: array of widestring;




begin
  {$ifdef cpu64}
  //allocate a stack for this call and fill in the parameters
  //setup the parameters at callstack $fff0-parametersize
  //getmem(callstack, 65536);

  setlength(ts,0);
  setlength(tws,0);

  if lua_gettop(L)>=1 then
  begin
    AddressToCall:=pointer(lua_toaddress(L,1,true));
    paramcount:=lua_gettop(L)-1;


    paramsize:=max(32,8*paramcount);
    setlength(callstack,paramsize);
    paramstart:=@callstack[0];

    if paramcount>0 then
    begin
      setlength(ts,paramcount);
      setlength(tws,paramcount);

      for i:=2 to 2+paramcount-1 do  //
      begin
        if lua_istable(L,i) then
        begin
          lua_pushstring(L,'type');
          lua_gettable(L,i);
          if lua_isnil(L,-1) then
          begin
            lua_pop(L,1);
            lua_pushinteger(L,1);
            lua_gettable(L,i);
            if lua_isnil(L,-1) then
            begin
              lua_pushnil(L);
              lua_pushstring(L,'Invalid parametertype '+inttostr(i));
              exit(2);
            end;
          end;
          valuetype:=lua_tointeger(L,-1);
          lua_pop(L,1);

          lua_pushstring(L,'value');
          lua_gettable(L,i);
          if lua_isnil(L,-1) then
          begin
            lua_pop(L,1);
            lua_pushinteger(L,2);
            lua_gettable(L,i);
            if lua_isnil(L,-1) then
            begin
              lua_pushnil(L);
              lua_pushstring(L,'Invalid parametervalue '+inttostr(i));
              exit(2);
            end;
          end;
        end
        else
        begin
          //no typedefinition
          if lua_type(L,i)=LUA_TSTRING then
            valuetype:=3
          else
          begin
            if lua_isnumber(L,i) then
            begin
              if lua_isinteger(L,i) then
                valuetype:=0 //integer/pointer
              else
                valuetype:=1; //float (if you want double then give a proper typespecficiation and FU)
            end
            else
            begin
              lua_pushnil(L);
              lua_pushstring(L,'No idea how to handle the type you provided for parameter '+inttostr(i));
              exit(2);
            end;
          end;
          lua_pushvalue(L,i);  //-1 now contains the value

        end;

        case valuetype of
          0: pqword(ptruint(paramstart)+(i-2)*sizeof(pointer))^:=lua_tointeger(L,-1);
          1: psingle(ptruint(paramstart)+(i-2)*sizeof(pointer))^:=lua_tonumber(L,-1);
          2: pdouble(ptruint(paramstart)+(i-2)*sizeof(pointer))^:=lua_tonumber(L,-1);
          3:
          begin
            ts[i-2]:=Lua_ToString(L,-1);
            pqword(ptruint(paramstart)+(i-2)*sizeof(pointer))^:=ptruint(pchar(ts[i-2]));
            valuetype:=0;
          end;

          4:
          begin
            tws[i-2]:=Lua_ToString(L,-1);
            pqword(ptruint(paramstart)+(i-2)*sizeof(pointer))^:=ptruint(pwidechar(tws[i-2]));
            valuetype:=0;
          end;
        end;

        case i-1 of
          1: p1type:=valuetype;
          2: p2type:=valuetype;
          3: p3type:=valuetype;
          4: p4type:=valuetype;
        end;

        lua_pop(L,1);

      end;


      asm
        //parameters are accessed by use of RBP which is unaffected by this code
        mov oldstack,rsp

        sub rsp,paramsize
        and rsp,$fffffffffffffff0   //align just in case it was an unaligned paramcount

        mov paramstart2,rsp

        push rsi
        push rdi
        push rcx
        mov rsi,paramstart
        mov rdi,paramstart2
        mov rcx,paramsize
        rep movsb

        pop rcx
        pop rdi
        pop rsi

        cmp paramcount,1
        jb afterp4
//p1:
        cmp p1type,0
        je p1typeisint

        cmp p1type,1
        je p1typeisfloat

        movsd xmm0,[rsp]
        jmp afterp1

p1typeisint:
        mov rcx,[rsp]
        jmp afterp1

p1typeisfloat:
        movss xmm0,[rsp]

afterp1:
//p2:
        cmp paramcount,2
        jb afterp4

        cmp [p2type],0
        je p2typeisint

        cmp [p2type],1
        je p2typeisfloat

        movsd xmm1,[rsp+8]
        jmp afterp2

p2typeisint:
        mov rdx,[rsp+8]
        jmp afterp2

p2typeisfloat:
        movss xmm1,[rsp+8]

afterp2:

//p3
        cmp paramcount,3
        jb afterp4

        cmp [p3type],0
        je p3typeisint

        cmp [p3type],1
        je p3typeisfloat

        movsd xmm2,[rsp+$10]
        jmp afterp3

p3typeisint:
        mov r8,[rsp+$10]
        jmp afterp3

p3typeisfloat:
        movss xmm2,[rsp+$10]

afterp3:

//p4
        cmp paramcount,4
        jb afterp4

        cmp [p4type],0
        je p4typeisint

        cmp [p4type],1
        je p4typeisfloat

        movsd xmm3,[rsp+$18]
        jmp afterp4

p4typeisint:
        mov r9,[rsp+$18]
        jmp afterp4

p4typeisfloat:
        movss xmm3,[rsp+$18]

afterp4:


        call AddressToCall

        mov r,rax
        mov rsp,oldstack
      end;

      lua_pushinteger(L,r);
      exit(1);
    end;
  end
  else exit(0);




  {$else}
  lua_pushstring(L,'executeCodeLocalEx is currently not supported on the 32-bit build');
  lua_error(L);
  {$endif}


end;


function executeCodeLocal(L:PLua_state): integer; cdecl;
type
  TFunction=function(parameter: pointer):pointer; stdcall;
var
  address, parameter: PtrUInt;
  f: TFunction;
begin
  //executes the given address
  result:=0;
  if lua_gettop(L)>=1 then
  begin
    address:=lua_toaddress(L,1,true);


    if lua_gettop(L)>=2 then
    begin
      if lua_isstring(L,2) then
        parameter:=selfsymhandler.getAddressFromName(Lua_ToString(L,2), waitforsymbols)
      else
        parameter:=lua_tointeger(L, 2)

    end
    else
      parameter:=0;

    f:=pointer(address);
    lua_pushinteger(L, ptruint(f(pointer(parameter))));
    result:=1;
  end
  else
    exit;
end;

function md5file(L:PLua_state): integer; cdecl;
var
  filename: string;
  f: TMemoryStream;
begin
  result:=0;
  if lua_gettop(L)>=1 then
  begin
    filename:=Lua_ToString(L,1);

    f:=TMemoryStream.create;
    try
      f.LoadFromFile(filename);
      lua_pushstring(L, MD5Print(MD5Buffer(f.Memory^, f.Size)));
      result:=1;
    finally
      f.free;
    end;
  end;
end;

function md5memory(L:PLua_state): integer; cdecl;
var
  startaddress: ptruint;
  size: integer;

  buf: PByteArray;
  x: ptruint;
begin
  result:=0;
  if lua_gettop(L)>=2 then
  begin
    startaddress:=lua_toaddress(L,1);

    size:=lua_tointeger(L, 2);

    if size>0 then
    begin
      getmem(buf, size);
      if ReadProcessMemory(processhandle, pointer(startaddress), buf, size, x) then
      begin
        if x>0 then
        begin
          lua_pushstring(L, MD5Print(MD5Buffer(buf^, x)));
          result:=1;
        end;
      end;
      FreeMemAndNil(buf);
    end;

  end;

end;


function allocateKernelMemory(L:PLua_state): integer; cdecl;
begin
  result:=0;
  {$IFDEF windows}
  if lua_gettop(L)=1 then
  begin
    lua_pushinteger(L, ptruint(KernelAlloc(lua_tointeger(L,1))));
    result:=1;
  end;
  {$ENDIF}
end;

function freeKernelMemory(L:PLua_state): integer; cdecl;
begin
  {$IFDEF windows}
  if lua_gettop(L)=1 then
    KernelFree(lua_tointeger(L,1));
  {$ENDIF}

  result:=0; //you'll know it worked by not having a BSOD
end;

function lua_mapMemory(L:PLua_state): integer; cdecl;
var
  address: uint64;
  size: dword;
  frompid, topid: dword;

  mmr: TMapMemoryResult;
begin
  result:=0;
  {$IFDEF windows}
  frompid:=0;
  topid:=0;

  if lua_gettop(L)>=2 then
  begin
    address:=lua_toaddress(L,1);
    size:=lua_tointeger(L,2);
  end
  else
    exit(0);

  if lua_gettop(L)>=3 then
    frompid:=lua_tointeger(L,3);

  if lua_gettop(L)>=4 then
    topid:=lua_tointeger(L,4);

  mmr:=MapMemory(address, size, frompid, topid);

  lua_pushinteger(L, mmr.address);
  lua_pushinteger(L, mmr.mdladdress);
  result:=2;
  {$ENDIF}
end;

function lua_unmapMemory(L:PLua_state): integer; cdecl;
var
  mmr: TMapMemoryResult;
begin
  result:=0;
  {$IFDEF windows}
  if lua_gettop(l)>=2 then
  begin
    mmr.address:=lua_toaddress(L, 1);
    mmr.mdladdress:=lua_toaddress(L, 2);
    UnmapMemory(mmr);
  end;
  {$ENDIF}
end;

function lua_lockMemory(L:PLua_state): integer; cdecl;
var
  address: qword;
  size: integer;
  mdl: qword;
begin
  result:=0;
  {$IFDEF windows}
  if lua_gettop(L)>=2 then
  begin
    address:=lua_tointeger(L,1);
    size:=lua_tointeger(L,2);

    mdl:=DBK32functions.LockMemory(processid, address, size);
    lua_pushinteger(L,mdl);
    result:=1;
  end;
  {$ENDIF}
end;

function lua_unlockMemory(L:PLua_state): integer; cdecl;
var
  mdl: qword;
begin
  result:=0;
  {$IFDEF windows}
  if lua_gettop(L)>=1 then
  begin
    mdl:=lua_tointeger(L,1);
    DBK32functions.unLockMemory(mdl);
  end;
  {$ENDIF}
end;

function lua_sendMessage(L:PLua_state): integer; cdecl;
var h: HWND;
    Msg:  UINT;
    wp: WPARAM;
    lp: LPARAM;
begin
  result:=0;
  if lua_gettop(L)=4 then
  begin
    h:=lua_tointeger(L,1);
    msg:=lua_tointeger(L,2);
    wp:=lua_tointeger(L,3);
    lp:=lua_tointeger(L,4);

    lua_pushinteger(L, SendMessage(h, Msg, wp, lp));
    result:=1;
  end;
end;

function lua_sendMessageTimeout(L:PLua_state): integer; cdecl;
var h: HWND;
    Msg:  UINT;
    wp: WPARAM;
    lp: LPARAM;
    flags, timeout: uint;
    r: DWORD_PTR;
begin
  result:=0;
  {$IFDEF windows}
  if lua_gettop(L)=4 then
  begin
    h:=lua_tointeger(L,1);
    msg:=lua_tointeger(L,2);
    wp:=lua_tointeger(L,3);
    lp:=lua_tointeger(L,4);
    flags:=lua_tointeger(L,5);
    timeout:=lua_tointeger(L,6);

    if SendMessageTimeoutA(h, Msg, wp, lp, flags,timeout, r)<>0 then
      lua_pushinteger(L,r)
    else
      lua_pushnil(L);

    result:=1;
  end;
  {$ENDIF}
end;

function lua_findWindow(L:PLua_state): integer; cdecl;
var
  classname, windowname: pchar;
begin
  result:=0;
  {$IFDEF windows}
  classname:=nil;
  windowname:=nil;

  if lua_gettop(L)>=1 then
    classname:=lua.lua_tostring(L,1);

  if lua_gettop(L)>=2 then
    windowname:=lua.Lua_ToString(L, 2);

  lua_pushinteger(L, FindWindow(classname, windowname));
  result:=1;
  {$ENDIF}
end;

function lua_getWindow(L:PLua_state): integer; cdecl;
var
  h: hwnd;
  cmd: uint;
begin
  result:=0;
  {$IFDEF windows}
  if lua_gettop(L)>=2 then
  begin
    h:=lua_tointeger(L, 1);
    cmd:=lua_tointeger(L, 2);

    lua_pushinteger(L, GetWindow(h, cmd));
    result:=1;
  end;
  {$ENDIF}
end;

function lua_getWindowProcessID(L:PLua_state): integer; cdecl;
var
  h: hwnd;
  pid: DWORD;
  tid: dword;
begin
  result:=0;
  {$IFDEF windows}
  if lua_gettop(L)>=1 then
  begin
    pid:=0;
    tid:=0;

    h:=lua_tointeger(L,1);

    tid:=GetWindowThreadProcessId(h, pid);

    lua_pushinteger(L, pid);
    lua_pushinteger(L, tid);
    result:=2;

  end;
  {$ENDIF}
end;

function lua_getWindowCaption(L:PLua_state): integer; cdecl;
var
  h: hwnd;
  s: pchar;
  i: integer;
begin
  result:=0;
  {$IFDEF windows}
  if lua_gettop(L)=1 then
  begin
    h:=lua_tointeger(L, 1);
    getmem(s,256);
    try
      i:=GetWindowText(h, s, 255);
      s[i]:=#0;
      lua_pushstring(L,s);
      result:=1;
    finally
      FreeMemAndNil(s);
    end;
  end;
  {$ENDIF}
end;

function lua_getWindowClassName(L:PLua_state): integer; cdecl;
var
  h: hwnd;
  s: pchar;
  i: integer;
begin
  result:=0;
  {$IFDEF windows}
  if lua_gettop(L)=1 then
  begin
    h:=lua_tointeger(L, 1);

    getmem(s,256);
    try
      i:=GetClassNameA(h, s, 255);
      s[i]:=#0;
      lua_pushstring(L,s);
      result:=1;
    finally
      FreeMemAndNil(s);
    end;
  end;
  {$ENDIF}
end;

function lua_getForegroundWindow(L:PLua_state): integer; cdecl;
begin
  result:=1;
  lua_pushinteger(L, GetForegroundWindow());
end;

function getXBox360ControllerKeyPress(L:PLua_state): integer; cdecl;
{$IFDEF windows}
var
  i: integer;
  index: integer;
  ks: XINPUT_KEYSTROKE;
  state: XINPUT_STATE;
{$ENDIF}
begin

  result:=0;

  {$IFDEF windows}
  XInputMessages(false); //you don't want to use gui support for hotkeys, but handle it yourself


  index:=-1;
  if InitXinput=false then exit;
  if not assigned(XInputGetKeystroke) then exit;

  if lua_gettop(L)>=1 then
  begin
    index:=lua_tointeger(L, 1);
    if XInputGetKeystroke(index, 0, @ks)<>0 then exit;
  end
  else
  begin
    for i:=0 to XUSER_MAX_COUNT-1 do
    begin
      if (XInputGetState(i, state)=0) and (XInputGetKeystroke(i, 0, @ks)=0) then //found a controller  (usually 0)
      begin
        index:=i;
        break;
      end;
    end;
  end;

  if index<>-1 then
  begin
    lua_newtable(L);
    i:=lua_gettop(L);

    lua_setbasictableentry(L, i, 'VirtualKey', ks.VirtualKey);
    lua_setbasictableentry(L, i, 'Unicode', ks.Unicode);
    lua_setbasictableentry(L, i, 'Flags', ks.Flags);
    lua_setbasictableentry(L, i, 'UserIndex', ks.UserIndex);
    lua_setbasictableentry(L, i, 'HidCode', ks.HidCode);
    result:=1;
  end;
  {$ENDIF}

end;

function getXBox360ControllerState(L:PLua_state): integer; cdecl;
{$IFDEF windows}
var
  index: integer;
  i: integer;
  state: XINPUT_STATE;
{$ENDIF}
begin
  result:=0;
  {$IFDEF windows}

  index:=-1;
  if InitXinput=false then exit;

  if lua_gettop(L)>=1 then
  begin
    index:=lua_tointeger(L, 1);
    if XInputGetState(index, state)<>0 then exit;
  end
  else
  begin
    for i:=0 to XUSER_MAX_COUNT-1 do
    begin
      if XInputGetState(i, state)=0 then //found a controller  (usually 0)
      begin
        index:=i;
        break;
      end;
    end;
  end;

  if index<>-1 then
  begin
    //state is now filled in, convert it to a readable table
    lua_newtable(L);
    i:=lua_gettop(L);

    lua_setbasictableentry(L, i, 'ControllerID', index);
    lua_setbasictableentry(L, i, 'PacketNumber', state.dwPacketNumber);
    lua_setbasictableentry(L, i, 'GAMEPAD_DPAD_UP', (state.Gamepad.wButtons and XINPUT_GAMEPAD_DPAD_UP)<>0);
    lua_setbasictableentry(L, i, 'GAMEPAD_DPAD_DOWN', (state.Gamepad.wButtons and XINPUT_GAMEPAD_DPAD_DOWN)<>0);
    lua_setbasictableentry(L, i, 'GAMEPAD_DPAD_LEFT', (state.Gamepad.wButtons and XINPUT_GAMEPAD_DPAD_LEFT)<>0);
    lua_setbasictableentry(L, i, 'GAMEPAD_DPAD_RIGHT', (state.Gamepad.wButtons and XINPUT_GAMEPAD_DPAD_RIGHT)<>0);

    lua_setbasictableentry(L, i, 'GAMEPAD_START', (state.Gamepad.wButtons and XINPUT_GAMEPAD_START)<>0);
    lua_setbasictableentry(L, i, 'GAMEPAD_BACK', (state.Gamepad.wButtons and XINPUT_GAMEPAD_BACK)<>0);

    lua_setbasictableentry(L, i, 'GAMEPAD_LEFT_THUMB', (state.Gamepad.wButtons and XINPUT_GAMEPAD_LEFT_THUMB)<>0);
    lua_setbasictableentry(L, i, 'GAMEPAD_RIGHT_THUMB', (state.Gamepad.wButtons and XINPUT_GAMEPAD_RIGHT_THUMB)<>0);

    lua_setbasictableentry(L, i, 'GAMEPAD_LEFT_SHOULDER', (state.Gamepad.wButtons and XINPUT_GAMEPAD_LEFT_SHOULDER)<>0);
    lua_setbasictableentry(L, i, 'GAMEPAD_RIGHT_SHOULDER', (state.Gamepad.wButtons and XINPUT_GAMEPAD_RIGHT_SHOULDER)<>0);

    lua_setbasictableentry(L, i, 'GAMEPAD_A', (state.Gamepad.wButtons and XINPUT_GAMEPAD_A)<>0);
    lua_setbasictableentry(L, i, 'GAMEPAD_B', (state.Gamepad.wButtons and XINPUT_GAMEPAD_B)<>0);
    lua_setbasictableentry(L, i, 'GAMEPAD_X', (state.Gamepad.wButtons and XINPUT_GAMEPAD_X)<>0);
    lua_setbasictableentry(L, i, 'GAMEPAD_Y', (state.Gamepad.wButtons and XINPUT_GAMEPAD_Y)<>0);

    lua_setbasictableentry(L, i, 'wButtons', state.Gamepad.wButtons);

    lua_setbasictableentry(L, i, 'LeftTrigger', state.Gamepad.bLeftTrigger);
    lua_setbasictableentry(L, i, 'RightTrigger', state.Gamepad.bRightTrigger);

    lua_setbasictableentry(L, i, 'ThumbLeftX', state.Gamepad.sThumbLX);
    lua_setbasictableentry(L, i, 'ThumbLeftY', state.Gamepad.sThumbLY);
    lua_setbasictableentry(L, i, 'ThumbRightX', state.Gamepad.sThumbRX);
    lua_setbasictableentry(L, i, 'ThumbRightY', state.Gamepad.sThumbRY);



    result:=1;
  end;
  {$ENDIF}
end;

function setXBox360ControllerVibration(L:PLua_state): integer; cdecl;
{$IFDEF windows}
var
  index: integer;
  left, right: word;
  vib: XINPUT_VIBRATION;
{$ENDIF}
begin
  result:=0;
  {$IFDEF windows}
  if InitXinput=false then exit;

  if lua_gettop(L)>=3 then
  begin
    index:=lua_tointeger(L,1);
    left:=lua_tointeger(L,2);
    right:=lua_tointeger(L, 3);

    vib.wLeftMotorSpeed:=left;
    vib.wRightMotorSpeed:=right;

    result:=1;
    lua_pushboolean(L, XInputSetState(index, @vib)=0);
  end;
  {$ENDIF}
end;


function lua_registerAutoAssemblerTemplate(L:PLua_state): integer; cdecl;
var
  f: integer;
  routine: string;
  lc: tluacaller;
  name: string;
  shortcut: TShortCut;
begin
  result:=0;

  if lua_gettop(L)>=2 then
  begin
    name:=Lua_ToString(L, 1);

    if lua_isfunction(L, 2) then
    begin
      lua_pushvalue(L, 2);
      f:=luaL_ref(L,LUA_REGISTRYINDEX);

      lc:=TLuaCaller.create;
      lc.luaroutineIndex:=f;
    end
    else
    if lua_isstring(L,2) then
    begin
      routine:=lua_tostring(L,2);
      lc:=TLuaCaller.create;
      lc.luaroutine:=routine;
    end
    else exit;

    shortcut:=0;
    if lua_gettop(L)>=3 then
    begin
      if lua_isinteger(L,3) then
        shortcut:=lua_tointeger(L,3)
      else
      if lua_isstring(L,3) then
        shortcut:=textToShortCut(Lua_ToString(L,3))
    end;

    lua_pushinteger(L, registerAutoAssemblerTemplate(name, lc.AutoAssemblerTemplateCallback, shortcut));
    result:=1;
  end;
end;

function lua_unregisterAutoAssemblerTemplate(L:PLua_state): integer; cdecl;
var id: integer;
begin
  result:=0;
  if lua_gettop(L)=1 then
  begin
    id:=lua_tointeger(L, 1);
    unregisterAutoAssemblerTemplate(id);
  end;
end;


function lua_GenerateCodeInjectionScript(L: PLua_state): integer; cdecl;
var
  script: TStrings;
  address: string;
begin
  result:=0;
  if lua_gettop(L)>=1 then
  begin
    script:=lua_ToCEUserData(L,1);

    if lua_gettop(L)>=2 then
      address:=Lua_ToString(L,2)
    else
      address:=inttohex(MemoryBrowser.disassemblerview.SelectedAddress,8);

    try
      GenerateCodeInjectionScript(script, address);
      lua_pushboolean(L,true);
      result:=1;
    except
    end;
  end;
end;

function lua_GenerateAOBInjectionScript(L: PLua_state): integer; cdecl;
var
  script: TStrings;
  address, symbolname: string;
begin
  result:=0;
  if lua_gettop(L)>=2 then
  begin
    script:=lua_ToCEUserData(L,1);
    symbolname:=Lua_ToString(L,2);

    if lua_gettop(L)>=3 then
      address:=Lua_ToString(L,3)
    else
      address:=inttohex(MemoryBrowser.disassemblerview.SelectedAddress,8);


    try
      GenerateAOBInjectionScript(script, address, symbolname);
      lua_pushboolean(L,true);
      result:=1;
    except
    end;
  end;
end;

function lua_GenerateFullInjectionScript(L: PLua_state): integer; cdecl;
var
  script: TStrings;
  address: string;
begin
  result:=0;
  if lua_gettop(L)>=1 then
  begin
    script:=lua_ToCEUserData(L,1);

    if lua_gettop(L)>=2 then
      address:=Lua_ToString(L,2)
    else
      address:=inttohex(MemoryBrowser.disassemblerview.SelectedAddress,8);

    try
      GenerateFullInjectionScript(script, address);
      lua_pushboolean(L,true);
      result:=1;
    except
    end;
  end;
end;

function lua_unloadLoadedFont(L: PLua_state): integer; cdecl;
begin
  {$IFDEF windows}
  if lua_isnumber(L, 1) then
    RemoveFontMemResourceEx(lua_tointeger(L,1));
  {$ENDIF}

  result:=0;
end;

function lua_loadFontFromStream(L: PLua_state): integer; cdecl;
var
  s: TStream;
  ms: TMemoryStream absolute s;
  f: TFont;
  pc: dword;

  h: THandle;
begin
  result:=0;

  {$IFDEF windows}
  if lua_isuserdata(L, 1) then
  begin
    s:=lua_toceuserdata(L, 1);
    if s is TMemoryStream then
    begin
      pc:=1;
      h:=AddFontMemResourceEx(ms.Memory, ms.Size, nil, @pc);
      lua_pushinteger(L, h);
      result:=1;
    end;
  end;
  {$ENDIF}
end;

function lua_speakex(engLang: boolean; L: Plua_State): integer; cdecl;
var
  pc: integer;
  s: widestring;
begin
  result:=0;
  {$IFDEF windows}
  pc:=lua_gettop(L);

  if pc>=1 then
    s:=Lua_ToString(L, 1)
  else
    exit(0);


  if engLang then
  begin
    s:=StringReplace(s,'&','&amp;',[rfReplaceAll]);
    s:=StringReplace(s,'<','&lt;',[rfReplaceAll]);
    s:=StringReplace(s,'>','&gt;',[rfReplaceAll]);
    //s:='<speak version="1.0" xml:lang="en">'+s+'</speak>';
    //s:='<lang langid="409">'+s+'</lang>';
    s:='<voice required="Language=409">'+s+'</voice>';   //413=dutch (while running under a debugger, this is slow. But normal usage is fine)
  end;

  if pc>=2 then
  begin
    if lua_isboolean(l,2) then
    begin
      lua_pushinteger(L, speak(s, lua_toboolean(L,2)));
      exit(1);
    end
    else
    begin
      lua_pushinteger(L, speak(s, lua_tointeger(L,2)));
      exit(1);
    end;
  end
  else
  begin
    lua_pushinteger(L, speak(s));
    exit(1);
  end;
  {$ENDIF}

end;


function lua_speak(L: Plua_State): integer; cdecl;
begin
  lua_speakEx(false,L);
  result:=0;
end;

function lua_speakEnglish(L: Plua_State): integer; cdecl;
begin
  lua_speakEx(true,L);
  result:=0;
end;


function lua_getFileVersion(L: Plua_State): integer; cdecl;
{$IFDEF windows}
var
  filepath: string;
  h: THandle;
  size: integer;
  data: pointer;
  ffi: ^VS_FIXEDFILEINFO;
  t: integer;

  v: qword;
  s: UINT;
{$ENDIF}
begin
  result:=0;
  {$IFDEF windows}
  if lua_gettop(L)=1 then
  begin
    filepath:=Lua_ToString(l,1);
    size:=GetFileVersionInfoSize(pchar(filepath), @h);
    if size<>0 then
    begin
      getmem(data, size);

      if GetFileVersionInfo(pchar(filepath), h, size, data) then
      begin
        s:=sizeof(ffi);
        if VerQueryValue(data, pchar('\'), @ffi, @s) then
        begin
          v:=(qword(ffi^.dwFileVersionMS) shl 32) or ffi^.dwFileVersionLS;
          result:=2;
          lua_pushinteger(L, v);
          lua_newtable(L);
          t:=lua_gettop(L);


          lua_setbasictableentry(L, t, 'major', (v shr 48) and $ffff);
          lua_setbasictableentry(L, t, 'minor', (v shr 32) and $ffff);
          lua_setbasictableentry(L, t, 'release', (v shr 16) and $ffff);
          lua_setbasictableentry(L, t, 'build', v and $ffff);
        end;

      end;
      FreeMemAndNil(data);
    end;
  end;
  {$ENDIF}
end;

function lua_getCheatEngineFileVersion(L: Plua_State): integer; cdecl;
begin
  lua_pushstring(L,application.ExeName);
  exit(lua_getFileVersion(L));
end;


function lua_hookWndProc(L: Plua_State): integer; cdecl;
{$IFDEF windows}
var
  s: tstringlist;
  hWnd: THandle;
  f: integer;

  orig: qword;
  ts: string;

  wndhooklist_table, hwnd_table: integer;
  i: integer;
  b: boolean;

  async: boolean;

  pc: TLuaPipeClient;
{$ENDIF}
begin
  result:=0;
  {$IFDEF windows}
  lua_getglobal(L, 'CEWindowProcEvent_Internal');


  if lua_isnil(L, -1) then
  begin
    lua_pop(L, 1);

    s:=TStringList.Create;
    s.add('wndhooklist={}');
    s.add('function CEWindowProcEvent_Internal(hWnd, Msg, lParam, wParam)');
    s.add('  if (wndhooklist[hWnd].f) then');
    s.add('    local r, hWnd2, Msg2, lParam2, wParam2');
    s.add('    r,hWnd2,Msg2,lParam2,wParam2=wndhooklist[hWnd].f(hWnd, Msg, lParam, wParam)');
    s.add('    if (r==0) or (r==1) then return r,(hWnd2 or hWnd),(Msg2 or Msg),(lParam2 or lParam),(wParam2 or wParam) end');
    s.add('  end');
    s.add('  return wndhooklist[hWnd].orig,(hWnd2 or hWnd),(Msg2 or Msg),(lParam2 or lParam),(wParam2 or wParam)');
    s.add('end');

    LUA_DoScript(s.Text);
    s.free;
  end
  else
    lua_pop(L, 1);

  //setup the server if needed
  ts:='CEWINHOOK'+inttostr(processid);
  if luaserverExists(ts)=false then
  begin
    tluaserver.create(ts);

    if processhandler.is64Bit then
      ts:='x86_64'
    else
      ts:='i386';

    try
      cefuncproc.InjectDll(CheatEngineDir+'winhook-'+ts+'.dll');
    except
    end;
  end;


  //get the windowhandle and function parameter
  if (lua_gettop(L)>=2) and lua_isnumber(L, 1) and lua_isfunction(L, 2) then
  begin
    if lua_gettop(L)>=3 then
      async:=lua_toboolean(L, 3)
    else
      async:=false;

    hWnd:=lua_tointeger(L, 1);
    pc:=TLuaPipeClient.create('CEWINHOOKC'+inttostr(processid));
    try
      pc.writeByte(1);
      pc.writeQword(hWnd);
      orig:=pc.readQword;

      lua_getglobal(L, 'wndhooklist');
      wndhooklist_table:=lua_gettop(L);

      lua_pushinteger(L, hWnd);
      lua_newtable(L);

      //fill the hWnd table entry
      hwnd_table:=lua_gettop(L);
      lua_pushstring(L, 'f');
      lua_pushvalue(L, 2);
      lua_settable(L, hwnd_table);

      lua_pushstring(L, 'orig');
      lua_pushinteger(L, orig);
      lua_settable(L, hwnd_table);

      lua_settable(L, wndhooklist_table);


      pc.writeByte(4); //set async state
      pc.writeByte(ifthen(async,1,0));
      pc.readByte;

      pc.writeByte(2); //hook
      pc.writeQword(hWnd);
      if pc.readByte=1 then
      begin
        lua_pushboolean(L, true);
        result:=1;
      end;

    finally
      pc.free;
    end;
  end;

  //get the old proc event of the window
  {$ENDIF}

end;

function lua_unhookWndProc(L: Plua_State): integer; cdecl;
{$IFDEF windows}
var pc: TLuaPipeClient;
{$ENDIF}
begin
  result:=0;
  {$IFDEF windows}
  if (lua_gettop(L)=1) and lua_isnumber(L, 1) then
  begin
    lua_getglobal(L, 'wndhooklist');

    lua_pushinteger(L, lua_tointeger(L, 1));
    lua_gettable(L,-2);
    if lua_istable(L, -1) then
    begin
      lua_pushstring(L, 'orig');
      lua_gettable(L, -2);
      if lua_isnumber(L, -1) then
      begin
        pc:=TLuaPipeClient.create('CEWINHOOKC'+inttostr(processid));
        try
          pc.writeByte(3);
          pc.writeQword(lua_tointeger(L, 1));
          pc.writeQword(lua_tointeger(L, -1));
          if pc.readByte=1 then
          begin
            lua_pushboolean(L, true);
            result:=1;
          end;
        finally
          pc.free;
        end;
      end;
    end;
  end;
  {$ENDIF}
end;

function lua_registerEXETrainerFeature(L: Plua_State): integer; cdecl;
var i,j: integer;
begin
  result:=0;
  if (lua_gettop(L)=2) and lua_isstring(L,1) and lua_isfunction(L,2) then
  begin
    j:=length(exeTrainerFeatures);
    for i:=0 to length(exeTrainerFeatures)-1 do
      if exeTrainerFeatures[i].featurename='' then
      begin
        j:=i;
        break;
      end;

    if j=length(exeTrainerFeatures) then
      setlength(exeTrainerFeatures,j+1);

    exeTrainerFeatures[j].featurename:=Lua_ToString(L, 1);
    exeTrainerFeatures[j].functionid:=luaL_ref(L, LUA_REGISTRYINDEX);

    lua_pushinteger(L, j);
    result:=1;
  end;
end;

function lua_unregisterEXETrainerFeature(L: Plua_State): integer; cdecl;
var i: integer;
begin
  if (lua_gettop(L)=1) and lua_isnumber(L, 1) then
  begin
    i:=lua_tointeger(L,1);
    if i<length(exeTrainerFeatures) then
    begin
      exeTrainerFeatures[i].featurename:='';
      luaL_unref(L, LUA_REGISTRYINDEX, exeTrainerFeatures[i].functionid);
      exeTrainerFeatures[i].functionid:=0;
    end;
  end;

  result:=0;
end;

function lwriter(L: Plua_State; const p: Pointer; sz: size_t; ud: Pointer): Integer; cdecl;
var s: TStream;
begin
  s:=tstream(ud);
  s.WriteBuffer(p^,sz);
  result:=0;
end;



function lua_encodeFunction(L: Plua_State): integer; cdecl;
var
  s: TMemoryStream;
  cs: Tcompressionstream;
  i: integer;

  output: pchar;

  new: pchar;
begin
  s:=TMemoryStream.Create;
  cs:=Tcompressionstream.create(clmax, s);


  if (lua_gettop(L)=1) and (lua_isfunction(L, 1)) then
    lua_dump(L, @lwriter, cs, 1);

  cs.free;

  getmem(output, (s.size div 4) * 5 + 5 );
  BinToBase85(pchar(s.Memory), output, s.size);

  lua_pushstring(L, output);
  FreeMemAndNil(output);

  s.free;

  result:=1;
end;

function lua_encodeFunctionEx(L: Plua_State): integer; cdecl;
//takes a string and an optional lua dll and encode it with that dll instead
var
  s: TMemoryStream;
  cs: Tcompressionstream;
  script,luadll: string;
  hm: HModule;

  _luaL_newstate: function : Plua_State; cdecl;
  _luaL_openlibs: procedure(L: Plua_State); cdecl;
  _luaL_loadstring: function(L: Plua_State; const s: PChar): Integer; cdecl;
  _lua_dump: function(L: Plua_State; writer: lua_Writer; data: Pointer; strip: integer): Integer; cdecl;
  _lua_close: procedure(L: Plua_State); cdecl;

  l2: Plua_State;
  r: integer;

  rs:  string;
  output: pchar;
begin
  result:=0;
  if lua_gettop(L)>=1 then
  begin
    script:=Lua_ToString(L,1);

    if lua_gettop(L)>=2 then
      luadll:=Lua_ToString(L,2)
    else
      luadll:=LUA_LIB_NAME;

    hm:=LoadLibrary(pchar(luadll));
    if hm<>0 then
    begin
      _luaL_newstate:=getprocaddress(hm,'luaL_newstate');
      _luaL_openlibs:=getprocaddress(hm,'luaL_openlibs');
      _luaL_loadstring:=getprocaddress(hm,'luaL_loadstring');
      _lua_dump:=getprocaddress(hm,'lua_dump');
      _lua_close:=getprocaddress(hm,'lua_close');



      l2:=_luaL_newstate;
      _luaL_openlibs(l2);
      if _luaL_loadstring(l2, pchar(script))=0 then
      begin
        //encode the function.
        s:=TMemoryStream.Create;
        cs:=Tcompressionstream.create(clmax, s);

        _lua_dump(L2, @lwriter, cs, 1);

        cs.free;
        getmem(output, (s.size div 4) * 5 + 5 );
        BinToBase85(pchar(s.Memory), output, s.size);

        lua_pushstring(L, output);
        FreeMemAndNil(output);

        s.free;

        result:=1;

        _lua_close(l2);

        FreeLibrary(hm);
      end;
    end;
  end;
end;


function lreader(L: Plua_State; ud: Pointer; sz: Psize_t): PChar; cdecl;
var s: TMemoryStream;
begin
  s:=TMemoryStream(ud);

  result:=pchar(ptruint(s.Memory)+s.Position);
  sz^:=s.Size-s.position;

  s.position:=s.position+sz^;
end;

function lua_decodeFunction(L: Plua_State): integer; cdecl;
var
  ds: Tdecompressionstream;
  s: TMemoryStream;

  decompressed: TMemoryStream;
  i: integer;

  size: integer;
  input, output: pchar;
begin
  result:=1;
  if (lua_gettop(L)=1) and lua_isstring(L,1) then
  begin
    input:=lua.lua_tostring(L,1);

    size:=(length(input) div 5)*4+(length(input) mod 5);
    getmem(output, size*2);


    size:=Base85ToBin(input, output);
    lua_pushlstring(L, output, size);

    s:=TMemoryStream.Create;
    s.WriteBuffer(output^, size);
    s.position:=0;
    ds:=Tdecompressionstream.create(s);

    decompressed:=TMemoryStream.create;
    decompressed.CopyFrom(ds,0);

    decompressed.position:=0;
    lua_load(L, @lreader, decompressed,'cechunk', 'b');


    freeandnil(decompressed);
    freeandnil(ds);
    freeandnil(s);
    FreeMemAndNil(output);

    result:=1;
  end;

end;

function lua_getFileList(L: Plua_State): integer; cdecl;
var
  list: Tstringlist;
  path: string;
  mask: string;
  subdirs: boolean;
  attrib: word;

  paramcount: integer;
  i: integer;
begin
  paramcount:=lua_gettop(L);
  if paramcount=0 then exit(0);

  path:=lua_tostring(L,1);
  if paramcount>1 then
    mask:=Lua_ToString(L, 2)
  else
    mask:='';

  if paramcount>2 then
    subdirs:=lua_toboolean(L,3)
  else
    subdirs:=false;

  if paramcount>3 then
    attrib:=lua_tointeger(L, 4)
  else
    attrib:=faDirectory;

  lua_pop(L, paramcount);

  list:=FindAllFiles(path,mask,subdirs,attrib);

  lua_createtable(L, list.count, 0);
  result:=1;

  for i:=0 to list.count-1 do
  begin
    lua_pushinteger(L, i+1);
    lua_pushstring(L, list[i]);
    lua_settable(L, 1);
  end;

  list.free;
end;

function lua_getDirectoryList(L: Plua_State): integer; cdecl;
var
  list: Tstringlist;
  path: string;
  mask: string;
  subdirs: boolean;
  attrib: word;

  paramcount: integer;
  i: integer;
begin
  paramcount:=lua_gettop(L);
  if paramcount=0 then exit(0);

  path:=lua_tostring(L,1);

  if paramcount>1 then
    subdirs:=lua_toboolean(L,2)
  else
    subdirs:=false;

  lua_pop(L, paramcount);

  list:=FindAllDirectories(path,subdirs);

  lua_createtable(L, list.count, 0);
  result:=1;

  for i:=0 to list.count-1 do
  begin
    lua_pushinteger(L, i+1);
    lua_pushstring(L, list[i]);
    lua_settable(L, 1);
  end;

  list.free;
end;

function lua_connectToCEServer(L: Plua_State): integer; cdecl;
var
  hostname: string;
  port: integer;
begin
  result:=0;
  if lua_gettop(L)=2 then
  begin
    hostname:=Lua_ToString(L, 1);
    port:=lua_tointeger(L, 2);
    CEconnect(hostname, port);
  end;
end;

function lua_copyMemory(L: Plua_State): integer; cdecl;
var
  sourceAddress: ptruint;
  destinationAddress: ptruint;
  Method: integer;
  size: integer;

  pc: integer;
  temp: Pointer;
  ar: ptruint;
begin
  result:=0;
  pc:=lua_gettop(L);
  if pc=0 then exit;

  sourceAddress:=lua_toaddress(L,1);

  if pc>1 then
    size:=lua_tointeger(L,2);

  if pc>3 then
    Method:=lua_tointeger(L, 4)
  else
    Method:=0;

  if (pc>2) and (not lua_isnil(L,3)) then
    destinationAddress:=lua_toaddress(L, 3)
  else
  begin
    //allocate the memory
    case method of
      0,2:
      begin
        //target process
        destinationAddress:=ptruint(VirtualAllocEx(processhandle, nil,size,MEM_COMMIT or MEM_RESERVE,PAGE_EXECUTE_READWRITE));
        if destinationAddress=0 then exit;
      end;

      1,3:
      begin
        //ce memory
        destinationAddress:=ptruint(VirtualAlloc(nil,size,MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE));
        if destinationAddress=0 then exit;
      end;
    end;
  end;


  case method of
    0: //target to target
    begin
      temp:=VirtualAlloc(nil,size,MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
      try
        if readprocessmemory(processhandle, pointer(sourceAddress), temp, size, ar) then
        begin
          if ar=size then
          begin
            if WriteProcessMemory(processhandle, pointer(destinationAddress), temp, size, ar) then
            begin
              if ar=size then
              begin
                lua_pushinteger(L, destinationAddress);
                exit(1);
              end;
            end;
          end;
        end;

      finally
        VirtualFree(temp,0, MEM_RELEASE);
      end;
    end;

    1: //target to CE
    begin
      if readprocessmemory(processhandle, pointer(sourceAddress), pointer(destinationAddress), size, ar) then
      begin
        if ar=size then
        begin
          lua_pushinteger(L, destinationAddress);
          exit(1);
        end;
      end;
    end;

    2: //CE to target
    begin
      if writeprocessmemory(processhandle, pointer(sourceAddress), pointer(destinationAddress), size, ar) then
      begin
        if ar=size then
        begin
          lua_pushinteger(L, destinationAddress);
          exit(1);
        end;
      end;
    end;

    3: //CE to CE
    begin
      try
        {$ifdef windows}
        RtlCopyMemory(pointer(destinationAddress), pointer(sourceAddress), size);
        {$else}
        copymemory(pointer(destinationAddress), pointer(sourceAddress), size);
        {$endif}
        lua_pushinteger(L, destinationAddress);
        exit(1);
      except
      end;
    end;
  end;
end;


function lua_compareMemory(L: PLua_state): integer; cdecl;
var
  address1,address2: ptruint;
  Method: integer;
  size,i: integer;

  pc: integer;
  temp: Pointer;
  ar: ptruint;

  buf1, buf2: PByteArray;
begin
  result:=0;
  pc:=lua_gettop(L);
  if pc<3 then exit;


  if pc=4 then
    method:=lua_tointeger(L,4)
  else
    method:=0;

  if method=2 then
    address1:=lua_toaddress(L,1,true)
  else
    address1:=lua_toaddress(L,1);

  if method>0 then
    address2:=lua_toaddress(L,2,true)
  else
    address2:=lua_toaddress(L,2);

  size:=lua_tointeger(L,3);

  if size=0 then exit;

  buf1:=nil;
  buf2:=nil;

  case method of
    0:
    begin
      getmem(buf1,size);
      getmem(buf2,size);
      ReadProcessMemory(processhandle, pointer(address1),buf1,size,ar);
      ReadProcessMemory(processhandle, pointer(address2),buf2,size,ar);
    end;

    1:
    begin
      getmem(buf1,size);
      ReadProcessMemory(processhandle, pointer(address1),buf1,size,ar);
      buf2:=pointer(address2);
    end;

    2:
    begin
      buf1:=pointer(address1);
      buf2:=pointer(address2);
    end;
  end;

  //compare
  result:=1;


  {$ifdef windows}
  i:=RtlCompareMemory(buf1,buf2,size);
  {$else}
  i:=CompareMemRange(buf1,buf2,size);
  {$endif}

  lua_pushboolean(L,i=size);
  if i<>size then
  begin
    lua_pushinteger(L, i);
    result:=2;
  end;


  case method of
    0:
    begin
      if buf1<>nil then
        FreeMemAndNil(buf1);

      if buf2<>nil then
        FreeMemAndNil(buf2);
    end;

    1:
    begin
      if buf1<>nil then
        freeMemAndNil(buf1);
    end;
  end;


end;


function lua_enableDRM(L: Plua_State): integer; cdecl;
var
  PreferedAltitude: word;
  ProtectedProcess: dword; //pid
begin
  result:=0;

  {$IFDEF windows}
  DBK32Initialize;

  if lua_gettop(L)>=1 then
    PreferedAltitude:=lua_tointeger(L,1)
  else
    PreferedAltitude:=0;

  if lua_gettop(L)>=2 then
  begin
    if lua_isstring(L,2) then
      ProtectedProcess:=ce_getProcessIDFromProcessName(pchar(Lua_ToString(L,2)))
    else
      ProtectedProcess:=lua_tointeger(L,2);
  end
  else
    ProtectedProcess:=0;

  result:=1;
  lua_pushboolean(L, dbk_enabledrm(preferedAltitude, GetPEProcess(ProtectedProcess)));
  {$ENDIF}
end;


function lua_saveOpenedFile(L: Plua_State): integer; cdecl;
begin
  if lua_gettop(L)>=1 then
    filehandler.commitchanges(Lua_ToString(L,1))
  else
    Filehandler.commitChanges;

  result:=0;
end;

function lua_openFileAsProcess(L: Plua_State): integer; cdecl;
{$IFDEF windows}
var
  filename: string;
  is64bit: boolean;
  oldprocessname: string;
  oldprocess: dword;
  oldprocesshandle: thandle;
  parameters: integer;
  startaddress: ptruint;
{$ENDIF}

begin
  result:=0;

  {$IFDEF windows}
  result:=1;
  parameters:=lua_gettop(L);
  if parameters>=1 then
  begin
    filename:=Lua_ToString(L,1);

    if parameters>=2 then
      is64bit:=lua_toboolean(L,2)
    else
      is64bit:=false;

    if parameters>=3 then
      startaddress:=lua_tointeger(L,3)
    else
      startaddress:=0;

    DetachIfPossible;
    oldprocessname := copy(mainform.ProcessLabel.Caption, pos('-', mainform.ProcessLabel.Caption) + 1, length(mainform.ProcessLabel.Caption));
    oldprocess := processID;
    oldprocesshandle := processhandle;

    try
      DBKFileAsMemory(filename,startaddress);

    except
      lua_pushboolean(L,false);
      exit;
    end;

    ProcessHandler.ProcessHandle:=THandle(-2);

    MainForm.ProcessLabel.caption:=extractfilename(filename);
    MainForm.miSaveFile.visible:=true;

    ProcessHandler.processid:=$FFFFFFFF;

    ProcessHandler.is64Bit:=is64bit;

    mainform.openProcessEpilogue(oldprocessname, oldprocess, oldprocesshandle,true);

    lua_pushboolean(L,true);
  end;
  {$ENDIF}
end;

function lua_getPEB(L: Plua_State): integer; cdecl;
var peb: qword;
  pbi: TProcessBasicInformation;
  x: ulong;
begin
  result:=0;


 {$IFDEF windows}
 if DBKLoaded then
    peb:=dbk_getPEB(GetPEProcess(processid))
  else
  begin
    if NtQueryInformationProcess(processhandle, ProcessBasicInformation, @pbi, sizeof(pbi), @x)=STATUS_SUCCESS then
      peb:=qword(pbi.PebBaseAddress)
    else
      peb:=0;
  end;

  lua_pushinteger(L, peb);
  result:=1;
 {$ENDIF}
end;

function lua_createAPC(L: Plua_State): integer; cdecl;
var address: ptruint;
begin
  result:=0;
  {$IFDEF windows}
  if lua_gettop(L)>=1 then
  begin
    address:=lua_toaddress(L,1);
    CreateRemoteAPC(getathreadid(processid), pointer(address));
  end;
  {$ENDIF}
end;

function lua_setAssemblerMode(L: Plua_State): integer; cdecl;
var mode: integer;
begin
  result:=0;
  if lua_gettop(L)>=1 then
  begin
    mode:=lua_tointeger(L,1);
    if mode=0 then
      processhandler.is64Bit:=false;

    if mode=1 then
      processhandler.is64Bit:=true;
  end;
end;

function lua_allocateMemory(l: Plua_State): integer; cdecl;
var
  size: integer;
  a: pointer;
  base: pointer;
  prot: dword;
begin
  result:=0;
  if lua_gettop(L)>=1 then
  begin
    size:=lua_tointeger(L,1);
    if lua_gettop(L)>=2 then
      base:=pointer(lua_tointeger(L,2))
    else
      base:=nil;

    if lua_gettop(L)>=3 then
      prot:=lua_tointeger(L,3)
    else
      prot:=PAGE_EXECUTE_READWRITE;


    a:=VirtualAllocEx(processhandle,base,size,MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if a=nil then
    begin
      //try to fix a mistake
      base:=FindFreeBlockForRegion(ptruint(base),size);
      a:=VirtualAllocEx(processhandle,base,size,MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);
      if a=nil then exit(0);
    end;

    lua_pushinteger(L, ptruint(a));
    result:=1;
  end;
end;

function lua_try(l: Plua_State): integer; cdecl;
//nice idea, but the return value of this function seems broken after an raise exception in a function called by pcall (lua_error does function properly)
begin
  result:=2;
  if lua_gettop(L)>=1 then
  begin
    if lua_isfunction(L,1) then
    begin

      try
        if lua.lua_pcall(L,lua_gettop(L)-1,LUA_MULTRET,0)=0 then
        begin
          lua_pushboolean(L,true);
          lua_insert(L,1);
          result:=lua_gettop(L);
        end
        else
        begin
          lua_pushboolean(L,false);
          lua_pushvalue(L,-2);
        end;
      except
        on e:exception do
        begin
          lua_pop(L,lua_gettop(L));
          lua_pop(L,1);
          lua_pushboolean(L,false);
          lua_pushstring(L,e.message);
        end;
      end;

    end
    else
    begin
      lua_pushboolean(L,false);
      lua_pushstring(L,'First parameter for try is not a function');
    end;
  end
  else
  begin
    lua_pushboolean(L,false);
    lua_pushstring(L,'No parameter given');
  end;
end;

function lua_getSystemMetrics(l: Plua_State): integer; cdecl;
var parameters, nIndex: integer;
begin
  result:=0;
  parameters:=lua_gettop(L);
  if parameters=1 then
  begin
    nIndex:=lua_tointeger(L,-1);
    lua_pop(L, parameters);
    lua_pushinteger(L, GetSystemMetrics(nIndex));
    result:=1;
  end else lua_pop(L, parameters);
end;


function lua_getScreenDPI(l: Plua_State): integer; cdecl;
begin
  lua_pushinteger(L, Screen.PixelsPerInch);
  result:=1;
end;


function lua_getScreenHeight(l: Plua_State): integer; cdecl;
begin
  lua_pushinteger(L, screen.Height);
  result:=1;
end;

function lua_getScreenWidth(l: Plua_State): integer; cdecl;
begin
  lua_pushinteger(L, screen.Width);
  result:=1;
end;

function lua_getWorkAreaHeight(l: Plua_State): integer; cdecl;
begin
  lua_pushinteger(L, screen.WorkAreaHeight);
  result:=1;
end;

function lua_getWorkAreaWidth(l: Plua_State): integer; cdecl;
begin
  lua_pushinteger(L, screen.WorkAreaWidth);
  result:=1;
end;

var screencanvas: TCanvas=nil;
function lua_getScreenCanvas(L: PLua_state): integer; cdecl;
begin
  if screencanvas=nil then
  begin
    screencanvas:=tcanvas.Create;
    screencanvas.Handle:=GetDC(0);
  end;

  luaclass_newClass(L, screencanvas);
  result:=1;
end;

function lua_getHandleList(L: PLua_state): integer; cdecl;
var
  shi: PSYSTEM_HANDLE_INFORMATION=nil;
  rl: ulong;
  r: ntstatus;
  i,j: integer;

  filter: integer;
  peprocess: ptruint=0;
begin
  result:=0;

  {$IFDEF windows}
  i:=sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO)+128*sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO);
  getmem(shi,i);

  repeat
    zeromemory(shi,i);
    r:=NtQuerySystemInformation(SystemHandleInformation, shi,i,@rl);
    if r=STATUS_INFO_LENGTH_MISMATCH then
    begin
      FreeMemAndNil(shi);
      i:=i*2-2;
      getmem(shi,i);
    end;

  until (r<>STATUS_INFO_LENGTH_MISMATCH) or (i>256*1024*1024);

  if r=STATUS_INFO_LENGTH_MISMATCH then exit(0);
  if r<>0 then exit(0);

  if lua_gettop(L)>=1 then
  begin
    filter:=lua_tointeger(L,1);
    //0=everything
    //1=all handles from the opened process
    //2=all handles to the opened process
    //3=all handles to cheat engine

    case filter of
      2:
      begin
        LoadDBK32;
        peprocess:=GetPEProcess(processid);
      end;

      3:
      begin
        LoadDBK32;
        peprocess:=GetPEProcess(GetCurrentProcessId);
        filter:=2;
      end;
    end;
  end
  else
    filter:=0;

  lua_pop(l, lua_gettop(L));


  lua_createtable(L, shi.HandleCount,0);
  j:=0;
  for i:=0 to shi.HandleCount-1 do
  begin
    if (filter=0) or
       ((filter=1) and (shi.list[i].ProcessId=processid)) or
       ((filter=2) and (ptruint(shi.list[i].obj)=peprocess)) then
    begin
      inc(j);
      lua_pushinteger(L,j);
      lua_createtable(L,0,6);

      lua_pushstring(L, 'ProcessID');
      lua_pushinteger(L, shi.list[i].ProcessId );
      lua_settable(L,-3);

      lua_pushstring(L, 'ObjectTypeIndex');
      lua_pushinteger(L, shi.list[i].ObjectTypeIndex );
      lua_settable(L,-3);

      lua_pushstring(L, 'HandleAttributes');
      lua_pushinteger(L, shi.list[i].HandleAttributes );
      lua_settable(L,-3);

      lua_pushstring(L, 'HandleValue');
      lua_pushinteger(L, shi.list[i].HandleValue );
      lua_settable(L,-3);

      lua_pushstring(L, 'Object');
      lua_pushinteger(L, ptruint(shi.list[i].obj));
      lua_settable(L,-3);

      lua_pushstring(L, 'GrantedAccess');
      lua_pushinteger(L, shi.list[i].GrantedAccess );
      lua_settable(L,-3);

      lua_settable(L,1);

    end;
  end;

  if shi<>nil then
    FreeMemAndNil(shi);

  result:=1;
  {$ENDIF}
end;

function lua_closeRemoteHandle(L: PLua_state): integer; cdecl;
var
  handle, newhandle: THandle;
  ph: thandle;
begin
  result:=0;

  {$IFDEF windows}
  if lua_gettop(L)>=1 then
  begin
    handle:=lua_tointeger(L,1);

    if lua_gettop(L)>=2 then
    begin
      ph:=newkernelhandler.openProcess(PROCESS_DUP_HANDLE,false,lua_tointeger(L,2));
      if ph=0 then exit
    end
    else
      ph:=processhandle;

    DuplicateHandle(ph, handle, 0,nil, 0, false, DUPLICATE_CLOSE_SOURCE);

    if (lua_gettop(L)>=2) then
      closehandle(ph);
  end;
  {$ENDIF}
end;

function lua_showSelectionList(L: PLua_state): integer; cdecl;
var
  title,
  caption: string;
  list: Tstringlist;
  output: string;
  custominput: boolean;
  r: integer;
begin
  if lua_gettop(L)>=3 then
  begin
    title:=Lua_ToString(L,1);
    caption:=Lua_ToString(L,2);
    list:=lua_ToCEUserData(L,3);

    if lua_gettop(L)>=4 then
      custominput:=lua_toboolean(L,4)
    else
      custominput:=false;

    r:=ShowSelectionList(application,title, caption,list, output, custominput);

    lua_pushinteger(L,r);
    lua_pushstring(L, output);

    result:=2;
  end
  else result:=0;

end;

function lua_cpuid(L: PLua_state): integer; cdecl;
var a,c: dword;
var r: TCPUIDResult;
i: integer;
begin
  if lua_gettop(L)>=1 then
    a:=lua_tointeger(L,1)
  else
    exit(0);


  if lua_gettop(L)>=2 then
    c:=lua_tointeger(L,2)
  else
    c:=0;

  r:=CPUID(a,c);
  lua_newtable(L);
  i:=lua_gettop(L);
  lua_setbasictableentry(L, i, 'EAX', r.eax);
  lua_setbasictableentry(L, i, 'EBX', r.ebx);
  lua_setbasictableentry(L, i, 'ECX', r.ecx);
  lua_setbasictableentry(L, i, 'EDX', r.edx);
  result:=1;
end;

function lua_gc_setPassive(L: PLua_state): integer; cdecl;
begin
  if lua_gettop(L)>=1 then
    mainform.tLuaGCPassive.enabled:=lua_toboolean(L,1);

  result:=0;
end;

function lua_gc_setActive(L: PLua_state): integer; cdecl;
begin
  if lua_gettop(L)>=1 then
    mainform.tLuaGCActive.enabled:=lua_toboolean(L,1);

  if lua_gettop(L)>=2 then
    mainform.tLuaGCActive.interval:=lua_tointeger(L,2);

  if lua_gettop(L)>=3 then
    luagc_MinSize:=lua_tointeger(L,3);

  result:=0;
end;

function lua_getHotkeyHandlerThread(L: PLua_state): integer; cdecl;
begin
  luaclass_newClass(L, hotkeythread);
  result:=1;
end;

function lua_enumMemoryRegions(L: PLua_state): integer; cdecl;
var
  mbi: TMEMORYBASICINFORMATION;
  address: ptruint;
  oldaddress: ptruint;
  i: integer;
begin
  address:=0;
  lua_newtable(L);
  i:=1;
  while newkernelhandler.VirtualQueryEx(processhandle, pointer(address),mbi,sizeof(mbi))=sizeof(mbi) do
  begin
    lua_pushinteger(L,i);
    lua_newtable(L);

    lua_pushstring(L,'BaseAddress');
    lua_pushinteger(L,ptruint(mbi.BaseAddress));
    lua_settable(L,-3);

    lua_pushstring(L,'AllocationBase');
    lua_pushinteger(L,ptruint(mbi.AllocationBase));
    lua_settable(L,-3);

    lua_pushstring(L,'AllocationProtect');
    lua_pushinteger(L,mbi.AllocationProtect);
    lua_settable(L,-3);

    lua_pushstring(L,'RegionSize');
    lua_pushinteger(L,mbi.RegionSize);
    lua_settable(L,-3);

    lua_pushstring(L,'State');
    lua_pushinteger(L,mbi.RegionSize);
    lua_settable(L,-3);

    lua_pushstring(L,'Protect');
    lua_pushinteger(L,mbi.Protect);
    lua_settable(L,-3);

    lua_pushstring(L,'Type');
    lua_pushinteger(L,mbi.Protect);
    lua_settable(L,-3);

    lua_settable(L,-3);

    oldaddress:=address;
    address:=address+mbi.RegionSize;
    if address<oldaddress then break;

    inc(i);
  end;

  result:=1;
end;

function lua_enableWindowsSymbols(L: PLua_state): integer; cdecl;
begin
  EnableWindowsSymbols(false);
  result:=0;
end;

function lua_enableKernelSymbols(L: PLua_state): integer; cdecl;
begin
  result:=0;
  symhandler.kernelsymbols:=true;
  MemoryBrowser.Kernelmodesymbols1.checked:=true;
  symhandler.reinitialize(true);
end;

function lua_enumExports(L: PLua_state): integer; cdecl;
var
  address: ptruint;
  path: string;
  self: boolean;
  e: boolean;
  list: Tstringlist;
  i: integer;
begin

  result:=0;
  {$IFDEF windows}
  if lua_gettop(L)>=1 then
  begin
    list:=Tstringlist.create;
    try
      if lua_gettop(L)>=2 then
        self:=lua_toboolean(L,2);

      try
        address:=lua_toaddress(L,1,self);
        try
          peinfo_getExportList(address,list);
        except
          exit(0); //no export list
        end;
      except
        if lua_isstring(L,1) then
        begin
          path:=Lua_ToString(L,1);
          try
            peinfo_getExportList(path,list);
          except
            exit(0);
          end;
        end;
      end;

      lua_newtable(L);
      for i:=0 to list.count-1 do
      begin
        lua_pushstring(L,list[i]);
        lua_pushinteger(L,ptruint(list.Objects[i]));
        lua_settable(L,-3);
      end;
      result:=1;


    finally
      list.free;
    end;

  end;
  {$ENDIF}
end;

function lua_duplicateHandle(L: PLua_state): integer; cdecl;
//three formats:
//(handle): Duplicates a CE handle to the target process
//(handle, mode) : where mode is 0: CE to Target, 1: Target to CE
//(handle, frompid,topid)
var
  fromprocess: THandle;
  toprocess: THandle;

  sourcehandle: THandle;
  newhandle: THandle;

  frompid, topid: qword;

  openedfromprocess: boolean=false;
  openedtoprocess: boolean=false;
begin
  result:=0;
  {$IFDEF windows}
  try

    fromprocess:=GetCurrentProcess;
    toprocess:=processhandle;
    if lua_gettop(L)>=1 then
    begin
      sourcehandle:=lua_tointeger(L,1);

      if lua_gettop(L)>=2 then
      begin
        if lua_gettop(L)>=3 then
        begin
          //frompid,topid
          frompid:=lua_tointeger(L,2);
          topid:=lua_tointeger(L,3);

          if frompid=GetCurrentProcessId then
            fromprocess:=GetCurrentProcess
          else
          if frompid=processid then
            fromprocess:=processhandle
          else
          begin
            fromprocess:=newkernelhandler.openProcess(PROCESS_DUP_HANDLE,false,frompid);
            if fromprocess<>0 then
              openedfromprocess:=true
            else
            begin
              lua_pushnil(L);
              lua_pushstring(L,'Failure opening process '+inttostr(frompid)+' ('+SysErrorMessage(GetLastOSError)+')');
              exit(2); //failed to open the process
            end;
          end;

          if topid=GetCurrentProcessId then
            toprocess:=GetCurrentProcess
          else
          if topid=processid then
            toprocess:=processhandle
          else
          begin
            toprocess:=newkernelhandler.openProcess(PROCESS_DUP_HANDLE,false,topid);
            if toprocess<>0 then
              openedtoprocess:=true
            else
            begin
              lua_pushnil(L);
              lua_pushstring(L,'Failure opening process '+inttostr(topid)+' ('+SysErrorMessage(GetLastOSError)+')');
              exit(2); //failed to open the process
            end;
          end;
        end
        else
        begin
          //mode
          if lua_tointeger(L,2)=1 then //target to CE, so switch processes
          begin
            toprocess:=GetCurrentProcess;
            fromprocess:=processhandle;
          end; //else as it was
        end;
      end;

      if DuplicateHandle(fromprocess, sourcehandle,toprocess,@newhandle, 0, false, DUPLICATE_SAME_ACCESS) then
      begin
        lua_pushinteger(L,newhandle);
        exit(1);
      end
      else
      begin
        lua_pushnil(L);
        lua_pushstring(L, 'Duplication failed due to :'+SysErrorMessage(GetLastOSError));
        exit(2);
      end;

    end;

  finally
    if openedfromprocess then closehandle(fromprocess);
    if openedtoprocess then closehandle(toprocess);
  end;
  {$ENDIF}
end;

function lua_getOperatingSystem(L: PLua_state): integer; cdecl;
begin
  lua_pushinteger(L,{$ifdef windows}0{$else}1{$endif});
  result:=1;
end;

function lua_createColorDialog(L: Plua_State): integer; cdecl;
var
  owner: TComponent;
  cd: TColorDialog;
begin
  result:=0;

  if lua_gettop(L)=1 then
    owner:=lua_toceuserdata(L, 1)
  else
    owner:=nil;

  cd:=TColorDialog.Create(owner);
  luaclass_newClass(L, cd);
  result:=1;
end;

function lua_createColorBox(L: Plua_State): integer; cdecl;
var
  owner: TComponent;
  cb: TColorBox;
begin
  result:=0;

  if lua_gettop(L)=1 then
    owner:=lua_toceuserdata(L, 1)
  else
    owner:=nil;

  cb:=TColorBox.Create(owner);
  luaclass_newClass(L, cb);
  result:=1;
end;

function lua_createAutoAssemblerForm(L: Plua_State): integer; cdecl;
var f: TfrmAutoInject;
begin
  f:=TfrmAutoInject.Create(application);
  if lua_gettop(L)>=1 then
    f.assemblescreen.Text:=Lua_ToString(L,1);

  f.show;

  luaclass_newClass(L, f);
  result:=1;
end;


function lua_getRTTIClassName(L: Plua_State): integer; cdecl;
var address: ptruint;
  classname: string;
begin
  result:=0;
  if lua_gettop(L)>=1 then
  begin
    address:=lua_tointeger(L,1);
    if getRTTIClassName(address, classname) then
    begin
      lua_pushstring(L,classname);
      exit(1);
    end;
  end;

end;

function lua_getAutoRunPath(L: Plua_State): integer; cdecl;
begin
  lua_pushstring(L,autorunpath);
  exit(1);
end;

procedure InitializeLua;
var
  s: tstringlist;
  k32: THandle;
  i: integer;
  l: PLUA_STATE;
begin
  {$ifdef darwin}
  if assigned(luaL_newstate)=false then
  begin
    lua.initializeLua;

    if assigned(luaL_newstate)=false then
    begin
      outputdebugstring('Invalid lua config');
      exit;
    end;
  end;
  {$endif}


  _LuaVM:=lua_open();

  L:=LUAVM;
  if L<>nil then
  begin
    luaL_openlibs(L);

    lua_atpanic(L, LuaPanic);
    lua_register(L, 'print', print);
    lua_register(L, 'sleep', lua_sleep);
    lua_register(L, 'pause', pause);
    lua_register(L, 'unpause', unpause);
    lua_register(L, 'readBytes', readbytes);
    lua_register(L, 'writeBytes', writebytes);
    lua_register(L, 'readSmallInteger', readSmallInteger);
    lua_register(L, 'readInteger', readInteger);
    lua_register(L, 'readQword', readQword);
    lua_register(L, 'readPointer', readPointer);
    lua_register(L, 'readFloat', readFloat);
    lua_register(L, 'readDouble', readDouble);
    lua_register(L, 'readString', readString);
    lua_register(L, 'readSmallIntegerLocal', readSmallIntegerLocal);
    lua_register(L, 'readIntegerLocal', readIntegerLocal);
    lua_register(L, 'readQwordLocal', readQwordLocal);
    lua_register(L, 'readPointerLocal', readPointerLocal);
    lua_register(L, 'readFloatLocal', readFloatLocal);
    lua_register(L, 'readDoubleLocal', readDoubleLocal);
    lua_register(L, 'readStringLocal', readStringLocal);

    lua_register(L, 'writeSmallInteger', writeSmallInteger);
    lua_register(L, 'writeInteger', writeInteger);
    lua_register(L, 'writeQword', writeQword);
    lua_register(L, 'writePointer', writePointer);
    lua_register(L, 'writeFloat', writeFloat);
    lua_register(L, 'writeDouble', writeDouble);
    lua_register(L, 'writeString', writeString);
    lua_register(L, 'writeSmallIntegerLocal', writeSmallIntegerLocal);
    lua_register(L, 'writeIntegerLocal', writeIntegerLocal);
    lua_register(L, 'writeQwordLocal', writeQwordLocal);
    lua_register(L, 'writePointerLocal', writePointerLocal);
    lua_register(L, 'writeFloatLocal', writeFloatLocal);
    lua_register(L, 'writeDoubleLocal', writeDoubleLocal);
    lua_register(L, 'writeStringLocal', writeStringLocal);


    lua_register(L, 'readBytesLocal', readbyteslocal);
    lua_register(L, 'writeBytesLocal', writebyteslocal);
    lua_register(L, 'autoAssemble', autoAssemble_lua);
    lua_register(L, 'autoAssembleCheck', AutoAssembleCheck_lua);
    lua_register(L, 'deAlloc', deAlloc_lua);
    lua_register(L, 'deAllocLocal', deAllocLocal_lua);
    lua_register(L, 'showMessage', showMessage_lua);
    lua_register(L, 'inputQuery', inputQuery_lua);
    lua_register(L, 'getPixel', getPixel);
    lua_register(L, 'getMousePos', getMousePos);
    lua_register(L, 'setMousePos', setMousePos);
    lua_register(L, 'createTableEntry', createTableEntry);
    lua_register(L, 'getTableEntry', getTableEntry);

    initializeLuaMemoryRecord;





    lua_register(L, 'mouse_event', lua_mouse_event);
    lua_register(L, 'isKeyPressed', isKeyPressed);
    lua_register(L, 'keyDown', keyDown);
    lua_register(L, 'keyUp', keyUp);
    lua_register(L, 'doKeyPress', doKeyPress);
    lua_register(L, 'getProcessIDFromProcessName', getProcessIDFromProcessName);
    lua_register(L, 'openProcess', openProcess);
    lua_register(L, 'debugProcess', debugProcess);
    lua_register(L, 'debug_getBreakpointList', debug_getBreakpointList);
    lua_register(L, 'debug_isDebugging', debug_isDebugging);
    lua_register(L, 'debug_getCurrentDebuggerInterface', debug_getCurrentDebuggerInterface);
    lua_register(L, 'debug_canBreak', debug_canBreak);
    lua_register(L, 'debug_isBroken', debug_isBroken);
    lua_register(L, 'debug_setBreakpoint', debug_setBreakpoint);
    lua_register(L, 'debug_removeBreakpoint', debug_removeBreakpoint);
    lua_register(L, 'debug_continueFromBreakpoint', debug_continueFromBreakpoint);

    lua_register(L, 'debug_addThreadToNoBreakList', debug_addThreadToNoBreakList);
    lua_register(L, 'debug_removeThreadFromNoBreakList', debug_removeThreadFromNoBreakList);

    lua_register(L, 'debug_getContext', getDebugContext);
    lua_register(L, 'debug_setContext', setDebugContext);
    lua_register(L, 'debug_updateGUI', debug_updateGUI);

    lua_register(L, 'getDebugContext', getDebugContext);
    lua_register(L, 'setDebugContext', setDebugContext);



    lua_register(L, 'closeCE', closeCE);
    lua_register(L, 'hideAllCEWindows', hideAllCEWindows);
    lua_register(L, 'unhideMainCEwindow', unhideMainCEwindow);


    initializeLuaGroupbox;


    lua_register(L, 'createLabel', createLabel);
    lua_register(L, 'createSplitter', createSplitter);
    lua_register(L, 'createPaintBox', createPaintBox);

    lua_register(L, 'messageDialog', messageDialog);
    lua_register(L, 'speedhack_setSpeed', speedhack_setSpeed);
    lua_register(L, 'speedhack_getSpeed', speedhack_getSpeed);
    lua_register(L, 'injectDLL', injectDLL);
    lua_register(L, 'getAutoAttachList', getAutoAttachList);


    lua_register(L, 'generateAPIHookScript', generateAPIHookScript_lua);
    lua_register(L, 'createProcess', createProcess);
    lua_register(L, 'AOBScan', AOBScan);
    lua_register(L, 'AOBScanUnique', AOBScanUnique);
    lua_register(L, 'getOpenedProcessID', getOpenedProcessID);
    lua_register(L, 'getOpenedProcessHandle', getOpenedProcessHandle);
    lua_register(L, 'getAddress', getAddress);
    lua_register(L, 'getModuleSize', getModuleSize);
    lua_register(L, 'getAddressSafe', getAddressSafe);

    lua_register(L, 'waitForExports', waitForExports);
    lua_register(L, 'waitForDotNet', waitForDotNet);
    lua_register(L, 'waitForPDB', waitForPDB);
    lua_register(L, 'waitforExports', waitForExports);
    lua_register(L, 'waitforDotNet', waitForDotNet);
    lua_register(L, 'waitforPDB', waitForPDB);
    lua_register(L, 'searchPDBWhileLoading', searchPDBWhileLoading);
    lua_register(L, 'reinitializeSymbolhandler', reinitializeSymbolhandler);
    lua_register(L, 'reinitializeDotNetSymbolhandler', reinitializeDotNetSymbolhandler);
    lua_register(L, 'reinitializeSelfSymbolhandler', reinitializeSelfSymbolhandler);
    lua_register(L, 'enumModules', enumModules);




    //ce6.1
    lua_register(L, 'getNameFromAddress', getNameFromAddress);
    lua_register(L, 'inModule', inModule);
    lua_register(L, 'inSystemModule', inSystemModule);
    lua_register(L, 'getCommonModuleList', getCommonModuleList);

    initializeLuaImage;

    initializeLuaRasterImage;

    initializeLuaGenericHotkey;



    initializeLuaObject;
    InitializeLuaComponent;


    InitializeLuaControl;

    initializeLuaWinControl;

    initializeLuaStrings;
    initializeLuaStringlist;

    initializeLuaForm;
    initializeLuaPanel;

    initializeLuaEdit;





    initializeLuaMemo;


    InitializeLuaButton;

    lua_register(L, 'createToggleBox', createToggleBox);

    initializeLuaCheckbox;
    initializeLuaRadioGroup;
    initializeLuaListbox;
    initializeLuaCheckListbox;
    initializeLuaCombobox;
    initializeLuaProgressbar;
    initializeLuaTrackbar;


    initializeLuaListColumn;
    initializeLuaCollection;

    initializeLuaListColumns;


    initializeLuaListItem;


    initializeLuaListItems;


    initializeLuaListview;
    initializeLuaTreeview;
    initializeLuaTimer;





    lua_register(L, 'openDialog_execute', openDialog_execute);
    lua_register(L, 'createOpenDialog', createOpenDialog);
    lua_register(L, 'createSaveDialog', createSaveDialog);
    lua_register(L, 'createSelectDirectoryDialog', createSelectDirectoryDialog);


    lua_register(L, 'createMemoryStream', createMemoryStream);
    lua_register(L, 'createFileStream', createFileStream);
    lua_register(L, 'createStringStream', createStringStream);



    Lua_register(L, 'getSettingsForm', getSettingsForm);
    Lua_register(L, 'getMemoryViewForm', getMemoryViewForm);
    Lua_register(L, 'getMainForm', getMainForm);
    Lua_register(L, 'getAddressList', getAddressList);
    Lua_register(L, 'getFreezeTimer', getFreezeTimer);
    Lua_register(L, 'getUpdateTimer', getUpdateTimer);

    lua_register(L, 'setGlobalKeyPollInterval', setGlobalKeyPollInterval);
    lua_register(L, 'setGlobalDelayBetweenHotkeyActivation', setGlobalDelayBetweenHotkeyActivation);

    initializeLuaMemoryview;
    initializeLuaTableFile;

    InitializeLuaXMPlayer;


    Lua_register(L, 'writeRegionToFile', writeRegionToFile);
    Lua_register(L, 'readRegionFromFile', readRegionFromFile);

    Lua_register(L, 'registerSymbol', registersymbol);
    Lua_register(L, 'unregisterSymbol', unregistersymbol);
    Lua_register(L, 'getSymbolInfo', getSymbolInfo);

    Lua_register(L, 'resetLuaState', resetLuaState);
    Lua_register(L, 'reloadSettingsFromRegistry', reloadSettingsFromRegistry);


    InitializeLuaCheatComponent;


    initializeMemoryRecordHotkey;

    InitializeLuaAddresslist;



    Lua_register(L, 'createMemScan', createMemScan);
    Lua_register(L, 'getCurrentMemscan', getCurrentMemscan);

    InitializeMemscan;
    InitializeFoundlist;


    Lua_register(L, 'supportCheatEngine', supportCheatEngine);
    Lua_register(L, 'fuckCheatEngine', fuckCheatEngine);



    lua_register(L, 'inheritsFromObject', inheritsFromObject);
    lua_register(L, 'inheritsFromComponent', inheritsFromComponent);
    lua_register(L, 'inheritsFromControl', inheritsFromControl);
    lua_register(L, 'inheritsFromWinControl', inheritsFromWinControl);

    Lua_register(L, 'beep', beep);

    lua_register(L, 'dbk_initialize', dbk_initialize);
    lua_register(L, 'dbk_useKernelmodeOpenProcess', dbk_useKernelmodeOpenProcess);
    lua_register(L, 'dbk_useKernelmodeProcessMemoryAccess', dbk_useKernelmodeProcessMemoryAccess);
    lua_register(L, 'dbk_useKernelmodeQueryMemoryRegions', dbk_useKernelmodeQueryMemoryRegions);
    lua_register(L, 'dbk_usePhysicalMemoryAccess', dbk_usePhysicalMemoryAccess);
    lua_register(L, 'dbk_setSaferPhysicalMemoryScanning', dbk_setSaferPhysicalMemoryScanning);


    lua_register(L ,'dbk_readPhysicalMemory', lua_dbk_readphysicalmemory);
    lua_register(L ,'dbk_writePhysicalMemory', lua_dbk_writephysicalmemory);


    lua_register(L, 'dbk_getPEProcess', dbk_getPEProcess);
    lua_register(L, 'dbk_getPEThread', dbk_getPEThread);
    lua_register(L, 'dbk_executeKernelMemory', dbk_executeKernelMemory);
    lua_register(L, 'dbk_readMSR', dbk_readMSR);
    lua_register(L, 'dbk_writeMSR', dbk_writeMSR);


    lua_register(L, 'dbk_getCR0', dbk_getCR0);
    lua_register(L, 'dbk_getCR3', dbk_getCR3);
    lua_register(L, 'dbk_getCR4', dbk_getCR4);
    lua_register(L, 'dbk_test', lua_dbk_test);
    lua_register(L, 'dbvm_getCR0', dbvm_getCR0);
    lua_register(L, 'dbvm_getCR3', dbvm_getCR3);
    lua_register(L, 'dbvm_getCR4', dbvm_getCR4);
    lua_register(L, 'dbvm_readMSR', lua_dbvm_readMSR);
    lua_register(L, 'dbvm_writeMSR', lua_dbvm_writeMSR);
    lua_register(L, 'dbvm_jtagbp', lua_dbvm_jtagbp);
    lua_register(L ,'dbvm_readPhysicalMemory', lua_dbvm_readphysicalmemory);
    lua_register(L ,'dbvm_writePhysicalMemory', lua_dbvm_writephysicalmemory);
    lua_register(L ,'dbvm_psod', lua_dbvm_psod);
    lua_register(L ,'dbvm_getNMIcount', lua_dbvm_getNMIcount);
    lua_register(L, 'dbvm_get_statistics',lua_dbvm_get_statistics);
    lua_register(L, 'dbvm_watch_writes', lua_dbvm_watch_writes);
    lua_register(L, 'dbvm_watch_reads', lua_dbvm_watch_reads);
    lua_register(L, 'dbvm_watch_executes', lua_dbvm_watch_executes);
    lua_register(L, 'dbvm_watch_retrievelog', lua_dbvm_watch_retrievelog);
    lua_register(L, 'dbvm_watch_disable', lua_dbvm_watch_disable);

    lua_register(L, 'dbvm_cloak_activate', lua_dbvm_cloak_activate);
    lua_register(L, 'dbvm_cloak_deactivate', lua_dbvm_cloak_deactivate);
    lua_register(L, 'dbvm_cloak_readOriginal', lua_dbvm_cloak_readOriginal);
    lua_register(L, 'dbvm_cloak_writeOriginal', lua_dbvm_cloak_writeOriginal);
    lua_register(L, 'dbvm_changeregonbp', lua_dbvm_changeregonbp);
    lua_register(L, 'dbvm_removechangeregonbp', lua_dbvm_removechangeregonbp);

    lua_register(L, 'dbvm_ept_reset', lua_dbvm_ept_reset);
    lua_register(L, 'dbvm_log_cr3_start', lua_dbvm_log_cr3_start);
    lua_register(L, 'dbvm_log_cr3_stop', lua_dbvm_log_cr3_stop);
    lua_register(L, 'dbvm_registerPlugin', lua_dbvm_registerPlugin);
    lua_register(L, 'dbvm_raisePMI', lua_dbvm_raisePMI); //mostly just for debugging
    lua_register(L, 'dbvm_ultimap2_hideRangeUsage', lua_dbvm_ultimap2_hideRangeUsage); //same
    lua_register(L, 'dbvm_ultimap_getDebugInfo', lua_dbvm_ultimap_getDebugInfo); //more debugging

    lua_register(L, 'dbvm_setTSCAdjust', lua_dbvm_setTSCAdjust);
    lua_register(L, 'dbvm_speedhack_setSpeed', lua_dbvm_speedhack_setSpeed);


    lua_register(L, 'dbvm_enableTSCHook', lua_dbvm_enableTSCHook);
    lua_register(L, 'dbvm_disableTSCHook', lua_dbvm_disableTSCHook);

    lua_register(L, 'dbvm_findCR3', lua_dbvm_findCR3);


    lua_register(L, 'dbk_getPhysicalAddress', dbk_getPhysicalAddress);
    lua_register(L, 'dbk_writesIgnoreWriteProtection', dbk_writesIgnoreWriteProtection);

    lua_register(L, 'getPhysicalAddressCR3', lua_getPhysicalAddressCR3);
    lua_register(L, 'readProcessMemoryCR3', lua_readProcessMemoryCR3);
    lua_register(L, 'writeProcessMemoryCR3', lua_writeProcessMemoryCR3);



    lua_register(L, 'allocateSharedMemoryLocal', allocateSharedMemoryLocal);
    lua_register(L, 'deallocateSharedMemoryLocal', deallocateSharedMemoryLocal);

    lua_register(L, 'allocateSharedMemory', allocateSharedMemory);
    lua_register(L, 'deallocateSharedMemory', deallocateSharedMemory);
    lua_register(L, 'getCheatEngineDir', getCheatEngineDir);
    lua_register(L, 'getCheatEngineProcessID', lua_getCheatEngineProcessID);

    lua_register(L, 'disassemble', disassemble_lua);
    lua_register(L, 'splitDisassembledString', splitDisassembledString);
    lua_register(L, 'getInstructionSize', getInstructionSize);
    lua_Register(L, 'getPreviousOpcode', getPreviousOpcode);

    initializegraphiccontrol;

    lua_register(L, 'disassemblerview_getSelectedAddress', disassemblerview_getSelectedAddress);
    lua_register(L, 'disassemblerview_setSelectedAddress', disassemblerview_setSelectedAddress);
    lua_register(L, 'disassemblerview_onSelectionChange', disassemblerview_onSelectionChange);

    lua_register(L, 'hexadecimalview_getTopAddress', hexadecimalview_getTopAddress);
    lua_register(L, 'hexadecimalview_setTopAddress', hexadecimalview_setTopAddress);
    lua_register(L, 'hexadecimalview_onAddressChange', hexadecimalview_onAddressChange);
    lua_register(L, 'hexadecimalview_onByteSelect', hexadecimalview_onByteSelect);



    lua_register(L, 'getForegroundProcess', getForegroundProcess);

    lua_register(L, 'cheatEngineIs64Bit', cheatEngineIs64Bit);
    lua_register(L, 'targetIs64Bit', targetIs64Bit);

    lua_register(L, 'getFormCount', getFormCount);
    lua_register(L, 'getForm', getForm);
    lua_register(L, 'registerFormAddNotification', registerFormAddNotification);
    Lua_Register(L, 'unregisterFormAddNotification', unregisterFormAddNotification);


    lua_register(L, 'onAutoGuess', onAutoGuess);
    lua_register(L, 'onAPIPointerChange', onAPIPointerChange);

    lua_register(L, 'setAPIPointer', setAPIPointer);

    lua_register(L, 'dbvm_initialize', dbvm_initialize);
    lua_register(L, 'dbvm_addMemory', dbvm_addMemory);

    lua_register(L, 'shellExecute', lua_shellExecute);
    lua_register(L, 'getTickCount', getTickCount_lua);
    lua_register(L, 'processMessages', processMessages);

    lua_register(L, 'integerToUserData', integerToUserData);
    lua_register(L, 'userDataToInteger', userDataToInteger);



    lua_register(L, 'writeToClipboard', writeToClipboard);
    lua_register(L, 'readFromClipboard', readFromClipboard);

    lua_register(L, 'createBitmap', createBitmap);
    lua_register(L, 'createPNG', createPNG);
    lua_register(L, 'createJpeg', createJpeg);
    lua_register(L, 'createIcon', createIcon);
    lua_register(L, 'errorOnLookupFailure', errorOnLookupFailure);
    lua_register(L, 'waitforsymbols', lua_waitforsymbols);

    lua_register(L, 'loadPlugin', loadPlugin);

    lua_register(L, 'getCEVersion', getCEVersion);

    lua_register(L, 'utf8ToAnsi', lua_Utf8ToAnsi);
    lua_register(L, 'UTF8ToAnsi', lua_Utf8ToAnsi);
    lua_register(L, 'ansiToUtf8', lua_AnsiToUtf8);
    lua_register(L, 'ansiToUTF8', lua_AnsiToUtf8);



    lua_register(L, 'fullAccess', fullAccess);

    lua_register(L, 'getWindowlist', getWindowList_lua);
    lua_register(L, 'getWindowList', getWindowList_lua);

    lua_register(L, 'getProcesslist', getProcessList_lua);
    lua_register(L, 'getProcessList', getProcessList_lua);
    lua_register(L, 'getThreadlist', getThreadlist_lua);
    lua_register(L, 'getThreadList', getThreadlist_lua);

    Lua_register(L, 'loadTable', lua_loadTable);
    Lua_register(L, 'saveTable', lua_saveTable);
    Lua_register(L, 'detachIfPossible', lua_DetachIfPossible);
    Lua_register(L, 'getComment', getComment);
    Lua_register(L, 'setComment', setComment);
    Lua_register(L, 'getHeader', getHeader);
    Lua_register(L, 'setHeader', setHeader);

    lua_register(L, 'createClass', lua_createClass);
    lua_register(L, 'createComponentClass', lua_createComponentClass);

    lua_register(L, 'openLuaServer', openLuaServer);

    lua_register(L, 'registerAutoAssemblerCommand', lua_registerAutoAssemblerCommand);
    lua_register(L, 'unregisterAutoAssemblerCommand', lua_unregisterAutoAssemblerCommand);

    lua_register(L, 'registerSymbolLookupCallback', lua_registerSymbolLookupCallback);
    lua_register(L, 'unregisterSymbolLookupCallback', lua_unregisterSymbolLookupCallback);
    lua_register(L, 'registerAddressLookupCallback', lua_registerAddressLookupCallback);
    lua_register(L, 'unregisterAddressLookupCallback', lua_unregisterAddressLookupCallback);

    lua_register(L, 'registerGlobalDisassembleOverride', lua_registerGlobalDisassembleOverride);
    lua_register(L, 'unregisterGlobalDisassembleOverride', lua_unregisterGlobalDisassembleOverride);

    lua_register(L, 'registerStructureDissectOverride', lua_registerStructureDissectOverride);
    lua_register(L, 'unregisterStructureDissectOverride', lua_unregisterStructureDissectOverride);

    lua_register(L, 'registerStructureNameLookup', lua_registerStructureNameLookup);
    lua_register(L, 'unregisterStructureNameLookup', lua_unregisterStructureNameLookup);

    lua_register(L, 'registerAssembler', lua_registerAssembler);
    lua_register(L, 'unregisterAssembler', lua_unregisterAssembler);

    lua_register(L, 'registerAutoAssemblerPrologue', lua_registerAutoAssemblerPrologue);
    lua_register(L, 'unregisterAutoAssemblerPrologue', lua_unregisterAutoAssemblerPrologue);

    lua_register(L, 'registerStructureAndElementListCallback', lua_registerStructureAndElementListCallback);
    lua_register(L, 'unregisterStructureAndElementListCallback', lua_unregisterStructureAndElementListCallback);




    lua_register(L, 'shortCutToText', lua_shortCutToText);
    lua_register(L, 'textToShortCut', lua_textToShortCut);

    lua_register(L, 'inMainThread', inMainThread);
    lua_register(L, 'synchronize', lua_synchronize);
    lua_register(L, 'queue', lua_queue);
    lua_register(L, 'checkSynchronize', lua_checkSynchronize);

    lua_register(L, 'playSound', lua_playSound);

    lua_register(L, 'outputDebugString', lua_outputDebugString);
    lua_register(L, 'broadcastEnvironmentUpdate', broadcastEnvironmentUpdate);
    lua_register(L, 'getUserRegistryEnvironmentVariable', getUserRegistryEnvironmentVariable);
    lua_register(L, 'setUserRegistryEnvironmentVariable', setUserRegistryEnvironmentVariable);

    lua_register(L, 'createRef', createRef);
    lua_register(L, 'getRef', getRef);
    lua_register(L, 'destroyRef', destroyRef);

    lua_register(L, 'activateProtection', activateProtection);
    lua_register(L, 'getLuaEngine', getLuaEngine);
    lua_register(L, 'getApplication', getApplication);

    lua_Register(L, 'stringToMD5String', lua_stringToMD5String);
    lua_register(L, 'convertKeyComboToString', lua_ConvertKeyComboToString);
    lua_register(L, 'restoreSeDebugPrivilege', restoreSeDebugPrivilege);

    lua_register(L, 'translate', lua_translate);
    lua_register(L, 'translateID', lua_translateid);
    lua_register(L, 'loadPOFile', lua_loadPOFile);
    lua_register(L, 'getTranslationFolder', lua_getTranslationFolder);

    lua_register(L, 'registerBinUtil', lua_registerBinUtil);
    lua_register(L, 'setPointerSize', setPointerSize);


    lua_register(L, 'executeCode', executeCode);
    lua_register(L, 'executeCodeEx', executeCodeEx);
    lua_register(L, 'executeMethod', executeMethod);


    lua_register(L, 'executeCodeLocal', executeCodeLocal);
    lua_register(L, 'executeCodeLocalEx', executeCodeLocalEx);

    lua_register(L, 'md5file', md5file);
    lua_register(L, 'md5memory', md5memory);

    lua_register(L, 'allocateKernelMemory', allocateKernelMemory);
    lua_register(L, 'freeKernelMemory', freeKernelMemory);

    lua_register(L, 'mapMemory', lua_mapMemory);
    lua_register(L, 'unmapMemory', lua_unmapMemory);

    lua_register(L, 'lockMemory', lua_lockMemory);
    lua_register(L, 'unlockMemory', lua_unlockMemory);

    lua_register(L, 'sendMessage', lua_sendMessage);
    lua_register(L, 'sendMessageTimeout', lua_sendMessageTimeout);

    lua_register(L, 'findWindow', lua_findWindow);
    lua_register(L, 'getWindow', lua_getWindow);
    lua_register(L, 'getWindowProcessID', lua_getWindowProcessID);
    lua_register(L, 'getWindowCaption', lua_getWindowCaption);
    lua_register(L, 'getWindowClassName', lua_getWindowClassName);
    lua_register(L, 'getForegroundWindow', lua_getForegroundWindow);


    lua_register(L, 'getXBox360ControllerKeyPress', getXBox360ControllerKeyPress);
    lua_register(L, 'getXBox360ControllerState', getXBox360ControllerState);
    lua_register(L, 'setXBox360ControllerVibration', setXBox360ControllerVibration);

    lua_register(L, 'registerAutoAssemblerTemplate', lua_registerAutoAssemblerTemplate);
    lua_register(L, 'unregisterAutoAssemblerTemplate', lua_unregisterAutoAssemblerTemplate);

    lua_register(L, 'generateCodeInjectionScript', lua_GenerateCodeInjectionScript);
    lua_register(L, 'generateAOBInjectionScript', lua_GenerateAOBInjectionScript);
    lua_register(L, 'generateFullInjectionScript', lua_GenerateFullInjectionScript);

    lua_register(L, 'loadFontFromStream', lua_loadFontFromStream);
    lua_register(L, 'unloadLoadedFont', lua_unloadLoadedFont);

    lua_register(L, 'speak', lua_speak);
    lua_register(L, 'speakEnglish', lua_speakEnglish);

    lua_register(L, 'getFileVersion', lua_getFileVersion);
    lua_register(L, 'getCheatEngineFileVersion', lua_getCheatEngineFileVersion);


    lua_register(L, 'hookWndProc', lua_hookWndProc);
    lua_register(L, 'unhookWndProc', lua_unhookWndProc);

    lua_register(L, 'registerEXETrainerFeature', lua_registerEXETrainerFeature);
    lua_register(L, 'unregisterEXETrainerFeature', lua_unregisterEXETrainerFeature);

    lua_register(L, 'encodeFunction', lua_encodefunction);
    lua_register(L, 'decodeFunction', lua_decodeFunction);

    lua_register(L, 'encodeFunctionEx', lua_encodefunctionEx);

    lua_register(L, 'getFileList', lua_getFileList);
    lua_register(L, 'getDirectoryList', lua_getDirectoryList);

    lua_register(L, 'connectToCEServer', lua_connectToCEServer);

    lua_register(L, 'copyMemory', lua_copyMemory);
    lua_register(L, 'enableDRM', lua_enableDRM);

    lua_register(L, 'openFileAsProcess', lua_openFileAsProcess);
    lua_register(L, 'saveOpenedFile', lua_saveOpenedFile);


    lua_register(L, 'getPEB', lua_getPEB);

    lua_register(L, 'createAPC', lua_createAPC);
    lua_register(L, 'setAssemblerMode', lua_setAssemblerMode);
    lua_register(L, 'allocateMemory', lua_allocateMemory);

    lua_register(L, 'try', lua_try);

    lua_register(L, 'createSection',lua_createSection);
    lua_register(L, 'mapViewOfSection',lua_MapViewOfSection);
    lua_register(L, 'unMapViewOfSection', lua_unMapViewOfSection);

    lua_register(L, 'getSystemMetrics', lua_getSystemMetrics);

    lua_register(L, 'getScreenHeight', lua_getScreenHeight);
    lua_register(L, 'getScreenWidth', lua_getScreenWidth);
    lua_register(L, 'getScreenDPI', lua_getScreenDPI);

    lua_register(L, 'getWorkAreaHeight', lua_getWorkAreaHeight);
    lua_register(L, 'getWorkAreaWidth', lua_getWorkAreaWidth);


    lua_register(L, 'getScreenCanvas', lua_getScreenCanvas);
    lua_register(L, 'getHandleList', lua_getHandleList);
    lua_register(L, 'closeRemoteHandle', lua_closeRemoteHandle);

    lua_register(L, 'showSelectionList', lua_showSelectionList);
    lua_register(L, 'cpuid', lua_cpuid);
    lua_register(L, 'gc_setPassive', lua_gc_setPassive);
    lua_register(L, 'gc_setActivate', lua_gc_setPassive);

    lua_register(L, 'getHotkeyHandlerThread', lua_getHotkeyHandlerThread);
    lua_register(L, 'enumMemoryRegions', lua_enumMemoryRegions);
    lua_register(L, 'enableWindowsSymbols', lua_enableWindowsSymbols);
    lua_register(L, 'enableKernelSymbols', lua_enableKernelSymbols);

    lua_register(L, 'compareMemory', lua_compareMemory);

    lua_register(L, 'enumExports', lua_enumExports);
    lua_register(L, 'duplicateHandle', lua_duplicateHandle);

    lua_register(L, 'getOperatingSystem', lua_getOperatingSystem);
    lua_register(L, 'createColorDialog', lua_createColorDialog);
    lua_register(L, 'createColorBox', lua_createColorBox);
    lua_register(L, 'createAutoAssemblerForm', lua_createAutoAssemblerForm);
    lua_register(L, 'getRTTIClassName', lua_getRTTIClassName);

    lua_register(L, 'getAutoRunPath', lua_getAutoRunPath);
    lua_register(L, 'getAutorunPath', lua_getAutoRunPath);



    initializeLuaRemoteThread;

    initializeLuaCustomControl;
    initializeLuaPicture;
    initializeLuaPen;
    initializeLuaBrush;
    initializeLuaFont;
    initializeLuaCanvas;
    initializeLuaMenu;

    initializeLuaDebug; //eventually I should add a LuaLuaDebug...
    initializeLuaThread;
    initializeLuaGraphic;
    initializeLuaOldD3DHook;
    initializeLuaD3DHook;
    initializeLuaStructure;
    initializeLuaRegion;
    initializeLuaDisassembler;
    initializeLuaDissectCode;
    initializeLuaByteTable;
    initializeLuaBinary;
    {$IFDEF windows}
    initializeLuaPipeClient;
    initializeLuaPipeServer;
    {$ENDIF}
    initializeLuaSymbolListHandler;
    initializeLuaFindDialog;
    initializeLuaSettings;
    initializeLuaPageControl;

    initializeLuaCalendar;
    initializeLuaRipRelativeScanner;


    initializeLuaStructureFrm;
    initializeLuaInternet;
    initializeLuaCustomType;
    initializeLuaSQL;
    {$IFDEF windows}
    initializeLuaModuleLoader;
    {$ENDIF}
    initializeLuaPointerValueList;
    initializeLuaWriteLog;

    initializeLuaDiagram;
    initializeLuaUltimap2;
    initializeLuaCodeFilter;
    initializeLuaSynEdit;
    initializeLuaCustomImageList;





    s:=tstringlist.create;
    try
      //ce 6.0 compatibility. 6.0 has these methods in the stringlist instead of the strings class
      s.add('package.path = package.path .. ";?.lua";');
      {$ifdef darwin}
      s.add('package.path = package.path .. [[;'+getcedir+'?.lua]]');
      s.add('package.path = package.path .. [[;'+extractfiledir(extractfiledir(application.exename))+'/Lua/?.lua]]');
      {$endif}


{$ifdef cpu64}
      s.add('package.cpath = package.cpath .. [[;'+getcedir+'clibs64'+pathdelim+'?'+{$ifdef windows}'.dll'{$endif}{$ifdef darwin}'.dylib'{$endif}+']]');
      s.add('package.cpath = package.cpath .. [[;.'+pathdelim+'clibs64'+pathdelim+'?'+{$ifdef windows}'.dll'{$endif}{$ifdef darwin}'.dylib'{$endif}+']]');
{$else}
      s.add('package.cpath = package.cpath .. [[;'+getcedir+'clibs32'+pathdelim+'?'+{$ifdef windows}'.dll'{$endif}{$ifdef darwin}'.dylib'{$endif}+']]');
      s.add('package.cpath = package.cpath .. [[;.'+pathdelim+'clibs32'+pathdelim+'?'+{$ifdef windows}'.dll'{$endif}{$ifdef darwin}'.dylib'{$endif}+']]');
{$endif}
      s.add('stringlist_getCount=strings_getCount');
      s.add('stringlist_getString=strings_getString');
      s.add('stringlist_add=strings_add');
      s.add('stringlist_remove=strings_remove');

      //same for the rename of memrec to memoryrecord
      s.add('memrec_setDescription = memoryrecord_setDescription');
      s.add('memrec_getDescription = memoryrecord_getDescription');
      s.add('memrec_getAddress = memoryrecord_getAddress');
      s.add('memrec_setAddress = memoryrecord_setAddress');
      s.add('memrec_getType = memoryrecord_getType');
      s.add('memrec_setType = memoryrecord_setType');
      s.add('memrec_getValue = memoryrecord_getValue');
      s.add('memrec_setValue = memoryrecord_setValue');
      s.add('memrec_getScript = memoryrecord_getScript');
      s.add('memrec_isActive = memoryrecord_isActive');
      s.add('memrec_freeze = memoryrecord_freeze');
      s.add('memrec_unfreeze = memoryrecord_unfreeze');
      s.add('memrec_setColor = memoryrecord_setColor');
      s.add('memrec_appendToEntry = memoryrecord_appendToEntry');
      s.add('memrec_delete = memoryrecord_delete');
      s.add('getAddressFromName = getAddress');

      //timer onInterval has been renamed to timer onTimer
      s.add('timer_onInterval = timer_onTimer');


      {$ifdef windows}
      k32:=loadlibrary('kernel32.dll');
      s.add('windows_OpenProcess=0x'+inttohex(ptruint(getProcAddress(k32, 'OpenProcess')),8));
      s.add('windows_ReadProcessMemory=0x'+inttohex(ptruint(getProcAddress(k32, 'ReadProcessMemory')),8));
      s.add('windows_WriteProcessMemory=0x'+inttohex(ptruint(getProcAddress(k32, 'WriteProcessMemory')),8));
      s.add('windows_VirtualQueryEx=0x'+inttohex(ptruint(getProcAddress(k32, 'VirtualQueryEx')),8));


      s.add('dbk_OpenProcess=0x'+inttohex(ptruint(@DBK32functions.OP),8));
      s.add('dbk_NtOpenProcess=0x'+inttohex(ptruint(@DBK32functions.NOP),8));
      s.add('dbk_ReadProcessMemory=0x'+inttohex(ptruint(@DBK32functions.RPM),8));
      s.add('dbk_WriteProcessMemory=0x'+inttohex(ptruint(@DBK32functions.WPM),8));
      s.add('dbk_VirtualQueryEx=0x'+inttohex(ptruint(@DBK32functions.VQE),8));
      s.add('dbk_ReadPhysicalMemory=0x'+inttohex(ptruint(@DBK32functions.ReadPhysicalMemory),8));
      s.add('dbk_WritePhysicalMemory=0x'+inttohex(ptruint(@DBK32functions.WritePhysicalMemory),8));
      s.add('VirtualQueryExPhysical=0x'+inttohex(ptruint(@VirtualQueryExPhysical),8));

      s.add('dbvm_ReadPhysicalMemory=0x'+inttohex(ptruint(@vmxfunctions.dbvm_read_physical_memory),8));
      s.add('dbvm_WritePhysicalMemory=0x'+inttohex(ptruint(@vmxfunctions.dbvm_write_physical_memory),8));


      s.add('dbvm_block_interrupts=0x'+inttohex(ptruint(@vmxfunctions.dbvm_block_interrupts),8));
      s.add('dbvm_raise_privilege=0x'+inttohex(ptruint(@vmxfunctions.dbvm_raise_privilege),8));
      s.add('dbvm_restore_interrupts=0x'+inttohex(ptruint(@vmxfunctions.dbvm_restore_interrupts),8));
      s.add('dbvm_changeselectors=0x'+inttohex(ptruint(@vmxfunctions.dbvm_changeselectors),8));
      {$endif}

      //5.2 backward compatibility:
      s.add('math.log10=function(v) return math.log(v,10) end');
      s.add('loadstring=load');
      s.add('unpack=table.unpack');
      s.add('package.loaders=package.searchers');

      //5.3 backward compatibility:
      s.add('math.pow=function(x,y) return x^y end');
      s.add('math.atan2=math.atan');
      s.add('math.ldexp=function(x,exp) return x * 2.0^exp end');
      s.add('math.mod=math.fmod');
      s.add('string.gfind=string.gmatch');

      s.add('BinUtils={}');

      lua_doscript(s.text);

      lua_getglobal(L, 'math');
      i:=lua_gettop(L);

      lua_pushstring(L, 'frexp');
      lua_pushcfunction(L, lua_frexp);
      lua_settable(L,i);

      lua_pushstring(L, 'cosh');
      lua_pushcfunction(L, lua_cosh);
      lua_settable(L,i);

      lua_pushstring(L, 'sinh');
      lua_pushcfunction(L, lua_sinh);
      lua_settable(L,i);

      lua_pushstring(L, 'tanh');
      lua_pushcfunction(L, lua_tanh);
      lua_settable(L,i);


      lua_settop(L,i-1);


      {$ifdef darwin}
      autorunpath:=extractfiledir(extractfiledir(Application.ExeName))+'/Lua/Autorun/';
      {$else}
      autorunpath:=CheatEngineDir+'autorun'+pathdelim;
      {$endif}


    finally
      s.free;
    end;
  end;

end;

var
  tm: TThreadManager;
  oldReleaseThreadVars: procedure;

procedure ReleaseLuaThreadVars;
begin
  if Thread_LuaVM<>nil then
  begin
    if Thread_LuaRef<>0 then
      lua_unref(Thread_LuaVM, Thread_LuaRef);

    Thread_LuaVM:=nil;
  end;

  if assigned(oldReleaseThreadVars) then
    oldReleaseThreadVars();
end;

initialization
  _LuaCS:=TCriticalSection.create;
  luarefcs:=TCriticalSection.create;

  GetThreadManager(tm);
  oldReleaseThreadVars:=tm.ReleaseThreadVars;
  tm.ReleaseThreadVars:=@ReleaseLuaThreadVars;
  SetThreadManager(tm);


  InitializeLua;



finalization
  if _LuaCS<>nil then
    _LuaCS.free;

  if _LuaVM<>nil then
    lua_close(_LuaVM);

end.


