On Saturday, 25 June 2016 at 13:44:48 UTC, Andre Pany wrote:
Hi everyone,
I have some issue with win32 function SetWindowsHookEx. For
this specific funtion there is no possibility to pass extra
data (pointer to a class instance to be called) to the callback
function.
The general solution seems to use thunks. I found s.th. for c++:
http://www.codeproject.com/Articles/16785/Thunking-in-Win-Simplifying-Callbacks-to-Non-sta
Does D/Phobos has any support for thunks?
Kind regards
André
This will only work on X86:
version(X86)
struct FunctionPtr(TDelegate) if (is(TDelegate == delegate)) {
import std.traits;
alias TResult = ReturnType!TDelegate;
alias TParameters = Parameters!TDelegate;
private struct ThunkCode {
align(1):
ubyte mov_eax;
void* this_ptr;
ubyte mov_ecx;
void* func_ptr;
ubyte mov_edx;
void* cb_ptr;
ushort jmp_edx;
}
this(TDelegate method) {
this = method;
}
auto ref opAssign(TDelegate method) {
extern(Windows)
TResult callback(TParameters parameters) {
TDelegate dg = void;
asm {
mov [dg], EAX;
mov [dg + 4], ECX;
}
return dg(parameters);
}
if (auto thunk = cast(ThunkCode*)VirtualAlloc(null,
ThunkCode.sizeof,
MEM_COMMIT, PAGE_EXECUTE_READWRITE)) {
with (thunk) {
mov_eax = 0xB8;
this_ptr = method.ptr;
mov_ecx = 0xB9;
func_ptr = method.funcptr;
mov_edx = 0xBA;
cb_ptr = &callback;
jmp_edx = 0xE2FF;
}
FlushInstructionCache(GetCurrentProcess(), thunk,
ThunkCode.sizeof);
ptr = cast(typeof(ptr))thunk;
}
else {
assert(false);
}
return this;
}
~this() {
if (ptr) {
VirtualFree(ptr, ThunkCode.sizeof, MEM_DECOMMIT);
ptr = null;
}
}
extern(Windows)
TResult function(TParameters) nothrow ptr;
alias ptr this;
}
alias HookProc = FunctionPtr!(LRESULT delegate(int, WPARAM,
LPARAM));
LRESULT hookProc(int code, WPARAM wparam, LPARAM lparam) {
return 0;
}
HookProc hook = &hookProc;
SetWindowsHookEx(WH_KEYBOARD, hook, GetModuleHandle(null), 0);