Подтвердить что ты не робот

Перечислять окна, такие как alt-tab,

Я создаю замену 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;
}
4b9b3361

Ответ 1

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

Это на самом деле довольно просто, хотя вряд ли вы сможете догадаться самостоятельно. Примечание. Детали этого алгоритма являются деталями реализации. Он может измениться в любое время, поэтому не полагайтесь на него. Фактически, это уже изменилось с Flip и Flip3D; Я просто говорю об окне Classic 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;
}

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

Ответ 2

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

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

Вот мой полный код, он использовал его на один день и не заметил никаких отличий от реальной вкладки alt. Там какой-то базовый код не размещен, но это не проблема, выясняя, что он делает.:)

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

        //http://stackoverflow.com/questions/210504/enumerate-windows-like-alt-tab-does
        //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 notifybox i think
                wi.className == "SysShadow" ||                              //Live messenger shadow-hack
                wi.className.StartsWith("WMP9MediaBarFlyout"))              //WMP "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);
    }

Ответ 3

Это функция в паскале /delphi, вы можете легко перевести ее на С#.

Включает поддержку приложений Windows 10.


EnumWindows(@ListApps, 0);

function ListApps(LHWindow: HWND; lParam: Pointer): Boolean; stdcall;
var
   LHDesktop: HWND;
   LHParent: HWND;
   LExStyle: DWORD;

   AppClassName: array[0..255] of char;

   Cloaked: Cardinal;

   titlelen: Integer;
   title: String;
begin

  LHDesktop:=GetDesktopWindow;

    GetClassName(LHWindow, AppClassName, 255);
    LHParent:=GetWindowLong(LHWindow,GWL_HWNDPARENT);
    LExStyle:=GetWindowLong(LHWindow,GWL_EXSTYLE);

    if AppClassName = 'ApplicationFrameWindow' then
      DwmGetWindowAttribute(LHWindow, DWMWA_CLOAKED, @cloaked, sizeof(Cardinal))
    else
      cloaked := DWM_NORMAL_APP_NOT_CLOAKED;

    if IsWindowVisible(LHWindow)
    and (AppClassName <> 'Windows.UI.Core.CoreWindow')
    and ( (cloaked = DWM_NOT_CLOAKED) or (cloaked = DWM_NORMAL_APP_NOT_CLOAKED) )
    and ( (LHParent=0) or (LHParent=LHDesktop) )
    and (Application.Handle<>LHWindow)
    and ((LExStyle and WS_EX_TOOLWINDOW = 0) or (LExStyle and WS_EX_APPWINDOW <> 0))
    then
    begin
      titlelen := GetWindowTextLength(LHWindow);
      SetLength(title, titlelen);
      GetWindowText(LHWindow, PChar(title), titlelen + 1);
      { add each to a list }
      But.ListBox1.Items.Add(title);
      { also add each HWND to the list too, later switch using SwitchToThisWindow }
      { ... }
    end;


  Result := True;
end;