Python使用ctypes操作c/c++ DLL

1 生成一个C/C++ 动态链接库

dlloutput.cpp  输出对外的接口函数


#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "A.h"

#define DLLEXPORT extern "C" __declspec(dllexport)

static A  A_a = A(); //定义一个A的静态变量操作类A中的函数
				   //两数相加 int
DLLEXPORT int A_add2(int a, int b) {
	return A_a.add2(a,b);
}


//两数相加 int
DLLEXPORT int ADD1(int a, int b) {
	return a + b;
}
//两数相减 float
DLLEXPORT float sub1(float a, float b) {
	//printf("%f\n", a-b);
	return a - b;
}

//两数相减 float
DLLEXPORT float mul(float a, float b) {
	//printf("%f", a * b);
	return a * b;
}
//传入int指针 返回int 
DLLEXPORT int getNumber(int *a) {
	*a = 2;
	return *a+1;
}

//传入int指针 返回int 
DLLEXPORT int getNumber2(int &a) {
	a = 2;
	return a + 1;
}

//传入int数组指针 返回int 
DLLEXPORT int getsum(int *a,int n) {
	int sum = 0;
	for(int i = 0;i < n;i++)
	{
		sum += a[i];
	}
	return sum;
}
//传入int数组指针 返回int 
DLLEXPORT int getsum2(int a[], int n) {
	a[0] = 10;
	int sum = 0;
	for (int i = 0; i < n; i++)
	{
		sum += a[i];
	}
	return sum;
}
//传入char数组指针 修改位置0的值 
DLLEXPORT void updatechararray(char*a, int n) {
	a[0] = 'a';
	
}

//传入字符 返回字符
DLLEXPORT char* getstring(char * f) {

	return "hello world";
}


//对结构体的操作,
struct bbox_t {
	unsigned int x, y, w, h;    // (x,y) - top-left corner, (w, h) - width & height of bounded box
	float prob;                    // confidence - probability that the object was found correctly  类的概率
	unsigned int obj_id;        // class of object - from range [0, classes-1] 类标签
	unsigned int track_id;        // tracking id for video (0 - untracked, 1 - inf - tracked object) 追踪视频的目标id
	unsigned int frames_counter;// counter of frames on which the object was detected  目标被探测到的次数
};

#define C_SHARP_MAX_OBJECTS 1000
struct bbox_t_container {
	bbox_t candidates[C_SHARP_MAX_OBJECTS];
};

//传入结构体的指针或者引用并修改其中的值
DLLEXPORT int  updateBoxContainner(bbox_t_container &b) {

	b.candidates[1].x = 100;
	printf("%d", b.candidates[0].x);
	return 1;
}

//传入结构体的指针或者引用并修改其中的值 
DLLEXPORT int  updatebox(bbox_t &b) {

	b.x = 1020;
	printf("%d", b.x);
	return 1;
}
DLLEXPORT int  updatebox2(bbox_t *b) {

	b->x = 1020;
	printf("%d", b->x);
	return 1;
}



A.h 和A.cpp

//--------A.h
#pragma once

class A{
public:
	  int add2(int a,int b);
};


//--------A.cpp
#include "A.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include<windows.h>
#define DLLEXPORT extern "C" __declspec(dllexport)


int A::add2(int a, int b)
{
	return a+b;
}

2 python使用ctypes 举例

   https://docs.python.org/3.6/library/ctypes.html#structures-and-unions

   

mport os
import sys
import ctypes
from ctypes    import *
from threading import Thread
import time


#载入接口 C:\Users\user\Documents\Visual Studio 2015\Projects\wxt1\x64\Release\wxt1.dll
#最好是绝对路径引用,如果使用的dll还引用了其他的dll,所有的引用的dll都需要放在同一个文件夹下或者系统目录下
path2=r"C:\Users\user\Documents\Visual Studio 2015\Projects\wxt1\x64\Release\wxt1.dll"
lib = ctypes.windll.LoadLibrary(path2)

# 传入int 相加,返回int  1,2 直接传入函数不需要类型转换,整形可以直接互相转换
print("1+2=",lib.ADD1(1,2))

print("1+2=",lib.A_add2(1,2))
# 传入float 相减 返回float 
x1=c_float(1.0)#对于float 类型的必须指定
x2=c_float(2.0)
lib.sub1.restype=c_float  #此处必须指定 返回类型是float
print("1-2=",lib.sub1(x1,x2))
# 1*2
lib.mul.restype=c_float  #此处必须指定 返回类型是float
print("1*2=",lib.mul(c_float(1.0),c_float(2.0)))

#传入字符串 返回字符串
s1=b"hello"  #字符串一定是转成bytes 这里再字符串前加上b
lib.getstring.restype=c_char_p  #必须确定返回类型为:c_char_p
s2=str(lib.getstring(s1))
print("S:",s2)

#传入整数指针返回整数,并通过指针修改n的大小
n=c_int(1)
print(lib.getNumber(byref(n)))
print(n)
#传入整数引用返回整数,并通过指针修改n的大小
n=c_int(1)
print(lib.getNumber(byref(n)))
print(n)


#传入int 数组指针 返回总和,同时修改位置0的值
p=(c_int * 10)()
for i in range(10):
    p[i] = i

print(lib.getsum2(p,10))
#print(lib.getsum2(byref(p),10)) 加上byref也可以
print(p[0])

#传入char[] 并修改位置0的值
p=(c_char * 10)()
for i in range(10):
    p[i] = i

print(lib.updatechararray(p,10))
print(p[0],p[1],p[2],p[3])

#传入结构体并对结构体进行操作  
# 按下面的方式定义结构体
C_SHARP_MAX_OBJECTS=1000
class bbox_t(Structure):
    _fields_=[("x",c_uint),("y",c_uint),("w",c_uint),("h",c_uint)
                ,("prob",c_float),("obj_id",c_int),("track_id",c_int),("frames_counter",c_int)]

box=bbox_t()
# lib.updatebox2(byref(box)) #传入box的引用修改box   C/C++中的函数无论是 传指针还是引用 使用byref都是可以的
lib.updatebox2(byref(box)) #传入box的指针修改box
print(box.x)

#结构体中放自定义结构体的数组增加测试复杂性 
class bbox_t_container(Structure):
    _fields_ = [("candidates",bbox_t * C_SHARP_MAX_OBJECTS)]    

boxContainer = bbox_t_container()
lib.updateBoxContainner(byref(boxContainer)) #传入引用

print(boxContainer.candidates[1].x)

3 常见的问题

   (1)传参错误的报错如下,检查传参类型,个数是否正确

     

猜你喜欢

转载自blog.csdn.net/wxtcstt/article/details/99858968