python高階教程-調用win c/c++ dll文件
- 2019 年 11 月 20 日
- 筆記
本篇內容來自原創小冊子《python高階教程》
背景
某些情況下,我們需要python與其他程式語言,如c/c++聯合運行,以獲得額外的性能或者功能。比如,將 經常調用的業務邏輯用c重寫一遍,提高效率;或者重複利用已經開發好的dll庫,縮短開發周期。
兩種調用c/c++庫的方式
- __stdcall方式
在python中通過dll = ctypes.WinDLL("TestDll.dll")
調用
- __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
- ctypes中的c與python對象映射表
- 指針作為參數