Does D has any support for thunks?

John via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sat Jun 25 07:06:51 PDT 2016


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


More information about the Digitalmars-d-learn mailing list