Как определить, находится ли окно за пределами экрана?

в Windows XP и выше, учитывая дескриптор окна (HWND), как я могу сказать, если положение и размер окна оставляет окно безвозвратно с экрана? Например, если строка заголовка доступна курсору, то окно можно перетащить обратно на экран. Мне нужно выяснить, действительно ли окно видно или, по крайней мере, доступно пользователю. Думаю, мне также нужно знать, как обнаруживать и реагировать на изменения разрешения и как обращаться с несколькими мониторами. Это кажется довольно большим сделка. Я использую C++ и обычный SDK, поэтому, пожалуйста, ограничьте свои ответы этой платформой, а не вызывая C# или аналогичный.

3 ответов


Windows позволяет относительно просто определить размер рабочей области пользователя на основном мониторе (т. е. область экрана, не затемненная панелью задач). Вызовите SystemParametersInfo функции и указать SPI_GETWORKAREA флаг для первого параметра (uiAction). The pvParam параметр должен указывать на RECT структура который получит координаты рабочей зоны в виртуальном экране координирует.

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


Желание поддерживать несколько мониторов делает вещи немного сложнее. Документация для SystemParametersInfo предполагает, что вам нужно позвонить GetMonitorInfo функции вместо того, чтобы получить рабочую область монитор, отличный от основного. Он заполняет структуру под названием MONITORINFOEX который содержит элемент rcWork это определяет рабочую область этого монитора, снова выраженную в координатах виртуального экрана как RECT структура.

чтобы сделать это правильно, вам нужно перечислить все мониторы, которые пользователь подключил к системе, и получить рабочую область каждого с помощью GetMonitorInfo.

есть несколько примеров этого можно найти по всему интернету:

  • MSDN имеет некоторый пример кода для позиционирование объектов на нескольких настройках дисплея.
  • если вы используете MFC, вот что кажется отличный пример поддержки нескольких мониторов.
  • даже если вы не используете MFC, эта статья ссылается следующей ссылке который выглядит настоящим сокровищем, поскольку объясняет, как несколько мониторов поддерживает работу в Windows, даже если это немного старомодно. Нравится вам это или нет, очень мало что изменилось в более поздних версиях Windows.


Наконец, вы упомянули о желании обнаружить изменения разрешения. Это гораздо проще, чем вы, вероятно, себе представляли. Как вы знаете, если вы занимались программированием Windows, основной способ, которым операционная система взаимодействует с вашим приложением, - это отправка сообщений на ваш WindowProc функции.
В этом случае, вы захотите смотреть на WM_DISPLAYCHANGE, который отправляется во все окна при изменении разрешения дисплея. The wParam содержит новую глубину изображения в битах на пиксель; младшее слово lParam задает горизонтальное разрешение и слово высокого порядка lParam задает вертикальное разрешение экрана.


вы можете использовать MonitorFromRect или MonitorFromPoint, чтобы проверить, не содержится ли верхняя левая точка окна или нижняя правая точка в любом мониторе дисплея (вне экрана).

POINT p;
p.x = x;
p.y = y;
HMONITOR hMon = MonitorFromPoint(p, MONITOR_DEFAULTTONULL);
if (hMon == NULL) {
    // point is off screen
}

проверка видимости очень проста.

RECT rtDesktop, rtView;

GetWindowRect( GetDesktopWindow(), &rtDesktop );
GetWindowRect( m_hWnd, &rtView );

HRGN rgn = CreateRectRgn( rtDesktop.left, rtDesktop.top, rtDesktop.right, rtDesktop.bottom );

BOOL viewIsVisible = RectInRegion( rgn, &rtView );

DeleteObject(rgn);

вам не нужно использовать RectInRegion, я использовал для сокращения кода.

дисплей, мониторинг изменения разрешения также легко, если вы обрабатываете WM_SETTINGCHANGE сообщение.

http://msdn.microsoft.com/en-us/library/ms725497 (v=против 85).aspx

обновление

Как отметил @Cody Gray, я думаю, что WM_DISPLAYCHANGE более подходит, чем WM_SETTINGCHANGE. Но MFC 9.0 библиотека использует WM_SETTINGCHANGE.