문제

The Window-Procedure in the Win32 API must be static \ global function since it cannot take a class-object (the this) parameter. One can of-course use workarounds like a hWnd->object dictionary and such.

I wonder if D has a way to elegantly solve it, like create a tiny member function copy for each object (to call the object's real handler) or anonymous function that I can assign to WNDCLASS.lpfnWndProc (I know there are anonymous functions, but I cannot use the extern(Windows) property on them) ?

Can I do something like this :


class Window {
    extern (Windows)
    LRESULT delegate (HWND hWnd, UINT msg, WPARAM w, LPARAM l) MyWinProcDelegate;

    this() {
        MyWinProcDelegate = &Events;
    }

    extern (Windows)
    LRESULT Events (HWND hWnd, UINT msg, WPARAM w, LPARAM l) {
        MessageBoxA(null , "Success!!!" , null ,0);
        return DefWindowProcA(hWnd, message, wParam, lParam);
    }
}

(Omitting the registration\creation\msg-loop...)

The Events() doesn't seem to fire... am I missing something ?

도움이 되었습니까?

해결책

How about storing this in the window itself, with SetWindowLong?

다른 팁

Here I made this for you (based on BCS' answer):

version (Windows)
{
    import std.c.windows.windows;

    void makeExecutable(ubyte[] code)
    {
        DWORD old;
        VirtualProtect(code.ptr, code.length, PAGE_EXECUTE_READWRITE, &old);
    }
}
else
version (linux)
{
    import core.sys.posix.sys.mman;
    import core.sys.posix.unistd;

    static if (!is(typeof(&mprotect)))
        extern(C) int mprotect(void*, size_t, int);

    void makeExecutable(ubyte[] code)
    {
        auto pageSize = sysconf(_SC_PAGE_SIZE);
        auto address = ((cast(size_t)code.ptr) & ~(pageSize-1));
        int pageCount =
            (address/pageSize == (address+code.length)/pageSize) ? 1 : 2;
        mprotect(cast(void*)address, pageSize * pageCount,
            PROT_READ | PROT_WRITE | PROT_EXEC);
    }
}
else
    static assert(0, "TODO");

R function(A) delegate2function(R, A...)(R delegate(A) d)
{
    enum size_t TEMPLATE1 = cast(size_t)0x01234567_01234567;
    enum size_t TEMPLATE2 = cast(size_t)0x89ABCDEF_89ABCDEF;

    static R functionTemplate(A args)
    {
        R delegate(A) d;
        d.ptr     = cast(typeof(d.ptr    ))TEMPLATE1;
        d.funcptr = cast(typeof(d.funcptr))TEMPLATE2;
        return d(args);
    }

    static void functionTemplateEnd() {}

    static void replaceWord(ubyte[] a, size_t from, size_t to)
    {
        foreach (i; 0..a.length - size_t.sizeof + 1)
        {
            auto p = cast(size_t*)(a.ptr + i);
            if (*p == from)
            {
                *p = to;
                return;
            }
        }
        assert(0);
    }

    auto templateStart = cast(ubyte*)&functionTemplate;
    auto templateEnd   = cast(ubyte*)&functionTemplateEnd;
    auto templateBytes = templateStart[0 .. templateEnd - templateStart];

    // must allocate type with pointers, otherwise GC won't scan it
    auto functionWords = new void*[(templateBytes.length / (void*).sizeof) + 3];
    // store context in word-aligned boundary, so the GC can find it
    functionWords[0] = d.ptr;
    functionWords[1] = d.funcptr;
    functionWords = functionWords[2..$];

    auto functionBytes = (cast(ubyte[])functionWords)[0..templateBytes.length];
    functionBytes[] = templateBytes[];

    replaceWord(functionBytes, TEMPLATE1, cast(size_t)d.ptr    );
    replaceWord(functionBytes, TEMPLATE2, cast(size_t)d.funcptr);
    makeExecutable(functionBytes);

    return cast(typeof(return)) functionBytes.ptr;
}

void main()
{
    import std.stdio;

    auto context = 42;

    void del(string s)
    {
        writeln(s);
        writeln(context);
    }

    auto f = delegate2function(&del);
    f("I am a pretty function");
}

Tested on Windows 32-bit and Linux 64-bit.

One very un-portable solution would be to dynamically create a function that wraps the call. I would do this by writing a function that looks like this:

extern(C) RetType TestFn(Arg arg /* and any others */) {
   Class c = cast(Class)(0xDEAD_BEEF);
   return c.Method(arg);
}

You can then compile this function as un-optimized PIC, de-compile it, and find a byte sequence that can be mashed into what you need. The end result would be a type (likely a struct) that has a methoud returning a function pointer and that, when constructed, populates an internal void array with the bytes you found from the above step and pokes the object in question into the appropriate places.

A slightly more advanced solution would populate a delegate with both the object and the method pointer so both can be provided to the constructor. An even more advanced solution would template the type and take advantage of knowledge of the C and D calling conventions to dynamically generate the argument forwarding code.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top