使用ctypes調(diào)用系統(tǒng)C API函數(shù)需要注意的問題,函數(shù)參數(shù)中有指針或結(jié)構(gòu)體的情況下最好不要修改argtypes

有人向我反應(yīng),在代碼里同時用我的python模塊?uiautomation?和其它另一個模塊后,腳本運行時會報錯,但單獨使用任意一個模塊時都是正常的,沒有錯誤。

我用一個例子來演示下這個問題是如何出現(xiàn)的。

假設(shè)我需要寫一個module,這個module需要提供獲取當(dāng)前鼠標(biāo)光標(biāo)下窗口句柄的功能,這需要調(diào)用系統(tǒng)C API來實現(xiàn)。

實現(xiàn)如下:

module1.py

#!python3# -*- coding: utf-8 -*-importctypesimportctypes.wintypesclassPOINT(ctypes.Structure):_fields_ = [("x", ctypes.wintypes.LONG),? ? ? ? ? ? ? ? ("y", ctypes.wintypes.LONG)]ctypes.windll.user32.WindowFromPoint.argtypes = (POINT, )ctypes.windll.user32.WindowFromPoint.restype = ctypes.c_void_pctypes.windll.user32.GetCursorPos.argtypes = (ctypes.POINTER(POINT), )defWindowFromPoint(x, y):returnctypes.windll.user32.WindowFromPoint(POINT(x, y))defGetCursorPos():point = POINT(0,0)? ? ctypes.windll.user32.GetCursorPos(ctypes.byref(point))returnpoint.x, point.ydefWindowFromCursor():x, y = GetCursorPos()returnWindowFromPoint(x, y)

調(diào)用的代碼如下

test.py

#!python3# -*- coding:utf-8 -*-importmodule1defmain():print('the handle under cursor is', module1.WindowFromCursor())if__name__ =='__main__':? ? main()

運行結(jié)果如下

the handle undercursoris1839250

這時復(fù)制一份module1.py,重命名為module2.py,他們的代碼是完全一樣的

在test.py同時調(diào)用這兩個module,代碼如下

#!python3# -*- coding:utf-8 -*-importmodule1importmodule2defmain():print('the handle under cursor is', module1.WindowFromCursor())? ? print('the handle under cursor is', module2.WindowFromCursor())if__name__ =='__main__':? ? main()

運行就會報錯了

ctypes.ArgumentError: argument1: : expected LP_POINTinstanceinsteadofpointertoPOINT

但分開單獨調(diào)用任一個模塊就是正常的,不會出錯。

這是因為,module1,module2調(diào)用的同一個C函數(shù),在設(shè)置?argtypes的時候,后面的修改會覆蓋前面的設(shè)置。

執(zhí)行

importmodule1importmodule2

后,C函數(shù)中的POINT參數(shù)必須是module2.POINT才是合法的。

在用module1調(diào)用時,傳入的參數(shù)類型是module1.POINT,運行時就會報錯了。

這種錯誤應(yīng)該只有在參數(shù)中有結(jié)構(gòu)體或結(jié)構(gòu)體指針時才會出現(xiàn)。

假設(shè)module1, module2分別是兩個人寫,你又要同時用這兩個module,只要有一個module設(shè)置了argtypes,運行時可能就會出錯。

解決方法是,在module1, module2中注釋兩行代碼

#ctypes.windll.user32.WindowFromPoint.argtypes = (POINT, )ctypes.windll.user32.WindowFromPoint.restype= ctypes.c_void_p#ctypes.windll.user32.GetCursorPos.argtypes = (ctypes.POINTER(POINT), )

不要修改argtypes,再運行test.py就不會報錯了。

作為庫的作者,需要主要一下,最好不要設(shè)置系統(tǒng)C函數(shù)的argtypes。

看我主頁簡介免費C++學(xué)習(xí)資源,視頻教程、職業(yè)規(guī)劃、面試詳解、學(xué)習(xí)路線、開發(fā)工具

每晚8點直播講解C++編程技術(shù)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容