您好,登錄后才能下訂單哦!
python如何使用ctypes庫調(diào)用DLL動態(tài)鏈接庫?針對這個問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
一、Python調(diào)用DLL里面的導(dǎo)出函數(shù)
1.VS生成dll
1.1 新建動態(tài)鏈接庫項(xiàng)目
1.2 在myTest.cpp中輸入以下內(nèi)容:
// myTest.cpp : 定義 DLL 應(yīng)用程序的導(dǎo)出函數(shù)。 // #include "stdafx.h" #define DLLEXPORT extern "C" __declspec(dllexport) //放在 #include "stdafx.h" 之后 //兩數(shù)相加 DLLEXPORT int sum(int a, int b) { return a + b; }
注意:導(dǎo)出函數(shù)前面要加 extern "C" __declspec(dllexport) ,這是因?yàn)閏types只能調(diào)用C函數(shù)。如果不用extern "C",構(gòu)建后的動態(tài)鏈接庫沒有這些函數(shù)的符號表。采用C++的工程,導(dǎo)出的接口需要extern "C",這樣python中才能識別導(dǎo)出的函數(shù)。
1.3生成dll動態(tài)鏈接庫
因?yàn)槲业膒ython3是64位的,所以VS生成的dll要選擇64位的,如下所示:
點(diǎn)擊標(biāo)題欄的 生成 -> 生成解決方案
1.4 查看生成的dll動態(tài)鏈接庫
2.Python導(dǎo)入dll動態(tài)鏈接庫
用python將動態(tài)鏈接庫導(dǎo)入,然后調(diào)用動態(tài)鏈接庫的函數(shù)。為此,新建main.py文件,輸入如下內(nèi)容:
from ctypes import * #----------以下四種加載DLL方式皆可————————— # pDLL = WinDLL("./myTest.dll") # pDll = windll.LoadLibrary("./myTest.dll") # pDll = cdll.LoadLibrary("./myTest.dll") pDll = CDLL("./myTest.dll") #調(diào)用動態(tài)鏈接庫函數(shù) res = pDll.sum(1,2) #打印返回結(jié)果 print(res)
運(yùn)行結(jié)果如下所示:
二、Python調(diào)用DLL里面的實(shí)例方法更新全局變量值
1.VS生成dll
1.1 添加 mainClass 類,內(nèi)容如下:
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 內(nèi)容
myTest.cpp:
#include "stdafx.h" #define DLLEXPORT extern "C" __declspec(dllexport) //放在 #include "stdafx.h" 之后 #include "mainClass.h" //返回實(shí)例方法里面更新數(shù)據(jù)后的值 DLLEXPORT int getRandData() { mainClass dataClass = mainClass(); dataClass.produceData(); return dta; }
1.3 生成64位dll
2.Python導(dǎo)入dll動態(tài)鏈接庫
明顯可以看出,在C++里設(shè)置的全局變量的值已經(jīng)從0變?yōu)?0了,說明python可以通過調(diào)用dll里面的實(shí)例方法來更新全局變量值
三、Python_ctypes 指定函數(shù)參數(shù)類型和返回類型
前面兩個例子C++動態(tài)鏈接庫導(dǎo)出函數(shù)的返回類型都是int型,而Python 默認(rèn)函數(shù)的參數(shù)類型和返回類型為 int 型,所以Python 理所當(dāng)然的 以為 dll導(dǎo)出函數(shù)返回了一個 int 類型的值。但是如果C++動態(tài)鏈接庫導(dǎo)出的函數(shù)返回類型不是int型,而是特定類型,就需要指定ctypes的函數(shù)返回類型 restype 。同樣,通過ctypes給函數(shù)傳遞參數(shù)時,參數(shù)類型默認(rèn)為int型,如果不是int型,而是特定類型,就需要指定ctypes的函數(shù)形參類型 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") ########## 指定 函數(shù)的參數(shù)類型 ################# pDll.getRandData.argtypes = [c_char_p] #第一個參數(shù) arg1 = c_char_p(bytes("hello", 'utf-8')) ########## 指定 函數(shù)的返回類型 ################# pDll.getRandData.restype = c_char_p ########### 調(diào)用動態(tài)鏈接庫函數(shù) ################## res = pDll.getRandData(arg1) #打印返回結(jié)果 print(res.decode()) #返回的是utf-8編碼的數(shù)據(jù),需要解碼
或者如下形式:
from ctypes import * pDll = CDLL("./myTest.dll") ########## 指定 函數(shù)的返回類型 ################# pDll.getRandData.restype = c_char_p ########### 調(diào)用動態(tài)鏈接庫函數(shù) ################## res = pDll.getRandData(b'hello') # 或者變量.encode() #打印返回結(jié)果 print(res.decode()) #返回的是utf-8編碼的數(shù)據(jù),需要解碼
運(yùn)行結(jié)果:
四、Python_ctypes dll返回?cái)?shù)組_結(jié)構(gòu)體
在ctypes里,可以把數(shù)組指針傳遞給dll,但是我們無法通過dll獲取到c++返回的數(shù)組指針。由于python中沒有對應(yīng)的數(shù)組指針類型,因此,要獲取dll返回的數(shù)組,我們需要借助結(jié)構(gòu)體。
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 這個結(jié)構(gòu)體占用的字節(jié)數(shù) //malloc(sizeof(StructTest))就是申請 struct StructPointerTest 這個結(jié)構(gòu)體占用字節(jié)數(shù)大小的空間 //(StructPointer)malloc(sizeof(StructTest))就是將申請的空間的地址強(qiáng)制轉(zhuǎn)化為 struct StructPointerTest * 指針類型 //StructPointer p = (StructPointer)malloc(sizeof(StructTest))就是將那個強(qiáng)制轉(zhuǎn)化的地址賦值給 p StructPointer p = (StructPointer)malloc(sizeof(StructTest)); //字符串 DLLEXPORT StructPointer test() // 返回結(jié)構(gòu)體指針 { 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代碼:
# 返回結(jié)構(gòu)體 import ctypes path = r'./myTest.dll' dll = ctypes.WinDLL(path) #定義結(jié)構(gòu)體 class StructPointer(ctypes.Structure): #Structure在ctypes中是基于類的結(jié)構(gòu)體 _fields_ = [("name", ctypes.c_char * 20), #定義一維數(shù)組 ("age", ctypes.c_int), ("arr", ctypes.c_int * 3), #定義一維數(shù)組 ("arrTwo", (ctypes.c_int * 3) * 2)] #定義二維數(shù)組 #設(shè)置導(dǎo)出函數(shù)返回類型 dll.test.restype = ctypes.POINTER(StructPointer) # POINTER(StructPointer)表示一個結(jié)構(gòu)體指針 #調(diào)用導(dǎo)出函數(shù) p = dll.test() print(p.contents.name.decode()) #p.contents返回要指向點(diǎn)的對象 #返回的字符串是utf-8編碼的數(shù)據(jù),需要解碼 print(p.contents.age) print(p.contents.arr[0]) #返回一維數(shù)組第一個元素 print(p.contents.arr[:]) #返回一維數(shù)組所有元素 print(p.contents.arrTwo[0][:]) #返回二維數(shù)組第一行所有元素 print(p.contents.arrTwo[1][:]) #返回二維數(shù)組第二行所有元素
運(yùn)行結(jié)果:
關(guān)于python如何使用ctypes庫調(diào)用DLL動態(tài)鏈接庫問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。