【问题标题】:How to use ctypes void ** pointer in python3如何在python3中使用ctypes void **指针
【发布时间】:2015-11-04 08:52:37
【问题描述】:

我想通过其 DLL 连接光谱仪,其中一个功能定义为

UINT UAI_SpectrometerOpen(unsigned int dev, void** handle, unsigned int VID,  unsigned int PID)

来自文档,dev 是指定光谱仪的索引 handle is 返回光谱仪的句柄指针 VID 是提供指定的 VID PID 是提供指定的 PID dev, VID, PID 是已知的,但我不知道如何设置句柄。 我当前的代码是

import ctypes
otoDLL = ctypes.CDLL('UserApplication.dll')
spectrometerOpen = otoDLL.UAI_SpectrometerOpen
spectrometerOpen.argtypes = (ctypes.c_uint, ctypes.POINTER(c_void_p),
                         ctypes.c_uint, ctypes.c_uint)
spectrometerOpen.restypes = ctypes.c_uint
handle = ctypes.c_void_p
errorCode = spectrometerOpen(0, handle, 1592, 2732)

当我运行上面的代码时,我得到了错误

runfile('C:/Users/Steve/Documents/Python Scripts/otoDLL.py', wdir='C:/Users/Steve/Documents/Python Scripts')
Traceback (most recent call last):

  File "<ipython-input-1-73fe9922d732>", line 1, in <module>
    runfile('C:/Users/Steve/Documents/Python Scripts/otoDLL.py', wdir='C:/Users/Steve/Documents/Python Scripts')

  File "C:\Users\Steve\Anaconda3\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 685, in runfile
    execfile(filename, namespace)

  File "C:\Users\Steve\Anaconda3\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 85, in execfile
    exec(compile(open(filename, 'rb').read(), filename, 'exec'), namespace)

  File "C:/Users/Steve/Documents/Python Scripts/otoDLL.py", line 5, in <module>
    spectrometerOpen.argtypes = (ctypes.c_uint, ctypes.POINTER(c_void_p),

NameError: name 'c_void_p' is not defined

我不熟悉 ctypes 和 C,谁能帮我解决这个问题。 非常感谢。

【问题讨论】:

    标签: python ctypes


    【解决方案1】:

    根据你的错误输出:

      File "C:/Users/Steve/Documents/Python Scripts/otoDLL.py", line 5, in <module>
        spectrometerOpen.argtypes = (ctypes.c_uint, ctypes.POINTER(c_void_p),
    

    您忘记将ctypes 放在c_void_p 之前,因此:

    spectrometerOpen.argtypes = (ctypes.c_uint, ctypes.POINTER(ctypes.c_void_p),
                             ctypes.c_uint, ctypes.c_uint)
    

    根据您的函数签名,句柄参数是指向void* 的指针,因此您需要像这样传递它:

    import ctypes
    otoDLL = ctypes.CDLL('UserApplication.dll')
    spectrometerOpen = otoDLL.UAI_SpectrometerOpen
    spectrometerOpen.argtypes = (ctypes.c_uint, ctypes.POINTER(ctypes.c_void_p),
                             ctypes.c_uint, ctypes.c_uint)
    spectrometerOpen.restypes = ctypes.c_uint
    
    # declare HANDLE type, which is a void*
    HANDLE = ctypes.c_void_p
    
    # example: declare an instance of HANDLE, set to NULL (0)
    my_handle = HANDLE(0)
    
    #pass the handle by reference (works like passing a void**)
    errorCode = spectrometerOpen(0, ctypes.byref(my_handle), 1592, 2732)
    

    注意:这只是一个示例,您应该查看spectrometerOpen 函数的文档,以查看它究竟在等待handle 参数的确切内容(它可以为NULL,它究竟是什么类型,等等。 )。

    【讨论】:

    • 结果类型属性是restype,而不是restypes。默认值为c_int
    • 一个设计良好的 ctypes 包装器应该使解释器的段错误变得极其困难。应事先捕获无效参数以引发异常。为了更强的类型安全性,您可以创建一个句柄类型为class Handle(ctypes.Structure): _fields_ = [('value', ctypes.c_void_p)]。在spectrometerOpen.argtypes 中设置ctypes.POINTER(Handle)。对于使用句柄的函数,只需在argtypes 中设置Handle。如果使用无效参数调用函数,这将比使用 c_void_p 宽松得多。
    猜你喜欢
    • 2012-11-30
    • 1970-01-01
    • 2021-10-06
    • 1970-01-01
    • 2013-10-23
    • 1970-01-01
    • 2013-04-03
    • 2021-03-17
    • 2012-12-04
    相关资源
    最近更新 更多