On Thursday, 19 November 2020 at 04:23:13 UTC, Marcone wrote:
// Function threadingw()
void threadingw(HWND hwn, void delegate() fun) nothrow {
try {
// Function _fun()
extern(Windows)
uint _fun(void * arg){
(*(cast(void delegate()*) arg))(); // Do not show "Hello
World!" :(
return 0;
}
CreateThread(null, 0, &_fun, &fun, 0, null);
} catch(Throwable){}
}
void main(){
null.threadingw({writeln("Hello World!");});
}
A delegate is a "fat" pointer (function pointer + context), so it
can't fit in a void*.
You could do something like the following to "uncurry" the
delegate and extract its context to a void* and a regular
function, which can then combine the void* given to it later to
call the original delegate:
import std.traits;
auto uncurryDelegate(alias anchor, alias target)()
{
alias Args = Parameters!target;
alias R = ReturnType!target;
alias ContextPtr = void*;
alias Dg = typeof(&target);
union Delegate
{
Dg dg;
struct
{
void* ptr;
void* funcptr;
}
}
auto dg = Delegate(&target);
__gshared void* funcptr; // Will always be the same for this
instantiation
funcptr = (&target).funcptr;
static struct Result
{
R function(ContextPtr ptr, Args args) fun;
ContextPtr context;
}
static R fun(ContextPtr ptr, Args args)
{
Delegate dg;
dg.funcptr = funcptr;
dg.ptr = ptr;
return dg.dg(args);
}
return Result(&fun, dg.ptr);
}
auto uncurryDelegate(alias target)()
{
return uncurryDelegate!(target, target);
}
unittest
{
int fun(int i)
{
return i + 1;
}
auto r = uncurryDelegate!fun;
assert(r.fun(r.context, 2) == 3);
}
unittest
{
struct S
{
int i;
int fun(int j)
{
return i + j;
}
auto funUncurried() { return uncurryDelegate!(i, fun); }
}
auto s = S(2);
auto r = s.funUncurried();
assert(r.fun(r.context, 3) == 5);
}
Sadly you can't write `static immutable void* funcptr =
(&target).funcptr;`, because the compiler tries to evaluate
&target first.
Alternatively you could do this (not recommended):
https://stackoverflow.com/a/8656294/21501