Search code examples
luacalling-convention

Lua alien returning multiple values


I have this function, i would like to return multiple values but i dont know how to achieve this

function GetDiskSpace(_disk)
    require("alien")
    local kernel32 = alien.load("kernel32.dll")
    kernel32.GetDiskFreeSpaceExA:types("int", "pointer", "int", "int", "int")

    if kernel32.GetDiskFreeSpaceExA(_disk, _avail_space, _disk_space, _free_space) ~= 0 then
            return _avail_space, _disk_space, _free_space
            --[[or like this return kernel32.GetDiskFreeSpaceExA(_disk, _avail_space, _disk_space, _free_space)
            GetDiskFreeSpaceExA should retun non zero if function ran properly, 
            and should retun additional values if those are given 
            (btw values are __int64 i'm not sure if I specified them correct, maybe
            I should set them as "long" instead of "int")
            either way it return only function value and nil's.
            --]]
    else
            print("GetDiskSpace returned error.")
    end
end

hdd_a, hdd_b, hdd_c = GetDiskSpace("C:\\")

Solution

  • The type specification you gave is wrong for several reason. The first argument is of type "string" and not "pointer". You have to write "ref int" and not just "int" for a reference (or pointer) to an int. And you must also specify the ABI to "stdcall".

    When calling the function with a "ref int" argument, you pass a dummy 0 value, but get an additional return value, so here GetDiskFreeSpaceExA effectively returns 4 results.

    You are right to worry about the uint64_t value type for the results. As far as I know, Alien does not support 64 bit integers, so the following code only returns the 32 lower bits for the disk spaces:

    function GetDiskSpace(_disk)
        require("alien")
        local kernel32 = alien.load("kernel32.dll")
        kernel32.GetDiskFreeSpaceExA:types { ret="int", abi="stdcall", 
            "string", "ref int", "ref int", "ref int" }
        local ok, _avail_space, _disk_space, _free_space = 
            kernel32.GetDiskFreeSpaceExA(_disk, 0, 0, 0)
        assert(ok == 1, "GetDiskSpace returned error.")
        return _avail_space, _disk_space, _free_space
    end
    
    hdd_a, hdd_b, hdd_c = GetDiskSpace("C:\\")
    

    To correct this, you can add support for 64 bit integers by modifying the source code of Alien and rebuilding it.