在Python語言中,可以使用ctypes模塊調用其它如C++語言編寫的動態連結庫DLL文件中的函數,在提高軟體運行效率的同時,也可以充分利用目前市面上各種第三方的DLL庫函數,以擴充Python軟體的功能及應用領域,減少重複編寫代碼、重複造輪子的工作量,這也充分體現了Python語言作為一種膠水語言所特有的優勢。
這次以具體的例子講一下在Python中,如何使用ctypes模塊調用DLL中的庫函數。本文的編程系統環境是win7 64位,Python使用的版本是python2.7.14。
由於DLL中函數中傳遞的參數類型比較多樣化,擬打算分三次講解這部分內容,這次先講傳遞數值、指針與字符串參數的情況,後面再分兩次講解傳遞結構體、數值數組等類型的情況。
DLL文件的加載
假定已經有了一個DLL文件「MyDll.dll」,其函數約定的調用方式為C調用(cdecl)方式,則Python中加載該dll文件的代碼如下:
其中,第1行是引入ctypes模塊,第2行是採用C調用約定加載「MyDll.dll」文件,並將返回值賦給dll變量,後續調用該DLL文件中的函數時,會使用該變量定義要使用的具體函數。
另外,需要說明的是,若DLL函數的調用約定是標準調用約定(stdcall)方式,則DLL文件的加載代碼改為如下:
dll = WinDLL('MyDll.dll')
DLL函數的調用——函數參數為數值情況
如對於「MyDll.dll」文件中的函數add,其函數聲明如下:
該函數有兩個int類型的輸入參數數x和y,返回的兩個數的和。其C語言的實現代碼如下:
在Python中的調用方式如下:
這個函數應該說是最簡單的一個函數了,在第17行,直接使用第一步加載DLL後返回的名稱dll,後面跟函數名字即可返回其值。
DLL函數的調用——函數參數為指針情況
對於上面的函數改進為add2,其函數C語言的實現代碼如下:
此時函數有三個指向int類型的指針參數x、y、z,z為x和y的和。
在Python中的調用方式如下:
其中,第20-22行定義了3個int型的變量x、y和z,初始值分別為2,3,0。第23行調用add2函數時,使用byref指明參數傳遞時為引用傳遞,對應著C語言的指針傳遞。函數運行後,使用z.value即可查看z的值。
也可以使用下面的代碼調用:
上面代碼中,第23-24行,在使用add2函數時,先將函數賦給一個變量add2,然後對其輸入輸出參數進行單獨聲明,使用POINTER聲明為這三個參數為指向int類型的指針變量。
DLL函數的調用——函數參數為字符串情況
例1:如對於下面的函數,返回一個輸入字符串的字節長度,其函數C語言的實現代碼如下:
在Python中的調用代碼如下:
其中,第33行使用c_char_p定義了一個指向char型的指針變量pStr,並賦初值為』abcdef』,第34行將其傳入GetStringLength函數返回其長度。
也可以使用下面代碼調用:
將GetStringLength函數的輸入輸出參數分別使用argtypes和restype單獨進行聲明。
例2:如對於下面的函數,輸入輸出皆為字符串指針,函數的功能是對於輸入pStr1賦值為「StrIn」,對於輸出返回一個指向字符串常量「strOut」的指針,其函數C語言的實現代碼如下:
在Python中的調用代碼如下:
在上面代碼中,同樣分別對輸入輸出參數進行了聲明。對於輸入參數pStr,使用create_string_buffer函數定義了一個字符串緩衝區。對於返回值pChar,在列印輸出結果時,將其強制轉換為c_char_p類型,取其value值即可。
完整的測試代碼
完整的測試代碼如下圖所示:
運行結果如下圖所示:
總結
這次的例子基本涵蓋了在Python中通過ctypes模塊調用DLL函數時,傳遞數值、指針、字符串類型參數時的大部分情況。要注意的是,使用ctypes映射C語言中的數據類型時,兩者必須完全一致。下面是Python的ctypes模塊中數據類型與C語言中數據類型對照表:
歡迎加關注,共同交流。