Перечислять окна, как это делает alt-tab - PullRequest
27 голосов
/ 17 октября 2008

Я создаю замену alt-tab для Vista, но у меня возникают проблемы со списком всех активных программ.

Я использую EnumWindows для получения списка Windows, но этот список огромен. Он содержит около 400 элементов, когда у меня открыто только 10 окон. Кажется, это hwnd для каждого элемента управления и многих других вещей.

Так что мне нужно как-то отфильтровать этот список, но я не могу сделать это точно так, как это делает alt-tab.

Это код, который я использую для фильтрации списка прямо сейчас. Это работает довольно хорошо, но я получаю некоторые нежелательные окна, такие как отдельные окна инструментов в Visual Studio, и я также скучаю по окнам, таким как iTunes и Warcraft3.

private bool ShouldWindowBeDisplayed(IntPtr window)
{
    uint windowStyles = Win32.GetWindowLong(window, GWL.GWL_STYLE);

    if (((uint)WindowStyles.WS_VISIBLE & windowStyles) != (uint)WindowStyles.WS_VISIBLE ||
        ((uint)WindowExStyles.WS_EX_APPWINDOW & windowStyles) != (uint)WindowExStyles.WS_EX_APPWINDOW)
    {
        return true;
    }
    return false;
}

Ответы [ 2 ]

24 голосов
/ 17 октября 2008

Рэймонд Чен ответил на это некоторое время назад
(https://devblogs.microsoft.com/oldnewthing/20071008-00/?p=24863):

Это на самом деле довольно просто, хотя вряд ли что-то, что вы сможете угадать самостоятельно. Примечание: детали этого алгоритм является реализацией подробно. Это может измениться в любое время, поэтому не надейся на это. На самом деле это уже изменено с Flip и Flip3D; Я просто говорить о классическом Alt + Tab окно здесь.

Для каждого видимого окна пройдитесь по его цепочка владельцев пока не найдешь рут владелец. Затем идите обратно вниз по видимому последняя активная цепочка всплывающих окон, пока вы не найдете видимое окно. Если вы вернулись к где вы начали, а затем положить окно в списке Alt + Tab. В псевдо-код:

BOOL IsAltTabWindow(HWND hwnd)
{
 // Start at the root owner
 HWND hwndWalk = GetAncestor(hwnd, GA_ROOTOWNER);

 // See if we are the last active visible popup
 HWND hwndTry;
 while ((hwndTry = GetLastActivePopup(hwndWalk)) != hwndTry) {
  if (IsWindowVisible(hwndTry)) break;
  hwndWalk = hwndTry;
 }
 return hwndWalk == hwnd;
}

Перейдите по ссылке на запись в блоге Чена для получения более подробной информации и некоторых угловых условий.

11 голосов
/ 18 октября 2008

Спасибо, Майк Б. Пример из блога Raymonds указал мне правильное направление.

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

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

    private static bool KeepWindowHandleInAltTabList(IntPtr window)
    {
        if (window == Win32.GetShellWindow())   //Desktop
            return false;

        ///152772/perechislyat-okna-kak-eto-delaet-alt-tab
        //http://blogs.msdn.com/oldnewthing/archive/2007/10/08/5351207.aspx
        //1. For each visible window, walk up its owner chain until you find the root owner. 
        //2. Then walk back down the visible last active popup chain until you find a visible window.
        //3. If you're back to where you're started, (look for exceptions) then put the window in the Alt+Tab list.
        IntPtr root = Win32.GetAncestor(window, Win32.GaFlags.GA_ROOTOWNER);

        if (GetLastVisibleActivePopUpOfWindow(root) == window)
        {
            WindowInformation wi = new WindowInformation(window);

            if (wi.className == "Shell_TrayWnd" ||                          //Windows taskbar
                wi.className == "DV2ControlHost" ||                         //Windows startmenu, if open
                (wi.className == "Button" && wi.windowText == "Start") ||   //Windows startmenu-button.
                wi.className == "MsgrIMEWindowClass" ||                     //Live messenger's notifybox i think
                wi.className == "SysShadow" ||                              //Live messenger's shadow-hack
                wi.className.StartsWith("WMP9MediaBarFlyout"))              //WMP's "now playing" taskbar-toolbar
                return false;

            return true;
        }
        return false;
    }

    private static IntPtr GetLastVisibleActivePopUpOfWindow(IntPtr window)
    {
        IntPtr lastPopUp = Win32.GetLastActivePopup(window);
        if (Win32.IsWindowVisible(lastPopUp))
            return lastPopUp;
        else if (lastPopUp == window)
            return IntPtr.Zero;
        else
            return GetLastVisibleActivePopUpOfWindow(lastPopUp);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...