Типы Windows не позволяют моему обратному вызову обращаться к локальным переменным, есть ли обходной путь? - PullRequest
2 голосов
/ 12 мая 2019

Я пытаюсь использовать функцию EnumWindows, которая принимает WNDENUMPROC в качестве обратного вызова с лямбдой для доступа к локальным переменным.К сожалению, если я попытаюсь использовать [&], компилятор скажет мне, что типы не совпадают.То, что я пытаюсь:

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 глобальным и определить лямбду с помощью [], но так как это необходимо только тогда, когда оно возвращается из этой функции и не требуется глобальноя бы предпочел этого избегать.

Я люблю использовать глобальные переменные больше, чем советуют люди, но я делаю это только тогда, когда глобальная переменная взаимодействует со всей программой, а это не так.

Какое лучшее решение мне не хватает?

Ответы [ 2 ]

4 голосов
/ 12 мая 2019

Лямбда-функции, которые захватывают внешние переменные, не могут использоваться в качестве обратных вызовов Win32. Они не конвертируются в необработанные указатели функций.

Решение в вашем случае состоит в том, чтобы передать указатель на что-то в качестве параметра LPARAM в EnumWindows (), который передается обратному вызову.

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

Большинство оконных функций, которым требуется обратный вызов, поддерживают передачу определенного пользователем значения, которое может быть указателем на структуру. Компилятор достаточно умен, чтобы автоматически преобразовывать лямбда без захвата в CALLBACK (= _stdcall).

2 голосов
/ 12 мая 2019

Есть ли какое-нибудь лучшее решение, которого мне не хватает?

Ну да, этот 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;
    }
...