Is there a way to create an elegant member function of a class?

The Window procedure in the Win32 API must be a static \ global function because it cannot accept the class-object ( this ) parameter. You can, of course, use workarounds such as the hWnd-> object dictionary, etc.

I wonder if method D has its elegant solution, for example, to create a small copy of a member function for each object (call the real object handler) or an anonymous function that I can assign to WNDCLASS.lpfnWndProc (I know there are anonymous functions, but I donโ€™t can I use the extern(Windows) property extern(Windows) 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 registration \ creating \ msg-loop ...)

Events () do not seem to fire ... am I missing something?

+4
source share
3 answers

How about saving this in the window itself, SetWindowLong ?

+1
source

Here I did it 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 32-bit and 64-bit versions of Windows.

+3
source

One very intolerable solution would be to dynamically create a function that completes 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 a non-optimized PIC , decompile it and find a sequence of bytes that might be confused with what you need. The end result will be a type (probably a struct) that has methoud, which returns a pointer to a function, and which, when building, fills the internal void array with the bytes that you found from the above step, and calls this object in appropriate places.

A slightly more advanced solution is to populate the delegate with both an object and a method pointer, so that both can be provided to the constructor. An even more advanced solution would be to use a type pattern and use the knowledge of C and D invocation calls to dynamically generate argument transfer code.

+1
source

Source: https://habr.com/ru/post/1388131/


All Articles