python使用ctypes库调用DLL动态链接库
作者:蛋片鸡 发布时间:2023-12-08 14:14:05
最近要使用python调用C++编译生成的DLL动态链接库,因此学习了一下ctypes库的基本使用。
ctypes是一个用于Python的外部函数库,它提供C兼容的数据类型,并允许在DLL或共享库中调用函数。
一、Python调用DLL里面的导出函数
1.VS生成dll
1.1 新建动态链接库项目
1.2 在myTest.cpp中输入以下内容:
// myTest.cpp : 定义 DLL 应用程序的导出函数。
//
#include "stdafx.h"
#define DLLEXPORT extern "C" __declspec(dllexport) //放在 #include "stdafx.h" 之后
//两数相加
DLLEXPORT int sum(int a, int b) {
return a + b;
}
注意:导出函数前面要加 extern "C" __declspec(dllexport) ,这是因为ctypes只能调用C函数。如果不用extern "C",构建后的动态链接库没有这些函数的符号表。采用C++的工程,导出的接口需要extern "C",这样python中才能识别导出的函数。
1.3生成dll动态链接库
因为我的python3是64位的,所以VS生成的dll要选择64位的,如下所示:
点击标题栏的 生成 -> 生成解决方案
1.4 查看生成的dll动态链接库
2.Python导入dll动态链接库
用python将动态链接库导入,然后调用动态链接库的函数。为此,新建main.py文件,输入如下内容:
from ctypes import *
#----------以下四种加载DLL方式皆可—————————
# pDLL = WinDLL("./myTest.dll")
# pDll = windll.LoadLibrary("./myTest.dll")
# pDll = cdll.LoadLibrary("./myTest.dll")
pDll = CDLL("./myTest.dll")
#调用动态链接库函数
res = pDll.sum(1,2)
#打印返回结果
print(res)
运行结果如下所示:
二、Python调用DLL里面的实例方法更新全局变量值
1.VS生成dll
1.1 添加 mainClass 类,内容如下:
mainClass.h:
#pragma once
extern int dta;
class mainClass
{
public:
mainClass();
~mainClass();
void produceData();
};
mainClass.cpp:
#include "stdafx.h"
#include "mainClass.h"
int dta = 0;
mainClass::mainClass()
{
}
mainClass::~mainClass()
{
}
void mainClass::produceData() {
dta = 10;
}
1.2 更改 myTest.cpp 内容
myTest.cpp:
#include "stdafx.h"
#define DLLEXPORT extern "C" __declspec(dllexport) //放在 #include "stdafx.h" 之后
#include "mainClass.h"
//返回实例方法里面更新数据后的值
DLLEXPORT int getRandData() {
mainClass dataClass = mainClass();
dataClass.produceData();
return dta;
}
1.3 生成64位dll
2.Python导入dll动态链接库
明显可以看出,在C++里设置的全局变量的值已经从0变为10了,说明python可以通过调用dll里面的实例方法来更新全局变量值
三、Python_ctypes 指定函数参数类型和返回类型
前面两个例子C++动态链接库导出函数的返回类型都是int型,而Python 默认函数的参数类型和返回类型为 int 型,所以Python 理所当然的 以为 dll导出函数返回了一个 int 类型的值。但是如果C++动态链接库导出的函数返回类型不是int型,而是特定类型,就需要指定ctypes的函数返回类型 restype 。同样,通过ctypes给函数传递参数时,参数类型默认为int型,如果不是int型,而是特定类型,就需要指定ctypes的函数形参类型 argtypes 。
接下来,我将举一个简单例子来说明一下
myTest.cpp:
#include "stdafx.h"
#define DLLEXPORT extern "C" __declspec(dllexport) //放在 #include "stdafx.h" 之后
#include <string> //使用string类型 需要包含头文件 <string>
using namespace std; //string类是一个模板类,位于名字空间std中
//字符串
DLLEXPORT char *getRandData(char *arg) {
return arg;
}
python代码:
from ctypes import *
pDll = CDLL("./myTest.dll")
########## 指定 函数的参数类型 #################
pDll.getRandData.argtypes = [c_char_p]
#第一个参数
arg1 = c_char_p(bytes("hello", 'utf-8'))
########## 指定 函数的返回类型 #################
pDll.getRandData.restype = c_char_p
########### 调用动态链接库函数 ##################
res = pDll.getRandData(arg1)
#打印返回结果
print(res.decode()) #返回的是utf-8编码的数据,需要解码
或者如下形式:
from ctypes import *
pDll = CDLL("./myTest.dll")
########## 指定 函数的返回类型 #################
pDll.getRandData.restype = c_char_p
########### 调用动态链接库函数 ##################
res = pDll.getRandData(b'hello') # 或者变量.encode()
#打印返回结果
print(res.decode()) #返回的是utf-8编码的数据,需要解码
运行结果:
四、Python_ctypes dll返回数组_结构体
在ctypes里,可以把数组指针传递给dll,但是我们无法通过dll获取到c++返回的数组指针。由于python中没有对应的数组指针类型,因此,要获取dll返回的数组,我们需要借助结构体。
myTest.cpp:
#include "stdafx.h"
#define DLLEXPORT extern "C" __declspec(dllexport) //放在 #include "stdafx.h" 之后
#include <string> //使用string类型 需要包含头文件 <string>
using namespace std; //string类是一个模板类,位于名字空间std中
typedef struct StructPointerTest
{
char name[20];
int age;
int arr[3];
int arrTwo[2][3];
}StructTest, *StructPointer;
//sizeof(StructTest)就是求 struct StructPointerTest 这个结构体占用的字节数
//malloc(sizeof(StructTest))就是申请 struct StructPointerTest 这个结构体占用字节数大小的空间
//(StructPointer)malloc(sizeof(StructTest))就是将申请的空间的地址强制转化为 struct StructPointerTest * 指针类型
//StructPointer p = (StructPointer)malloc(sizeof(StructTest))就是将那个强制转化的地址赋值给 p
StructPointer p = (StructPointer)malloc(sizeof(StructTest));
//字符串
DLLEXPORT StructPointer test() // 返回结构体指针
{
strcpy_s(p->name, "Lakers");
p->age = 20;
p->arr[0] = 3;
p->arr[1] = 5;
p->arr[2] = 10;
for (int i = 0; i < 2; i++)
for (int j = 0; j < 3; j++)
p->arrTwo[i][j] = i*10+j;
return p;
}
python代码:
# 返回结构体
import ctypes
path = r'./myTest.dll'
dll = ctypes.WinDLL(path)
#定义结构体
class StructPointer(ctypes.Structure): #Structure在ctypes中是基于类的结构体
_fields_ = [("name", ctypes.c_char * 20), #定义一维数组
("age", ctypes.c_int),
("arr", ctypes.c_int * 3), #定义一维数组
("arrTwo", (ctypes.c_int * 3) * 2)] #定义二维数组
#设置导出函数返回类型
dll.test.restype = ctypes.POINTER(StructPointer) # POINTER(StructPointer)表示一个结构体指针
#调用导出函数
p = dll.test()
print(p.contents.name.decode()) #p.contents返回要指向点的对象 #返回的字符串是utf-8编码的数据,需要解码
print(p.contents.age)
print(p.contents.arr[0]) #返回一维数组第一个元素
print(p.contents.arr[:]) #返回一维数组所有元素
print(p.contents.arrTwo[0][:]) #返回二维数组第一行所有元素
print(p.contents.arrTwo[1][:]) #返回二维数组第二行所有元素
运行结果:
来源:https://www.cnblogs.com/FHC1994/p/11421229.html


