From: Martin Landa on
Hi,

is it possible to pass pointer to a method using ctypes. Sample code:

...
G_set_error_routine(byref(self._print_error))
...

def _print_error(self, msg, type):
"""!Redirect stderr"""
self.log.write(msg)

gives me

G_set_error_routine(byref(self._print_error))
TypeError: byref() argument must be a ctypes instance, not
'instancemethod'


C function G_set_error_routine is defined as

void G_set_error_routine(int (*error_routine) (const char *, int))

Thanks in advance for any pointers. Martin
From: Nobody on
On Thu, 05 Aug 2010 10:50:21 -0700, Martin Landa wrote:

> is it possible to pass pointer to a method using ctypes.

I don't know about methods, but it works for functions.

> Sample code:
>
> ...
> G_set_error_routine(byref(self._print_error))

This won't work; you have to be more explicit, e.g.:

errtype = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_int))
errfunc = errtype(print_error)
G_set_error_routine(errfunc)

NOTE: be sure to keep a reference to the wrapper, as ctypes doesn't hold
references itself. IOW, you can't replace the above with:

errtype = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_int))
G_set_error_routine(errtype(print_error))

If you do this, the wrapper is eligible for garbage collection as soon as
G_set_error_routine() returns, and will probably have vanished by the time
that G_fatal_error() gets called.

For more information see:

http://docs.python.org/library/ctypes.html#callback-functions

From: Martin Landa on
Hi,

On Aug 5, 9:32 pm, Nobody <nob...(a)nowhere.com> wrote:
> I don't know about methods, but it works for functions.
>
> > Sample code:
>
> >     ...
> >     G_set_error_routine(byref(self._print_error))
>
> This won't work; you have to be more explicit, e.g.:
>
>         errtype = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_int))
>         errfunc = errtype(print_error)
>         G_set_error_routine(errfunc)

the C function is defined as

G_set_error_routine = _libs['grass_gis.
7.0.svn'].G_set_error_routine
G_set_error_routine.restype = None
G_set_error_routine.argtypes = [CFUNCTYPE(UNCHECKED(c_int),
String, c_int)]

I defined in Python function print_error()

def print_error(self, msg, type):
print msg, type

and

errtype = CFUNCTYPE(UNCHECKED(c_int), String, c_int)
errfunc = errtype(print_error)
G_set_error_routine(errfunc)

unfortunately the application crashes when print_error() is called
from C library

static void vfprint_error(int type, const char *template, va_list ap)
{
char buffer[2000]; /* G_asprintf does not work */

vsprintf(buffer, template, ap);

G_debug(5, "print_error(): msg = \"%s\" type = %d", buffer, type);
print_error(buffer, type);
}

Any idea how to solve it. Thanks, Martin

From: Martin Landa on
Hi,

On Aug 6, 10:10 pm, Martin Landa <landa.mar...(a)gmail.com> wrote:

> Any idea how to solve it. Thanks, Martin

I overlooked note

"""
Make sure you keep references to CFUNCTYPE objects as long as they are
used from C code. ctypes doesn’t, and if you don’t, they may be
garbage collected, crashing your program when a callback is made.
"""

If I defined errtype and errfunc as global variable everything works.
Thanks again for your help. Martin
From: Martin Landa on
Hi,

On Aug 5, 9:32 pm, Nobody <nob...(a)nowhere.com> wrote:
>         errtype = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_int))
>         errfunc = errtype(print_error)
>         G_set_error_routine(errfunc)

the problem occurs when restype is not None, but c_int. E.g.

if hasattr(_libs['grass_gis'], 'G_set_error_routine'):
G_set_error_routine = _libs['grass_gis'].G_set_error_routine
G_set_error_routine.restype = c_int
G_set_error_routine.argtypes = [CFUNCTYPE(UNCHECKED(c_int),
String, c_int)]

errtype = CFUNCTYPE(UNCHECKED(c_int), String, c_int)
errfunc = errtype(print_error)

or

errtype = CFUNCTYPE(c_int, String, c_int)
errfunc = errtype(print_error)

ends up with error

G_set_error_routine(errfunc)
TypeError: in method 'G_set_error_routine', argument 1 of type 'int (*)
(char const *,int)'

The first argument of CFUNCTYPE defines result type (restype), AFAIU
that should work.

Thanks in advance again, Martin