目录

  • 用处
  • 文档翻译
    • windows加载dll
    • linux加载so
    • 声明函数
    • 调用约定
    • 数据类型
    • 使用ctypes类型
    • 传递指针
    • 结构体
    • 结构体 字段对齐和字节序
    • 数组
    • 类型强制转换
    • 回调函数
    • dll导出的值
  • 例子

用处

ctypes主要还是用于调用dll和so里面的函数

文档翻译

windows加载dll

from ctypes import windll, cdll
# 加载Windows的kernel32.dll
print(windll.kernel32)
# 加载Windows的msvcrt.dll,和libc一样,里面是Windows的标准库函数
print(cdll.msvcrt)

linux加载so

from ctypes import cdll, CDLL
# 方法1
libc1 = cdll.LoadLibrary("libc.so.6")
# 方法2
libc2 = CDLL("libc.so.6")

声明函数

如果函数的参数和返回值是基础类型(字符串和数值),则可以直接调用函数,无需声明

from ctypes import windll
handle = windll.kernel32.GetModuleHandleA(None)
print(hex(handle ))
t = cdll.msvcrt.time(None)
print(t)
printf = cdll.msvcrt.printf
printf(b"Hello, %s\n", b"World!")

如果函数参数或返回值包含一些复杂数据类型,则需要先声明函数参数(argtypes )和返回值(restype)

from ctypes import *
from ctypes.wintypes import *GetModuleHandleA = windll.kernel32.GetModuleHandleA
GetModuleHandleA.argtypes = (LPCSTR,)
GetModuleHandleA.restype = HMODULE
handle = GetModuleHandleA(None)
print(hex(handle))

直接调用GetModuleHandleA和声明之后调用,返回值是不一样的,这是因为返回的指针类型没有被正确解释。所以调用dll的函数前最好先声明函数的参数和类型

比如调用kernel32.dll的GetModuleHandleA,可以先在微软的官方文档中搜一下函数原型

调用约定

ctypes只支持两种调用约定,cdll支持cdecl调用约定,windll支持stdcall调用约定。还有个oledll也是stdcall调用约定,没看到和windll有啥区别

数据类型

使用ctypes类型

from ctypes import *i = c_int(10)
print(i)
print(c_wchar_p("Hello, World"))
print(c_ushort(-3))i.value = 100
print(i)

传递指针

可以用byref函数来传递指针,当然也可以用pointer函数,一样的效果,但是byref效率更高,因为pointer需要构造一个真实的指针。

from ctypes import *i = c_int(100)
f = c_float(3.14)
s = create_string_buffer(b"address: ")
cdll.msvcrt.printf(b"%s %p %x", s, byref(f), pointer(i))

结构体

继承Structure,然后声明_fields_ 字段就可以定义一个结构体类型

from ctypes import *class POINT(Structure):_fields_ = [("x", c_int),("y", c_int)]point = POINT(10, 20)
print(point.x, point.y)
point = POINT(y=5)
print(point.x, point.y)

结构体嵌套

class RECT(Structure):_fields_ = [("upperleft", POINT),("lowerright", POINT)]
rc = RECT(POINT(1, 2), POINT(3, 4))
# rc = RECT((1, 2), (3, 4))
print(rc.upperleft.x, rc.upperleft.y)
print(rc.lowerright.x, rc.lowerright.y)

结构体 字段对齐和字节序

默认对齐方式和C一样。可以用_pack_ 属性来定义,值可以设置一个正整数,表示字段的最大对齐方式,和#pragma pack(n)效果是一样的

ctypes 中的结构体使用的是本地字节序,要使用非本地字节序,可以使用 BigEndianStructure, LittleEndianStructure, BigEndianUnion, LittleEndianUnion 作为基类。这些类不能包含指针字段

数组

# 定义
a = c_char * 4
# 赋值
s = a(b'a', b'b', b'c', b'\x00')

等同于

char a[4] = "abc";

类型强制转换

比如将一个float类型指针强制转换为int类型指针

from ctypes import *a = pointer(c_float(3.14))print(cast(a, POINTER(c_int)).contents)

当然输出结果肯定不是3

回调函数

在Python中定义一个可以在dll里面被调用的函数

qsort是一个排序函数,第一个参数是排序的数组,第二个是数组长度,第三个是数组元素的大小,第四个是个回调函数,如果返回值小于0,a将放在b前面,如果大于0,a将放在b后面

