Python ctypes Unable to pass memory array in a str

2019-07-24 12:36发布

问题:

Python 2.7.8, Windows 7, Phyton USB programmer's DLL

I am stuck with the Data element which should be a large memory array, I have tried using several different definitions, but I cannot understand what the errors are trying to tell me. Most of the errors I have encountered have been type errors, this code below is the closest I have been, it seems to be calling the function, but it does not process due to the error.

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;

My python code:

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))

The API call returns a 1 which means: define ACI_ERR_INVALID_PARAMS_SIZE 1 // Invalid structure size in ACI function

Update: The critical things I missed: Creating and using the MemoryBuffer object after defining it, and how to correctly define the pointer. If anyone else has a similar situation, here is working code:

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))

回答1:

  • When you initialize the WData object, the 6th argument is ctypes.POINTER(MemoryBuffer). This is (or should be syntactically) incorrect: POINTER returns a pointer type, while you need an unsigned char array (which is an object or an instance of a type)
  • The size error that you get is because the Python structure doesn't match the C one. The Data member in C is a PVOID, which is a pointer with a size of 8 (or 4 if you have a 32bit Python), while in Python it has the MemoryBuffer type which has a size of 1024

To correct the problem, make your Memory_Params.Data member's type: ctypes.POINTER(ctypes.c_ubyte)