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

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

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

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

实现如下:

module1.py

#!python3# -*- coding: utf-8 -*-importctypesimportctypes.wintypesclassPOINT(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_pctypes.windll.user32.GetCursorPos.argtypes = (ctypes.POINTER(POINT), )defWindowFromPoint(x, y):returnctypes.windll.user32.WindowFromPoint(POINT(x, y))defGetCursorPos():point = POINT(0,0)    ctypes.windll.user32.GetCursorPos(ctypes.byref(point))returnpoint.x, point.ydefWindowFromCursor():x, y = GetCursorPos()returnWindowFromPoint(x, y)

调用的代码如下

test.py

#!python3# -*- coding:utf-8 -*-importmodule1defmain():print('the handle under cursor is', module1.WindowFromCursor())if__name__ =='__main__':    main()

运行结果如下

the handle undercursoris1839250

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

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

#!python3# -*- coding:utf-8 -*-importmodule1importmodule2defmain():print('the handle under cursor is', module1.WindowFromCursor())    print('the handle under cursor is', module2.WindowFromCursor())if__name__ =='__main__':    main()

运行就会报错了

ctypes.ArgumentError: argument1: : expected LP_POINTinstanceinsteadofpointertoPOINT

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

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

执行

importmodule1importmodule2

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

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

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

假设module1, module2分别是两个人写,你又要同时用这两个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就不会报错了。

作为库的作者,需要主要一下,最好不要设置系统C函数的argtypes。

看我主页简介免费C++学习资源,视频教程、职业规划、面试详解、学习路线、开发工具

每晚8点直播讲解C++编程技术。

你可能感兴趣的:(使用ctypes调用系统C API函数需要注意的问题,函数参数中有指针或结构体的情况下最好不要修改argtypes)