www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Calling delegate in a dll callback fails silently

reply Andre Pany <andre s-e-a-p.de> writes:
Hi,

my D application uses a Dll written in another language.
In my D code I retrieve the address of a delegate as integer:

int dgRef = cast(int) &(dg);

This integer I pass to a function in the dll together with the
address of a callback function.

extern(C) static void notifyEventCallback(int reference1)
{
	if (auto dg = *cast(NotifyEvent*)cast(void*) reference1)
	{
		writeln("HERE1");
		dg(null);
		writeln("HERE2");
	}
}

The callback function casts the integer back to the delegate
and execute it.

This scenario is working fine if in the dll function the callback
immediatelly is called. But my real scenario is not working.
The dll shows an UI and the callback should be called on a
button press in the UI.
In this scenario the callback is called, the cast is successful
and HERE1 is shown but neither the dg is called (has a dummy 
writeln as coding)
nor HERE2 is shown.

I have no idea why the cast can be succesful but the call to 
dg(null) is silently
failing. Do you have any idea? Maybe the UI button press runs in 
another thread and causes this issue?

Kind regards
André
Jun 16 2017
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Friday, 16 June 2017 at 22:17:07 UTC, Andre Pany wrote:
 int dgRef = cast(int) &(dg);
What is the type of dg there? This looks horribly, horribly wrong to me. If it is type delegate, you took the address of a local variable, which is likely overwritten by the time the callback triggers. Moreover, even if you didn't get a pointer to local, a delegate is twice the size of a pointer and thus wouldn't fit in an int anyway... If it is a direct function reference it might work, though then you might as well just use it directly as the callback.
 	if (auto dg = *cast(NotifyEvent*)cast(void*) reference1)
This suggests you got a pointer to the pointer; an escaped reference to a local variable. If the function is called immediately, the local is still in scope and valid, but if called later, the local goes away and gets overwritten, causing the dll thread to jump into nonsense and most likely crash and die. What you want to use is a regular function with a global thing, an object reference kept alive, or a thunk. Here's one fairly simple technique you can use: https://stackoverflow.com/questions/22845175/pass-delegates-to-external-c-functions-in-d
Jun 16 2017
parent Andre Pany <andre s-e-a-p.de> writes:
On Saturday, 17 June 2017 at 03:35:42 UTC, Adam D. Ruppe wrote:
 On Friday, 16 June 2017 at 22:17:07 UTC, Andre Pany wrote:
 [...]
What is the type of dg there? This looks horribly, horribly wrong to me. [...]
Thanks a lot for the explanation and the link. Now it makes sense why it not works. Kind regards André
Jun 17 2017