Thread overview
Does D has any support for thunks?
Jun 25, 2016
Andre Pany
Jun 25, 2016
Adam D. Ruppe
Jun 25, 2016
John
Jun 25, 2016
Andre Pany
Jun 25, 2016
Vladimir Panteleev
Jun 25, 2016
Andre Pany
Jun 25, 2016
Andre Pany
June 25, 2016
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é
June 25, 2016
On Saturday, 25 June 2016 at 13:44:48 UTC, Andre Pany wrote:
> Does D/Phobos has any support for thunks?

It isn't included in the stdlib, but you can use the same C++ they describe in the link in D.

June 25, 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);
June 25, 2016
On Saturday, 25 June 2016 at 14:06:51 UTC, John wrote:
> On Saturday, 25 June 2016 at 13:44:48 UTC, Andre Pany wrote:
>> [...]
>
> This will only work on X86:
>
> version(X86)
> struct FunctionPtr(TDelegate) if (is(TDelegate == delegate)) {
>
> [...]

Thanks a lot John, that's fantastic.

Kind regards
André
June 25, 2016
On Saturday, 25 June 2016 at 13:44:48 UTC, Andre Pany wrote:
> Does D/Phobos has any support for thunks?

Made this a while ago:

http://stackoverflow.com/a/8656294/21501
June 25, 2016
On Saturday, 25 June 2016 at 16:05:30 UTC, Vladimir Panteleev wrote:
> On Saturday, 25 June 2016 at 13:44:48 UTC, Andre Pany wrote:
>> Does D/Phobos has any support for thunks?
>
> Made this a while ago:
>
> http://stackoverflow.com/a/8656294/21501

Thanks, I had a look. Unfortunately it doesn't compile for my use case.
SetWindowsHookEx expects an "extern(windows)" and "nothrow" function.
delegate2function does not accept a delegate with

If it is possible to make this coding generic, it would fit into
std.functional.

Kind regards
André


June 25, 2016
On Saturday, 25 June 2016 at 17:26:03 UTC, Andre Pany wrote:
> On Saturday, 25 June 2016 at 16:05:30 UTC, Vladimir Panteleev wrote:
>> On Saturday, 25 June 2016 at 13:44:48 UTC, Andre Pany wrote:
>>> Does D/Phobos has any support for thunks?
>>
>> Made this a while ago:
>>
>> http://stackoverflow.com/a/8656294/21501
>
> Thanks, I had a look. Unfortunately it doesn't compile for my use case.
> SetWindowsHookEx expects an "extern(windows)" and "nothrow" function.
> delegate2function does not accept a delegate with
>
> If it is possible to make this coding generic, it would fit into
> std.functional.
>
> Kind regards
> André

...  does not accept a delegate with extern(windows).
July 02, 2016
On Saturday, 25 June 2016 at 17:52:48 UTC, Andre Pany wrote:
> On Saturday, 25 June 2016 at 17:26:03 UTC, Andre Pany wrote:
>> On Saturday, 25 June 2016 at 16:05:30 UTC, Vladimir Panteleev wrote:
>>> On Saturday, 25 June 2016 at 13:44:48 UTC, Andre Pany wrote:
>>>> Does D/Phobos has any support for thunks?
>>>
>>> Made this a while ago:
>>>
>>> http://stackoverflow.com/a/8656294/21501
>>
>> Thanks, I had a look. Unfortunately it doesn't compile for my use case.
>> SetWindowsHookEx expects an "extern(windows)" and "nothrow" function.
>> delegate2function does not accept a delegate with
>>
>> If it is possible to make this coding generic, it would fit into
>> std.functional.
>>
>> Kind regards
>> André
>
> ...  does not accept a delegate with extern(windows).

You can fix this by a cast:

alias callbackType = extern (Windows) uint function(void*);	
	
CreateThread(cast(SECURITY_ATTRIBUTES*)null, stackSize, cast(callbackType)delegate2function(c), cast(void*)&param, (suspended) ? CREATE_SUSPENDED : 0, &Id);

But there seems to be a problem as I can only get parameters to pass correctly on dmd x64.