ctypes中函数和结构体指针的错误

2 投票
1 回答
708 浏览
提问于 2025-04-18 07:36

我正在尝试用 Python 调用一个 C++ 函数(在一个动态链接库中)。为此,我使用了 ctypes 这个库。

我的 C++ 代码是一个用来操作 网络摄像头 的库,它导出了一组 C 函数。

我想使用的函数是:

/*! Release the grabber object. Must be called, if the calling application
    does no longer need the grabber.
    @param hGrabber The handle to grabber to be released.
    @sa IC_CreateGrabber
*/
void AC IC_ReleaseGrabber( HGRABBER *hGrabber ); ///< Releas an HGRABBER object.

这是一个释放内存的函数。

这是 HGRABBER 结构体:

//////////////////////////////////////////////////////////////////////////
/*! This is the handle of an grabber object. Please use the HGRABBER type to access
    this object.
*/
typedef struct HGRABBER_t__ { int unused; } HGRABBER_t; ///<Internal structure of the grabber object handle.
#define HGRABBER HGRABBER_t* ///< Type of grabber object handle. Used for all functions. 

我的代码是:

必要的结构体 HGRABBER(在我的情况下叫 HGRABBER_TYPE)

class HGRABBER_T(ctypes.Structure):
    _fields_ = [("unused", ctypes.c_int)] 

HGRABBER_TYPE = ctypes.POINTER(HGRABBER_T)

调用函数的代码:

self._dllref =  ctypes.windll.LoadLibrary(DLL_PATH)
self._grabber_handle = self._dllref.IC_CreateGrabber() 
 ....
 ...
 ....
self._dllref.IC_ReleaseGrabber(ctypes.pointer(HGRABBER_TYPE(self._grabber_handle)))

最后,我收到的错误是:

self._dllref.IC_ReleaseGrabber(ctypes.byref(HGRABBER_TYPE(self._grabber_handle)))
TypeError: expected HGRABBER_T instead of int

我查看了其他相关的帖子,比如 这个,但没有帮助我。

我非常感谢任何帮助!

更新:

我应用了 restype 和 argtypes 来指定参数和返回值(谢谢!)。

经过修改,代码是:

self._dllref =  ctypes.windll.LoadLibrary(DLL_PATH)
self._dllref.IC_CreateGrabber.restype = HGRABBER_TYPE        
self._grabber_handle = self._dllref.IC_CreateGrabber() 
...
..
self._dllref.IC_ReleaseGrabber.argtypes = [HGRABBER_TYPE]
self._dllref.IC_ReleaseGrabber(self._grabber_handle)

我应该有多个错误,现在我的错误是:

self._dllref.IC_ReleaseGrabber(self._grabber_handle)
WindowsError: exception: access violation writing 0x6E657137

我检查了函数的参数(HGRABBER *hGrabber),释放函数的 argtypes 应该是:

self._dllref.IC_ReleaseGrabber.argtypes = [ctypes.POINTER(HGRABBER_TYPE)]

通过这个修改,我得到了另一个不同的错误:

self._dllref.IC_ReleaseGrabber(self._grabber_handle)
WindowsError: exception: access violation reading 0x6B0F1FE0

我在查找这些错误,似乎是指针转换出错,我不太明白,结构体看起来很简单,我不知道我漏掉了什么。

更新 2

我在调用函数时忘记加 ctypes.byref,应该是:

 self._dllref.IC_ReleaseGrabber(ctypes.byref(self._grabber_handle))

更新 3

不幸的是,我遇到了一个与指针参数相关的随机错误((ctypes.byref(self._grabber_handle))),有时候释放函数能接受这个对象,但有时候会出现这个错误:

    _dllref.IC_ReleaseGrabber(ctypes.byref(_grabber_handle))
WindowsError: exception: access violation reading 0x5A694F44

1 个回答

2

你可以设置IC_CreateGrabber的返回类型,这样在调用IC_ReleaseGrabber时就不需要再转换数据了。

举个例子:

self._dllref =  ctypes.windll.LoadLibrary(DLL_PATH)

# here set the return type
self._dllref.IC_CreateGrabber.restype = HGRABBER_TYPE

# here set the argtypes
self._dllref.IC_ReleaseGrabber.argtypes = [ctypes.POINTER(HGRABBER_TYPE)]

self._grabber_handle = self._dllref.IC_CreateGrabber() 

self._dllref.IC_ReleaseGrabber(ctypes.byref(self._grabber_handle))

通过设置库函数的restypeargtypes,ctypes就知道怎么处理来自C语言那边的值了。

撰写回答