新聞中心

創(chuàng)新互聯(lián)建站是一家專注于成都網(wǎng)站制作、成都網(wǎng)站建設(shè)與策劃設(shè)計(jì),定興網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)建站做網(wǎng)站,專注于網(wǎng)站建設(shè)10年,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:定興等地區(qū)。定興做網(wǎng)站價(jià)格咨詢:13518219792
一、神秘的模塊
我們都知道C語言是比較靠近底層的語言,所以我們要想使用動態(tài)鏈接庫就要給Python和C構(gòu)建一座橋梁。今天我們要說的這座橋梁就是---Ctypes。
二、安裝并導(dǎo)入Ctypes
系統(tǒng)自帶有該模塊,若沒有,安裝Pywin32也就有了。
from ctypes import *
三、認(rèn)識動態(tài)鏈接庫
動態(tài)鏈接庫在linux 系統(tǒng)中表現(xiàn)為“.so”的后綴文件,而在Windows中表現(xiàn)為”.dll“的后綴文件。
四、初步了解Ctypes
安裝好后我們需要對Ctypes做一個(gè)大致的了解,首先我們得先查看它的所有函數(shù)及其方法。
接下來我們就將對這些方法做一個(gè)簡單的了解,并且配上一個(gè)小實(shí)例讓大家看了之后更容易懂,讓天底下不再有十分艱難的編程問題存在是我們的宗旨。
五、Ctypes的基本用法
1. 數(shù)據(jù)類型
Ctypes很完美的契合了C的數(shù)據(jù)類型,豐富多樣,下面我們來看看吧:
我們可以看到這些都是可以在Python中使用的C語言數(shù)據(jù)類型。我們一起來看看它的用處吧:
我們可以看到這些基本就是數(shù)據(jù)類型的使用方法了,也是挺簡單的。
2. 操作變量
剛剛我們定義了許多類型的變量,下面我們像使用C語言變量一樣來使用它們。
(1) 訪問變量的值
it.value
(2) 修改變量的值
it.value=43 #直接賦值,即可修改
(3) 給變量添加指針
#強(qiáng)指針
pt=pointer(it) pointer(c_int(10)) #定義指針,指向變量 pt,pt是指針內(nèi)存地址
pt.contents #指針?biāo)傅膶ο?br>#弱指針 比強(qiáng)指針?biāo)俣瓤?br>byref(it,4) #it:c的實(shí)例 4:偏移量
#返回一個(gè)指針的圖片來做一個(gè)C實(shí)例,只可用作為函數(shù)參數(shù)
上面的指針只是簡單的創(chuàng)建了指針實(shí)例,還有一種方法可以指定指針類型,然后進(jìn)行創(chuàng)建:
aa=POINTER(c_int) #創(chuàng)建指針
aa(c_int(43)) #創(chuàng)建指針實(shí)例
aa(c_int(43)).contents.value#獲取指針的值
也可以創(chuàng)建一個(gè)空指針:
POINTER(c_int)() #創(chuàng)建空指針,空指針是一個(gè)bool值
可以看出空指針沒有Contents屬性。
也可以使用抽象基類“_Pointer”來完成指針的操作:
import ctypes
class ss(ctypes._Pointer): #這里必須帶上ctypes,否則會報(bào)錯
_type_=c_int
contents=c_float
aa=ss(c_int(10)) #指定對象類型為整形
print(aa.contents) #替換為浮點(diǎn)類型
3. 創(chuàng)建修改緩沖
Ctypes定義的指針類型是不可以修改的,如果需要在C函數(shù)中被修改,需要使用一些函數(shù)來修改,下面來看看:
(1) 字符緩沖
p=create_string_buffer(4) #創(chuàng)建一個(gè)4字節(jié)緩沖區(qū) 初始化為空字節(jié)
create_string_buffer(b"Hello") #創(chuàng)建一個(gè)包含空字符結(jié)尾字符串緩沖區(qū)
create_string_buffer(b"Hello", 10) #創(chuàng)建一個(gè)10字節(jié)緩沖區(qū)
print(sizeof(p),repr(p.raw)) #內(nèi)存塊大小 字節(jié)信息
(2) unicode緩沖
a=create_unicode_buffer(5) #創(chuàng)建一個(gè)10字節(jié)的unicode字符緩沖區(qū)
create_unicode_buffer('ffsa')
create_unicode_buffer('ffsa',5) #結(jié)尾空字符
print(sizeof(a)) #內(nèi)存塊大小
4. 調(diào)用動態(tài)鏈接庫
動態(tài)鏈接庫的調(diào)用方法很多,任你挑選。
CDLL(xx.dll)
OleDLL(xx.dll)
PyDLL(xx.dll)
WinDLL(xx.dll)
cdll.LoadLibrary(xx.dll)
oledll.LoadLibrary(xx.dll)
pydll.LoadLibrary(xx.dll)
windll.LoadLibrary(xx.dll)
#也可使用鏈接庫讀取器LibraryLoader,它也同樣支持上面的八種方式
LibraryLoader(CDLL('C:\\Windows\\System32\\user32.dll'))
LibraryLoader(cdll.LoadLibrary('C:\\Windows\\System32\\user32.dll'))
綜上所述,調(diào)用動態(tài)鏈接庫的方法共有16種之多。
5. 查找動態(tài)鏈接庫
from ctypes.util import find_library
find_library('user32')# 查找
6. 調(diào)用動態(tài)鏈接庫函數(shù)
dll=windll.LoadLibrary(xx.dll)
dll.函數(shù)名
7. Windows Api函數(shù)
所有的Window Api 函數(shù)都包含在Dll中,其中有幾個(gè)非常重要的Dll:
kernel32.dll #用于管理內(nèi)存、進(jìn)程和線程的各個(gè)函數(shù)
user32.dll #用于創(chuàng)建用戶界面的各個(gè)函數(shù)
gdi32.dll #用于畫圖和顯示文本的各個(gè)函數(shù)
advapi32.dll #用于操作注冊表、系統(tǒng)終止與重啟、Windows服務(wù)啟動/停止/創(chuàng)建、賬戶管理的各個(gè)函數(shù)
shell32.dll #用于訪問操作系統(tǒng)shell提供的功能
netapi32.dll #用于訪問操作系統(tǒng)提供的各種通信功能
comctl32.dll #用于訪問操作系統(tǒng)的狀態(tài)條、進(jìn)度條、工具條等功能
comdlg32.dll #用于管理文件打開、文件保存、顏色字體選擇等標(biāo)準(zhǔn)對話框
#調(diào)用這些dll非常簡單:
windll.gdi32 #即可
8. 獲取模塊頭
windll.kernel32#同時(shí)導(dǎo)出同一個(gè)函數(shù)的ANSI版本(GetModuleHandleA)和UNICODE版(GetModuleHandleW)
windll.kernel32.GetModuleHandleA(0) #里面只允許有0或者None,其它會報(bào)錯
windll.kernel32.GetModuleHandleW()
9. Dll基本信息獲取
當(dāng)我們讀取Dll后有時(shí)候需要對它的路徑或者句柄進(jìn)行操作,這個(gè)時(shí)候我們需要獲取這些參數(shù):
(1) 獲取窗口句柄
dll._handle
(2) 獲取Dll絕對路徑
dll._name
10. 調(diào)用Python中的Os模塊中的所有方法
這個(gè)自是不必說,與Os模塊密切相關(guān)。
os=ctypes._os
os.getcwd()
11. 打印字符長度
windll.msvcrt.printf(b'fsfs') #不支持中文輸出 輸出為4
windll.msvcrt.printf('fsfs') #輸出為2
#以下情況與上相同
cdll.msvcrt.printf('fsfs')
pydll.msvcrt.printf('fsfs')
oledll.msvcrt.printf('fsfs')
12. 獲取C實(shí)例內(nèi)部緩沖區(qū)地址
addressof(c_int(30))
13. 判斷是否有管理員權(quán)限
windll.shell32.IsUserAnAdmin()
cdll.shell32.IsUserAnAdmin()
pydll.shell32.IsUserAnAdmin()
oledll.shell32.IsUserAnAdmin()
#結(jié)果返回1則表示有,否則無
通過判斷當(dāng)前用戶是否為管理員用戶后,我可以進(jìn)行下一步操作,如果是則打開瀏覽器,如果不是則嘗試打開:
import ctypes, sys
def admin():
try:
aa=ctypes.windll.shell32.IsUserAnAdmin()
except:
return
finally:
return aa
if admin()==1:
os.popen(r'E:\360browser\360se6\Application\360se.exe')
else:
if sys.version_info[0] == 3:
ctypes.windll.shell32.ShellExecuteW(0, "runas", sys.executable,'',__file__,0)
else:
print('版本太低,不支持2.0')
#sys.executable:python主程序的絕對路徑
#__file__:當(dāng)前程序的絕對路徑
14. 讓鼠標(biāo)鍵盤失靈
aa=cdll.LoadLibrary('C:\\Windows\\System32\\user32.dll')
aa.BlockInput(True)#鍵盤鼠標(biāo)被鎖定
time.sleep(5) # 鎖定五秒
aa.BlockInput(False) #被釋放
15. 打開文件或者應(yīng)用程序
aa=windll.shell32.ShellExecuteW(0,'open','C:\\Windows\\System32\\notepad.exe','',os.path.join(os.path.dirname(__file__),'OSI.txt'),0)
#參數(shù)1:父窗口的句柄,如果沒有父窗口,則為0
#參數(shù)2:要運(yùn)行的操作,如:runas,open,print
#參數(shù)3:要運(yùn)行的程序絕對路徑
#參數(shù)4:給程序傳遞的參數(shù),如果打開的是文件則為空
#參數(shù)5:要打開的文件的絕對路徑
#參數(shù)6:是否顯示窗口 0:后臺打開 1:前臺打開
#如果aa返回值小于32則表示打開失敗
aa.bit_length()#指定數(shù)值的二進(jìn)制的長度數(shù)、寬度數(shù)
16. 結(jié)構(gòu)體和聯(lián)合體
要想使用必須從Structure 和 Union 繼承,子類必須定義,F(xiàn)ields 屬性,F(xiàn)ields屬性必須是一個(gè)二元組的列表。
元祖中第一個(gè)是變量名,第二個(gè)是數(shù)據(jù)類型,可以是Ctypes任意一種變量類型。
(1) 結(jié)構(gòu)體Structure
也可以一次性傳遞多個(gè)不同數(shù)據(jù)類型的參數(shù):
(2) 聯(lián)合體Union
它和結(jié)構(gòu)體的使用方法一樣,但是結(jié)果不同,下面我們來看下:
造成這一區(qū)別的原因聯(lián)合體所有成員變量共用一塊內(nèi)存,可以內(nèi)存復(fù)用;而結(jié)構(gòu)體,每個(gè)成員變量占用一塊內(nèi)存。
17. 數(shù)組操作
ARRAY(type,len) #前者是Ctypes的某個(gè)類型的值,而后者是值的長度,返回一個(gè)值與長度的乘積
Array(*args) #它是一個(gè)數(shù)組抽象基類, 我們可以重寫它來進(jìn)行使用,
class cx(Array):
_length_=100 #重寫方法_length_(數(shù)組中元素的數(shù)量)
_type_=c_int #指定數(shù)組中每個(gè)元素的類型(整形)
aa=cx(12,32,43,324,54,4,32,34,52434)
print(aa[2],aa[5:7]) #利用下標(biāo)或者切片訪問
18. 改變對象的內(nèi)存緩沖區(qū)大小
Ctypes可以重新設(shè)置對象的內(nèi)存緩沖區(qū)大?。?/p>
可以看到,此時(shí)的同一個(gè)對象內(nèi)存緩沖區(qū)大小不一樣.
19. 轉(zhuǎn)換指向不同數(shù)據(jù)類型的指針
這里我們用到了一個(gè)神器的函數(shù)“Cast”,它可以將不同的數(shù)據(jù)類型的指針進(jìn)行轉(zhuǎn)換。
class bb(Structure):
_fields_ = [("val", POINTER(c_int))]
b=bb()
b.val=cast((c_float*4)(1.2,3.2,4.3),POINTER(c_int))
print(b.val[1])
20. 進(jìn)程操作
aa=0x00000020 #定義正常優(yōu)先級的類
ker=windll.LoadLibrary('kernel32.dll') #加載動態(tài)鏈接庫
crk=ker.CreateProcessA #獲得創(chuàng)建后的進(jìn)程的函數(shù)地址
rk=ker.ReadProcessMemory #獲得讀取進(jìn)程內(nèi)存的函數(shù)地址
wk=ker.WriteProcessMemory #獲得寫入進(jìn)程內(nèi)存的函數(shù)地址
ker.TerminateProcess #終止進(jìn)程
print(ker,'\n',crk,'\n',rk,'\n',wk)
21. 調(diào)用Window系統(tǒng)Api
就以Window 彈框函數(shù)MessageBox為例。
from ctypes import c_int, WINFUNCTYPE, windll
from ctypes.wintypes import HWND, LPCWSTR, UINT
tp = WINFUNCTYPE(c_int, HWND, LPCWSTR, LPCWSTR, UINT) #window函數(shù)類型
bt = (1, "hwnd", 0), (1, "text", "我是內(nèi)容"), (1, "caption", "我是標(biāo)題"), (1, "type", 0)
MessageBox =tp(("MessageBoxW", windll.user32),bt) #調(diào)用消息彈框函數(shù)
MessageBox()
ab=MessageBox(caption='提示',text="我也是內(nèi)容") #設(shè)置彈框參數(shù)
aa=MessageBox(caption='警告',type=2,text="是否進(jìn)入?")
if aa==3: #判斷輸出類型
print('終止操作')
if aa==4:
print('重試')
if aa==5:
print('忽略')
可以看到當(dāng)我選擇了中止之后它便提示終止操作。其實(shí)還有一種類似的方法:
注:這里彈窗的參數(shù)均不支持中文,務(wù)必按我上面的格式寫,不然會出錯。
22. 獲取Windows窗口中的所有頂層窗口的值
from ctypes import *
from ctypes import wintypes
#定義回調(diào)函數(shù)類型
res= WINFUNCTYPE(wintypes.BOOL,wintypes.HWND, wintypes.LPARAM)
def win(h,p):#實(shí)現(xiàn)回調(diào)函數(shù)功能,函數(shù)為bool類型;h:頂層窗口的句柄 p:應(yīng)用程序定義的一個(gè)值,
le= user32.GetWindowTextLengthW(h)+1 #獲取window文本長度,加1可獲取完整的信息
buffer = create_unicode_buffer(le) #創(chuàng)建緩沖
user32.GetWindowTextW(h, buffer, le) #獲取window文本
print(buffer.value) #獲取緩沖區(qū)中的信息
return True
user32 = windll.LoadLibrary('user32.dll')#加載dll
user32.EnumWindows(res(win), 0) #枚舉頂層窗口,不列舉子窗口
六、總結(jié)
Ctypes總的來說還是蠻不錯的,挺適合C語言小白學(xué)習(xí),畢竟Api的確太多太復(fù)雜了,還是Python友好點(diǎn)。
本文題目:厲害了,Python也能使用動態(tài)鏈接庫
文章源于:http://m.fisionsoft.com.cn/article/coccoeh.html


咨詢
建站咨詢
