网站首页 文章专栏 python 调用win c/c++ dll文件
python 调用win c/c++ dll文件
创建于:2021-07-04 08:20:45 更新于:2024-05-03 14:59:48 羽瀚尘 441

调用win c/c++ dll文件

背景

某些情况下,我们需要python与其他编程语言,如c/c++联合运行,以获得额外的性能或者功能。比如,将
经常调用的业务逻辑用c重写一遍,提高效率;或者重复利用已经开发好的dll库,缩短开发周期。

两种调用c/c++库的方式

  1. __stdcall方式

在python中通过dll = ctypes.WinDLL("TestDll.dll")调用

  1. __cdecl方式

在python中通过dll = ctypes.cdll.LoadLibrary("TestDll.dll")调用

具体使用了哪种方式需要看源码,如果不知道源码,可以两种方式都试试,错误的调用方式会
出现以下ValueError.

ValueError: Procedure called with not enough arguments (8 bytes missing) or wrong calling convention

查看dll中的函数名称

实际上,编译器会修改函数的名称。虽然可以通过.def文件来禁止编译器做修改,但是尚未发现在MinGW上如果操作。在本文中使用Dependency Walker(depends)软件读取dll中的函数列表,获取函数名称。

下载地址

简单Demo

  1. TestDll.h文件

    #ifdef __cplusplus
    extern "C"{
    #endif
    int __stdcall __declspec(dllexport) MyAdd(int nA, int nB);
    #ifdef __cplusplus
    }
    #endif
    
  2. TestDll.cpp文件

    #include "TestDll.h"
    #ifdef __cplusplus
    extern "C"{
    #endif
    int __stdcall __declspec(dllexport) MyAdd(int nA, int nB)
    {
    return nA + nB;
    }
    #ifdef __cplusplus
    }
    #endif
    
  3. TestDll.bat编译脚本

    gcc TestDll.cpp -shared -o TestDll.dll
    
  4. TestDll.py调用

    import ctypes
    ## 导出函数是__stdcall声明的使用
    dll = ctypes.WinDLL("TestDll.dll")
    ## 导出函数是__cdecl声明的使用
    #dll = ctypes.cdll.LoadLibrary("TestDll.dll")
    summmm = getattr(dll, 'MyAdd@8')
    ret = summmm(2, 4)
    print(ret)
    

运行后会看到python脚本输出了正确结果。

TODO

  1. ctypes中的c与python对象映射表
  2. 指针作为参数