I cannot access from python ctypes the (fixed length) string from referenced structure allocated by C code (dll library). But the int type I can access and change.
This is simplified code. In reality I'm accessing proprietary dll which I cannot change, therefore please take the content of this dll as fixed. I'm able to access the dll struct string from C code without problems - that's the way I constructed this example dll, so it's interface is the same as interface of proprietary dll.
My assumption was that wrong is either python declaration of "text" in DATA_STRUCT (various tested possibilities are listed), or the way I want to access the string - are commented as they are either returning only object or fails in windows error (access violation).
Just to note, I'm using compiler provided with Dev-C++ TDM-GCC 4.9.2 64-bit (which should use MingW64) and 64bit Python 3.8.2. The reason for using 64 bit python is the proprietary dll, which is 64bit. Everthing is under Windows (7).
dll.h
typedef struct REFERENCE_STRUCT {
int type ;
void * dataP ;
} REFERENCE_STRUCT ;
typedef struct DATA_STRUCT {
int number ;
char text [41] ; // the string is fixed length
} DATA_STRUCT ;
__declspec(dllexport) int test_alloc (REFERENCE_STRUCT *refP) ;
__declspec(dllexport) int test_print (REFERENCE_STRUCT *refP) ;
__declspec(dllexport) int test_free (REFERENCE_STRUCT *refP) ;
maindll.c
#include "dll.h"
#include <windows.h>
#include <string.h>
#include <stdio.h>
__declspec(dllexport) int test_alloc (REFERENCE_STRUCT *refP) {
DATA_STRUCT *dataP ;
dataP = malloc (sizeof (DATA_STRUCT));
dataP->number = 5 ;
strcpy (dataP->text, "number 1");
refP->type = 40 ;
refP->dataP = ( void *) dataP ;
printf ("DLL - alloc: reference type: %d; data <%d>; <%s>\n", refP->type, dataP->number, dataP->text) ;
return 0;
} ;
__declspec(dllexport) int test_print (REFERENCE_STRUCT *refP) {
DATA_STRUCT *dataP ;
dataP = (DATA_STRUCT*) refP->dataP ;
printf ("DLL - print: reference type: %d; data <%d>; <%s>\n", refP->type, dataP->number, dataP->text) ;
return 0;
} ;
__declspec(dllexport) int test_free (REFERENCE_STRUCT *refP){
free(refP->dataP) ;
printf ("DLL - free\n") ;
return 0;
} ;
script.py
import sys,os, ctypes, ctypes.util, faulthandler
faulthandler.enable()
os.add_dll_directory("D:/path_to_lib/")
mylib_path = ctypes.util.find_library("mydll")
mylib = ctypes.CDLL(mylib_path)
class REFERENCE_STRUCT(ctypes.Structure):
_fields_ = [("type", ctypes.c_int),
("dataP", ctypes.c_void_p)]
class DATA_STRUCT(ctypes.Structure):
_fields_ = [("number", ctypes.c_int),
("text", ctypes.c_char * (41))] # !!! THIS declaration is correct for C "char text [41] ;" !!!
("text", ctypes.POINTER(ctypes.c_char * (41)))] # WHICH declaration is correct for C "char text [41] ;" ?
# ("text", ctypes.POINTER(ctypes.c_char))] # WHICH declaration is correct for C "char text [41] ;" ?
# ("text", ctypes.c_char_p)] # WHICH declaration is correct for C "char text [41] ;" ?
reference = REFERENCE_STRUCT()
print("test_alloc: ", mylib.test_alloc (ctypes.byref(reference)))
print("reference.type: ", reference.type)
dataP = ctypes.cast(reference.dataP, ctypes.POINTER(DATA_STRUCT))
# accessing the number without problem:
print("dataP.contents.number: ",dataP.contents.number)
print(ctypes.cast(reference.dataP,
ctypes.POINTER(DATA_STRUCT)).contents.text)
print("test_print: ", mylib.test_print (ctypes.byref(reference)))
dataP.contents.number = 7
ctypes.cast(reference.dataP, ctypes.POINTER(DATA_STRUCT)).contents.text = b'num 6'
print("dataP.contents.number: ",dataP.contents.number)
print(ctypes.cast(reference.dataP, ctypes.POINTER(DATA_STRUCT)).contents.text)
print("test_print: ", mylib.test_print (ctypes.byref(reference)))
print("\n")
print("test_free: ", mylib.test_free (ctypes.byref(reference))) # freeing the alocated memory