Определить видимость окна в Vista - PullRequest
3 голосов
/ 05 ноября 2008

Я хочу определить, является ли определенное окно видимым для пользователя или скрыто / скрыто. В Windows XP я использовал бы функцию GetClipBox () и проверил бы NULLREGION или пустое возвращаемое значение RECT. Это прекрасно работало, но в Windows Vista оно не работает, если другое окно закрывает окно. В этом случае GetClipBox () возвращает SIMPLEREGION с непустым RECT.

Кто-нибудь знает, почему это не работает в Vista или есть другой способ проверить, может ли пользователь видеть окно?

Ответы [ 5 ]

2 голосов
/ 21 ноября 2008

Простая причина, по которой GetClipBox () не возвращает NULLREGION с включенным DWM, заключается в том, что вы не обрезаны! Весь смысл DWM состоит в том, что каждое окно (которое не является дочерним, например кнопки или поля редактирования) получает свой собственный буфер для рисования, поэтому окна переднего плана можно перемещать, не заполняя окна позади них.

В качестве простого примера, наведите курсор мыши на элемент окна в панели задач, когда он находится в фоновом режиме, и посмотрите, как он обновляется в окне предварительного просмотра.

Также обратите внимание, что со стеклянными краями ваше окно может быть полностью закрыто другими окнами и при этом оставаться видимым! (Вы не можете даже протестировать клиентскую область из-за расширенного стекла, как использует Windows Media Player - измените его размер до минимального размера, и вы увидите, что он использует стекло для всей своей площади!) Конечно, многослойные окна (от XP на ) и области пользовательских окон означали, что это всегда может иметь место, но теперь это значение по умолчанию.

Резюме / TL; DR:

Если вы выполняете тяжелые анимационные / причудливые эффекты и хотите уменьшить нагрузку на процессор при работе в DWM, возможно, лучшее, что вы можете сделать, это обнаружить, когда ваше приложение теряет передний план и откат к более дружественному обновлению процессора (НЕ обновлять! вы получаете WM_PAINT и игнорируете его, потому что вы находитесь в фоновом режиме, вы не получите его, когда активированы!).

2 голосов
/ 05 ноября 2008

В вашей установке Vista включена компоновка оконного менеджера рабочего стола? Я предполагаю, что это так, и если вы выключите его, вы получите ожидаемое поведение XP. Проблема в том, что в Vista с композицией DWM способ обработки окон сильно изменился, и я не думаю, что будет простой способ получить то, что вы хотите.

1 голос
/ 05 ноября 2008

В вашей установке Vista, это рабочий стол состав оконного менеджера включен? Я думаю, что это так, и если Вы выключите его, вы получите ожидаемое поведение XP. Вопрос что под Vista с составом DWM, способ обработки окон сильно изменился, и я не думаю, там будет простой способ добраться до что ты хочешь.

Да, DWM включен на моей машине. Я попробовал следующее, чтобы проверить ваше предположение:

  1. Щелкните правой кнопкой мыши мое приложение и выберите "Свойства"
  2. Кликнул по вкладке «Совместимость»
  3. Включен флажок «Отключить композицию рабочего стола»
  4. Нажал «Применить»

После этого функция GetClipBox () работает правильно. Так что твоя догадка верна. Я обнаружил, что могу выполнить это программно, используя следующую функцию в моем приложении:

DwmEnableComposition(DWM_EC_DISABLECOMPOSITION);

Однако это отключает эффекты прозрачности во время работы моего приложения, что нежелательно. Я бы предпочел менее навязчивое решение.

В любом случае, спасибо за совет!

1 голос
/ 05 ноября 2008

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

0 голосов
/ 05 ноября 2008

Поскольку вы знаете, что выводит GetClipRect как в XP, так и в Vista (с включенным DWM и без него), вы можете создать функцию для определения этого, которая использует разные пути в зависимости от ОС. В псевдо-код:

function bool IsWindowVisible()
{
   bool isVisible = false;

   if (OSVersion == "XP")
   {
      // GetClipRect tests which run on XP and set isVisible
   }
   else if (OSVersion == "Vista")
   {
      if (DWMCompisitionEnabled == true)
      {
         // GetClipRect tests for Vista with DWM enabled and set isVisible
      }
      else
      {
         // GetClipRect tests for Vista with DWM disabled and set isVisible
      }
   }
   return isVisible;
}
...