用 lua 调用 Windows 的 API
昨天同事谈起能否给一个从 lua 中调用 Windows API 的简单方案。一开始觉得,如果是一个通用方案,那么至少需要先给出一个类似 windows.h 的原型声明,然后从 lua 来解析这些原型。大约写了几十行程序就实现了。后来又想了一下,似乎可以用一个更简单的方式,绕过原型,更简洁(但不保证安全)的方法来做到。
其间的问题就只有一个,每个 api 的参数都不一样,如何自动生成 C 中匹配的函数指针。似乎 C++ 的 template 是一个正统的解决方案。不过思考过几分钟以后,就被我否决了。实际用到的解决方案比较诡异:
先用 alloca 分配出正确的参数空间,再立刻填充这些参数,接下来以无参数的形式调用 api 。这样做,对于 __stdcall 的函数是没有问题的。好在 api 大多也是这样。
我写了这样一段程序来验证我的想法:
这个方法唯一的漏洞,可能存在于 _alloca
并不能正确的分配出需要的空间。因为由于某些(对齐?)因素,我们不能保证分配出来的空间正好符合后面的函数调用需要的位置。个人感觉,这个问题在大多数编译器上不会出现。不过安全起见,我写了个 check 函数运行时检查。
用这个程序验证无误后,就写了个简单的 lua 扩展。使用起来大约是这样的:
opendll = require("api.opendll")
getprocaddress =require("api.procaddress")
user32=opendll("user32.dll")
MessageBox=getprocaddress(user32,"MessageBoxA")
MessageBox(nil,"hello","test",0)
有点意思 :) 另外我还测试了 FindWindow , ShowWindow 等,都工作的很正常。
这个方案初步解决了 dll 中 api 的调用问题,但还并不实用。比如我们需要写一套 dll 管理模块(直接用 lua 完成即可)。更重要的是需要解决 api 调用中无处不在的 C struct 的传递问题。这个问题又分两类,一类是作为输入参数的 struct ,一类是作为输出参数的 struct 如 (GetWindowRect) 。我们可以用 lua 的 table 去模拟 struct 。作为输入参数做 lua table 到 c struct 的转换;而作为输出参数则做 c struct 到 lua table 的回转。或者干脆用 userdata 直接映射 struct ,再用 metable 去读写之。
另一个需要解决的问题是,有些 api 为了返回多个参数,以传入指针的形式接收返回值。lua 里是没有指针的概念的。简单的解决方法是统一用 struct 的方式解决,把单一指针看成是一个只有一个成员的 struct 指针。
因为做这个东西纯属娱乐,目前项目中并不会用到,所以我也就没有继续深入下去了。
Comments
Posted by: blknit | (23) August 1, 2012 05:50 PM
Posted by: blknit | (22) August 1, 2012 05:50 PM
Posted by: David | (21) October 19, 2009 05:23 PM
Posted by: chengjie | (20) April 23, 2008 05:19 PM
Posted by: yippeesoft | (19) July 24, 2007 10:27 AM
Posted by: Anonymous | (18) June 10, 2007 06:37 AM
Posted by: Cloud | (17) April 19, 2007 05:46 PM
Posted by: huo | (16) April 19, 2007 02:29 PM
Posted by: Cloud | (15) August 28, 2006 05:00 PM
Posted by: Lua有一个扩展可以调用Win32 API | (14) August 28, 2006 04:21 PM
Posted by: Cloud | (13) August 2, 2006 12:31 PM
Posted by: Siney | (12) August 2, 2006 11:26 AM
Posted by: Cloud | (11) August 1, 2006 11:57 PM
Posted by: Siney | (10) August 1, 2006 11:38 PM
Posted by: Cloud | (9) July 31, 2006 05:28 PM
Posted by: Cloud | (8) July 31, 2006 05:19 PM
Posted by: Bennie | (7) July 31, 2006 04:44 PM
Posted by: Cloud | (6) July 30, 2006 01:25 PM
Posted by: yufeng | (5) July 29, 2006 12:01 PM
Posted by: gmcat | (4) July 29, 2006 11:25 AM
Posted by: Bennie | (3) July 28, 2006 10:27 PM
Posted by: Cloud | (2) July 28, 2006 12:43 PM
Posted by: HappyChui | (1) July 28, 2006 09:39 AM