使用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. ...
随机推荐
- Redis Sentinel 高可用服务架构搭建
https://www.cnblogs.com/xishuai/p/redis-sentinel.html
- osg fbx 模型树结构
void Test::printOsgGroup(osg::ref_ptr<osg::Group> &groupParam) { qDebug() <<groupPar ...
- VBA基础出发
一.什么是VBA,学习的原因是什么. Visual Basic for Applicaion(VBA)是Visual Basic的一种宏语言,主要用来扩展Windows的应用程序功能.在日常生活中,使 ...
- LeetCode_28. Implement strStr()
28. Implement strStr() Easy Implement strStr(). Return the index of the first occurrence of needle i ...
- 浅谈Delphi高效使用TreeView
本来我一直都是使用递归算法, 效率很低 下边这段代码是我原来写的 ------------------------------------------------------------------- ...
- (四)HttpServletRequest对象(转)
转自“孤傲苍狼”博客. Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象.和代表响应的response对象. request和response对象即 ...
- PHP实现简单留言板
最近学习了下PHP基础,这里做一个简单的留言板,算是对PHP和MySQL的使用做一个整体的练习吧,不遇到问题总感觉学不到东西. 截图如下: 总结: 1>数据库的简单操作,数据库的增删改查: 2. ...
- PHP和MySQL.Web开发(原书第4版)学习盲点笔记
1.浏览器输出中文乱码解决: <?php header("Content-type: text/html; charset=utf-8"); ?> 相当于html中的: ...
- JQuery.BlockUI使用方法举例
JQuery.BlockUI是众多JQuery插件弹出层中的一个,它小巧(原版16k,压缩后10左右),容易使用, 功能齐全,支持Iframe,支持Modal,可定制性高也意味他默认谦虚的外表. jQ ...
- Arduino图形化编程软件ArduBlock的安装过程
ArduBlock是一款图形编程插件,接下来我们在Windows10上进行安装 注意ArduBlock虽然能安装在1.83版本的Ardunio上,但在载入程序时会报错,用本身的IDE不会出现这种情况. ...