title: Accesing the referenced C struct string from python ctypes
body: <p>I cannot access from python <em>ctypes</em> the (fixed length) <em>string</em> from referenced structure allocated by C code (dll library). But the <em>int</em> type I can access and change.</p>
  
  <p>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.</p>
  
  <p>My assumption was that wrong is either python declaration of <em>"text"</em> in <em>DATA_STRUCT</em> (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).</p>
  
  <p>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).</p>
  
  <p><strong>dll.h</strong></p>
  
  <pre><code>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) ;
  </code></pre>
  
  <p><strong>maindll.c</strong></p>
  
  <pre><code>#include "dll.h"
  #include &lt;windows.h&gt;
  #include &lt;string.h&gt;
  #include &lt;stdio.h&gt;
  
  __declspec(dllexport) int test_alloc (REFERENCE_STRUCT *refP) {
      DATA_STRUCT         *dataP ;
      dataP = malloc (sizeof (DATA_STRUCT));
      dataP-&gt;number = 5 ;
      strcpy (dataP-&gt;text, "number 1");
      refP-&gt;type = 40 ;
      refP-&gt;dataP = ( void *) dataP ;
      printf ("DLL - alloc: reference type: %d;  data &lt;%d&gt;; &lt;%s&gt;\n", refP-&gt;type, dataP-&gt;number, dataP-&gt;text) ;
      return 0;
  } ;
  
  __declspec(dllexport) int test_print (REFERENCE_STRUCT *refP) {
      DATA_STRUCT         *dataP ;
      dataP = (DATA_STRUCT*) refP-&gt;dataP ;
      printf ("DLL - print: reference type: %d;  data &lt;%d&gt;; &lt;%s&gt;\n", refP-&gt;type, dataP-&gt;number, dataP-&gt;text) ;
      return 0;
  } ;
  
  __declspec(dllexport) int test_free (REFERENCE_STRUCT *refP){
      free(refP-&gt;dataP) ;
      printf ("DLL - free\n") ;
      return 0;
  } ;
  </code></pre>
  
  <p><strong>script.py</strong></p>
  
  <pre><code>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
  </code></pre>