Python常被誉为胶水语言,很大的一方面原因,在于其能很方便与其他语言结合使用,比如:调用C++ 编译的dll文件。以下简单介绍下其调用dll的常用案例。
1. 导入dll
python中调用dll,主要会依赖ctypes这个库,其中提供了两个LibraryLoader的方法:CDLL和WinDLL。
CDLL支持__cdecl,WinDLL支持__stdcall(仅限Windows),说实话我并不清楚两种方式具体的差异,所以在实际调用dll时,会采用以下试错法,确定dll文件是否可以被导入Python。
from ctypes import *
try:
dll = CDLL('/TSMaster.dll')
except:
try:
dll = WinDLL('/TSMaster.dll')
except:
print ('failed to load lib')
2. 获取dll的输入及输出参数
如果dll包含.h文件或API参考文档,则首选参考其参数列表或文档进行参数的选择。
如果没有.h文件,则可以考虑用ViewApi等工具查看或导出dll参数列表。以下为一个.h文件的例子。
从.h文件中,我们通常可以获取两个信息,1. 参数的数据类型,2. 参数是输入还是输出参数
p.s. 有些.h文件并不会标明输入输出参数,此时,只能根据经验判断或参考API列表来确定了。
TSAPI(s32) initialize_lib_tsmaster(const char* AAppName);
TSAPI(s32) tsapp_configure_baudrate_can(const s32 AIdxChn, const float ABaudrateKbps, const bool AListenOnly, const bool AInstallTermResistor120Ohm);
3. 确定python中调用dll时,相应变量的数据类型
(1) 对于大部分bool, int, float, char 或 char*类型输入参数,我们大多可以直接参考下表,用对应的ctypes类型做转换后输入dll,或直接用对应的python类型给DLL赋值,比如:
#.h
TSAPI(s32) initialize_lib_tsmaster(const char* AAppName);
#python
AppName = b"YFT_Tester"
ret= dll.initialize_lib_tsmaster(AppName)
#或
ret= dll.initialize_lib_tsmaster(c_char_p(AppName))
print(ret)
#.h
TSAPI(s32) tsapp_configure_baudrate_can(const s32 AIdxChn, const float ABaudrateKbps, const bool AListenOnly, const bool AInstallTermResistor120Ohm);
#python
chn = 0
bitrate = 500.0
AListenOnly = False
Resistor = True
ret = dll.tsapp_configure_baudrate_can( c_int(chn), c_float(bitrate), AListenOnly, Resistor)
print(ret)
v2-7f950185c3eaababc7f15237a93b6dda_r.jpg
(2) 对于数组类型的变量。
数组:
# C++
void update(double a[], int size)
{
for (int i = 0; i < size; i++)
*a++ *= 0.0098;
}
#Python
arr = (c_double*5)() #*5为数组的数量
arr[0] = 100
arr[1] = 200
arr[2] = 300
arr[3] = 200
arr[4] = 200
dll.update(byref(arr), len(arr))
#通常输入参数,可使用byref()来传递引用参数,它不会创建指针对象
#pointer()作为传参通常会创建一个实际的指针对象,多于用输出参数。
(3)对于结构体
结构体:
如果需要将结构体作为dll的输入或输出参数,我们必须新建一个类,并必须继承Structure和Union基础类,它们都在ctypes模块中定义,每一个子类必须定义个fields属性,fields是一个二维的tuples列表,包含着每个field的name及type,这field类型必须是一个ctypes类型,如c_int,或者任何其他的继承ctypes的类型,如Structure, Union, Array, 指针等。
#.h
typedef struct _TCANFD{
u8 FIdxChn;
u8 FProperties;
u8 FDLC;
u8 FFDProperties;
s32 FIdentifier;
s64 FTimeUs;
u8 FData[64];
......
} TCANFD, *PCANFD;
TSAPI(s32) tsapp_add_cyclic_msg_canfd(const PCANFD ACANFD, const float APeriodMS);
#Python
class TLIBCANFD(Structure):
_pack_ = 1
_fields_ = [("FIdxChn", c_uint8), # channel
("FProperties", c_uint8), # 定义canfd数据类型 1:FD标准帧 5:FD扩展帧
("FDLC", c_uint8), # dlc
("FFDProperties", c_uint8), # 0:普通can数据帧 1:canfd数据帧
("FIdentifier", c_int32), # msg id
("FTimeUs", c_ulonglong), # time stamp
("FData", c_ubyte * 64), # msg data
]
ret = dll.tsapp_add_cyclic_msg_canfd(byref(Msg), c_float(APeriodMS))
print(ret)
网友评论