python使用ctypes库调用DLL动态链接库


Posted in Python onOctober 22, 2020

最近要使用python调用C++编译生成的DLL动态链接库,因此学习了一下ctypes库的基本使用。

ctypes是一个用于Python的外部函数库,它提供C兼容的数据类型,并允许在DLL或共享库中调用函数。

一、Python调用DLL里面的导出函数

1.VS生成dll

1.1 新建动态链接库项目

python使用ctypes库调用DLL动态链接库

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位的,如下所示:

python使用ctypes库调用DLL动态链接库

点击标题栏的 生成 -> 生成解决方案 

python使用ctypes库调用DLL动态链接库

1.4 查看生成的dll动态链接库

python使用ctypes库调用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使用ctypes库调用DLL动态链接库

二、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动态链接库

python使用ctypes库调用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动态链接库

四、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][:]) #返回二维数组第二行所有元素

运行结果:

python使用ctypes库调用DLL动态链接库

以上就是python使用ctypes库调用DLL动态链接库的详细内容,更多关于python 调用DLL动态链接库的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
Django验证码的生成与使用示例
May 20 Python
Python使用zip合并相邻列表项的方法示例
Mar 17 Python
pygame游戏之旅 计算游戏中躲过的障碍数量
Nov 20 Python
浅谈Python基础—判断和循环
Mar 22 Python
Python的log日志功能及设置方法
Jul 11 Python
使用Python和OpenCV检测图像中的物体并将物体裁剪下来
Oct 30 Python
Python中zip函数如何使用
Jun 04 Python
OpenCV 之按位运算举例解析
Jun 19 Python
ITK 实现多张图像转成单个nii.gz或mha文件案例
Jul 01 Python
python文件及目录操作代码汇总
Jul 08 Python
python对批量WAV音频进行等长分割的方法实现
Sep 25 Python
解决Python 写文件报错TypeError的问题
Oct 23 Python
Python通过len函数返回对象长度
Oct 22 #Python
python 还原梯度下降算法实现一维线性回归
Oct 22 #Python
利用Pycharm + Django搭建一个简单Python Web项目的步骤
Oct 22 #Python
python处理写入数据代码讲解
Oct 22 #Python
基于Python爬取股票数据过程详解
Oct 21 #Python
OpenCV利用python来实现图像的直方图均衡化
Oct 21 #Python
Python实现手势识别
Oct 21 #Python
You might like
PHP 杂谈《重构-改善既有代码的设计》之三 重新组织数据
2012/04/09 PHP
php权重计算方法代码分享
2014/01/09 PHP
一个php生成16位随机数的代码(两种方法)
2014/09/16 PHP
php实现的替换敏感字符串类实例
2014/09/22 PHP
PHP利用超级全局变量$_GET来接收表单数据的实例
2016/11/05 PHP
php基于curl实现的股票信息查询类实例
2016/11/11 PHP
增强用户体验友好性之jquery easyui window 窗口关闭时的提示
2012/06/22 Javascript
onkeydown事件解决按回车键直接提交数据的需求
2013/04/11 Javascript
JS/FLASH实现复制代码到剪贴板(兼容所有浏览器)
2013/05/27 Javascript
使用ImageMagick进行图片缩放、合成与裁剪(js+python)
2013/09/16 Javascript
node.js中的http.request方法使用说明
2014/12/14 Javascript
日常收集整理的JavaScript常用函数方法
2015/12/10 Javascript
基于javascript数组实现图片轮播
2016/05/02 Javascript
解决IE11 vue +webpack 项目中数据更新后页面没有刷新的问题
2018/09/25 Javascript
深入理解JavaScript的值传递和引用传递
2018/10/24 Javascript
微信小程序实现笑脸评分功能
2018/11/03 Javascript
vue.js的双向数据绑定Object.defineProperty方法的神奇之处
2019/01/18 Javascript
JS精确判断数据类型代码实例
2019/12/18 Javascript
[05:20]2018DOTA2亚洲邀请赛主赛事第三日战况回顾 LGD率先挺进胜者组决赛
2018/04/06 DOTA
[37:21]完美世界DOTA2联赛PWL S2 Inki vs Magma 第二场 11.22
2020/11/24 DOTA
Python3实现的Mysql数据库操作封装类
2018/06/06 Python
Python不使用int()函数把字符串转换为数字的方法
2018/07/09 Python
使用Python实现正态分布、正态分布采样
2019/11/20 Python
Django 删除upload_to文件的步骤
2020/03/30 Python
PyQt5如何将.ui文件转换为.py文件的实例代码
2020/05/26 Python
python interpolate插值实例
2020/07/06 Python
如何在 Matplotlib 中更改绘图背景的实现
2020/11/26 Python
Python 按比例获取样本数据或执行任务的实现代码
2020/12/03 Python
HTML5中如何显示视频呢 HTML5视频播放demo
2013/06/08 HTML / CSS
人力资源管理毕业生自荐信
2013/11/21 职场文书
2015教师见习期工作总结
2014/12/12 职场文书
优秀学生干部事迹材料
2014/12/24 职场文书
爱牙日宣传活动总结
2015/02/05 职场文书
幼儿园教师自荐书
2015/03/06 职场文书
优秀班主任工作总结2015
2015/05/25 职场文书
Sql Server 行数据的某列值想作为字段列显示的方法
2022/04/20 SQL Server