【问题标题】:Using python ctypes and libc to write void pointer to binary file使用 python ctypes 和 libc 将 void 指针写入二进制文件
【发布时间】:2013-06-19 21:03:27
【问题描述】:

我正在使用 python ctypes 和 libc 与供应商提供的 DLL 文件进行交互。 DLL 文件的目的是从相机中获取图像。

图像采集运行似乎没有错误;我遇到的问题是访问数据。

图像采集函数将 ctypes.c_void_p 作为图像数据的参数。

简化如下:

"""
typedef struct AvailableData
{
    void* initial_readout;
    int64 readout_count;
} imageData;
"""

class AvailableData(ctypes.Structure):
    _fields_ = [("initial_readout", ctypes.c_void_p), 
                ("readout_count", ctypes.c_longlong)]

"""
Prototype
Acquire(
CamHandle                 camera,
int64                       readout_count,
int                       readout_time_out,
AvailableData*         available,
AcquisitionErrorsMask* errors );
"""

>>> imageData = AvailableData()
>>> Acquire.argtypes = CamHandle, ctypes.c_longlong, ctypes.c_int, 
         ctypes.POINTER(AvailableData), ctypes.POINTER(AcquisitionErrorsMask)
>>> Acquire.restype = ctypes.c_void_p

>>> status = Acquire(camera, readout_count, readout_time_out, imageData, errors)

我并不完全理解该函数在做什么,因为在我运行该函数后,imageData.initial_readout 似乎是一个“long”类型(甚至不是 ctypes.c_long:只是“long”)。但是,它也有一个与之相关的值。我假设这是存储数据的起始地址。

>>> type(imageData.initial_readout)
<type 'long'>
>>> imageData.initial_readout
81002560L

我目前访问数据的方法是使用libc.fopen、libc.fwrite、libc.fclose,如下:

>>> libc = ctypes.cdll.msvcrt

>>> fopen = libc.fopen
>>> fwrite = libc.fwrite
>>> fclose = libc.fclose
>>> fopen.argtypes = ctypes.c_char_p, ctypes.c_char_p
>>> fopen.restype = ctypes.c_void_p

>>> fopen.restype = ctypes.c_void_p
>>> fwrite.argtypes = ctypes.c_void_p, ctypes.c_size_t, ctypes.c_size_t, ctypes.c_void_p
>>> fwrite.restype = ctypes.c_size_t

>>> fclose = libc.fclose
>>> fclose.argtypes = ctypes.c_void_p,
>>> fclose.restype = ctypes.c_int

>>> fp = fopen('output3.raw', 'wb')
>>> print 'fwrite returns: ',fwrite(ctypes.c_void_p(imageData.initial_readout), readoutstride.value, 1, fp)
fwrite returns:  0
>>> fclose(fp)

其中readoutstride = 2097152 对应于 16 位像素的 1024x1024 数组。

文件“output3.raw”显示在 Windows 资源管理器中,但是它有 0 KB,当我尝试使用(例如使用 imag 查看器)打开它时,它说文件是空的。

我看到fwrite 返回值 0(但应该返回值 1)

如果您对我在这里做错了什么有任何想法,我将不胜感激。提前谢谢你。

【问题讨论】:

  • @eryksun 我在今天早上的编辑中包含了一个用于获取的原型。另外,严格来说 imageData 是一个结构,它包含一个 void 指针(我省略了这些细节以简化最初的问题)。但是,既然你问我已经修改了上面的代码以包含完整的结构。希望这可以澄清事情。
  • @eryksun readout_count 是正在收集的帧数。当我调用Acquire 函数时,它的第二个参数是readout_count,我指定为1。运行Acquire 后,这个值被分配给imageData.readout_countreadoutstride 指定步幅(帧)中的字节数。我可以调用一个附加函数(在获取之前),它返回readoutsride。它返回的值是2097152,对应1024x1024像素的每像素2字节。
  • @eryksun 在我看来,确实有一个字节字符串存储在内存中(在 available.initial_readout 给出的地址处)。在 Python 中有没有办法访问从给定内存地址开始的 next2097152 字节,例如81002560L 或十六进制 0x4d40040L?
  • 如果调用成功,有很多方法可以创建字符串。一种方法是使用ctypes.string_at(address, size) 之后,调用释放内存的库函数。

标签: python ctypes fwrite void-pointers libc


【解决方案1】:

指定argtypesrestype的函数。

import ctypes

libc = ctypes.windll.msvcrt

fopen = libc.fopen
fopen.argtypes = ctypes.c_char_p, ctypes.c_char_p,
fopen.restype = ctypes.c_void_p

fwrite = libc.fwrite
fwrite.argtypes = ctypes.c_void_p, ctypes.c_size_t, ctypes.c_size_t, ctypes.c_void_p
fwrite.restype = ctypes.c_size_t

fclose = libc.fclose
fclose.argtypes = ctypes.c_void_p,
fclose.restype = ctypes.c_int

fp = fopen('output3.raw', 'wb')
fwrite('Hello', 5, 1, fp)
fclose(fp)

【讨论】:

  • 我修改了我的代码以包含argstypesrestype 的规范。我仍然有同样的问题 - 请随时查看我对上述问题的更新。感谢您对此进行调查。
  • @J.Lowney, 你必须指定 argtypes, restype 不仅适用于 fopen, fwrite, fclose, 还有acquire, ....
  • @J.Lowney,将 ctypes.c_void_p(available.initial_readout) 更改为 ctypes.addressof(available.initial_readout)
  • 当我修改为ctypes.addressof(imageData.initial_readout) 时出现错误:TypeError: invalid type。令人困惑的是,在我将结构传递给函数之前,available.initial_readout 被定义为ctypes.c_void_p。当我从函数中取回它时,它是 long 类型——所以我认为 python 正在将它转换回 python 变量。因此,我认为我丢失了 ctypes.addressof 信息。
  • argstypeargtypesargstypes 是否是别名?我似乎在互联网上找到了所有内容(虽然主要是 argtypes)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-30
  • 1970-01-01
  • 2014-01-07
  • 2013-08-22
  • 2015-09-09
  • 1970-01-01
相关资源
最近更新 更多