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中使用

 

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