from ctypes import *def py_cmp_func(a, b):print("py_cmp_func", a[0], b[0])return a[0]-b[0]IntArray5 = c_int * 5
ia = IntArray5(5, 1, 7, 33, 99)
qsort = cdll.msvcrt.qsort
qsort.restype = NoneCMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
cmp_func = CMPFUNC(py_cmp_func)qsort(ia, len(ia), sizeof(c_int), cmp_func)
print(list(ia))

CFUNCTYPE定义cdecl调用约定的函数,WINFUNCTYPE定义stdcall 调用约定的函数。第一个参数为返回值类型,后面的则是参数类型

也可以通过装饰器的形式定义

@CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
def py_cmp_func(a, b):print("py_cmp_func", a[0], b[0])return a[0] - b[0]

dll导出的值

动态链接库不止可以导出函数,也可以导出变量。这里的pythonapi,其实就是加载的python.dll

from ctypes import *opt_flag = c_int.in_dll(pythonapi, "Py_OptimizeFlag")
print(opt_flag)

例子

枚举进程的所有模块信息

c语言大概代码

hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE32 | TH32CS_SNAPMODULE, dwPID );
if( hModuleSnap == INVALID_HANDLE_VALUE ) { return( r_mi );
}
me32.dwSize = sizeof( MODULEENTRY32 );
if( !Module32First( hModuleSnap, &me32 ) ) { CloseHandle( hModuleSnap );return( r_mi );
}
do { } while( Module32Next( hModuleSnap, &me32 ) );

Python翻译

第一步:定义结构体 MODULEENTRY32

from ctypes import *
from ctypes.wintypes import *class MODULEENTRY32(Structure):_fields_ = [("dwSize", DWORD), # 结构的大小,以字节为单位,必须先初始化("th32ModuleID", DWORD), # 该成员不再使用,并且始终设置为 1("th32ProcessID", DWORD), # 进程pid("GlblcntUsage", DWORD), # 无意义, 一般等于0xFFFF("ProccntUsage", DWORD), # 无意义, 一般等于0xFFFF("modBaseAddr", POINTER(BYTE)), # 拥有进程上下文中模块的基地址("modBaseSize", DWORD), # 模块的大小,以字节为单位("hModule", HMODULE), # 拥有进程上下文中的模块句柄("szModule", c_char*256), # 模块名称("szExePath",  c_char*260), # 模块路径]

第二步:定义函数

kernel32 = WinDLL('kernel32', use_last_error=True)def func_def(name, restype, *argtypes, dll=kernel32):def errcheck(result, func, args):if not result:raise WinError(get_last_error())return resultcfunc = getattr(dll, name)cfunc.argtypes = argtypescfunc.restype = restype#cfunc.errcheck = errcheckreturn cfuncCreateToolhelp32Snapshot = func_def("CreateToolhelp32Snapshot", HANDLE, *(DWORD, DWORD))
Module32First = func_def("Module32First", BOOL, *(HANDLE, POINTER(MODULEENTRY32)))
Module32Next = func_def("Module32Next", BOOL, *(HANDLE, POINTER(MODULEENTRY32)))
CloseHandle = func_def("CloseHandle", BOOL, *(HANDLE,))

第三步:

TH32CS_SNAPMODULE = 0x00000008
TH32CS_SNAPMODULE32 = 0x00000010def getModuleInfo(moduleName, pid):'''获取模块信息,返回模块信息的字典'''hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE|TH32CS_SNAPMODULE32, pid)me32 = MODULEENTRY32()me32.dwSize = sizeof(MODULEENTRY32)bRet = Module32First(hModuleSnap, pointer(me32))while bRet:szModule = me32.szModule.decode()if szModule.upper() == moduleName.upper():addr = cast(me32.modBaseAddr, c_void_p).value # hex(addressof(modBaseAddr.contents))CloseHandle(hModuleSnap)try:me32.szExePath.decode("gbk")except UnicodeDecodeError:print(me32.szExePath)module = {'modBaseSize': me32.modBaseSize, # 模块字节大小'th32ProcessID': me32.th32ProcessID, # 进程pid'modBaseAddr': addr, # 模块基址"hModule": me32.hModule, # 模块句柄'szModule': me32.szModule.decode("ansi"), # 模块名称'szExePath': me32.szExePath.decode("ansi") # 模块路径}return modulebRet = Module32Next(hModuleSnap, pointer(me32) )CloseHandle(hModuleSnap)import os
import syspy_version = str(sys.version_info[0]) + str(sys.version_info[1])
print(getModuleInfo(f"python{py_version}.dll", os.getpid()))

