使用 Python 从 c++ dll 返回数据

Posted

技术标签:

【中文标题】使用 Python 从 c++ dll 返回数据【英文标题】:Return data from c++ dll with Python 【发布时间】:2018-09-28 21:26:23 【问题描述】:

我正在用 3M 文档扫描仪编写接口。

我正在调用一个名为MMMReader_GetData的函数

MMMReaderErrorCode MMMReader_GetData(MMMReaderDataType aDataType,void* DataPtr,int* aDataLen);

说明:

从文档中读取数据项后,可以通过 这个 API。 aDataPtr 参数中提供的缓冲区将是 写入数据,并且 aDataLen 更新为 数据。

问题是如何创建void* DataPrt 以及如何获取数据?

我试过了:

from ctypes import *
lib=cdll.LoadLibrary('MMMReaderHighLevelAPI.dll')
CD_CODELINE = 0
aDataLen = c_int()
aDataPtr = c_void_p()
index= c_int(0)

r = lib.MMMReader_GetData(CD_CODELINE,byref(aDataPtr),byref(aDataLen),index)

aDataLen 总是返回一个值,但 aDataPtr 返回 None

【问题讨论】:

【参考方案1】:

您需要做的是分配一个“缓冲区”。缓冲区的地址将作为 void* 参数传递,缓冲区的大小(以字节为单位)将作为 aDataLen 参数传递。然后该函数会将其数据放入您给它的缓冲区中,然后您可以从缓冲区中读取数据。

在 C 或 C++ 中,您将使用 malloc 或类似的东西来创建缓冲区。使用ctypes时,可以使用ctypes.create_string_buffer做一个一定长度的缓冲区,然后将缓冲区和长度传递给函数。然后,一旦函数将其填入,您就可以从您创建的缓冲区中读取数据,该缓冲区的工作方式类似于带有[]len() 的字符列表。

【讨论】:

【参考方案2】:

使用ctypes,最好定义参数类型和返回值以便更好地检查错误,并且声明指针类型在 64 位系统上尤为重要。

from ctypes import *

MMMReaderErrorCode = c_int  # Set to an appropriate type
MMMReaderDataType = c_int   # ditto...

lib = CDLL('MMMReaderHighLevelAPI')
lib.MMMReader_GetData.argtypes = MMMReaderDataType,c_void_p,POINTER(c_int)
lib.MMMReader_GetData.restype = MMMReaderErrorCode

CD_CODELINE = 0

# Make sure to pass in the original buffer size.
# Assumption: the API should update it on return with the actual size used (or needed)
# and will probably return an error code if the buffer is not large enough.
aDataLen = c_int(256)

# Allocate a writable buffer of the correct size.
aDataPtr = create_string_buffer(aDataLen.value)

# aDataPtr is already a pointer, so no need to pass it by reference,
# but aDataLen is a reference so the value can be updated.
r = lib.MMMReader_GetData(CD_CODELINE,aDataPtr,byref(aDataLen))

返回时,您可以通过字符串切片仅访问缓冲区的返回部分,例如:

>>> from ctypes import *
>>> aDataLen = c_int(10)
>>> aDataPtr = create_string_buffer(aDataLen.value)
>>> aDataPtr.raw
'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
>>> aDataLen.value = 5        # Value gets updated
>>> aDataPtr[:aDataLen.value] # Get the valid portion of buffer
'\x00\x00\x00\x00\x00'

【讨论】:

【参考方案3】:

您的代码有几个问题:

    您需要分配aDataPtr指向的缓冲区。 您需要在aDataLen 中传递缓冲区长度。根据 [1],如果缓冲区不够大,MMMReader_GetData 会根据需要重新分配。 你应该直接传递aDataPtr,而不是byref。 您正在根据您提供的 MMMReader_GetData 的方法描述符向方法(index 参数)传递一个额外的参数。

尝试以下方法:

import ctypes

lib = ctypes.cdll.LoadLibrary('MMMReaderHighLevelAPI.dll')

CD_CODELINE = 0
aDataLen = ctypes.c_int(1024)
aDataPtr = ctypes.create_string_buffer(aDataLen.value)

err = lib.MMMReader_GetData(CD_CODELINE, aDataPtr, ctype.byref(aDataLen))

然后您可以将缓冲区的内容作为常规字符数组读取。在aDataLen 中为您返回实际长度。

[1] 3M 页面阅读器程序员指南:https://wenku.baidu.com/view/1a16b6d97f1922791688e80b.html

【讨论】:

以上是关于使用 Python 从 c++ dll 返回数据的主要内容,如果未能解决你的问题,请参考以下文章

从 python ctypes 中的 c++ dll 传递向量

C++ 与 Python 函数通信

嵌入式单声道:将数组从 C# DLL 返回/复制到 C++

调用从 c# 返回 char* 的 c++ dll 函数。无法使用 DllImport()

关于delphi调用C++的DLL中char*参数的问题

从 python 调试 VS2010 中的 c++ dll