Python調用C++類庫 (踩坑日誌)

Python調用C++類庫 (踩坑日誌)

原由

開發自動化工具過程當中,須要使用專業的測試射頻參數的儀器IQmeasure,廠家提供的API只用C ++版本。
客戶端使用python(wxpython)開發,因此遇到了python調用C ++類庫的問題。html

環境

  • PyCharm2020
  • python3.6.12  32位   (python3.8沒法使用,64位python沒法使用;其餘版本未測試)
  • IQmeasure_SCPI.dll (供應商給的dll包)
  • IQmeasure.chm (dll對應的文檔)

參考資料

ctypes的python官方文檔python

使用

使用前請先瀏覽ctypes官方文檔工具

  1. 建立一個新項目(python使用3.6.12 32位版本)
  2. 將dll文件放入根目錄
  3. 根目錄建立main.py

目錄結構以下

test
├── IQmeasure_SCPI.dll
├── venv
└── main.py學習

基礎使用方法以下(main.py):

from ctypes import *

# 加載dll包
iq = cdll.LoadLibrary('./IQmeasure_SCPI.dll')
# 調用方法
init_result = iq.LP_Init(c_int(0), c_int(1))
print('init_result:', init_result)  # init_result: 0
# 該方法中,返回0爲成功

# 原C++文檔中,該方法以下:
# int LP_Init(int IQtype = IQTYPE_XEL,int testerControlMethod = 1);

知識點

  • 使用ctypes.cdll.LoadLibrary()加載dll包
  • 參數須要轉換爲c的類型(如c_int(),不理解的先看一下參考資料 ctypes的python官方文檔
  • 在C++中的可選參數,在使用python調用時不可省略,請傳入方法中的默認值

有返回值

from ctypes import *

# 加載dll包
iq = cdll.LoadLibrary('./IQmeasure_SCPI.dll')

# 有返回值
# 設置返回值類型
iq.LP_GetErrorString.restype = c_char_p
# 設置初始值類型
iq.LP_GetErrorString.argtypes = [c_int]

msg = iq.LP_GetErrorString(c_int(10))
print(msg)  # b'Invalid analysis type'
# 轉換爲string
str_msg = msg.decode("utf-8")
print(str_msg) # VSA number is out of range. Try 1-4.

# 原C++文檔中,該方法以下:
# char* LP_GetErrorString(int err)

知識點

  • 有返回值時,使用 .方法名.restype 設置返回值類型
  • 參數值也可以使用相似方法設置,使用 .方法名.argtypes 設置參數類型

參數值爲 *類型

簡單得查了資料,帶 好像是指針類型吧,開發着急因此沒有深刻學習了,相似int , char * 這樣的測試

# ...省略加載dll

# 參數值爲*類型
# 使用byref(),包裝對應類型便可
iq.LP_SetTesterMode(c_int(0), byref(c_int(1)), c_int(1))
# 原C++文檔中,該方法以下:
# int LP_SetTesterMode( int signalMode = UP_TO_80MHZ_SIGNAL, int *selectedModules = NULL, int numOfSelectedModules = 1 );

知識點

  • 參數爲*類型的參數,使用byref包裝

引用類型參數

# ...省略加載dll

version = create_string_buffer(4096)
iq.LP_GetVersion(version, 4096)
version_result = version.value.decode("utf-8")
# 原C++文檔中,該方法以下:
# 該方法會改變*buffer,python中須要讀取*buffer的值
# bool LP_GetVersion(char *buffer, int buf_size);

知識點

  • 方法參數傳入後,方法會改變原參數,須要讀取改參數的新值
  • 先建立一個buffer
  • 調用方法
  • 將buffer轉換回來

完整測試代碼

from ctypes import *

# 加載dll包
iq = cdll.LoadLibrary('./IQmeasure_SCPI.dll')
# 調用方法
init_result = iq.LP_Init(c_int(0), c_int(1))
print('init_result:', init_result)  # init_result: 0
# 該方法中,返回0爲成功

# 原C++文檔中,該方法以下:
# int LP_Init(int IQtype = IQTYPE_XEL,int testerControlMethod = 1);

# 有返回值
# 設置返回值類型
iq.LP_GetErrorString.restype = c_char_p
# 設置初始值類型
iq.LP_GetErrorString.argtypes = [c_int]

msg = iq.LP_GetErrorString(c_int(10))
print(msg)  # b'Invalid analysis type'
# 轉換爲string
str_msg = msg.decode("utf-8")
print(str_msg)  # VSA number is out of range. Try 1-4.

# 原C++文檔中,該方法以下:
# char* LP_GetErrorString(int err)

# 參數值爲*類型
# 使用byref(),包裝對應類型便可
iq.LP_SetTesterMode(c_int(0), byref(c_int(1)), c_int(1))
# 原C++文檔中,該方法以下:
# int LP_SetTesterMode( int signalMode = UP_TO_80MHZ_SIGNAL, int *selectedModules = NULL, int numOfSelectedModules = 1 );

version = create_string_buffer(4096)
iq.LP_GetVersion(version, 4096)
version_result = version.value.decode("utf-8")
# 原C++文檔中,該方法以下:
# 該方法會改變*buffer,python中須要讀取*buffer的值
# bool LP_GetVersion(char *buffer, int buf_size);

總結

由於對C ++不甚瞭解,對C ++部分的解釋、名詞有誤差,水平限制勿怪,歡迎私信糾正。指針

內容爲本人和駱小萍同窗在開發實踐中獲得rest

以上日誌

相關文章
相關標籤/搜索