Python基础库-ctypes相关推荐

  1. Python基础库-正则表达式库

    ​ ​ 活动地址:CSDN21天学习挑战赛 文章目录 1.正则表达式 1.1正则表达概述 1.2正则表达式库 1.3一个简单的例子:检查用户输入的邮箱地址是否合法 2.正则表达式-原子 3.正则表达式 ...

  2. python基础代码库-CNN详解-基于python基础库实现的简单CNN

    CNN,即卷积神经网络,主要用于图像识别,分类.由输入层,卷积层,池化层,全连接层(Affline层),Softmax层叠加而成.卷积神经网络中还有一个非常重要的结构:过滤器,它作用于层与层之间(卷积 ...

  3. python基础库-python基础库-Pandas

    s1,s2,s3为3个Series,用其组成一个人dataframe: df_new = pd.DataFrame([s1,s2,s3],index=["A","B&qu ...

  4. 【Python基础库】保留重要缓存内容 dill 使用【案例】

    保存重要变量数据 例子如下 import dill#保存变量 T='Hiya' val=[1,2,3] a = np.zeros([4,5]) #建立一个缓存的文件 filename= 'global ...

  5. 【Python基础库】-在dataframe中错位相减-使用shift()函数

    shift 英文:偏移 DataFrame.shift(periods=1, freq=None, axis=0) 参数 periods:类型为int,表示移动的幅度,可以是正数,也可以是负数,默认值 ...

  6. Python基础模块:图像处理模块@PIL(批量分类处理图片及添加水印)

    大家好,才哥又来了! 又要上班了,春节总是过的太匆匆. 最近接到一个需求,把一批照片按照分辨率进行分类存储,再将其中指定宽高比的照片设置为特定的分辨率且添加水印. 以下是简单的效果: 目录: 文章目录 ...

  7. python 基础命令-Python 命令行(CLI)基础库

    在 CLI 下写 UI 应用 前阵子看了一下自己去年写的 Python-视频转字符动画,感觉好糗..所以几乎把整篇文章重写了一遍.并使用 curses 库实现字符动画的播放. 但是感觉,curses ...

  8. Python中运用的基础库

    库名称简介 Chardet字符编码探测器,可以自动检测文本.网页.xml的编码. colorama主要用来给文本添加各种颜色,并且非常简单易用. Prettytable主要用于在终端或浏览器端构建格式 ...

  9. python基础代码库-Python基础数据处理库-NumPy

    最近更新:2017-07-19 NumPy是Python做数据处理的底层库,是高性能科学计算和数据分析的基础,比如著名的Python机器学习库SKlearn就需要NumPy的支持.掌握NumPy的基础 ...

最新文章

  1. 3次握手中的最后一个ACK服务端收到了吗
  2. A folder failed to be moved——Android SDK的安装问题解决方案
  3. WIFI配置专项测试
  4. io操作是指什么_各种IO模型,一篇打尽
  5. 1732: 数花费(Kruscal)
  6. python参数默认值实例_Python中使用partial改变方法默认参数实例
  7. 微软服务器收费吗,了解 Azure 外部服务收费
  8. 配置 Sybase数据源
  9. TCP/IP笔记-Qt使用Win10pcap发送以太帧(理论与实践)
  10. 安卓actionbar上的搜索按钮点击没反应如何解决
  11. 论文笔记--跨媒体语义共享子空间学习理论与方法研究-2015
  12. Python selenium 延时的几种方法
  13. java 任务栏程序_如何为Java Swing程序动态启用或禁用任务栏图标
  14. 学会2种方法,小白也能快速产出标准的Axure原型
  15. 产品经理学习——Axure常用快捷键
  16. 树莓派搭建DLNA客户端,使用gmediarender,DLAN render。
  17. android高效ORM数据库框架greenDao使用
  18. Oracle视图(View)----------------数据库中虚拟的表
  19. Spring Boot整合websocket实现群聊,点对点聊天,图片发送,音频发送
  20. CSS之关于min-width、max-width、min-height和max-height的使用

热门文章

  1. java滚动条_java Swing界面优化JscrollPane滚动条教程
  2. 如何在html网页内引入css样式
  3. Ubuntu 中WPS乱码问题
  4. 计算机文化基础知识梳理,计算机文化基础知识梳理.doc
  5. SQL Server中row_number函数用法介绍
  6. 如果去掉数学前后的空格_如何取消excel表格中数据前的空格-Excel 如何去除单元格中数字前后的空格...
  7. 导出数据Excel打开乱码问题
  8. 关于Python中面向对象的理解
  9. HDUOJ 2087 剪花布条
  10. 常用的数字正则(严格匹配)