猜你喜欢
- golang常用库之-pkg/errors包背景golang自带了错误信息包error只提供了简单的用法, 如errors.New(),和e
- 本文实例为大家分享了python使用sendmail发送邮件的具体代码,供大家参考,具体内容如下参考链接:How do I send mai
- Pycharm创建的项目,使用了虚拟环境,对库的版本进行管理;有些项目的对第三方库的版本 要求不同,可使用虚拟环境进行管理直接想通过pip命
- 刚开始时,这个表的字段很少(10个以内),前开发者把这个表的所有存储过程与触发器以及表函数全是写死了。用户每添加一些字段,都需要手动去更改这
- /* --注意:准备数据(可略过,非常耗时) CREATE TABLE CHECK1_T1 ( ID INT, C1 CHAR(8000)
- 当下基本所有的目标检测类的任务都会选择基于深度学习的方式,诸如:YOLO、SSD、RCNN等等,这一领域不乏有很多出色的模型,而且还在持续地
- 在这种配置下我们要实现关键词不区分大小写搜索并高亮显示要借助ASP的正则处理了,请看下面代码:<% Function&nbs
- 今天,数据库的操作越来越成为整个应用的性能瓶颈了,这点对于Web应用尤其明显。关于数据库的性能,这并不只是DBA才需要担心的事,而这更是我们
- 为什页面刷新会出现404因为vue项目中路由hash模式改为了history模式,由于hash模式时url带的#号后面是哈希值不会作为url
- 最近在研究python调度框架APScheduler使用的路上,那么今天也算个学习笔记吧!# coding=utf-8""
- 本文实例为大家分享了python实现简单的飞机大战的具体代码,供大家参考,具体内容如下制作初衷这几天闲来没事干,就想起来好长时间没做过游戏了
- 禁用默认事务为了确保数据一致性,GORM 会在事务里执行写入操作(创建、更新、删除)。如果没有这方面的要求,您可以在初始化时禁用它,这将获得
- 1.在用windows模式登陆sql server 数据库 简历一个student的数据库,然后新建查询:create table stud
- 随着网络的普及,基于网络的应用也越来越多。网络数据库就是其中之一。通过一台或几台服务器可以为很多客户提供服务,这种方式给人们带来了很多方便,
- 首先我们看公式:这个是要拟合的函数然后我们求出它的损失函数, 注意:这里的n和m均为数据集的长度,写的时候忘了注意,前面的theta0-th
- 本文记录django中如何使用celery完成异步任务。Celery 是一个简单、灵活且可靠的,处理大量消息的分布式系统,并且提供维护这样一
- 一、中间件的基本使用在web开发中,中间件起着很重要的作用。比如,身份验证、权限认证、日志记录等。以下就是各框架对中间件的基本使用。1.1
- 首先,与其他语言不同,JS的效率很大程度是取决于JS engine的效率。除了引擎实现的优劣外,引擎自己也会为一些特殊的代码模式采取一些优化
- 最近发现数据库服务器压力很大,CPU经常达到100%。查看进程,发现有大量的sp_cursorclose;1进程信息。网上查了下,出现sp_
- 一、背景介绍在 Python 项目开发过程中,根据不同的项目场景,需要切换不同的 Python 版本。因此,我们经常会对不同的项目,创建特定