www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Use nested functions as callbacks with Windows API functions?

reply spikespaz <spikespaz outlook.com> writes:
I have the following code, this works.

================================================================

import core.sys.windows.windows: EnumWindows;
import std.stdio: writeln;

void*[] hWndList;

extern (Windows) int callback(void* hWnd, long /* lParams */ ) 
nothrow {
     hWndList ~= hWnd;

     return true;
}

void main() {
     EnumWindows(&callback, 0);

     writeln(hWndList);
}

================================================================

I was hoping I could use something more akin to JavaScript's 
syntax: (void* hWnd, long) => {}.

I tried this but I'm getting errors with the signature, it says 
the function is a delegate and apparently Windows API can't 
accept a delegate.

================================================================

import core.sys.windows.windows: EnumWindows;
import std.stdio: writeln;

void main() {
     void*[] hWndList;

     EnumWindows((void* hWnd, long /* lParams */ ) nothrow {
         hWndList ~= hWnd; return true;
     }, 0);

     writeln(hWndList);
}

================================================================

I'm not going to even paste the compiler error because I am very 
clearly going about this the wrong way.

Of course there is nothing wrong with defining each callback as a 
separate function, but then comes the issue of naming them. I 
also don't like the way it makes my code look.

Thanks.
Oct 01 2018
next sibling parent reply Boris-Barboris <ismailsiege gmail.com> writes:
On Monday, 1 October 2018 at 20:27:43 UTC, spikespaz wrote:
 I was hoping I could use something more akin to JavaScript's 
 syntax: (void* hWnd, long) => {}.

 I tried this but I'm getting errors with the signature, it says 
 the function is a delegate and apparently Windows API can't 
 accept a delegate.
You can make it a non-delegate by passing a pointer to hWndList in lParams as it was supposed to by WinApi devs, instead of zero, and not implicitly capturing stack pointer by referencing hWndList directly from the body. https://run.dlang.io/is/t4k4Nc
Oct 01 2018
next sibling parent spikespaz <spikespaz outlook.com> writes:
On Monday, 1 October 2018 at 21:03:24 UTC, Boris-Barboris wrote:
 On Monday, 1 October 2018 at 20:27:43 UTC, spikespaz wrote:
 I was hoping I could use something more akin to JavaScript's 
 syntax: (void* hWnd, long) => {}.

 I tried this but I'm getting errors with the signature, it 
 says the function is a delegate and apparently Windows API 
 can't accept a delegate.
You can make it a non-delegate by passing a pointer to hWndList in lParams as it was supposed to by WinApi devs, instead of zero, and not implicitly capturing stack pointer by referencing hWndList directly from the body. https://run.dlang.io/is/t4k4Nc
I don't know how to do this. I'm not the best with pointers, I'm still learning D and I'm unfamiliar with functional programming. ============================================== import core.sys.windows.windows: EnumWindows; import std.stdio: writeln; extern (Windows) int callback(void* hWnd, long hWndList) nothrow { hWndList ~= hWnd; return true; } void main() { void*[] hWndList; EnumWindows(&callback, &hWndList); writeln(hWndList); } ============================================== Clearly I can't use &hWndList to pass the reference, how would I access the variable by the memory address inside the callback?
Oct 01 2018
prev sibling parent reply spikespaz <spikespaz outlook.com> writes:
On Monday, 1 October 2018 at 21:03:24 UTC, Boris-Barboris wrote:
 On Monday, 1 October 2018 at 20:27:43 UTC, spikespaz wrote:
 I was hoping I could use something more akin to JavaScript's 
 syntax: (void* hWnd, long) => {}.

 I tried this but I'm getting errors with the signature, it 
 says the function is a delegate and apparently Windows API 
 can't accept a delegate.
You can make it a non-delegate by passing a pointer to hWndList in lParams as it was supposed to by WinApi devs, instead of zero, and not implicitly capturing stack pointer by referencing hWndList directly from the body. https://run.dlang.io/is/t4k4Nc
The problem with the code you have is that the callback needs to be extern (Windows). I don't know how to do that with a "lambda". =========================================== import core.sys.windows.windows: EnumWindows; import std.stdio: writeln; void main() { void*[] hWndList; EnumWindows((void* hWnd, void* lParam) nothrow { *(cast(void*[] *) lParam) ~= hWnd; return true; }, &hWndList); writeln(hWndList); } =========================================== source\cb.d(7): Error: function core.sys.windows.winuser.EnumWindows(extern (Windows) int function(void*, long) nothrow, long) is not callable using argument types (bool function(void* hWnd, void* lParam) pure nothrow system, void*[]*) source\cb.d(7): cannot pass argument __lambda1 of type bool function(void* hWnd, void* lParam) pure nothrow system to parameter extern (Windows) int function(void*, long) nothrow
Oct 01 2018
parent Boris-Barboris <ismailsiege gmail.com> writes:
On Monday, 1 October 2018 at 23:07:29 UTC, spikespaz wrote:
 The problem with the code you have is that the callback needs 
 to be extern (Windows). I don't know how to do that with a 
 "lambda".
Neither do I actually. Apparently it is impossible. Best I could squeeze out was this: https://run.dlang.io/is/CpyfW3
Oct 01 2018
prev sibling parent John Chapman <johnch_atms hotmail.com> writes:
On Monday, 1 October 2018 at 20:27:43 UTC, spikespaz wrote:
 Of course there is nothing wrong with defining each callback as 
 a separate function, but then comes the issue of naming them. I 
 also don't like the way it makes my code look.
I think the best you can do is something like this: --- auto callback(T, string file = __FILE__, size_t line = __LINE__)(T handler) { import std.traits; __gshared T handler_; handler_ = handler; extern(Windows) ReturnType!T fn(Parameters!T args) { synchronized return handler_(args); } return &fn; } void main() { HWND[] list; EnumWindows((HWND hwnd, LPARAM lparam) { list ~= hwnd; return TRUE; }.callback(), 0); writeln(list); } ---
Oct 02 2018