Python 调用dll Part1

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)

你可能感兴趣的:(Python 调用dll Part1)