Skip to content

Commit

Permalink
Better app listing like Alt-Tab supports UWP apps and hidden apps run…
Browse files Browse the repository at this point in the history
…ning including in another Virtual Desktops (#1956)

* Better app listing like Alt-Tab supports UWP apps and hidden apps running in another virtual desktop just like Windows Alt-Tab

* Modified not to hide cloaked apps i.e. also show apps running in another virtual desktop

* Improved listing apps, with readability and reusable abstract properties.
Including a function to detect cloaked UWP apps for future use.
  • Loading branch information
vhanla committed Apr 7, 2020
1 parent 5ff146b commit c241d48
Show file tree
Hide file tree
Showing 3 changed files with 271 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -594,9 +594,187 @@ public POINT(System.Drawing.Point pt)
}
}

/// <summary>
/// GetWindow relationship between the specified window and the window whose handle is to be retrieved.
/// </summary>
public enum GetWindowCmd : uint
{
/// <summary>
/// The retrieved handle identifies the window of the same type that is highest in the Z order.
/// </summary>
GW_HWNDFIRST = 0,
/// <summary>
/// The retrieved handle identifies the window of the same type that is lowest in the Z order.
/// </summary>
GW_HWNDLAST = 1,
/// <summary>
/// The retrieved handle identifies the window below the specified window in the Z order.
/// </summary>
GW_HWNDNEXT = 2,
/// <summary>
/// The retrieved handle identifies the window above the specified window in the Z order.
/// </summary>
GW_HWNDPREV = 3,
/// <summary>
/// The retrieved handle identifies the specified window's owner window, if any.
/// </summary>
GW_OWNER = 4,
/// <summary>
/// The retrieved handle identifies the child window at the top of the Z order, if the specified window
/// is a parent window.
/// </summary>
GW_CHILD = 5,
/// <summary>
/// The retrieved handle identifies the enabled popup window owned by the specified window.
/// </summary>
GW_ENABLEDPOPUP = 6
}

/// <summary>
/// GetWindowLong index to retrieves the extended window styles.
/// </summary>
public const int GWL_EXSTYLE = -20;

