Python中ctypes的使用整理 ctypes是Python的一個(gè)外部庫(kù),提供和C語(yǔ)言兼容的數(shù)據(jù)類型,可以很方便地調(diào)用C DLL中的函數(shù)。ctypes的官方文檔在這里。 1. ctypes基本數(shù)據(jù)類型映射表 參數(shù)類型預(yù)先設(shè)定好,或者在調(diào)用函數(shù)時(shí)再把參數(shù)轉(zhuǎn)成相應(yīng)的c_***類型。ctypes的類型對(duì)應(yīng)如下:
對(duì)應(yīng)的指針類型是在后面加上'_p',如int*是c_int_p等等。在python中要實(shí)現(xiàn)c語(yǔ)言中的結(jié)構(gòu),需要用到類。 2. 加載DLL 訪問(wèn)dll,首先需引入ctypes庫(kù) 假設(shè)你已經(jīng)有了一個(gè)的DLL(名字是add.dll),且該DLL有一個(gè)符合cdecl(這里強(qiáng)調(diào)調(diào)用約定是因?yàn)?,stdcall調(diào)用約定和cdecl調(diào)用約定聲明的導(dǎo)出函數(shù),在使用python加載時(shí)使用的加載函數(shù)是不同的,后面會(huì)有說(shuō)明)調(diào)用約定的導(dǎo)出函數(shù)Add。 Objdll = ctypes.windll.LoadLibrary('dllpath') Objdll = ctypes.WinDLL('dllpath') cdecl調(diào)用約定:也有兩種加載方式 Objdll = ctypes.cdll.LoadLibrary('dllpath') Objdll = ctypes.CDLL('dllpath') 其實(shí)windll和cdll分別是WinDLL類和CDll類的對(duì)象。
3. 調(diào)用DLL方法 加載dll后會(huì)返回一個(gè)DLL對(duì)象,使用其中的函數(shù)方法則相當(dāng)于操作該對(duì)象的對(duì)應(yīng)屬性。 注意,經(jīng)過(guò)stdcall聲明的方法,如果不是用def文件聲明的導(dǎo)出函數(shù)或者extern “C” 聲明的話,編譯器會(huì)對(duì)函數(shù)名進(jìn)行修改 函數(shù)參數(shù)申明,通過(guò)設(shè)置函數(shù)的argtypes屬性 函數(shù)返回類型,函數(shù)默認(rèn)返回c_int類型,如果需要返回其他類型,需要設(shè)置函數(shù)的restype屬性
4. 指針與引用 常用的通過(guò)調(diào)用ctypes類型的指針函數(shù)來(lái)創(chuàng)建指針實(shí)例: from ctype import *i = c_int(1)pi = POINTER(i) 對(duì)指針實(shí)例賦值只會(huì)改變其指向的內(nèi)存地址,而不是改變內(nèi)存的內(nèi)容,與其他語(yǔ)言類似,如需要可改變內(nèi)容的字符串,可須使用create_string_buffer() >>> p = create_string_buffer('Hello', 10) # create a 10 byte buffer>>> print sizeof(p), repr(p.raw)10 'Hello/x00/x00/x00/x00/x00' 不帶參數(shù)的調(diào)用指針類型創(chuàng)建一個(gè)NULL指針, NULL指針有一個(gè)False布爾值 >>> null_ptr = POINTER(c_int)() >>> print bool(null_ptr) False 指針實(shí)例有一個(gè)contents屬性,返回這個(gè)指針?biāo)赶虻膶?duì)象。 另外,byref()是用來(lái)傳遞引用參數(shù),pointer()作為傳參通常會(huì)創(chuàng)建一個(gè)實(shí)際的指針對(duì)象,當(dāng)不需要實(shí)際指針對(duì)象時(shí),則可使用byref()
5. 結(jié)構(gòu)體類型處理 Structures和Unions必須繼承Structure和Union基礎(chǔ)類,它們都在ctypes模塊中定義,每一個(gè)子類必須定義個(gè)_fields_屬性,_fields_是一個(gè)二維的tuples列表,包含著每個(gè)field的name及type,這field類型必須是一個(gè)ctypes類型,如c_int,或者任何其他的繼承ctypes的類型,如Structure, Union, Array, 指針等。 例如有一個(gè)簡(jiǎn)單結(jié)構(gòu),包含兩個(gè)整型x和y,可如下初始化一個(gè)結(jié)構(gòu): from ctypes import *import typesclass Test(Structure): _fields_ = [('x', c_int), ('y', c_char)]test1 = Test(1, 2) 另外,如結(jié)構(gòu)體用于鏈表操作,即包含指向結(jié)構(gòu)體指針時(shí),若直接定義: from ctypes import *import typesclass Test(Structure): _fields_ = [('x', c_int), ('y', c_char), ('next', Test)] 則python會(huì)報(bào)錯(cuò)type未定義,: from ctypes import *import typesclass Test(Structure): passTest._fields_ = [('x', c_int), ('y', c_char), ('next', POINTER(Test))]
6. 數(shù)組定義 數(shù)組包含一個(gè)固定數(shù)目的相同類型的實(shí)例,常用創(chuàng)建數(shù)組類型是對(duì)一個(gè)數(shù)據(jù)類型與一個(gè)正數(shù)相乘,例如: ArrayType = Test * 10 初始化和使用數(shù)組:>>> from ctypes import *>>> TenIntegers = c_int * 10>>> ii = TenIntegers(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)>>> print ii
7. 回調(diào)函數(shù) ctypes可以從python可調(diào)用對(duì)象中創(chuàng)建一個(gè)c可調(diào)用的函數(shù)指針,這些通常被稱為回調(diào)函數(shù)。 (這個(gè)等用到時(shí),再仔細(xì)研究。。。) |
|