prototype
规范说
第一项是一个整数,包含参数的方向标志组合:[...]
4:输入参数,默认为整数零。
不久之后,
可选的第三项是该参数的默认值。
当看似完全相同的事物可以通过在第三个元组元素中写入
0
来指定时,为什么会存在“类型 4”?它们确实是等价的吗?为什么其中一个会比另一个更受青睐?
事实上,有一些证据表明它们并不等同:如果我定义 WlanRegisterNotification 就像
proto = ctypes.WINFUNCTYPE(
ctypes.wintypes.DWORD,
ctypes.wintypes.HANDLE,
ctypes.wintypes.DWORD,
ctypes.wintypes.BOOL,
WLAN_NOTIFICATION_CALLBACK,
ctypes.wintypes.LPVOID,
ctypes.wintypes.LPVOID,
ctypes.POINTER(ctypes.wintypes.DWORD),
)
fun = proto(
('WlanRegisterNotification', wlanapi),
(
(IN, 'hClientHandle'),
(IN, 'dwNotifSource'),
(IN, 'bIgnoreDuplicate'),
(IN | DEFAULT_ZERO, 'funcCallback'),
(IN | DEFAULT_ZERO, 'pCallbackContext'),
(IN | DEFAULT_ZERO, 'pReserved'),
(OUT, 'pdwPrevNotifSource'),
),
)
当传递前四个参数的值时,它的行为毫无意义:
TypeError: call takes exactly 3 arguments (4 given)
当参数四、五和六给出默认值(但应该接受显式值)时,为什么应该假设正好有三个参数?删除
DEFAULT_ZERO
并添加 , None
可以解决问题,但并不是令人满意的答案。
DEFAULT_ZERO
似乎意味着“不要传递参数...它将始终为零”,因此只有使用 pReserved
才有意义。其他两个参数需要有效的默认值。请注意,0
不是回调的有效默认值,因此我传递了通知回调类型的默认 null 实例。
功能示例:
import ctypes
import ctypes.wintypes
PWLAN_NOTIFICATION_DATA = ct.c_void_p
WLAN_NOTIFICATION_CALLBACK = ct.WINFUNCTYPE(None, PWLAN_NOTIFICATION_DATA, w.LPVOID)
# valid callback
@WLAN_NOTIFICATION_CALLBACK
def callback(param1, param2):
print(param1, param2)
IN = 1
OUT = 2
DEFAULT_ZERO = 4
wlanapi = ct.WinDLL('wlanapi')
proto = ctypes.WINFUNCTYPE(
ctypes.wintypes.DWORD,
ctypes.wintypes.HANDLE,
ctypes.wintypes.DWORD,
ctypes.wintypes.BOOL,
WLAN_NOTIFICATION_CALLBACK,
ctypes.wintypes.LPVOID,
ctypes.wintypes.LPVOID,
ctypes.POINTER(ctypes.wintypes.DWORD),
)
fun = proto(
('WlanRegisterNotification', wlanapi),
(
(IN, 'hClientHandle'),
(IN, 'dwNotifSource'),
(IN, 'bIgnoreDuplicate'),
(IN, 'funcCallback', WLAN_NOTIFICATION_CALLBACK()),
(IN, 'pCallbackContext', None),
(IN | DEFAULT_ZERO, 'pReserved'),
(OUT, 'pdwPrevNotifSource'),
),
)
fun.errcheck = lambda result, func, args: (result, args[5])
print(fun(0,0,0))
print(fun(0,0,0,callback))
print(fun(0,0,0,callback,None))
print(fun(0,0,0,callback,None,None)) # this will fail. pReserved can't be passed.
输出(注意
ERROR_INVALID_PARAMETER = 87
,因为我传递了垃圾参数,但它使其通过了ctypes参数验证):
(87, 0)
(87, 0)
(87, 0)
Traceback (most recent call last):
File "C:\test.py", line 44, in <module>
print(fun(0,0,0,callback,None,None))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: call takes exactly 5 arguments (6 given)