www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Re: pass a delegate to an API as a context pointer?

reply teo <teo.ubuntu yahoo.com> writes:
teo Wrote:

 Hi *, is it possible to pass a delegate to an API function which takes a
pointer to a callback function and a context pointer? The code bellow describes
what I'm trying to achieve.
 

I got it! Thanks to all of you Russell, Kirk, Jascha and Frits! Let me summarize: the idea is to keep the delegate in a member variable of the class and pass the address of that variable as a context data. This way the address remains valid when the callback is called from within the C-library. Perhaps it can be done in a more elegant way, but I'm satisfied with this solution: // C-Library typedef void (*callback)(void *context); void xyz(callback handler, void *context); // D-Program alias extern(C) void function(void *context) callback; extern(C) void xyz(callback handler, void *context); alias int delegate() foo; class A { int abc() { return 1; } } class B { foo _f = null; static extern(C) void handler(void *context) { foo f = *(cast(foo*)context); int i = f(); // call A.abc(); } void test(foo f) { _f = f; // this way the address remains valid xyz(&handler, &_f); } } void main() { A a = new A(); B b = new B(); b.test(&a.abc); // ... return; } By the way, I'm going to play with garbage collector, so I might have further questions.
Jul 03 2007
parent Russell Lewis <webmaster villagersonline.com> writes:
teo wrote:
 teo Wrote:
 
 Hi *, is it possible to pass a delegate to an API function which takes a
pointer to a callback function and a context pointer? The code bellow describes
what I'm trying to achieve.

I got it! Thanks to all of you Russell, Kirk, Jascha and Frits! Let me summarize: the idea is to keep the delegate in a member variable of the class and pass the address of that variable as a context data. This way the address remains valid when the callback is called from within the C-library. Perhaps it can be done in a more elegant way, but I'm satisfied with this solution: // C-Library typedef void (*callback)(void *context); void xyz(callback handler, void *context); // D-Program alias extern(C) void function(void *context) callback; extern(C) void xyz(callback handler, void *context); alias int delegate() foo; class A { int abc() { return 1; } } class B { foo _f = null; static extern(C) void handler(void *context) { foo f = *(cast(foo*)context); int i = f(); // call A.abc(); } void test(foo f) { _f = f; // this way the address remains valid xyz(&handler, &_f); } } void main() { A a = new A(); B b = new B(); b.test(&a.abc); // ... return; }

I don't see any problems with this implementation as it stands, but remember: this only works if xyz() calls your handler back synchronously. If it calls back asynchronously (that is, after main() exits), then the GC may have run and cleaned up the 'B b' variable you declared in main(). Obviously, that doesn't seem likely if with main()...but it is quite possible if the function is just some ordinary function in a larger program. Russ
Jul 05 2007