'Show a list of all "Alt+Tab windows" (even full screen UWP windows) and retrieve the handle of the one picked by the user
I need to retrieve the handle of a window selected by the user and then retrieve its handle. This window must be one of those shown when ALT+TAB is pressed.
I tried enumerating the windows using EnumWindows, but it does not enumerate the full screen UWP windows. For example, if you open a picture with the Photos app and put it in full screen, EnumWindows will not enumerate it.
Then I tried EnumChildWindows because I thought it could enumerate everything, even fullscreen UWP windows, but probably not.
The GraphicsCapturePicker.PickSingleItemAsync method shows a list of windows and the user can pick one, but it returns a GraphicsCaptureItem and I guess you can't get the window handle from it.
Is it possible to reuse the ALT+TAB window to do this (or any other way that shows a list of windows) and retrieve the handle of the window selected by the user?
Note: I need all the windows shown when ALT+TAB is pressed, even the full screen UWP windows, and no others.
Solution 1:[1]
I have investigated with Spy++ and neither EnumWindows nor EnumChildWindows retrieve the handles of the root owners of full screen UWP windows. However EnumChildWindows retrieves their child windows, and each UWP window has a child window whose class name is ApplicationFrameInputSinkWindow (and other child windows). Then, you can retrive the root owner window with GetAncestor.
So, to retrieve "standard" windows you have to call EnumWindows.
But to retrieve full screen UWP windows:
- Call EnumChildWindows with the desktop window as parent.
- In the callback function fetch only the windows whose class name is ApplicationFrameInputSinkWindow.
- Call GetAncestor to get the root owner window.
- If the root owner window has the extended window style WS_EX_TOPMOST and not WS_EX_NOACTIVATE or WS_EX_TOOLWINDOW, it is a full screen UWP window.
Here is a sample to list all the "Alt+Tab windows", even the full screen UWP windows, in a form with a two-column DataGridView and retrieve the handle of the window picked by the user:
const int GWL_EXSTYLE = -20;
const uint DWMWA_CLOAKED = 14;
const uint DWM_CLOAKED_SHELL = 0x00000002;
const uint GA_ROOTOWNER = 3;
const uint WS_EX_TOOLWINDOW = 0x00000080;
const uint WS_EX_TOPMOST = 0x00000008;
const uint WS_EX_NOACTIVATE = 0x08000000;
private void Form1_Load(object sender, EventArgs e)
{
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dataGridView1.MultiSelect = false;
dataGridView1.ReadOnly = true;
dataGridView1.Click += dataGridView1_Click;
EnumWindows(GetAltTabWindows, IntPtr.Zero);
EnumChildWindows(GetDesktopWindow(), GetFullScreenUWPWindows, IntPtr.Zero);
}
private bool GetAltTabWindows(IntPtr hWnd, IntPtr lparam)
{
if (IsAltTabWindow(hWnd))
AddWindowToGrid(hWnd);
return true;
}
private bool GetFullScreenUWPWindows(IntPtr hWnd, IntPtr lparam)
{
// Check only the windows whose class name is ApplicationFrameInputSinkWindow
StringBuilder className = new StringBuilder(1024);
GetClassName(hWnd, className, className.Capacity);
if (className.ToString() != "ApplicationFrameInputSinkWindow")
return true;
// Get the root owner of the window
IntPtr rootOwner = GetAncestor(hWnd, GA_ROOTOWNER);
if (IsFullScreenUWPWindows(rootOwner))
AddWindowToGrid(rootOwner);
return true;
}
private bool IsAltTabWindow(IntPtr hWnd)
{
// The window must be visible
if (!IsWindowVisible(hWnd))
return false;
// The window must be a root owner
if (GetAncestor(hWnd, GA_ROOTOWNER) != hWnd)
return false;
// The window must not be cloaked by the shell
DwmGetWindowAttribute(hWnd, DWMWA_CLOAKED, out uint cloaked, sizeof(uint));
if (cloaked == DWM_CLOAKED_SHELL)
return false;
// The window must not have the extended style WS_EX_TOOLWINDOW
uint style = GetWindowLong(hWnd, GWL_EXSTYLE);
if ((style & WS_EX_TOOLWINDOW) != 0)
return false;
return true;
}
private bool IsFullScreenUWPWindows(IntPtr hWnd)
{
// Get the extended style of the window
uint style = GetWindowLong(hWnd, GWL_EXSTYLE);
// The window must have the extended style WS_EX_TOPMOST
if ((style & WS_EX_TOPMOST) == 0)
return false;
// The window must not have the extended style WS_EX_NOACTIVATE
if ((style & WS_EX_NOACTIVATE) != 0)
return false;
// The window must not have the extended style WS_EX_TOOLWINDOW
if ((style & WS_EX_TOOLWINDOW) != 0)
return false;
return true;
}
private void AddWindowToGrid(IntPtr hWnd)
{
StringBuilder windowText = new StringBuilder(1024);
GetWindowText(hWnd, windowText, windowText.Capacity);
var strTitle = windowText.ToString();
var strHandle = hWnd.ToString("X8");
dataGridView1.Rows.Add(new string[] { strHandle, strTitle });
}
private void dataGridView1_Click(object sender, EventArgs e)
{
var dgv = (DataGridView)sender;
if (dgv.SelectedRows.Count == 0)
return;
// Get the value of the first cell of the selected row
var value = dgv.SelectedRows[0].Cells[0].Value;
if (value == null)
return;
// Convert the value to IntPtr
var strValue = value.ToString();
var intValue = int.Parse(strValue, System.Globalization.NumberStyles.HexNumber);
var windowHandle = new IntPtr(intValue);
// Do what you want with the window handle
}
Note: Standard windows cannot be cloaked by the shell; full screen UWP windows can. When you place another window over a full screen UWP window it disappears because it is cloaked by the shell, not minimized.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |