美文网首页
Python 调用dll Part1

Python 调用dll Part1

作者: welder77 | 来源:发表于2022-06-04 23:00 被阅读0次

    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

          本文链接:https://www.haomeiwen.com/subject/xvllmrtx.html