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

Reply via email to