/// <summary>
/// The following are the extended window styles
/// </summary>
[Flags]
public enum ExtendedWindowStyles : UInt32
{
/// <summary>
/// The window has a double border; the window can, optionally, be created with a title bar by specifying
/// the WS_CAPTION style in the dwStyle parameter.
/// </summary>
WS_EX_DLGMODALFRAME = 0X0001,
/// <summary>
/// The child window created with this style does not send the WM_PARENTNOTIFY message to its parent window
/// when it is created or destroyed.
/// </summary>
WS_EX_NOPARENTNOTIFY = 0X0004,
/// <summary>
/// The window should be placed above all non-topmost windows and should stay above all non-topmost windows
/// and should stay above them, even when the window is deactivated.
/// </summary>
WS_EX_TOPMOST = 0X0008,
/// <summary>
/// The window accepts drag-drop files.
/// </summary>
WS_EX_ACCEPTFILES = 0x0010,
/// <summary>
/// The window should not be painted until siblings beneath the window (that were created by the same thread)
/// have been painted.
/// </summary>
WS_EX_TRANSPARENT = 0x0020,
/// <summary>
/// The window is a MDI child window.
/// </summary>
WS_EX_MDICHILD = 0x0040,
/// <summary>
/// The window is intended to be used as a floating toolbar. A tool window has a title bar that is shorter
/// than a normal title bar, and the window title is drawn using a smaller font. A tool window does not
/// appear in the taskbar or in the dialog that appears when the user presses ALT+TAB.
/// </summary>
WS_EX_TOOLWINDOW = 0x0080,
/// <summary>
/// The window has a border with a raised edge.
/// </summary>
WS_EX_WINDOWEDGE = 0x0100,
/// <summary>
/// The window has a border with a sunken edge.
/// </summary>
WS_EX_CLIENTEDGE = 0x0200,
/// <summary>
/// The title bar of the window includes a question mark.
/// </summary>
WS_EX_CONTEXTHELP = 0x0400,
/// <summary>
/// The window has generic "right-aligned" properties. This depends on the window class. This style has
/// an effect only if the shell language supports reading-order alignment, otherwise is ignored.
/// </summary>
WS_EX_RIGHT = 0x1000,
/// <summary>
/// The window has generic left-aligned properties. This is the default.
/// </summary>
WS_EX_LEFT = 0x0,
/// <summary>
/// If the shell language supports reading-order alignment, the window text is displayed using right-to-left
/// reading-order properties. For other languages, the styles is ignored.
/// </summary>
WS_EX_RTLREADING = 0x2000,
/// <summary>
/// The window text is displayed using left-to-right reading-order properties. This is the default.
/// </summary>
WS_EX_LTRREADING = 0x0,
/// <summary>
/// If the shell language supports reading order alignment, the vertical scroll bar (if present) is to
/// the left of the client area. For other languages, the style is ignored.
/// </summary>
WS_EX_LEFTSCROLLBAR = 0x4000,
/// <summary>
/// The vertical scroll bar (if present) is to the right of the client area. This is the default.
/// </summary>
WS_EX_RIGHTSCROLLBAR = 0x0,
/// <summary>
/// The window itself contains child windows that should take part in dialog box, navigation. If this
/// style is specified, the dialog manager recurses into children of this window when performing
/// navigation operations such as handling tha TAB key, an arrow key, or a keyboard mnemonic.
/// </summary>
WS_EX_CONTROLPARENT = 0x10000,
/// <summary>
/// The window has a three-dimensional border style intended to be used for items that do not accept
/// user input.
/// </summary>
WS_EX_STATICEDGE = 0x20000,
/// <summary>
/// Forces a top-level window onto the taskbar when the window is visible.
/// </summary>
WS_EX_APPWINDOW = 0x40000,
/// <summary>
/// The window is an overlapped window.
/// </summary>
WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE,
/// <summary>
/// The window is palette window, which is a modeless dialog box that presents an array of commands.
/// </summary>
WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
/// <summary>
/// The window is a layered window. This style cannot be used if the window has a class style of either
/// CS_OWNDC or CS_CLASSDC. Only for top level window before Windows 8, and child windows from Windows 8.
/// </summary>
WS_EX_LAYERED = 0x80000,
/// <summary>
/// The window does not pass its window layout to its child windows.
/// </summary>
WS_EX_NOINHERITLAYOUT = 0x100000,
/// <summary>
/// If the shell language supports reading order alignment, the horizontal origin of the window is on the
/// right edge. Increasing horizontal values advance to the left.
/// </summary>
WS_EX_LAYOUTRTL = 0x400000,
/// <summary>
/// Paints all descendants of a window in bottom-to-top painting order using double-buffering.
/// Bottom-to-top painting order allows a descendent window to have translucency (alpha) and
/// transparency (color-key) effects, but only if the descendent window also has the WS_EX_TRANSPARENT
/// bit set. Double-buffering allows the window and its descendents to be painted without flicker.
/// </summary>
WS_EX_COMPOSITED = 0x2000000,
/// <summary>
/// A top-level window created with this style does not become the foreground window when the user
/// clicks it. The system does not bring this window to the foreground when the user minimizes or closes
/// the foreground window.
/// </summary>
WS_EX_NOACTIVATE = 0x8000000
}

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int EnumWindows(CallBackPtr callPtr, int lPar);

[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetWindow(IntPtr hWnd, GetWindowCmd uCmd);

[DllImport("user32.dll", SetLastError = true)]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);

Expand All @@ -606,6 +784,9 @@ public POINT(System.Drawing.Point pt)
[DllImport("user32.dll")]
public static extern bool IsWindowVisible(IntPtr hWnd);

[DllImport("user32.dll")]
public static extern bool IsWindow(IntPtr hWnd);

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SetWindowPosFlags uFlags);
Expand Down Expand Up @@ -633,6 +814,9 @@ public POINT(System.Drawing.Point pt)
[DllImport("psapi.dll")]
public static extern uint GetProcessImageFileName(IntPtr hProcess, [Out] StringBuilder lpImageFileName, [In] [MarshalAs(UnmanagedType.U4)] int nSize);

