使用ctypes调用系统C API函数需要注意的问题,函数参数中有指针或结构体的情况下最好不要修改argtypes...

博客讲述了Python中同时使用uiautomation模块和另一个模块时脚本运行报错,单独使用则正常的问题。以获取鼠标光标下窗口句柄的功能为例,解释了因调用同一C函数设置argtypes时后面覆盖前面,导致参数类型不匹配报错,给出注释代码不修改argtypes的解决办法。

有人向我反应,在代码里同时用我的python模块uiautomation和其它另一个模块后,脚本运行时会报错,但单独使用任意一个模块时都是正常的,没有错误。issue链接

我用一个例子来演示下这个问题是如何出现的。

假设我需要写一个module,这个module需要提供获取当前鼠标光标下窗口句柄的功能,这需要调用系统C API来实现。

实现如下:

module1.py

 
 
#!python3
# -*- coding: utf-8 -*-
import ctypes
import ctypes.wintypes


class POINT(ctypes.Structure):
    _fields_ = [("x", ctypes.wintypes.LONG),
                ("y", ctypes.wintypes.LONG)]


ctypes.windll.user32.WindowFromPoint.argtypes = (POINT, )
ctypes.windll.user32.WindowFromPoint.restype = ctypes.c_void_p

ctypes.windll.user32.GetCursorPos.argtypes = (ctypes.POINTER(POINT), )


def WindowFromPoint(x, y):
    return ctypes.windll.user32.WindowFromPoint(POINT(x, y))


def GetCursorPos():
    point = POINT(0, 0)
    ctypes.windll.user32.GetCursorPos(ctypes.byref(point))
    return point.x, point.y


def WindowFromCursor():
    x, y = GetCursorPos()
    return WindowFromPoint(x, y)
 
 

调用的代码如下

test.py

#!python3
# -*- coding:utf-8 -*-
import module1


def main():
    print('the handle under cursor is', module1.WindowFromCursor())


if __name__ == '__main__':
    main()

 

运行结果如下

the handle under cursor is 1839250

这时复制一份module1.py,重命名为module2.py,他们的代码是完全一样的

在test.py同时调用这两个module,代码如下

#!python3
# -*- coding:utf-8 -*-
import module1
import module2


def main():
    print('the handle under cursor is', module1.WindowFromCursor())
    print('the handle under cursor is', module2.WindowFromCursor())


if __name__ == '__main__':
    main()

运行就会报错了

ctypes.ArgumentError: argument 1: <class 'TypeError'>: expected LP_POINT instance instead of pointer to POINT

但分开单独调用任一个模块就是正常的,不会出错。

 

这是因为,module1,module2调用的同一个C函数,在设置argtypes的时候,后面的修改会覆盖前面的设置。

执行

import module1
import module2

后,C函数中的POINT参数必须是module2.POINT才是合法的。

在用module1调用时,传入的参数类型是module1.POINT,运行时就会报错了。

这种错误应该只有在参数中有结构体或结构体指针时才会出现。

假设module1, module2分别是两个人写,而这两个module都会调用同一个C函数,C函数参数里有你自定义的ctypes.Structure类型,你又要同时用这两个module,只要有一个module设置了argtypes,运行时可能就会出错。

 

解决方法是,在module1, module2中注释两行代码

#ctypes.windll.user32.WindowFromPoint.argtypes = (POINT, )
ctypes.windll.user32.WindowFromPoint.restype = ctypes.c_void_p

#ctypes.windll.user32.GetCursorPos.argtypes = (ctypes.POINTER(POINT), )

不要修改argtypes,再运行test.py就不会报错了。

 

  

转载于:https://www.cnblogs.com/Yinkaisheng/p/10955468.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值