以下為一些 prototype 較簡單的 Win32 API, 其 Alien 的 prototype 定義:
require "alien"
local SendMessage = alien.User32.SendMessageA
SendMessage:types({ret = "long", abi = "stdcall", "ulong", "uint", "ulong", "ulong"})
local PostMessage = alien.User32.PostMessageA
PostMessage:types({ret = "long", abi = "stdcall", "ulong", "uint", "ulong", "ulong"})
local Sleep = alien.Kernel32.Sleep
Sleep:types({ret = "void", abi = "stdcall", "uint"})
local GetLastError = alien.Kernel32.GetLastError
GetLastError:types({ret = "uint", abi = "stdcall"})
由於 Win32 API 的 calling convention 為 stdcall, 並非 cdecl, 因此我們需要指定 abi="stdcall", 否則在呼叫時可能會導致 AV(access violation).牽扯到資料結構的函式, 我們就需要用到 alien.defstruct 或 alien.struct 來打包資料, 以下使用 alien.struct 來打包 SendInput 所使用的 INPUT 資料結構:
require "alien"
local struct = require "alien.struct"
-- prototypes of foreign functions
local SendInput = alien.User32.SendInput
SendInput:types({ret = "uint", abi = "stdcall", "uint", "pointer", "int"})
-- specify structure format of INPUT for SendInput
local fmtMI
local fmtKI
if os.getenv("PROCESSOR_ARCHITECTURE") == "x86" then
fmtMI = "L".."LLLLLL"
fmtKI = "L".."HHLLLxxxxxxxx"
else
-- with alignment and paddings for 64-bit
fmtMI = "Lxxxx".."LLLLLxxxxI8"
fmtKI = "Lxxxx".."HHLLxxxxI8xxxxxxxx"
end
-- Send F1 key
local VK_F1 = 0x70
local input = struct.pack(fmtKI, 1, VK_F1, 0, 0, 0, 0)
local result = SendInput(1, input, struct.size(fmtKI))
從以上例子中可看出, 在資料結構中有用到 union 的, 我們可能會需要加 padding 以維持整個資料結購的大小, 另外, 在不同位元的作業系統上, 可能還會需要做 alignment.
更多資訊:
- LuaForge - Alien
- Library for Converting Data to and from C Structs
- LUA调用Windows下的DLL
- init.lua - guacamole - Simple platform for creating 2D games with Lua Source Code Reference
沒有留言:
張貼留言