How to call the winapi EnumWindows in a lambda?
My attempt:
DWORD parentId;
// ...
HWND parent_hwnd;
EnumWindows([parent_hwnd](HWND hwnd, LPARAM lParam)
{
DWORD lpdwProcessId;
GetWindowThreadProcessId(hwnd,&lpdwProcessId);
if(lpdwProcessId == lParam)
{
parent_hwnd = hwnd;
return FALSE;
}
return TRUE;
}, (LPARAM)&parentId);
>Solution :
EnumWindows() expects a plain function pointer for its callback, however a capturing lambda is not convertible to a function pointer. Only a non-capturing lambda is convertible to a function pointer. As such, you need to use a non-capturing lambda, and use the callback’s LPARAM parameter to pass around all of your lambda’s state information.
Note that you have two bugs in your original lambda, which would have caused your code to fail even if you could have used a capturing lambda as the callback:
-
You are capturing the caller’s
parent_hwndvariable by-value, which means the lambda makes a copy and won’t modify the value of the caller’s original variable. You would need to capture the variable by-reference instead. Not that it matters in this case, since you can’t use a capturing lambda anyway. -
(this one affects a non-capturing lambda, too) You are passing the caller’s
parentIdvariable byDWORD*pointer to the callback’sLPARAM, but then you are treating theLPARAM‘s value as-is, which means your comparison to each window’s process ID will never find a match. You would need to cast theLPARAMto aDWORD*pointer and then dereference that pointer in order to get the correctDWORDvalue for the comparisons, egif (lpdwProcessId == *(DWORD*)lParam). Otherwise, just pass in the caller’sparentIdvariable by-value instead of by-pointer, then you don’t have to worry about this casting. Not that it matters in this case, since you need to pass in more than just a singleDWORDto the callback in order for your logic to work.
With all of that said, try something more like this instead:
struct enumInfo {
DWORD procId;
HWND hwnd;
};
enumInfo info;
info.procId = ...;
info.hwnd = NULL;
EnumWindows(
[](HWND hwnd, LPARAM lParam)
{
enumInfo *info = reinterpret_cast<enumInfo*>(lParam);
DWORD dwProcessId;
GetWindowThreadProcessId(hwnd, &dwProcessId);
if (dwProcessId == info->procId)
{
info->hwnd = hwnd;
return FALSE;
}
return TRUE;
},
reinterpret_cast<LPARAM>(&info)
);
HWND parent_hwnd = info.hwnd;
// use parent_hwnd as needed...