先看例子
from ctypes import *u32 = windll.LoadLibrary('user32.dll') #加載user32.dllu32.MessageBoxW(0, u'內容', u'標題',0)crt = cdll.LoadLibrary('msvcrt.dll')   #加載C運行庫crt.PRintf('hello world !/n')   調用 C 庫用 cdll,而調用 Windows API 用 windll。
之所以有 cdll 和 windll 的區(qū)別,是因為 Windows API 和 C 庫函數的調用規(guī)范不一樣,前者遵從的是 __stdcall,后者是 __cdecl。
__cdecl 是 C Declaration 的縮寫,表示 C 編譯器默認的函數調用規(guī)范,這種方式下由調用者負責清理參數棧。比如在VC中,如果函數前面不加任何修飾,默認的就是 __cdecl。
__stdcall 是 Standard Call 的縮寫,這種方式下被調的函數自己負責清理參數棧。在 VC 中,如果函數前有 __stdcall 修飾的話,編譯出來的就是這種類型。
Windows API 全部采用的是 __stdcall 。因為 Windows API 要被各種編譯器下的各種語言調用,如果采用 __cdecl 的方式,由于各種編譯器中使用的棧結構也許并不相同,所以就不敢保證其每種編譯器都能正確清理 Windows API 產生的參數棧。而采用 __stdcall 的方式,由被調用者自己清理參數棧,就能避免了以上麻煩。
在 Windows 環(huán)境,LoadLibrary() 的參數可以不包括擴展名。還有一種更簡短的寫法,比如下面三個是等效的:
from ctypes import *windll.LoadLibrary('user32.dll').MessageBoxW(0, u'內容', u'標題',0)windll.LoadLibrary('user32').MessageBoxW(0, u'內容', u'標題',0)windll.user32.MessageBoxW(0, u'內容', u'標題',0)下面三個也一樣
from ctypes import *cdll.LoadLibrary('msvcrt.dll').printf('hello world !/n')cdll.LoadLibrary('msvcrt').printf('hello world !/n')cdll.msvcrt.printf('hello world !/n')int、str、unicode,這三種類型是可以直接作為參數傳遞的,不用指明對應的C類型
from ctypes import *cdll.msvcrt.printf('%d, %s/n', 100, 'abc')int、str、unicode 之外的類型在作為參數時要做顯式類型轉換,指出對應的C類型
from ctypes import *cdll.msvcrt.printf('%.2f/n', c_double(3.14))byref() 可以引用內存地址,相當于 C 的 &
from ctypes import *i = c_int(0)cdll.msvcrt.sscanf('100', '%d', byref(i))print i.valuepointer() 也可以達到相同的效果
from ctypes import *i = c_int(0)cdll.msvcrt.sscanf('100', '%d', pointer(i))print i.value二者的區(qū)別在于,pointer() 會構造一個指針對象,而 byref() 只是一個函數,所以 byref() 的開銷較小。
如果只是用于傳遞參數,那么用 byref() 就足夠了。
直接用 create_string_buffer() 和 create_unicode_buffer()
from ctypes import *s = create_string_buffer('abc') #初始值abccdll.msvcrt.sscanf('def', '%s', s)print s.value #現(xiàn)在是def為了測試回調函數,先編寫一個 test.dll,下面是 C 代碼
 #include <stdio.h> typedef void __stdcall (*MyCallback)(int);__declspec(dllexport) void __stdcall TestMyCallback( int i, MyCallback mycallback){    printf("TestMyCallback:%d/n", i);    mycallback(i*10);}上面這個函數接受兩個參數,第一個是整型變量 i,第二個是一個回調函數。
首先打印變量 i,然后再把 i*10 傳給回調函數。
( __declspec(dllexport) 關鍵字用于從dll導出函數,詳見這里 )
下面的Python代碼中實現(xiàn)了回調函數,并傳給了test.TestMyCallbackPython
from ctypes import *def mycallback( i ):    print 'mycallback:', ic_mycallback = WINFUNCTYPE(None,         #返回值類型 None 代表 void                           c_int         #第一個參數類型 int                           )(mycallback) #括號內是需要被包裝的Python函數windll.test.TestMyCallback(100, c_mycallback)WINFUNCTYPE 的用法實際包括兩個步驟:
首先要聲明一個 C 函數原型
c_function_type = WINFUNCTYPE(返回值類型,第一個參數類型,第二個參數類型...)然后再用這個原型包裝 Python 函數
c_function = c_function_type(Python函數)WINFUNCTYPE 遵守 __stdcall 調用規(guī)范,對應的 __cdecl 版本是 CFUNCTYPE
新聞熱點
疑難解答