国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

ctypes調用dll

2019-11-14 17:42:20
字體:
來源:轉載
供稿:網友

1. 加載 Windows API 和 C 運行庫

先看例子

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')

2. 隱式類型轉換

int、str、unicode,這三種類型是可以直接作為參數傳遞的,不用指明對應的C類型

from ctypes import *cdll.msvcrt.printf('%d, %s/n', 100, 'abc')

3. 顯式類型轉換

int、str、unicode 之外的類型在作為參數時要做顯式類型轉換,指出對應的C類型

from ctypes import *cdll.msvcrt.printf('%.2f/n', c_double(3.14))

4. 指針和引用

byref() 可以引用內存地址,相當于 C 的 &

from ctypes import *i = c_int(0)cdll.msvcrt.sscanf('100', '%d', byref(i))print i.value

pointer() 也可以達到相同的效果

from ctypes import *i = c_int(0)cdll.msvcrt.sscanf('100', '%d', pointer(i))print i.value

二者的區(qū)別在于,pointer() 會構造一個指針對象,而 byref() 只是一個函數,所以 byref() 的開銷較小。

如果只是用于傳遞參數,那么用 byref() 就足夠了。

5. 字符串指針

直接用 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

6. 回調函數

為了測試回調函數,先編寫一個 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


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 英超| 循化| 丹棱县| 榆林市| 海口市| 临泉县| 丹江口市| 霍州市| 冀州市| 鄄城县| 临城县| 田东县| 盱眙县| 新绛县| 米泉市| 信宜市| 南昌县| 湘西| 神农架林区| 年辖:市辖区| 永登县| 偃师市| 嘉禾县| 霍城县| 美姑县| 会宁县| 兰州市| 桐梓县| 阿荣旗| 拉孜县| 聂荣县| 古交市| 宁陵县| 陆丰市| 福建省| 义马市| 云安县| 思茅市| 红原县| 泸州市| 澄迈县|