ctypes 中的冗余原型参数规范

问题描述 投票:0回答:1

ctypes 函数

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
可以解决问题,但并不是令人满意的答案。

python ctypes
1个回答
0
投票

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)
© www.soinside.com 2019 - 2024. All rights reserved.