|
已经写了一篇 blog 里面介绍了如何传入结构体指针的方法,而前不久发现了另外一种传入一整块 buffer 的方案,不用定义 Structure class,直接类似 malloc 那样的方法去执行,就是 create_string_buffer addressof string_at 系列函数,感觉更接近底层调用.
首先修正上篇文档里面的一个问题,就是 load 这个方法已经取消了(当时我使用的好像是 0.9.9.3 版的 ctypes),LoadLibrary 这个接口随着ctypes 1.0 的发布并被集成进 python 2.5,应该是正式确定了名称。
其次注意的是根据源代码里面对函数不同的声明,还得选择采用 cdll 还是 windll 来实例化一个动态库,用 WINAPI 声明的函数需要用 windll.LoadLibrary(dll_file_path)。因为不同的声明导致参数传递的方法不一样,我自己就是费了好长时间的尝试,才搞清楚为什么总是报错"rocedure called with not enough arguments (xx bytes missing) or wrong calling convention"。ctypes 的手册里面还提到另外有oledll, pydll 两种类型.
如果一个 dll 里面即有普通方法定义的函数,也有 WINAPI 定义的函数,而你只希望只 Load 一次动态库,那么就需要 WINFUNCTYPE 或者 CFUNCTYPE 这样的方法来指定不同的函数类型了。
大家都应该机器上安装 XviD 解码器了吧,:)
现在我们分别用两个不同的方法取出 XviD 编码器的缺省配置(C 源代码参考 xvidcore-x.y.z\vfw\src\driverproc.c)
from ctypes import *
DriverProc = windll.LoadLibrary("c:\\windows\\system32\\xvidvfw.dll").DriverProcconfigsize = DriverProc(c_int(0), c_int(0), c_int(0x5000), c_voidp(0), c_voidp(0))
# 获取结构体大小 configsize
did = DriverProc(c_int(0), c_int(0), c_int(0x0003), c_voidp(0), c_voidp(0))
# 获取访问句柄 did
config = create_string_buffer(configsize, configsize)
# 创建 buffer, 返回一个 Python 对象
pconfig = addressof(config)
# buffer 的地址,让我想起了 C 里面的 &
DriverProc(c_int(did), c_int(0), c_int(0x5000), pconfig, c_voidp(0))
# 这次调用就是把缺省配置复制到传入的内存区域内
s = string_at(pconfig, configsize)
# 最后我们从 pconfig 地址里的内容生成一个字符串对象出来
上面的代码通过 cdll + WINFUNCTYPE 来写就是
from ctypes import *
from ctypes.wintypes import *
xvidvfw = cdll.LoadLibrary("c:\\windows\\system32\\xvidvfw.dll")
# 看好了,这里可用的是 cdllprototype = WINFUNCTYPE(LONG, DWORD, DWORD, UINT, LPARAM, LPARAM)
# LONG 是返回值,DWORD, DWORD, UINT, LPARAM, LPARAM 是参数列表
paramflags = (1, "driverid", 0), \
(1, "hdriver", 0), \
(1, "umsg", 0), \
(1, "para1", 0), \
(1, "para2", 0)
# 设定一下参数表,以及缺省参数,就可以用 key=value 的方式来传递了
x = prototype(("DriverProc", xvidvfw), paramflags)
# ...
configsize = x(umsg=0x5000)
# 这里只传入一个参数,其它的就自动用缺省的了;而且无需 c_int 这样来转换
did = x(umsg=0x0003)
# .... 以下就不需要注释了吧
config = create_string_buffer(configsize, configsize)
pconfig = addressof(config)
y = x(driverid=did, umsg=0x5000, para1=pconfig)
s = string_at(pconfig, configsize)
最后要说的是通过 dumpbin.exe /exports dll_file_path,就可以查看一个 dll 里面有哪些函数是被 export 出来,可以给我们来调用的(我自己猜测) . dumpbin.exe 可以从 masm32 里面免费获得
update: 在上述第一个例子里面,传入的参数用 addressof 去做一次转换并不是必须的. 可能 ctypes 会在内部自动处理
转自:http://www.dup2.org/node/248 |
|