Исходник Гайд AHK-LUA-API

Тема в разделе "AutoHotKey", создана пользователем Rinat_Namazov, 3 окт 2018.

  1. Rinat_Namazov

    Rinat_Namazov ( ͡° ͜ʖ ͡°)
    Всефорумный модератор

    Регистрация:
    9 авг 2015
    Сообщения:
    1.134
    Симпатии:
    579
    AHK-LUA-API
    API для взаимодействия LUA и AHK.
    API состоит из файла AHK-LUA-API.ahk, для работы требуется lua51.dll.
    Для подключения библиотеки нужно вписать в начало скрипта следующий код:
    #include AHK-LUA-API.ahk
    Перед тем как вызывать функции нужно подгрузить lua51.dll в процесс ахк.
    DllCall("kernel32.dll\LoadLibrary", "Str", A_ScriptDir "\lua51.dll")


    Примеры:
    Вызов AHK функции из Lua:
    
    L := luaL_newstate()
    lua_register(L, "MsgBox", "LUAFUNC_MsgBox")
    lua_register(L, "Test", "LUAFUNC_Test")
    
    code =
    (
        sum = Test(228, 1337, 666)
        MsgBox("sum = " .. sum)
    )
    
    luaL_doString(L, code)
    lua_close(L)
    
    LUAFUNC_MsgBox(L)
    {
        MsgBox, % lua_tostring(L, 1)
        return 0
    }
    
    LUAFUNC_Test(L)
    {
        sum := 0
        n := lua_gettop(L)
        loop % n
            sum += lua_tonumber(L, A_Index)
        lua_pushnumber(L, sum)
        return 1
    }
    
    Вызов Lua функции из AHK:
    
    L := luaL_newstate()
    
    code =
    (
        function add(x, y)
            return x + y
        end
    )
    
    luaL_doString(L, code)
    MsgBox, % LUAFUNC_add(L, 5, 13)
    lua_close(L)
    
    LUAFUNC_add(L, x, y)
    {
       lua_getglobal(L, "add")
       lua_pushnumber(L, x)
       lua_pushnumber(L, y)
       lua_call(L, 2, 1)
       sum := lua_tointeger(L, -1)
       lua_pop(L, 1)
       return sum
    }
    
    Чтение Lua переменных:
    
    L := luaL_newstate()
    
    code =
    (
        var = "String"
    )
    
    luaL_doString(L, code)
    
    lua_getglobal(L, "var")
    MsgBox, % lua_tostring(L, -1)
    
    lua_close(L)
    
    Активация функции на клавишу, через AHK:
    
    L := luaL_newstate()
    
    lua_register(L, "MsgBox", "LUAFUNC_MsgBox")
    lua_register(L, "Hotkey", "LUAFUNC_Hotkey")
    
    code =
    (
        Hotkey("!1", "Show", "On")
        function Show(ThisHotKey)
            MsgBox("ThisHotKey = " .. ThisHotKey)
        end
    )
    
    luaL_doString(L, code)
    
    LUAFUNC_MsgBox(L)
    {
        MsgBox, % lua_tostring(L, 1)
        return 0
    }
    
    LUAFUNC_Hotkey(L)
    {
        static HotKeyCount := 0, ARGS := {}
        ARGS.Push({L: L, ARG1: lua_tostring(L, 1), ARG2: lua_tostring(L, 2), ARG3: lua_tostring(L, 3)})
        HotKeyCount++
        Hotkey, % ARGS[HotKeyCount]["ARG1"], LuaHotKey, % ARGS[HotKeyCount]["ARG3"]
        lua_pushnumber(L, ErrorLevel)
        return 1
     
        LuaHotKey:
            for k, v in ARGS
            {
                if (A_ThisHotkey == v["ARG1"])
                {
                    lua_getglobal(v["L"], v["ARG2"])
                    lua_pushstring(v["L"], A_ThisHotkey)
                    lua_call(v["L"], 1, 0)
                }
            }
        return
    }
    
    Экспорты луа апи генерируются автоматический:
    
    result = ; Переменная в которую будеть писаться сгенерирвованный код.
    (
    /*
        AHK-LUA-API
     
        MIT License
    
        Copyright (c) 2018 Rinat_Namazov
    
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
    
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
    
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
    */
    
    global LUAJIT_MODE_ENGINE        := 0    ; Set mode for whole JIT engine.
    global LUAJIT_MODE_DEBUG        := 1    ; Set debug mode (idx = level).
    global LUAJIT_MODE_FUNC            := 2    ; Change mode for a function.
    global LUAJIT_MODE_ALLFUNC        := 3    ; Recurse into subroutine protos.
    global LUAJIT_MODE_ALLSUBFUNC    := 4    ; Change only the subroutines.
    global LUAJIT_MODE_TRACE        := 5    ; Flush a compiled trace.
    global LUAJIT_MODE_WRAPCFUNC    := 0x10 ; Set wrapper mode for C function calls.
    global LUAJIT_MODE_MAX
    global LUA_TNONE                := -1
    global LUA_TNIL                    := 0
    global LUA_TBOOLEAN                := 1
    global LUA_TLIGHTUSERDATA        := 2
    global LUA_TNUMBER                := 3
    global LUA_TSTRING                := 4
    global LUA_TTABLE                := 5
    global LUA_TFUNCTION            := 6
    global LUA_TUSERDATA            := 7
    global LUA_TTHREAD                := 8
    global LUA_REGISTRYINDEX        := -10000
    global LUA_ENVIRONINDEX            := -10001
    global LUA_GLOBALSINDEX            := -10002
    global BUFSIZ                    := 512
    global LUAL_BUFFERSIZE            := (BUFSIZ > 16384 ? 8192 : BUFSIZ)
    global LUA_GCSTOP                := 0
    global LUA_GCRESTART            := 1
    global LUA_GCCOLLECT            := 2
    global LUA_GCCOUNT                := 3
    global LUA_GCCOUNTB                := 4
    global LUA_GCSTEP                := 5
    global LUA_GCSETPAUSE            := 6
    global LUA_GCSETSTEPMUL            := 7
    
    lua_pop(ByRef L, n)
    {
        lua_settop(L, -n - 1)
    }
    
    lua_newtable(ByRef L)
    {
        return lua_createtable(L, 0, 0)
    }
    
    lua_register(ByRef L, n, f)
    {
        if f is not integer
            f := RegisterCallback(f, "CDecl")
        lua_pushcfunction(L, f)
        lua_setglobal(L, n)
    }
    
    lua_pushcfunction(ByRef L, f)
    {
        return lua_pushcclosure(L, f, 0)
    }
    
    lua_strlen(ByRef L, i)
    {
        return lua_objlen(L, i)
    }
    
    lua_isfunction(ByRef L, n)
    {
        return (lua_type(L, n) == LUA_TFUNCTION)
    }
    
    lua_istable(ByRef L, n)
    {
        return (lua_type(L, n) == LUA_TTABLE)
    }
    
    lua_islightuserdata(ByRef L, n)
    {
        return (lua_type(L, n) == LUA_TLIGHTUSERDATA)
    }
    
    lua_isnil(ByRef L, n)
    {
        return (lua_type(L, n) == LUA_TNIL)
    }
    
    lua_isboolean(ByRef  L, n)
    {
        return (lua_type(L, n) == LUA_TBOOLEAN)
    }
    
    lua_isthread(ByRef  L, n)
    {
        return (lua_type(L, n) == LUA_TTHREAD)
    }
    
    lua_isnone(ByRef L, n)
    {
        return (lua_type(L, n) == LUA_TNONE)
    }
    
    lua_isnoneornil(ByRef L, n)
    {
        return (lua_type(L, n) <= 0)
    }
    
    lua_pushliteral(ByRef L, s)
    {
        return lua_pushlstring(L, s, strlen(s))
    }
    
    lua_setglobal(ByRef L, s)
    {
        return lua_setfield(L, LUA_GLOBALSINDEX, s)
    }
    
    lua_getglobal(ByRef L, s)
    {
        return lua_getfield(L, LUA_GLOBALSINDEX, s)
    }
    
    lua_tostring(ByRef L, i)
    {
        return lua_tolstring(L, i, 0)
    }
    
    lua_open()
    {
        return luaL_newstate()
    }
    
    lua_getregistry(ByRef L)
    {
        return lua_pushvalue(L, LUA_REGISTRYINDEX)
    }
    
    lua_getgccount(ByRef L)
    {
        return lua_gc(L, LUA_GCCOUNT, 0)
    }
    
    lua_upvalueindex(i)
    {
        return LUA_GLOBALSINDEX - i
    }
    
    luaL_dofile(ByRef L, fn)
    {
        luaL_loadfile(L, fn)
        return lua_pCall(l, 0, -1, 0)
    }
    
    luaL_dostring(ByRef L, ByRef s)
    {
        luaL_loadstring(L, s)
        return lua_pCall(L, 0, -1, 0)
    }
    )
    
    
    GetType(type, isRetVal := false)
    {
        types := { "lua_State": "Ptr"
            , "int": "Int"
            , "size_t": "Int"
            , "const char": "Str"
            , "lua_Integer": "Int"
            , "lua_Number": "Double" }
        if (isRetVal && type == "void")
            return ""
        if (types[type] != "")
            return (isRetVal ? " " : "") types[type]
        return (isRetVal ? " " : "") "UInt" ; const luaL_Reg, luaL_Buffer, lua_Alloc, lua_CFunction, const lua_Debug, lua_Debug, lua_Hook, lua_Reader, lua_Writer
    }
    FuncList := ["LUAJIT_VERSION_SYM"]
    
    Loop, LuaJIT-master\src\*.c ; Проходимся по всем файлам с расширением ".c" исходника LUA-JIT.
    {
        A_FileText := "", fpos := 1 ; Позиция с которого начинается поиск по шаблону.
        Loop, Read, %A_LoopFileFullPath% ; Читаем построчно файл.
        {
            TrimLine := Trim(A_LoopReadLine) ; Убираем лишние символы (\n|\r|\s|\t).
            if (TrimLine != "") ; Если строка не пустая.
                A_FileText .= TrimLine ; Добавляем строку без переноса.
        }
        while (npos := RegExMatch(A_FileText, "mUS)(LUALIB_API|LUA_API)\s(?<Type>[a-zA-Z0-9_\s]+)\s(?<IsPtrOrAddrOrDefault>[*&]{0,1})(?<Name>[a-zA-Z0-9_]+)\((?<Params>.*)\)", Func_, fpos)) ; Поиск функций.
        {
            fpos := npos + strlen(Func_) ; Прибавляем к позиции длину вхождения.
            IsContinue := false
            for k, v in FuncList ; Поиск функции, вдруг она уже найдена.
            {
                if (Func_Name == v)
                    IsContinue := true ; Функция найдена.
            }
            if (IsContinue) ; Если функция уже найдена.
                continue ; Пропускаем.
            AhkFuncParams := "", DllCallParams := "" ; Будущие аргументы.
            if (Func_Params != "void") ; Если функция имеет аргументы.
            {
                Loop, Parse, % Func_Params, `, ; Проходимся по аргументам функции.
                {
                    RegExMatch(Trim(A_LoopField), "S)(?<Type>[a-zA-Z0-9_\s]+)\s(?<IsPtrOrAddrOrDefault>[*&]{0,2})(?<Name>[a-zA-Z0-9_]+)", Params_) ; Делим аргумент на тип и название.
                    if (Params_Type == "va_list" || A_LoopField == " ...") ; Пропускаем, ведь ахк само умеет форматировать.
                        continue
                    if (Params_Name == "l") ; Так как AHK не регистрозависимый язык, нужно заменить.
                        Params_Name := "l2"
                    AhkFuncParams .= (A_Index == 1 ? "" : ", ") (Params_IsPtrOrAddrOrDefault == "*" ? "ByRef " : "") Params_Name ; Аргументы в ахк функцию.
                    DllCallParams .= (A_Index == 1 ? "" : ", ") """" GetType(Params_Type) """, " Params_Name ; Аргументы в С функцию.
                }
            }
            FuncList.Push(Func_Name) ; Добавляем функцию в список.
            result .= "`n`n" Func_Name "(" AhkFuncParams ")`n{`n`treturn DllCall(""lua51.dll\" Func_Name """" (DllCallParams == "" ? "" : ", " DllCallParams) ", ""CDecl" GetType(Func_Type, true) """)`n}" ; Формируем код.
        }
    }
    
    FileDelete, AHK-LUA-API.ahk
    FileAppend, %result%, AHK-LUA-API.ahk
    
    Скачать
     
    Cucumber, Harryss, SuSmer4Coder и 14 другим нравится это.
  2. DonHomka

    DonHomka Lealtà' verso la famiglia Tunes
    Друг

    Регистрация:
    8 ноя 2017
    Сообщения:
    2.541
    Симпатии:
    1.631
    какой в этом смысл?
    все равно что писать письмо в письме. вообще не вижу в этом логики, еще и скорость луа умирает из-за ахк.
     
    Ranx, AppleThe, BBooGG и 2 другим нравится это.
  3. Frapsy

    Проверенный

    Регистрация:
    4 сен 2016
    Сообщения:
    395
    Симпатии:
    193
    Ты конечно вложил в это свои силы, но рил, в чем кайф таких извращений, если проще уж начать писать на LUA? Это логичней и правильней будет, нежели мутить между этими двумя созданиями API для извращений.
     
    AppleThe, Ranx, Oreshka23 и 2 другим нравится это.
  4. iAmerican

    Друг

    Регистрация:
    17 фев 2014
    Сообщения:
    573
    Симпатии:
    237
    Потому что может, по этому и создает.
    Такие работы , как по мне , уникальны.
     
    SuSmer4Coder, Alfinity, Mirrorka и 4 другим нравится это.
  5. cover

    Проверенный

    Регистрация:
    25 дек 2014
    Сообщения:
    246
    Симпатии:
    227
    Несомненно, была проделана определенная работа и это должно ценится, но вопрос в другом: насколько это полезно?
     
    imring нравится это.
  6. Oreshka23

    Oreshka23 Знающий

    Регистрация:
    10 май 2015
    Сообщения:
    247
    Симпатии:
    72
    Как то слишком замудренно, и бесполезно.
     
  7. Rinat_Namazov

    Rinat_Namazov ( ͡° ͜ʖ ͡°)
    Всефорумный модератор

    Регистрация:
    9 авг 2015
    Сообщения:
    1.134
    Симпатии:
    579
    Замудренного ничего нет, это стандартное апи луа.
    При написании на C++ выглядит точно также.
     
  8. ЯedЯuM

    ЯedЯuM Malware Maker

    Регистрация:
    13 мар 2016
    Сообщения:
    282
    Симпатии:
    294
    Я не смотрел апи но если он добавил весь функционал lua51.dll то можно ставить дебаг хуки на луа скрипты и отслеживать значения всех переменных и вызовы функций, полезно для обхода привязок в закомпилированых скриптах.
     
    Kvisk и DonHomka нравится это.
  9. Rinat_Namazov

    Rinat_Namazov ( ͡° ͜ʖ ͡°)
    Всефорумный модератор

    Регистрация:
    9 авг 2015
    Сообщения:
    1.134
    Симпатии:
    579
    Да.
    lua_sethook(L, func, mask, count)

    Устанавливает функцию отладочной ловушки (hook).

    Аргумент func является функцией ловушки. mask указывает на каких событиях будет вызываться ловушка: значение аргумента формируется побитовым ИЛИ из констант LUA_MASKCALL, LUA_MASKRET, LUA_MASKLINE, и LUA_MASKCOUNT. Аргумент count имеет смысл только когд маска содержит LUA_MASKCOUNT. Для каждого события, ловушка вызывается как описано ниже:
    • Ловушка вызова: вызывается, когда интерпретатор вызывает функцию. Ловушка вызывается сразу после ввода Lua новой функции, перед получением функцией своих аргументов.
    • Ловушка возврата: вызывается когда интерпретатор возвращается из функции. Ловушка вызывается непосредственно перед тем, как Lua оставляет функцию. При этом нет стандартного способа обращения к значениям, возвращаемым функцией.
    • Ловушка строки: вызывается когда интерпретатор собирается начать выполнение новой строки кода или когда он переходит назад в коде (даже на ту же самую строку). (Это событие происходит только пока Lua выполняет Lua функцию.)
    • Ловушка счета: вызывается после выполнения интерпретатором каждого определенного количества (указанного в count) инструкций. (Это событие происходит только пока Lua выполняет Lua функцию.)
    Ловушка отключается установкой аргумента mask в ноль.

    Но нужно знать указатель на структуру интерпретатора который в MoonLoader используется. Либо погуглю про апи, вдруг там есть функция для получения, либо в отладчике поставлю хук на luaL_newstate и вернувшись из функции узнаю адрес с указателем.
     
    #9 Rinat_Namazov, 4 окт 2018
    Последнее редактирование: 4 окт 2018
    ЯedЯuM нравится это.
  10. cover

    Проверенный

    Регистрация:
    25 дек 2014
    Сообщения:
    246
    Симпатии:
    227
    Как будто это нельзя сделать через другой луа скрипт.
     
    #Northn, AppleThe, ShuffleBoy и 3 другим нравится это.
  11. DonHomka

    DonHomka Lealtà' verso la famiglia Tunes
    Друг

    Регистрация:
    8 ноя 2017
    Сообщения:
    2.541
    Симпатии:
    1.631
    Я все еще не вижу в этом смысла. Ковер везде прав. Можно было и более полезно провести время. Да даже время потраченное на порнхаб в разы кпдшней
     
    777qwerty777, #Northn и ЯedЯuM нравится это.
  12. cover

    Проверенный

    Регистрация:
    25 дек 2014
    Сообщения:
    246
    Симпатии:
    227
    Это определенно круто, что ты сделал подобное, но надо учитывать тот факт, что чем проще - тем лучше. Но для людей, которые любят писать на АХК, будет полезно.
     
  13. madrasso

    Проверенный

    Регистрация:
    27 июл 2016
    Сообщения:
    549
    Симпатии:
    105
    Люди которые пишут на ахк (а точнее самперы), не смогут осилить подобное, только единицы.
     
    Emilio Armstrong нравится это.
  14. project0

    project0 Участник

    Регистрация:
    27 мар 2018
    Сообщения:
    5
    Симпатии:
    0
    @Rinat_Namazov, если не сложно, был бы очень благодарен за ссылку на проект на AHK-LUA-API со скриптом который выводит что-либо в игровой чат. Чет вообще недоумеваю как это должно работать, lua51.dll подгружается и MsgBox выводит, и на этом, как говорится, всё, и ещё - где можно взять нормальную библиотеку для LUA?
     
  15. Double Tap Inside

    Double Tap Inside Знающий

    Регистрация:
    12 фев 2019
    Сообщения:
    240
    Симпатии:
    72
    Ебать, так это охуенно, блять.

    Ток это... Я вот хочу написать функцию в .ahk и вызвать её уже из .lua
    Чет не вьебу, даже как примеры запустить.
    Кинул Апи и примеры в папку GTA там же и lua51.dll валяется.
    чет нихуя я понять не могу

    "Экспорты луа апи генерируются автоматический:" - а это шо и куда?

    ---
    есть какие - то публичные пирмеры скриптов на ahk и на lua использующие это API?
     
    #15 Double Tap Inside, 8 мар 2019
    Последнее редактирование: 8 мар 2019
  16. Rinat_Namazov

    Rinat_Namazov ( ͡° ͜ʖ ͡°)
    Всефорумный модератор

    Регистрация:
    9 авг 2015
    Сообщения:
    1.134
    Симпатии:
    579
    Это про сам API.

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

    Если ты про MoonLoader, то у тебя должен быть доступ к LuaState который создал ML, то есть надо хукнуть luaL_newstate() в lua51.dll через AHK, и добавлять свои функции туда.
     
  17. Double Tap Inside

    Double Tap Inside Знающий

    Регистрация:
    12 фев 2019
    Сообщения:
    240
    Симпатии:
    72
    Короче, надо рабочий пример как добавить ахк функцию в Moonloader.
     
  18. Rinat_Namazov

    Rinat_Namazov ( ͡° ͜ʖ ͡°)
    Всефорумный модератор

    Регистрация:
    9 авг 2015
    Сообщения:
    1.134
    Симпатии:
    579
    
    #include AHK-LUA-API.ahk
    #include AHK-HOOK-API.ahk
    
    global luaL_newstateHook := new Hook("lua51.dll", "luaL_newstate", "Hook_luaL_newstate", "CDecl")
    
    Hook_luaL_newstate()
    {
        luaL_newstateHook.SetStatus(false)
        retValue := luaL_newstate()
        luaL_newstateHook.SetStatus(true)
        lua_register(retValue, "MsgBox", "LUAFUNC_MsgBox")
        lua_register(retValue, "MultiAdd", "LUAFUNC_Test")
        return retValue
    }
    
    LUAFUNC_MsgBox(L)
    {
        MsgBox, % lua_tostring(L, 1)
        return 0
    }
    
    LUAFUNC_Test(L)
    {
        sum := 0
        n := lua_gettop(L)
        loop % n
            sum += lua_tonumber(L, A_Index)
        lua_pushnumber(L, sum)
        return 1
    }
    
    Наверно это должно сработать, но такой способ добавить эту функцию во все lua скрипты.

    Ну, а лучше было бы написать это в виде модуля, для подключения через require, но такой способ требует небольших изменений в интерпретаторе ахк.
     
  19. Belo4ka_belka

    Belo4ka_belka Интересующийся

    Регистрация:
    28 июл 2015
    Сообщения:
    120
    Симпатии:
    2
    Это что-то типо интерпретатора lua? Ну как в ахк 2.0 с его многопоточностью? Допустим тот же imgui хотя бы теоретически можно будет запускать в АХК? Или можно чисто функции вызывать и все? Хочу понять спектр возможности прежде чем начать изучать все это)
     
    #19 Belo4ka_belka, 28 мар 2019
    Последнее редактирование: 29 мар 2019