Взаимодействие io.popen() и cmd

hookernice

Новичок
Автор темы
3
0
Версия MoonLoader
Другое
Решил написать код, который выполняет запросы для командной строки Windows прямо в SA:MP, но столкнулся с большой проблемой, обнаружив, что при выполнении в игре функции io.popen() неизбежно открываеться окно консоли как при открытии bat-файла, что приводит к принудительному сворачиванию игры, и это, очевидно, крайне неудобно (даже при переводе окна консоли в "nul 2>&1" игра все равно сворачивается хоть уже и без самого окошка). Хотел бы спросить: возможно ли это избежать и по моей задумке выполнять команды и получать вывод с этих команд? Буду очень благодарен любому решению, мне хочется как минимум понять что можно попробовать.


Lua:
require("lib.moonloader")
require("lib.sampfuncs")

function main()
    while not isSampAvailable() do wait(123) end

    -- начать выполнение
    sampRegisterChatCommand('Test', function()
        exec = lua_thread.create(exectest)
    end)

    wait(-1)
end

function exectest()

    -- выполнение команды
    local handle = io.popen("help")

    -- вывод результата построчно
    while true do
        wait(0)
        local line = handle:read()
        if line == nil then
            break
        end
        sampAddChatMessage(line)
    end
    handle:close()
end
 

yung milonov

Известный
1,031
532
вот кому-то делать нехуй конечно
может и проще можно, может вовсе в пару строк можно, ну мне похуй так-то
учитывай что на 49 строке меняется кодировка в консоли, чтоб в сампе нормально это вывелось, по дефолту в консоли CP866 стоит
пиздец:
local ffi = require("ffi")

ffi.cdef[[
    typedef void* HANDLE;
    typedef struct {
        unsigned long nLength;
        void* lpSecurityDescriptor;
        int bInheritHandle;
    } SECURITY_ATTRIBUTES;

    typedef struct {
        unsigned long cb;
        char* lpReserved;
        char* lpDesktop;
        char* lpTitle;
        unsigned long dwX, dwY, dwXSize, dwYSize;
        unsigned long dwXCountChars, dwYCountChars;
        unsigned long dwFillAttribute, dwFlags;
        unsigned short wShowWindow, cbReserved2;
        unsigned char* lpReserved2;
        HANDLE hStdInput, hStdOutput, hStdError;
    } STARTUPINFO;

    typedef struct {
        HANDLE hProcess, hThread;
        unsigned long dwProcessId, dwThreadId;
    } PROCESS_INFORMATION;

    int CreatePipe(HANDLE* hReadPipe, HANDLE* hWritePipe, SECURITY_ATTRIBUTES* lpPipeAttributes, unsigned long nSize);
    int CreateProcessA(const char* lpApplicationName, char* lpCommandLine, void* lpProcessAttributes, void* lpThreadAttributes,
                    int bInheritHandles, unsigned long dwCreationFlags, void* lpEnvironment, const char* lpCurrentDirectory,
                    STARTUPINFO* lpStartupInfo, PROCESS_INFORMATION* lpProcessInformation);
    int ReadFile(HANDLE hFile, char* lpBuffer, unsigned long nNumberOfBytesToRead, unsigned long* lpNumberOfBytesRead, void* lpOverlapped);
    int CloseHandle(HANDLE hObject);
]]

function exec(command)
    local si = ffi.new("STARTUPINFO")
    si.cb = ffi.sizeof("STARTUPINFO")
    local pi = ffi.new("PROCESS_INFORMATION")
    local sa = ffi.new("SECURITY_ATTRIBUTES")
    sa.nLength, sa.bInheritHandle = ffi.sizeof("SECURITY_ATTRIBUTES"), 1
    local readPipe, writePipe = ffi.new("HANDLE[1]"), ffi.new("HANDLE[1]")
    if ffi.C.CreatePipe(readPipe, writePipe, sa, 0) == 0 then
        return nil
    end
    si.dwFlags, si.hStdOutput, si.hStdError = 0x100, writePipe[0], writePipe[0]

    local fullCmd = "cmd.exe /c chcp 1251 >nul && " .. command
    local cmdBuf = ffi.new("char[?]", #fullCmd + 1)
    ffi.copy(cmdBuf, fullCmd)
    if ffi.C.CreateProcessA(nil, cmdBuf, nil, nil, 1, 0x08000000, nil, nil, si, pi) == 0 then
        ffi.C.CloseHandle(readPipe[0])
        ffi.C.CloseHandle(writePipe[0])
        return nil
    end
    ffi.C.CloseHandle(writePipe[0])
    local buffer, bytesRead, output = ffi.new("char[4096]"), ffi.new("unsigned long[1]"), ""
    while true do
        if ffi.C.ReadFile(readPipe[0], buffer, 4096, bytesRead, nil) == 0 then break end
        if bytesRead[0] == 0 then break end
        output = output .. ffi.string(buffer, bytesRead[0])
    end

    ffi.C.CloseHandle(readPipe[0])
    ffi.C.CloseHandle(pi.hProcess)
    ffi.C.CloseHandle(pi.hThread)
    return output
end

function main()
    sampRegisterChatCommand("test123", function()
        local result, err = exec("help")
        for line in result:gmatch("[^\r\n]+") do
            sampAddChatMessage(line, -1)
        end
    end)
    wait(-1)
end