[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetProp(IntPtr hWnd, string lpString);

[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId);

Expand All @@ -642,6 +826,9 @@ public POINT(System.Drawing.Point pt)
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);

[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out int pvAttribute, int cbAttribute);

[DllImport("user32.dll")]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,22 +94,11 @@ public bool WindowEnumerationCallBack(IntPtr hwnd, IntPtr lParam)
{
Window newWindow = new Window(hwnd);

if (windows.Select(x => x.Title).Contains(newWindow.Title))
{
if (newWindow.ProcessName.ToLower().Equals("applicationframehost.exe"))
{
windows.Remove(windows.Where(x => x.Title == newWindow.Title).First());
}

return true;
}

if ((newWindow.Visible && !newWindow.ProcessName.ToLower().Equals("iexplore.exe")) ||
(newWindow.ProcessName.ToLower().Equals("iexplore.exe") && newWindow.ClassName == "TabThumbnailWindow"))
if (newWindow.IsWindow && newWindow.Visible && newWindow.IsOwner &&
(!newWindow.IsToolWindow || newWindow.IsAppWindow ) && !newWindow.TaskListDeleted &&
newWindow.ClassName != "Windows.UI.Core.CoreWindow")
{
windows.Add(newWindow);

OnOpenWindowsUpdate?.Invoke(this, new SearchController.SearchResultUpdateEventArgs());
}

return true;
Expand Down
81 changes: 81 additions & 0 deletions src/modules/windowwalker/app/Window Walker/Components/Window.cs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,87 @@ public bool Visible
}
}

/// <summary>
/// Determines whether the specified window handle identifies an existing window.
/// </summary>
public bool IsWindow
{
get
{
return InteropAndHelpers.IsWindow(Hwnd);
}
}

/// <summary>
/// Get a value indicating whether is the window GWL_EX_STYLE is a toolwindow
/// </summary>
public bool IsToolWindow
{
get
{
return (InteropAndHelpers.GetWindowLong(Hwnd, InteropAndHelpers.GWL_EXSTYLE) &
(uint)InteropAndHelpers.ExtendedWindowStyles.WS_EX_TOOLWINDOW) ==
(uint)InteropAndHelpers.ExtendedWindowStyles.WS_EX_TOOLWINDOW;
}
}

/// <summary>
/// Get a value indicating whether the window GWL_EX_STYLE is an appwindow
/// </summary>
public bool IsAppWindow
{
get
{
return (InteropAndHelpers.GetWindowLong(Hwnd, InteropAndHelpers.GWL_EXSTYLE) &
(uint)InteropAndHelpers.ExtendedWindowStyles.WS_EX_APPWINDOW) ==
(uint)InteropAndHelpers.ExtendedWindowStyles.WS_EX_APPWINDOW;
}
}

/// <summary>
/// Get a value indicating whether the window has ITaskList_Deleted property
/// </summary>
public bool TaskListDeleted
{
get
{
return InteropAndHelpers.GetProp(Hwnd, "ITaskList_Deleted") != IntPtr.Zero;
}
}

/// <summary>
/// Get a value indicating whether the app is a cloaked UWP app
/// </summary>
public bool IsUWPCloaked
{
get
{
return (this.IsWindowCloaked() && this.ClassName == "ApplicationFrameWindow");
}
}

/// <summary>
/// Determines whether the specified windows is the owner
/// </summary>
public bool IsOwner
{
get
{
return InteropAndHelpers.GetWindow(Hwnd, InteropAndHelpers.GetWindowCmd.GW_OWNER) != null;
}
}

/// <summary>
/// Gets a value indicating whether is the window cloaked. To detect UWP apps in background or win32 apps running in another virtual desktop
/// </summary>
public bool IsWindowCloaked()
{
int isCloaked = 0;
const int DWMWA_CLOAKED = 14;
InteropAndHelpers.DwmGetWindowAttribute(this.hwnd, DWMWA_CLOAKED, out isCloaked, sizeof(int));
return isCloaked != 0;
}

/// <summary>
/// Gets a value indicating whether returns true if the window is minimized
/// </summary>
Expand Down

0 comments on commit c241d48

Please sign in to comment.