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;
}
我正在尝试使用 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;
}