【问题标题】:Python ctypes Unable to pass memory array in a structurePython ctypes无法在结构中传递内存数组
【发布时间】:2015-04-30 16:25:03
【问题描述】:

Python 2.7.8、Windows 7、Phyton USB 程序员的 DLL

我被 Data 元素困住了,它应该是一个大内存数组,我尝试使用几种不同的定义,但我无法理解错误试图告诉我什么。我遇到的大部分错误都是类型错误,下面这段代码是我最接近的,似乎是在调用函数,但由于错误而没有处理。

C API:

typedef struct tagACI_Memory_Params
{
  UINT   Size;             // (in)  Size of structure, in bytes
  UINT   BufferNumber;     // (in)  Number of buffer of interest, the first buffer number is 0
  UINT   LayerNumber;      // (in)  Number of layer of interest, the first layer number is 0
  DWORD  AddressLow;       // (in)  Low 32 bits of address, in layer units (natural to device address)
  DWORD  AddressHigh;      // (in)  High 32 bits of address, in layer units (natural to device address)
  PVOID  Data;             // (in || out) Pointer to data to read to or write from
  DWORD  DataSize;         // (in)  Size of data to read or write, in layer units, max. 16 MB (0x1000000)
  DWORD  FillValue;        // (in)  Value to fill buffer with, used by ACI_FillLayer() only
} ACI_Memory_Params;

我的python代码:

MaxMemorySize = 1024
MemoryBuffer = ctypes.c_ubyte * MaxMemorySize 

class Memory_Params(ctypes.Structure):
    _fields_ =  [("Size", ctypes.wintypes.UINT),
                 ("BufferNumber", ctypes.wintypes.UINT),
                 ("LayerNumber", ctypes.wintypes.UINT),
                 ("AddressLow", ctypes.wintypes.DWORD),
                 ("AddressHigh", ctypes.wintypes.DWORD),
                 ("Data", MemoryBuffer ),
                 ("DataSize", ctypes.wintypes.DWORD),
                 ("FillValue", ctypes.wintypes.DWORD)
                ]

WriteLayer = ctypes.windll.ACI.ACI_WriteLayer
WriteLayer.argtypes = [ctypes.POINTER(Memory_Params)]
WriteLayer.restype = ctypes.HRESULT

WData = Memory_Params(ctypes.sizeof(Memory_Params),0,0,0,0,ctypes.POINTER(MemoryBuffer),15,0)
for i in range(10):
    WData.Data[i] = i

print 'write result', WriteLayer(ctypes.byref(WData))

API 调用返回 1,这意味着:define ACI_ERR_INVALID_PARAMS_SIZE 1 // ACI 函数中的结构大小无效

更新: 我错过的关键事情:定义后创建和使用 MemoryBuffer 对象,以及如何正确定义指针。 如果其他人有类似的情况,这里是工作代码:

MaxMemorySize = 1024
MemoryBuffer = ctypes.c_ubyte * MaxMemorySize

class Memory_Params(ctypes.Structure):
    _fields_ =  [("Size", ctypes.wintypes.UINT),
                 ("BufferNumber", ctypes.wintypes.UINT),
                 ("LayerNumber", ctypes.wintypes.UINT),
                 ("AddressLow", ctypes.wintypes.DWORD),
                 ("AddressHigh", ctypes.wintypes.DWORD),
                 ("Data", ctypes.POINTER(ctypes.c_ubyte) ),
                 ("DataSize", ctypes.wintypes.DWORD),
                 ("FillValue", ctypes.wintypes.DWORD)
                ]
WriteLayer = ctypes.windll.ACI.ACI_WriteLayer
WriteLayer.argtypes = [ctypes.POINTER(Memory_Params)]
WriteLayer.restype = ctypes.wintypes.UINT

PData = MemoryBuffer()
WData = Memory_Params(ctypes.sizeof(Memory_Params),0,0,0,0,PData,for i in range(10):
    PData[i] = i
WriteLayer(ctypes.byref(WData))

【问题讨论】:

  • 你不应该更正这个问题。

标签: python windows dll ctypes


【解决方案1】:
  • 当您初始化 WData 对象时,第 6 个 参数是 ctypes.POINTER(MemoryBuffer)。这是(或应该在语法上)不正确:POINTER 返回一个指针 type,而您需要一个 unsigned char 数组(这是一个 >对象或类型的实例
  • 您得到的大小错误是因为 Python 结构与 C 结构不匹配。 C 中的 Data 成员是一个 PVOID,它是一个大小为 8 的指针(如果你有一个 32 位,则为 4 Python),而在 Python 中它具有 MemoryBuffer 类型,其大小为 1024

要纠正问题,请将您的 Memory_Params.Data 成员类型设为: ctypes.POINTER(ctypes.c_ubyte)

【讨论】:

  • 澄清一下,Data 字段应该被分配一个缓冲区类型的实例,例如Memory_Params(ctypes.sizeof(Memory_Params), Data=MemoryBuffer(), DataSize=15)Data 字段将包含缓冲区的地址(假设 OP 进行了您建议的更改),并且结构实例将通过其 _objects 字典中的引用保持缓冲区活动。
  • 感谢两位的帮助。它现在正在工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多