3

I want to use c++ lambda expression as a window procedure in WinApi.
I've seen it on many pages, this one for example.
The code won't compile tho:

WNDPROC x = [](HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -> LRESULT {
    return 0;
};

Error I'm getting:

invalid user-defined conversion from 'main()::<lambda(HWND, UINT, WPARAM, LPARAM)>' to 'WNDPROC {aka long int (__attribute__((__stdcall__)) *)(HWND__*, unsigned int, unsigned int, long int)}' [-fpermissive]|

The problem seems to lay in __stdcall convention, but when I'm trying to add it:

WNDPROC x = [](HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -> CALLBACK LRESULT {
    return 0;
};

The complier says:

warning: 'stdcall' attribute only applies to function types [-Wattributes]|

So how are people using lambda as wndproc then?
Is it a compiler thing? (Does not work in CodeBlocks standard compiler, nor Visual Studio 2015)

Cansisti
  • 153
  • 7
  • https://stackoverflow.com/questions/14169295/how-to-specify-vc11-lambda-calling-convention#14169489 ? – R2RT Dec 07 '17 at 20:00
  • Just write a function. Then you can control all of the compiler-specific attributes. – Pete Becker Dec 07 '17 at 20:01
  • @R2RT am not sure if linked answer is good enough. Those casts seem to be undefined behavior to me. – SergeyA Dec 07 '17 at 20:02
  • 2
    The first code example compiles fine for me under Visual Studio 2017 – UnholySheep Dec 07 '17 at 20:03
  • https://stackoverflow.com/questions/14292803/can-i-have-main-window-procedure-as-a-lambda-in-winmain – rafix07 Dec 07 '17 at 20:03
  • 1
    Codeblocks comes with an old version of the MinGW GCC toolchain by default. Get the latest GCC version for MinGW. – user0042 Dec 07 '17 at 20:06
  • @user0042 Any tips or instructions how to do so? I've never changed the compiler before. – Cansisti Dec 07 '17 at 20:13
  • @Cansisti I'm not sure if your MinGW installation is up to date enugh, but the more recent ones come with a GUI driven update program. Search in your MinGW installation. Otherwise simply download their latest version and follow the installation instructions, an existing older version will probably be detected and removed with this process. – user0042 Dec 07 '17 at 20:18
  • What would be the rationale to do so? You aren't capturing anything, so what benefit over a regular function are you after? – IInspectable Dec 07 '17 at 20:18
  • @R2RT I'm still getting the same error when using static_cast operator – Cansisti Dec 07 '17 at 20:19
  • @IInspectable I want to be able to create unique functions in the runtime, each one having it's own static variable. – Cansisti Dec 07 '17 at 20:21
  • How is that in any way superior to simply having functions, for which you can take the address? What problem are you trying to solve? – IInspectable Dec 07 '17 at 20:32
  • @IInspectable I'm trying to create an unknown number of windows in runtime, each one having the same procedure, but different static variable (pointer to a class in my case). – Cansisti Dec 07 '17 at 20:37
  • 2
    @Cansisti: you don't need a static variable at all. Store the class pointer in the `HWND` itself, via `SetWindowLongPtr(GWL_USERDATA)` or `SetProp()` or `SetWindowSubclass()`, and then your window procedure can retrieve that pointer when needed, via `GetWindowLongPtr(GWL_USERDATA)`, `GetProp()`, or the `dwRefData` parameter of the subclass callback. – Remy Lebeau Dec 07 '17 at 21:42
  • 1
    The window procedure has to adhere to a defined interface. And your lambdas don't. Use a normal function. – David Heffernan Dec 08 '17 at 07:18
  • @Cansisti, That still won't work. Every *lambda expression* is a new type. Multiple invocations of the same closure use the same static variable, just as if you had written it out yourself. You can't create types at runtime in C++. – chris Dec 08 '17 at 14:18
  • Expanding on Remy Lebeau's comment, if you register the window classes yourself, you can set aside *cbWndExtra* bytes of memory, that's allocated per window instance to hold any references to custom per-instance data. This memory can be accessed through `GetWindowLongPtr`, passing an index into that memory, where zero indexes the beginning of the per-instance memory. When using `SetProp`, you need a unique string. A GUID is a common way to do that. `GWLP_USERDATA` should only be a last resort. It is a controversial subject, who is allowed to use that data. – IInspectable Dec 08 '17 at 14:38

0 Answers0