有人向我反应,在代码里同时用我的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)

WindowFromPoint和GetCursorPos是系统user32.dll里的函数。

WindowFromPoint的C/C++函数原型是 HWND WindowFromPoint( POINT Point ); POINT 是C/C++里的struct类型,HWND是void*类型。

WindowFromPoint.argtypes = (POINT, ) 设置函数的参数类型,如果在Python里调用WindowFromPoint传入的参数不是POINT类型就会提示参数类型不匹配。如果不设置argtypes也是可以调用的,但要保证传入的参数是合法的类型。

WindowFromPoint.restype = ctypes.c_void_p 设置函数的返回类型,这个是必要的,如果用的是64位版本,C函数返回是64位指针值,如果不设置,返回值会被截断成32位。

调用的代码如下

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就不会报错了。

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

  1. C语言--- 高级指针2(结构体指针,数组作为函数参数)

    一.结构体指针 1. 什么是结构体指针?指向结构体变量的指针     结构体:     typedef  struct stu{                          char name[ ...

  2. C++ 利用指针和数组以及指针和结构体实现一个函数返回多个值

    C++ 利用指针和数组实现一个函数返回多个值demo1 #include <iostream> using namespace std; int* test(int,int,int); i ...

  3. (60) 结构体指针、结构体变量嵌套、结构体指针嵌套、函数指针、数组指针、指针数组、typedef 综合运用

    #include<stdio.h> #include<iostream> #include<malloc.h> /* author : 吴永聪 program: 结 ...

  4. C语言基础知识点整理(函数/变量/常量/指针/数组/结构体)

    函数 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ...

  5. Delphi调用WINAPI时到底应该是指针还是结构体(注意是Delphi变量本身就是指针)

    看MSDN,GetWindowRect的说明如下: BOOL WINAPI GetWindowRect( _In_  HWND   hWnd, _Out_ LPRECT lpRect // 注意,没* ...

  6. C与指针(结构体指针,函数指针,数组指针,指针数组)定义与使用

    类型 普通指针 指针数组(非指针类型) 数组指针 结构体指针 函数指针 二重指针 定义方式 int *p; int *p[5]; int (*p)[5]; int a[3][5]; struct{.. ...

  7. 调用系统相机拍照,保存照片,调用系统裁剪API对照片处理,显示裁剪之后的照片

    package com.pingyijinren.test; import android.annotation.TargetApi; import android.app.Notification; ...

  8. Python3基础 函数 参数 在设定缺省值的情况下指明参数类型

             Python : 3.7.3          OS : Ubuntu 18.04.2 LTS         IDE : pycharm-community-2019.1.3    ...

  9. 调用系统api修改系统时间

    一:截图 二:代码 using System; using System.Collections.Generic; using System.ComponentModel; using System. ...

随机推荐

  1. android studio 错误汇总以及解决办法

    android studio 错误汇总以及解决办法  参考 https://www.jianshu.com/p/7c7de6562231 问题1. Error:Execution failed for ...

  2. Android插件化(二):OpenAtlas插件安装过程分析

    Android插件化(二):OpenAtlas插件安装过程分析   转 https://www.300168.com/yidong/show-2788.html   核心提示:在前一篇博客 Andro ...

  3. angular绑定数据

    Angular 中使用{{}}绑定业务逻辑里面定义的数据 <h1> Welcome to {{ title }}! /*引入title*/ </h1> export class ...

  4. Windows7 安装docker工具的方法

    1.参考官方文档 https://docs.docker.com/toolbox/toolbox_install_windows/ 注意:因为我的电脑是windows10 家庭版,所以,无法使用 Do ...

  5. CerntOS7下搭建git服务器

    (1).安装git yum安装git,需要ssh的支持.某些版本需要安装git-core,那才是服务器. [root@youxi1 ~]# yum -y install git 创建git用户 [ro ...

  6. Python - Django - 编辑作者

    在作者列表页面的操作栏中加上编辑按钮 <!DOCTYPE html> <html lang="en"> <head> <meta char ...

  7. shell脚本安装python、pip--交互式的

    首先把pip-.tgz 安装包放在 /usr/local 下面,按照顺序先安装pip,再安装python.不要先安装或只安装python,否则很容易出错, [root@bogon ~]# cat pi ...

  8. mysql命令、mysqldump命令找不到解决

    1.解决bash: mysql: command not found 的方法 [root@DB-02 ~]# mysql -u root -bash: mysql: command not found ...

  9. 【Leetcode_easy】653. Two Sum IV - Input is a BST

    problem 653. Two Sum IV - Input is a BST 参考 1. Leetcode_easy_653. Two Sum IV - Input is a BST; 完

  10. 【ARTS】01_30_左耳听风-201900603~201900609

    ARTS: Algrothm: leetcode算法题目 Review: 阅读并且点评一篇英文技术文章 Tip/Techni: 学习一个技术技巧 Share: 分享一篇有观点和思考的技术文章 Algo ...