有人向我反應(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ù)。