厉害了,Python也能使用动态链接库
回复“书籍”即可获赠Python从入门到进阶共10本电子书
今
日
鸡
汤
未谙姑食性,先遣小姑尝。
大家好,我是Python进阶者。
前言
动态链接库(DLL)想必大家都不陌生了吧,C/C++编程经常会用到,那么,它跟我们的Python有什么关系?要说关系恐怕也就是Python是用C写的了,不过,还有一点更重要的关系,那就是Python可以调用C函数,这一点,在Pywin32中有所体现。下面我们就来详细了解下到底Python使用动态链接库是怎么回事吧。
一、神秘的模块
我们都知道C语言是比较靠近底层的语言,所以我们要想使用动态链接库就要给Python和C构建一座桥梁。今天我们要说的这座桥梁就是---Ctypes。
二、安装并导入Ctypes
系统自带有该模块,若没有,安装Pywin32也就有了。
from ctypes import *
三、认识动态链接库
动态链接库在linux 系统中表现为“.so”的后缀文件,而在Windows中表现为”.dll“的后缀文件。
四、初步了解Ctypes
安装好后我们需要对Ctypes做一个大致的了解,首先我们得先查看它的所有函数及其方法。
接下来我们就将对这些方法做一个简单的了解,并且配上一个小实例让大家看了之后更容易懂,让天底下不再有十分艰难的编程问题存在是我们的宗旨。
五、Ctypes的基本用法
1).数据类型
Ctypes很完美的契合了C的数据类型,丰富多样,下面我们来看看吧:
ctypes 类型 | C 类型 | Python 类型 |
---|---|---|
c_bool | _Bool | bool (1) |
c_char | char | 单字符字节对象 |
c_wchar | wchar_t | 单字符字符串 |
c_byte | char | 整型 |
c_ubyte | unsigned char | 整型 |
c_short | short | 整型 |
c_ushort | unsigned short | 整型 |
c_int | int | 整型 |
c_uint | unsigned int | 整型 |
c_long | long | 整型 |
c_ulong | unsigned long | 整型 |
c_longlong | __int64 或 long long | 整型 |
c_ulonglong | unsigned __int64 或 unsigned long long | 整型 |
c_size_t | size_t | 整型 |
c_ssize_t | ssize_t 或 Py_ssize_t | 整型 |
c_float | float | 浮点数 |
c_double | double | 浮点数 |
c_longdouble | long double | 浮点数 |
c_char_p | char * (以 NUL 结尾) | 字节串对象或 None |
c_wchar_p | wchar_t * (以 NUL 结尾) | 字符串或 None |
c_void_p | void * | int 或 None |
我们可以看到这些都是可以在Python中使用的C语言数据类型。我们一起来看看它的用处吧:
我们可以看到这些基本就是数据类型的使用方法了,也是挺简单的。
2).操作变量
刚刚我们定义了许多类型的变量,下面我们像使用C语言变量一样来使用它们。
1)).访问变量的值
it.value
2)).修改变量的值
it.value=43 #直接赋值,即可修改
3)).给变量添加指针
#强指针
pt=pointer(it) pointer(c_int(10)) #定义指针,指向变量 pt,pt是指针内存地址
pt.contents #指针所指的对象
#弱指针 比强指针速度快
byref(it,4) #it:c的实例 4:偏移量
#返回一个指针的图片来做一个C实例,只可用作为函数参数
上面的指针只是简单的创建了指针实例,还有一种方法可以指定指针类型,然后进行创建:
aa=POINTER(c_int) #创建指针
aa(c_int(43)) #创建指针实例
aa(c_int(43)).contents.value#获取指针的值
也可以创建一个空指针:
POINTER(c_int)() #创建空指针,空指针是一个bool值
可以看出空指针没有Contents属性。
也可以使用抽象基类“_Pointer”来完成指针的操作:
import ctypes
class ss(ctypes._Pointer): #这里必须带上ctypes,否则会报错_type_=c_intcontents=c_float
aa=ss(c_int(10)) #指定对象类型为整形
print(aa.contents) #替换为浮点类型
3).创建修改缓冲
Ctypes定义的指针类型是不可以修改的,如果需要在C函数中被修改,需要使用一些函数来修改,下面来看看:
1)).字符缓冲
p=create_string_buffer(4) #创建一个4字节缓冲区 初始化为空字节
create_string_buffer(b"Hello") #创建一个包含空字符结尾字符串缓冲区
create_string_buffer(b"Hello", 10) #创建一个10字节缓冲区
print(sizeof(p),repr(p.raw)) #内存块大小 字节信息
2)).unicode缓冲
a=create_unicode_buffer(5) #创建一个10字节的unicode字符缓冲区
create_unicode_buffer('ffsa')
create_unicode_buffer('ffsa',5) #结尾空字符
print(sizeof(a)) #内存块大小
4).调用动态链接库
动态链接库的调用方法很多,任你挑选。
CDLL(xx.dll)
OleDLL(xx.dll)
PyDLL(xx.dll)
WinDLL(xx.dll)
cdll.LoadLibrary(xx.dll)
oledll.LoadLibrary(xx.dll)
pydll.LoadLibrary(xx.dll)
windll.LoadLibrary(xx.dll)
#也可使用链接库读取器LibraryLoader,它也同样支持上面的八种方式
LibraryLoader(CDLL('C:\\Windows\\System32\\user32.dll'))
LibraryLoader(cdll.LoadLibrary('C:\\Windows\\System32\\user32.dll'))
综上所述,调用动态链接库的方法共有16种之多。
5).查找动态链接库
from ctypes.util import find_library
find_library('user32')# 查找
6).调用动态链接库函数
dll=windll.LoadLibrary(xx.dll)
dll.函数名
7).Windows Api函数
所有的Window Api 函数都包含在Dll中,其中有几个非常重要的Dll:
kernel32.dll #用于管理内存、进程和线程的各个函数
user32.dll #用于创建用户界面的各个函数
gdi32.dll #用于画图和显示文本的各个函数
advapi32.dll #用于操作注册表、系统终止与重启、Windows服务启动/停止/创建、账户管理的各个函数
shell32.dll #用于访问操作系统shell提供的功能
netapi32.dll #用于访问操作系统提供的各种通信功能
comctl32.dll #用于访问操作系统的状态条、进度条、工具条等功能
comdlg32.dll #用于管理文件打开、文件保存、颜色字体选择等标准对话框#调用这些dll非常简单:
windll.gdi32 #即可
8).获取模块头
windll.kernel32#同时导出同一个函数的ANSI版本(GetModuleHandleA)和UNICODE版(GetModuleHandleW)
windll.kernel32.GetModuleHandleA(0) #里面只允许有0或者None,其它会报错
windll.kernel32.GetModuleHandleW()
9).Dll基本信息获取
当我们读取Dll后有时候需要对它的路径或者句柄进行操作,这个时候我们需要获取这些参数:
1)).获取窗口句柄
dll._handle
2)).获取Dll绝对路径
dll._name
10).调用Python中的Os模块中的所有方法
这个自是不必说,与Os模块密切相关。
os=ctypes._os
os.getcwd()
11).打印字符长度
windll.msvcrt.printf(b'fsfs') #不支持中文输出 输出为4
windll.msvcrt.printf('fsfs') #输出为2
#以下情况与上相同
cdll.msvcrt.printf('fsfs')
pydll.msvcrt.printf('fsfs')
oledll.msvcrt.printf('fsfs')
12).获取C实例内部缓冲区地址
addressof(c_int(30))
13).判断是否有管理员权限
windll.shell32.IsUserAnAdmin()
cdll.shell32.IsUserAnAdmin()
pydll.shell32.IsUserAnAdmin()
oledll.shell32.IsUserAnAdmin()
#结果返回1则表示有,否则无
通过判断当前用户是否为管理员用户后,我可以进行下一步操作,如果是则打开浏览器,如果不是则尝试打开:
import ctypes, sys
def admin():try:aa=ctypes.windll.shell32.IsUserAnAdmin()except:returnfinally:return aa
if admin()==1:os.popen(r'E:\360browser\360se6\Application\360se.exe')
else:if sys.version_info[0] == 3:ctypes.windll.shell32.ShellExecuteW(0, "runas", sys.executable,'',__file__,0)else:print('版本太低,不支持2.0')#sys.executable:python主程序的绝对路径
#__file__:当前程序的绝对路径
14).让鼠标键盘失灵
aa=cdll.LoadLibrary('C:\\Windows\\System32\\user32.dll')
aa.BlockInput(True)#键盘鼠标被锁定
time.sleep(5) # 锁定五秒
aa.BlockInput(False) #被释放
15).打开文件或者应用程序
aa=windll.shell32.ShellExecuteW(0,'open','C:\\Windows\\System32\\notepad.exe','',os.path.join(os.path.dirname(__file__),'OSI.txt'),0)
#参数1:父窗口的句柄,如果没有父窗口,则为0
#参数2:要运行的操作,如:runas,open,print
#参数3:要运行的程序绝对路径
#参数4:给程序传递的参数,如果打开的是文件则为空
#参数5:要打开的文件的绝对路径
#参数6:是否显示窗口 0:后台打开 1:前台打开
#如果aa返回值小于32则表示打开失败
aa.bit_length()#指定数值的二进制的长度数、宽度数
16).结构体和联合体
要想使用必须从Structure 和 Union 继承,子类必须定义,Fields 属性,Fields属性必须是一个二元组的列表。
元祖中第一个是变量名,第二个是数据类型,可以是Ctypes任意一种变量类型。
1))结构体Structure
也可以一次性传递多个不同数据类型的参数:
2)).联合体Union
它和结构体的使用方法一样,但是结果不同,下面我们来看下:
造成这一区别的原因联合体所有成员变量共用一块内存,可以内存复用;而结构体,每个成员变量占用一块内存。
17).数组操作
ARRAY(type,len) #前者是Ctypes的某个类型的值,而后者是值的长度,返回一个值与长度的乘积
Array(*args) #它是一个数组抽象基类, 我们可以重写它来进行使用,
class cx(Array):_length_=100 #重写方法_length_(数组中元素的数量)_type_=c_int #指定数组中每个元素的类型(整形)
aa=cx(12,32,43,324,54,4,32,34,52434)
print(aa[2],aa[5:7]) #利用下标或者切片访问
18).改变对象的内存缓冲区大小
Ctypes可以重新设置对象的内存缓冲区大小:
可以看到,此时的同一个对象内存缓冲区大小不一样
19).转换指向不同数据类型的指针
这里我们用到了一个神器的函数“Cast”,它可以将不同的数据类型的指针进行转换。
class bb(Structure):_fields_ = [("val", POINTER(c_int))]
b=bb()
b.val=cast((c_float*4)(1.2,3.2,4.3),POINTER(c_int))
print(b.val[1])
20).进程操作
aa=0x00000020 #定义正常优先级的类
ker=windll.LoadLibrary('kernel32.dll') #加载动态链接库
crk=ker.CreateProcessA #获得创建后的进程的函数地址
rk=ker.ReadProcessMemory #获得读取进程内存的函数地址
wk=ker.WriteProcessMemory #获得写入进程内存的函数地址
ker.TerminateProcess #终止进程
print(ker,'\n',crk,'\n',rk,'\n',wk)
21).调用Window系统Api
就以Window 弹框函数MessageBox为例。
from ctypes import c_int, WINFUNCTYPE, windll
from ctypes.wintypes import HWND, LPCWSTR, UINT
tp = WINFUNCTYPE(c_int, HWND, LPCWSTR, LPCWSTR, UINT) #window函数类型
bt = (1, "hwnd", 0), (1, "text", "我是内容"), (1, "caption", "我是标题"), (1, "type", 0)
MessageBox =tp(("MessageBoxW", windll.user32),bt) #调用消息弹框函数
MessageBox()
ab=MessageBox(caption='提示',text="我也是内容") #设置弹框参数
aa=MessageBox(caption='警告',type=2,text="是否进入?")
if aa==3: #判断输出类型print('终止操作')
if aa==4:print('重试')
if aa==5:print('忽略')
可以看到当我选择了中止之后它便提示终止操作。其实还有一种类似的方法:
注:这里弹窗的参数均不支持中文,务必按我上面的格式写,不然会出错。
22).获取Windows窗口中的所有顶层窗口的值
from ctypes import *
from ctypes import wintypes
#定义回调函数类型
res= WINFUNCTYPE(wintypes.BOOL,wintypes.HWND, wintypes.LPARAM)
def win(h,p):#实现回调函数功能,函数为bool类型;h:顶层窗口的句柄 p:应用程序定义的一个值,le= user32.GetWindowTextLengthW(h)+1 #获取window文本长度,加1可获取完整的信息buffer = create_unicode_buffer(le) #创建缓冲user32.GetWindowTextW(h, buffer, le) #获取window文本print(buffer.value) #获取缓冲区中的信息return True
user32 = windll.LoadLibrary('user32.dll')#加载dll
user32.EnumWindows(res(win), 0) #枚举顶层窗口,不列举子窗口
六、总结
Ctypes总的来说还是蛮不错的,挺适合C语言小白学习,毕竟Api的确太多太复杂了,还是Python友好点。
小伙伴们,快快用实践一下吧!如果在学习过程中,有遇到任何问题,欢迎加我好友,我拉你进Python学习交流群共同探讨学习。
------------------- End -------------------
往期精彩文章推荐:
Python中encode和encoding的区别是什么?
手把手教你使用openpyxl库从Excel文件中提取指定的数据并生成新的文件(附源码)
手把手教你用Python来模拟绘制自由落体运动过程中的抛物线(附源码)
盘点3种Python网络爬虫过程中的中文乱码的处理方法
欢迎大家点赞,留言,转发,转载,感谢大家的相伴与支持
想加入Python学习群请在后台回复【入群】
万水千山总是情,点个【在看】行不行
/今日留言主题/
随便说一两句吧~
厉害了,Python也能使用动态链接库相关推荐
- python调用C语言动态链接库详解
python调用动态链接库详解 Python 调用动态链接库 环境说明 构建动态链接库 python动态链接库基础调用 python动态链接库结构体调用 python动态链接库回调函数 本文介绍在li ...
- python ctypes库中动态链接库加载方式
最近看了<Gray hat python>一书,这才知道为什么python是黑客必学的编程语言.通过python的ctypes模块,可以直接调用动态链接库中的导出函数,而且甚至可以直接在p ...
- python真的这么厉害吗-Python为什么这么厉害?——Python ,能用来做什么
[摘要]Python的特点之一在于,使用简单的语法,就能处理大量复杂问题.这使得初学者能够专注于学习编程概念,同时不必担心太多的细节,还可以节省大量时间.比如以编程中最常见的程序" Hell ...
- python 加载DLL动态链接库
软件+环境:VS2013.C#.pycharm.python3.8 一.利用VS2013 编写 dll 1.新建项目,请把名称写的容易识别一点 2.代码如下,大致就包含两个函数,一个返回 一列字符串, ...
- 真厉害用python只要50行代码爬取黑丝美眉纯欲高清图
要说最美好的欲望莫过于看黑丝美眉. 一.技术路线 requests:网页请求 BeautifulSoup:解析html网页 re:正则表达式,提取html网页信息 os:保存文件 import re ...
- python真的很厉害吗-python为什么这么牛?Python真有这么好的前景?
要说最近几年最火的语言,python绝对可以拥有姓名,最近几年Python更是有超越Java之势.python的应用范围非常非常的广泛,但Python的整体语言难度来讲又比Java简单的很多.尤其是在 ...
- python fortran混合编程输入矩阵_如何将动态数组从Python传递到Fortran动态链接库
我在Python调用fortran dll时遇到了一些问题,我真的需要一些帮助和建议. 我的问题是将动态数组传递给函数(由Fortran DLL提供).在 例如,我有一个带有动态数组的类型:Modul ...
- 厉害的Python工程师,都是怎么做学习规划的?超详细学习入门—精通教程
随着Python的发展,已成为程序员能力模型中,非常重要的一个技能. 甚至BATZJ的工程师,都无可否认现在Python对于一个程序员职业发展的重要性. 但很多小白在面对"怎么规划未来Pyt ...
- 一个超级厉害的python病毒
切勿在实体机上运行! 兼容系统:python 3.5+,windows 7+ 说明:需手动安装keyboard库(pip install keyboard) 声明:本程序仅供学习和研究使用,请在创建后 ...
最新文章
- 2016.4.2 动态规划练习--讲课整理
- .NET应用三层架构分析
- 大数据预测:成都、郑州等跻身春节十大“瘦身”城市
- python中try_python中try...excpet多种使用方法
- 知识图谱(五)——实体消歧
- log4j异步mysql_log4j2用Log4jContextSelector启动参数配置全局异步日志是如何使用disruptor...
- python的socket编程接收浏览器上传的文件_使用python套接字编程将文件发送到浏览器...
- 详解linux运维工程师入门级必备技能
- Qt 实现控件抖动 动画窗口抖动 QQ抖动
- 极限学习机原理(含公式推导透彻)
- 小米笔记本linux指纹,小米笔记本Air13.3寸指纹版(128GB) u盘装系统win10步骤
- CT一般扫描参数_工业CT检测服务
- adguard home上网慢_如何正确使用smartdns搭配adguardhome, 优选dns并去除广告
- 【微信小程序】深入学习小程序基本目录文件与代码结构
- 5分钟学会使用Excel插入数据统计图
- Python IDLE编写代码 输入反斜杠\显示为人民币符号¥
- python 微信二次开发_python微信公众账号二次开发
- SpringSecurity:授权
- linux桌面 任务栏,状态栏消失恢复
- 网页源代码隐藏域中存在密码
热门文章
- Vue双向绑定失效 v-model
- (一)Siamese目标跟踪——SiamFC训练和跟踪过程:从论文细节角度出发
- 魔方APP项目-04-用户模块API接口、Marshmallow,基本构造器(Schema),Schema数据序列化、Schema数据反序列化、反序列化对数据验证、模型构造器(ModelSchema)
- 从0开发游戏引擎之引擎基础组件-Node类实现
- 手机/移动端的UI框架-Vant和NutUI
- 俞敏洪大学经典励志演讲:像树一样活着
- 浅聊Java反射机制(三)
- 护肤品买了这么多还是不见好转,钱都去哪里了?
- 面试必问之JVM原理 1
- 长短期记忆网络LSTM