使用ctypes调用系统C API函数需要注意的问题,函数参数中有指针或结构体的情况下最好不要修改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)
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的更多相关文章
- C语言--- 高级指针2(结构体指针,数组作为函数参数)
一.结构体指针 1. 什么是结构体指针?指向结构体变量的指针 结构体: typedef struct stu{ char name[ ...
- C++ 利用指针和数组以及指针和结构体实现一个函数返回多个值
C++ 利用指针和数组实现一个函数返回多个值demo1 #include <iostream> using namespace std; int* test(int,int,int); i ...
- (60) 结构体指针、结构体变量嵌套、结构体指针嵌套、函数指针、数组指针、指针数组、typedef 综合运用
#include<stdio.h> #include<iostream> #include<malloc.h> /* author : 吴永聪 program: 结 ...
- C语言基础知识点整理(函数/变量/常量/指针/数组/结构体)
函数 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ...
- Delphi调用WINAPI时到底应该是指针还是结构体(注意是Delphi变量本身就是指针)
看MSDN,GetWindowRect的说明如下: BOOL WINAPI GetWindowRect( _In_ HWND hWnd, _Out_ LPRECT lpRect // 注意,没* ...
- C与指针(结构体指针,函数指针,数组指针,指针数组)定义与使用
类型 普通指针 指针数组(非指针类型) 数组指针 结构体指针 函数指针 二重指针 定义方式 int *p; int *p[5]; int (*p)[5]; int a[3][5]; struct{.. ...
- 调用系统相机拍照,保存照片,调用系统裁剪API对照片处理,显示裁剪之后的照片
package com.pingyijinren.test; import android.annotation.TargetApi; import android.app.Notification; ...
- Python3基础 函数 参数 在设定缺省值的情况下指明参数类型
Python : 3.7.3 OS : Ubuntu 18.04.2 LTS IDE : pycharm-community-2019.1.3 ...
- 调用系统api修改系统时间
一:截图 二:代码 using System; using System.Collections.Generic; using System.ComponentModel; using System. ...
随机推荐
- sklearn里计算roc_auc_score,报错ValueError: bad input shape
用sklearn的DecisionTreeClassifer训练模型,然后用roc_auc_score计算模型的auc.代码如下 clf = DecisionTreeClassifier(criter ...
- C语言中的异常处理
一 前言: 异常处理,对于做面向对象开发的开发者来说是再熟悉不过了,例如在C#中有 try { ... } catch( Exception e){...} finally{ ..... } 在C++ ...
- osg 场景漫游
#ifdef _WIN32 #include <Windows.h> #endif // _WIN32 #include <osg/Group> #include <os ...
- 算法习题---3.12浮点数(UVa11809)
一:题目 尴尬的非会员水印 二:题目摘要 1.int和float比较 int共32位,可以表示的最大的数为2^32次方 float虽然也是32位,但是是以指数形式保存,指数占8位(含符号),最大127 ...
- Linux下开发常用配置
JDK /etc/profile export JAVA_HOME=/usr/local/jdk1.8.0_181export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.ja ...
- <configSections> 位置引起的错误
今天在配置一个项目的时候,花了挺长时间配置完成,然后一启动项目,懵了,启动报错:错误显示 Configuration Error Description: An error occurred duri ...
- WordPress主题制作:基础样式文件
1.style.css文件,其中必须包含 /* Theme Name:主题名称 Theme URI: 主题链接 Version: 版本 Description: 主题简介 Author: 主题作者 A ...
- FineReport点击输入框直接展示下拉框列表
引用自帆软官方文档-http://help.finereport.com/doc-view-1899.html 1. 描述 下拉框以及下拉复选框默认状态,必须点击最右侧的三角才可以实现下拉,不够人性化 ...
- 粒子系统与雨的效果 (DirectX11 with Windows SDK)
前言 最近在学粒子系统,看这之前的<<3D图形编程基础 基于DirectX 11 >>是基于Direct SDK的,而DXSDK微软已经很久没有更新过了并且我学的DX11是用W ...
- Qt598x64vs2017.跨线程传递std::string
1.Qt编译的时候 提示 str::string 需要在main(...)中注册什么的(大概是这个意思,记不清了),于是 在main(...)中调用了 “qRegisterMetaType<st ...