有人向我反应,在代码里同时用我的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. 亲历谷歌 Chrome 浏览器弹窗境外广告的解决方法(图) | 技术乐园

    亲历谷歌 Chrome 浏览器弹窗境外广告的解决方法(图) | 技术乐园 转 https://www.hack520.com/338.html 谷歌的 Chrome 浏览器是我非常喜欢的一款的浏览器, ...

  2. c语言 正则表达式 IP地址

    #include <stdio.h> #include <string.h> #include <regex.h> #define SUBSLEN 10 /* 匹配 ...

  3. 22Flutter中的常见的按钮组件 以及自定义按钮组件

    /* Flutter中的常见的按钮组件 以及自定义按钮组件 一.Flutter中的按钮组件介绍 Flutter里有很多的Button组件,常见的按钮组件有:RaisedButton/FlatButto ...

  4. Java根据实体快速生成对象

    一.来源 在写代码时总是遇到下面这种情况: Account account = new Account(); account.setId(); account.setGmtCreate(); acco ...

  5. 沙箱测试环境配置AND证书添加

    支付宝SDK接口项目Demo测试 一.进入支付宝开放中心 下载密钥生成器 https://developers.alipay.com/developmentAccess/developmentAcce ...

  6. preg_replace修饰符e的用法

    $tmp_refer = postget('refer');$tmp_refer = preg_replace("/tn-(.*?).html/ies", "'tn-'. ...

  7. ubuntu 18.04安装mysql 8

    wget -c https://dev.mysql.com/get/mysql-apt-config_0.8.10-1_all.deb sudo dpkg -i mysql-apt-config_0. ...

  8. MySQL5.1中文文档学习笔记——第1章:一般信息(一)

    原文地址 MySQL软件是一种开放源码软件. 开放源码"意味着任何人都能使用和改变软件.任何人都能从Internet下载MySQL软件,而无需支付任何费用.如果愿意,你可以研究源码并进行恰当 ...

  9. Leetcode之148. Sort List Medium

    https://leetcode.com/problems/sort-list/ Sort a linked list in O(n log n) time using constant space ...

  10. Python笔记004-Python最基本内置数据类型和运算符

    第二章(1)Python编程基础概念 1. 最基本内置数据类型和运算符 每个对象都有类型,Python 中最基本的内置数据类型: 1. 整数 整数,2345 ,10 ,50 2. 浮点型 小数,3.1 ...