Python调用DLL动态链接库——ctypes使用
最近要使用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 = ; mainClass::mainClass()
{
} mainClass::~mainClass()
{
} void mainClass::produceData() {
dta = ;
}
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[];
int age;
int arr[];
int arrTwo[][];
}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 = ;
p->arr[] = ;
p->arr[] = ;
p->arr[] = ; for (int i = ; i < ; i++)
for (int j = ; j < ; j++)
p->arrTwo[i][j] = i*+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调用DLL动态链接库——ctypes使用的更多相关文章
- python 调用dll 动态链接库 结构体参数及回调函数等示例
结构体示例: 这里是 C 代码的部分,主要是结构体的声明和回调函数定义. // 新版本定义 typedef enum { DevCard, DevLocator, DevReader } DevTyp ...
- python调用dll详解
参考链接https://www.cnblogs.com/TQCAI/p/8881530.html https://www.jb51.net/article/52513.htm https://www. ...
- C#中调用Dll动态链接库
C#中调用Dll动态链接库 起始 受限于语言的不同,我们有的时候可能会用别人提供的函数及方法 或者其他的什么原因.反正就是要调!!! 恰巧别人所使用的的语言跟自己又不是一样的 这个时候想要调用别人的函 ...
- python 调用dll中c或c++语言的带指针方法,
在项目开发中遇到了,python需要去调用一个动态链接库dll中的c++方法.这个方法的参数为一个指针类型的参数,一个bool类型参数, 在python中并未对数字类型进行区分. int LP_Agc ...
- python调用dll方法
在python中调用dll文件中的接口比较简单,实例代码如下: 如我们有一个test.dll文件,内部定义如下: extern "C"{ int __stdcall test( v ...
- c#下调用dll动态链接库[转]
C# 调用传统的 API 动态链接库,是.NET开发经常被讨论的问题. 比如有这么一个动态链接库(delphi 语言): library DelphiDLL; uses SysUtils, Class ...
- VS2015环境下生成和调用DLL动态链接库
一.生成动态链接库: 1.打开VS2015->文件->新建->项目->Visual C++->Win32->Win32控制台应用程序->将名称改为dll_ge ...
- VBA 调用DLL动态链接库
在ArcMap中引用动态链接库 我在VB6下编译生成了一个动态链接库文件VBAPrj.dll,其中有一类模块VBACls,此类模块有一个方法Test(Doc As Object). ...
- Windows下C语言调用dll动态链接库
dll是windows下的动态链接库文件,下面记录一下在windows下如何调用C语言开发的dll动态链接库. 1.dll动态链接库的源代码 hello_dll.c #include "st ...
随机推荐
- markdown常用数学符号小结
(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦 markdown使用LaTex输入数学公式类 Markdown数学符号&公式 CSDN-MarkDown编辑器使用手册(4)- ...
- 实现组件props双向绑定解决方案
注意: 子组件不能直接修改prop过来的数据,会报错 方案一: 用data对象中创建一个props属性的副本 watch props属性 赋予data副本 来同步组件外对props的修改 watch ...
- 杂项:CSS3
ylbtech-杂项:CSS3 1.返回顶部 1. CSS3是CSS(层叠样式表)技术的升级版本,于1999年开始制订,2001年5月23日W3C完成了CSS3的工作草案,主要包括盒子模型.列表模块. ...
- class4_Listbox 列表部件
最终的运行效果图: #!/usr/bin/env python# -*- coding:utf-8 -*-# --------------------------------------------- ...
- word 文献标题自动编号
来自:word中自动编号和多级编号的使用 选中标题或段落,点击鼠标右键,在编号菜单内选择适合的自动编号样式.或者在窗口上方的“开始”选项卡中选择编号样式.如果对已选的编号样式不满意,可以照以上方法直接 ...
- 2019 牛客多校第一场 A Equivalent Prefixes
题目链接:https://ac.nowcoder.com/acm/contest/881/A 题目大意 定义 RMQ(u, L, R) 为 u 数组在区间 [L, R] 上最小值的下标. 如果有 2 ...
- Flutter介绍
1. flutter简介 Flutter是Google使用Dart语言开发的移动应用开发框架,使用一套Dart代码就能快速构建高性能.高保真的ios和Android应用程序, 并且在排版.图标.滚动. ...
- ATC/TC/CF
10.25 去打 CF,然后被 CF 打了. CF EDU 75 A. Broken Keyboard 精神恍惚,WA 了一发. B. Binary Palindromes 比赛中的憨憨做法,考虑一个 ...
- springcloud(十六):服务网关 zuul 快速入门
服务网关是微服务架构中一个不可或缺的部分.通过服务网关统一向外系统提供REST API的过程中,除了具备服务路由.均衡负载功能之外,它还具备了权限控制等功能.Spring Cloud Netflix中 ...
- pytorch clamp 与clamp_区别
pytorch clamp 与clamp_ ,有下划线的表示修改并付给自身,无下划线的表示需要返回处理后的值,比如: h = k.clamp(min=0) #将结果存入h,k保留原值 k.clamp_ ...