digitalmars.D - Re: pass a delegate to an API as a context pointer?
- teo <teo.ubuntu yahoo.com> Jul 03 2007
- Russell Lewis <webmaster villagersonline.com> Jul 05 2007
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
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