看介紹python語言時,說它是膠水語言,可以調用其他語言。通過使用ctypes模塊就可以調用C語言的動態庫。下面先放上官方文檔和幾個比較好的博文。
1、官方文檔:http://python.net/crew/theller/ctypes/tutorial.html
2、Python調用windows下DLL詳解 - ctypes庫的使用:
http://blog.csdn.net/magictong/article/details/3075478
3、聊聊Python ctypes 模塊:
https://zhuanlan.zhihu.com/p/20152309
4、Python的學習(三十二)---- ctypes庫的使用整理
http://blog.csdn.net/linda1000/article/details/12623527
5、ctypes使用指南:
http://blog.csdn.net/samdy2008/article/details/52139142
因為這個實例,自己也只是簡單使用沒有整明白,所以先把參考的幾個文章列出來。
把C語言編譯為動態鏈接庫。Windows下動態鏈接庫的擴展名是dll,Linux下是so,Mac OS X下是dylib。
Gcc編譯出的動態庫,python調用時,可以直接調用原型,不需要做特殊處理。
VS使用的編譯器是 MSVC,和g++編譯出來的動態庫,需要特珠聲明才能被調用。因為編譯出的函數名實際上不是本來的名字,這也是C++可以重載的原因,真實的函數名已經變了。
頭文件中定義
#ifdef __cplusplus extern "C" { //這個是必須有的 #endif
/*************************************
*函數功能:打開攝像頭
不是函數接口,所以不需要特殊處理
*************************************/
INT8U BSP_CameraOpen(INT8U ucPort);
/*************************************
*函數功能:獲取圖像
因是接口,需要特殊處理
*************************************/
_declspec(dllexport) INT8U BSP_CameraGetPhoto(INT8U ucFormat,INT8U *pDataBuf,INT16U *pDataLen);
/*
拍照片初始化,即創建串口,打開攝像頭,之后就可以直接操作讀照片了。
因是接口,需要特殊處理
*/
_declspec(dllexport) int ComCamInit(void);
#ifdef __cplusplus
};
#endif
如不特殊處理,python加載庫時不會報錯,但是調用函數接口時,會拋出找不到函數的異常。(編譯庫時,函數名字變了嘛)
>>> import ctypes #導入ctypes庫 >>> testdll = ctypes.CDLL(r"D:\project program\photo\VS_dll\photo_dll\photo_dll.dll") >>> ret = testdll.ComCamInit() #調用庫中的ComCamInit()函數,返回0說明返回成功了。 >>> ret 0
庫里的BSP_CameraGetPhoto()函數,參數為INT8U *pDataBuf,INT16U *pDataLen,需要傳入一個數組的指針,用於返回獲取到的圖片數據,和一個short類型的指針用於保存返回的長度。
所以要用到數組的映射和指針的映射,也就是C語言的數據類型轉換為ctypes中的數據類型。
基本類型映射
>>>type_uchar_array_20k = ctypes.c_char * (20*1024) #創建一個20K的char型數組類型type_uchar_array_20k >>> my_array = type_uchar_array_20k() #實例化生成這個20K的char型數組的對象 >>> uwlen = 0 #定義uwlen >>> uwLenPara= ctypes.c_ushort(uwlen) #這里可以不使用uwlen,而使用0,這里是要告訴 uwLenPara 的類型和值 >>> ret = testdll.BSP_CameraGetPhoto(1,my_array,ctypes.byref(uwLenPara)) >>> ret 40459264 >>> help(ctypes.byref) Help on built-in function byref in module _ctypes: byref(...) byref(C instance[, offset=0]) -> byref-object Return a pointer lookalike to a C instance, only usable as function argument
Byref關鍵字會這個這個對像的指針。
返回結果為40459264( 0x2695C00)
Python中返回的類型默認為int,而庫里這個函數返回的類型是unsigned char所以需要指定返回類型,這里最低字節0x00說明返回成功了。
如果動態鏈接庫中的C函數返回值不是int,需要在調用函數之前顯式的告訴ctypes返回值的類型
testdll.BSP_CameraGetPhoto.restype = ctypes.c_ubyte >>> ret = testdll.BSP_RearCommClose() #調用動態庫關閉串口句柄 >>> my_array #數組對象 <__main__.c_char_Array_20480 object at 0x02695CB0> >>> my_array.value #輸出數組的值需要用循環,這里只顯示四個字節(默認按int顯示) '\xff\xd8\xff\xdb' >>> uwlen #說明返回值和uwlen 沒關系,定義uwLenPara時只是使用了uwlen做為初始值 0 >>> uwLenPara #返回他的類型,和值 6592 c_short(6592) >>> uwLenPara.value 6592 >>> type_uchar_array_20k #數組類型(比較my_array返回) <class '__main__.c_char_Array_20480'> >>> ctypes.byref(uwLenPara) #返回一個指針(02695C88) <cparam 'P' (02695C88)> #把獲取到的圖片數據寫到二進制文件里, >>> with open(r"D:\test123.jpg",'wb') as f: for i in xrange(uwLenPara.value): f.write(my_array[i])
實驗結果: