Search code examples
pythonctypesfreetds

How to translate the cast of a memory address in C into python ctypes call?


Sorry if the title isn't accurate, I am not 100% sure it describes the situation correctly:

I am attempting to interface with the FreeTDS C-library using Python's ctypes module. I have some code running surprisingly well, but have run into one snag. I am not sure how to to translate the last parameter of the dbbind() call below into ctypes.

The C example I am following is:

  /* these variable types are defined in the FreeTDS library */
  DBINT customer_id;
  DBCHAR company_name[255];
  DBFLT8 avg_income;

  /* <snip> */


  /* Now bind the returned columns to the variables */
  /* BYTE is defined in the FreeTDS library */
  dbbind(dbconn, 1, INTBIND, 0, (BYTE *)&customer_id);
  dbbind(dbconn, 2, NTBSTRINGBIND, 0, (BYTE *)&company_name);
  dbbind(dbconn, 3, FLT8BIND, 0, (BYTE*)&avg_income);

So, A) how do I define my variables in Python as variable types from the library and B) how do I translate "(BYTE *)&company_name" etc. into ctypes calls?

Thank you!

Solution: thanks to Zuljin, I was able to work out the following:

import ctypes as ct

#<snip>

cid = ct.c_int()
cname = ct.create_string_buffer(256)
cavgincome = ct.c_float()
dtlib.dbbind(cdbconn, 1, INTBIND, 0, ct.byref(cid))
dtlib.dbbind(cdbconn, 2, NTBSTRINGBIND, 0, cname)
dtlib.dbbind(cdbconn, 3, REALBIND, 0, ct.byref(cavgincome))

while dtlib.dbnextrow(cdbconn) != NO_MORE_ROWS:
    print '%s | %s | %s' % (cid, cname.value, cavgincome)

Solution

  • I think you should just check what is behind these DBINT,DBCHAR,DBFLT8 types. Probably this is int, char and double. And for those basic types you can find ctypes - probably c_int, c_char, c_double. So you can now create python instances that will hold values returned by function. To pass these values as a pointer parameter you need to use byref() function. Something like this:

    customer_id = c_int()
    dbbind(dbconn, 1, INTBIND, 0, byref(customer_id))
    

    EDIT: For name you have to create empty character buffer. To do that ctypes provide 2 functions create_string_buffer and create_unicode_buffer. Output object from these functions can be directly passed to your function. Here is example (in Python 3) of normal and unicode scanf function call on Windows.

    from ctypes import *
    libc = cdll.msvcrt
    
    buf = create_string_buffer(256) 
    buf_u = create_unicode_buffer(256)
    
    libc.scanf(b"%s",  buf)
    libc.wscanf("%s",  buf_u)
    
    print(buf.value)
    print(buf_u.value)