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);

Reply via email to