Найти все окна под точкой

Я хочу найти все окна верхнего уровня (дети рабочего стола) под заданной точкой на рабочем столе. Я не могу найти API для этого.

мой сценарий заключается в том, что я перетаскиваю окно по экрану и хочу поместить его в другое (известное) окно. Я могу проверить границы целевого окна ok, но это не говорит мне, закрыто ли оно другим (неизвестным) окном. Используя WindowFromPoint и друзья не будут работать, потому что перетаскиваемое окно обязательно напрямую под мышки. Поэтому мне интересно, могу ли я получить все окна в положении мыши и просмотреть их, чтобы увидеть, находится ли одно из окон, которое я отслеживаю, прямо под окном, которое я перетаскиваю.

есть ли способ сделать это не прибегая к EnumDesktopWindows/GetWindowRect на каждом перетаскивании мыши? Или, возможно, есть другое решение, которое я упускаю.

2 ответов


если вы спросите по-доброму, WindowFromPoint проигнорирует ваше окно (которое в настоящее время перетаскивается) и вернет следующее окно. Это то, что Internet Explorer делает при перетаскивании вкладки.

для этого:

  1. дескриптор WM_NCHITTEST в окно перетаскивается
  2. возвращение HTTRANSPARENT во время перетаскивания. Вызовите окно по умолчанию proc в противном случае.
  3. WindowFromPoint игнорировать HTTRANSPARENT windows, но только те, которые принадлежат вызывающий поток. Это не должно быть проблемой для вас, потому что вы должны позвонить WindowFromPoint из окна в любом случае резьбы.
  4. убедитесь, что нет дочерних окон в точке, переданной WindowFromPoint, или handle WM_NCHITTEST для этих дочерних окон, а также.

устранение неисправностей (если вы все еще получаете окно из WindowFromPoint)

  1. тест GetCurrentThreadID() == GetWindowThreadProcessId(WindowFromPoint(), 0) чтобы убедиться, что вы звоните из правильного потока
  2. на 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 ().