python高階教程-調用win c/c++ dll文件

  • 2019 年 11 月 20 日
  • 筆記

本篇內容來自原創小冊子《python高階教程》

背景

某些情況下,我們需要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. 指針作為參數