Using delegates for C callbacks.

Kirk McDonald kirklin.mcdonald at gmail.com
Fri Feb 1 14:23:40 PST 2008


Leandro Lucarella wrote:
> Hi! I'm doing some code to interface with C and I need to use D delegates
> as C callbacks.
> 
> I've tested a lot of posibilities to do this, asking on IRC channels, but
> nothing seems to work entirely.
[snip]
> 
> The thunk for the plain function adaptation works fine, but not the
> delegate. If I uncomment the code at line 33 I get:
> 
> thunk.d:10: Error: need 'this' to access member dcb
> 
> I have a void* pointer to use, I can "inject" the this pointer, but I
> don't know how. Doing something like:
> 
>  8  extern (C) static void thunk(alias Fn)(void* arg)
>  9  {
> 10  	Fn.ptr = arg;
> 11  	Fn();
> 12  }
> 
> Doesn't work, it says:
> thunk.d:10: Error: no property 'ptr' for type 'void'
> thunk.d:10: Error: constant dcb().ptr is not an lvalue
> thunk.d:10: Error: cannot implicitly convert expression (arg) of type void* to int
> 
> Which I don't understand (specially the part of "no property 'ptr' for
> type 'void'", why dcb is void? I don't think I understand very well the
> semantics of an alias template parameter =S
> 
> 
> Is there any recomended solution for this? I think it (or should be) a
> fairly common problem (at least when making D bindings for C libraries).
> 

Try something like this:

extern(C) void f(void function(void*) fn, void* closure) {
     fn(closure);
}

class C {
     void foo(int i) {}
}

struct Closure {
     C self;
     int arg;
}

// It is possible to do some template trickery in order to
// generalize this thunk for any function signature and any
// class, but it is simpler to get the point across with a
// concrete example.
extern(C) void thunk(alias Fn)(void* _closure) {
     void delegate(int) dg;
     Closure* closure = cast(Closure*)_closure;
     dg.funcptr = &Fn;
     dg.ptr = cast(void*)(closure.self);
     dg(closure.arg);
}

void main() {
     C c = new C;
     auto closure = new Closure;
     closure.self = c;
     closure.arg = 20;
     // Note that we're passing the function C.foo and not
     // the method c.foo.
     thunk!(C.foo)(closure);
     f(&thunk!(C.foo), closure);
}

-- 
Kirk McDonald
http://kirkmcdonald.blogspot.com
Pyd: Connecting D and Python
http://pyd.dsource.org


More information about the Digitalmars-d-learn mailing list