Найти все окна под точкой
Я хочу найти все окна верхнего уровня (дочерние элементы рабочего стола) под заданной точкой на рабочем столе. Я не могу найти API для этого.
Мой сценарий заключается в том, что я перетаскиваю окно через экран и хочу поместить его в другое (известное) окно. Я могу нажать, чтобы проверить границы целевого окна, но это не говорит мне, закрыто ли оно другим (неизвестным) окном. С помощью WindowFromPoint
и друзья не будут работать, потому что перетаскиваемое окно обязательно находится прямо под мышью. Поэтому мне интересно, смогу ли я получить все окна в позиции мыши и просмотреть их, чтобы увидеть, находится ли одно из отслеживаемых окон непосредственно под окном, которое я перетаскиваю.
Есть ли способ сделать это, не прибегая к EnumDesktopWindows
/GetWindowRect
на каждое перетаскивание мыши? Или возможно есть другое решение, которое я пропускаю.
2 ответа
Если вы любезно спросите, WindowFromPoint
проигнорирует ваше окно (которое в данный момент перетаскивается) и вернет следующее окно. Это то, что Internet Explorer делает, когда вы перетаскиваете вкладку.
Для этого:
- Справиться
WM_NCHITTEST
в окно тащат - Вернуть
HTTRANSPARENT
во время перетаскивания. В противном случае вызовите процедуру окна по умолчанию. WindowFromPoint
будет игнорироватьHTTRANSPARENT
окна, но только те, которые принадлежат вызывающему потоку. Это не должно быть проблемой для вас, потому что вы должны звонитьWindowFromPoint
в любом случае из окна владельца темы.- Убедитесь, что нет дочерних окон в точке, переданной
WindowFromPoint
или ручкойWM_NCHITTEST
и для этих дочерних окон.
Устранение неполадок (если вы по-прежнему получаете окно от WindowFromPoint
)
- Тестовое задание
GetCurrentThreadID() == GetWindowThreadProcessId(WindowFromPoint(), 0)
чтобы убедиться, что вы звоните из правильного потока - В
WM_NCHITTEST
проверить этоhwnd
параметр равен тому, что вы получаете отWindowFromPoint()
Пример (область внутри прямоугольника возвращает основное окно из WindowFromPoint
):
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static const RECT s_TransparentRect = {100, 100, 200, 200};
switch (message)
{
case WM_NCCREATE:
SetTimer(hWnd, 1, 100, 0);
break;
case WM_TIMER:
{
POINT cursorPos;
GetCursorPos(&cursorPos);
TCHAR buffer[256];
_snwprintf_s(buffer, _countof(buffer), _TRUNCATE, _T("WindowFromPoint: %08X\n"), (int)WindowFromPoint(cursorPos));
SetWindowText(hWnd, buffer);
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(hWnd, &ps);
Rectangle(ps.hdc, s_TransparentRect.left, s_TransparentRect.top, s_TransparentRect.right, s_TransparentRect.bottom);
EndPaint(hWnd, &ps);
}
break;
case WM_NCHITTEST:
{
POINT cursorPos;
GetCursorPos(&cursorPos);
MapWindowPoints(HWND_DESKTOP, hWnd, &cursorPos, 1);
if (PtInRect(&s_TransparentRect, cursorPos))
return HTTRANSPARENT;
}
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
Правильно, вы уже знаете, что должен возвращать WindowFromPoint (), именно тот, который вы перетаскиваете. Затем используйте GetWindow() с uCmd = GW_HWNDNEXT, чтобы получить нижний в Z-порядке. GetWindowRect(), чтобы получить его границы, IntersectRect(), чтобы вычислить перекрытие.
Продолжайте вызывать GetWindow(), чтобы найти больше окон, которые могут перекрываться. Пока не вернется NULL или перекрытие не будет достаточно хорошим. Если нет, то вы, как правило, предпочитаете тот, который имеет наибольший прямоугольник результата из IntersectRect().