Nicolas Candela
Nicolas Candela

Reputation: 31

Return data from c++ dll with Python

I'm programming an interface with 3M document scanners.

I am calling a function called MMMReader_GetData

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

Description:

After a data item has been read from a document it may be obtained via this API. The buffer supplied in the aDataPtr parameter will be written to with the data, and aDataLen updated to be the length of the data.

The problem is how can I create a void* DataPrt and how can get it the data?

I have tried:

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 always returns a value but aDataPtr returns None

Upvotes: 2

Views: 1353

Answers (3)

MEE
MEE

Reputation: 2412

There are several issues with your code:

  1. You need to allocate the buffer pointed to by aDataPtr.
  2. You need to pass the buffer length in aDataLen. According to [1], if the buffer isn't big enough, MMMReader_GetData will reallocate it as needed.
  3. You should pass aDataPtr directly, not byref.
  4. You are passing an extra argument to the method (the index argument) based on the method descriptor of MMMReader_GetData you provided.

Try the following:

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

Then you can read the content of the buffer as a regular character array. The actual length is returned back for you in aDataLen.

[1] 3M Page Reader Programmers' Guide: https://wenku.baidu.com/view/1a16b6d97f1922791688e80b.html

Upvotes: 2

Mark Tolonen
Mark Tolonen

Reputation: 178334

With ctypes, it is best to define the argument types and return value for better error checking, and declaring pointer types is especially important on 64-bit systems.

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

On return you can access just the returned portion of the buffer by string slicing, e.g.:

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

Upvotes: 2

interfect
interfect

Reputation: 2877

What you need to do is allocate a "buffer". The address of the buffer will be passed as the void* parameter, and the size of the buffer in bytes will be passed as the aDataLen parameter. Then the function will put its data in the buffer you gave it, and then you can read the data back out of the buffer.

In C or C++ you would use malloc or something similar to create a buffer. When using ctypes, you can use ctypes.create_string_buffer to make a buffer of a certain length, and then pass the buffer and the length to the function. Then once the function fills it in, you can read the data out of the buffer you created, which works like a list of characters with [] and len().

Upvotes: 2

Related Questions