Calling plain-C functions with "opaque pointer"

I have a problem (I think) similar to what discussed in this question:

I need to call functions contained in a rather complex plain-C shared lib:

  • all functions return an int acting as error code (as usual 0 means "all green").
  • first call ever returns (in argument) an opaque pointer to an "instance".
  • this pointer must be passed to all further function invocations.

In plain-C this translates to something like:

lib_instance *instance;
static lib_ConfigParameters configParams;
static const void* descriptorTable[] = { ... };

int main() {
    int32_t ret;
    ret = lib_getDefaultParams(&configParams);
    // check ret
    configParams.whatever = someParam;
    ret = lib_init(&instance, &configParams, descriptorTable, sizeof(descriptorTable)/sizeof(descriptorTable[0]);
    // check ret
    ret = lib_somefunc(&instance, someparam);
    ...
}

I tried something along the lines:

from ctypes import cdll, Structure, CDLL, POINTER, c_int

class Params(Structure):
    pass

lib = CDLL('../Lib/lib.so')
lib.lib_getParamDefaults.argtypes = (POINTER(Params),)
lib.lib_getParamDefaults.restype = c_int
par = Params()
ret = lib.lib_getParamDefaults(par)
print(ret, par)

but already at this level par does not seem to contain anything useful.

I also have no idea how to handle the "instance" stuff.

Can someone point me in the right direction?

🟢 Solution

You have two problems. First of all, you need a variable that can hold your opaque pointer. Second, you need to pass a pointer to that variable into the C function. A structure might be able to hold the opaque pointer if you defined it properly, but it seems like an over-complicated solution. There's a c_void_p type that seems ideally suited.

I haven't tested this code but I think it does what you want.

from ctypes import cdll, CDLL, c_int, c_void_p, byref

lib = CDLL('../Lib/lib.so')
# ...
par = c_void_p()
ret = lib.lib_getParamDefaults(byref(par))
print(ret, par)