python:使用ctypes庫調用DLL

ctypes是一個用於Python的外部函數庫。它提供C兼容的數據類型,並允許在DLL或共享庫中調用函數。它可以用來將這些庫封裝在純Python中

 

1.使用Visual Studio創建dll

 

點擊完成,創建dll導出函數,下代碼爲C++代碼

// test_dll.cpp : 定義 DLL 應用程序的導出函數。
//

#include "stdafx.h"
//用於簡單測試
extern "C" _declspec(dllexport) int add(int a, int b);

int add(int a, int b)
{
	return a+b;

}
//用於指針的使用
extern "C" _declspec(dllexport) int * add_pointer(int a, int b);
int * add_pointer(int a, int b)
{
	int *c = new int;
	*c = a + b;

	return c;

}
extern "C" _declspec(dllexport) int  get_value(int *a);
int get_value(int *a)
{
	int b = *a;
	delete a;

	return b;

}
//用於字符串使用
extern "C" _declspec(dllexport) char * str(char *a);
char * str(char *a)
{
	
	return a;

}
//用於測試結構體使用
struct Rect{

	int left;
	int top;
	int right;
	int bottom;	

};
extern "C" _declspec(dllexport) Rect struct_rect(Rect a);

Rect struct_rect(Rect a)
{
	a.left += 5;
	a.top += 5;

	return a;
}
//用於數組測試
extern "C" _declspec(dllexport) int array1(int arr[]);
int array1(int arr[])
{
	

	return arr[0];
}

2.ctypes引用dll調用函數

引用dll 有四個方法

CDLL(dllPath),WINDLL(dllPath),cdll.LoadLibrary(dllpath),windll.LoadLibrary(dllpath)

基本測試

from ctypes import *
dll = CDLL(r"C:\Users\DELL\Documents\visual studio 2013\Projects\test_dll\x64\Debug\test_dll.dll")#引入dll
num = dll.add(5,6)#調用函數
print(num)

ctypes支持的原生數據類型如下: 

ctypes類型

C類型

Python類型

c_bool

_Bool

bool (1)

c_char

char

1-character string

c_wchar

wchar_t

1-character unicode string

c_byte

char

int/long

c_ubyte

unsigned char

int/long

c_short

short

int/long

c_ushort

unsigned short

int/long

c_int

int

int/long

c_uint

unsigned int

int/long

c_long

long

int/long

c_ulong

unsigned long

int/long

c_longlong

__int64 or long long

int/long

c_ulonglong

unsigned __int64 or unsigned long long

int/long

c_float

float

float

c_double

double

float

c_longdouble

long double

float

c_char_p

char * (NUL terminated)

string or None

c_wchar_p

wchar_t * (NUL terminated)

unicode or None

c_void_p

void *

int/long or None

指針使用

 

num1 = dll.add_pointer(5,6)
print(num1)
num1 = dll.get_value(num1)
porint(num1)

如果如上面代碼直接獲取指針和引用指針會64位的python會報出如:

OSError: exception: access violation reading 0xFFFFFFFFF179FBC0

如下圖:

而且指針成了負數,應該事因爲ctypes默認的返回類型都是有符號int, 最高位表示正負的原因

解決辦法:

指定dll 函數的返回類型如下代碼

dll.add_pointer.restype = c_uint64 #指定函數返回指針類型爲c_uint64
num1_pointer =dll.add_pointer(5,6)
num1 = dll.get_value(c_uint64(num1_pointer))#參數指針類型爲c_uint64

3.字符串使用

dll.str.restype = c_char_p #c_char_p對應char指針指定返回類型爲c_char_p
str = dll.str( c_char_p(bytes("可以",encoding="utf-8")))#字符串參數,將字符串解碼,再轉(c_char_p)
print(str.decode()) #字節編碼成字符串

4 結構體使用

結構體
struct Rect{

	int left;
	int top;
	int right;
	int bottom;	

};
python 對應class類
class Rect(Structure):
    _fields_ = [

        ("left", c_int),
        ("top", c_int),
        ("right", c_int),
        ("bottom", c_int),

    ]
結構體引用
class Rect(Structure):
    _fields_ = [

        ("left", c_int),
        ("top", c_int),
        ("right", c_int),
        ("bottom", c_int),

    ]
rect = Rect(5,5,5,5)
dll.struct_rect.restype = Rect #確定返回類型爲Rect
rect = dll.struct_rect(rect) # 參數直接使用對象
print(rect.left,rect.top)

5數組的使用

arr = (c_uint*5)(1,2,3,4,5) #ctypes定義C類型數據方法
i = dll.array1(arr)
print(1)

numpy 數組傳入C/C++方法
arr1 = np.array([2, 3, 4])
if not arr1.flags['C_CONTIGUOUS']:
    arr1 = np.ascontiguous(arr1, dtype=arr1.dtype)  # 如果不是C連續的內存,必須強制轉換
arr1_point = cast(arr1.ctypes.data,POINTER(c_uint))  #轉換爲ctypes,這裏轉換後的可以直接利用ctypes轉換爲c中的int*,然後在c中使用

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章