Search code examples
c++windowswinapilambdascoping

Windows types won't let my callback access local variables, any workaround?


I'm trying to use the EnumWindows function, which takes a WNDENUMPROC as callback with a lambda in order to access local variables. Unfrotunately if i try to use [&] the compiler will tell me types don't match. What i'm trying:

HWND get_wallpaper_window()
    {
    HWND progman = FindWindow(L"ProgMan", NULL);
    SendMessageTimeout(progman, 0x052C, 0, 0, SMTO_NORMAL, 1000, nullptr);

    HWND wallpaper_hwnd;
    EnumWindows(
            // Error here 
            [&](HWND hwnd, LPARAM lParam) -> BOOL CALLBACK 
                    {
                    HWND p = FindWindowEx(hwnd, NULL, L"SHELLDLL_DefView", NULL);
                    if (p) { wallpaper_hwnd = FindWindowEx(NULL, hwnd, L"WorkerW", NULL); }
                    }
            , NULL);
    return wallpaper_hwnd;
    }

The only solution i could come up with is making wallpaper_hwnd global and defining the lambda with [], but since it's only needed when returned from that function and not needed globally i'd rather avoid that.

I love using globals way more than people would advice, but i only do when the global variable is something that interacts with the whole program, and this is not the case.

Any better solution i'm missing?


Solution

  • Lambda functions that capture outside variables cannot be used as Win32 callbacks. They are not convertible to raw function pointers.

    The solution in your case is to pass a pointer to something as the LPARAM parameter of EnumWindows(), which is passed to the callback.

    class A {...};
    A a;
    EnumWindows([](HWND   hwnd,LPARAM lParam) -> BOOL {
    A* a = (A*)lParam;
    ...
    },(LPARAM)&a);
    

    Most windows functions that require a callback support passing a user-defined value which can be a pointer to a structure. The compiler is smart enough to convert a non-capturing lambda to CALLBACK (=_stdcall) calling convention automatically.