Windows 类型不允许我的回调访问局部变量,有什么解决方法吗?

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

我正在尝试使用 EnumWindows function, which takes a WNDENUMPROC 作为带有 lambda 的回调来访问局部变量。不幸的是,如果我尝试使用 [&],编译器会告诉我类型不匹配。 我在尝试什么:

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

我能想出的唯一解决方案是使 wallpaper_hwnd 全局化并使用 [] 定义 lambda,但由于它仅在从该函数返回时才需要,而不是全局需要,所以我宁愿避免这种情况。

我比人们建议的更喜欢使用全局变量,但我只在全局变量与整个程序交互时才这样做,而事实并非如此。

我还缺少更好的解决方案吗?

捕获外部变量的 Lambda 函数不能用作 Win32 回调。它们不能转换为原始函数指针。

您的解决方案是将指向某物的指针作为 EnumWindows() 的 LPARAM 参数传递给回调。

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

大多数需要回调的 windows 函数支持传递 user-defined 值,该值可以是指向结构的指针。编译器足够聪明,可以自动将 non-capturing lambda 转换为 CALLBACK (=_stdcall) 调用约定。

Any better solution i'm missing?

嗯,是的,第二个参数中的 NULL 被传递回回调,因此您可以轻松地使用它来传播本地状态。

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

    HWND wallpaper_hwnd;
    EnumWindows(
            [](HWND hwnd, LPARAM lParam) -> BOOL CALLBACK 
                {
                    auto wallpaper_hwnd_ptr = reinterpret_cast<HWND*>(lParam);
                    HWND p = FindWindowEx(hwnd, NULL, L"SHELLDLL_DefView", NULL);
                    if (p) { *wallpaper_hwnd = FindWindowEx(NULL, hwnd, L"WorkerW", NULL); }
                    }
            , &wallpaper_hwnd);
    return wallpaper_hwnd;
    }