I want to pass null void pointer to an API in ctypes. Below is my scenario,
C Code
//local variables
void *out_data = NULL;
uint32_t out_size;
StructureData pdata;
//API
Analyze(&pdata, &out_data, &out_size);
In Ctypes, how to pass local variables declared in C?
Python
api_call = dll.Analyze
api_call.argtypes = [ctypes.POINTER(pdata), ??, ??]
api_call.restypes = ctypes.c_int
pdata_obj = pdata() # casted datatypes for structure
Analyze(pdata_obj, ??, ??)
Actually what i'm trying is, In C *out_data pointer and out_size are declared locally and passing those into Analyze API. So likewise how we can declare in python and pass it to Analyze wrapper API.
CodePudding user response:
I made the following demo based on the C description of parameters:
test.c
#include <stdlib.h>
#include <stdint.h>
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
// Not defined by OP, so made something up for demonstration.
typedef struct StructureData {
uint32_t number;
uint32_t size;
} StructureData;
// implied parameters from OP description
API void Analyze(StructureData* pdata, void** out_data, uint32_t* out_size) {
// something for demonstration
*out_data = calloc(pdata->number, pdata->size);
*out_size = pdata->number * pdata->size;
}
test.py
import ctypes as ct
class StructureData(ct.Structure):
_fields_ = (('number', ct.c_uint32),
('size', ct.c_uint32))
dll = ct.CDLL('./test')
dll.Analyze.argtypes = (ct.POINTER(StructureData), # C StructureData*
ct.POINTER(ct.c_void_p), # C void**
ct.POINTER(ct.c_uint32)) # C uint32_t*
dll.Analyze.restype = None # C void return
data = StructureData(5, 4) # StructureData instance, number=5, size=4
out_data = ct.c_void_p() # C void* instance, null by default
out_size = ct.c_uint32() # C uint32_t instance, 0 by default
print(out_data, out_size)
# ct.byref() is equivalent to & (address of) in C
dll.Analyze(ct.byref(data), ct.byref(out_data), ct.byref(out_size))
print(out_data, out_size)
# To see the data, cast to a C BYTE type and slice to output size
out = ct.cast(out_data, ct.POINTER(ct.c_ubyte))
print(out[:out_size.value])
Output:
c_void_p(None) c_ulong(0)
c_void_p(3049559977216) c_ulong(20)
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]