Как идентифицировать процессы хранения фонового хранилища Windows 10, которые имеют не отображаемые окна, программно видимые и минимизируемые?

У меня есть приложение Win32, которое определяет, отображаются ли какие-либо видимые, не-знаковые, минимизируемые окна. Насколько мне известно, он отлично работал для Win9x до Win8.1, но в Windows 10 он часто находит несколько окон, которые на самом деле не видны на экране.

Чтобы попытаться определить, что происходит, я написал простое тестовое приложение, которое перечисляет и записывает все такие окна. Здесь суть кода обратного вызова EnumWindows:

BOOL CALLBACK EnumFunc( HWND hWnd, LPARAM lParam )
{
  if ( IsWindowVisible( hWnd ) )
  {
    if ( !IsIconic( hWnd ) )
    {
      const LONG style = GetWindowLong( hWnd, GWL_STYLE );

      if ( WS_MINIMIZEBOX & style )
      {
     //      record window info
      }
    }
   }
 return TRUE;
}

Большинство окон phantom под Windows 10 принадлежат процессам приложений фонового хранилища, таким как Mail, Calculator и Photos. Они перечислены в разделе "Фоновые процессы" диспетчера задач, и если я использую диспетчер задач для завершения этих фоновых задач, их окно phantom больше не будет найдено моим тестовым приложением.

введите описание изображения здесь

В приведенном выше скриншоте из моего тестового приложения вы можете видеть, что все, кроме одного из оскорбительных окон, принадлежат нитьм того же идентификатора процесса 7768, который является ApplicationFrameHost.exe. В последнем окне с идентификатором процесса 11808 является explorer.exe.

Я просмотрел окна phantom со Spy ++ и не вижу никакой конкретной комбинации стилей, которая помогла бы однозначно идентифицировать их.

У меня было предположение, что могут быть задействованы недокументированные "группы" Windows, но я попытался использовать (недокументированный, так что это может быть неправильно) API:

BOOL WINAPI GetWindowBand (HWND hWnd, PDWORD pdwBand);

но он возвращает полосу 1 для любого окна, поэтому не дифференцирует эти фантомы.

Как надежно идентифицировать эти окна phantom?

Ответ 1

Утвержденный способ обнаружения этих phantom окон заключается в использовании DwmGetWindowAttribute и DWMWA_CLOAKED.

Вот код, который я использовал:

static bool IsInvisibleWin10BackgroundAppWindow( HWND hWnd )
{
    int CloakedVal;
    HRESULT hRes = DwmGetWindowAttribute( hWnd, DWMWA_CLOAKED, &CloakedVal, sizeof( CloakedVal ) );
    if ( hRes != S_OK )
    {
        CloakedVal = 0;
    }
    return CloakedVal ? true : false;
}

Спасибо Scot Br от MS за сообщение ответа here

Ответ 2

Окна верхнего уровня класса ApplicationFrameWindow являются контейнерами для приложений Windows Store. Во-первых, вот окно Mail, показанное в Spy:

введите описание изображения здесь

Это действительно видимо (не phantom). Вы можете сказать, что это потому, что первый ребенок является окном класса Windows.UI.Core.CoreWindow. Интересно, что процесс владельца ApplicationFrameWindow равен APPLICATIONFRAMEHOST, но процесс владельца Windows.UI.Core.CoreWindow является different one: HXMAIL. (Я еще не видел дочернее окно, принадлежащее другому процессу, чем родительский!)

Сравните это с окном phantom (как указано в RWTool):

введите описание изображения здесь

Отсутствует дочерний элемент класса Windows.UI.Core.CoreWindow.

Это дает ответ на ваш вопрос: если окно верхнего уровня имеет класс ApplicationFrameWindow, повторите его дочерние элементы. Если у первого дочернего элемента есть класс Windows.UI.Core.CoreWindow, окно видно, в противном случае оно (т.е. Оно phantom).

Но что, если у старомодного, не-магазина приложение оказалось окно верхнего уровня класса ApplicationFrameWindow? У него не было бы ребенка Windows.UI.Core.CoreWindow. Но это видно. Как сказать, это обычное приложение, а не приложение для Windows Store? У меня нет надежного способа. Вы также можете проверить наличие других дочерних окон приложения Store: ApplicationFrameTitleBarWindow и ApplicationFrameInputSinkWindow. Шансы на то, что приложение не для магазина, имеющее эту точную иерархию Windows, исчезает незначительно.

ИЗМЕНИТЬ

ApplicationFrameWindow (а также Windows.UI.Core.CoreWindow) имеют WS_EX_NOREDIRECTIONBITMAP стиль:

Окно не отображает поверхность перенаправления. Это для окон, которые не имеют видимого содержимого или которые используют механизмы, отличные от поверхностей, для обеспечения их визуального соответствия.

Как минимум, вы можете проверить этот стиль вместо специального корпуса ApplicationFrameWindow. Хотя чтобы убедиться, что какой-либо контент был действительно виден, вам все равно нужно зависеть от того, имеет ли он дочерний элемент Windows.UI.Core.CoreWindow.