以下為一些 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
沒有留言:
張貼留言